Imported Upstream version 2.81
[platform/upstream/libbullet.git] / Extras / CDTestFramework / AntTweakBar / src / TwBar.cpp
1 //  ---------------------------------------------------------------------------
2 //
3 //  @file       TwBar.cpp
4 //  @author     Philippe Decaudin - http://www.antisphere.com
5 //  @license    This file is part of the AntTweakBar library.
6 //              For conditions of distribution and use, see License.txt
7 //
8 //  ---------------------------------------------------------------------------
9
10
11 #include "TwPrecomp.h"
12 #include <AntTweakBar.h>
13 #include "TwMgr.h"
14 #include "TwBar.h"
15 #include "TwColors.h"
16   
17 using namespace std;
18
19 extern const char *g_ErrNotFound;
20 const char *g_ErrUnknownAttrib  = "Unknown parameter";
21 const char *g_ErrInvalidAttrib  = "Invalid parameter";
22 const char *g_ErrNotGroup       = "Value is not a group";
23 const char *g_ErrNoValue        = "Value required";
24 const char *g_ErrBadValue       = "Bad value";
25 const char *g_ErrUnknownType    = "Unknown type";
26 const char *g_ErrNotEnum        = "Must be of type Enum";
27
28 #undef PERF         // comment to print benchs
29 #define PERF(cmd)
30
31
32 PerfTimer g_BarTimer;
33
34 #define ANT_SET_CURSOR(_Name)       g_TwMgr->SetCursor(g_TwMgr->m_Cursor##_Name)
35 #define ANT_SET_ROTO_CURSOR(_Num)   g_TwMgr->SetCursor(g_TwMgr->m_RotoCursors[_Num])
36
37 #if !defined(ANT_WINDOWS)
38 #   define _stricmp strcasecmp
39 #   define _strdup  strdup
40 #endif  // defined(ANT_WINDOWS)
41
42 #if !defined(M_PI)
43 #   define M_PI 3.1415926535897932384626433832795
44 #endif  // !defined(M_PI)
45
46 const float  FLOAT_MAX  = 3.0e+38f;
47 const double DOUBLE_MAX = 1.0e+308;
48 const double DOUBLE_EPS = 1.0e-307;
49
50 bool IsCustomType(int _Type)
51 {
52     return (g_TwMgr && _Type>=TW_TYPE_CUSTOM_BASE && _Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size());
53 }
54
55 bool IsCSStringType(int _Type)
56 {
57     return (_Type>TW_TYPE_CSSTRING_BASE && _Type<=TW_TYPE_CSSTRING_MAX);
58 }
59
60 bool IsEnumType(int _Type)
61 {
62     return (g_TwMgr && _Type>=TW_TYPE_ENUM_BASE && _Type<TW_TYPE_ENUM_BASE+(int)g_TwMgr->m_Enums.size());
63 }
64
65 //  ---------------------------------------------------------------------------
66
67 CTwVar::CTwVar()
68
69     m_IsRoot = false; 
70     m_DontClip = false; 
71     m_Visible = true; 
72     m_LeftMargin = 0; 
73     m_TopMargin = 0; 
74     m_ColorPtr = &COLOR32_WHITE; 
75     m_BgColorPtr = &COLOR32_ZERO;   // default
76 }
77
78 CTwVarAtom::CTwVarAtom()
79 {
80     m_Type = TW_TYPE_UNDEF;
81     m_Ptr = NULL;
82     m_SetCallback = NULL;
83     m_GetCallback = NULL;
84     m_ClientData = NULL;
85     m_ReadOnly = false;
86     m_NoSlider = false;
87     m_KeyIncr[0] = 0;
88     m_KeyIncr[1] = 0;
89     m_KeyDecr[0] = 0;
90     m_KeyDecr[1] = 0;
91     memset(&m_Val, 0, sizeof(UVal));
92 }
93
94 CTwVarAtom::~CTwVarAtom()
95 {
96     if( m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP )
97     {
98         if( m_Val.m_Bool.m_FreeTrueString && m_Val.m_Bool.m_TrueString!=NULL )
99         {
100             free(m_Val.m_Bool.m_TrueString);
101             m_Val.m_Bool.m_TrueString = NULL;
102         }
103         if( m_Val.m_Bool.m_FreeFalseString && m_Val.m_Bool.m_FalseString!=NULL )
104         {
105             free(m_Val.m_Bool.m_FalseString);
106             m_Val.m_Bool.m_FalseString = NULL;
107         }
108     }
109     else if( m_Type==TW_TYPE_CDSTDSTRING && m_GetCallback==CTwMgr::CCDStdString::GetCB && m_ClientData!=NULL && g_TwMgr!=NULL )
110     {
111         // delete corresponding g_TwMgr->m_CDStdStrings element
112         const CTwMgr::CCDStdString *CDStdString = (const CTwMgr::CCDStdString *)m_ClientData;
113         //if( &(*CDStdString->m_This)==CDStdString )
114         //  g_TwMgr->m_CDStdStrings.erase(CDStdString->m_This);
115         for( list<CTwMgr::CCDStdString>::iterator it=g_TwMgr->m_CDStdStrings.begin(); it!=g_TwMgr->m_CDStdStrings.end(); ++it )
116             if( &(*it)==CDStdString )
117             {
118                 g_TwMgr->m_CDStdStrings.erase(it);
119                 break;
120             }
121     }
122     /*
123     else if( m_Type==TW_TYPE_ENUM8 || m_Type==TW_TYPE_ENUM16 || m_Type==TW_TYPE_ENUM32 )
124     {
125         if( m_Val.m_Enum.m_Entries!=NULL )
126         {
127             delete m_Val.m_Enum.m_Entries;
128             m_Val.m_Enum.m_Entries = NULL;
129         }
130     }
131     */
132 }
133
134 //  ---------------------------------------------------------------------------
135
136 void CTwVarAtom::ValueToString(string *_Str) const
137 {
138     assert(_Str!=NULL);
139     static const char *ErrStr = "unreachable";
140     char Tmp[1024];
141     if( m_Type==TW_TYPE_UNDEF || m_Type==TW_TYPE_HELP_ATOM || m_Type==TW_TYPE_HELP_GRP || m_Type==TW_TYPE_BUTTON )  // has no value
142     {
143         *_Str = "";
144         return;
145     }
146     else if( m_Type==TW_TYPE_HELP_HEADER )
147     {
148         *_Str = "SHORTCUTS";
149         return;
150     }
151     else if( m_Type==TW_TYPE_SHORTCUT ) // special case for help bar: display shortcut
152     {
153         *_Str = "";
154         if( m_ReadOnly && m_Val.m_Shortcut.m_Incr[0]==0 && m_Val.m_Shortcut.m_Decr[0]==0 )
155             (*_Str) = "(read only)";
156         else
157         {
158             if( m_Val.m_Shortcut.m_Incr[0]>0 )
159                 TwGetKeyString(_Str, m_Val.m_Shortcut.m_Incr[0], m_Val.m_Shortcut.m_Incr[1]);
160             else
161                 (*_Str) += "(none)";
162             if( m_Val.m_Shortcut.m_Decr[0]>0 )
163             {
164                 (*_Str) += "  ";
165                 TwGetKeyString(_Str, m_Val.m_Shortcut.m_Decr[0], m_Val.m_Shortcut.m_Decr[1]);
166             }
167         }
168         return;
169     }
170     else if( m_Type==TW_TYPE_HELP_STRUCT )
171     {
172         int idx = m_Val.m_HelpStruct.m_StructType - TW_TYPE_STRUCT_BASE;
173         if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() )
174         {
175             if( g_TwMgr->m_Structs[idx].m_Name.length()>0 )
176                 (*_Str) = '{' + g_TwMgr->m_Structs[idx].m_Name + '}';
177             else
178                 (*_Str) = "{struct}";
179         }
180         return;
181     }
182
183     if( m_Ptr==NULL && m_GetCallback==NULL )
184     {
185         *_Str = ErrStr;
186         return;
187     }
188     bool UseGet = (m_GetCallback!=NULL);
189     switch( m_Type )
190     {
191     case TW_TYPE_BOOLCPP:
192         {
193             bool Val = 0;
194             if( UseGet )
195                 m_GetCallback(&Val, m_ClientData);
196             else
197                 Val = *(bool *)m_Ptr;
198             if( Val )
199                 *_Str = (m_Val.m_Bool.m_TrueString!=NULL) ? m_Val.m_Bool.m_TrueString : "1";
200             else
201                 *_Str = (m_Val.m_Bool.m_FalseString!=NULL) ? m_Val.m_Bool.m_FalseString : "0";
202         }
203         break;
204     case TW_TYPE_BOOL8:
205         {
206             char Val = 0;
207             if( UseGet )
208                 m_GetCallback(&Val, m_ClientData);
209             else
210                 Val = *(char *)m_Ptr;
211             if( Val )
212                 *_Str = (m_Val.m_Bool.m_TrueString!=NULL) ? m_Val.m_Bool.m_TrueString : "1";
213             else
214                 *_Str = (m_Val.m_Bool.m_FalseString!=NULL) ? m_Val.m_Bool.m_FalseString : "0";
215         }
216         break;
217     case TW_TYPE_BOOL16:
218         {
219             short Val = 0;
220             if( UseGet )
221                 m_GetCallback(&Val, m_ClientData);
222             else
223                 Val = *(short *)m_Ptr;
224             if( Val )
225                 *_Str = (m_Val.m_Bool.m_TrueString!=NULL) ? m_Val.m_Bool.m_TrueString : "1";
226             else
227                 *_Str = (m_Val.m_Bool.m_FalseString!=NULL) ? m_Val.m_Bool.m_FalseString : "0";
228         }
229         break;
230     case TW_TYPE_BOOL32:
231         {
232             int Val = 0;
233             if( UseGet )
234                 m_GetCallback(&Val, m_ClientData);
235             else
236                 Val = *(int *)m_Ptr;
237             if( Val )
238                 *_Str = (m_Val.m_Bool.m_TrueString!=NULL) ? m_Val.m_Bool.m_TrueString : "1";
239             else
240                 *_Str = (m_Val.m_Bool.m_FalseString!=NULL) ? m_Val.m_Bool.m_FalseString : "0";
241         }
242         break;
243     case TW_TYPE_CHAR:
244         {
245             unsigned char Val = 0;
246             if( UseGet )
247                 m_GetCallback(&Val, m_ClientData);
248             else
249                 Val = *(unsigned char *)m_Ptr;
250             if( Val!=0 )
251             {
252                 int d = Val;
253                 if( m_Val.m_Char.m_Hexa )
254                     sprintf(Tmp, "%c (0x%.2X)", Val, d);
255                 else
256                     sprintf(Tmp, "%c (%d)", Val, d);
257                 *_Str = Tmp;
258             }
259             else
260             {
261                 *_Str = "  (0)";
262                 const_cast<char *>(_Str->c_str())[0] = '\0';
263             }
264         }
265         break;
266     case TW_TYPE_INT8:
267         {
268             signed char Val = 0;
269             if( UseGet )
270                 m_GetCallback(&Val, m_ClientData);
271             else
272                 Val = *(signed char *)m_Ptr;
273             int d = Val;
274             if( m_Val.m_Int8.m_Hexa )
275                 sprintf(Tmp, "0x%.2X", d&0xff);
276             else
277                 sprintf(Tmp, "%d", d);
278             *_Str = Tmp;
279         }
280         break;
281     case TW_TYPE_UINT8:
282         {
283             unsigned char Val = 0;
284             if( UseGet )
285                 m_GetCallback(&Val, m_ClientData);
286             else
287                 Val = *(unsigned char *)m_Ptr;
288             unsigned int d = Val;
289             if( m_Val.m_UInt8.m_Hexa )
290                 sprintf(Tmp, "0x%.2X", d);
291             else        
292                 sprintf(Tmp, "%u", d);
293             *_Str = Tmp;
294         }
295         break;
296     case TW_TYPE_INT16:
297         {
298             short Val = 0;
299             if( UseGet )
300                 m_GetCallback(&Val, m_ClientData);
301             else
302                 Val = *(short *)m_Ptr;
303             int d = Val;
304             if( m_Val.m_Int16.m_Hexa )
305                 sprintf(Tmp, "0x%.4X", d&0xffff);
306             else
307                 sprintf(Tmp, "%d", d);
308             *_Str = Tmp;
309         }
310         break;
311     case TW_TYPE_UINT16:
312         {
313             unsigned short Val = 0;
314             if( UseGet )
315                 m_GetCallback(&Val, m_ClientData);
316             else
317                 Val = *(unsigned short *)m_Ptr;
318             unsigned int d = Val;
319             if( m_Val.m_UInt16.m_Hexa )
320                 sprintf(Tmp, "0x%.4X", d);
321             else
322                 sprintf(Tmp, "%u", d);
323             *_Str = Tmp;
324         }
325         break;
326     case TW_TYPE_INT32:
327         {
328             int Val = 0;
329             if( UseGet )
330                 m_GetCallback(&Val, m_ClientData);
331             else
332                 Val = *(int *)m_Ptr;
333             if( m_Val.m_Int32.m_Hexa )
334                 sprintf(Tmp, "0x%.8X", Val);
335             else
336                 sprintf(Tmp, "%d", Val);
337             *_Str = Tmp;
338         }
339         break;
340     case TW_TYPE_UINT32:
341         {
342             unsigned int Val = 0;
343             if( UseGet )
344                 m_GetCallback(&Val, m_ClientData);
345             else
346                 Val = *(unsigned int *)m_Ptr;
347             if( m_Val.m_UInt32.m_Hexa )
348                 sprintf(Tmp, "0x%.8X", Val);
349             else
350                 sprintf(Tmp, "%u", Val);
351             *_Str = Tmp;
352         }
353         break;
354     case TW_TYPE_FLOAT:
355         {
356             float Val = 0;
357             if( UseGet )
358                 m_GetCallback(&Val, m_ClientData);
359             else
360                 Val = *(float *)m_Ptr;
361             if( m_Val.m_Float32.m_Precision<0 )
362                 sprintf(Tmp, "%g", Val);
363             else
364             {
365                 char Fmt[64];
366                 sprintf(Fmt, "%%.%df", (int)m_Val.m_Float32.m_Precision);
367                 sprintf(Tmp, Fmt, Val);
368             }
369             *_Str = Tmp;
370         }
371         break;  
372     case TW_TYPE_DOUBLE:
373         {
374             double Val = 0;
375             if( UseGet )
376                 m_GetCallback(&Val, m_ClientData);
377             else
378                 Val = *(double *)m_Ptr;
379             if( m_Val.m_Float64.m_Precision<0 )
380                 sprintf(Tmp, "%g", Val);
381             else
382             {
383                 char Fmt[128];
384                 sprintf(Fmt, "%%.%dlf", (int)m_Val.m_Float64.m_Precision);
385                 sprintf(Tmp, Fmt, Val);
386             }
387             *_Str = Tmp;
388         }
389         break;
390     case TW_TYPE_STDSTRING:
391         {
392             if( UseGet )
393                 m_GetCallback(_Str, m_ClientData);
394             else
395                 *_Str = *(std::string *)m_Ptr;
396         }
397         break;
398     /*
399     case TW_TYPE_ENUM8:
400     case TW_TYPE_ENUM16:
401     case TW_TYPE_ENUM32:
402         {
403             unsigned int d = 0;
404             if( m_Type==TW_TYPE_ENUM8 )
405             {
406                 unsigned char Val = 0;
407                 if( UseGet )
408                     m_GetCallback(&Val, m_ClientData);
409                 else
410                     Val = *(unsigned char *)m_Ptr;
411                 d = Val;
412             }
413             else if( m_Type==TW_TYPE_ENUM16 )
414             {
415                 unsigned short Val = 0;
416                 if( UseGet )
417                     m_GetCallback(&Val, m_ClientData);
418                 else
419                     Val = *(unsigned short *)m_Ptr;
420                 d = Val;
421             }
422             else
423             {
424                 assert(m_Type==TW_TYPE_ENUM32);
425                 unsigned int Val = 0;
426                 if( UseGet )
427                     m_GetCallback(&Val, m_ClientData);
428                 else
429                     Val = *(unsigned int *)m_Ptr;
430                 d = Val;
431             }
432             bool Found = false;
433             if( m_Val.m_Enum.m_Entries!=NULL )
434             {
435                 UVal::CEnumVal::CEntries::iterator It = m_Val.m_Enum.m_Entries->find(d);
436                 if( It!=m_Val.m_Enum.m_Entries->end() )
437                 {
438                     *_Str = It->second;
439                     Found = true;
440                 }
441             }
442             if( !Found )
443             {
444                 sprintf(Tmp, "%u", d);
445                 *_Str = Tmp;
446             }
447         }
448         break;
449     */
450     default:
451         if( IsEnumType(m_Type) )
452         {
453             unsigned int Val = 0;
454             if( UseGet )
455                 m_GetCallback(&Val, m_ClientData);
456             else
457                 Val = *(unsigned int *)m_Ptr;
458
459             CTwMgr::CEnum& e = g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE];
460             CTwMgr::CEnum::CEntries::iterator It = e.m_Entries.find(Val);
461             if( It!=e.m_Entries.end() )
462                 *_Str = It->second;
463             else
464             {
465                 sprintf(Tmp, "%u", Val);
466                 *_Str = Tmp;
467             }
468         }
469         else if( IsCSStringType(m_Type) )
470         {
471             char *Val = NULL;
472             if( UseGet )
473             {
474                 int n = TW_CSSTRING_SIZE(m_Type);
475                 if( n+32>(int)g_TwMgr->m_CSStringBuffer.size() )
476                     g_TwMgr->m_CSStringBuffer.resize(n+32);
477                 Val = &(g_TwMgr->m_CSStringBuffer[0]);
478                 m_GetCallback(Val , m_ClientData);
479                 Val[n] = '\0';
480             }
481             else
482                 Val = (char *)m_Ptr;
483             if( Val!=NULL )
484                 *_Str = Val;
485             else
486                 *_Str = "";
487         }
488         else if( m_Type==TW_TYPE_CDSTRING || m_Type==TW_TYPE_CDSTDSTRING )
489         {
490             char *Val = NULL;
491             if( UseGet )
492                 m_GetCallback(&Val , m_ClientData);
493             else
494                 Val = *(char **)m_Ptr;
495             if( Val!=NULL )
496                 *_Str = Val;
497             else
498                 *_Str = "";
499         }
500         else if( IsCustom() ) // m_Type>=TW_TYPE_CUSTOM_BASE && m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size() )
501         {
502             *_Str = "";
503         }
504         else
505         {
506             *_Str = "unknown type";
507             const_cast<CTwVarAtom *>(this)->m_ReadOnly = true;
508         }
509     }
510 }
511
512 //  ---------------------------------------------------------------------------
513
514 double CTwVarAtom::ValueToDouble() const
515 {
516     if( m_Ptr==NULL && m_GetCallback==NULL )
517         return 0;   // unreachable
518     bool UseGet = (m_GetCallback!=NULL);
519     switch( m_Type )
520     {
521     case TW_TYPE_BOOLCPP:
522         {
523             bool Val = 0;
524             if( UseGet )
525                 m_GetCallback(&Val, m_ClientData);
526             else
527                 Val = *(bool *)m_Ptr;
528             if( Val )
529                 return 1;
530             else
531                 return 0;
532         }
533         break;
534     case TW_TYPE_BOOL8:
535         {
536             char Val = 0;
537             if( UseGet )
538                 m_GetCallback(&Val, m_ClientData);
539             else
540                 Val = *(char *)m_Ptr;
541             if( Val )
542                 return 1;
543             else
544                 return 0;
545         }
546         break;
547     case TW_TYPE_BOOL16:
548         {
549             short Val = 0;
550             if( UseGet )
551                 m_GetCallback(&Val, m_ClientData);
552             else
553                 Val = *(short *)m_Ptr;
554             if( Val )
555                 return 1;
556             else
557                 return 0;
558         }
559         break;
560     case TW_TYPE_BOOL32:
561         {
562             int Val = 0;
563             if( UseGet )
564                 m_GetCallback(&Val, m_ClientData);
565             else
566                 Val = *(int *)m_Ptr;
567             if( Val )
568                 return 1;
569             else
570                 return 0;
571         }
572         break;
573     case TW_TYPE_CHAR:
574         {
575             unsigned char Val = 0;
576             if( UseGet )
577                 m_GetCallback(&Val, m_ClientData);
578             else
579                 Val = *(unsigned char *)m_Ptr;
580             return Val;
581         }
582         break;
583     case TW_TYPE_INT8:
584         {
585             signed char Val = 0;
586             if( UseGet )
587                 m_GetCallback(&Val, m_ClientData);
588             else
589                 Val = *(signed char *)m_Ptr;
590             int d = Val;
591             return d;
592         }
593         break;
594     case TW_TYPE_UINT8:
595         {
596             unsigned char Val = 0;
597             if( UseGet )
598                 m_GetCallback(&Val, m_ClientData);
599             else
600                 Val = *(unsigned char *)m_Ptr;
601             unsigned int d = Val;
602             return d;
603         }
604         break;
605     case TW_TYPE_INT16:
606         {
607             short Val = 0;
608             if( UseGet )
609                 m_GetCallback(&Val, m_ClientData);
610             else
611                 Val = *(short *)m_Ptr;
612             int d = Val;
613             return d;
614         }
615         break;
616     case TW_TYPE_UINT16:
617         {
618             unsigned short Val = 0;
619             if( UseGet )
620                 m_GetCallback(&Val, m_ClientData);
621             else
622                 Val = *(unsigned short *)m_Ptr;
623             unsigned int d = Val;
624             return d;
625         }
626         break;
627     case TW_TYPE_INT32:
628         {
629             int Val = 0;
630             if( UseGet )
631                 m_GetCallback(&Val, m_ClientData);
632             else
633                 Val = *(int *)m_Ptr;
634             return Val;
635         }
636         break;
637     case TW_TYPE_UINT32:
638         {
639             unsigned int Val = 0;
640             if( UseGet )
641                 m_GetCallback(&Val, m_ClientData);
642             else
643                 Val = *(unsigned int *)m_Ptr;
644             return Val;
645         }
646         break;
647     case TW_TYPE_FLOAT:
648         {
649             float Val = 0;
650             if( UseGet )
651                 m_GetCallback(&Val, m_ClientData);
652             else
653                 Val = *(float *)m_Ptr;
654             return Val;
655         }
656         break;  
657     case TW_TYPE_DOUBLE:
658         {
659             double Val = 0;
660             if( UseGet )
661                 m_GetCallback(&Val, m_ClientData);
662             else
663                 Val = *(double *)m_Ptr;
664             return Val;
665         }
666         break;
667     /*
668     case TW_TYPE_ENUM8:
669     case TW_TYPE_ENUM16:
670     case TW_TYPE_ENUM32:
671         {
672             unsigned int d = 0;
673             if( m_Type==TW_TYPE_ENUM8 )
674             {
675                 unsigned char Val = 0;
676                 if( UseGet )
677                     m_GetCallback(&Val, m_ClientData);
678                 else
679                     Val = *(unsigned char *)m_Ptr;
680                 d = Val;
681             }
682             else if( m_Type==TW_TYPE_ENUM16 )
683             {
684                 unsigned short Val = 0;
685                 if( UseGet )
686                     m_GetCallback(&Val, m_ClientData);
687                 else
688                     Val = *(unsigned short *)m_Ptr;
689                 d = Val;
690             }
691             else
692             {
693                 assert(m_Type==TW_TYPE_ENUM32);
694                 unsigned int Val = 0;
695                 if( UseGet )
696                     m_GetCallback(&Val, m_ClientData);
697                 else
698                     Val = *(unsigned int *)m_Ptr;
699                 d = Val;
700             }
701             return d;
702         }
703         break;
704     */
705     default:
706         if( IsEnumType(m_Type) )
707         {
708             unsigned int Val = 0;
709             if( UseGet )
710                 m_GetCallback(&Val, m_ClientData);
711             else
712                 Val = *(unsigned int *)m_Ptr;
713             return Val;
714         }
715         else
716             return 0; // unknown type
717     }
718 }
719
720 //  ---------------------------------------------------------------------------
721
722 void CTwVarAtom::ValueFromDouble(double _Val)
723 {
724     if( m_Ptr==NULL && m_SetCallback==NULL )
725         return; // unreachable
726     bool UseSet = (m_SetCallback!=NULL);
727     switch( m_Type )
728     {
729     case TW_TYPE_BOOLCPP:
730         {
731             bool Val = (_Val!=0);
732             if( UseSet )
733                 m_SetCallback(&Val, m_ClientData);
734             else
735                 *(bool*)m_Ptr = Val;
736         }
737         break;
738     case TW_TYPE_BOOL8:
739         {
740             char Val = (_Val!=0) ? 1 : 0;
741             if( UseSet )
742                 m_SetCallback(&Val, m_ClientData);
743             else
744                 *(char*)m_Ptr = Val;
745         }
746         break;
747     case TW_TYPE_BOOL16:
748         {
749             short Val = (_Val!=0) ? 1 : 0;
750             if( UseSet )
751                 m_SetCallback(&Val, m_ClientData);
752             else
753                 *(short*)m_Ptr = Val;
754         }
755         break;
756     case TW_TYPE_BOOL32:
757         {
758             int Val = (_Val!=0) ? 1 : 0;
759             if( UseSet )
760                 m_SetCallback(&Val, m_ClientData);
761             else
762                 *(int*)m_Ptr = Val;
763         }
764         break;
765     case TW_TYPE_CHAR:
766         {
767             unsigned char Val = (unsigned char)_Val;
768             if( UseSet )
769                 m_SetCallback(&Val, m_ClientData);
770             else
771                 *(unsigned char*)m_Ptr = Val;
772         }
773         break;
774     case TW_TYPE_INT8:
775         {
776             signed char Val = (signed char)_Val;
777             if( UseSet )
778                 m_SetCallback(&Val, m_ClientData);
779             else
780                 *(signed char*)m_Ptr = Val;
781         }
782         break;
783     case TW_TYPE_UINT8:
784     //case TW_TYPE_ENUM8:
785         {
786             unsigned char Val = (unsigned char)_Val;
787             if( UseSet )
788                 m_SetCallback(&Val, m_ClientData);
789             else
790                 *(unsigned char*)m_Ptr = Val;
791         }
792         break;
793     case TW_TYPE_INT16:
794         {
795             short Val = (short)_Val;
796             if( UseSet )
797                 m_SetCallback(&Val, m_ClientData);
798             else
799                 *(short*)m_Ptr = Val;
800         }
801         break;
802     case TW_TYPE_UINT16:
803     //case TW_TYPE_ENUM16:
804         {
805             unsigned short Val = (unsigned short)_Val;
806             if( UseSet )
807                 m_SetCallback(&Val, m_ClientData);
808             else
809                 *(unsigned short*)m_Ptr = Val;
810         }
811         break;
812     case TW_TYPE_INT32:
813         {
814             int Val = (int)_Val;
815             if( UseSet )
816                 m_SetCallback(&Val, m_ClientData);
817             else
818                 *(int*)m_Ptr = Val;
819         }
820         break;
821     case TW_TYPE_UINT32:
822     //case TW_TYPE_ENUM32:
823         {
824             unsigned int Val = (unsigned int)_Val;
825             if( UseSet )
826                 m_SetCallback(&Val, m_ClientData);
827             else
828                 *(unsigned int*)m_Ptr = Val;
829         }
830         break;
831     case TW_TYPE_FLOAT:
832         {
833             float Val = (float)_Val;
834             if( UseSet )
835                 m_SetCallback(&Val, m_ClientData);
836             else
837                 *(float*)m_Ptr = Val;
838         }
839         break;
840     case TW_TYPE_DOUBLE:
841         {
842             double Val = (double)_Val;
843             if( UseSet )
844                 m_SetCallback(&Val, m_ClientData);
845             else
846                 *(double*)m_Ptr = Val;
847         }
848         break;
849     default:
850         if( IsEnumType(m_Type) )
851         {
852             unsigned int Val = (unsigned int)_Val;
853             if( UseSet )
854                 m_SetCallback(&Val, m_ClientData);
855             else
856                 *(unsigned int*)m_Ptr = Val;
857         }
858     }
859 }
860
861 //  ---------------------------------------------------------------------------
862
863 void CTwVarAtom::MinMaxStepToDouble(double *_Min, double *_Max, double *_Step) const
864 {
865     double max = DOUBLE_MAX;
866     double min = -DOUBLE_MAX;
867     double step = 1;
868
869     switch( m_Type )
870     {
871     case TW_TYPE_BOOLCPP:
872     case TW_TYPE_BOOL8:
873     case TW_TYPE_BOOL16:
874     case TW_TYPE_BOOL32:
875         min = 0;
876         max = 1;
877         step = 1;
878         break;
879     case TW_TYPE_CHAR:
880         min = (double)m_Val.m_Char.m_Min;
881         max = (double)m_Val.m_Char.m_Max;
882         step = (double)m_Val.m_Char.m_Step;
883         break;
884     case TW_TYPE_INT8:
885         min = (double)m_Val.m_Int8.m_Min;
886         max = (double)m_Val.m_Int8.m_Max;
887         step = (double)m_Val.m_Int8.m_Step;
888         break;
889     case TW_TYPE_UINT8:
890         min = (double)m_Val.m_UInt8.m_Min;
891         max = (double)m_Val.m_UInt8.m_Max;
892         step = (double)m_Val.m_UInt8.m_Step;
893         break;
894     case TW_TYPE_INT16:
895         min = (double)m_Val.m_Int16.m_Min;
896         max = (double)m_Val.m_Int16.m_Max;
897         step = (double)m_Val.m_Int16.m_Step;
898         break;
899     case TW_TYPE_UINT16:
900         min = (double)m_Val.m_UInt16.m_Min;
901         max = (double)m_Val.m_UInt16.m_Max;
902         step = (double)m_Val.m_UInt16.m_Step;
903         break;
904     case TW_TYPE_INT32:
905         min = (double)m_Val.m_Int32.m_Min;
906         max = (double)m_Val.m_Int32.m_Max;
907         step = (double)m_Val.m_Int32.m_Step;
908         break;
909     case TW_TYPE_UINT32:
910         min = (double)m_Val.m_UInt32.m_Min;
911         max = (double)m_Val.m_UInt32.m_Max;
912         step = (double)m_Val.m_UInt32.m_Step;
913         break;
914     case TW_TYPE_FLOAT:
915         min = (double)m_Val.m_Float32.m_Min;
916         max = (double)m_Val.m_Float32.m_Max;
917         step = (double)m_Val.m_Float32.m_Step;
918         break;
919     case TW_TYPE_DOUBLE:
920         min = m_Val.m_Float64.m_Min;
921         max = m_Val.m_Float64.m_Max;
922         step = m_Val.m_Float64.m_Step;
923         break;
924     default:
925         {}  // nothing
926     }
927
928     if( _Min!=NULL )
929         *_Min = min;
930     if( _Max!=NULL )
931         *_Max = max;
932     if( _Step!=NULL )
933         *_Step = step;
934 }
935
936 //  ---------------------------------------------------------------------------
937
938 const CTwVar *CTwVarAtom::Find(const char *_Name, CTwVarGroup **_Parent, int *_Index) const
939 {
940     if( strcmp(_Name, m_Name.c_str())==0 )
941     {
942         if( _Parent!=NULL )
943             *_Parent = NULL;
944         if( _Index!=NULL )
945             *_Index = -1;
946         return this;
947     }
948     else
949         return NULL;
950 }
951
952 //  ---------------------------------------------------------------------------
953
954 enum EVarAttribs
955 {
956     V_LABEL = 1,
957     V_HELP,
958     V_GROUP,
959     V_SHOW,
960     V_HIDE,
961     V_READONLY,
962     V_READWRITE,
963     V_ORDER,
964     V_VISIBLE,
965     V_ENDTAG
966 };
967
968 int CTwVar::HasAttrib(const char *_Attrib, bool *_HasValue) const
969 {
970     *_HasValue = true;
971     if( _stricmp(_Attrib, "label")==0 )
972         return V_LABEL;
973     else if( _stricmp(_Attrib, "help")==0 )
974         return V_HELP;
975     else if( _stricmp(_Attrib, "group")==0 )
976         return V_GROUP;
977     else if( _stricmp(_Attrib, "order")==0 )
978         return V_ORDER;
979     else if( _stricmp(_Attrib, "visible")==0 )
980         return V_VISIBLE;
981     else if( _stricmp(_Attrib, "readonly")==0 )
982         return V_READONLY;
983
984     // for backward compatibility
985     *_HasValue = false;
986     if( _stricmp(_Attrib, "show")==0 )
987         return V_SHOW;
988     else if( _stricmp(_Attrib, "hide")==0 )
989         return V_HIDE;
990     if( _stricmp(_Attrib, "readonly")==0 )
991         return V_READONLY;
992     else if( _stricmp(_Attrib, "readwrite")==0 )
993         return V_READWRITE;
994
995     return 0; // not found
996 }
997
998 int CTwVar::SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex)
999 {
1000     switch( _AttribID )
1001     {
1002     case V_LABEL:
1003     case V_HELP:
1004         if( _Value && strlen(_Value)>0 )
1005         {
1006             /*
1007             if( IsGroup() && static_cast<CTwVarGroup *>(this)->m_StructValuePtr!=NULL )
1008             {
1009                 int Idx = static_cast<CTwVarGroup *>(this)->m_StructType-TW_TYPE_STRUCT_BASE;
1010                 if( Idx>=0 && Idx<(int)g_TwMgr->m_Structs.size() )
1011                     if( _AttribID==V_LABEL )
1012                         g_TwMgr->m_Structs[Idx].m_Label = _Value;
1013                     else // V_HELP
1014                         g_TwMgr->m_Structs[Idx].m_Help = _Value;
1015             }
1016             else
1017             */
1018             {
1019                 CTwVarGroup *Parent = NULL;
1020                 CTwVar *ThisVar = _Bar->Find(m_Name.c_str(), &Parent);
1021                 if( this==ThisVar && Parent!=NULL && Parent->m_StructValuePtr!=NULL )
1022                 {
1023                     int Idx = Parent->m_StructType-TW_TYPE_STRUCT_BASE;
1024                     if( Idx>=0 && Idx<(int)g_TwMgr->m_Structs.size() )
1025                     {
1026                         size_t nl = m_Name.length();
1027                         for( size_t im=0; im<g_TwMgr->m_Structs[Idx].m_Members.size(); ++im )
1028                         {
1029                             size_t ml = g_TwMgr->m_Structs[Idx].m_Members[im].m_Name.length();
1030                             if( nl>=ml && strcmp(g_TwMgr->m_Structs[Idx].m_Members[im].m_Name.c_str(), m_Name.c_str()+(nl-ml))==0 )
1031                             {
1032                                 // TODO: would have to be applied to other vars already created
1033                                 if( _AttribID==V_LABEL )
1034                                 {
1035                                     g_TwMgr->m_Structs[Idx].m_Members[im].m_Label = _Value;
1036 //                                    m_Label = _Value;
1037                                 }
1038                                 else // V_HELP
1039                                     g_TwMgr->m_Structs[Idx].m_Members[im].m_Help = _Value;
1040                                 break;
1041                             }
1042                         }
1043                     }
1044                 }
1045                 else
1046                 {
1047                     if( _AttribID==V_LABEL )
1048                         m_Label = _Value;
1049                     else // V_HELP
1050                         m_Help = _Value;
1051                 }
1052             }
1053             _Bar->NotUpToDate();
1054             return 1;
1055         }
1056         else
1057         {
1058             g_TwMgr->SetLastError(g_ErrNoValue);
1059             return 0;
1060         }
1061     case V_GROUP:
1062         {
1063             CTwVarGroup *Grp = NULL;
1064             if( _Value==NULL || strlen(_Value)<=0 )
1065                 Grp = &(_Bar->m_VarRoot);
1066             else
1067             {
1068                 CTwVar *v = _Bar->Find(_Value, NULL, NULL);
1069                 if( v && !v->IsGroup() )
1070                 {
1071                     g_TwMgr->SetLastError(g_ErrNotGroup);
1072                     return 0;
1073                 }
1074                 Grp = static_cast<CTwVarGroup *>(v);
1075                 if( Grp==NULL )
1076                 {
1077                     Grp = new CTwVarGroup;
1078                     Grp->m_Name = _Value;
1079                     Grp->m_Open = true;
1080                     Grp->m_SummaryCallback = NULL;
1081                     Grp->m_SummaryClientData = NULL;
1082                     Grp->m_StructValuePtr = NULL;
1083                     Grp->m_ColorPtr = &(_Bar->m_ColGrpText);
1084                     _Bar->m_VarRoot.m_Vars.push_back(Grp);
1085                 }
1086             }
1087             Grp->m_Vars.push_back(this);
1088             if( _VarParent!=NULL && _VarIndex>=0 )
1089             {
1090                 _VarParent->m_Vars.erase(_VarParent->m_Vars.begin()+_VarIndex);
1091                 if( _VarParent!=&(_Bar->m_VarRoot) && _VarParent->m_Vars.size()<=0 )
1092                     TwRemoveVar(_Bar, _VarParent->m_Name.c_str());
1093             }
1094             _Bar->NotUpToDate();
1095             return 1;           
1096         }
1097     case V_SHOW: // for backward compatibility
1098         if( !m_Visible )
1099         {
1100             m_Visible = true;
1101             _Bar->NotUpToDate();
1102         }
1103         return 1;
1104     case V_HIDE: // for backward compatibility
1105         if( m_Visible )
1106         {
1107             m_Visible = false;
1108             _Bar->NotUpToDate();
1109         }
1110         return 1;
1111     /*
1112     case V_READONLY:
1113         SetReadOnly(true);
1114         _Bar->NotUpToDate();
1115         return 1;
1116     */
1117     case V_READWRITE: // for backward compatibility
1118         SetReadOnly(false);
1119         _Bar->NotUpToDate();
1120         return 1;
1121     case V_ORDER:
1122         // a special case for compatibility with deprecated command 'option=ogl/dx'
1123         if( IsGroup() && _Value!=NULL && static_cast<CTwVarGroup *>(this)->m_SummaryCallback==CColorExt::SummaryCB && static_cast<CTwVarGroup *>(this)->m_StructValuePtr!=NULL ) // is tw_type_color?
1124         {
1125             if( _stricmp(_Value, "ogl")==0 )
1126             {
1127                 static_cast<CColorExt *>(static_cast<CTwVarGroup *>(this)->m_StructValuePtr)->m_OGL = true;
1128                 return 1;
1129             }
1130             else if( _stricmp(_Value, "dx")==0 )
1131             {
1132                 static_cast<CColorExt *>(static_cast<CTwVarGroup *>(this)->m_StructValuePtr)->m_OGL = false;
1133                 return 1;
1134             }
1135         }
1136         // todo: general 'order' command (no else)
1137         return 0;
1138     case V_VISIBLE:
1139         if( _Value!=NULL && strlen(_Value)>0 )
1140         {
1141             if( _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 )
1142             {
1143                 if( !m_Visible )
1144                 {
1145                     m_Visible = true;
1146                     _Bar->NotUpToDate();
1147                 }
1148                 return 1;
1149             }
1150             else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "0")==0 )
1151             {
1152                 if( m_Visible )
1153                 {
1154                     m_Visible = false;
1155                     _Bar->NotUpToDate();
1156                 }
1157                 return 1;
1158             }
1159             else
1160             {
1161                 g_TwMgr->SetLastError(g_ErrBadValue);
1162                 return 0;
1163             }
1164         }
1165         else
1166         {
1167             g_TwMgr->SetLastError(g_ErrNoValue);
1168             return 0;
1169         }
1170     case V_READONLY:
1171         if( _Value==NULL || strlen(_Value)==0 // no value is acceptable (for backward compatibility)
1172             || _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 )
1173         {
1174             if( !IsReadOnly() )
1175             {
1176                 SetReadOnly(true);
1177                 _Bar->NotUpToDate();
1178             }
1179             return 1;
1180         }
1181         else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "0")==0 )
1182         {
1183             if( IsReadOnly() )
1184             {
1185                 SetReadOnly(false);
1186                 _Bar->NotUpToDate();
1187             }
1188             return 1;
1189         }
1190         else
1191         {
1192             g_TwMgr->SetLastError(g_ErrBadValue);
1193             return 0;
1194         }
1195     default:
1196         g_TwMgr->SetLastError(g_ErrUnknownAttrib);
1197         return 0;
1198     }
1199 }
1200
1201
1202 ERetType CTwVar::GetAttrib(int _AttribID, TwBar * /*_Bar*/, CTwVarGroup * _VarParent, int /*_VarIndex*/, std::vector<double>& outDoubles, std::ostringstream& outString) const
1203 {
1204     outDoubles.clear();
1205     outString.clear();
1206
1207     switch( _AttribID )
1208     {
1209     case V_LABEL:
1210         outString << m_Label;
1211         return RET_STRING;
1212     case V_HELP:
1213         outString << m_Help;
1214         return RET_STRING;
1215     case V_GROUP:
1216         if( _VarParent!=NULL )
1217             outString << _VarParent->m_Name;
1218         return RET_STRING;
1219     case V_VISIBLE:
1220         outDoubles.push_back(m_Visible ? 1 : 0);
1221         return RET_DOUBLE;
1222     case V_READONLY:
1223         outDoubles.push_back(IsReadOnly() ? 1 : 0);
1224         return RET_DOUBLE;
1225     default:
1226         g_TwMgr->SetLastError(g_ErrUnknownAttrib);
1227         return RET_ERROR;
1228     }
1229 }
1230
1231
1232 //  ---------------------------------------------------------------------------
1233
1234 enum EVarAtomAttribs
1235 {
1236     VA_KEY_INCR = V_ENDTAG+1,
1237     VA_KEY_DECR,
1238     VA_MIN,
1239     VA_MAX,
1240     VA_STEP,
1241     VA_PRECISION,
1242     VA_HEXA,
1243     VA_DECIMAL, // for backward compatibility
1244     VA_TRUE,
1245     VA_FALSE,
1246     VA_ENUM,
1247     VA_VALUE
1248 };
1249
1250 int CTwVarAtom::HasAttrib(const char *_Attrib, bool *_HasValue) const
1251 {
1252     *_HasValue = true;
1253     if( _stricmp(_Attrib, "keyincr")==0 || _stricmp(_Attrib, "key")==0 )
1254         return VA_KEY_INCR;
1255     else if( _stricmp(_Attrib, "keydecr")==0 )
1256         return VA_KEY_DECR;
1257     else if( _stricmp(_Attrib, "min")==0 )
1258         return VA_MIN;
1259     else if( _stricmp(_Attrib, "max")==0 )
1260         return VA_MAX;
1261     else if( _stricmp(_Attrib, "step")==0 )
1262         return VA_STEP;
1263     else if( _stricmp(_Attrib, "precision")==0 )
1264         return VA_PRECISION;
1265     else if( _stricmp(_Attrib, "hexa")==0 )
1266         return VA_HEXA;
1267     else if( _stricmp(_Attrib, "decimal")==0 ) // for backward compatibility
1268     {
1269         *_HasValue = false;
1270         return VA_DECIMAL;
1271     }
1272     else if( _stricmp(_Attrib, "true")==0 )
1273         return VA_TRUE;
1274     else if( _stricmp(_Attrib, "false")==0 )
1275         return VA_FALSE;
1276     else if( _stricmp(_Attrib, "enum")==0 
1277              || _stricmp(_Attrib, "val")==0 ) // for backward compatibility
1278         return VA_ENUM;
1279     else if( _stricmp(_Attrib, "value")==0 )
1280         return VA_VALUE;
1281
1282     return CTwVar::HasAttrib(_Attrib, _HasValue);
1283 }
1284
1285 int CTwVarAtom::SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex)
1286 {
1287     switch( _AttribID )
1288     {
1289     case VA_KEY_INCR:
1290         {
1291             int Key = 0;
1292             int Mod = 0;
1293             if( TwGetKeyCode(&Key, &Mod, _Value) )
1294             {
1295                 m_KeyIncr[0] = Key;
1296                 m_KeyIncr[1] = Mod;
1297                 return 1;
1298             }
1299             else
1300                 return 0;
1301         }
1302     case VA_KEY_DECR:
1303         {
1304             int Key = 0;
1305             int Mod = 0;
1306             if( TwGetKeyCode(&Key, &Mod, _Value) )
1307             {
1308                 m_KeyDecr[0] = Key;
1309                 m_KeyDecr[1] = Mod;
1310                 return 1;
1311             }
1312             else
1313                 return 0;
1314         }
1315     case VA_TRUE:
1316         if( (m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP) && _Value!=NULL )
1317         {
1318             if( m_Val.m_Bool.m_FreeTrueString && m_Val.m_Bool.m_TrueString!=NULL )
1319                 free(m_Val.m_Bool.m_TrueString);
1320             m_Val.m_Bool.m_TrueString = _strdup(_Value);
1321             m_Val.m_Bool.m_FreeTrueString = true;
1322             return 1;
1323         }
1324         else
1325             return 0;
1326     case VA_FALSE:
1327         if( (m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP) && _Value!=NULL )
1328         {
1329             if( m_Val.m_Bool.m_FreeFalseString && m_Val.m_Bool.m_FalseString!=NULL )
1330                 free(m_Val.m_Bool.m_FalseString);
1331             m_Val.m_Bool.m_FalseString = _strdup(_Value);
1332             m_Val.m_Bool.m_FreeFalseString = true;
1333             return 1;
1334         }
1335         else
1336             return 0;
1337     case VA_MIN:
1338     case VA_MAX:
1339     case VA_STEP:
1340         if( _Value && strlen(_Value)>0 )
1341         {
1342             void *Ptr = NULL;
1343             const char *Fmt = NULL;
1344             int d = 0;
1345             unsigned int u = 0;
1346             int Num = (_AttribID==VA_STEP) ? 2 : ((_AttribID==VA_MAX) ? 1 : 0);
1347             switch( m_Type )
1348             {
1349             case TW_TYPE_CHAR:
1350                 //Ptr = (&m_Val.m_Char.m_Min) + Num;
1351                 //Fmt = "%c";
1352                 Ptr = &u;
1353                 Fmt = "%u";
1354                 break;
1355             case TW_TYPE_INT16:
1356                 Ptr = (&m_Val.m_Int16.m_Min) + Num;
1357                 Fmt = "%hd";
1358                 break;
1359             case TW_TYPE_INT32:
1360                 Ptr = (&m_Val.m_Int32.m_Min) + Num;
1361                 Fmt = "%d";
1362                 break;
1363             case TW_TYPE_UINT16:
1364                 Ptr = (&m_Val.m_UInt16.m_Min) + Num;
1365                 Fmt = "%hu";
1366                 break;
1367             case TW_TYPE_UINT32:
1368                 Ptr = (&m_Val.m_UInt32.m_Min) + Num;
1369                 Fmt = "%u";
1370                 break;
1371             case TW_TYPE_FLOAT:
1372                 Ptr = (&m_Val.m_Float32.m_Min) + Num;
1373                 Fmt = "%f";
1374                 break;
1375             case TW_TYPE_DOUBLE:
1376                 Ptr = (&m_Val.m_Float64.m_Min) + Num;
1377                 Fmt = "%lf";
1378                 break;
1379             case TW_TYPE_INT8:
1380                 Ptr = &d;
1381                 Fmt = "%d";
1382                 break;
1383             case TW_TYPE_UINT8:
1384                 Ptr = &u;
1385                 Fmt = "%u";
1386                 break;
1387             default:
1388                 g_TwMgr->SetLastError(g_ErrUnknownType);
1389                 return 0;
1390             }
1391
1392             if( Fmt!=NULL && Ptr!=NULL && sscanf(_Value, Fmt, Ptr)==1 )
1393             {
1394                 if( m_Type==TW_TYPE_CHAR )
1395                     *((&m_Val.m_Char.m_Min)+Num) = (unsigned char)(u);
1396                 else if( m_Type==TW_TYPE_INT8 )
1397                     *((&m_Val.m_Int8.m_Min)+Num) = (signed char)(d);
1398                 else if( m_Type==TW_TYPE_UINT8 )
1399                     *((&m_Val.m_UInt8.m_Min)+Num) = (unsigned char)(u);
1400
1401                 // set precision
1402                 if( _AttribID==VA_STEP && ((m_Type==TW_TYPE_FLOAT && m_Val.m_Float32.m_Precision<0) || (m_Type==TW_TYPE_DOUBLE && m_Val.m_Float64.m_Precision<0)) )
1403                 {
1404                     double Step = fabs( (m_Type==TW_TYPE_FLOAT) ? m_Val.m_Float32.m_Step : m_Val.m_Float64.m_Step );
1405                     signed char *Precision = (m_Type==TW_TYPE_FLOAT) ? &m_Val.m_Float32.m_Precision : &m_Val.m_Float64.m_Precision;
1406                     const double K_EPS = 1.0 - 1.0e-6;
1407                     if( Step>=1 )
1408                         *Precision = 0;
1409                     else if( Step>=0.1*K_EPS )
1410                         *Precision = 1;
1411                     else if( Step>=0.01*K_EPS )
1412                         *Precision = 2;
1413                     else if( Step>=0.001*K_EPS )
1414                         *Precision = 3;
1415                     else if( Step>=0.0001*K_EPS )
1416                         *Precision = 4;
1417                     else if( Step>=0.00001*K_EPS )
1418                         *Precision = 5;
1419                     else if( Step>=0.000001*K_EPS )
1420                         *Precision = 6;
1421                     else if( Step>=0.0000001*K_EPS )
1422                         *Precision = 7;
1423                     else if( Step>=0.00000001*K_EPS )
1424                         *Precision = 8;
1425                     else if( Step>=0.000000001*K_EPS )
1426                         *Precision = 9;
1427                     else if( Step>=0.0000000001*K_EPS )
1428                         *Precision = 10;
1429                     else if( Step>=0.00000000001*K_EPS )
1430                         *Precision = 11;
1431                     else if( Step>=0.000000000001*K_EPS )
1432                         *Precision = 12;
1433                     else
1434                         *Precision = -1;
1435                 }
1436
1437                 return 1;
1438             }
1439             else
1440             {
1441                 g_TwMgr->SetLastError(g_ErrBadValue);
1442                 return 0;
1443             }
1444         }
1445         else
1446         {
1447             g_TwMgr->SetLastError(g_ErrNoValue);
1448             return 0;
1449         }
1450     case VA_PRECISION:
1451         if( _Value && strlen(_Value)>0 )
1452         {
1453             int Precision = 0;
1454             if( sscanf(_Value, "%d", &Precision)==1 && Precision>=-1 && Precision<=12 )
1455             {
1456                 if( m_Type==TW_TYPE_FLOAT )
1457                     m_Val.m_Float32.m_Precision = (signed char)Precision;
1458                 else if ( m_Type==TW_TYPE_DOUBLE )
1459                     m_Val.m_Float64.m_Precision = (signed char)Precision;
1460                 return 1;
1461             }
1462             else
1463             {
1464                 g_TwMgr->SetLastError(g_ErrBadValue);
1465                 return 0;
1466             }
1467         }
1468         else
1469         {
1470             g_TwMgr->SetLastError(g_ErrNoValue);
1471             return 0;
1472         }
1473     case VA_HEXA:
1474     case VA_DECIMAL:
1475         {
1476             bool hexa = false;
1477             if (_AttribID==VA_HEXA) 
1478             {
1479                 if( _Value==NULL || strlen(_Value)==0 // no value is acceptable (for backward compatibility)
1480                     || _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 )
1481                     hexa = true;
1482             }
1483
1484             switch( m_Type )
1485             {
1486             case TW_TYPE_CHAR:
1487                 m_Val.m_Char.m_Hexa = hexa;
1488                 return 1;
1489             case TW_TYPE_INT8:
1490                 m_Val.m_Int8.m_Hexa = hexa;
1491                 return 1;
1492             case TW_TYPE_INT16:
1493                 m_Val.m_Int16.m_Hexa = hexa;
1494                 return 1;
1495             case TW_TYPE_INT32:
1496                 m_Val.m_Int32.m_Hexa = hexa;
1497                 return 1;
1498             case TW_TYPE_UINT8:
1499                 m_Val.m_UInt8.m_Hexa = hexa;
1500                 return 1;
1501             case TW_TYPE_UINT16:
1502                 m_Val.m_UInt16.m_Hexa = hexa;
1503                 return 1;
1504             case TW_TYPE_UINT32:
1505                 m_Val.m_UInt32.m_Hexa = hexa;
1506                 return 1;
1507             default:
1508                 return 0;
1509             }
1510         }
1511     case VA_ENUM:
1512         if( _Value && strlen(_Value)>0 && IsEnumType(m_Type) )
1513         {
1514             const char *s = _Value;
1515             int n = 0, i = 0;
1516             unsigned int u;
1517             bool Cont;
1518             g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.clear(); // anyway reset entries
1519             do
1520             {
1521                 Cont = false;
1522                 i = 0;
1523                 char Sep;
1524                 n = sscanf(s, "%u %c%n", &u, &Sep, &i);
1525                 if( n==2 && i>0 && ( Sep=='<' || Sep=='{' || Sep=='[' || Sep=='(' ) )
1526                 {
1527                     if( Sep=='<' )  // Change to closing separator
1528                         Sep = '>';
1529                     else if( Sep=='{' )
1530                         Sep = '}';
1531                     else if( Sep=='[' )
1532                         Sep = ']';
1533                     else if( Sep=='(' )
1534                         Sep = ')';
1535                     s += i;
1536                     i = 0;
1537                     while( s[i]!=Sep && s[i]!=0 )
1538                         ++i;
1539                     if( s[i]==Sep )
1540                     {
1541                         //if( m_Val.m_Enum.m_Entries==NULL )
1542                         //  m_Val.m_Enum.m_Entries = new UVal::CEnumVal::CEntries;
1543                         //UVal::CEnumVal::CEntries::value_type v(u, "");
1544                         CTwMgr::CEnum::CEntries::value_type v(u, "");
1545                         if( i>0 )
1546                             v.second.assign(s, i);
1547                         //m_Val.m_Enum.m_Entries->insert(v);
1548                         pair<CTwMgr::CEnum::CEntries::iterator, bool> ret;
1549                         ret = g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.insert(v);
1550                         if( !ret.second ) // force overwrite if element already exists
1551                         {
1552                             g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.erase(ret.first);
1553                             g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.insert(v);
1554                         }
1555
1556                         s += i+1;
1557                         i = 0;
1558                         n = sscanf(s, " ,%n", &i);
1559                         if( n==0 && i>=1 )
1560                         {
1561                             s += i;
1562                             Cont = true;
1563                         }
1564                     }
1565                     else
1566                     {
1567                         g_TwMgr->SetLastError(g_ErrBadValue);
1568                         return 0;
1569                     }
1570                 }
1571                 else
1572                 {
1573                     g_TwMgr->SetLastError(g_ErrBadValue);
1574                     return 0;
1575                 }
1576             } while( Cont );
1577             return 1;
1578         }
1579         else
1580         {
1581             g_TwMgr->SetLastError(g_ErrNoValue);
1582             return 0;
1583         }
1584         break;
1585     case VA_VALUE:
1586         if( _Value!=NULL && strlen(_Value)>0 ) // do not check ReadOnly here.
1587         {
1588             if( !( m_Type==TW_TYPE_BUTTON || IsCustom() ) ) // || (m_Type>=TW_TYPE_CUSTOM_BASE && m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size()) ) )
1589             {
1590                 if( m_Type==TW_TYPE_CDSTRING || m_Type==TW_TYPE_CDSTDSTRING )
1591                 {
1592                     if( m_SetCallback!=NULL )
1593                     {
1594                         m_SetCallback(&_Value, m_ClientData);
1595                         if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call
1596                             _Bar->NotUpToDate();
1597                         return 1;
1598                     }
1599                     else if( m_Type!=TW_TYPE_CDSTDSTRING )
1600                     {
1601                         char **StringPtr = (char **)m_Ptr;
1602                         if( StringPtr!=NULL && g_TwMgr->m_CopyCDStringToClient!=NULL )
1603                         {
1604                             g_TwMgr->m_CopyCDStringToClient(StringPtr, _Value);
1605                             _Bar->NotUpToDate();
1606                             return 1;
1607                         }
1608                     }
1609                 }
1610                 else if( IsCSStringType(m_Type) )
1611                 {
1612                     int n = TW_CSSTRING_SIZE(m_Type);
1613                     if( n>0 )
1614                     {
1615                         string str = _Value;
1616                         if( (int)str.length()>n-1 )
1617                             str.resize(n-1);
1618                         if( m_SetCallback!=NULL )
1619                         {
1620                             m_SetCallback(str.c_str(), m_ClientData);
1621                             if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call
1622                                 _Bar->NotUpToDate();
1623                             return 1;
1624                         }
1625                         else if( m_Ptr!=NULL )
1626                         {
1627                             if( n>1 )
1628                                 strncpy((char *)m_Ptr, str.c_str(), n-1);
1629                             ((char *)m_Ptr)[n-1] = '\0';
1630                             _Bar->NotUpToDate();
1631                             return 1;
1632                         }
1633                     }
1634                 }
1635                 else
1636                 {
1637                     double dbl;
1638                     if( sscanf(_Value, "%lf", &dbl)==1 )
1639                     {
1640                         ValueFromDouble(dbl);
1641                         if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call
1642                             _Bar->NotUpToDate();
1643                         return 1;
1644                     }
1645                 }
1646             }
1647         }
1648         return 0;
1649     default:
1650         return CTwVar::SetAttrib(_AttribID, _Value, _Bar, _VarParent, _VarIndex);
1651     }
1652 }
1653
1654 ERetType CTwVarAtom::GetAttrib(int _AttribID, TwBar *_Bar, CTwVarGroup *_VarParent, int _VarIndex, std::vector<double>& outDoubles, std::ostringstream& outString) const
1655 {
1656     outDoubles.clear();
1657     outString.clear();
1658     std::string str;
1659     int num = 0;
1660
1661     switch( _AttribID )
1662     {
1663     case VA_KEY_INCR:
1664         if( TwGetKeyString(&str, m_KeyIncr[0], m_KeyIncr[1]) )
1665             outString << str;
1666         return RET_STRING;
1667     case VA_KEY_DECR:
1668         if( TwGetKeyString(&str, m_KeyDecr[0], m_KeyDecr[1]) )
1669             outString << str;
1670         return RET_STRING;
1671     case VA_TRUE:
1672         if( m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP )
1673         {
1674             outString << m_Val.m_Bool.m_TrueString;
1675             return RET_STRING;
1676         }
1677         else
1678         {
1679             g_TwMgr->SetLastError(g_ErrInvalidAttrib);
1680             return RET_ERROR;
1681         }
1682     case VA_FALSE:
1683         if( m_Type==TW_TYPE_BOOL8 || m_Type==TW_TYPE_BOOL16 || m_Type==TW_TYPE_BOOL32 || m_Type==TW_TYPE_BOOLCPP )
1684         {
1685             outString << m_Val.m_Bool.m_FalseString;
1686             return RET_STRING;
1687         }
1688         else
1689         {
1690             g_TwMgr->SetLastError(g_ErrInvalidAttrib);
1691             return RET_ERROR;
1692         }
1693     case VA_MIN:
1694     case VA_MAX:
1695     case VA_STEP:
1696         num = (_AttribID==VA_STEP) ? 2 : ((_AttribID==VA_MAX) ? 1 : 0);
1697         switch( m_Type )
1698         {
1699         case TW_TYPE_CHAR:
1700             outDoubles.push_back( *((&m_Val.m_Char.m_Min) + num) );
1701             return RET_DOUBLE;
1702         case TW_TYPE_INT8:
1703             outDoubles.push_back( *((&m_Val.m_Int8.m_Min) + num) );
1704             return RET_DOUBLE;
1705         case TW_TYPE_UINT8:
1706             outDoubles.push_back( *((&m_Val.m_UInt8.m_Min) + num) );
1707             return RET_DOUBLE;
1708         case TW_TYPE_INT16:
1709             outDoubles.push_back( *((&m_Val.m_Int16.m_Min) + num) );
1710             return RET_DOUBLE;
1711         case TW_TYPE_INT32:
1712             outDoubles.push_back( *((&m_Val.m_Int32.m_Min) + num) );
1713             return RET_DOUBLE;
1714         case TW_TYPE_UINT16:
1715             outDoubles.push_back( *((&m_Val.m_UInt16.m_Min) + num) );
1716             return RET_DOUBLE;
1717         case TW_TYPE_UINT32:
1718             outDoubles.push_back( *((&m_Val.m_UInt32.m_Min) + num) );
1719             return RET_DOUBLE;
1720         case TW_TYPE_FLOAT:
1721             outDoubles.push_back( *((&m_Val.m_Float32.m_Min) + num) );
1722             return RET_DOUBLE;
1723         case TW_TYPE_DOUBLE:
1724             outDoubles.push_back( *((&m_Val.m_Float64.m_Min) + num) );
1725             return RET_DOUBLE;
1726         default:
1727             g_TwMgr->SetLastError(g_ErrInvalidAttrib);
1728             return RET_ERROR;
1729         }
1730     case VA_PRECISION:
1731         if( m_Type==TW_TYPE_FLOAT )
1732         {
1733             outDoubles.push_back( m_Val.m_Float32.m_Precision );
1734             return RET_DOUBLE;
1735         }
1736         else if ( m_Type==TW_TYPE_DOUBLE )
1737         {
1738             outDoubles.push_back( m_Val.m_Float64.m_Precision );
1739             return RET_DOUBLE;
1740         }
1741         else
1742         {
1743             g_TwMgr->SetLastError(g_ErrInvalidAttrib);
1744             return RET_ERROR;
1745         }
1746     case VA_HEXA:
1747         switch( m_Type )
1748         {
1749         case TW_TYPE_CHAR:
1750             outDoubles.push_back( m_Val.m_Char.m_Hexa );
1751             return RET_DOUBLE;
1752         case TW_TYPE_INT8:
1753             outDoubles.push_back( m_Val.m_Int8.m_Hexa );
1754             return RET_DOUBLE;
1755         case TW_TYPE_INT16:
1756             outDoubles.push_back( m_Val.m_Int16.m_Hexa );
1757             return RET_DOUBLE;
1758         case TW_TYPE_INT32:
1759             outDoubles.push_back( m_Val.m_Int32.m_Hexa );
1760             return RET_DOUBLE;
1761         case TW_TYPE_UINT8:
1762             outDoubles.push_back( m_Val.m_UInt8.m_Hexa );
1763             return RET_DOUBLE;
1764         case TW_TYPE_UINT16:
1765             outDoubles.push_back( m_Val.m_UInt16.m_Hexa );
1766             return RET_DOUBLE;
1767         case TW_TYPE_UINT32:
1768             outDoubles.push_back( m_Val.m_UInt32.m_Hexa );
1769             return RET_DOUBLE;
1770         default:
1771             g_TwMgr->SetLastError(g_ErrInvalidAttrib);
1772             return RET_ERROR;
1773         }
1774     case VA_ENUM:
1775         if( IsEnumType(m_Type) )
1776         {
1777             CTwMgr::CEnum::CEntries::iterator it = g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.begin();
1778             for( ; it != g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.end(); ++it )
1779             {
1780                 if( it != g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE].m_Entries.begin() )
1781                     outString << ',';
1782                 outString << it->first << ' ';
1783                 if( it->second.find_first_of("{}")==std::string::npos )
1784                     outString << '{' << it->second << '}';
1785                 else if ( it->second.find_first_of("<>")==std::string::npos )
1786                     outString << '<' << it->second << '>';
1787                 else if ( it->second.find_first_of("()")==std::string::npos )
1788                     outString << '(' << it->second << ')';
1789                 else if ( it->second.find_first_of("[]")==std::string::npos )
1790                     outString << '[' << it->second << ']';
1791                 else
1792                     outString << '{' << it->second << '}'; // should not occured (use braces)
1793             }
1794             return RET_STRING;
1795         }
1796         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
1797         return RET_ERROR;
1798     case VA_VALUE:
1799         if( !( m_Type==TW_TYPE_BUTTON || IsCustom() ) ) // || (m_Type>=TW_TYPE_CUSTOM_BASE && m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size()) ) )
1800         {
1801             if( m_Type==TW_TYPE_CDSTRING || m_Type==TW_TYPE_CDSTDSTRING || IsCSStringType(m_Type) )
1802             {
1803                 string str;
1804                 ValueToString(&str);
1805                 outString << str;
1806                 return RET_STRING;
1807             }
1808             else
1809             {
1810                 outDoubles.push_back( ValueToDouble() );
1811                 return RET_DOUBLE;
1812             }
1813         }
1814         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
1815         return RET_ERROR;
1816     default:
1817         return CTwVar::GetAttrib(_AttribID, _Bar, _VarParent, _VarIndex, outDoubles, outString);
1818     }
1819 }
1820
1821 //  ---------------------------------------------------------------------------
1822
1823 void CTwVarAtom::Increment(int _Step)
1824 {
1825     if( _Step==0 )
1826         return;
1827     switch( m_Type )
1828     {
1829     case TW_TYPE_BOOL8:
1830         {
1831             char v = false;
1832             if( m_Ptr!=NULL )
1833                 v = *((char *)m_Ptr);
1834             else if( m_GetCallback!=NULL )
1835                 m_GetCallback(&v, m_ClientData);
1836             if( v )
1837                 v = false;
1838             else
1839                 v = true;
1840             if( m_Ptr!=NULL )
1841                 *((char *)m_Ptr) = v;
1842             else if( m_SetCallback!=NULL )
1843                 m_SetCallback(&v, m_ClientData);
1844         }
1845         break;
1846     case TW_TYPE_BOOL16:
1847         {
1848             short v = false;
1849             if( m_Ptr!=NULL )
1850                 v = *((short *)m_Ptr);
1851             else if( m_GetCallback!=NULL )
1852                 m_GetCallback(&v, m_ClientData);
1853             if( v )
1854                 v = false;
1855             else
1856                 v = true;
1857             if( m_Ptr!=NULL )
1858                 *((short *)m_Ptr) = v;
1859             else if( m_SetCallback!=NULL )
1860                 m_SetCallback(&v, m_ClientData);
1861         }
1862         break;
1863     case TW_TYPE_BOOL32:
1864         {
1865             int v = false;
1866             if( m_Ptr!=NULL )
1867                 v = *((int *)m_Ptr);
1868             else if( m_GetCallback!=NULL )
1869                 m_GetCallback(&v, m_ClientData);
1870             if( v )
1871                 v = false;
1872             else
1873                 v = true;
1874             if( m_Ptr!=NULL )
1875                 *((int *)m_Ptr) = v;
1876             else if( m_SetCallback!=NULL )
1877                 m_SetCallback(&v, m_ClientData);
1878         }
1879         break;
1880     case TW_TYPE_BOOLCPP:
1881         {
1882             bool v = false;
1883             if( m_Ptr!=NULL )
1884                 v = *((bool *)m_Ptr);
1885             else if( m_GetCallback!=NULL )
1886                 m_GetCallback(&v, m_ClientData);
1887             if( v )
1888                 v = false;
1889             else
1890                 v = true;
1891             if( m_Ptr!=NULL )
1892                 *((bool *)m_Ptr) = v;
1893             else if( m_SetCallback!=NULL )
1894                 m_SetCallback(&v, m_ClientData);
1895         }
1896         break;
1897     case TW_TYPE_CHAR:
1898         {
1899             unsigned char v = 0;
1900             if( m_Ptr!=NULL )
1901                 v = *((unsigned char *)m_Ptr);
1902             else if( m_GetCallback!=NULL )
1903                 m_GetCallback(&v, m_ClientData);
1904             int iv = _Step*(int)m_Val.m_Char.m_Step + (int)v;
1905             if( iv<m_Val.m_Char.m_Min )
1906                 iv = m_Val.m_Char.m_Min;
1907             if( iv>m_Val.m_Char.m_Max )
1908                 iv = m_Val.m_Char.m_Max;
1909             if( iv<0 )
1910                 iv = 0;
1911             else if( iv>0xff )
1912                 iv = 0xff;
1913             v = (unsigned char)iv;
1914             if( m_Ptr!=NULL )
1915                 *((unsigned char *)m_Ptr) = v;
1916             else if( m_SetCallback!=NULL )
1917                 m_SetCallback(&v, m_ClientData);
1918         }
1919         break;
1920     case TW_TYPE_INT8:
1921         {
1922             signed char v = 0;
1923             if( m_Ptr!=NULL )
1924                 v = *((signed char *)m_Ptr);
1925             else if( m_GetCallback!=NULL )
1926                 m_GetCallback(&v, m_ClientData);
1927             int iv = _Step*(int)m_Val.m_Int8.m_Step + (int)v;
1928             if( iv<m_Val.m_Int8.m_Min )
1929                 iv = m_Val.m_Int8.m_Min;
1930             if( iv>m_Val.m_Int8.m_Max )
1931                 iv = m_Val.m_Int8.m_Max;
1932             v = (signed char)iv;
1933             if( m_Ptr!=NULL )
1934                 *((signed char *)m_Ptr) = v;
1935             else if( m_SetCallback!=NULL )
1936                 m_SetCallback(&v, m_ClientData);
1937         }
1938         break;
1939     case TW_TYPE_UINT8:
1940         {
1941             unsigned char v = 0;
1942             if( m_Ptr!=NULL )
1943                 v = *((unsigned char *)m_Ptr);
1944             else if( m_GetCallback!=NULL )
1945                 m_GetCallback(&v, m_ClientData);
1946             int iv = _Step*(int)m_Val.m_UInt8.m_Step + (int)v;
1947             if( iv<m_Val.m_UInt8.m_Min )
1948                 iv = m_Val.m_UInt8.m_Min;
1949             if( iv>m_Val.m_UInt8.m_Max )
1950                 iv = m_Val.m_UInt8.m_Max;
1951             if( iv<0 )
1952                 iv = 0;
1953             else if( iv>0xff )
1954                 iv = 0xff;
1955             v = (unsigned char)iv;
1956             if( m_Ptr!=NULL )
1957                 *((unsigned char *)m_Ptr) = v;
1958             else if( m_SetCallback!=NULL )
1959                 m_SetCallback(&v, m_ClientData);
1960         }
1961         break;
1962     case TW_TYPE_INT16:
1963         {
1964             short v = 0;
1965             if( m_Ptr!=NULL )
1966                 v = *((short *)m_Ptr);
1967             else if( m_GetCallback!=NULL )
1968                 m_GetCallback(&v, m_ClientData);
1969             int iv = _Step*(int)m_Val.m_Int16.m_Step + (int)v;
1970             if( iv<m_Val.m_Int16.m_Min )
1971                 iv = m_Val.m_Int16.m_Min;
1972             if( iv>m_Val.m_Int16.m_Max )
1973                 iv = m_Val.m_Int16.m_Max;
1974             v = (short)iv;
1975             if( m_Ptr!=NULL )
1976                 *((short *)m_Ptr) = v;
1977             else if( m_SetCallback!=NULL )
1978                 m_SetCallback(&v, m_ClientData);
1979         }
1980         break;
1981     case TW_TYPE_UINT16:
1982         {
1983             unsigned short v = 0;
1984             if( m_Ptr!=NULL )
1985                 v = *((unsigned short *)m_Ptr);
1986             else if( m_GetCallback!=NULL )
1987                 m_GetCallback(&v, m_ClientData);
1988             int iv = _Step*(int)m_Val.m_UInt16.m_Step + (int)v;
1989             if( iv<m_Val.m_UInt16.m_Min )
1990                 iv = m_Val.m_UInt16.m_Min;
1991             if( iv>m_Val.m_UInt16.m_Max )
1992                 iv = m_Val.m_UInt16.m_Max;
1993             if( iv<0 )
1994                 iv = 0;
1995             else if( iv>0xffff )
1996                 iv = 0xffff;
1997             v = (unsigned short)iv;
1998             if( m_Ptr!=NULL )
1999                 *((unsigned short *)m_Ptr) = v;
2000             else if( m_SetCallback!=NULL )
2001                 m_SetCallback(&v, m_ClientData);
2002         }
2003         break;
2004     case TW_TYPE_INT32:
2005         {
2006             int v = 0;
2007             if( m_Ptr!=NULL )
2008                 v = *((int *)m_Ptr);
2009             else if( m_GetCallback!=NULL )
2010                 m_GetCallback(&v, m_ClientData);
2011             double dv = (double)_Step*(double)m_Val.m_Int32.m_Step + (double)v;
2012             if( dv>(double)0x7fffffff )
2013                 v = 0x7fffffff;
2014             else if( dv<(double)(-0x7fffffff-1) )
2015                 v = -0x7fffffff-1;
2016             else
2017                 v = _Step*m_Val.m_Int32.m_Step + v;
2018             if( v<m_Val.m_Int32.m_Min )
2019                 v = m_Val.m_Int32.m_Min;
2020             if( v>m_Val.m_Int32.m_Max )
2021                 v = m_Val.m_Int32.m_Max;
2022             if( m_Ptr!=NULL )
2023                 *((int *)m_Ptr) = v;
2024             else if( m_SetCallback!=NULL )
2025                 m_SetCallback(&v, m_ClientData);
2026         }
2027         break;
2028     case TW_TYPE_UINT32:
2029         {
2030             unsigned int v = 0;
2031             if( m_Ptr!=NULL )
2032                 v = *((unsigned int *)m_Ptr);
2033             else if( m_GetCallback!=NULL )
2034                 m_GetCallback(&v, m_ClientData);
2035             double dv = (double)_Step*(double)m_Val.m_UInt32.m_Step + (double)v;
2036             if( dv>(double)0xffffffff )
2037                 v = 0xffffffff;
2038             else if( dv<0 )
2039                 v = 0;
2040             else
2041                 v = _Step*m_Val.m_UInt32.m_Step + v;
2042             if( v<m_Val.m_UInt32.m_Min )
2043                 v = m_Val.m_UInt32.m_Min;
2044             if( v>m_Val.m_UInt32.m_Max )
2045                 v = m_Val.m_UInt32.m_Max;
2046             if( m_Ptr!=NULL )
2047                 *((unsigned int *)m_Ptr) = v;
2048             else if( m_SetCallback!=NULL )
2049                 m_SetCallback(&v, m_ClientData);
2050         }
2051         break;
2052     case TW_TYPE_FLOAT:
2053         {
2054             float v = 0;
2055             if( m_Ptr!=NULL )
2056                 v = *((float *)m_Ptr);
2057             else if( m_GetCallback!=NULL )
2058                 m_GetCallback(&v, m_ClientData);
2059             v += _Step*m_Val.m_Float32.m_Step;
2060             if( v<m_Val.m_Float32.m_Min )
2061                 v = m_Val.m_Float32.m_Min;
2062             if( v>m_Val.m_Float32.m_Max )
2063                 v = m_Val.m_Float32.m_Max;
2064             if( m_Ptr!=NULL )
2065                 *((float *)m_Ptr) = v;
2066             else if( m_SetCallback!=NULL )
2067                 m_SetCallback(&v, m_ClientData);
2068         }
2069         break;
2070     case TW_TYPE_DOUBLE:
2071         {
2072             double v = 0;
2073             if( m_Ptr!=NULL )
2074                 v = *((double *)m_Ptr);
2075             else if( m_GetCallback!=NULL )
2076                 m_GetCallback(&v, m_ClientData);
2077             v += _Step*m_Val.m_Float64.m_Step;
2078             if( v<m_Val.m_Float64.m_Min )
2079                 v = m_Val.m_Float64.m_Min;
2080             if( v>m_Val.m_Float64.m_Max )
2081                 v = m_Val.m_Float64.m_Max;
2082             if( m_Ptr!=NULL )
2083                 *((double *)m_Ptr) = v;
2084             else if( m_SetCallback!=NULL )
2085                 m_SetCallback(&v, m_ClientData);
2086         }
2087         break;
2088     /*
2089     case TW_TYPE_ENUM8:
2090         {
2091             assert(_Step==1 || _Step==-1);
2092             unsigned char v = 0;
2093             if( m_Ptr!=NULL )
2094                 v = *((unsigned char *)m_Ptr);
2095             else if( m_GetCallback!=NULL )
2096                 m_GetCallback(&v, m_ClientData);
2097             if( m_Val.m_Enum.m_Entries!=NULL )
2098             {
2099                 UVal::CEnumVal::CEntries::iterator It = m_Val.m_Enum.m_Entries->find(v);
2100                 if( It==m_Val.m_Enum.m_Entries->end() )
2101                     It = m_Val.m_Enum.m_Entries->begin();
2102                 else if( _Step==1 )
2103                 {
2104                     ++It;
2105                     if( It==m_Val.m_Enum.m_Entries->end() )
2106                         It = m_Val.m_Enum.m_Entries->begin();
2107                 }
2108                 else if( _Step==-1 )
2109                 {
2110                     if( It==m_Val.m_Enum.m_Entries->begin() )
2111                         It = m_Val.m_Enum.m_Entries->end();
2112                     if( It!=m_Val.m_Enum.m_Entries->begin() )
2113                         --It;
2114                 }
2115                 if( It != m_Val.m_Enum.m_Entries->end() )
2116                 {
2117                     v = (unsigned char)(It->first);
2118                     if( m_Ptr!=NULL )
2119                         *((unsigned char *)m_Ptr) = v;
2120                     else if( m_SetCallback!=NULL )
2121                         m_SetCallback(&v, m_ClientData);
2122                 }
2123             }
2124         }
2125         break;
2126     case TW_TYPE_ENUM16:
2127         {
2128             assert(_Step==1 || _Step==-1);
2129             unsigned short v = 0;
2130             if( m_Ptr!=NULL )
2131                 v = *((unsigned short *)m_Ptr);
2132             else if( m_GetCallback!=NULL )
2133                 m_GetCallback(&v, m_ClientData);
2134             if( m_Val.m_Enum.m_Entries!=NULL )
2135             {
2136                 UVal::CEnumVal::CEntries::iterator It = m_Val.m_Enum.m_Entries->find(v);
2137                 if( It==m_Val.m_Enum.m_Entries->end() )
2138                     It = m_Val.m_Enum.m_Entries->begin();
2139                 else if( _Step==1 )
2140                 {
2141                     ++It;
2142                     if( It==m_Val.m_Enum.m_Entries->end() )
2143                         It = m_Val.m_Enum.m_Entries->begin();
2144                 }
2145                 else if( _Step==-1 )
2146                 {
2147                     if( It==m_Val.m_Enum.m_Entries->begin() )
2148                         It = m_Val.m_Enum.m_Entries->end();
2149                     if( It!=m_Val.m_Enum.m_Entries->begin() )
2150                         --It;
2151                 }
2152                 if( It != m_Val.m_Enum.m_Entries->end() )
2153                 {
2154                     v = (unsigned short)(It->first);
2155                     if( m_Ptr!=NULL )
2156                         *((unsigned short *)m_Ptr) = v;
2157                     else if( m_SetCallback!=NULL )
2158                         m_SetCallback(&v, m_ClientData);
2159                 }
2160             }
2161         }
2162         break;
2163     case TW_TYPE_ENUM32:
2164         {
2165             assert(_Step==1 || _Step==-1);
2166             unsigned int v = 0;
2167             if( m_Ptr!=NULL )
2168                 v = *((unsigned int *)m_Ptr);
2169             else if( m_GetCallback!=NULL )
2170                 m_GetCallback(&v, m_ClientData);
2171             if( m_Val.m_Enum.m_Entries!=NULL )
2172             {
2173                 UVal::CEnumVal::CEntries::iterator It = m_Val.m_Enum.m_Entries->find(v);
2174                 if( It==m_Val.m_Enum.m_Entries->end() )
2175                     It = m_Val.m_Enum.m_Entries->begin();
2176                 else if( _Step==1 )
2177                 {
2178                     ++It;
2179                     if( It==m_Val.m_Enum.m_Entries->end() )
2180                         It = m_Val.m_Enum.m_Entries->begin();
2181                 }
2182                 else if( _Step==-1 )
2183                 {
2184                     if( It==m_Val.m_Enum.m_Entries->begin() )
2185                         It = m_Val.m_Enum.m_Entries->end();
2186                     if( It!=m_Val.m_Enum.m_Entries->begin() )
2187                         --It;
2188                 }
2189                 if( It!=m_Val.m_Enum.m_Entries->end() )
2190                 {
2191                     v = (unsigned int)(It->first);
2192                     if( m_Ptr!=NULL )
2193                         *((unsigned int *)m_Ptr) = v;
2194                     else if( m_SetCallback!=NULL )
2195                         m_SetCallback(&v, m_ClientData);
2196                 }
2197             }
2198         }
2199         break;
2200     */
2201     default:
2202         if( m_Type==TW_TYPE_BUTTON )
2203         {
2204             if( m_Val.m_Button.m_Callback!=NULL )
2205             {
2206                 m_Val.m_Button.m_Callback(m_ClientData);
2207                 if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
2208                     return;
2209             }
2210         }
2211         else if( IsEnumType(m_Type) )
2212         {
2213             assert(_Step==1 || _Step==-1);
2214             unsigned int v = 0;
2215             if( m_Ptr!=NULL )
2216                 v = *((unsigned int *)m_Ptr);
2217             else if( m_GetCallback!=NULL )
2218                 m_GetCallback(&v, m_ClientData);
2219             CTwMgr::CEnum& e = g_TwMgr->m_Enums[m_Type-TW_TYPE_ENUM_BASE];
2220             CTwMgr::CEnum::CEntries::iterator It = e.m_Entries.find(v);
2221             if( It==e.m_Entries.end() )
2222                 It = e.m_Entries.begin();
2223             else if( _Step==1 )
2224             {
2225                 ++It;
2226                 if( It==e.m_Entries.end() )
2227                     It = e.m_Entries.begin();
2228             }
2229             else if( _Step==-1 )
2230             {
2231                 if( It==e.m_Entries.begin() )
2232                     It = e.m_Entries.end();
2233                 if( It!=e.m_Entries.begin() )
2234                     --It;
2235             }
2236             if( It!=e.m_Entries.end() )
2237             {
2238                 v = (unsigned int)(It->first);
2239                 if( m_Ptr!=NULL )
2240                     *((unsigned int *)m_Ptr) = v;
2241                 else if( m_SetCallback!=NULL )
2242                     m_SetCallback(&v, m_ClientData);
2243             }
2244         }
2245         else
2246             fprintf(stderr, "CTwVarAtom::Increment : unknown or unimplemented type\n");
2247     }
2248 }
2249
2250 //  ---------------------------------------------------------------------------
2251
2252 void CTwVarAtom::SetDefaults()
2253 {
2254     switch( m_Type )
2255     {
2256     case TW_TYPE_BOOL8:
2257     case TW_TYPE_BOOL16:
2258     case TW_TYPE_BOOL32:
2259     case TW_TYPE_BOOLCPP:
2260         m_NoSlider = true;
2261         break;
2262     case TW_TYPE_CHAR:
2263         m_Val.m_Char.m_Max = 0xff;
2264         m_Val.m_Char.m_Min = 0;
2265         m_Val.m_Char.m_Step = 1;
2266         m_Val.m_Char.m_Precision = -1;
2267         m_Val.m_Char.m_Hexa = false;
2268         break;
2269     case TW_TYPE_INT8:
2270         m_Val.m_Int8.m_Max = 0x7f;
2271         m_Val.m_Int8.m_Min = -m_Val.m_Int8.m_Max-1;
2272         m_Val.m_Int8.m_Step = 1;
2273         m_Val.m_Int8.m_Precision = -1;
2274         m_Val.m_Int8.m_Hexa = false;
2275         break;
2276     case TW_TYPE_UINT8:
2277         m_Val.m_UInt8.m_Max = 0xff;
2278         m_Val.m_UInt8.m_Min = 0;
2279         m_Val.m_UInt8.m_Step = 1;
2280         m_Val.m_UInt8.m_Precision = -1;
2281         m_Val.m_UInt8.m_Hexa = false;
2282         break;
2283     case TW_TYPE_INT16:
2284         m_Val.m_Int16.m_Max = 0x7fff;
2285         m_Val.m_Int16.m_Min = -m_Val.m_Int16.m_Max-1;
2286         m_Val.m_Int16.m_Step = 1;
2287         m_Val.m_Int16.m_Precision = -1;
2288         m_Val.m_Int16.m_Hexa = false;
2289         break;
2290     case TW_TYPE_UINT16:
2291         m_Val.m_UInt16.m_Max = 0xffff;
2292         m_Val.m_UInt16.m_Min = 0;
2293         m_Val.m_UInt16.m_Step = 1;
2294         m_Val.m_UInt16.m_Precision = -1;
2295         m_Val.m_UInt16.m_Hexa = false;
2296         break;
2297     case TW_TYPE_INT32:
2298         m_Val.m_Int32.m_Max = 0x7fffffff;
2299         m_Val.m_Int32.m_Min = -m_Val.m_Int32.m_Max-1;
2300         m_Val.m_Int32.m_Step = 1;
2301         m_Val.m_Int32.m_Precision = -1;
2302         m_Val.m_Int32.m_Hexa = false;
2303         break;
2304     case TW_TYPE_UINT32:
2305         m_Val.m_UInt32.m_Max = 0xffffffff;
2306         m_Val.m_UInt32.m_Min = 0;
2307         m_Val.m_UInt32.m_Step = 1;
2308         m_Val.m_UInt32.m_Precision = -1;
2309         m_Val.m_UInt32.m_Hexa = false;
2310         break;
2311     case TW_TYPE_FLOAT:
2312         m_Val.m_Float32.m_Max = FLOAT_MAX;
2313         m_Val.m_Float32.m_Min = -FLOAT_MAX;
2314         m_Val.m_Float32.m_Step = 1;
2315         m_Val.m_Float32.m_Precision = -1;
2316         m_Val.m_Float32.m_Hexa = false;
2317         break;
2318     case TW_TYPE_DOUBLE:
2319         m_Val.m_Float64.m_Max = DOUBLE_MAX;
2320         m_Val.m_Float64.m_Min = -DOUBLE_MAX;
2321         m_Val.m_Float64.m_Step = 1;
2322         m_Val.m_Float64.m_Precision = -1;
2323         m_Val.m_Float64.m_Hexa = false;
2324         break;
2325     case TW_TYPE_CDSTRING:
2326     case TW_TYPE_STDSTRING:
2327         m_NoSlider = true;
2328         break;
2329     /*
2330     case TW_TYPE_ENUM8:
2331     case TW_TYPE_ENUM16:
2332     case TW_TYPE_ENUM32:
2333         m_NoSlider = true;
2334         break;
2335     */
2336     default:
2337         {} // nothing
2338     }
2339
2340     // special types
2341     if(    m_Type==TW_TYPE_BUTTON 
2342         || IsEnumType(m_Type) // (m_Type>=TW_TYPE_ENUM_BASE && m_Type<TW_TYPE_ENUM_BASE+(int)g_TwMgr->m_Enums.size()) 
2343         || IsCSStringType(m_Type) // (m_Type>=TW_TYPE_CSSTRING_BASE && m_Type<=TW_TYPE_CSSTRING_MAX) 
2344         || m_Type==TW_TYPE_CDSTDSTRING 
2345         || IsCustom() ) // (m_Type>=TW_TYPE_CUSTOM_BASE && m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size()) )
2346         m_NoSlider = true;
2347 }
2348
2349 //  ---------------------------------------------------------------------------
2350
2351 /*
2352 int CTwVarAtom::DefineEnum(const TwEnumVal *_EnumValues, unsigned int _NbValues)
2353 {
2354     assert(_EnumValues!=NULL);
2355     if( m_Type!=TW_TYPE_ENUM8 && m_Type!=TW_TYPE_ENUM16 && m_Type!=TW_TYPE_ENUM32 )
2356     {
2357         g_TwMgr->SetLastError(g_ErrNotEnum);
2358         return 0;
2359     }
2360     if( m_Val.m_Enum.m_Entries==NULL )
2361         m_Val.m_Enum.m_Entries = new UVal::CEnumVal::CEntries;
2362     for(unsigned int i=0; i<_NbValues; ++i)
2363     {
2364         UVal::CEnumVal::CEntries::value_type Entry(_EnumValues[i].Value, (_EnumValues[i].Label!=NULL)?_EnumValues[i].Label:"");
2365         pair<UVal::CEnumVal::CEntries::iterator, bool> Result = m_Val.m_Enum.m_Entries->insert(Entry);
2366         if( !Result.second )
2367             (Result.first)->second = Entry.second;
2368     }
2369     return 1;
2370 }
2371 */
2372
2373 //  ---------------------------------------------------------------------------
2374
2375 enum EVarGroupAttribs
2376 {
2377     VG_OPEN = V_ENDTAG+1, // for backward compatibility
2378     VG_CLOSE,       // for backward compatibility
2379     VG_OPENED,
2380     VG_TYPEID,      // used internally for structs
2381     VG_VALPTR,      // used internally for structs
2382     VG_ALPHA,       // for backward compatibility
2383     VG_NOALPHA,     // for backward compatibility
2384     VG_COLORALPHA,  // tw_type_color* only
2385     VG_HLS,         // for backward compatibility
2386     VG_RGB,         // for backward compatibility
2387     VG_COLORMODE,   // tw_type_color* only
2388     VG_COLORORDER,  // tw_type_color* only
2389     VG_ARROW,       // tw_type_quat* only
2390     VG_ARROWCOLOR,  // tw_type_quat* only
2391     VG_AXISX,       // tw_type_quat* only
2392     VG_AXISY,       // tw_type_quat* only
2393     VG_AXISZ,       // tw_type_quat* only
2394     VG_SHOWVAL      // tw_type_quat* only
2395 };
2396
2397 int CTwVarGroup::HasAttrib(const char *_Attrib, bool *_HasValue) const
2398 {
2399     *_HasValue = false;
2400     if( _stricmp(_Attrib, "open")==0 ) // for backward compatibility
2401         return VG_OPEN;
2402     else if( _stricmp(_Attrib, "close")==0 ) // for backward compatibility
2403         return VG_CLOSE;
2404     else if( _stricmp(_Attrib, "opened")==0 )
2405     {
2406         *_HasValue = true;
2407         return VG_OPENED;
2408     }
2409     else if( _stricmp(_Attrib, "typeid")==0 )
2410     {
2411         *_HasValue = true;
2412         return VG_TYPEID;
2413     }
2414     else if( _stricmp(_Attrib, "valptr")==0 )
2415     {
2416         *_HasValue = true;
2417         return VG_VALPTR;
2418     }
2419     else if( _stricmp(_Attrib, "alpha")==0 ) // for backward compatibility
2420         return VG_ALPHA;
2421     else if( _stricmp(_Attrib, "noalpha")==0 ) // for backward compatibility
2422         return VG_NOALPHA;
2423     else if( _stricmp(_Attrib, "coloralpha")==0 )
2424     {
2425         *_HasValue = true;
2426         return VG_COLORALPHA;
2427     }
2428     else if( _stricmp(_Attrib, "hls")==0 ) // for backward compatibility
2429         return VG_HLS;
2430     else if( _stricmp(_Attrib, "rgb")==0 ) // for backward compatibility
2431         return VG_RGB;
2432     else if( _stricmp(_Attrib, "colormode")==0 )
2433     {
2434         *_HasValue = true;
2435         return VG_COLORMODE;
2436     }
2437     else if( _stricmp(_Attrib, "colororder")==0 )
2438     {
2439         *_HasValue = true;
2440         return VG_COLORORDER;
2441     }
2442     else if( _stricmp(_Attrib, "arrow")==0 )
2443     {
2444         *_HasValue = true;
2445         return VG_ARROW;
2446     }
2447     else if( _stricmp(_Attrib, "arrowcolor")==0 )
2448     {
2449         *_HasValue = true;
2450         return VG_ARROWCOLOR;
2451     }
2452     else if( _stricmp(_Attrib, "axisx")==0 )
2453     {
2454         *_HasValue = true;
2455         return VG_AXISX;
2456     }
2457     else if( _stricmp(_Attrib, "axisy")==0 )
2458     {
2459         *_HasValue = true;
2460         return VG_AXISY;
2461     }
2462     else if( _stricmp(_Attrib, "axisz")==0 )
2463     {
2464         *_HasValue = true;
2465         return VG_AXISZ;
2466     }
2467     else if( _stricmp(_Attrib, "showval")==0 )
2468     {
2469         *_HasValue = true;
2470         return VG_SHOWVAL;
2471     }
2472
2473     return CTwVar::HasAttrib(_Attrib, _HasValue);
2474 }
2475
2476 int CTwVarGroup::SetAttrib(int _AttribID, const char *_Value, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex)
2477 {
2478     switch( _AttribID )
2479     {
2480     case VG_OPEN: // for backward compatibility
2481         if( !m_Open )
2482         {
2483             m_Open = true;
2484             _Bar->NotUpToDate();
2485         }
2486         return 1;
2487     case VG_CLOSE: // for backward compatibility
2488         if( m_Open )
2489         {
2490             m_Open = false;
2491             _Bar->NotUpToDate();
2492         }
2493         return 1;
2494     case VG_OPENED:
2495         if( _Value!=NULL && strlen(_Value)>0 )
2496         {
2497             if( _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 )
2498             {
2499                 if( !m_Open )
2500                 {
2501                     m_Open = true;
2502                     _Bar->NotUpToDate();
2503                 }
2504                 return 1;
2505             }
2506             else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "0")==0 )
2507             {
2508                 if( m_Open )
2509                 {
2510                     m_Open = false;
2511                     _Bar->NotUpToDate();
2512                 }
2513                 return 1;
2514             }
2515             else
2516             {
2517                 g_TwMgr->SetLastError(g_ErrBadValue);
2518                 return 0;
2519             }
2520         }
2521         else
2522         {
2523             g_TwMgr->SetLastError(g_ErrNoValue);
2524             return 0;
2525         }
2526     case VG_TYPEID:
2527         {
2528             int type = TW_TYPE_UNDEF;
2529             if( _Value!=NULL && sscanf(_Value, "%d", &type)==1 )
2530             {
2531                 int idx = type - TW_TYPE_STRUCT_BASE;
2532                 if( idx>=0 && idx<(int)g_TwMgr->m_Structs.size() )
2533                 {
2534                     m_SummaryCallback   = g_TwMgr->m_Structs[idx].m_SummaryCallback;
2535                     m_SummaryClientData = g_TwMgr->m_Structs[idx].m_SummaryClientData;
2536                     m_StructType = (TwType)type;
2537                     return 1;
2538                 }
2539             }
2540             return 0;
2541         }
2542     case VG_VALPTR:
2543         {
2544             void *structValuePtr = NULL;
2545             if( _Value!=NULL && sscanf(_Value, "%p", &structValuePtr)==1 )
2546             {
2547                 m_StructValuePtr = structValuePtr;
2548                 m_ColorPtr = &(_Bar->m_ColStructText);
2549                 return 1;
2550             }
2551             return 0;
2552         }
2553     case VG_ALPHA: // for backward compatibility
2554         if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2555             if( static_cast<CColorExt *>(m_StructValuePtr)->m_CanHaveAlpha )
2556             {
2557                 static_cast<CColorExt *>(m_StructValuePtr)->m_HasAlpha = true;
2558                 _Bar->NotUpToDate();
2559                 return 1;
2560             }
2561         return 0;
2562     case VG_NOALPHA: // for backward compatibility
2563         if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2564         {
2565             static_cast<CColorExt *>(m_StructValuePtr)->m_HasAlpha = false;
2566             _Bar->NotUpToDate();
2567             return 1;
2568         }
2569         else
2570             return 0;
2571     case VG_COLORALPHA:
2572         if( _Value!=NULL && strlen(_Value)>0 )
2573         {
2574             if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2575             {
2576                 if( _stricmp(_Value, "true")==0 || _stricmp(_Value, "1")==0 )
2577                 {
2578                     if( static_cast<CColorExt *>(m_StructValuePtr)->m_CanHaveAlpha )
2579                     {
2580                         if( !static_cast<CColorExt *>(m_StructValuePtr)->m_HasAlpha )
2581                         {
2582                             static_cast<CColorExt *>(m_StructValuePtr)->m_HasAlpha = true;
2583                             _Bar->NotUpToDate();
2584                         }
2585                         return 1;
2586                     }
2587                 }
2588                 else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "0")==0 )
2589                 {
2590                     if( static_cast<CColorExt *>(m_StructValuePtr)->m_HasAlpha )
2591                     {
2592                         static_cast<CColorExt *>(m_StructValuePtr)->m_HasAlpha = false;
2593                         _Bar->NotUpToDate();
2594                     }
2595                     return 1;
2596                 }
2597             }
2598         }
2599         return 0;
2600     case VG_HLS: // for backward compatibility
2601         if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2602         {
2603             static_cast<CColorExt *>(m_StructValuePtr)->m_HLS = true;
2604             _Bar->NotUpToDate();
2605             return 1;
2606         }
2607         else
2608             return 0;
2609     case VG_RGB: // for backward compatibility
2610         if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2611         {
2612             static_cast<CColorExt *>(m_StructValuePtr)->m_HLS = false;
2613             _Bar->NotUpToDate();
2614             return 1;
2615         }
2616         else
2617             return 0;
2618     case VG_COLORMODE:
2619         if( _Value!=NULL && strlen(_Value)>0 )
2620         {
2621             if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2622             {
2623                 if( _stricmp(_Value, "hls")==0 )
2624                 {
2625                     if( !static_cast<CColorExt *>(m_StructValuePtr)->m_HLS )
2626                     {
2627                         static_cast<CColorExt *>(m_StructValuePtr)->m_HLS = true;
2628                         _Bar->NotUpToDate();
2629                     }
2630                     return 1;
2631                 }
2632                 else if( _stricmp(_Value, "rgb")==0 )
2633                 {
2634                     if( static_cast<CColorExt *>(m_StructValuePtr)->m_HLS )
2635                     {
2636                         static_cast<CColorExt *>(m_StructValuePtr)->m_HLS = false;
2637                         _Bar->NotUpToDate();
2638                     }
2639                     return 1;
2640                 }
2641             }
2642         }
2643         return 0;
2644     case VG_COLORORDER:
2645         if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2646         {
2647             if( _Value!=NULL )
2648             {
2649                 if( _stricmp(_Value, "rgba")==0 )
2650                     static_cast<CColorExt *>(m_StructValuePtr)->m_OGL = true;
2651                 else if( _stricmp(_Value, "argb")==0 )
2652                     static_cast<CColorExt *>(m_StructValuePtr)->m_OGL = false;
2653                 else
2654                     return 0;
2655                 return 1;
2656             }
2657             return 0;
2658         }
2659         else
2660             return 0;
2661     case VG_ARROW:
2662         if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL )    // is tw_type_quat?
2663         {
2664             if( _Value!=NULL )
2665             {
2666                 double *dir = static_cast<CQuaternionExt *>(m_StructValuePtr)->m_Dir;
2667                 double x, y, z;
2668                 if( sscanf(_Value, "%lf %lf %lf", &x, &y, &z)==3 )
2669                 {
2670                     dir[0] = x; 
2671                     dir[1] = y;
2672                     dir[2] = z;
2673                 }
2674                 else if( _stricmp(_Value, "off")==0 || _stricmp(_Value, "0")==0 )
2675                     dir[0] = dir[1] = dir[2] = 0;
2676                 else
2677                     return 0;
2678                 return 1;
2679             }
2680             return 0;
2681         }
2682         else
2683             return 0;
2684     case VG_ARROWCOLOR:
2685         if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL )    // is tw_type_quat?
2686         {
2687             if( _Value!=NULL )
2688             {
2689                 int r, g, b;
2690                 if( sscanf(_Value, "%d %d %d", &r, &g, &b)==3 )
2691                     static_cast<CQuaternionExt *>(m_StructValuePtr)->m_DirColor = Color32FromARGBi(255, r, g, b);
2692                 else
2693                     return 0;
2694                 return 1;
2695             }
2696             return 0;
2697         }
2698         else
2699             return 0;
2700     case VG_AXISX:
2701     case VG_AXISY:
2702     case VG_AXISZ:
2703         if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL )    // is tw_type_quat?
2704         {
2705             if( _Value!=NULL )
2706             {
2707                 float x = 0, y = 0, z = 0;
2708                 if( _stricmp(_Value, "x")==0 || _stricmp(_Value, "+x")==0 )
2709                     x = 1;
2710                 else if( _stricmp(_Value, "-x")==0 )
2711                     x = -1;
2712                 else if( _stricmp(_Value, "y")==0 || _stricmp(_Value, "+y")==0 )
2713                     y = 1;
2714                 else if( _stricmp(_Value, "-y")==0 )
2715                     y = -1;
2716                 else if( _stricmp(_Value, "z")==0 || _stricmp(_Value, "+z")==0 )
2717                     z = 1;
2718                 else if( _stricmp(_Value, "-z")==0 )
2719                     z = -1;
2720                 else
2721                     return 0;
2722                 int i = (_AttribID==VG_AXISX) ? 0 : ((_AttribID==VG_AXISY) ? 1 : 2);
2723                 static_cast<CQuaternionExt *>(m_StructValuePtr)->m_Permute[i][0] = x; 
2724                 static_cast<CQuaternionExt *>(m_StructValuePtr)->m_Permute[i][1] = y; 
2725                 static_cast<CQuaternionExt *>(m_StructValuePtr)->m_Permute[i][2] = z;
2726                 return 1;
2727             }
2728             return 0;
2729         }
2730         else
2731             return 0;
2732     case VG_SHOWVAL:
2733         if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat?
2734         {
2735             if( _Value!=NULL )
2736             {
2737                 if( _stricmp(_Value, "true")==0 || _stricmp(_Value, "on")==0 || _stricmp(_Value, "1")==0 )
2738                 {
2739                     static_cast<CQuaternionExt *>(m_StructValuePtr)->m_ShowVal = true;
2740                     _Bar->NotUpToDate();
2741                     return 1;
2742                 }
2743                 else if( _stricmp(_Value, "false")==0 || _stricmp(_Value, "off")==0 || _stricmp(_Value, "0")==0 )
2744                 {
2745                     static_cast<CQuaternionExt *>(m_StructValuePtr)->m_ShowVal = false;
2746                     _Bar->NotUpToDate();
2747                     return 1;
2748                 }
2749             }
2750             return 0;
2751         }
2752         else
2753             return 0;
2754     default:
2755         return CTwVar::SetAttrib(_AttribID, _Value, _Bar, _VarParent, _VarIndex);
2756     }
2757 }
2758
2759 ERetType CTwVarGroup::GetAttrib(int _AttribID, TwBar *_Bar, struct CTwVarGroup *_VarParent, int _VarIndex, std::vector<double>& outDoubles, std::ostringstream& outString) const
2760 {
2761     outDoubles.clear();
2762     outString.clear();
2763
2764     switch( _AttribID )
2765     {
2766     case VG_OPENED:
2767         outDoubles.push_back( m_Open );
2768         return RET_DOUBLE;
2769     case VG_COLORALPHA:
2770         if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2771         {
2772             outDoubles.push_back( static_cast<CColorExt *>(m_StructValuePtr)->m_HasAlpha );
2773             return RET_DOUBLE;
2774         }
2775         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
2776         return RET_ERROR;
2777     case VG_COLORMODE:
2778         if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2779         {
2780             if( static_cast<CColorExt *>(m_StructValuePtr)->m_HLS ) 
2781                 outString << "hls";
2782             else
2783                 outString << "rgb";
2784             return RET_STRING;
2785         }
2786         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
2787         return RET_ERROR;
2788     case VG_COLORORDER:
2789         if( m_SummaryCallback==CColorExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_color?
2790         {
2791             if( static_cast<CColorExt *>(m_StructValuePtr)->m_OGL )
2792                 outString << "rgba";
2793             else 
2794                 outString << "argb";
2795             return RET_STRING;
2796         }
2797         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
2798         return RET_ERROR;
2799     case VG_ARROW:
2800         if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat?
2801         {
2802             double *dir = static_cast<CQuaternionExt *>(m_StructValuePtr)->m_Dir;
2803             outDoubles.push_back(dir[0]);
2804             outDoubles.push_back(dir[1]);
2805             outDoubles.push_back(dir[2]);
2806             return RET_DOUBLE;
2807         }
2808         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
2809         return RET_ERROR;
2810     case VG_ARROWCOLOR:
2811         if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat?
2812         {
2813             int a, r, g, b;
2814             a = r = g = b = 0;
2815             Color32ToARGBi(static_cast<CQuaternionExt *>(m_StructValuePtr)->m_DirColor, &a, &r, &g, &b);
2816             outDoubles.push_back(r);
2817             outDoubles.push_back(g);
2818             outDoubles.push_back(b);
2819             return RET_DOUBLE;
2820         }
2821         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
2822         return RET_ERROR;
2823     case VG_AXISX:
2824     case VG_AXISY:
2825     case VG_AXISZ:
2826         if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat?
2827         {
2828             int i = (_AttribID==VG_AXISX) ? 0 : ((_AttribID==VG_AXISY) ? 1 : 2);
2829             float x = static_cast<CQuaternionExt *>(m_StructValuePtr)->m_Permute[i][0]; 
2830             float y = static_cast<CQuaternionExt *>(m_StructValuePtr)->m_Permute[i][1]; 
2831             float z = static_cast<CQuaternionExt *>(m_StructValuePtr)->m_Permute[i][2]; 
2832             if( x>0 )
2833                 outString << "+x";
2834             else if( x<0 )
2835                 outString << "-x";
2836             else if( y>0 )
2837                 outString << "+y";
2838             else if( y<0 )
2839                 outString << "-y";
2840             else if( z>0 )
2841                 outString << "+z";
2842             else if( z<0 )
2843                 outString << "-z";
2844             else
2845                 outString << "0"; // should not happened
2846             return RET_DOUBLE;
2847         }
2848         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
2849         return RET_ERROR;
2850     case VG_SHOWVAL:
2851         if( m_SummaryCallback==CQuaternionExt::SummaryCB && m_StructValuePtr!=NULL ) // is tw_type_quat?
2852         {
2853             outDoubles.push_back( static_cast<CQuaternionExt *>(m_StructValuePtr)->m_ShowVal );
2854             return RET_DOUBLE;
2855         }
2856         g_TwMgr->SetLastError(g_ErrInvalidAttrib);
2857         return RET_ERROR;
2858     default:
2859         return CTwVar::GetAttrib(_AttribID, _Bar, _VarParent, _VarIndex, outDoubles, outString);
2860     }
2861 }
2862
2863 //  ---------------------------------------------------------------------------
2864
2865 const CTwVar *CTwVarGroup::Find(const char *_Name, CTwVarGroup **_Parent, int *_Index) const
2866 {
2867     if( strcmp(_Name, m_Name.c_str())==0 )
2868     {
2869         if( _Parent!=NULL )
2870             *_Parent = NULL;
2871         if( _Index!=NULL )
2872             *_Index = -1;
2873         return this;
2874     }
2875     else
2876     {
2877         const CTwVar *v;
2878         for( size_t i=0; i<m_Vars.size(); ++ i )
2879             if( m_Vars[i]!=NULL )
2880             {
2881                 v = m_Vars[i]->Find(_Name, _Parent, _Index);
2882                 if( v!=NULL )
2883                 {
2884                     if( _Parent!=NULL && *_Parent==NULL )
2885                     {
2886                         *_Parent = const_cast<CTwVarGroup *>(this);
2887                         if( _Index!=NULL )
2888                             *_Index  = (int)i;
2889                     }
2890                     return v;
2891                 }
2892             }
2893         return NULL;
2894     }
2895 }
2896
2897 //  ---------------------------------------------------------------------------
2898
2899 size_t CTwVar::GetDataSize(TwType _Type)
2900 {
2901     switch( _Type )
2902     {
2903     case TW_TYPE_BOOLCPP:
2904         return sizeof(bool);
2905     case TW_TYPE_BOOL8:
2906     case TW_TYPE_CHAR:
2907     case TW_TYPE_INT8:
2908     case TW_TYPE_UINT8:
2909     //case TW_TYPE_ENUM8:
2910         return 1;
2911     case TW_TYPE_BOOL16:
2912     case TW_TYPE_INT16:
2913     case TW_TYPE_UINT16:
2914     //case TW_TYPE_ENUM16:
2915         return 2;
2916     case TW_TYPE_BOOL32:
2917     case TW_TYPE_INT32:
2918     case TW_TYPE_UINT32:
2919     case TW_TYPE_FLOAT:
2920     //case TW_TYPE_ENUM32:
2921         return 4;
2922     case TW_TYPE_DOUBLE:
2923         return 8;
2924     case TW_TYPE_CDSTRING:
2925         return sizeof(char *);
2926     case TW_TYPE_STDSTRING:
2927         return (g_TwMgr!=0) ? g_TwMgr->m_ClientStdStringStructSize : sizeof(std::string);
2928     default:
2929         if( g_TwMgr && _Type>=TW_TYPE_STRUCT_BASE && _Type<TW_TYPE_STRUCT_BASE+(int)g_TwMgr->m_Structs.size() )
2930         {
2931             const CTwMgr::CStruct& s = g_TwMgr->m_Structs[_Type-TW_TYPE_STRUCT_BASE];
2932             return s.m_Size;
2933             /*
2934             size_t size = 0;
2935             for( size_t i=0; i<s.m_Members.size(); ++i )
2936                 size += s.m_Members[i].m_Size;
2937             return size;
2938             */
2939         }
2940         else if( g_TwMgr && IsEnumType(_Type) )
2941             return 4;
2942         else if( IsCSStringType(_Type) )
2943             return TW_CSSTRING_SIZE(_Type);
2944         else if( _Type==TW_TYPE_CDSTDSTRING )
2945             return (g_TwMgr!=0) ? g_TwMgr->m_ClientStdStringStructSize : sizeof(std::string);
2946         else    // includes TW_TYPE_BUTTON
2947             return 0;
2948     }
2949 }
2950
2951 //  ---------------------------------------------------------------------------
2952
2953 CTwBar::CTwBar(const char *_Name)
2954 {
2955     assert(g_TwMgr!=NULL && g_TwMgr->m_Graph!=NULL);
2956
2957     m_Name = _Name;
2958     m_Visible = true;
2959     m_VarRoot.m_IsRoot = true;
2960     m_VarRoot.m_Open = true;
2961     m_VarRoot.m_SummaryCallback = NULL;
2962     m_VarRoot.m_SummaryClientData = NULL;
2963     m_VarRoot.m_StructValuePtr = NULL;
2964
2965     m_UpToDate = false;
2966     int n = (int)g_TwMgr->m_Bars.size();
2967     m_PosX = 24*n-8;
2968     m_PosY = 24*n-8;
2969     m_Width = 200;
2970     m_Height = 320;
2971     int cr, cg, cb;
2972     if( g_TwMgr->m_UseOldColorScheme )
2973     {
2974         ColorHLSToRGBi(g_TwMgr->m_BarInitColorHue%256, 180, 200, &cr, &cg, &cb);
2975         m_Color = Color32FromARGBi(0xf0, cr, cg, cb);
2976         m_DarkText = true;
2977     }
2978     else
2979     {
2980         ColorHLSToRGBi(g_TwMgr->m_BarInitColorHue%256, 80, 200, &cr, &cg, &cb);
2981         m_Color = Color32FromARGBi(64, cr, cg, cb);
2982         m_DarkText = false;
2983     }
2984     g_TwMgr->m_BarInitColorHue -= 16;
2985     if( g_TwMgr->m_BarInitColorHue<0 )
2986         g_TwMgr->m_BarInitColorHue += 256;
2987     m_Font = g_TwMgr->m_CurrentFont;
2988     //m_Font = g_DefaultNormalFont;
2989     //m_Font = g_DefaultSmallFont;
2990     //m_Font = g_DefaultLargeFont;
2991     m_TitleWidth = 0;
2992     m_Sep = 1;
2993 //#pragma warning "lineSep WIP"
2994     m_LineSep = 1;
2995     m_ValuesWidth = 10*(m_Font->m_CharHeight/2); // about 10 characters
2996     m_NbHierLines = 0;
2997     m_NbDisplayedLines = 0;
2998     m_FirstLine = 0;
2999     m_LastUpdateTime = 0;
3000     m_UpdatePeriod = 2;
3001     m_ScrollYW = 0;
3002     m_ScrollYH = 0;
3003     m_ScrollY0 = 0;
3004     m_ScrollY1 = 0;
3005
3006     m_DrawHandles = false;
3007     m_DrawIncrDecrBtn = false;
3008     m_DrawRotoBtn = false;
3009     m_DrawClickBtn = false;
3010     m_DrawListBtn = false;
3011     m_DrawBoolBtn = false;
3012     m_MouseDrag = false;
3013     m_MouseDragVar = false;
3014     m_MouseDragTitle = false;
3015     m_MouseDragScroll = false;
3016     m_MouseDragResizeUR = false;
3017     m_MouseDragResizeUL = false;
3018     m_MouseDragResizeLR = false;
3019     m_MouseDragResizeLL = false;
3020     m_MouseDragValWidth = false;
3021     m_MouseOriginX = 0;
3022     m_MouseOriginY = 0;
3023     m_ValuesWidthRatio = 0;
3024     m_VarHasBeenIncr = true;
3025     m_FirstLine0 = 0;
3026     m_HighlightedLine = -1;
3027     m_HighlightedLinePrev = -1;
3028     m_HighlightedLineLastValid = -1;
3029     m_HighlightIncrBtn = false;
3030     m_HighlightDecrBtn = false;
3031     m_HighlightRotoBtn = false;
3032     m_HighlightClickBtn = false;
3033     m_HighlightClickBtnAuto = 0;
3034     m_HighlightListBtn = false;
3035     m_HighlightBoolBtn = false;
3036     m_HighlightTitle = false;
3037     m_HighlightScroll = false;
3038     m_HighlightUpScroll = false;
3039     m_HighlightDnScroll = false;
3040     m_HighlightMinimize = false;
3041     m_HighlightFont = false;
3042     m_HighlightValWidth = false;
3043     m_HighlightLabelsHeader = false;
3044     m_HighlightValuesHeader = false;
3045     m_ButtonAlign = g_TwMgr->m_ButtonAlign;
3046
3047     m_IsMinimized = false;
3048     m_MinNumber = 0;
3049     m_MinPosX = 0;
3050     m_MinPosY = 0;
3051     m_HighlightMaximize = false;
3052     m_IsHelpBar = false;
3053     m_IsPopupList = false;
3054     m_VarEnumLinkedToPopupList = NULL;
3055     m_BarLinkedToPopupList = NULL;
3056
3057     m_Resizable = true;
3058     m_Movable = true;
3059     m_Iconifiable = true;
3060     m_Contained = g_TwMgr->m_Contained;
3061
3062     m_TitleTextObj = g_TwMgr->m_Graph->NewTextObj();
3063     m_LabelsTextObj = g_TwMgr->m_Graph->NewTextObj();
3064     m_ValuesTextObj = g_TwMgr->m_Graph->NewTextObj();
3065     m_ShortcutTextObj = g_TwMgr->m_Graph->NewTextObj();
3066     m_HeadersTextObj = g_TwMgr->m_Graph->NewTextObj();
3067     m_ShortcutLine = -1;
3068
3069     m_RotoMinRadius = 24;
3070     m_RotoNbSubdiv = 256;   // number of steps for one turn
3071
3072     m_CustomActiveStructProxy = NULL;
3073
3074     UpdateColors();
3075     NotUpToDate();
3076 }
3077
3078 //  ---------------------------------------------------------------------------
3079
3080 CTwBar::~CTwBar()
3081 {
3082     if( m_IsMinimized )
3083         g_TwMgr->Maximize(this);
3084     if( m_TitleTextObj )
3085         g_TwMgr->m_Graph->DeleteTextObj(m_TitleTextObj);
3086     if( m_LabelsTextObj )
3087         g_TwMgr->m_Graph->DeleteTextObj(m_LabelsTextObj);
3088     if( m_ValuesTextObj )
3089         g_TwMgr->m_Graph->DeleteTextObj(m_ValuesTextObj);
3090     if( m_ShortcutTextObj )
3091         g_TwMgr->m_Graph->DeleteTextObj(m_ShortcutTextObj);
3092     if( m_HeadersTextObj )
3093         g_TwMgr->m_Graph->DeleteTextObj(m_HeadersTextObj);
3094 }
3095
3096 //  ---------------------------------------------------------------------------
3097
3098 const CTwVar *CTwBar::Find(const char *_Name, CTwVarGroup **_Parent, int *_Index) const
3099 {
3100     return m_VarRoot.Find(_Name, _Parent, _Index);
3101 }
3102
3103 CTwVar *CTwBar::Find(const char *_Name, CTwVarGroup **_Parent, int *_Index)
3104 {
3105     return const_cast<CTwVar *>(const_cast<const CTwBar *>(this)->Find(_Name, _Parent, _Index));
3106 }
3107
3108 //  ---------------------------------------------------------------------------
3109
3110 enum EBarAttribs
3111 {
3112     BAR_LABEL = 1,
3113     BAR_HELP,
3114     BAR_COLOR,
3115     BAR_ALPHA,
3116     BAR_TEXT,
3117     BAR_SHOW,    // deprecated, used BAR_VISIBLE instead
3118     BAR_HIDE,    // deprecated, used BAR_VISIBLE instead
3119     BAR_ICONIFY, // deprecated, used BAR_ICONIFIED instead
3120     BAR_VISIBLE,
3121     BAR_ICONIFIED,
3122     BAR_SIZE,
3123     BAR_POSITION,
3124     BAR_REFRESH,
3125     BAR_FONT_SIZE,
3126     BAR_FONT_STYLE,
3127     BAR_VALUES_WIDTH,
3128     BAR_ICON_POS,
3129     BAR_ICON_ALIGN,
3130     BAR_ICON_MARGIN,
3131     BAR_RESIZABLE,
3132     BAR_MOVABLE,
3133     BAR_ICONIFIABLE,
3134     BAR_FONT_RESIZABLE,
3135     BAR_ALWAYS_TOP,
3136     BAR_ALWAYS_BOTTOM,
3137     BAR_COLOR_SCHEME,
3138     BAR_CONTAINED,
3139     BAR_BUTTON_ALIGN
3140 };
3141
3142 int CTwBar::HasAttrib(const char *_Attrib, bool *_HasValue) const
3143 {
3144     *_HasValue = true;
3145     if( _stricmp(_Attrib, "label")==0 )
3146         return BAR_LABEL;
3147     else if( _stricmp(_Attrib, "help")==0 )
3148         return BAR_HELP;
3149     else if( _stricmp(_Attrib, "color")==0 )
3150         return BAR_COLOR;
3151     else if( _stricmp(_Attrib, "alpha")==0 )
3152         return BAR_ALPHA;
3153     else if( _stricmp(_Attrib, "text")==0 )
3154         return BAR_TEXT;
3155     else if( _stricmp(_Attrib, "size")==0 )
3156         return BAR_SIZE;
3157     else if( _stricmp(_Attrib, "position")==0 )
3158         return BAR_POSITION;
3159     else if( _stricmp(_Attrib, "refresh")==0 )
3160         return BAR_REFRESH;
3161     else if( _stricmp(_Attrib, "fontsize")==0 )
3162         return BAR_FONT_SIZE;
3163     else if( _stricmp(_Attrib, "fontstyle")==0 )
3164         return BAR_FONT_STYLE;
3165     else if( _stricmp(_Attrib, "valueswidth")==0 )
3166         return BAR_VALUES_WIDTH;
3167     else if( _stricmp(_Attrib, "iconpos")==0 )
3168         return BAR_ICON_POS;
3169     else if( _stricmp(_Attrib, "iconalign")==0 )
3170         return BAR_ICON_ALIGN;
3171     else if( _stricmp(_Attrib, "iconmargin")==0 )
3172         return BAR_ICON_MARGIN;
3173     else if( _stricmp(_Attrib, "resizable")==0 )
3174         return BAR_RESIZABLE;
3175     else if( _stricmp(_Attrib, "movable")==0 )
3176         return BAR_MOVABLE;
3177     else if( _stricmp(_Attrib, "iconifiable")==0 )
3178         return BAR_ICONIFIABLE;
3179     else if( _stricmp(_Attrib, "fontresizable")==0 )
3180         return BAR_FONT_RESIZABLE;
3181     else if( _stricmp(_Attrib, "alwaystop")==0 )
3182         return BAR_ALWAYS_TOP;
3183     else if( _stricmp(_Attrib, "alwaysbottom")==0 )
3184         return BAR_ALWAYS_BOTTOM;
3185     else if( _stricmp(_Attrib, "visible")==0 )
3186         return BAR_VISIBLE;
3187     else if( _stricmp(_Attrib, "iconified")==0 )
3188         return BAR_ICONIFIED;
3189     else if( _stricmp(_Attrib, "colorscheme")==0 )
3190         return BAR_COLOR_SCHEME;
3191     else if( _stricmp(_Attrib, "contained")==0 )
3192         return BAR_CONTAINED;
3193     else if( _stricmp(_Attrib, "buttonalign")==0 )
3194         return BAR_BUTTON_ALIGN;
3195
3196     *_HasValue = false;
3197     if( _stricmp(_Attrib, "show")==0 ) // for backward compatibility
3198         return BAR_SHOW;
3199     else if( _stricmp(_Attrib, "hide")==0 ) // for backward compatibility
3200         return BAR_HIDE;
3201     else if( _stricmp(_Attrib, "iconify")==0 ) // for backward compatibility
3202         return BAR_ICONIFY;
3203
3204     return 0; // not found
3205 }
3206
3207 int CTwBar::SetAttrib(int _AttribID, const char *_Value)
3208 {
3209     switch( _AttribID )
3210     {
3211     case BAR_LABEL:
3212         if( _Value && strlen(_Value)>0 )
3213         {
3214             m_Label = _Value;
3215             NotUpToDate();
3216             return 1;
3217         }
3218         else
3219         {
3220             g_TwMgr->SetLastError(g_ErrNoValue);
3221             return 0;
3222         }
3223     case BAR_HELP:
3224         if( _Value && strlen(_Value)>0 )
3225         {
3226             m_Help = _Value;
3227             NotUpToDate();
3228             return 1;
3229         }
3230         else
3231         {
3232             g_TwMgr->SetLastError(g_ErrNoValue);
3233             return 0;
3234         }
3235     case BAR_COLOR:
3236         if( _Value && strlen(_Value)>0 )
3237         {
3238             int v0, v1, v2, v3;
3239             int n = sscanf(_Value, "%d%d%d%d", &v0, &v1, &v2, &v3);
3240             color32 c;
3241             int alpha = (m_Color>>24) & 0xff;
3242             if( n==3 && v0>=0 && v0<=255 && v1>=0 && v1<=255 && v2>=0 && v2<=255 )
3243                 c = Color32FromARGBi(alpha, v0, v1, v2);
3244             else if( n==4 && v0>=0 && v0<=255 && v1>=0 && v1<=255 && v2>=0 && v2<=255 && v3>=0 && v3<=255 )
3245                 c = Color32FromARGBi(v0, v1, v2, v3);
3246             else
3247             {
3248                 g_TwMgr->SetLastError(g_ErrBadValue);
3249                 return 0;
3250             }
3251             m_Color = c;
3252             NotUpToDate();
3253             return 1;
3254         }
3255         else
3256         {
3257             g_TwMgr->SetLastError(g_ErrNoValue);
3258             return 0;
3259         }
3260     case BAR_ALPHA:
3261         if( _Value && strlen(_Value)>0 )
3262         {
3263             int alpha = 255;
3264             int n = sscanf(_Value, "%d", &alpha);
3265             if( n==1 && alpha>=0 && alpha<=255 )
3266                 m_Color = (alpha<<24) | (m_Color & 0xffffff);
3267             else
3268             {
3269                 g_TwMgr->SetLastError(g_ErrBadValue);
3270                 return 0;
3271             }
3272             NotUpToDate();
3273             return 1;
3274         }
3275         else
3276         {
3277             g_TwMgr->SetLastError(g_ErrNoValue);
3278             return 0;
3279         }
3280     case BAR_TEXT:
3281         if( _Value && strlen(_Value)>0 )
3282         {
3283             if( _stricmp(_Value, "dark")==0 )
3284                 m_DarkText = true;
3285             else if( _stricmp(_Value, "light")==0 )
3286                 m_DarkText = false;
3287             else
3288             {
3289                 g_TwMgr->SetLastError(g_ErrBadValue);
3290                 return 0;
3291             }
3292             NotUpToDate();
3293             return 1;
3294         }
3295         else
3296         {
3297             g_TwMgr->SetLastError(g_ErrNoValue);
3298             return 0;
3299         }
3300     case BAR_SIZE:
3301         if( _Value && strlen(_Value)>0 )
3302         {
3303             int sx, sy;
3304             int n = sscanf(_Value, "%d%d", &sx, &sy);
3305             if( n==2 && sx>0 && sy>0 )
3306             {
3307                 m_Width = sx;
3308                 m_Height = sy;
3309                 NotUpToDate();
3310                 return 1;
3311             }
3312             else
3313             {
3314                 g_TwMgr->SetLastError(g_ErrBadValue);
3315                 return 0;
3316             }
3317         }
3318         else
3319         {
3320             g_TwMgr->SetLastError(g_ErrNoValue);
3321             return 0;
3322         }
3323     case BAR_POSITION:
3324         if( _Value && strlen(_Value)>0 )
3325         {
3326             int x, y;
3327             int n = sscanf(_Value, "%d%d", &x, &y);
3328             if( n==2 && x>=0 && y>=0 )
3329             {
3330                 m_PosX = x;
3331                 m_PosY = y;
3332                 NotUpToDate();
3333                 return 1;
3334             }
3335             else
3336             {
3337                 g_TwMgr->SetLastError(g_ErrBadValue);
3338                 return 0;
3339             }
3340         }
3341         else
3342         {
3343             g_TwMgr->SetLastError(g_ErrNoValue);
3344             return 0;
3345         }
3346     case BAR_REFRESH:
3347         if( _Value && strlen(_Value)>0 )
3348         {
3349             float r;
3350             int n = sscanf(_Value, "%f", &r);
3351             if( n==1 && r>=0 )
3352             {
3353                 m_UpdatePeriod = r;
3354                 return 1;
3355             }
3356             else
3357             {
3358                 g_TwMgr->SetLastError(g_ErrBadValue);
3359                 return 0;
3360             }
3361         }
3362         else
3363         {
3364             g_TwMgr->SetLastError(g_ErrNoValue);
3365             return 0;
3366         }
3367     case BAR_VALUES_WIDTH:
3368         if( _Value && strlen(_Value)>0 )
3369         {
3370             if( _stricmp(_Value, "fit")==0 )
3371             {
3372                 m_ValuesWidth = VALUES_WIDTH_FIT;
3373                 NotUpToDate();
3374                 return 1;
3375             } 
3376             else
3377             {
3378                 int w;
3379                 int n = sscanf(_Value, "%d", &w);
3380                 if( n==1 && w>0 )
3381                 {
3382                     m_ValuesWidth = w;
3383                     NotUpToDate();
3384                     return 1;
3385                 }
3386                 else
3387                 {
3388                     g_TwMgr->SetLastError(g_ErrBadValue);
3389                     return 0;
3390                 }
3391             }
3392         }
3393         else
3394         {
3395             g_TwMgr->SetLastError(g_ErrNoValue);
3396             return 0;
3397         }
3398     case BAR_FONT_SIZE:
3399         return g_TwMgr->SetAttrib(MGR_FONT_SIZE, _Value);
3400     case BAR_FONT_STYLE:
3401         return g_TwMgr->SetAttrib(MGR_FONT_STYLE, _Value);
3402     case BAR_ICON_POS:
3403         return g_TwMgr->SetAttrib(MGR_ICON_POS, _Value);
3404     case BAR_ICON_ALIGN:
3405         return g_TwMgr->SetAttrib(MGR_ICON_ALIGN, _Value);
3406     case BAR_ICON_MARGIN:
3407         return g_TwMgr->SetAttrib(MGR_ICON_MARGIN, _Value);
3408     case BAR_SHOW:    // deprecated
3409         TwSetBarState(this, TW_STATE_SHOWN);
3410         return 1;
3411     case BAR_HIDE:    // deprecated
3412         TwSetBarState(this, TW_STATE_HIDDEN);
3413         return 1;
3414     case BAR_ICONIFY: // deprecated
3415         TwSetBarState(this, TW_STATE_ICONIFIED);
3416         return 1;
3417     case BAR_RESIZABLE:
3418         if( _Value && strlen(_Value)>0 )
3419         {
3420             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
3421             {
3422                 m_Resizable = true;
3423                 return 1;
3424             }
3425             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
3426             {
3427                 m_Resizable = false;
3428                 return 1;
3429             }
3430             else
3431             {
3432                 g_TwMgr->SetLastError(g_ErrBadValue);
3433                 return 0;
3434             }
3435         }
3436         else
3437         {
3438             g_TwMgr->SetLastError(g_ErrNoValue);
3439             return 0;
3440         }
3441     case BAR_MOVABLE:
3442         if( _Value && strlen(_Value)>0 )
3443         {
3444             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
3445             {
3446                 m_Movable = true;
3447                 return 1;
3448             }
3449             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
3450             {
3451                 m_Movable = false;
3452                 return 1;
3453             }
3454             else
3455             {
3456                 g_TwMgr->SetLastError(g_ErrBadValue);
3457                 return 0;
3458             }
3459         }
3460         else
3461         {
3462             g_TwMgr->SetLastError(g_ErrNoValue);
3463             return 0;
3464         }
3465     case BAR_ICONIFIABLE:
3466         if( _Value && strlen(_Value)>0 )
3467         {
3468             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
3469             {
3470                 m_Iconifiable = true;
3471                 return 1;
3472             }
3473             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
3474             {
3475                 m_Iconifiable = false;
3476                 return 1;
3477             }
3478             else
3479             {
3480                 g_TwMgr->SetLastError(g_ErrBadValue);
3481                 return 0;
3482             }
3483         }
3484         else
3485         {
3486             g_TwMgr->SetLastError(g_ErrNoValue);
3487             return 0;
3488         }
3489     case BAR_FONT_RESIZABLE:
3490         return g_TwMgr->SetAttrib(MGR_FONT_RESIZABLE, _Value);
3491     case BAR_ALWAYS_TOP:
3492         if( _Value && strlen(_Value)>0 )
3493         {
3494             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
3495             {
3496                 g_TwMgr->m_BarAlwaysOnTop = m_Name;
3497                 if( g_TwMgr->m_BarAlwaysOnBottom.length()>0 && strcmp(g_TwMgr->m_BarAlwaysOnBottom.c_str(), m_Name.c_str())==0 )
3498                     g_TwMgr->m_BarAlwaysOnBottom.clear();
3499                 TwSetTopBar(this);
3500                 return 1;
3501             }
3502             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
3503             {
3504                 if( g_TwMgr->m_BarAlwaysOnTop.length()>0 && strcmp(g_TwMgr->m_BarAlwaysOnTop.c_str(), m_Name.c_str())==0 )
3505                     g_TwMgr->m_BarAlwaysOnTop.clear();
3506                 return 1;
3507             }
3508             else
3509             {
3510                 g_TwMgr->SetLastError(g_ErrBadValue);
3511                 return 0;
3512             }
3513         }
3514         else
3515         {
3516             g_TwMgr->SetLastError(g_ErrNoValue);
3517             return 0;
3518         }
3519     case BAR_ALWAYS_BOTTOM:
3520         if( _Value && strlen(_Value)>0 )
3521         {
3522             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
3523             {
3524                 g_TwMgr->m_BarAlwaysOnBottom = m_Name;
3525                 if( g_TwMgr->m_BarAlwaysOnTop.length()>0 && strcmp(g_TwMgr->m_BarAlwaysOnTop.c_str(), m_Name.c_str())==0 )
3526                     g_TwMgr->m_BarAlwaysOnTop.clear();
3527                 TwSetBottomBar(this);
3528                 return 1;
3529             }
3530             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
3531             {
3532                 if( g_TwMgr->m_BarAlwaysOnBottom.length()>0 && strcmp(g_TwMgr->m_BarAlwaysOnBottom.c_str(), m_Name.c_str())==0 )
3533                     g_TwMgr->m_BarAlwaysOnBottom.clear();
3534                 return 1;
3535             }
3536             else
3537             {
3538                 g_TwMgr->SetLastError(g_ErrBadValue);
3539                 return 0;
3540             }
3541         }
3542         else
3543         {
3544             g_TwMgr->SetLastError(g_ErrNoValue);
3545             return 0;
3546         }
3547     case BAR_VISIBLE:
3548         if( _Value && strlen(_Value)>0 )
3549         {
3550             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
3551             {
3552                 TwSetBarState(this, TW_STATE_SHOWN);
3553                 return 1;
3554             }
3555             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
3556             {
3557                 TwSetBarState(this, TW_STATE_HIDDEN);
3558                 return 1;
3559             }
3560             else
3561             {
3562                 g_TwMgr->SetLastError(g_ErrBadValue);
3563                 return 0;
3564             }
3565         }
3566         else
3567         {
3568             g_TwMgr->SetLastError(g_ErrNoValue);
3569             return 0;
3570         }
3571     case BAR_ICONIFIED:
3572         if( _Value && strlen(_Value)>0 )
3573         {
3574             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
3575             {
3576                 TwSetBarState(this, TW_STATE_ICONIFIED);
3577                 return 1;
3578             }
3579             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
3580             {
3581                 TwSetBarState(this, TW_STATE_UNICONIFIED);
3582                 return 1;
3583             }
3584             else
3585             {
3586                 g_TwMgr->SetLastError(g_ErrBadValue);
3587                 return 0;
3588             }
3589         }
3590         else
3591         {
3592             g_TwMgr->SetLastError(g_ErrNoValue);
3593             return 0;
3594         }
3595     case BAR_COLOR_SCHEME:
3596         return g_TwMgr->SetAttrib(MGR_COLOR_SCHEME, _Value);
3597     case BAR_CONTAINED:
3598         if( _Value && strlen(_Value)>0 )
3599         {
3600             if( _stricmp(_Value, "1")==0 || _stricmp(_Value, "true")==0 )
3601             {
3602                 m_Contained = true;
3603                 return 1;
3604             }
3605             else if( _stricmp(_Value, "0")==0 || _stricmp(_Value, "false")==0 )
3606             {
3607                 m_Contained = false;
3608                 return 1;
3609             }
3610             else
3611             {
3612                 g_TwMgr->SetLastError(g_ErrBadValue);
3613                 return 0;
3614             }
3615         }
3616         else
3617         {
3618             g_TwMgr->SetLastError(g_ErrNoValue);
3619             return 0;
3620         }
3621     case BAR_BUTTON_ALIGN:
3622         if( _Value && strlen(_Value)>0 )
3623         {
3624             if( _stricmp(_Value, "left")==0 )
3625             {
3626                 m_ButtonAlign = BUTTON_ALIGN_LEFT;
3627                 return 1;
3628             }
3629             else if( _stricmp(_Value, "center")==0 )
3630             {
3631                 m_ButtonAlign = BUTTON_ALIGN_CENTER;
3632                 return 1;
3633             }
3634             if( _stricmp(_Value, "right")==0 )
3635             {
3636                 m_ButtonAlign = BUTTON_ALIGN_RIGHT;
3637                 return 1;
3638             }
3639             else
3640             {
3641                 g_TwMgr->SetLastError(g_ErrBadValue);
3642                 return 0;
3643             }
3644         }
3645         else
3646         {
3647             g_TwMgr->SetLastError(g_ErrNoValue);
3648             return 0;
3649         }
3650     default:
3651         g_TwMgr->SetLastError(g_ErrUnknownAttrib);
3652         return 0;
3653     }
3654 }
3655
3656 ERetType CTwBar::GetAttrib(int _AttribID, std::vector<double>& outDoubles, std::ostringstream& outString) const
3657 {
3658     outDoubles.clear();
3659     outString.clear();
3660
3661     switch( _AttribID )
3662     {
3663     case BAR_LABEL:
3664         outString << m_Label;
3665         return RET_STRING;
3666     case BAR_HELP:
3667         outString << m_Help;
3668         return RET_STRING;
3669     case BAR_COLOR:
3670         {
3671             int a, r, g, b;
3672             a = r = g = b = 0;
3673             Color32ToARGBi(m_Color, &a, &r, &g, &b);
3674             outDoubles.push_back(r);
3675             outDoubles.push_back(g);
3676             outDoubles.push_back(b);
3677             return RET_DOUBLE;
3678         }
3679     case BAR_ALPHA:
3680         {
3681             int a, r, g, b;
3682             a = r = g = b = 0;
3683             Color32ToARGBi(m_Color, &a, &r, &g, &b);
3684             outDoubles.push_back(a);
3685             return RET_DOUBLE;
3686         }
3687     case BAR_TEXT:
3688         if( m_DarkText )
3689             outString << "dark";
3690         else 
3691             outString << "light";
3692         return RET_STRING;
3693     case BAR_SIZE:
3694         outDoubles.push_back(m_Width);
3695         outDoubles.push_back(m_Height);
3696         return RET_DOUBLE;
3697     case BAR_POSITION:
3698         outDoubles.push_back(m_PosX);
3699         outDoubles.push_back(m_PosY);
3700         return RET_DOUBLE;
3701     case BAR_REFRESH:
3702         outDoubles.push_back(m_UpdatePeriod);
3703         return RET_DOUBLE;
3704     case BAR_VALUES_WIDTH:
3705         outDoubles.push_back(m_ValuesWidth);
3706         return RET_DOUBLE;
3707     case BAR_FONT_SIZE:
3708         return g_TwMgr->GetAttrib(MGR_FONT_SIZE, outDoubles, outString);
3709     case BAR_FONT_STYLE:
3710         return g_TwMgr->GetAttrib(MGR_FONT_STYLE, outDoubles, outString);
3711     case BAR_ICON_POS:
3712         return g_TwMgr->GetAttrib(MGR_ICON_POS, outDoubles, outString);
3713     case BAR_ICON_ALIGN:
3714         return g_TwMgr->GetAttrib(MGR_ICON_ALIGN, outDoubles, outString);
3715     case BAR_ICON_MARGIN:
3716         return g_TwMgr->GetAttrib(MGR_ICON_MARGIN, outDoubles, outString);
3717     case BAR_RESIZABLE:
3718         outDoubles.push_back(m_Resizable);
3719         return RET_DOUBLE;
3720     case BAR_MOVABLE:
3721         outDoubles.push_back(m_Movable);
3722         return RET_DOUBLE;
3723     case BAR_ICONIFIABLE:
3724         outDoubles.push_back(m_Iconifiable);
3725         return RET_DOUBLE;
3726     case BAR_FONT_RESIZABLE:
3727         return g_TwMgr->GetAttrib(MGR_FONT_RESIZABLE, outDoubles, outString);
3728     case BAR_ALWAYS_TOP:
3729         outDoubles.push_back( g_TwMgr->m_BarAlwaysOnTop == m_Name );
3730         return RET_DOUBLE;
3731     case BAR_ALWAYS_BOTTOM:
3732         outDoubles.push_back( g_TwMgr->m_BarAlwaysOnBottom == m_Name );
3733         return RET_DOUBLE;
3734     case BAR_VISIBLE:
3735         outDoubles.push_back(m_Visible);
3736         return RET_DOUBLE;
3737     case BAR_ICONIFIED:
3738         outDoubles.push_back(m_IsMinimized);
3739         return RET_DOUBLE;
3740     case BAR_COLOR_SCHEME:
3741         return g_TwMgr->GetAttrib(MGR_COLOR_SCHEME, outDoubles, outString);
3742     case BAR_CONTAINED:
3743         outDoubles.push_back(m_Contained);
3744         return RET_DOUBLE;
3745     case BAR_BUTTON_ALIGN:
3746         if( m_ButtonAlign==BUTTON_ALIGN_LEFT )
3747             outString << "left";
3748         else if( m_ButtonAlign==BUTTON_ALIGN_CENTER )
3749             outString << "center";
3750         else
3751             outString << "right";
3752         return RET_STRING;
3753     default:
3754         g_TwMgr->SetLastError(g_ErrUnknownAttrib);
3755         return RET_ERROR;
3756     }
3757 }
3758
3759 //  ---------------------------------------------------------------------------
3760
3761 void CTwBar::NotUpToDate()
3762 {
3763     m_UpToDate = false;
3764 }
3765
3766 //  ---------------------------------------------------------------------------
3767
3768 void CTwBar::UpdateColors()
3769 {
3770     float a, r, g, b, h, l, s;
3771     Color32ToARGBf(m_Color, &a, &r, &g, &b);
3772     ColorRGBToHLSf(r, g, b, &h, &l, &s);
3773     bool lightText = !m_DarkText;
3774
3775     // Colors independant of m_Color
3776
3777     // Highlighted line background ramp
3778     m_ColHighBg0 = lightText ? Color32FromARGBf(0.4f, 0.9f, 0.9f, 0.9f) : Color32FromARGBf(0.4f, 1.0f, 1.0f, 1.0f);
3779     m_ColHighBg1 = lightText ? Color32FromARGBf(0.4f, 0.2f, 0.2f, 0.2f) : Color32FromARGBf(0.1f, 0.7f, 0.7f, 0.7f);
3780
3781     // Text colors & background
3782     m_ColLabelText = lightText ? COLOR32_WHITE : COLOR32_BLACK;
3783     m_ColStructText = lightText ? 0xffefef00 : 0xff303000;
3784
3785     m_ColValText = lightText ? 0xffc7d7ff : 0xff000080;
3786     m_ColValTextRO = lightText ? 0xffb7b7b7 : 0xff505050;
3787     m_ColValMin = lightText ? 0xff9797ff : 0xff0000f0;
3788     m_ColValMax = m_ColValMin;
3789     m_ColValTextNE = lightText ? 0xff97f797 : 0xff004000;
3790
3791     m_ColValBg = lightText ? Color32FromARGBf(0.2f+0.3f*a, 0.1f, 0.1f, 0.1f) : Color32FromARGBf(0.2f+0.3f*a, 1, 1, 1);
3792     m_ColStructBg = lightText ? Color32FromARGBf(0.4f*a, 0, 0, 0) : Color32FromARGBf(0.4f*a, 1, 1, 1);
3793
3794     m_ColLine = lightText ? Color32FromARGBf(0.6f, 1, 1, 1) : Color32FromARGBf(0.6f, 0.3f, 0.3f, 0.3f);
3795     m_ColLineShadow = lightText ? Color32FromARGBf(0.6f, 0, 0, 0) : Color32FromARGBf(0.6f, 0, 0, 0);
3796     m_ColUnderline = lightText ? 0xffd0d0d0 : 0xff202000;
3797
3798     m_ColGrpBg = lightText ? Color32FromARGBf(0.1f+0.25f*a, 1, 1, 1) : Color32FromARGBf(0.1f+0.05f*a, 0, 0, 0);
3799     m_ColGrpText = lightText ? 0xffffff80 : 0xff000000;
3800
3801     m_ColShortcutText = lightText ? 0xffffb060 : 0xff802000;
3802     m_ColShortcutBg = lightText ? Color32FromARGBf(0.4f*a, 0.2f, 0.2f, 0.2f) : Color32FromARGBf(0.4f*a, 0.8f, 0.8f, 0.8f);
3803     m_ColInfoText = lightText ? Color32FromARGBf(1.0f, 0.7f, 0.7f, 0.7f) : Color32FromARGBf(1.0f, 0.3f, 0.3f, 0.3f);
3804
3805     m_ColRoto = lightText ? Color32FromARGBf(0.8f, 0.85f, 0.85f, 0.85f) : Color32FromARGBf(0.8f, 0.1f, 0.1f, 0.1f);
3806     m_ColRotoVal = Color32FromARGBf(1, 1.0f, 0.2f, 0.2f);
3807     m_ColRotoBound = lightText ? Color32FromARGBf(0.8f, 0.6f, 0.6f, 0.6f) : Color32FromARGBf(0.8f, 0.3f, 0.3f, 0.3f);
3808
3809     m_ColEditText = lightText ? COLOR32_WHITE : COLOR32_BLACK;
3810     m_ColEditBg = lightText ? 0xff575757 : 0xffc7c7c7; // must be opaque
3811     m_ColEditSelText = lightText ? COLOR32_BLACK : COLOR32_WHITE;
3812     m_ColEditSelBg = lightText ? 0xffc7c7c7 : 0xff575757;
3813
3814     // Colors dependant of m_Colors
3815     
3816     // Bar background
3817     ColorHLSToRGBf(h, l, s, &r, &g, &b);
3818     m_ColBg = Color32FromARGBf(a, r, g, b);
3819     ColorHLSToRGBf(h, l-0.05f, s, &r, &g, &b);
3820     m_ColBg1 = Color32FromARGBf(a, r, g, b);
3821     ColorHLSToRGBf(h, l-0.1f, s, &r, &g, &b);
3822     m_ColBg2 = Color32FromARGBf(a, r, g, b);
3823     
3824     ColorHLSToRGBf(h, l-0.15f, s, &r, &g, &b);
3825     m_ColTitleBg = Color32FromARGBf(a+0.9f, r, g, b);
3826     m_ColTitleText = lightText ? COLOR32_WHITE : COLOR32_BLACK;
3827     m_ColTitleShadow = lightText ? 0x40000000 : 0x00000000;
3828     ColorHLSToRGBf(h, l-0.25f, s, &r, &g, &b);
3829     m_ColTitleHighBg = Color32FromARGBf(a+0.8f, r, g, b);
3830     ColorHLSToRGBf(h, l-0.3f, s, &r, &g, &b);
3831     m_ColTitleUnactiveBg = Color32FromARGBf(a+0.2f, r, g, b);
3832
3833     ColorHLSToRGBf(h, l-0.2f, s, &r, &g, &b);
3834     m_ColHierBg = Color32FromARGBf(a, r, g, b);
3835
3836     ColorHLSToRGBf(h, l+0.1f, s, &r, &g, &b);
3837     m_ColBtn = Color32FromARGBf(0.2f+0.4f*a, r, g, b);
3838     ColorHLSToRGBf(h, l-0.35f, s, &r, &g, &b);
3839     m_ColHighBtn = Color32FromARGBf(0.4f+0.4f*a, r, g, b);
3840     ColorHLSToRGBf(h, l-0.25f, s, &r, &g, &b);
3841     m_ColFold = Color32FromARGBf(0.1f+0.4f*a, r, g, b);
3842     ColorHLSToRGBf(h, l-0.35f, s, &r, &g, &b);
3843     m_ColHighFold = Color32FromARGBf(0.3f+0.4f*a, r, g, b);
3844
3845     ColorHLSToRGBf(h, 0.75f, s, &r, &g, &b);
3846     m_ColHelpBg = Color32FromARGBf(0.2f, 1, 1, 1);
3847     m_ColHelpText = lightText ? Color32FromARGBf(1, 0.2f, 1.0f, 0.2f) : Color32FromARGBf(1, 0, 0.4f, 0);
3848     m_ColSeparator = m_ColValTextRO;
3849     m_ColStaticText = m_ColHelpText;
3850 }
3851
3852 /*
3853 void CTwBar::UpdateColors()
3854 {
3855     float a, r, g, b, h, l, s;
3856     Color32ToARGBf(m_Color, &a, &r, &g, &b);
3857     ColorRGBToHLSf(r, g, b, &h, &l, &s);
3858     bool lightText = !m_DarkText; // (l<=0.45f);
3859     l = 0.2f + 0.6f*l;
3860     
3861     ColorHLSToRGBf(h, l, s, &r, &g, &b);
3862     m_ColBg = Color32FromARGBf(a, r, g, b);
3863     ColorHLSToRGBf(h, l-0.1f, s, &r, &g, &b);
3864     m_ColBg1 = Color32FromARGBf(a, r, g, b);
3865     ColorHLSToRGBf(h, l-0.2f, s, &r, &g, &b);
3866     m_ColBg2 = Color32FromARGBf(a, r, g, b);
3867
3868     ColorHLSToRGBf(h, l+0.1f, s, &r, &g, &b);
3869     m_ColHighBg = Color32FromARGBf(0.4f, r, g, b);
3870     //m_ColHighBg = Color32FromARGBf(a, 0.95f, 0.95f, 0.2f);
3871     
3872     m_ColLabelText = lightText ? COLOR32_WHITE : COLOR32_BLACK;
3873     m_ColStructText = lightText ? 0xffefef00 : 0xff505000;
3874
3875     m_ColValText = lightText ? 0xffb7b7ff : 0xff000080;
3876     m_ColValTextRO = lightText ? 0xffb7b7b7 : 0xff505050;
3877     m_ColValMin = lightText ? 0xff9797ff : 0xff0000f0;
3878     m_ColValMax = m_ColValMin;
3879     m_ColValTextNE = lightText ? 0xff97f797 : 0xff006000;
3880
3881     ColorHLSToRGBf(h, lightText ? (min(l+0.2f, 0.3f)) : (max(l-0.2f, 0.6f)), s, &r, &g, &b);
3882     m_ColValBg = Color32FromARGBf(0.4f*a, 0, 0, 0);
3883     m_ColStructBg = Color32FromARGBf(0.4f*a, 0, 0, 0);
3884
3885     ColorHLSToRGBf(h, 0.4f, s, &r, &g, &b);
3886     m_ColTitleBg = Color32FromARGBf(a+0.4f, r, g, b);
3887     m_ColTitleText = lightText ? COLOR32_WHITE : COLOR32_BLACK;
3888     m_ColTitleShadow = lightText ? 0x80000000 : 0x80ffffff;
3889     ColorHLSToRGBf(h, 0.3f, s, &r, &g, &b);
3890     m_ColTitleHighBg = Color32FromARGBf(a+0.4f, r, g, b);
3891     ColorHLSToRGBf(h, 0.4f, s, &r, &g, &b);
3892     m_ColTitleUnactiveBg = Color32FromARGBf(a+0.2f, r, g, b);
3893
3894     ColorHLSToRGBf(h, 0.8f, s, &r, &g, &b);
3895     m_ColLine = Color32FromARGBf(0.6f, r, g, b); // 0xfff0f0f0;
3896     m_ColLineShadow = Color32FromARGBf(0.6f, 0, 0, 0); //COLOR32_BLACK;
3897     m_ColUnderline = lightText ? 0xffd0d0d0 : 0xff202000;
3898     ColorHLSToRGBf(h, 0.7f, s, &r, &g, &b);
3899     m_ColBtn = Color32FromARGBf(0.6f, r, g, b);
3900     ColorHLSToRGBf(h, 0.4f, s, &r, &g, &b);
3901     m_ColHighBtn = Color32FromARGBf(0.6f, r, g, b);
3902     ColorHLSToRGBf(h, 0.6f, s, &r, &g, &b);
3903     m_ColFold = Color32FromARGBf(0.3f*a, r, g, b);
3904     ColorHLSToRGBf(h, 0.4f, s, &r, &g, &b);
3905     m_ColHighFold = Color32FromARGBf(0.3f, r, g, b);
3906
3907     ColorHLSToRGBf(h, lightText ? l+0.2f : l-0.2f, s, &r, &g, &b);
3908     m_ColGrpBg = Color32FromARGBf(0.5f*a, r, g, b);
3909     m_ColGrpText = lightText ? 0xffffff80 : 0xff404000;
3910
3911     ColorHLSToRGBf(h, 0.75f, s, &r, &g, &b);
3912     m_ColHelpBg = Color32FromARGBf(a, r, g, b);
3913     m_ColHelpText = Color32FromARGBf(1, 0, 0.4f, 0);
3914
3915     ColorHLSToRGBf(h, 0.45f, s, &r, &g, &b);
3916     m_ColHierBg = Color32FromARGBf(0.75f*a, r, g, b);
3917
3918     m_ColShortcutText = lightText ? 0xffff8040 : 0xff802000;  //0xfff0f0f0;
3919     m_ColShortcutBg = Color32FromARGBf(0.4f*a, 0.2f, 0.2f, 0.2f);
3920     m_ColInfoText = Color32FromARGBf(1.0f, 0.7f, 0.7f, 0.7f);
3921
3922     m_ColRoto = Color32FromARGBf(1, 0.75f, 0.75f, 0.75f);
3923     m_ColRotoVal = Color32FromARGBf(1, 1.0f, 0.2f, 0.2f);
3924     m_ColRotoBound = Color32FromARGBf(1, 0.4f, 0.4f, 0.4f);
3925
3926     m_ColEditText = lightText ? COLOR32_WHITE : COLOR32_BLACK;
3927     m_ColEditBg = lightText ? 0xb7575757 : 0xb7c7c7c7;
3928     m_ColEditSelText = lightText ? COLOR32_BLACK : COLOR32_WHITE;
3929     m_ColEditSelBg = lightText ? 0xffc7c7c7 : 0xff575757;
3930
3931     m_ColSeparator = m_ColValTextRO;
3932     m_ColStaticText = m_ColHelpText;
3933 }
3934 */
3935
3936 //  ---------------------------------------------------------------------------
3937
3938 CTwVarGroup::~CTwVarGroup()
3939 {
3940     for( vector<CTwVar*>::iterator it= m_Vars.begin(); it!=m_Vars.end(); ++it )
3941         if( *it != NULL )
3942         {
3943             CTwVar *Var = *it;
3944             delete Var;
3945             *it = NULL;
3946         }
3947 }
3948
3949 //  ---------------------------------------------------------------------------
3950
3951 static inline int IncrBtnWidth(int _CharHeight) 
3952
3953     return ((2*_CharHeight)/3+2)&0xfffe; // force even value 
3954 }
3955
3956 //  ---------------------------------------------------------------------------
3957
3958 void CTwBar::BrowseHierarchy(int *_CurrLine, int _CurrLevel, const CTwVar *_Var, int _First, int _Last)
3959 {
3960     assert(_Var!=NULL);
3961     if( !_Var->m_IsRoot )
3962     {
3963         if( (*_CurrLine)>=_First && (*_CurrLine)<=_Last )
3964         {
3965             CHierTag Tag;
3966             Tag.m_Level = _CurrLevel;
3967             Tag.m_Var = const_cast<CTwVar *>(_Var);
3968             Tag.m_Closing = false;
3969             m_HierTags.push_back(Tag);
3970         }
3971         *_CurrLine += 1;
3972     }
3973     else
3974     {
3975         *_CurrLine = 0;
3976         _CurrLevel = -1;
3977         m_HierTags.resize(0);
3978     }
3979
3980     if( _Var->IsGroup() )
3981     {
3982         const CTwVarGroup *Grp = static_cast<const CTwVarGroup *>(_Var);
3983         if( Grp->m_Open )
3984             for( vector<CTwVar*>::const_iterator it=Grp->m_Vars.begin(); it!=Grp->m_Vars.end(); ++it )
3985                 if( (*it)->m_Visible )
3986                     BrowseHierarchy(_CurrLine, _CurrLevel+1, *it, _First, _Last);
3987         if( m_HierTags.size()>0 )
3988             m_HierTags[m_HierTags.size()-1].m_Closing = true;
3989     }
3990 }
3991
3992 //  ---------------------------------------------------------------------------
3993
3994 void CTwBar::ListLabels(vector<string>& _Labels, vector<color32>& _Colors, vector<color32>& _BgColors, bool *_HasBgColors, const CTexFont *_Font, int _AtomWidthMax, int _GroupWidthMax)
3995 {
3996     const int NbEtc = 2;
3997     string ValStr;
3998     int Len, i, x, Etc, s;
3999     const unsigned char *Text;
4000     unsigned char ch;
4001     int WidthMax;
4002     
4003     int Space = _Font->m_CharWidth[(int)' '];
4004     int LevelSpace = max(_Font->m_CharHeight-6, 4); // space used by DrawHierHandles
4005
4006     int nh = (int)m_HierTags.size();
4007     for( int h=0; h<nh; ++h )
4008     {
4009         Len = (int)m_HierTags[h].m_Var->m_Label.length();
4010         if( Len>0 )
4011             Text = (const unsigned char *)(m_HierTags[h].m_Var->m_Label.c_str());
4012         else
4013         {
4014             Text = (const unsigned char *)(m_HierTags[h].m_Var->m_Name.c_str());
4015             Len = (int)m_HierTags[h].m_Var->m_Name.length();
4016         }
4017         x = 0;
4018         Etc = 0;
4019         _Labels.push_back("");  // add a new text line
4020         if( !m_HierTags[h].m_Var->IsGroup() && static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type==TW_TYPE_BUTTON && static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_ReadOnly && static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_Val.m_Button.m_Callback!=NULL )
4021             _Colors.push_back(m_ColValTextRO); // special case for read-only buttons
4022         else
4023             _Colors.push_back(m_HierTags[h].m_Var->m_ColorPtr!=NULL ? *(m_HierTags[h].m_Var->m_ColorPtr) : COLOR32_WHITE);
4024         color32 bg = m_HierTags[h].m_Var->m_BgColorPtr!=NULL ? *(m_HierTags[h].m_Var->m_BgColorPtr) : 0;
4025         _BgColors.push_back(bg);
4026         if( _HasBgColors!=NULL && bg!=0 )
4027             *_HasBgColors = true;
4028         bool IsCustom = m_HierTags[h].m_Var->IsCustom(); // !m_HierTags[h].m_Var->IsGroup() && (static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type>=TW_TYPE_CUSTOM_BASE && static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size());
4029         if( !IsCustom )
4030         {
4031             string& CurrentLabel = _Labels[_Labels.size()-1];
4032             if( m_HierTags[h].m_Var->IsGroup() && static_cast<const CTwVarGroup *>(m_HierTags[h].m_Var)->m_SummaryCallback==NULL )
4033                 WidthMax = _GroupWidthMax;
4034             else if( !m_HierTags[h].m_Var->IsGroup() && static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type==TW_TYPE_BUTTON )
4035             {
4036                 if( static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_Val.m_Button.m_Callback==NULL )
4037                     WidthMax = _GroupWidthMax;
4038                 else if( m_ButtonAlign == BUTTON_ALIGN_RIGHT )
4039                     WidthMax = _GroupWidthMax - 2*IncrBtnWidth(m_Font->m_CharHeight);
4040                 else
4041                     WidthMax = _AtomWidthMax;
4042             }
4043             //else if( m_HighlightedLine==h && m_DrawRotoBtn )
4044             //  WidthMax = _AtomWidthMax - IncrBtnWidth(m_Font->m_CharHeight);
4045             else
4046                 WidthMax = _AtomWidthMax;
4047             if( Space>0 )
4048                 for( s=0; s<m_HierTags[h].m_Level*LevelSpace; s+=Space )
4049                 {
4050                     CurrentLabel += ' ';
4051                     x += Space;
4052                 }
4053             if( x+(NbEtc+2)*_Font->m_CharWidth[(int)'.']<WidthMax || m_HierTags[h].m_Var->m_DontClip)
4054                 for( i=0; i<Len; ++i )
4055                 {
4056                     ch = (Etc==0) ? Text[i] : '.';
4057                     CurrentLabel += ch;
4058                     x += _Font->m_CharWidth[(int)ch];
4059                     if( Etc>0 )
4060                     {
4061                         ++Etc;
4062                         if( Etc>NbEtc )
4063                             break;
4064                     }
4065                     else if( i<Len-2 && x+(NbEtc+2)*_Font->m_CharWidth[(int)'.']>=WidthMax && !(m_HierTags[h].m_Var->m_DontClip))
4066                         Etc = 1;
4067                 }       
4068         }
4069     }
4070 }
4071
4072 //  ---------------------------------------------------------------------------
4073
4074 void CTwBar::ListValues(vector<string>& _Values, vector<color32>& _Colors, vector<color32>& _BgColors, const CTexFont *_Font, int _WidthMax)
4075 {
4076     CTwFPU fpu; // force fpu precision
4077
4078     const int NbEtc = 2;
4079     const CTwVarAtom *Atom = NULL;
4080     string ValStr;
4081     int Len, i, x, Etc;
4082     const unsigned char *Text;
4083     unsigned char ch;
4084     bool ReadOnly;
4085     bool IsMax;
4086     bool IsMin;
4087     bool IsROText;
4088     bool HasBgColor;
4089     bool AcceptEdit;
4090     size_t SummaryMaxLength = max(_WidthMax/_Font->m_CharWidth[(int)'I'], 4);
4091     static vector<char> Summary;
4092     Summary.resize(SummaryMaxLength+32);
4093
4094     int nh = (int)m_HierTags.size();
4095     for( int h=0; h<nh; ++h )
4096         if( !m_HierTags[h].m_Var->IsGroup() || m_IsHelpBar 
4097             || (m_HierTags[h].m_Var->IsGroup() && static_cast<const CTwVarGroup *>(m_HierTags[h].m_Var)->m_SummaryCallback!=NULL) )
4098         {
4099             ReadOnly = true;
4100             IsMax = false;
4101             IsMin = false;
4102             IsROText = false;
4103             HasBgColor = true;
4104             AcceptEdit = false;
4105             if( !m_HierTags[h].m_Var->IsGroup() )
4106             {
4107                 Atom = static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var);
4108                 Atom->ValueToString(&ValStr);
4109                 if( !m_IsHelpBar || (Atom->m_Type==TW_TYPE_SHORTCUT && (Atom->m_Val.m_Shortcut.m_Incr[0]>0 || Atom->m_Val.m_Shortcut.m_Decr[0]>0)) )
4110                     ReadOnly = Atom->m_ReadOnly;
4111                 if( !Atom->m_NoSlider )
4112                 {
4113                     double v, vmin, vmax;
4114                     v = Atom->ValueToDouble();
4115                     Atom->MinMaxStepToDouble(&vmin, &vmax, NULL);
4116                     IsMax = (v>=vmax);
4117                     IsMin = (v<=vmin);
4118                 }
4119                 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 )
4120                 {
4121                     if (ValStr=="1")
4122                         ValStr = "\x7f"; // check sign
4123                     else if (ValStr=="0")
4124                         ValStr = " -"; //"\x97"; // uncheck sign
4125                 }
4126                 if(    (Atom->m_Type==TW_TYPE_CDSTRING && Atom->m_SetCallback==NULL && g_TwMgr->m_CopyCDStringToClient==NULL)
4127                     || (Atom->m_Type==TW_TYPE_CDSTDSTRING && Atom->m_SetCallback==NULL)
4128                     || (Atom->m_Type==TW_TYPE_STDSTRING && Atom->m_SetCallback==NULL && g_TwMgr->m_CopyStdStringToClient==NULL) )
4129                     IsROText = true;
4130                 if( Atom->m_Type==TW_TYPE_HELP_ATOM || Atom->m_Type==TW_TYPE_HELP_GRP || Atom->m_Type==TW_TYPE_BUTTON || Atom->IsCustom() ) // (Atom->m_Type>=TW_TYPE_CUSTOM_BASE && Atom->m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size()) )
4131                     HasBgColor = false;
4132                 AcceptEdit = EditInPlaceAcceptVar(Atom) || (Atom->m_Type==TW_TYPE_SHORTCUT);
4133             }
4134             else if(m_HierTags[h].m_Var->IsGroup() && static_cast<const CTwVarGroup *>(m_HierTags[h].m_Var)->m_SummaryCallback!=NULL)
4135             {
4136                 const CTwVarGroup *Grp = static_cast<const CTwVarGroup *>(m_HierTags[h].m_Var);
4137                 // force internal value update
4138                 for( size_t v=0; v<Grp->m_Vars.size(); v++ ) 
4139                     if( Grp->m_Vars[v]!=NULL && !Grp->m_Vars[v]->IsGroup() && Grp->m_Vars[v]->m_Visible )
4140                         static_cast<CTwVarAtom *>(Grp->m_Vars[v])->ValueToDouble();
4141
4142                 Summary[0] = '\0';
4143                 if( Grp->m_SummaryCallback==CTwMgr::CStruct::DefaultSummary )
4144                     Grp->m_SummaryCallback(&Summary[0], SummaryMaxLength, Grp, Grp->m_SummaryClientData);
4145                 else
4146                     Grp->m_SummaryCallback(&Summary[0], SummaryMaxLength, Grp->m_StructValuePtr, Grp->m_SummaryClientData);
4147                 ValStr = (const char *)(&Summary[0]);
4148             }
4149             else
4150             {
4151                 ValStr = "";    // is a group in the help bar
4152                 HasBgColor = false;
4153             }
4154             Len = (int)ValStr.length();
4155             Text = (const unsigned char *)(ValStr.c_str());
4156             x = 0;
4157             Etc = 0;
4158             _Values.push_back("");  // add a new text line
4159             if( ReadOnly || (IsMin && IsMax) || IsROText )
4160                 _Colors.push_back(m_ColValTextRO);
4161             else if( IsMin )
4162                 _Colors.push_back(m_ColValMin);
4163             else if( IsMax )
4164                 _Colors.push_back(m_ColValMax);
4165             else if( !AcceptEdit )
4166                 _Colors.push_back(m_ColValTextNE);
4167             else
4168                 _Colors.push_back(m_ColValText);
4169             if( !HasBgColor )
4170                 _BgColors.push_back(0x00000000);
4171             else if( m_HierTags[h].m_Var->IsGroup() )
4172             {
4173                 const CTwVarGroup *Grp = static_cast<const CTwVarGroup *>(m_HierTags[h].m_Var);
4174                 // if typecolor set bgcolor 
4175                 if( Grp->m_SummaryCallback==CColorExt::SummaryCB )
4176                     _BgColors.push_back(0xff000000);
4177                 else
4178                     _BgColors.push_back(m_ColStructBg);
4179             }
4180             else
4181                 _BgColors.push_back(m_ColValBg);
4182
4183             string& CurrentValue = _Values[_Values.size()-1];
4184             int wmax = _WidthMax;
4185             if( m_HighlightedLine==h && m_DrawRotoBtn )
4186                 wmax -= 3*IncrBtnWidth(m_Font->m_CharHeight);
4187             else if( m_HighlightedLine==h && m_DrawIncrDecrBtn )
4188                 wmax -= 2*IncrBtnWidth(m_Font->m_CharHeight);
4189             else if( m_HighlightedLine==h && m_DrawListBtn )
4190                 wmax -= 1*IncrBtnWidth(m_Font->m_CharHeight);
4191             else if( m_HighlightedLine==h && m_DrawBoolBtn )
4192                 wmax -= 1*IncrBtnWidth(m_Font->m_CharHeight);
4193             for( i=0; i<Len; ++i )
4194             {
4195                 ch = (Etc==0) ? Text[i] : '.';
4196                 CurrentValue += ch;
4197                 x += _Font->m_CharWidth[(int)ch];
4198                 if( Etc>0 )
4199                 {
4200                     ++Etc;
4201                     if( Etc>NbEtc )
4202                         break;
4203                 }
4204                 else if( i<Len-2 && x+(NbEtc+2)*(_Font->m_CharWidth[(int)'.'])>=wmax )
4205                     Etc = 1;
4206             }
4207         }
4208         else
4209         {
4210             _Values.push_back("");  // add a new empty line
4211             _Colors.push_back(COLOR32_BLACK);
4212             _BgColors.push_back(0x00000000);
4213         }
4214 }
4215
4216 //  ---------------------------------------------------------------------------
4217
4218 int CTwBar::ComputeLabelsWidth(const CTexFont *_Font)
4219 {
4220     int Len, i, x, s;
4221     const unsigned char *Text;
4222     int LabelsWidth = 0;    
4223     int Space = _Font->m_CharWidth[(int)' '];
4224     int LevelSpace = max(_Font->m_CharHeight-6, 4); // space used by DrawHierHandles
4225
4226     int nh = (int)m_HierTags.size();
4227     for( int h=0; h<nh; ++h )
4228     {
4229         Len = (int)m_HierTags[h].m_Var->m_Label.length();
4230         if( Len>0 )
4231             Text = (const unsigned char *)(m_HierTags[h].m_Var->m_Label.c_str());
4232         else
4233         {
4234             Text = (const unsigned char *)(m_HierTags[h].m_Var->m_Name.c_str());
4235             Len = (int)m_HierTags[h].m_Var->m_Name.length();
4236         }
4237         x = 0;
4238         bool IsCustom = m_HierTags[h].m_Var->IsCustom(); // !m_HierTags[h].m_Var->IsGroup() && (static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type>=TW_TYPE_CUSTOM_BASE && static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size());
4239         if( !IsCustom )
4240         {
4241             if( Space>0 )
4242                 for( s=0; s<m_HierTags[h].m_Level*LevelSpace; s+=Space )
4243                     x += Space;
4244             for( i=0; i<Len; ++i )
4245                 x += _Font->m_CharWidth[(int)Text[i]];
4246             x += 3*Space; // add little margin
4247         }
4248         if (x > LabelsWidth)
4249             LabelsWidth = x;
4250     }
4251
4252     return LabelsWidth;
4253 }
4254
4255 int CTwBar::ComputeValuesWidth(const CTexFont *_Font)
4256 {
4257     CTwFPU fpu; // force fpu precision
4258
4259     const CTwVarAtom *Atom = NULL;
4260     string ValStr;
4261     int Len, i, x;
4262     int Space = _Font->m_CharWidth[(int)' '];
4263     const unsigned char *Text;
4264     int ValuesWidth = 0;
4265
4266     int nh = (int)m_HierTags.size();
4267     for( int h=0; h<nh; ++h )
4268         if( !m_HierTags[h].m_Var->IsGroup() )
4269         {
4270             Atom = static_cast<const CTwVarAtom *>(m_HierTags[h].m_Var);
4271             Atom->ValueToString(&ValStr);
4272
4273             Len = (int)ValStr.length();
4274             Text = (const unsigned char *)(ValStr.c_str());
4275             x = 0;
4276             for( i=0; i<Len; ++i )
4277                 x += _Font->m_CharWidth[(int)Text[i]];
4278             x += 2*Space; // add little margin
4279             if (x > ValuesWidth)
4280                 ValuesWidth = x;
4281         }
4282
4283     return ValuesWidth;
4284 }
4285
4286 //  ---------------------------------------------------------------------------
4287
4288 static int ClampText(string& _Text, const CTexFont *_Font, int _WidthMax)
4289 {
4290     int Len = (int)_Text.length();
4291     unsigned char ch;
4292     int Width = 0;
4293     int i;
4294     for( i=0; i<Len; ++i )
4295     {
4296         ch = _Text.at(i);
4297         if( i<Len-1 && Width+_Font->m_CharWidth[(int)'.']>=_WidthMax )
4298             break;
4299         Width += _Font->m_CharWidth[ch];
4300     }
4301     if( i<Len ) // clamp
4302     {
4303         _Text.resize(i+2);
4304         _Text.at(i+0) = '.';
4305         _Text.at(i+1) = '.';
4306         Width += 2*_Font->m_CharWidth[(int)'.'];
4307     }
4308     return Width;
4309 }
4310
4311 //  ---------------------------------------------------------------------------
4312
4313 void CTwBar::Update()
4314 {
4315     assert(m_UpToDate==false);
4316     assert(m_Font);
4317     ITwGraph *Gr = g_TwMgr->m_Graph;
4318
4319     bool DoEndDraw = false;
4320     if( !Gr->IsDrawing() )
4321     {
4322         Gr->BeginDraw(g_TwMgr->m_WndWidth, g_TwMgr->m_WndHeight);
4323         DoEndDraw = true;
4324     }
4325
4326     bool ValuesWidthFit = false;
4327     if( m_ValuesWidth==VALUES_WIDTH_FIT )
4328     {
4329         ValuesWidthFit = true;
4330         m_ValuesWidth = 0;
4331     }
4332     int PrevPosY = m_PosY;
4333     int vpx, vpy, vpw, vph;
4334     vpx = 0;
4335     vpy = 0;
4336     vpw = g_TwMgr->m_WndWidth;
4337     vph = g_TwMgr->m_WndHeight;
4338     if( !m_IsMinimized && vpw>0 && vph>0 )
4339     {
4340         bool Modif = false;
4341         if( m_Resizable )
4342         {
4343             if( m_Width>vpw && m_Contained )
4344             {
4345                 m_Width = vpw;
4346                 Modif = true;
4347             }
4348             if( m_Width<8*m_Font->m_CharHeight )
4349             {
4350                 m_Width = 8*m_Font->m_CharHeight;
4351                 Modif = true;
4352             }
4353             if( m_Height>vph && m_Contained )
4354             {
4355                 m_Height = vph;
4356                 Modif = true;
4357             }
4358             if( m_Height<5*m_Font->m_CharHeight )
4359             {
4360                 m_Height = 5*m_Font->m_CharHeight;
4361                 Modif = true;
4362             }
4363         }
4364         if( m_Movable && m_Contained )
4365         {
4366             if( m_PosX+m_Width>vpx+vpw )
4367                 m_PosX = vpx+vpw-m_Width;
4368             if( m_PosX<vpx )
4369                 m_PosX = vpx;
4370             if( m_PosY+m_Height>vpy+vph )
4371                 m_PosY = vpy+vph-m_Height;
4372             if( m_PosY<vpy )
4373                 m_PosY = vpy;
4374         }
4375         m_ScrollY0 += m_PosY-PrevPosY;
4376         m_ScrollY1 += m_PosY-PrevPosY;
4377         if( m_ValuesWidth<2*m_Font->m_CharHeight )
4378         {
4379             m_ValuesWidth = 2*m_Font->m_CharHeight;
4380             Modif = true;
4381         }
4382         if( m_ValuesWidth>m_Width-4*m_Font->m_CharHeight )
4383         {
4384             m_ValuesWidth = m_Width-4*m_Font->m_CharHeight;
4385             Modif = true;
4386         }
4387         if (ValuesWidthFit)
4388             Modif = true;
4389         if( Modif && m_IsHelpBar )
4390         {
4391             g_TwMgr->m_HelpBarNotUpToDate = true;
4392             g_TwMgr->m_KeyPressedBuildText = true;
4393             g_TwMgr->m_InfoBuildText = true;
4394         }
4395     }
4396
4397     UpdateColors();
4398
4399     // update geometry relatively to (m_PosX, m_PosY)
4400     if( !m_IsPopupList )
4401     {
4402         //m_VarX0 = 2*m_Font->m_CharHeight+m_Sep;
4403         m_VarX0 = m_Font->m_CharHeight+m_Sep;
4404         //m_VarX2 = m_Width - 4;
4405         m_VarX2 = m_Width - m_Font->m_CharHeight - m_Sep-2;
4406         m_VarX1 = m_VarX2 - m_ValuesWidth;
4407     }
4408     else
4409     {
4410         //m_VarX0 = m_Font->m_CharHeight+6+m_Sep;
4411         m_VarX0 = 2;
4412         //m_VarX2 = m_Width - 4;
4413         m_VarX2 = m_Width - m_Font->m_CharHeight - m_Sep-2;
4414         m_VarX1 = m_VarX2;
4415     }
4416     if( m_VarX1<m_VarX0+32 )
4417         m_VarX1 = m_VarX0+32;
4418     if( m_VarX1>m_VarX2 )
4419         m_VarX1 = m_VarX2;
4420     if( !m_IsPopupList )
4421     {
4422         m_VarY0 = m_Font->m_CharHeight+2+m_Sep+6;
4423         m_VarY1 = m_Height-m_Font->m_CharHeight-2-m_Sep;
4424         m_VarY2 = m_Height-1;
4425     }
4426     else
4427     {
4428         m_VarY0 = 4;
4429         m_VarY1 = m_Height-2-m_Sep;
4430         m_VarY2 = m_Height-1;
4431     }
4432
4433     int NbLines = (m_VarY1-m_VarY0+1)/(m_Font->m_CharHeight+m_LineSep);
4434     if( NbLines<= 0 )
4435         NbLines = 1;
4436     if( !m_IsMinimized )
4437     {
4438         int LineNum = 0;
4439         BrowseHierarchy(&LineNum, 0, &m_VarRoot, m_FirstLine, m_FirstLine+NbLines); // add a dummy tag at the end to avoid wrong 'tag-closing' problems
4440         if( (int)m_HierTags.size()>NbLines )
4441             m_HierTags.resize(NbLines); // remove the last dummy tag
4442         m_NbHierLines = LineNum;
4443         m_NbDisplayedLines = (int)m_HierTags.size();
4444
4445         if( ValuesWidthFit )
4446         {
4447             m_ValuesWidth = ComputeValuesWidth(m_Font);
4448             if( m_ValuesWidth<2*m_Font->m_CharHeight )
4449                 m_ValuesWidth = 2*m_Font->m_CharHeight; // enough to draw buttons
4450             if( m_ValuesWidth>m_VarX2 - m_VarX0 )
4451                 m_ValuesWidth = max(m_VarX2 - m_VarX0 - m_Font->m_CharHeight, 0);
4452             m_VarX1 = m_VarX2 - m_ValuesWidth;
4453             if( m_VarX1<m_VarX0+32 )
4454                 m_VarX1 = m_VarX0+32;
4455             if( m_VarX1>m_VarX2 )
4456                 m_VarX1 = m_VarX2;
4457             m_ValuesWidth = m_VarX2 - m_VarX1;
4458         }
4459     }
4460
4461     // scroll bar
4462     int y0 = m_PosY+m_VarY0;
4463     int y1 = m_PosY+m_VarY1;
4464     int x0 = m_PosX+2;
4465     int x1 = m_PosX+m_Font->m_CharHeight-2;
4466     if( ((x0+x1)&1)==1 )
4467         x1 += 1;
4468     int w  = x1-x0+1;
4469     int h  = y1-y0-2*w;
4470     int hscr = (m_NbHierLines>0) ? ((h*m_NbDisplayedLines)/m_NbHierLines) : h;
4471     if( hscr<=4 )
4472         hscr = 4;
4473     if( hscr>h )
4474         hscr = h;
4475     int yscr = (m_NbHierLines>0) ? ((h*m_FirstLine)/m_NbHierLines) : 0;
4476     if( yscr<=0 )
4477         yscr = 0;
4478     if( yscr>h-4 )
4479         yscr = h-4;
4480     if( yscr+hscr>h )
4481         hscr = h-yscr;
4482     if( hscr>h )
4483         hscr = h;
4484     if( hscr<=4 )
4485         hscr = 4;
4486     m_ScrollYW = w;
4487     m_ScrollYH = h;
4488     m_ScrollY0 = y0+w+yscr;
4489     m_ScrollY1 = y0+w+yscr+hscr;
4490
4491     // Build title
4492     string Title;
4493     if( m_Label.size()>0 )
4494         Title = m_Label;
4495     else
4496         Title = m_Name;
4497     m_TitleWidth = ClampText(Title, m_Font, (!m_IsMinimized)?(m_Width-5*m_Font->m_CharHeight):(16*m_Font->m_CharHeight));
4498     Gr->BuildText(m_TitleTextObj, &Title, NULL, NULL, 1, m_Font, 0, 0);
4499
4500     if( !m_IsMinimized )
4501     {
4502         // Build labels
4503         vector<string>  Labels;
4504         vector<color32> Colors;
4505         vector<color32> BgColors;
4506         bool HasBgColors = false;
4507         ListLabels(Labels, Colors, BgColors, &HasBgColors, m_Font, m_VarX1-m_VarX0, m_VarX2-m_VarX0);
4508         assert( Labels.size()==Colors.size() && Labels.size()==BgColors.size() );
4509         if( Labels.size()>0 )
4510             Gr->BuildText(m_LabelsTextObj, &(Labels[0]), &(Colors[0]), &(BgColors[0]), (int)Labels.size(), m_Font, m_LineSep, HasBgColors ? m_VarX1-m_VarX0-m_Font->m_CharHeight+2 : 0);
4511         else
4512             Gr->BuildText(m_LabelsTextObj, NULL, NULL, NULL, 0, m_Font, m_LineSep, 0);
4513
4514         // Should draw click button?
4515         m_DrawClickBtn    = ( m_VarX2-m_VarX1>4*IncrBtnWidth(m_Font->m_CharHeight)
4516                               && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size()
4517                               && m_HierTags[m_HighlightedLine].m_Var!=NULL 
4518                               && !m_HierTags[m_HighlightedLine].m_Var->IsGroup()
4519                               && !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly
4520                               && (    static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BUTTON ));
4521                             //     || static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOLCPP
4522                             //     || static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL8
4523                             //     || static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL16
4524                             //     || static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL32 ));
4525
4526         // Should draw [-/+] button?
4527         m_DrawIncrDecrBtn = ( m_VarX2-m_VarX1>5*IncrBtnWidth(m_Font->m_CharHeight)
4528                               && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size()
4529                               && m_HierTags[m_HighlightedLine].m_Var!=NULL 
4530                               && !m_HierTags[m_HighlightedLine].m_Var->IsGroup()
4531                               && static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type!=TW_TYPE_BUTTON
4532                               && !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly
4533                               && !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider 
4534                               && !(m_EditInPlace.m_Active && m_EditInPlace.m_Var==m_HierTags[m_HighlightedLine].m_Var) );
4535
4536         // Should draw [v] button (list)?
4537         m_DrawListBtn     = ( m_VarX2-m_VarX1>2*IncrBtnWidth(m_Font->m_CharHeight)
4538                               && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size()
4539                               && m_HierTags[m_HighlightedLine].m_Var!=NULL 
4540                               && !m_HierTags[m_HighlightedLine].m_Var->IsGroup()
4541                               && IsEnumType(static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type)
4542                               && !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly );
4543
4544         // Should draw [<>] button (bool)?
4545         m_DrawBoolBtn     = ( m_VarX2-m_VarX1>4*IncrBtnWidth(m_Font->m_CharHeight)
4546                               && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size()
4547                               && m_HierTags[m_HighlightedLine].m_Var!=NULL 
4548                               && !m_HierTags[m_HighlightedLine].m_Var->IsGroup()
4549                               && !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly
4550                               && (    static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOLCPP
4551                                    || static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL8
4552                                    || static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL16
4553                                    || static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BOOL32 ));
4554
4555         // Should draw [o] button?
4556         m_DrawRotoBtn     = m_DrawIncrDecrBtn;
4557         /*
4558         m_DrawRotoBtn     = ( m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size()
4559                               && m_HierTags[m_HighlightedLine].m_Var!=NULL 
4560                               && !m_HierTags[m_HighlightedLine].m_Var->IsGroup()
4561                               && static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type!=TW_TYPE_BUTTON
4562                               && !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly
4563                               && !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider );
4564         */
4565
4566         // Build values
4567         vector<string>& Values = Labels;    // reuse
4568         Values.resize(0);
4569         Colors.resize(0);
4570         BgColors.resize(0);
4571         ListValues(Values, Colors, BgColors, m_Font, m_VarX2-m_VarX1);
4572         assert( BgColors.size()==Values.size() && Colors.size()==Values.size() );
4573         if( Values.size()>0 )
4574             Gr->BuildText(m_ValuesTextObj, &(Values[0]), &(Colors[0]), &(BgColors[0]), (int)Values.size(), m_Font, m_LineSep, m_VarX2-m_VarX1);
4575         else
4576             Gr->BuildText(m_ValuesTextObj, NULL, NULL, NULL, 0, m_Font, m_LineSep, m_VarX2-m_VarX1);
4577
4578         // Build key shortcut text
4579         string Shortcut;
4580         m_ShortcutLine = -1;
4581         if( m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() )
4582         {
4583             const CTwVarAtom *Atom = static_cast<const CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
4584             if( Atom->m_KeyIncr[0]>0 || Atom->m_KeyDecr[0]>0 )
4585             {
4586                 if( Atom->m_KeyIncr[0]>0 && Atom->m_KeyDecr[0]>0 )
4587                     Shortcut = "Keys: ";
4588                 else
4589                     Shortcut = "Key: ";
4590                 if( Atom->m_KeyIncr[0]>0 )
4591                     TwGetKeyString(&Shortcut, Atom->m_KeyIncr[0], Atom->m_KeyIncr[1]);
4592                 else
4593                     Shortcut += "(none)";
4594                 if( Atom->m_KeyDecr[0]>0 )
4595                 {
4596                     Shortcut += "  ";
4597                     TwGetKeyString(&Shortcut, Atom->m_KeyDecr[0], Atom->m_KeyDecr[1]);
4598                 }
4599                 m_ShortcutLine = m_HighlightedLine;
4600             }
4601         }
4602         ClampText(Shortcut, m_Font, m_Width-3*m_Font->m_CharHeight);
4603         Gr->BuildText(m_ShortcutTextObj, &Shortcut, NULL, NULL, 1, m_Font, 0, 0);
4604
4605         // build headers text
4606         if (m_HighlightLabelsHeader || m_HighlightValuesHeader) {
4607             std::string HeadersText = "Fit column content";
4608             ClampText(HeadersText, m_Font, m_Width-3*m_Font->m_CharHeight);
4609             Gr->BuildText(m_HeadersTextObj, &HeadersText, NULL, NULL, 1, m_Font, 0, 0);
4610         }
4611     }
4612
4613     if( DoEndDraw )
4614         Gr->EndDraw();
4615
4616     m_UpToDate = true;
4617     m_LastUpdateTime = float(g_BarTimer.GetTime());
4618 }
4619
4620 //  ---------------------------------------------------------------------------
4621
4622 void CTwBar::DrawHierHandle()
4623 {
4624     assert(m_Font);
4625     ITwGraph *Gr = g_TwMgr->m_Graph;
4626
4627     //int x0 = m_PosX+m_Font->m_CharHeight+1;
4628     int x0 = m_PosX+3;
4629     //int x2 = m_PosX+m_VarX0-5;
4630     //int x2 = m_PosX+3*m_Font->m_CharWidth[(int)' ']-2;
4631     int x2 = m_PosX+m_Font->m_CharHeight-3;
4632     if( x2-x0<4 )
4633         x2 = x0+4;
4634     if( (x2-x0)&1 )
4635         --x2;
4636     int x1 = (x0+x2)/2;
4637     int w = x2-x0+1;
4638     int y0 = m_PosY+m_VarY0 +1;
4639     int y1;
4640     int dh0 = (m_Font->m_CharHeight+m_Sep-1-w)/2;
4641     if( dh0<0 )
4642         dh0 = 0;
4643     int dh1 = dh0+w-1;
4644     int i, h=0;
4645
4646     if( !m_IsPopupList )
4647     {
4648         CTwVarGroup *Grp;
4649         int nh = (int)m_HierTags.size();
4650         for( h=0; h<nh; ++h )
4651         {
4652             y1 = y0 + m_Font->m_CharHeight+m_Sep-1;
4653             if( m_HierTags[h].m_Var->IsGroup() )
4654                 Grp = static_cast<CTwVarGroup *>(m_HierTags[h].m_Var);
4655             else
4656                 Grp = NULL;
4657
4658             int dx = m_HierTags[h].m_Level * (x2-x0);
4659
4660             if( Grp )
4661             {
4662                 if( m_ColGrpBg!=0 && Grp->m_StructValuePtr==NULL )
4663                 {
4664                     color32 cb = (Grp->m_StructType==TW_TYPE_HELP_STRUCT) ? m_ColStructBg : m_ColGrpBg;
4665                     //Gr->DrawRect(x0+dx-1, y0, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, cb);
4666                     Gr->DrawRect(x2+dx+3, y0, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1+m_LineSep-1, cb);
4667                 }
4668
4669                 if( m_DrawHandles )
4670                 {
4671                     Gr->DrawLine(dx+x2+1,y0+dh0+1, dx+x2+1,y0+dh1+1, m_ColLineShadow);
4672                     Gr->DrawLine(dx+x0+1,y0+dh1+1, dx+x2+2,y0+dh1+1, m_ColLineShadow);
4673                 }
4674
4675                 //Gr->DrawRect(x0+1,y0+dh0+1,x2-1,y0+dh1-1, (h==m_HighlightedLine) ? m_ColHighBtn : m_ColBtn);
4676                 Gr->DrawRect(dx+x0, y0+dh0, dx+x2, y0+dh1, (h==m_HighlightedLine) ? m_ColHighFold : m_ColFold);
4677                 if( m_DrawHandles )
4678                 {
4679                     Gr->DrawLine(dx+x0,y0+dh0, dx+x2,y0+dh0, m_ColLine);
4680                     Gr->DrawLine(dx+x2,y0+dh0, dx+x2,y0+dh1+1, m_ColLine);
4681                     Gr->DrawLine(dx+x2,y0+dh1, dx+x0,y0+dh1, m_ColLine);
4682                     Gr->DrawLine(dx+x0,y0+dh1, dx+x0,y0+dh0, m_ColLine);
4683                 }
4684                 
4685                 Gr->DrawLine(dx+x0+2,y0+dh0+w/2, dx+x2-1,y0+dh0+w/2, m_ColTitleText);
4686                 if( !Grp->m_Open )
4687                     Gr->DrawLine(dx+x1,y0+dh0+2, dx+x1,y0+dh1-1, m_ColTitleText);
4688
4689                 /*
4690                 if( m_ColGrpBg!=0 && Grp->m_StructValuePtr==NULL )
4691                 {
4692                     color32 cb = (Grp->m_StructType==TW_TYPE_HELP_STRUCT) ? m_ColStructBg : m_ColGrpBg;
4693                     //int decal = m_Font->m_CharHeight/2-2+2*m_HierTags[h].m_Level;
4694                     //if( decal>m_Font->m_CharHeight-3 )
4695                     //  decal = m_Font->m_CharHeight-3;
4696                     int margin = dx; //m_Font->m_CharWidth[(int)' ']*m_HierTags[h].m_Level;
4697                     //Gr->DrawRect(m_PosX+m_VarX0+margin, y0+decal, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, cb);
4698                     Gr->DrawRect(m_PosX+m_VarX0+margin-1, y0+1, m_PosX+m_VarX2, y0+m_Font->m_CharHeight, cb);// m_ColHierBg);
4699                     //Gr->DrawRect(m_PosX+m_VarX0-4, y0+m_Font->m_CharHeight/2-1, m_PosX+m_VarX0+margin-2, y0+m_Font->m_CharHeight/2, m_ColHierBg);
4700                 }
4701                 */
4702             }
4703             else if( static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type==TW_TYPE_HELP_GRP && m_ColHelpBg!=0 )
4704                 Gr->DrawRect(m_PosX+m_VarX0+m_HierTags[h].m_Var->m_LeftMargin, y0+m_HierTags[h].m_Var->m_TopMargin, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, m_ColHelpBg);
4705             //else if( static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type==TW_TYPE_HELP_HEADER && m_ColHelpBg!=0 )
4706             //  Gr->DrawRect(m_PosX+m_VarX0+m_HierTags[h].m_Var->m_LeftMargin, y0+m_HierTags[h].m_Var->m_TopMargin, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1, m_ColHelpBg);
4707             /*
4708             else if( static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type==TW_TYPE_BUTTON && m_ColBtn!=0 )
4709             {
4710                 // draw button
4711                 int cbx0 = m_PosX+m_VarX2-2*bw+bw/2, cby0 = y0+2, cbx1 = m_PosX+m_VarX2-2-bw/2, cby1 = y0+m_Font->m_CharHeight-4;
4712                 if( m_HighlightClickBtn )
4713                 {
4714                     Gr->DrawRect(cbx0+2, cby0+2, cbx1+2, cby1+2, m_ColBtn);
4715                     Gr->DrawLine(cbx0+3, cby1+3, cbx1+4, cby1+3, 0x7F000000);
4716                     Gr->DrawLine(cbx1+3, cby0+3, cbx1+3, cby1+3, 0x7F000000);                       
4717                 }
4718                 else
4719                 {
4720                     Gr->DrawRect(cbx0+3, cby1+1, cbx1+3, cby1+3, 0x7F000000);
4721                     Gr->DrawRect(cbx1+1, cby0+3, cbx1+3, cby1, 0x7F000000);
4722                     Gr->DrawRect(cbx0, cby0, cbx1, cby1, m_ColBtn);
4723                 }
4724             }
4725             */
4726
4727             y0 = y1+m_LineSep;
4728         }
4729     }
4730
4731     if( m_NbDisplayedLines<m_NbHierLines )
4732     {
4733         // Draw scroll bar
4734         y0 = m_PosY+m_VarY0;
4735         y1 = m_PosY+m_VarY1;
4736         //x0 = m_PosX+2;
4737         //x1 = m_PosX+m_Font->m_CharHeight-2;
4738         x0 = m_PosX + m_VarX2+4;
4739         x1 = x0 + m_Font->m_CharHeight-4;
4740         if( ((x0+x1)&1)==1 )
4741             x1 += 1;
4742         w  = m_ScrollYW;
4743         h  = m_ScrollYH;
4744
4745         Gr->DrawRect(x0+2,y0+w, x1-2,y1-1-w, (m_ColBg&0xffffff)|0x11000000);
4746         if( m_DrawHandles || m_IsPopupList )
4747         {
4748             // scroll handle shadow lines
4749             Gr->DrawLine(x1-1,m_ScrollY0+1, x1-1,m_ScrollY1+1, m_ColLineShadow);
4750             Gr->DrawLine(x0+2,m_ScrollY1+1, x1,m_ScrollY1+1, m_ColLineShadow);
4751             
4752             // up & down arrow
4753             for( i=0; i<(x1-x0-2)/2; ++i )
4754             {
4755                 Gr->DrawLine(x0+2+i,y0+w-2*i, x1-i,y0+w-2*i, m_ColLineShadow);
4756                 Gr->DrawLine(x0+1+i,y0+w-1-2*i, x1-1-i,y0+w-1-2*i, m_HighlightUpScroll?((m_ColLine&0xffffff)|0x4f000000):m_ColLine);
4757
4758                 Gr->DrawLine(x0+2+i,y1-w+2+2*i, x1-i,y1-w+2+2*i, m_ColLineShadow);
4759                 Gr->DrawLine(x0+1+i,y1-w+1+2*i, x1-1-i,y1-w+1+2*i, m_HighlightDnScroll?((m_ColLine&0xffffff)|0x4f000000):m_ColLine);
4760             }
4761
4762             // middle lines
4763             Gr->DrawLine((x0+x1)/2-1,y0+w, (x0+x1)/2-1,m_ScrollY0, m_ColLine);
4764             Gr->DrawLine((x0+x1)/2,y0+w, (x0+x1)/2,m_ScrollY0, m_ColLine);
4765             Gr->DrawLine((x0+x1)/2+1,y0+w, (x0+x1)/2+1,m_ScrollY0, m_ColLineShadow);
4766             Gr->DrawLine((x0+x1)/2-1,m_ScrollY1, (x0+x1)/2-1,y1-w+1, m_ColLine);
4767             Gr->DrawLine((x0+x1)/2,m_ScrollY1, (x0+x1)/2,y1-w+1, m_ColLine);
4768             Gr->DrawLine((x0+x1)/2+1,m_ScrollY1, (x0+x1)/2+1,y1-w+1, m_ColLineShadow);
4769             // scroll handle lines
4770             Gr->DrawRect(x0+2,m_ScrollY0+1, x1-3,m_ScrollY1-1, m_HighlightScroll?m_ColHighBtn:m_ColBtn);
4771             Gr->DrawLine(x1-2,m_ScrollY0, x1-2,m_ScrollY1, m_ColLine);
4772             Gr->DrawLine(x0+1,m_ScrollY0, x0+1,m_ScrollY1, m_ColLine);
4773             Gr->DrawLine(x0+1,m_ScrollY1, x1-1,m_ScrollY1, m_ColLine);
4774             Gr->DrawLine(x0+1,m_ScrollY0, x1-2,m_ScrollY0, m_ColLine);
4775         }
4776         else
4777             Gr->DrawRect(x0+3,m_ScrollY0+1, x1-3,m_ScrollY1-1, m_ColBtn);
4778     }
4779
4780     if( m_DrawHandles && !m_IsPopupList )
4781     {
4782         if( m_Resizable ) // Draw resize handles
4783         {
4784             //   lower-left
4785             Gr->DrawLine(m_PosX+3, m_PosY+m_Height-m_Font->m_CharHeight+3, m_PosX+3, m_PosY+m_Height-4, m_ColLine);
4786             Gr->DrawLine(m_PosX+4, m_PosY+m_Height-m_Font->m_CharHeight+4, m_PosX+4, m_PosY+m_Height-3, m_ColLineShadow);
4787             Gr->DrawLine(m_PosX+3, m_PosY+m_Height-4, m_PosX+m_Font->m_CharHeight-4, m_PosY+m_Height-4, m_ColLine);
4788             Gr->DrawLine(m_PosX+4, m_PosY+m_Height-3, m_PosX+m_Font->m_CharHeight-3, m_PosY+m_Height-3, m_ColLineShadow);
4789             //   lower-right
4790             Gr->DrawLine(m_PosX+m_Width-4, m_PosY+m_Height-m_Font->m_CharHeight+3, m_PosX+m_Width-4, m_PosY+m_Height-4, m_ColLine);
4791             Gr->DrawLine(m_PosX+m_Width-3, m_PosY+m_Height-m_Font->m_CharHeight+4, m_PosX+m_Width-3, m_PosY+m_Height-3, m_ColLineShadow);
4792             Gr->DrawLine(m_PosX+m_Width-4, m_PosY+m_Height-4, m_PosX+m_Width-m_Font->m_CharHeight+3, m_PosY+m_Height-4, m_ColLine);
4793             Gr->DrawLine(m_PosX+m_Width-3, m_PosY+m_Height-3, m_PosX+m_Width-m_Font->m_CharHeight+4, m_PosY+m_Height-3, m_ColLineShadow);
4794             //   upper-left
4795             Gr->DrawLine(m_PosX+3, m_PosY+m_Font->m_CharHeight-4, m_PosX+3, m_PosY+3, m_ColLine);
4796             Gr->DrawLine(m_PosX+4, m_PosY+m_Font->m_CharHeight-3, m_PosX+4, m_PosY+4, m_ColLineShadow);
4797             Gr->DrawLine(m_PosX+3, m_PosY+3, m_PosX+m_Font->m_CharHeight-4, m_PosY+3, m_ColLine);
4798             Gr->DrawLine(m_PosX+4, m_PosY+4, m_PosX+m_Font->m_CharHeight-3, m_PosY+4, m_ColLineShadow);
4799             //   upper-right
4800             Gr->DrawLine(m_PosX+m_Width-4, m_PosY+3, m_PosX+m_Width-m_Font->m_CharHeight+3, m_PosY+3, m_ColLine);
4801             Gr->DrawLine(m_PosX+m_Width-3, m_PosY+4, m_PosX+m_Width-m_Font->m_CharHeight+4, m_PosY+4, m_ColLineShadow);
4802             Gr->DrawLine(m_PosX+m_Width-4, m_PosY+m_Font->m_CharHeight-4, m_PosX+m_Width-4, m_PosY+3, m_ColLine);
4803             Gr->DrawLine(m_PosX+m_Width-3, m_PosY+m_Font->m_CharHeight-3, m_PosX+m_Width-3, m_PosY+4, m_ColLineShadow);
4804         }
4805
4806         int xm = m_PosX+m_Width-2*m_Font->m_CharHeight, wm=m_Font->m_CharHeight-6;
4807         wm = (wm<6) ? 6 : wm;
4808         if( m_Iconifiable ) // Draw minimize button
4809         {
4810             Gr->DrawRect(xm+1, m_PosY+4, xm+wm-1, m_PosY+3+wm, m_HighlightMinimize?m_ColHighBtn:((m_ColBtn&0xffffff)|0x4f000000));
4811             Gr->DrawLine(xm, m_PosY+3, xm+wm, m_PosY+3, m_ColLine);
4812             Gr->DrawLine(xm+wm, m_PosY+3, xm+wm, m_PosY+3+wm, m_ColLine);
4813             Gr->DrawLine(xm+wm, m_PosY+3+wm, xm, m_PosY+3+wm, m_ColLine);
4814             Gr->DrawLine(xm, m_PosY+3+wm, xm, m_PosY+3, m_ColLine);
4815             Gr->DrawLine(xm+wm+1, m_PosY+4, xm+wm+1, m_PosY+4+wm, m_ColLineShadow);
4816             Gr->DrawLine(xm+wm+1, m_PosY+4+wm, xm, m_PosY+4+wm, m_ColLineShadow);
4817             Gr->DrawLine(xm+wm/3+((wm<9)?1:0)-1, m_PosY+4+wm/3-((wm<9)?0:1), xm+wm/2, m_PosY+2+wm-1, m_ColTitleText, true);
4818             Gr->DrawLine(xm+wm-wm/3+((wm<9)?0:1), m_PosY+4+wm/3-((wm<9)?0:1), xm+wm/2, m_PosY+2+wm-1, m_ColTitleText, true);
4819         }
4820
4821         if( g_TwMgr->m_FontResizable ) // Draw font button
4822         {
4823             xm = m_PosX+m_Font->m_CharHeight+2;
4824             Gr->DrawRect(xm+1, m_PosY+4, xm+wm-1, m_PosY+3+wm, m_HighlightFont?m_ColHighBtn:((m_ColBtn&0xffffff)|0x4f000000));
4825             Gr->DrawLine(xm, m_PosY+3, xm+wm, m_PosY+3, m_ColLine);
4826             Gr->DrawLine(xm+wm, m_PosY+3, xm+wm, m_PosY+3+wm, m_ColLine);
4827             Gr->DrawLine(xm+wm, m_PosY+3+wm, xm, m_PosY+3+wm, m_ColLine);
4828             Gr->DrawLine(xm, m_PosY+3+wm, xm, m_PosY+3, m_ColLine);
4829             Gr->DrawLine(xm+wm+1, m_PosY+4, xm+wm+1, m_PosY+4+wm, m_ColLineShadow);
4830             Gr->DrawLine(xm+wm+1, m_PosY+4+wm, xm, m_PosY+4+wm, m_ColLineShadow);
4831             Gr->DrawLine(xm+wm/2-wm/6, m_PosY+3+wm/3, xm+wm/2+wm/6+1, m_PosY+3+wm/3, m_ColTitleText);
4832             Gr->DrawLine(xm+wm/2-wm/6, m_PosY+3+wm/3, xm+wm/2-wm/6, m_PosY+4+wm-wm/3+(wm>11?1:0), m_ColTitleText);
4833             Gr->DrawLine(xm+wm/2-wm/6, m_PosY+3+wm/2+(wm>11?1:0), xm+wm/2+wm/6, m_PosY+3+wm/2+(wm>11?1:0), m_ColTitleText);
4834         }
4835     }
4836 }
4837
4838 //  ---------------------------------------------------------------------------
4839
4840 void CTwBar::Draw(int _DrawPart)
4841 {
4842     PERF( PerfTimer Timer; double DT; )
4843
4844     assert(m_Font);
4845     ITwGraph *Gr = g_TwMgr->m_Graph;
4846
4847     m_CustomRecords.clear();
4848
4849     if( float(g_BarTimer.GetTime())>m_LastUpdateTime+m_UpdatePeriod )
4850         NotUpToDate();
4851
4852     if( m_HighlightedLine!=m_HighlightedLinePrev )
4853     {
4854         m_HighlightedLinePrev = m_HighlightedLine;
4855         NotUpToDate();
4856     }
4857
4858     if( m_IsHelpBar && g_TwMgr->m_HelpBarNotUpToDate )
4859         g_TwMgr->UpdateHelpBar();
4860
4861     if( !m_UpToDate )
4862         Update();
4863
4864     if( !m_IsMinimized )
4865     {
4866         int y = m_PosY+1;
4867         int LevelSpace = max(m_Font->m_CharHeight-6, 4); // space used by DrawHierHandles
4868
4869         color32 colBg = m_ColBg, colBg1 = m_ColBg1, colBg2 = m_ColBg2;
4870         if( m_DrawHandles || m_IsPopupList )
4871         {
4872             unsigned int alphaMin = 0x70;
4873             if( m_IsPopupList )
4874                 alphaMin = 0xa0;
4875             if( (colBg>>24)<alphaMin )
4876                 colBg = (colBg&0xffffff)|(alphaMin<<24);
4877             if( (colBg1>>24)<alphaMin )
4878                 colBg1 = (colBg1&0xffffff)|(alphaMin<<24);
4879             if( (colBg2>>24)<alphaMin )
4880                 colBg2 = (colBg2&0xffffff)|(alphaMin<<24);
4881         }
4882
4883         // Draw title
4884         if( !m_IsPopupList )
4885         {
4886             PERF( Timer.Reset(); )
4887             if( _DrawPart&DRAW_BG )
4888             {
4889                 //Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Font->m_CharHeight+1, (m_HighlightTitle||m_MouseDragTitle) ? m_ColTitleHighBg : (m_DrawHandles ? m_ColTitleBg : m_ColTitleUnactiveBg));
4890                 if( m_HighlightTitle || m_MouseDragTitle )
4891                     Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Font->m_CharHeight+1, m_ColTitleHighBg);
4892                 else if (m_DrawHandles)
4893                     Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Font->m_CharHeight+1, m_ColTitleBg, m_ColTitleBg, colBg2, colBg1);
4894                 else
4895                     Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Font->m_CharHeight+1, m_ColTitleBg, m_ColTitleBg, colBg2, colBg1);
4896             }
4897             if( _DrawPart&DRAW_CONTENT )
4898             {
4899                 const color32 COL0 = 0x50ffffff;
4900                 const color32 COL1 = 0x501f1f1f;
4901                 Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, y, COL0, COL0, COL1, COL1);
4902                 if( m_ColTitleShadow!=0 )
4903                     Gr->DrawText(m_TitleTextObj, m_PosX+(m_Width-m_TitleWidth)/2+1, m_PosY+1, m_ColTitleShadow, 0);
4904                 Gr->DrawText(m_TitleTextObj, m_PosX+(m_Width-m_TitleWidth)/2, m_PosY, m_ColTitleText, 0);
4905             }
4906             y = m_PosY+m_Font->m_CharHeight+1;
4907             if( _DrawPart&DRAW_CONTENT && m_DrawHandles )
4908                 Gr->DrawLine(m_PosX, y, m_PosX+m_Width-1, y, 0x30ffffff); // 0x80afafaf);
4909             y++;
4910             PERF( DT = Timer.GetTime(); printf("Title=%.4fms ", 1000.0*DT); )
4911         }
4912
4913         // Draw background
4914         PERF( Timer.Reset(); )
4915         if( _DrawPart&DRAW_BG )
4916         {
4917             Gr->DrawRect(m_PosX, y, m_PosX+m_Width-1, m_PosY+m_Height-1, colBg2, colBg1, colBg1, colBg);
4918             //Gr->DrawRect(m_PosX, y, m_PosX+m_VarX0-5, m_PosY+m_Height-1, m_ColHierBg);
4919             Gr->DrawRect(m_PosX+m_VarX2+3, y, m_PosX+m_Width-1, m_PosY+m_Height-1, m_ColHierBg);
4920         }
4921
4922         if( _DrawPart&DRAW_CONTENT )
4923         {
4924             // Draw highlighted line
4925             if( m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var!=NULL
4926                 && (m_HierTags[m_HighlightedLine].m_Var->IsGroup() 
4927                     || (!static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly && !m_IsHelpBar 
4928                         && !m_HierTags[m_HighlightedLine].m_Var->IsCustom() ) ) ) // !(static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type>=TW_TYPE_CUSTOM_BASE && static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size()))) )
4929             {
4930                 int y0 = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_LineSep);
4931                 Gr->DrawRect(m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level, y0+1, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1+m_LineSep-1, m_ColHighBg0, m_ColHighBg0, m_ColHighBg1, m_ColHighBg1);
4932                 int eps = (g_TwMgr->m_GraphAPI==TW_OPENGL || g_TwMgr->m_GraphAPI==TW_OPENGL_CORE) ? 1 : 0;
4933                 if( !m_EditInPlace.m_Active )
4934                     Gr->DrawLine(m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level, y0+m_Font->m_CharHeight+m_LineSep-1+eps, m_PosX+m_VarX2, y0+m_Font->m_CharHeight+m_LineSep-1+eps, m_ColUnderline);
4935             }
4936             else if( m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() )
4937             {
4938                 int y0 = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_LineSep);
4939                 color32 col = ColorBlend(m_ColHighBg0, m_ColHighBg1, 0.5f);
4940                 CTwVarAtom *Atom = static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
4941                 if( !Atom->IsCustom() // !(Atom->m_Type>=TW_TYPE_CUSTOM_BASE && Atom->m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size()) 
4942                     && !(Atom->m_Type==TW_TYPE_BUTTON && Atom->m_Val.m_Button.m_Callback==NULL) )
4943                     Gr->DrawRect(m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level, y0+1, m_PosX+m_VarX2, y0+m_Font->m_CharHeight-1+m_LineSep-1, col);
4944                 else
4945                     Gr->DrawRect(m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level, y0+1, m_PosX+LevelSpace+6+LevelSpace*m_HierTags[m_HighlightedLine].m_Level+4, y0+m_Font->m_CharHeight-1+m_LineSep-1, col);
4946             }
4947             color32 clight = 0x5FFFFFFF; // bar contour
4948             Gr->DrawLine(m_PosX, m_PosY, m_PosX, m_PosY+m_Height, clight);
4949             Gr->DrawLine(m_PosX, m_PosY, m_PosX+m_Width, m_PosY, clight);
4950             Gr->DrawLine(m_PosX+m_Width, m_PosY, m_PosX+m_Width, m_PosY+m_Height, clight);
4951             Gr->DrawLine(m_PosX, m_PosY+m_Height, m_PosX+m_Width, m_PosY+m_Height, clight);
4952             int dshad = 3;  // bar shadows
4953             color32 cshad = (((m_Color>>24)/2)<<24) & 0xFF000000;
4954             Gr->DrawRect(m_PosX, m_PosY+m_Height, m_PosX+dshad, m_PosY+m_Height+dshad, 0, cshad, 0, 0);
4955             Gr->DrawRect(m_PosX+dshad+1, m_PosY+m_Height, m_PosX+m_Width-1, m_PosY+m_Height+dshad, cshad, cshad, 0, 0);
4956             Gr->DrawRect(m_PosX+m_Width, m_PosY+m_Height, m_PosX+m_Width+dshad, m_PosY+m_Height+dshad, cshad, 0, 0, 0);
4957             Gr->DrawRect(m_PosX+m_Width, m_PosY, m_PosX+m_Width+dshad, m_PosY+dshad, 0, 0, cshad, 0);
4958             Gr->DrawRect(m_PosX+m_Width, m_PosY+dshad+1, m_PosX+m_Width+dshad, m_PosY+m_Height-1, cshad, 0, cshad, 0);
4959             PERF( DT = Timer.GetTime(); printf("Bg=%.4fms ", 1000.0*DT); )
4960
4961             // Draw hierarchy handle
4962             PERF( Timer.Reset(); )
4963             DrawHierHandle();
4964             PERF( DT = Timer.GetTime(); printf("Handles=%.4fms ", 1000.0*DT); )
4965
4966             // Draw labels
4967             PERF( Timer.Reset(); )
4968             Gr->DrawText(m_LabelsTextObj, m_PosX+LevelSpace+6, m_PosY+m_VarY0, 0 /*m_ColLabelText*/, 0);
4969             PERF( DT = Timer.GetTime(); printf("Labels=%.4fms ", 1000.0*DT); )
4970
4971             // Draw values
4972             if( !m_IsPopupList )
4973             {
4974                 PERF( Timer.Reset(); )
4975                 Gr->DrawText(m_ValuesTextObj, m_PosX+m_VarX1, m_PosY+m_VarY0, 0 /*m_ColValText*/, 0 /*m_ColValBg*/);
4976                 PERF( DT = Timer.GetTime(); printf("Values=%.4fms ", 1000.0*DT); )
4977             }
4978
4979             // Draw preview for color values and draw buttons and custom types
4980             int h, nh = (int)m_HierTags.size();
4981             int yh = m_PosY+m_VarY0;
4982             int bw = IncrBtnWidth(m_Font->m_CharHeight);
4983             for( h=0; h<nh; ++h )
4984             {
4985                 if( m_HierTags[h].m_Var->IsGroup() )
4986                 {
4987                     const CTwVarGroup * Grp = static_cast<const CTwVarGroup *>(m_HierTags[h].m_Var);
4988                     if( Grp->m_SummaryCallback==CColorExt::SummaryCB && Grp->m_StructValuePtr!=NULL )
4989                     {
4990                         // draw color value
4991                         if( Grp->m_Vars.size()>0 && Grp->m_Vars[0]!=NULL && !Grp->m_Vars[0]->IsGroup() )
4992                             static_cast<CTwVarAtom *>(Grp->m_Vars[0])->ValueToDouble(); // force ext update
4993                         int ydecal = (g_TwMgr->m_GraphAPI==TW_OPENGL || g_TwMgr->m_GraphAPI==TW_OPENGL_CORE) ? 1 : 0;
4994                         const int checker = 8;
4995                         for( int c=0; c<checker; ++c )
4996                             Gr->DrawRect(m_PosX+m_VarX1+(c*(m_VarX2-m_VarX1))/checker, yh+1+ydecal+((c%2)*(m_Font->m_CharHeight-2))/2, m_PosX+m_VarX1-1+((c+1)*(m_VarX2-m_VarX1))/checker, yh+ydecal+(((c%2)+1)*(m_Font->m_CharHeight-2))/2, 0xffffffff);
4997                         Gr->DrawRect(m_PosX+m_VarX1, yh+1+ydecal, m_PosX+m_VarX2-1, yh+ydecal+m_Font->m_CharHeight-2, 0xbfffffff);
4998                         const CColorExt *colExt = static_cast<const CColorExt *>(Grp->m_StructValuePtr);
4999                         color32 col = Color32FromARGBi((colExt->m_HasAlpha ? colExt->A : 255), colExt->R, colExt->G, colExt->B);
5000                         if( col!=0 )
5001                             Gr->DrawRect(m_PosX+m_VarX1, yh+1+ydecal, m_PosX+m_VarX2-1, yh+ydecal+m_Font->m_CharHeight-2, col);
5002                         /*
5003                         Gr->DrawLine(m_PosX+m_VarX1-1, yh, m_PosX+m_VarX2+1, yh, 0xff000000);
5004                         Gr->DrawLine(m_PosX+m_VarX1-1, yh+m_Font->m_CharHeight, m_PosX+m_VarX2+1, yh+m_Font->m_CharHeight, 0xff000000);
5005                         Gr->DrawLine(m_PosX+m_VarX1-1, yh, m_PosX+m_VarX1-1, yh+m_Font->m_CharHeight, 0xff000000);
5006                         Gr->DrawLine(m_PosX+m_VarX2, yh, m_PosX+m_VarX2, yh+m_Font->m_CharHeight, 0xff000000);
5007                         */
5008                     }
5009                     //else if( Grp->m_SummaryCallback==CustomTypeSummaryCB && Grp->m_StructValuePtr!=NULL )
5010                     //{
5011                     //}
5012                 }
5013                 else if( static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type==TW_TYPE_BUTTON && !m_IsPopupList )
5014                 {
5015                     // draw button
5016                     int cbx0, cbx1;
5017                     if( m_ButtonAlign == BUTTON_ALIGN_LEFT )
5018                     {
5019                         cbx0 = m_PosX+m_VarX1+2;
5020                         cbx1 = m_PosX+m_VarX1+bw;
5021                     }
5022                     else if( m_ButtonAlign == BUTTON_ALIGN_CENTER )
5023                     {
5024                         cbx0 = m_PosX+(m_VarX1+m_VarX2)/2-bw/2+1;
5025                         cbx1 = m_PosX+(m_VarX1+m_VarX2)/2+bw/2-1;
5026                     }
5027                     else
5028                     {
5029                         cbx0 = m_PosX+m_VarX2-2*bw+bw/2;
5030                         cbx1 = m_PosX+m_VarX2-2-bw/2;
5031                     }
5032                     int cby0 = yh+3;
5033                     int cby1 = yh+m_Font->m_CharHeight-3;
5034                     if( !static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_ReadOnly )
5035                     {
5036                         double BtnAutoDelta = g_TwMgr->m_Timer.GetTime() - m_HighlightClickBtnAuto;
5037                         if( (m_HighlightClickBtn || (BtnAutoDelta>=0 && BtnAutoDelta<0.1)) && h==m_HighlightedLine )
5038                         {
5039                             cbx0--; cby0--; cbx1--; cby1--;
5040                             Gr->DrawRect(cbx0+2, cby0+2, cbx1+2, cby1+2, m_ColHighBtn);
5041                             Gr->DrawLine(cbx0+3, cby1+3, cbx1+4, cby1+3, 0xAF000000);
5042                             Gr->DrawLine(cbx1+3, cby0+3, cbx1+3, cby1+3, 0xAF000000);                       
5043                             Gr->DrawLine(cbx0+2, cby0+2, cbx0+2, cby1+2, m_ColLine);
5044                             Gr->DrawLine(cbx0+2, cby1+2, cbx1+2, cby1+2, m_ColLine);
5045                             Gr->DrawLine(cbx1+2, cby1+2, cbx1+2, cby0+2, m_ColLine);
5046                             Gr->DrawLine(cbx1+2, cby0+2, cbx0+2, cby0+2, m_ColLine);
5047                         }
5048                         else
5049                         {
5050                             Gr->DrawRect(cbx0+2, cby1+1, cbx1+2, cby1+2, (h==m_HighlightedLine)?0xAF000000:0x7F000000);
5051                             Gr->DrawRect(cbx1+1, cby0+2, cbx1+2, cby1, (h==m_HighlightedLine)?0xAF000000:0x7F000000);
5052                             Gr->DrawRect(cbx0, cby0, cbx1, cby1, (h==m_HighlightedLine)?m_ColHighBtn:m_ColBtn);
5053                             Gr->DrawLine(cbx0, cby0, cbx0, cby1, m_ColLine);
5054                             Gr->DrawLine(cbx0, cby1, cbx1, cby1, m_ColLine);
5055                             Gr->DrawLine(cbx1, cby1, cbx1, cby0, m_ColLine);
5056                             Gr->DrawLine(cbx1, cby0, cbx0, cby0, m_ColLine);
5057                         }
5058                     }
5059                     else if( static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Val.m_Button.m_Callback!=NULL )
5060                     {
5061                         Gr->DrawRect(cbx0+1, cby0+1, cbx1+1, cby1+1, m_ColBtn);
5062                     }
5063                     else if( static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Val.m_Button.m_Separator==1 )
5064                     {
5065                         int LevelSpace = max(m_Font->m_CharHeight-6, 4); // space used by DrawHierHandles
5066                         Gr->DrawLine(m_PosX+m_VarX0+m_HierTags[h].m_Level*LevelSpace, yh+m_Font->m_CharHeight/2, m_PosX+m_VarX2, yh+m_Font->m_CharHeight/2, m_ColSeparator );
5067                     }
5068                 }
5069                 else if( m_HierTags[h].m_Var->IsCustom() ) //static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type>=TW_TYPE_CUSTOM_BASE && static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Type<TW_TYPE_CUSTOM_BASE+(int)g_TwMgr->m_Customs.size() )
5070                 {   // record custom types
5071                     CTwMgr::CMemberProxy *mProxy = static_cast<CTwVarAtom *>(m_HierTags[h].m_Var)->m_Val.m_Custom.m_MemberProxy;
5072                     if( mProxy!=NULL && mProxy->m_StructProxy!=NULL )
5073                     {
5074                         CustomMap::iterator it = m_CustomRecords.find(mProxy->m_StructProxy);
5075                         int xMin = m_PosX + m_VarX0 + m_HierTags[h].m_Level*LevelSpace;
5076                         int xMax = m_PosX + m_VarX2 - 2;
5077                         int yMin = yh + 1;
5078                         int yMax = yh + m_Font->m_CharHeight;
5079                         if( it==m_CustomRecords.end() )
5080                         {
5081                             std::pair<CTwMgr::CStructProxy*, CCustomRecord> pr;
5082                             pr.first = mProxy->m_StructProxy;
5083                             pr.second.m_IndexMin = pr.second.m_IndexMax = mProxy->m_MemberIndex;
5084                             pr.second.m_XMin = xMin; 
5085                             pr.second.m_XMax = xMax;
5086                             pr.second.m_YMin = yMin;
5087                             pr.second.m_YMax = yMax;
5088                             pr.second.m_Y0 = 0; // will be filled by the draw loop below
5089                             pr.second.m_Y1 = 0; // will be filled by the draw loop below
5090                             pr.second.m_Var = mProxy->m_VarParent;
5091                             m_CustomRecords.insert(pr);
5092                         }
5093                         else
5094                         {
5095                             it->second.m_IndexMin = min(it->second.m_IndexMin, mProxy->m_MemberIndex);
5096                             it->second.m_IndexMax = min(it->second.m_IndexMax, mProxy->m_MemberIndex);
5097                             it->second.m_XMin = min(it->second.m_XMin, xMin);
5098                             it->second.m_XMax = max(it->second.m_XMax, xMax);
5099                             it->second.m_YMin = min(it->second.m_YMin, yMin);
5100                             it->second.m_YMax = max(it->second.m_YMax, yMax);
5101                             it->second.m_Y0 = 0;
5102                             it->second.m_Y1 = 0;
5103                             assert( it->second.m_Var==mProxy->m_VarParent );
5104                         }
5105                     }
5106                 }
5107
5108                 yh += m_Font->m_CharHeight+m_LineSep;
5109             }
5110
5111             // Draw custom types
5112             for( CustomMap::iterator it = m_CustomRecords.begin(); it!=m_CustomRecords.end(); ++it )
5113             {
5114                 CTwMgr::CStructProxy *sProxy = it->first;
5115                 assert( sProxy!=NULL );
5116                 CCustomRecord& r = it->second;
5117                 if( sProxy->m_CustomDrawCallback!=NULL )
5118                 {
5119                     int y0 = r.m_YMin - max(r.m_IndexMin - sProxy->m_CustomIndexFirst, 0)*(m_Font->m_CharHeight + m_LineSep);
5120                     int y1 = y0 + max(sProxy->m_CustomIndexLast - sProxy->m_CustomIndexFirst + 1, 0)*(m_Font->m_CharHeight + m_LineSep) - 2;
5121                     if( y0<y1 )
5122                     {
5123                         r.m_Y0 = y0;
5124                         r.m_Y1 = y1;
5125                         Gr->ChangeViewport(r.m_XMin, r.m_YMin, r.m_XMax-r.m_XMin+1, r.m_YMax-r.m_YMin+1, 0, y0-r.m_YMin+1);
5126                         sProxy->m_CustomDrawCallback(r.m_XMax-r.m_XMin, y1-y0, sProxy->m_StructExtData, sProxy->m_StructClientData, this, r.m_Var);
5127                         Gr->RestoreViewport();
5128                     }
5129                 }
5130             }
5131
5132             if( m_DrawHandles && !m_IsPopupList )
5133             {
5134                 // Draw -/+/o/click/v buttons
5135                 if( (m_DrawIncrDecrBtn || m_DrawClickBtn || m_DrawListBtn || m_DrawBoolBtn || m_DrawRotoBtn) && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() )
5136                 {
5137                     int y0 = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_LineSep);
5138                     if( m_DrawIncrDecrBtn )
5139                     {
5140                         bool IsMin = false;
5141                         bool IsMax = false;
5142                         if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() )
5143                         {
5144                             const CTwVarAtom *Atom = static_cast<const CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
5145                             double v, vmin, vmax;
5146                             v = Atom->ValueToDouble();
5147                             Atom->MinMaxStepToDouble(&vmin, &vmax, NULL);
5148                             IsMax = (v>=vmax);
5149                             IsMin = (v<=vmin);
5150                         }
5151
5152                         /*
5153                         Gr->DrawRect(m_PosX+m_VarX2-2*bw+1, y0+1, m_PosX+m_VarX2-bw-1, y0+m_Font->m_CharHeight-2, (m_HighlightDecrBtn && !IsMin)?m_ColHighBtn:m_ColBtn);
5154                         Gr->DrawRect(m_PosX+m_VarX2-bw+1, y0+1, m_PosX+m_VarX2-1, y0+m_Font->m_CharHeight-2, (m_HighlightIncrBtn && !IsMax)?m_ColHighBtn:m_ColBtn);
5155                         // [-]
5156                         Gr->DrawLine(m_PosX+m_VarX2-2*bw+3+(bw>8?1:0), y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw-2-(bw>8?1:0), y0+m_Font->m_CharHeight/2, IsMin?m_ColValTextRO:m_ColTitleText);
5157                         // [+]
5158                         Gr->DrawLine(m_PosX+m_VarX2-bw+3, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-2, y0+m_Font->m_CharHeight/2, IsMax?m_ColValTextRO:m_ColTitleText);
5159                         Gr->DrawLine(m_PosX+m_VarX2-bw/2, y0+m_Font->m_CharHeight/2-bw/2+2, m_PosX+m_VarX2-bw/2, y0+m_Font->m_CharHeight/2+bw/2-1, IsMax?m_ColValTextRO:m_ColTitleText);
5160                         */
5161                         Gr->DrawRect(m_PosX+m_VarX2-3*bw+1, y0+1, m_PosX+m_VarX2-2*bw-1, y0+m_Font->m_CharHeight-2, (m_HighlightDecrBtn && !IsMin)?m_ColHighBtn:m_ColBtn);
5162                         Gr->DrawRect(m_PosX+m_VarX2-2*bw+1, y0+1, m_PosX+m_VarX2-bw-1, y0+m_Font->m_CharHeight-2, (m_HighlightIncrBtn && !IsMax)?m_ColHighBtn:m_ColBtn);
5163                         // [-]
5164                         Gr->DrawLine(m_PosX+m_VarX2-3*bw+3+(bw>8?1:0), y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-2*bw-2-(bw>8?1:0), y0+m_Font->m_CharHeight/2, IsMin?m_ColValTextRO:m_ColTitleText);
5165                         // [+]
5166                         Gr->DrawLine(m_PosX+m_VarX2-2*bw+3, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw-2, y0+m_Font->m_CharHeight/2, IsMax?m_ColValTextRO:m_ColTitleText);
5167                         Gr->DrawLine(m_PosX+m_VarX2-bw-bw/2, y0+m_Font->m_CharHeight/2-bw/2+2, m_PosX+m_VarX2-bw-bw/2, y0+m_Font->m_CharHeight/2+bw/2-1, IsMax?m_ColValTextRO:m_ColTitleText);
5168                     }
5169                     else if( m_DrawListBtn )
5170                     {
5171                         // [v]
5172                         int eps = 1;
5173                         int dx = -1;
5174                         Gr->DrawRect(m_PosX+m_VarX2-bw+1, y0+1, m_PosX+m_VarX2-1, y0+m_Font->m_CharHeight-2, m_HighlightListBtn?m_ColHighBtn:m_ColBtn);
5175                         Gr->DrawLine(m_PosX+m_VarX2-bw+4+dx, y0+m_Font->m_CharHeight/2-eps, m_PosX+m_VarX2-bw/2+1+dx, y0+m_Font->m_CharHeight-4, m_ColTitleText, true);
5176                         Gr->DrawLine(m_PosX+m_VarX2-bw/2+1+dx, y0+m_Font->m_CharHeight-4, m_PosX+m_VarX2-2+dx, y0+m_Font->m_CharHeight/2-1, m_ColTitleText, true);
5177                     }
5178                     else if( m_DrawBoolBtn )
5179                     {
5180                         Gr->DrawRect(m_PosX+m_VarX2-bw+1, y0+1, m_PosX+m_VarX2-1, y0+m_Font->m_CharHeight-2, m_HighlightBoolBtn?m_ColHighBtn:m_ColBtn);
5181                         // [x]
5182                         //Gr->DrawLine(m_PosX+m_VarX2-bw/2-bw/6, y0+m_Font->m_CharHeight/2-bw/6, m_PosX+m_VarX2-bw/2+bw/6, y0+m_Font->m_CharHeight/2+bw/6, m_ColTitleText, true);
5183                         //Gr->DrawLine(m_PosX+m_VarX2-bw/2-bw/6, y0+m_Font->m_CharHeight/2+bw/6, m_PosX+m_VarX2-bw/2+bw/6, y0+m_Font->m_CharHeight/2-bw/6, m_ColTitleText, true);
5184                         // [<>]
5185                         int s = bw/4;
5186                         int eps = 1;
5187                         Gr->DrawLine(m_PosX+m_VarX2-bw/2-1, y0+m_Font->m_CharHeight/2-s, m_PosX+m_VarX2-bw/2-s-1, y0+m_Font->m_CharHeight/2, m_ColTitleText, true);
5188                         Gr->DrawLine(m_PosX+m_VarX2-bw/2-s-1, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw/2-eps, y0+m_Font->m_CharHeight/2+s+1-eps, m_ColTitleText, true);
5189                         //Gr->DrawLine(m_PosX+m_VarX2-bw/2+1, y0+m_Font->m_CharHeight/2+s, m_PosX+m_VarX2-bw/2+s+1, y0+m_Font->m_CharHeight/2, m_ColTitleText, true);
5190                         //Gr->DrawLine(m_PosX+m_VarX2-bw/2+s+1, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw/2+1, y0+m_Font->m_CharHeight/2-s, m_ColTitleText, true);
5191                         Gr->DrawLine(m_PosX+m_VarX2-bw/2+2, y0+m_Font->m_CharHeight/2-s, m_PosX+m_VarX2-bw/2+s+2, y0+m_Font->m_CharHeight/2, m_ColTitleText, true);
5192                         Gr->DrawLine(m_PosX+m_VarX2-bw/2+s+2, y0+m_Font->m_CharHeight/2, m_PosX+m_VarX2-bw/2+1+eps, y0+m_Font->m_CharHeight/2+s+1-eps, m_ColTitleText, true);
5193                     }
5194
5195                     if( m_DrawRotoBtn )
5196                     {
5197                         // [o] rotoslider button
5198                         /*
5199                         Gr->DrawRect(m_PosX+m_VarX1-bw-1, y0+1, m_PosX+m_VarX1-3, y0+m_Font->m_CharHeight-2, m_HighlightRotoBtn?m_ColHighBtn:m_ColBtn);
5200                         Gr->DrawLine(m_PosX+m_VarX1-bw+bw/2-2, y0+m_Font->m_CharHeight/2-1, m_PosX+m_VarX1-bw+bw/2-1, y0+m_Font->m_CharHeight/2-1, m_ColTitleText);
5201                         Gr->DrawLine(m_PosX+m_VarX1-bw+bw/2-3, y0+m_Font->m_CharHeight/2+0, m_PosX+m_VarX1-bw+bw/2+0, y0+m_Font->m_CharHeight/2+0, m_ColTitleText);
5202                         Gr->DrawLine(m_PosX+m_VarX1-bw+bw/2-3, y0+m_Font->m_CharHeight/2+1, m_PosX+m_VarX1-bw+bw/2+0, y0+m_Font->m_CharHeight/2+1, m_ColTitleText);
5203                         Gr->DrawLine(m_PosX+m_VarX1-bw+bw/2-2, y0+m_Font->m_CharHeight/2+2, m_PosX+m_VarX1-bw+bw/2-1, y0+m_Font->m_CharHeight/2+2, m_ColTitleText);
5204                         */
5205                         /*
5206                         Gr->DrawRect(m_PosX+m_VarX2-3*bw+1, y0+1, m_PosX+m_VarX2-2*bw-1, y0+m_Font->m_CharHeight-2, m_HighlightRotoBtn?m_ColHighBtn:m_ColBtn);
5207                         Gr->DrawLine(m_PosX+m_VarX2-3*bw+bw/2+0, y0+m_Font->m_CharHeight/2-1, m_PosX+m_VarX2-3*bw+bw/2+1, y0+m_Font->m_CharHeight/2-1, m_ColTitleText);
5208                         Gr->DrawLine(m_PosX+m_VarX2-3*bw+bw/2-1, y0+m_Font->m_CharHeight/2+0, m_PosX+m_VarX2-3*bw+bw/2+2, y0+m_Font->m_CharHeight/2+0, m_ColTitleText);
5209                         Gr->DrawLine(m_PosX+m_VarX2-3*bw+bw/2-1, y0+m_Font->m_CharHeight/2+1, m_PosX+m_VarX2-3*bw+bw/2+2, y0+m_Font->m_CharHeight/2+1, m_ColTitleText);
5210                         Gr->DrawLine(m_PosX+m_VarX2-3*bw+bw/2+0, y0+m_Font->m_CharHeight/2+2, m_PosX+m_VarX2-3*bw+bw/2+1, y0+m_Font->m_CharHeight/2+2, m_ColTitleText);
5211                         */
5212                         int dy = 0;
5213                         Gr->DrawRect(m_PosX+m_VarX2-bw+1, y0+1, m_PosX+m_VarX2-1, y0+m_Font->m_CharHeight-2, m_HighlightRotoBtn?m_ColHighBtn:m_ColBtn);
5214                         Gr->DrawLine(m_PosX+m_VarX2-bw+bw/2+0, y0+m_Font->m_CharHeight/2-1+dy, m_PosX+m_VarX2-bw+bw/2+1, y0+m_Font->m_CharHeight/2-1+dy, m_ColTitleText, true);
5215                         Gr->DrawLine(m_PosX+m_VarX2-bw+bw/2-1, y0+m_Font->m_CharHeight/2+0+dy, m_PosX+m_VarX2-bw+bw/2+2, y0+m_Font->m_CharHeight/2+0+dy, m_ColTitleText, true);
5216                         Gr->DrawLine(m_PosX+m_VarX2-bw+bw/2-1, y0+m_Font->m_CharHeight/2+1+dy, m_PosX+m_VarX2-bw+bw/2+2, y0+m_Font->m_CharHeight/2+1+dy, m_ColTitleText, true);
5217                         Gr->DrawLine(m_PosX+m_VarX2-bw+bw/2+0, y0+m_Font->m_CharHeight/2+2+dy, m_PosX+m_VarX2-bw+bw/2+1, y0+m_Font->m_CharHeight/2+2+dy, m_ColTitleText, true);
5218                     }
5219                 }
5220                 
5221
5222                 // Draw value width slider
5223                 if( !m_HighlightValWidth )
5224                 {
5225                     color32 col = m_DarkText ? COLOR32_WHITE : m_ColTitleText;
5226                     Gr->DrawRect(m_PosX+m_VarX1-2, m_PosY+m_VarY0-8, m_PosX+m_VarX1-1, m_PosY+m_VarY0-4, col);
5227                     Gr->DrawLine(m_PosX+m_VarX1-1, m_PosY+m_VarY0-3, m_PosX+m_VarX1, m_PosY+m_VarY0-3, m_ColLineShadow);
5228                     Gr->DrawLine(m_PosX+m_VarX1, m_PosY+m_VarY0-3, m_PosX+m_VarX1, m_PosY+m_VarY0-8, m_ColLineShadow);
5229                 }
5230                 else
5231                 {
5232                     color32 col = m_DarkText ? COLOR32_WHITE : m_ColTitleText;
5233                     Gr->DrawRect(m_PosX+m_VarX1-2, m_PosY+m_VarY0-8, m_PosX+m_VarX1-1, m_PosY+m_VarY1, col);
5234                     Gr->DrawLine(m_PosX+m_VarX1-1, m_PosY+m_VarY1+1, m_PosX+m_VarX1, m_PosY+m_VarY1+1, m_ColLineShadow);
5235                     Gr->DrawLine(m_PosX+m_VarX1, m_PosY+m_VarY1+1, m_PosX+m_VarX1, m_PosY+m_VarY0-8, m_ColLineShadow);
5236                 }
5237
5238                 // Draw labels & values headers
5239                 if (m_HighlightLabelsHeader) 
5240                 {
5241                     Gr->DrawRect(m_PosX+m_VarX0, m_PosY+m_Font->m_CharHeight+2, m_PosX+m_VarX1-4, m_PosY+m_VarY0-1, m_ColHighBg0, m_ColHighBg0, m_ColHighBg1, m_ColHighBg1);
5242                 }
5243                 if (m_HighlightValuesHeader) 
5244                 {
5245                     Gr->DrawRect(m_PosX+m_VarX1+2, m_PosY+m_Font->m_CharHeight+2, m_PosX+m_VarX2, m_PosY+m_VarY0-1, m_ColHighBg0, m_ColHighBg0, m_ColHighBg1, m_ColHighBg1);
5246                 }
5247             }
5248
5249             // Draw key shortcut text
5250             if( m_HighlightedLine>=0 && m_HighlightedLine==m_ShortcutLine && !m_IsPopupList && !m_EditInPlace.m_Active )
5251             {
5252                 PERF( Timer.Reset(); )  
5253                 Gr->DrawRect(m_PosX+m_Font->m_CharHeight-2, m_PosY+m_VarY1+1, m_PosX+m_Width-m_Font->m_CharHeight-2, m_PosY+m_VarY1+1+m_Font->m_CharHeight, m_ColShortcutBg);
5254                 Gr->DrawText(m_ShortcutTextObj, m_PosX+m_Font->m_CharHeight, m_PosY+m_VarY1+1, m_ColShortcutText, 0);
5255                 PERF( DT = Timer.GetTime(); printf("Shortcut=%.4fms ", 1000.0*DT); )
5256             }
5257             else if( (m_HighlightLabelsHeader || m_HighlightValuesHeader) && !m_IsPopupList && !m_EditInPlace.m_Active )
5258             {
5259                 Gr->DrawRect(m_PosX+m_Font->m_CharHeight-2, m_PosY+m_VarY1+1, m_PosX+m_Width-m_Font->m_CharHeight-2, m_PosY+m_VarY1+1+m_Font->m_CharHeight, m_ColShortcutBg);
5260                 Gr->DrawText(m_HeadersTextObj, m_PosX+m_Font->m_CharHeight, m_PosY+m_VarY1+1, m_ColShortcutText, 0);
5261             }
5262             else if( m_IsHelpBar )
5263             {
5264                 if( g_TwMgr->m_KeyPressedTextObj && g_TwMgr->m_KeyPressedStr.size()>0 ) // Draw key pressed
5265                 {
5266                     if( g_TwMgr->m_KeyPressedBuildText )
5267                     {
5268                         string Str = g_TwMgr->m_KeyPressedStr;
5269                         ClampText(Str, m_Font, m_Width-2*m_Font->m_CharHeight);
5270                         g_TwMgr->m_Graph->BuildText(g_TwMgr->m_KeyPressedTextObj, &Str, NULL, NULL, 1, g_TwMgr->m_HelpBar->m_Font, 0, 0);
5271                         g_TwMgr->m_KeyPressedBuildText = false;
5272                         g_TwMgr->m_KeyPressedTime = (float)g_BarTimer.GetTime();
5273                     }
5274                     if( (float)g_BarTimer.GetTime()>g_TwMgr->m_KeyPressedTime+1.0f ) // draw key pressed at least 1 second
5275                         g_TwMgr->m_KeyPressedStr = "";
5276                     PERF( Timer.Reset(); )  
5277                     Gr->DrawRect(m_PosX+m_Font->m_CharHeight-2, m_PosY+m_VarY1+1, m_PosX+m_Width-m_Font->m_CharHeight-2, m_PosY+m_VarY1+1+m_Font->m_CharHeight, m_ColShortcutBg);
5278                     Gr->DrawText(g_TwMgr->m_KeyPressedTextObj, m_PosX+m_Font->m_CharHeight, m_PosY+m_VarY1+1, m_ColShortcutText, 0);
5279                     PERF( DT = Timer.GetTime(); printf("KeyPressed=%.4fms ", 1000.0*DT); )  
5280                 }
5281                 else
5282                 {
5283                     if( g_TwMgr->m_InfoBuildText )
5284                     {
5285                         string Info = "> AntTweakBar";
5286                         char Ver[64];
5287                         sprintf(Ver, " (v%d.%02d)", TW_VERSION/100, TW_VERSION%100);
5288                         Info += Ver;
5289                         ClampText(Info, m_Font, m_Width-2*m_Font->m_CharHeight);
5290                         g_TwMgr->m_Graph->BuildText(g_TwMgr->m_InfoTextObj, &Info, NULL, NULL, 1, g_TwMgr->m_HelpBar->m_Font, 0, 0);
5291                         g_TwMgr->m_InfoBuildText = false;
5292                     }
5293                     PERF( Timer.Reset(); )  
5294                     Gr->DrawRect(m_PosX+m_Font->m_CharHeight-2, m_PosY+m_VarY1+1, m_PosX+m_Width-m_Font->m_CharHeight-2, m_PosY+m_VarY1+1+m_Font->m_CharHeight, m_ColShortcutBg);
5295                     Gr->DrawText(g_TwMgr->m_InfoTextObj, m_PosX+m_Font->m_CharHeight, m_PosY+m_VarY1+1, m_ColInfoText, 0);
5296                     PERF( DT = Timer.GetTime(); printf("Info=%.4fms ", 1000.0*DT); )
5297                 }
5298             }
5299
5300             if( !m_IsPopupList )
5301             {
5302                 // Draw RotoSlider
5303                 RotoDraw();
5304
5305                 // Draw EditInPlace
5306                 EditInPlaceDraw();
5307             }
5308
5309             if( g_TwMgr->m_PopupBar!=NULL && this!=g_TwMgr->m_PopupBar )
5310             {
5311                 // darken bar if a popup bar is displayed
5312                 Gr->DrawRect(m_PosX, m_PosY, m_PosX+m_Width-1, m_PosY+m_Height-1, 0x1F000000);
5313             }
5314         }
5315     }
5316     else // minimized
5317     {
5318         int vpx, vpy, vpw, vph;
5319         vpx = 0;
5320         vpy = 0;
5321         vpw = g_TwMgr->m_WndWidth;
5322         vph = g_TwMgr->m_WndHeight;
5323         if( g_TwMgr->m_IconMarginX>0 )
5324         {
5325             vpx = min(g_TwMgr->m_IconMarginX, vpw/3);
5326             vpw -= 2 * vpx;
5327         }
5328         if( g_TwMgr->m_IconMarginY>0 )
5329         {
5330             vpy = min(g_TwMgr->m_IconMarginY, vph/3);
5331             vph -= 2 * vpy;
5332         }
5333
5334         int MinXOffset = 0, MinYOffset = 0;
5335         if( g_TwMgr->m_IconPos==3 )         // top-right
5336         {
5337             if( g_TwMgr->m_IconAlign==1 )   // horizontal
5338             {
5339                 int n = max(1, vpw/m_Font->m_CharHeight-1);
5340                 m_MinPosX = vpx + vpw-((m_MinNumber%n)+1)*m_Font->m_CharHeight;
5341                 m_MinPosY = vpy + (m_MinNumber/n)*m_Font->m_CharHeight;
5342                 MinYOffset = m_Font->m_CharHeight;
5343                 MinXOffset = -m_TitleWidth;
5344             }
5345             else // vertical
5346             {
5347                 int n = max(1, vph/m_Font->m_CharHeight-1);
5348                 m_MinPosY = vpy + (m_MinNumber%n)*m_Font->m_CharHeight;
5349                 m_MinPosX = vpx + vpw-((m_MinNumber/n)+1)*m_Font->m_CharHeight;
5350                 MinXOffset = -m_TitleWidth-m_Font->m_CharHeight;
5351             }
5352         }
5353         else if( g_TwMgr->m_IconPos==2 )    // top-left
5354         {
5355             if( g_TwMgr->m_IconAlign==1 )   // horizontal
5356             {
5357                 int n = max(1, vpw/m_Font->m_CharHeight-1);
5358                 m_MinPosX = vpx + (m_MinNumber%n)*m_Font->m_CharHeight;
5359                 m_MinPosY = vpy + (m_MinNumber/n)*m_Font->m_CharHeight;
5360                 MinYOffset = m_Font->m_CharHeight;
5361             }
5362             else // vertical
5363             {
5364                 int n = max(1, vph/m_Font->m_CharHeight-1);
5365                 m_MinPosY = vpy + (m_MinNumber%n)*m_Font->m_CharHeight;
5366                 m_MinPosX = vpx + (m_MinNumber/n)*m_Font->m_CharHeight;
5367                 MinXOffset = m_Font->m_CharHeight;
5368             }
5369         }
5370         else if( g_TwMgr->m_IconPos==1 )    // bottom-right
5371         {
5372             if( g_TwMgr->m_IconAlign==1 )   // horizontal
5373             {
5374                 int n = max(1, vpw/m_Font->m_CharHeight-1);
5375                 m_MinPosX = vpx + vpw-((m_MinNumber%n)+1)*m_Font->m_CharHeight;
5376                 m_MinPosY = vpy + vph-((m_MinNumber/n)+1)*m_Font->m_CharHeight;
5377                 MinYOffset = -m_Font->m_CharHeight;
5378                 MinXOffset = -m_TitleWidth;
5379             }
5380             else // vertical
5381             {
5382                 int n = max(1, vph/m_Font->m_CharHeight-1);
5383                 m_MinPosY = vpy + vph-((m_MinNumber%n)+1)*m_Font->m_CharHeight;
5384                 m_MinPosX = vpx + vpw-((m_MinNumber/n)+1)*m_Font->m_CharHeight;
5385                 MinXOffset = -m_TitleWidth-m_Font->m_CharHeight;
5386             }
5387         }
5388         else // bottom-left
5389         {
5390             if( g_TwMgr->m_IconAlign==1 )   // horizontal
5391             {
5392                 int n = max(1, vpw/m_Font->m_CharHeight-1);
5393                 m_MinPosX = vpx + (m_MinNumber%n)*m_Font->m_CharHeight;
5394                 m_MinPosY = vpy + vph-((m_MinNumber/n)+1)*m_Font->m_CharHeight;
5395                 MinYOffset = -m_Font->m_CharHeight;
5396             }
5397             else // vertical
5398             {
5399                 int n = max(1, vph/m_Font->m_CharHeight-1);
5400                 m_MinPosY = vpy + vph-((m_MinNumber%n)+1)*m_Font->m_CharHeight;
5401                 m_MinPosX = vpx + (m_MinNumber/n)*m_Font->m_CharHeight;
5402                 MinXOffset = m_Font->m_CharHeight;
5403             }
5404         }
5405
5406         if( m_HighlightMaximize )
5407         {
5408             // Draw title
5409             if( _DrawPart&DRAW_BG )
5410             {
5411                 Gr->DrawRect(m_MinPosX, m_MinPosY, m_MinPosX+m_Font->m_CharHeight, m_MinPosY+m_Font->m_CharHeight, m_ColTitleUnactiveBg);
5412                 Gr->DrawRect(m_MinPosX+MinXOffset, m_MinPosY+MinYOffset, m_MinPosX+MinXOffset+m_TitleWidth+m_Font->m_CharHeight, m_MinPosY+MinYOffset+m_Font->m_CharHeight, m_ColTitleUnactiveBg);
5413             }
5414             if( _DrawPart&DRAW_CONTENT )
5415             {
5416                 if( m_ColTitleShadow!=0 )
5417                     Gr->DrawText(m_TitleTextObj, m_MinPosX+MinXOffset+m_Font->m_CharHeight/2, m_MinPosY+1+MinYOffset, m_ColTitleShadow, 0);
5418                 Gr->DrawText(m_TitleTextObj, m_MinPosX+MinXOffset+m_Font->m_CharHeight/2, m_MinPosY+MinYOffset, m_ColTitleText, 0);
5419             }
5420         }
5421
5422         if( !m_IsHelpBar )
5423         {
5424             // Draw maximize button
5425             int xm = m_MinPosX+2, wm=m_Font->m_CharHeight-6;
5426             wm = (wm<6) ? 6 : wm;
5427             if( _DrawPart&DRAW_BG )
5428                 Gr->DrawRect(xm+1, m_MinPosY+4, xm+wm-1, m_MinPosY+3+wm, m_HighlightMaximize?m_ColHighBtn:m_ColBtn);
5429             if( _DrawPart&DRAW_CONTENT )
5430             {
5431                 Gr->DrawLine(xm, m_MinPosY+3, xm+wm, m_MinPosY+3, m_ColLine);
5432                 Gr->DrawLine(xm+wm, m_MinPosY+3, xm+wm, m_MinPosY+3+wm, m_ColLine);
5433                 Gr->DrawLine(xm+wm, m_MinPosY+3+wm, xm, m_MinPosY+3+wm, m_ColLine);
5434                 Gr->DrawLine(xm, m_MinPosY+3+wm, xm, m_MinPosY+3, m_ColLine);
5435                 Gr->DrawLine(xm+wm+1, m_MinPosY+4, xm+wm+1, m_MinPosY+4+wm, m_ColLineShadow);
5436                 Gr->DrawLine(xm+wm+1, m_MinPosY+4+wm, xm, m_MinPosY+4+wm, m_ColLineShadow);
5437                 Gr->DrawLine(xm+wm/3-1, m_MinPosY+3+wm-wm/3, xm+wm/2, m_MinPosY+6, m_ColTitleText, true);
5438                 Gr->DrawLine(xm+wm-wm/3+1, m_MinPosY+3+wm-wm/3, xm+wm/2, m_MinPosY+6, m_ColTitleText, true);
5439             }
5440         }
5441         else
5442         {
5443             // Draw help button
5444             int xm = m_MinPosX+2, wm=m_Font->m_CharHeight-6;
5445             wm = (wm<6) ? 6 : wm;
5446             if( _DrawPart&DRAW_BG )
5447                 Gr->DrawRect(xm+1, m_MinPosY+4, xm+wm-1, m_MinPosY+3+wm, m_HighlightMaximize?m_ColHighBtn:m_ColBtn);
5448             if( _DrawPart&DRAW_CONTENT )
5449             {
5450                 Gr->DrawLine(xm, m_MinPosY+3, xm+wm, m_MinPosY+3, m_ColLine);
5451                 Gr->DrawLine(xm+wm, m_MinPosY+3, xm+wm, m_MinPosY+3+wm, m_ColLine);
5452                 Gr->DrawLine(xm+wm, m_MinPosY+3+wm, xm, m_MinPosY+3+wm, m_ColLine);
5453                 Gr->DrawLine(xm, m_MinPosY+3+wm, xm, m_MinPosY+3, m_ColLine);
5454                 Gr->DrawLine(xm+wm+1, m_MinPosY+4, xm+wm+1, m_MinPosY+4+wm, m_ColLineShadow);
5455                 Gr->DrawLine(xm+wm+1, m_MinPosY+4+wm, xm, m_MinPosY+4+wm, m_ColLineShadow);
5456                 Gr->DrawLine(xm+wm/2-wm/6, m_MinPosY+3+wm/4, xm+wm-wm/3, m_MinPosY+3+wm/4, m_ColTitleText);
5457                 Gr->DrawLine(xm+wm-wm/3, m_MinPosY+3+wm/4, xm+wm-wm/3, m_MinPosY+3+wm/2, m_ColTitleText);
5458                 Gr->DrawLine(xm+wm-wm/3, m_MinPosY+3+wm/2, xm+wm/2, m_MinPosY+3+wm/2, m_ColTitleText);
5459                 Gr->DrawLine(xm+wm/2, m_MinPosY+3+wm/2, xm+wm/2, m_MinPosY+3+wm-wm/4, m_ColTitleText);
5460                 Gr->DrawLine(xm+wm/2, m_MinPosY+3+wm-wm/4+1, xm+wm/2, m_MinPosY+3+wm-wm/4+2, m_ColTitleText);
5461             }
5462         }
5463     }
5464 }
5465
5466 //  ---------------------------------------------------------------------------
5467
5468 bool CTwBar::MouseMotion(int _X, int _Y)
5469 {
5470     assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0);
5471     if( !m_UpToDate )
5472         Update();
5473     
5474     bool Handled = false;
5475     bool CustomArea = false;
5476     if( !m_IsMinimized )
5477     {
5478         bool InBar = (_X>=m_PosX && _X<m_PosX+m_Width && _Y>=m_PosY && _Y<m_PosY+m_Height);
5479         for( size_t ib=0; ib<g_TwMgr->m_Bars.size(); ++ib )
5480             if( g_TwMgr->m_Bars[ib]!=NULL )
5481             {
5482                 g_TwMgr->m_Bars[ib]->m_DrawHandles = false;
5483                 g_TwMgr->m_Bars[ib]->m_HighlightTitle = false;
5484             }
5485         m_DrawHandles = InBar;
5486         const int ContainedMargin = 32;
5487
5488         if( !m_MouseDrag )
5489         {   
5490             Handled = InBar;
5491             m_HighlightedLine = -1;
5492             m_HighlightIncrBtn = false;
5493             m_HighlightDecrBtn = false;
5494             m_HighlightRotoBtn = false;
5495             if( abs(m_MouseOriginX-_X)>6 || abs(m_MouseOriginY-_Y)>6 )
5496                 m_HighlightClickBtn = false;
5497             m_HighlightListBtn = false;
5498             m_HighlightTitle = false;
5499             m_HighlightScroll = false;
5500             m_HighlightUpScroll = false;
5501             m_HighlightDnScroll = false;
5502             m_HighlightMinimize = false;
5503             m_HighlightFont = false;
5504             m_HighlightValWidth = false;
5505             m_HighlightLabelsHeader = false;
5506             m_HighlightValuesHeader = false;
5507             //if( InBar && _X>m_PosX+m_Font->m_CharHeight+1 && _X<m_PosX+m_VarX2 && _Y>=m_PosY+m_VarY0 && _Y<m_PosY+m_VarY1 )
5508             if( InBar && _X>m_PosX+2 && _X<m_PosX+m_VarX2 && _Y>=m_PosY+m_VarY0 && _Y<m_PosY+m_VarY1 )
5509             {   // mouse over var line
5510                 m_HighlightedLine = (_Y-m_PosY-m_VarY0)/(m_Font->m_CharHeight+m_LineSep);
5511                 if( m_HighlightedLine>=(int)m_HierTags.size() )
5512                     m_HighlightedLine = -1;
5513                 else if(m_HighlightedLine>=0)
5514                     m_HighlightedLineLastValid = m_HighlightedLine;
5515                 if( m_HighlightedLine<0 || m_HierTags[m_HighlightedLine].m_Var==NULL || m_HierTags[m_HighlightedLine].m_Var->IsGroup() )
5516                     ANT_SET_CURSOR(Arrow);
5517                 else
5518                 {
5519                     if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider )
5520                     {
5521                         if( static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly && !m_IsHelpBar 
5522                             && !(static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Type==TW_TYPE_BUTTON && static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_Val.m_Button.m_Callback==NULL) )
5523                             ANT_SET_CURSOR(No); //(Arrow);
5524                         else
5525                         {
5526                             ANT_SET_CURSOR(Arrow);
5527                             CustomArea = true;
5528                         }
5529
5530                         if( m_DrawListBtn )
5531                         {
5532                             m_HighlightListBtn = true;
5533                             CustomArea = false;
5534                         }
5535                         if( m_DrawBoolBtn )
5536                         {
5537                             m_HighlightBoolBtn = true;
5538                             CustomArea = false;
5539                         }
5540                     }
5541                     else if( m_DrawRotoBtn && ( _X>=m_PosX+m_VarX2-IncrBtnWidth(m_Font->m_CharHeight) || _X<m_PosX+m_VarX1 ) )  // [o] button
5542                     //else if( m_DrawRotoBtn && _X<m_PosX+m_VarX1 ) // [o] button
5543                     {
5544                         m_HighlightRotoBtn = true;
5545                         ANT_SET_CURSOR(Point);
5546                     }
5547                     else if( m_DrawIncrDecrBtn && _X>=m_PosX+m_VarX2-2*IncrBtnWidth(m_Font->m_CharHeight) ) // [+] button
5548                     {
5549                         m_HighlightIncrBtn = true;
5550                         ANT_SET_CURSOR(Arrow);
5551                     }
5552                     else if( m_DrawIncrDecrBtn && _X>=m_PosX+m_VarX2-3*IncrBtnWidth(m_Font->m_CharHeight) ) // [-] button
5553                     {
5554                         m_HighlightDecrBtn = true;
5555                         ANT_SET_CURSOR(Arrow);
5556                     }
5557                     else if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() && static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly )
5558                     {
5559                         if( !m_IsHelpBar )
5560                             ANT_SET_CURSOR(No);
5561                         else
5562                             ANT_SET_CURSOR(Arrow);
5563                     }
5564                     else
5565                         //ANT_SET_CURSOR(Point);
5566                         ANT_SET_CURSOR(IBeam);
5567                 }
5568             }
5569             else if( InBar && m_Movable && !m_IsPopupList && _X>=m_PosX+2*m_Font->m_CharHeight && _X<m_PosX+m_Width-2*m_Font->m_CharHeight && _Y<m_PosY+m_Font->m_CharHeight )
5570             {   // mouse over title
5571                 m_HighlightTitle = true;
5572                 ANT_SET_CURSOR(Move);
5573             }
5574             else if ( InBar && !m_IsPopupList && _X>=m_PosX+m_VarX1-5 && _X<m_PosX+m_VarX1+5 && _Y>m_PosY+m_Font->m_CharHeight && _Y<m_PosY+m_VarY0 )
5575             {   // mouse over ValuesWidth handle
5576                 m_HighlightValWidth = true;
5577                 ANT_SET_CURSOR(WE);
5578             }
5579             else if ( InBar && !m_IsPopupList && !m_IsHelpBar && _X>=m_PosX+m_VarX0 && _X<m_PosX+m_VarX1-5 && _Y>m_PosY+m_Font->m_CharHeight && _Y<m_PosY+m_VarY0 )
5580             {   // mouse over left column header
5581                 m_HighlightLabelsHeader = true;
5582                 ANT_SET_CURSOR(Arrow);
5583             }
5584             else if ( InBar && !m_IsPopupList && _X>=m_PosX+m_VarX1+5 && _X<m_PosX+m_VarX2 && _Y>m_PosY+m_Font->m_CharHeight && _Y<m_PosY+m_VarY0 )
5585             {   // mouse over right column header
5586                 m_HighlightValuesHeader = true;
5587                 ANT_SET_CURSOR(Arrow);
5588             }
5589             //else if( InBar && m_NbDisplayedLines<m_NbHierLines && _X>=m_PosX && _X<m_PosX+m_Font->m_CharHeight && _Y>=m_ScrollY0 && _Y<m_ScrollY1 )
5590             else if( InBar && m_NbDisplayedLines<m_NbHierLines && _X>=m_PosX+m_VarX2+2 && _X<m_PosX+m_Width-2 && _Y>=m_ScrollY0 && _Y<m_ScrollY1 )
5591             {
5592                 m_HighlightScroll = true;
5593               #ifdef ANT_WINDOWS
5594                 ANT_SET_CURSOR(NS);
5595               #else
5596                 ANT_SET_CURSOR(Arrow);
5597               #endif
5598             }
5599             else if( InBar && _X>=m_PosX+m_VarX2+2 && _X<m_PosX+m_Width-2 && _Y>=m_PosY+m_VarY0 && _Y<m_ScrollY0 )
5600             {
5601                 m_HighlightUpScroll = true;
5602                 ANT_SET_CURSOR(Arrow);
5603             }
5604             else if( InBar && _X>=m_PosX+m_VarX2+2 && _X<m_PosX+m_Width-2 && _Y>=m_ScrollY1 && _Y<m_PosY+m_VarY1 )
5605             {
5606                 m_HighlightDnScroll = true;
5607                 ANT_SET_CURSOR(Arrow);
5608             }
5609             else if( InBar && m_Resizable && !m_IsPopupList && _X>=m_PosX && _X<m_PosX+m_Font->m_CharHeight && _Y>=m_PosY && _Y<m_PosY+m_Font->m_CharHeight )
5610                 ANT_SET_CURSOR(TopLeft);
5611             else if( InBar && !m_IsPopupList && _X>=m_PosX && _X<m_PosX+m_Font->m_CharHeight && _Y>=m_PosY+m_Height-m_Font->m_CharHeight && _Y<m_PosY+m_Height )
5612                 ANT_SET_CURSOR(BottomLeft);
5613             else if( InBar && m_Resizable && !m_IsPopupList && _X>=m_PosX+m_Width-m_Font->m_CharHeight && _X<m_PosX+m_Width && _Y>=m_PosY && _Y<m_PosY+m_Font->m_CharHeight )
5614                 ANT_SET_CURSOR(TopRight);
5615             else if( InBar && m_Resizable && !m_IsPopupList && _X>=m_PosX+m_Width-m_Font->m_CharHeight && _X<m_PosX+m_Width && _Y>=m_PosY+m_Height-m_Font->m_CharHeight && _Y<m_PosY+m_Height )
5616                 ANT_SET_CURSOR(BottomRight);
5617             else if( InBar && g_TwMgr->m_FontResizable && !m_IsPopupList && _X>=m_PosX+m_Font->m_CharHeight && _X<m_PosX+2*m_Font->m_CharHeight && _Y<m_PosY+m_Font->m_CharHeight )
5618             {
5619                 m_HighlightFont = true;
5620                 ANT_SET_CURSOR(Arrow);
5621             }
5622             else if( InBar && m_Iconifiable && !m_IsPopupList && _X>=m_PosX+m_Width-2*m_Font->m_CharHeight && _X<m_PosX+m_Width-m_Font->m_CharHeight && _Y<m_PosY+m_Font->m_CharHeight )
5623             {
5624                 m_HighlightMinimize = true;
5625                 ANT_SET_CURSOR(Arrow);
5626             }
5627             else if( m_IsHelpBar && InBar && _X>=m_PosX+m_VarX0 && _X<m_PosX+m_Width-m_Font->m_CharHeight && _Y>m_PosY+m_Height-m_Font->m_CharHeight && _Y<m_PosY+m_Height )
5628                 ANT_SET_CURSOR(Arrow); //(Hand);   // web link
5629             else // if( InBar )
5630                 ANT_SET_CURSOR(Arrow);
5631         }
5632         else
5633         {
5634             if( m_MouseDragVar && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() )
5635             {
5636                 /*
5637                 CTwVarAtom *Var = static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
5638                 int Delta = _X-m_MouseOriginX;
5639                 if( Delta!=0 )
5640                 {
5641                     if( !Var->m_NoSlider && !Var->m_ReadOnly )
5642                     {
5643                         Var->Increment(Delta);
5644                         NotUpToDate();
5645                     }
5646                     m_VarHasBeenIncr = true;
5647                 }
5648                 m_MouseOriginX = _X;
5649                 m_MouseOriginY = _Y;
5650                 if( !Var->m_NoSlider && !Var->m_ReadOnly )
5651                     ANT_SET_CURSOR(Center);
5652                     //ANT_SET_CURSOR(WE);
5653                 else
5654                     ANT_SET_CURSOR(Arrow);
5655                 Handled = true;
5656                 */
5657
5658                 // move rotoslider
5659                 if( !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider )
5660                     RotoOnMouseMove(_X, _Y);
5661
5662                 if( static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly )
5663                     ANT_SET_CURSOR(No);
5664                 else if( static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_NoSlider )
5665                 {
5666                     ANT_SET_CURSOR(Arrow);
5667                     CustomArea = true;
5668                 }
5669                 m_VarHasBeenIncr = true;
5670                 Handled = true;
5671                 m_DrawHandles = true;
5672             }
5673             else if( m_MouseDragTitle )
5674             {
5675                 int y = m_PosY;
5676                 m_PosX += _X-m_MouseOriginX;
5677                 m_PosY += _Y-m_MouseOriginY;
5678                 m_MouseOriginX = _X;
5679                 m_MouseOriginY = _Y;
5680                 int vpx, vpy, vpw, vph;
5681                 vpx = 0;
5682                 vpy = 0;
5683                 vpw = g_TwMgr->m_WndWidth;
5684                 vph = g_TwMgr->m_WndHeight;
5685                 if( m_Contained )
5686                 {
5687                     if( m_PosX+m_Width>vpx+vpw )
5688                         m_PosX = vpx+vpw-m_Width;
5689                     if( m_PosX<vpx )
5690                         m_PosX = vpx;
5691                     if( m_PosY+m_Height>vpy+vph )
5692                         m_PosY = vpy+vph-m_Height;
5693                     if( m_PosY<vpy )
5694                         m_PosY = vpy;
5695                 } 
5696                 else 
5697                 {
5698                     if( m_PosX+ContainedMargin>vpx+vpw )
5699                         m_PosX = vpx+vpw-ContainedMargin;
5700                     if( m_PosX+m_Width<vpx+ContainedMargin )
5701                         m_PosX = vpx+ContainedMargin-m_Width;
5702                     if( m_PosY+ContainedMargin>vpy+vph )
5703                         m_PosY = vpy+vph-ContainedMargin;
5704                     if( m_PosY+m_Height<vpy+ContainedMargin )
5705                         m_PosY = vpy+ContainedMargin-m_Height;
5706                 }
5707                 m_ScrollY0 += m_PosY-y;
5708                 m_ScrollY1 += m_PosY-y;
5709                 ANT_SET_CURSOR(Move);
5710                 Handled = true;
5711             }
5712             else if( m_MouseDragValWidth )
5713             {
5714                 m_ValuesWidth += m_MouseOriginX-_X;
5715                 m_MouseOriginX = _X;
5716                 NotUpToDate();
5717                 if( m_IsHelpBar )
5718                     g_TwMgr->m_HelpBarNotUpToDate = true;
5719                 ANT_SET_CURSOR(WE);
5720                 Handled = true;
5721                 m_DrawHandles = true;
5722             }
5723             else if( m_MouseDragScroll )
5724             {
5725                 if( m_ScrollYH>0 )
5726                 {
5727                     int dl = ((_Y-m_MouseOriginY)*m_NbHierLines)/m_ScrollYH;
5728                     if( m_FirstLine0+dl<0 )
5729                         m_FirstLine = 0;
5730                     else if( m_FirstLine0+dl+m_NbDisplayedLines>m_NbHierLines )
5731                         m_FirstLine = m_NbHierLines-m_NbDisplayedLines;
5732                     else
5733                         m_FirstLine = m_FirstLine0+dl;
5734                     NotUpToDate();
5735                 }
5736               #ifdef ANT_WINDOWS
5737                 ANT_SET_CURSOR(NS);
5738               #else
5739                 ANT_SET_CURSOR(Arrow);
5740               #endif
5741                 Handled = true;
5742                 m_DrawHandles = true;
5743             }
5744             else if( m_MouseDragResizeUL )
5745             {
5746                 int w = m_Width;
5747                 int h = m_Height;
5748                 m_PosX += _X-m_MouseOriginX;
5749                 m_PosY += _Y-m_MouseOriginY;
5750                 m_Width -= _X-m_MouseOriginX;
5751                 m_Height -= _Y-m_MouseOriginY;
5752                 m_MouseOriginX = _X;
5753                 m_MouseOriginY = _Y;
5754                 int vpx = 0, vpy = 0, vpw = g_TwMgr->m_WndWidth, vph = g_TwMgr->m_WndHeight;
5755                 if( !m_Contained )
5756                 {
5757                     if( m_PosX+ContainedMargin>vpx+vpw )
5758                         m_PosX = vpx+vpw-ContainedMargin;
5759                     if( m_PosX+m_Width<vpx+ContainedMargin )
5760                         m_PosX = vpx+ContainedMargin-m_Width;
5761                     if( m_PosY+ContainedMargin>vpy+vph )
5762                         m_PosY = vpy+vph-ContainedMargin;
5763                     if( m_PosY+m_Height<vpy+ContainedMargin )
5764                         m_PosY = vpy+ContainedMargin-m_Height;
5765                 }
5766                 else 
5767                 {
5768                     if( m_PosX<vpx ) 
5769                     {
5770                         m_PosX = vpx;
5771                         m_Width = w;
5772                     }
5773                     if( m_PosY<vpy ) 
5774                     {
5775                         m_PosY = vpy;
5776                         m_Height = h;
5777                     }
5778                 }
5779                 if (m_ValuesWidthRatio > 0) 
5780                     m_ValuesWidth = int(m_ValuesWidthRatio * m_Width + 0.5);
5781                 ANT_SET_CURSOR(TopLeft);
5782                 NotUpToDate();
5783                 if( m_IsHelpBar )
5784                 {
5785                     g_TwMgr->m_HelpBarNotUpToDate = true;
5786                     g_TwMgr->m_HelpBarUpdateNow = true;
5787                 }
5788                 g_TwMgr->m_KeyPressedBuildText = true;
5789                 g_TwMgr->m_InfoBuildText = true;
5790                 Handled = true;
5791                 m_DrawHandles = true;
5792             }
5793             else if( m_MouseDragResizeUR )
5794             {
5795                 int h = m_Height;
5796                 m_PosY += _Y-m_MouseOriginY;
5797                 m_Width += _X-m_MouseOriginX;
5798                 m_Height -= _Y-m_MouseOriginY;
5799                 m_MouseOriginX = _X;
5800                 m_MouseOriginY = _Y;
5801                 int vpx = 0, vpy = 0, vpw = g_TwMgr->m_WndWidth, vph = g_TwMgr->m_WndHeight;
5802                 if( !m_Contained )
5803                 {
5804                     if( m_PosX+ContainedMargin>vpx+vpw )
5805                         m_PosX = vpx+vpw-ContainedMargin;
5806                     if( m_PosX+m_Width<vpx+ContainedMargin )
5807                         m_PosX = vpx+ContainedMargin-m_Width;
5808                     if( m_PosY+ContainedMargin>vpy+vph )
5809                         m_PosY = vpy+vph-ContainedMargin;
5810                     if( m_PosY+m_Height<vpy+ContainedMargin )
5811                         m_PosY = vpy+ContainedMargin-m_Height;
5812                 }
5813                 else
5814                 {
5815                     if( m_PosX+m_Width>vpx+vpw )
5816                         m_Width = vpx+vpw-m_PosX;
5817                     if( m_PosY<vpy ) 
5818                     {
5819                         m_PosY = vpy;
5820                         m_Height = h;
5821                     }
5822                 }
5823                 if (m_ValuesWidthRatio > 0) 
5824                     m_ValuesWidth = int(m_ValuesWidthRatio * m_Width + 0.5);
5825                 ANT_SET_CURSOR(TopRight);
5826                 NotUpToDate();
5827                 if( m_IsHelpBar )
5828                 {
5829                     g_TwMgr->m_HelpBarNotUpToDate = true;
5830                     g_TwMgr->m_HelpBarUpdateNow = true;
5831                 }
5832                 g_TwMgr->m_KeyPressedBuildText = true;
5833                 g_TwMgr->m_InfoBuildText = true;
5834                 Handled = true;
5835                 m_DrawHandles = true;
5836             }
5837             else if( m_MouseDragResizeLL )
5838             {
5839                 int w = m_Width;
5840                 m_PosX += _X-m_MouseOriginX;
5841                 m_Width -= _X-m_MouseOriginX;
5842                 m_Height += _Y-m_MouseOriginY;
5843                 m_MouseOriginX = _X;
5844                 m_MouseOriginY = _Y;
5845                 int vpx = 0, vpy = 0, vpw = g_TwMgr->m_WndWidth, vph = g_TwMgr->m_WndHeight;
5846                 if( !m_Contained )
5847                 {
5848                     if( m_PosX+ContainedMargin>vpx+vpw )
5849                         m_PosX = vpx+vpw-ContainedMargin;
5850                     if( m_PosX+m_Width<vpx+ContainedMargin )
5851                         m_PosX = vpx+ContainedMargin-m_Width;
5852                     if( m_PosY+ContainedMargin>vpy+vph )
5853                         m_PosY = vpy+vph-ContainedMargin;
5854                     if( m_PosY+m_Height<vpy+ContainedMargin )
5855                         m_PosY = vpy+ContainedMargin-m_Height;
5856                 }
5857                 else
5858                 {
5859                     if( m_PosY+m_Height>vpy+vph )
5860                         m_Height = vpy+vph-m_PosY;
5861                     if( m_PosX<vpx ) 
5862                     {
5863                         m_PosX = vpx;
5864                         m_Width = w;
5865                     }
5866                 }
5867                 if (m_ValuesWidthRatio > 0) 
5868                     m_ValuesWidth = int(m_ValuesWidthRatio * m_Width + 0.5);
5869                 ANT_SET_CURSOR(BottomLeft);
5870                 NotUpToDate();
5871                 if( m_IsHelpBar )
5872                 {
5873                     g_TwMgr->m_HelpBarNotUpToDate = true;
5874                     g_TwMgr->m_HelpBarUpdateNow = true;
5875                 }
5876                 g_TwMgr->m_KeyPressedBuildText = true;
5877                 g_TwMgr->m_InfoBuildText = true;
5878                 Handled = true;
5879                 m_DrawHandles = true;
5880             }
5881             else if( m_MouseDragResizeLR )
5882             {
5883                 m_Width += _X-m_MouseOriginX;
5884                 m_Height += _Y-m_MouseOriginY;
5885                 m_MouseOriginX = _X;
5886                 m_MouseOriginY = _Y;
5887                 int vpx = 0, vpy = 0, vpw = g_TwMgr->m_WndWidth, vph = g_TwMgr->m_WndHeight;
5888                 if( !m_Contained )
5889                 {
5890                     if( m_PosX+ContainedMargin>vpx+vpw )
5891                         m_PosX = vpx+vpw-ContainedMargin;
5892                     if( m_PosX+m_Width<vpx+ContainedMargin )
5893                         m_PosX = vpx+ContainedMargin-m_Width;
5894                     if( m_PosY+ContainedMargin>vpy+vph )
5895                         m_PosY = vpy+vph-ContainedMargin;
5896                     if( m_PosY+m_Height<vpy+ContainedMargin )
5897                         m_PosY = vpy+ContainedMargin-m_Height;
5898                 } 
5899                 else
5900                 {
5901                     if( m_PosX+m_Width>vpx+vpw )
5902                         m_Width = vpx+vpw-m_PosX;
5903                     if( m_PosY+m_Height>vpy+vph )
5904                         m_Height = vpy+vph-m_PosY;
5905                 }
5906                 if (m_ValuesWidthRatio > 0) 
5907                     m_ValuesWidth = int(m_ValuesWidthRatio * m_Width + 0.5);
5908                 ANT_SET_CURSOR(BottomRight);
5909                 NotUpToDate();
5910                 if( m_IsHelpBar )
5911                 {
5912                     g_TwMgr->m_HelpBarNotUpToDate = true;
5913                     g_TwMgr->m_HelpBarUpdateNow = true;
5914                 }
5915                 g_TwMgr->m_KeyPressedBuildText = true;
5916                 g_TwMgr->m_InfoBuildText = true;
5917                 Handled = true;
5918                 m_DrawHandles = true;
5919             }
5920             else if( m_EditInPlace.m_Active )
5921             {
5922                 EditInPlaceMouseMove(_X, _Y, true);
5923                 ANT_SET_CURSOR(IBeam);
5924                 Handled = true;
5925             }
5926             //else if( InBar )
5927             //  ANT_SET_CURSOR(Arrow);
5928         }
5929     }
5930     else // minimized
5931     {
5932         if( m_Iconifiable && _X>=m_MinPosX+2 && _X<m_MinPosX+m_Font->m_CharHeight && _Y>m_MinPosY && _Y<m_MinPosY+m_Font->m_CharHeight-2 )
5933         {
5934             m_HighlightMaximize = true;
5935             if( !m_IsHelpBar )
5936                 ANT_SET_CURSOR(Arrow);
5937             else
5938               #ifdef ANT_WINDOWS
5939                 ANT_SET_CURSOR(Help);
5940               #else
5941                 ANT_SET_CURSOR(Arrow);
5942               #endif
5943             Handled = true;
5944         }
5945         else
5946             m_HighlightMaximize = false;
5947     }
5948
5949     // Handled by a custom widget?
5950     CTwMgr::CStructProxy *currentCustomActiveStructProxy = NULL;
5951     if( g_TwMgr!=NULL && (!Handled || CustomArea) && !m_IsMinimized && m_CustomRecords.size()>0 )
5952     {
5953         bool CustomHandled = false;
5954         for( int s=0; s<2; ++s )    // 2 iterations: first for custom widget having focus, second for others if no focused widget.
5955             for( CustomMap::iterator it=m_CustomRecords.begin(); it!=m_CustomRecords.end(); ++it )
5956             {
5957                 CTwMgr::CStructProxy *sProxy = it->first;
5958                 const CCustomRecord& r = it->second;
5959                 if( (s==1 || sProxy->m_CustomCaptureFocus) && !CustomHandled && sProxy!=NULL && sProxy->m_CustomMouseMotionCallback!=NULL && r.m_XMin<r.m_XMax && r.m_Y0<r.m_Y1 && r.m_YMin<=r.m_YMax && r.m_YMin>=r.m_Y0 && r.m_YMax<=r.m_Y1 )
5960                 {
5961                     if( sProxy->m_CustomCaptureFocus || (_X>=r.m_XMin && _X<r.m_XMax && _Y>=r.m_YMin && _Y<r.m_YMax) )
5962                     {
5963                         CustomHandled = sProxy->m_CustomMouseMotionCallback(_X-r.m_XMin, _Y-r.m_Y0, r.m_XMax-r.m_XMin, r.m_Y1-r.m_Y0, sProxy->m_StructExtData, sProxy->m_StructClientData, this, r.m_Var);
5964                         currentCustomActiveStructProxy = sProxy;
5965                         s = 2; // force s-loop exit
5966                     }
5967                 }
5968                 else if( sProxy!=NULL )
5969                 {
5970                     sProxy->m_CustomCaptureFocus = false;   // force free focus, just in case.
5971                     ANT_SET_CURSOR(Arrow);
5972                 }
5973             }
5974         if( CustomHandled )
5975             Handled = true;
5976     }
5977     // If needed, send a 'MouseLeave' message to previously active custom struct
5978     if( g_TwMgr!=NULL && m_CustomActiveStructProxy!=NULL && m_CustomActiveStructProxy!=currentCustomActiveStructProxy )
5979     {
5980         bool found = false;
5981         for( list<CTwMgr::CStructProxy>::iterator it=g_TwMgr->m_StructProxies.begin(); it!=g_TwMgr->m_StructProxies.end() && !found; ++it )
5982             found = (&(*it)==m_CustomActiveStructProxy);
5983         if( found && m_CustomActiveStructProxy->m_CustomMouseLeaveCallback!=NULL )
5984             m_CustomActiveStructProxy->m_CustomMouseLeaveCallback(m_CustomActiveStructProxy->m_StructExtData, m_CustomActiveStructProxy->m_StructClientData, this);
5985     }
5986     m_CustomActiveStructProxy = currentCustomActiveStructProxy;
5987
5988     return Handled;
5989 }
5990
5991 //  ---------------------------------------------------------------------------
5992
5993 #ifdef ANT_WINDOWS
5994 #   pragma optimize("", off)
5995 //  disable optimizations because the conversion of Enum from unsigned int to double is not always exact if optimized and GraphAPI=DirectX !
5996 #endif
5997 static void ANT_CALL PopupCallback(void *_ClientData)
5998 {
5999     CTwFPU fpu; // force fpu precision
6000
6001     if( g_TwMgr!=NULL && g_TwMgr->m_PopupBar!=NULL )
6002     {
6003         unsigned int Enum = *(unsigned int *)&_ClientData;
6004         CTwVarAtom *Var = g_TwMgr->m_PopupBar->m_VarEnumLinkedToPopupList;
6005         CTwBar *Bar = g_TwMgr->m_PopupBar->m_BarLinkedToPopupList;
6006         if( Bar!=NULL && Var!=NULL && !Var->m_ReadOnly && IsEnumType(Var->m_Type) )
6007         {
6008             Var->ValueFromDouble(Enum);
6009             //Bar->UnHighlightLine();
6010             Bar->HaveFocus(true);
6011             Bar->NotUpToDate();
6012         }
6013         TwDeleteBar(g_TwMgr->m_PopupBar);
6014         g_TwMgr->m_PopupBar = NULL;
6015     }
6016 }
6017 #ifdef ANT_WINDOWS
6018 #   pragma optimize("", on)
6019 #endif
6020
6021 //  ---------------------------------------------------------------------------
6022
6023 bool CTwBar::MouseButton(ETwMouseButtonID _Button, bool _Pressed, int _X, int _Y)
6024 {
6025     assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0);
6026     bool Handled = false;
6027     if( !m_UpToDate )
6028         Update();
6029     bool EditInPlaceActive = false;
6030     bool CustomArea = false;
6031
6032     if( !m_IsMinimized )
6033     {
6034         Handled = (_X>=m_PosX && _X<m_PosX+m_Width && _Y>=m_PosY && _Y<m_PosY+m_Height);
6035         if( _Button==TW_MOUSE_LEFT && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var )
6036         {
6037             if( m_HierTags[m_HighlightedLine].m_Var->IsGroup() )
6038             {
6039                 if( _Pressed && !g_TwMgr->m_IsRepeatingMousePressed )
6040                 {
6041                     CTwVarGroup *Grp = static_cast<CTwVarGroup *>(m_HierTags[m_HighlightedLine].m_Var);
6042                     Grp->m_Open = !Grp->m_Open;
6043                     NotUpToDate();
6044                     ANT_SET_CURSOR(Arrow);
6045                 }
6046             }
6047             else if( _Pressed && m_HighlightIncrBtn )
6048             {
6049                 static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->Increment(1);
6050                 if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
6051                     return 1;
6052                 NotUpToDate();
6053             }
6054             else if( _Pressed && m_HighlightDecrBtn )
6055             {
6056                 static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->Increment(-1);
6057                 if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
6058                     return 1;
6059                 NotUpToDate();
6060             }
6061             else if( _Pressed && !m_MouseDrag )
6062             {
6063                 m_MouseDrag = true;
6064                 m_MouseDragVar = true;
6065                 m_MouseOriginX = _X;
6066                 m_MouseOriginY = _Y;
6067                 m_VarHasBeenIncr = false;
6068                 CTwVarAtom * Var = static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
6069                 if( !Var->m_NoSlider && !Var->m_ReadOnly && m_HighlightRotoBtn )
6070                 {
6071                     // begin rotoslider
6072                     if( _X>m_PosX+m_VarX1 )
6073                         RotoOnLButtonDown(m_PosX+m_VarX2-(1*IncrBtnWidth(m_Font->m_CharHeight))/2, _Y);
6074                     else
6075                         RotoOnLButtonDown(_X, _Y);
6076                     m_MouseDrag = true;
6077                     m_MouseDragVar = true;
6078                 }
6079                 else if( (Var->m_Type==TW_TYPE_BOOL8 || Var->m_Type==TW_TYPE_BOOL16 || Var->m_Type==TW_TYPE_BOOL32 || Var->m_Type==TW_TYPE_BOOLCPP) && !Var->m_ReadOnly )
6080                 {
6081                     Var->Increment(1);
6082                     //m_HighlightClickBtn = true;
6083                     m_VarHasBeenIncr = true;
6084                     m_MouseDragVar = false;
6085                     m_MouseDrag = false;
6086                     NotUpToDate();
6087                 }
6088                 else if( Var->m_Type==TW_TYPE_BUTTON && !Var->m_ReadOnly )
6089                 {
6090                     m_HighlightClickBtn = true;
6091                     m_MouseDragVar = false;
6092                     m_MouseDrag = false;
6093                 }
6094                 //else if( (Var->m_Type==TW_TYPE_ENUM8 || Var->m_Type==TW_TYPE_ENUM16 || Var->m_Type==TW_TYPE_ENUM32) && !Var->m_ReadOnly )
6095                 else if( IsEnumType(Var->m_Type) && !Var->m_ReadOnly && !g_TwMgr->m_IsRepeatingMousePressed )
6096                 {
6097                     m_MouseDragVar = false;
6098                     m_MouseDrag = false;
6099                     if( g_TwMgr->m_PopupBar!=NULL )
6100                     {
6101                         TwDeleteBar(g_TwMgr->m_PopupBar);
6102                         g_TwMgr->m_PopupBar = NULL;
6103                     }
6104                     // popup list
6105                     CTwMgr::CEnum& e = g_TwMgr->m_Enums[Var->m_Type-TW_TYPE_ENUM_BASE];
6106                     g_TwMgr->m_PopupBar = TwNewBar("~ Enum Popup ~");
6107                     g_TwMgr->m_PopupBar->m_IsPopupList = true;
6108                     g_TwMgr->m_PopupBar->m_Color = m_Color;
6109                     g_TwMgr->m_PopupBar->m_DarkText = m_DarkText;
6110                     g_TwMgr->m_PopupBar->m_PosX = m_PosX + m_VarX1 - 2;
6111                     g_TwMgr->m_PopupBar->m_PosY = m_PosY + m_VarY0 + (m_HighlightedLine+1)*(m_Font->m_CharHeight+m_LineSep);
6112                     g_TwMgr->m_PopupBar->m_Width = m_Width - 2*m_Font->m_CharHeight;
6113                     g_TwMgr->m_PopupBar->m_LineSep = g_TwMgr->m_PopupBar->m_Sep;
6114                     int popHeight0 = (int)e.m_Entries.size()*(m_Font->m_CharHeight+m_Sep) + m_Font->m_CharHeight/2+2;
6115                     int popHeight = popHeight0;
6116                     if( g_TwMgr->m_PopupBar->m_PosY+popHeight+2 > g_TwMgr->m_WndHeight )
6117                         popHeight = g_TwMgr->m_WndHeight-g_TwMgr->m_PopupBar->m_PosY-2;
6118                     if( popHeight<popHeight0/2 && popHeight<g_TwMgr->m_WndHeight/2 )
6119                         popHeight = min(popHeight0, g_TwMgr->m_WndHeight/2);
6120                     if( popHeight<3*(m_Font->m_CharHeight+m_Sep) )
6121                         popHeight = 3*(m_Font->m_CharHeight+m_Sep);
6122                     g_TwMgr->m_PopupBar->m_Height = popHeight;
6123                     g_TwMgr->m_PopupBar->m_VarEnumLinkedToPopupList = Var;
6124                     g_TwMgr->m_PopupBar->m_BarLinkedToPopupList = this;
6125                     unsigned int CurrentEnumValue = (unsigned int)((int)Var->ValueToDouble());
6126                     for( CTwMgr::CEnum::CEntries::iterator It=e.m_Entries.begin(); It!=e.m_Entries.end(); ++It )
6127                     {
6128                         char ID[64];
6129                         sprintf(ID, "%u", It->first);
6130                         //ultoa(It->first, ID, 10);
6131                         TwAddButton(g_TwMgr->m_PopupBar, ID, PopupCallback, *(void**)&(It->first), NULL);
6132                         CTwVar *Btn = g_TwMgr->m_PopupBar->Find(ID);
6133                         if( Btn!=NULL )
6134                         {
6135                             Btn->m_Label = It->second.c_str();
6136                             if( It->first==CurrentEnumValue )
6137                             {
6138                                 Btn->m_ColorPtr = &m_ColValTextNE;
6139                                 Btn->m_BgColorPtr = &m_ColGrpBg;
6140                             }
6141                         }
6142                     }
6143                     g_TwMgr->m_HelpBarNotUpToDate = false;
6144                 }
6145                 else if( (Var->m_ReadOnly && (Var->m_Type==TW_TYPE_CDSTRING || Var->m_Type==TW_TYPE_CDSTDSTRING || Var->m_Type==TW_TYPE_STDSTRING || IsCSStringType(Var->m_Type)) && EditInPlaceAcceptVar(Var))
6146                          || (!Var->m_ReadOnly && EditInPlaceAcceptVar(Var)) )
6147                     {
6148                         int dw = 0;
6149                         //if( m_DrawIncrDecrBtn )
6150                         //  dw = 2*IncrBtnWidth(m_Font->m_CharHeight);
6151                         if( !m_EditInPlace.m_Active || m_EditInPlace.m_Var!=Var )
6152                         {
6153                             EditInPlaceStart(Var, m_VarX1, m_VarY0+(m_HighlightedLine)*(m_Font->m_CharHeight+m_LineSep), m_VarX2-m_VarX1-dw-1);
6154                             if( EditInPlaceIsReadOnly() )
6155                                 EditInPlaceMouseMove(_X, _Y, false);
6156                             m_MouseDrag = false;
6157                             m_MouseDragVar = false;
6158                         }
6159                         else
6160                         {
6161                             EditInPlaceMouseMove(_X, _Y, false);
6162                             m_MouseDrag = true;
6163                             m_MouseDragVar = false;
6164                         }
6165                         EditInPlaceActive = m_EditInPlace.m_Active;
6166                         if( Var->m_ReadOnly )
6167                             ANT_SET_CURSOR(No);
6168                         else
6169                             ANT_SET_CURSOR(IBeam);
6170                     }
6171                 else if( Var->m_ReadOnly )
6172                     ANT_SET_CURSOR(No);
6173                 else
6174                 {
6175                     ANT_SET_CURSOR(Arrow);
6176                     CustomArea = true;
6177                 }
6178             }
6179             else if ( !_Pressed && m_MouseDragVar )
6180             {
6181                 m_MouseDrag = false;
6182                 m_MouseDragVar = false;
6183                 if( !Handled )
6184                     m_DrawHandles = false;
6185                 Handled = true;
6186                 // end rotoslider
6187                 RotoOnLButtonUp(_X, _Y);
6188
6189                 /* Incr/decr on right or left click
6190                 if( !m_VarHasBeenIncr && !static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly )
6191                 {
6192                     if( _Button==TW_MOUSE_LEFT )
6193                         static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->Increment(-1);
6194                     else if( _Button==TW_MOUSE_RIGHT )
6195                         static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->Increment(1);
6196                     NotUpToDate();
6197                 }
6198                 */
6199
6200                 if( static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var)->m_ReadOnly )
6201                     ANT_SET_CURSOR(No);
6202                 else
6203                 {
6204                     ANT_SET_CURSOR(Arrow);
6205                     CustomArea = true;
6206                 }
6207             }
6208             else if( !_Pressed && m_HighlightClickBtn ) // a button variable is activated
6209             {
6210                 m_HighlightClickBtn = false;
6211                 m_MouseDragVar = false;
6212                 m_MouseDrag = false;
6213                 Handled = true;
6214                 NotUpToDate();
6215                 if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() )
6216                 {
6217                     CTwVarAtom * Var = static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
6218                     if( !Var->m_ReadOnly && Var->m_Type==TW_TYPE_BUTTON && Var->m_Val.m_Button.m_Callback!=NULL )
6219                     {
6220                         Var->m_Val.m_Button.m_Callback(Var->m_ClientData);
6221                         if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
6222                             return 1;
6223                     }
6224                 }
6225             }
6226             else if( !_Pressed )
6227             {
6228                 m_MouseDragVar = false;
6229                 m_MouseDrag = false;
6230                 CustomArea = true;
6231             }
6232         }
6233         else if( _Pressed && !m_MouseDrag && m_Movable && !m_IsPopupList 
6234                  && ( (_Button==TW_MOUSE_LEFT && _X>=m_PosX+2*m_Font->m_CharHeight && _X<m_PosX+m_Width-2*m_Font->m_CharHeight && _Y>=m_PosY && _Y<m_PosY+m_Font->m_CharHeight)
6235                       || (_Button==TW_MOUSE_MIDDLE && _X>=m_PosX && _X<m_PosX+m_Width && _Y>=m_PosY && _Y<m_PosY+m_Height) ) )
6236         {
6237             m_MouseDrag = true;
6238             m_MouseDragTitle = true;
6239             m_MouseOriginX = _X;
6240             m_MouseOriginY = _Y;
6241             m_HighlightTitle = true;
6242             ANT_SET_CURSOR(Move);
6243         }
6244         else if( !_Pressed && m_MouseDragTitle )
6245         {
6246             m_MouseDrag = false;
6247             m_MouseDragTitle = false;
6248             ANT_SET_CURSOR(Arrow);
6249         }
6250         else if( _Pressed && !m_MouseDrag && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_VarX1-3 && _X<m_PosX+m_VarX1+3 && _Y>m_PosY+m_Font->m_CharHeight && _Y<m_PosY+m_VarY0 )
6251         {
6252             m_MouseDrag = true;
6253             m_MouseDragValWidth = true;
6254             m_MouseOriginX = _X;
6255             m_MouseOriginY = _Y;
6256             ANT_SET_CURSOR(WE);
6257         }
6258         else if( !_Pressed && m_MouseDragValWidth )
6259         {
6260             m_MouseDrag = false;
6261             m_MouseDragValWidth = false;
6262             ANT_SET_CURSOR(Arrow);
6263         }
6264         else if( _Pressed && !m_MouseDrag && m_NbDisplayedLines<m_NbHierLines && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_VarX2+2 && _X<m_PosX+m_Width-2 && _Y>=m_ScrollY0 && _Y<m_ScrollY1 )
6265         {
6266             m_MouseDrag = true;
6267             m_MouseDragScroll = true;
6268             m_MouseOriginX = _X;
6269             m_MouseOriginY = _Y;
6270             m_FirstLine0 = m_FirstLine;
6271           #ifdef ANT_WINDOWS
6272             ANT_SET_CURSOR(NS);
6273           #else
6274             ANT_SET_CURSOR(Arrow);
6275           #endif
6276         }
6277         else if( !_Pressed && m_MouseDragScroll )
6278         {
6279             m_MouseDrag = false;
6280             m_MouseDragScroll = false;
6281             ANT_SET_CURSOR(Arrow);
6282         }
6283         else if( _Pressed && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_VarX2+2 && _X<m_PosX+m_Width-2 && _Y>=m_PosY+m_VarY0 && _Y<m_ScrollY0 )
6284         {
6285             if( m_FirstLine>0 )
6286             {
6287                 --m_FirstLine;
6288                 NotUpToDate();
6289             }
6290         }
6291         else if( _Pressed && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_VarX2+2 && _X<m_PosX+m_Width-2 && _Y>=m_ScrollY1 && _Y<m_PosY+m_VarY1 )
6292         {
6293             if( m_FirstLine<m_NbHierLines-m_NbDisplayedLines )
6294             {
6295                 ++m_FirstLine;
6296                 NotUpToDate();
6297             }
6298         }
6299         else if( _Pressed && !m_MouseDrag && m_Resizable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX && _X<m_PosX+m_Font->m_CharHeight && _Y>=m_PosY && _Y<m_PosY+m_Font->m_CharHeight )
6300         {
6301             m_MouseDrag = true;
6302             m_MouseDragResizeUL = true;
6303             m_MouseOriginX = _X;
6304             m_MouseOriginY = _Y;
6305             m_ValuesWidthRatio = (m_Width>0) ? (double)m_ValuesWidth/m_Width : 0;
6306             ANT_SET_CURSOR(TopLeft);
6307         }
6308         else if( !_Pressed && m_MouseDragResizeUL )
6309         {
6310             m_MouseDrag = false;
6311             m_MouseDragResizeUL = false;
6312             ANT_SET_CURSOR(Arrow);
6313         }
6314         else if( _Pressed && !m_MouseDrag && m_Resizable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_Width-m_Font->m_CharHeight && _X<m_PosX+m_Width && _Y>=m_PosY && _Y<m_PosY+m_Font->m_CharHeight )
6315         {
6316             m_MouseDrag = true;
6317             m_MouseDragResizeUR = true;
6318             m_MouseOriginX = _X;
6319             m_MouseOriginY = _Y;
6320             m_ValuesWidthRatio = (m_Width>0) ? (double)m_ValuesWidth/m_Width : 0;
6321             ANT_SET_CURSOR(TopRight);
6322         }
6323         else if( !_Pressed && m_MouseDragResizeUR )
6324         {
6325             m_MouseDrag = false;
6326             m_MouseDragResizeUR = false;
6327             ANT_SET_CURSOR(Arrow);
6328         }
6329         else if( _Pressed && !m_MouseDrag && m_Resizable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX && _X<m_PosX+m_Font->m_CharHeight && _Y>=m_PosY+m_Height-m_Font->m_CharHeight && _Y<m_PosY+m_Height )
6330         {
6331             m_MouseDrag = true;
6332             m_MouseDragResizeLL = true;
6333             m_MouseOriginX = _X;
6334             m_MouseOriginY = _Y;
6335             m_ValuesWidthRatio = (m_Width>0) ? (double)m_ValuesWidth/m_Width : 0;
6336             ANT_SET_CURSOR(BottomLeft);
6337         }
6338         else if( !_Pressed && m_MouseDragResizeLL )
6339         {
6340             m_MouseDrag = false;
6341             m_MouseDragResizeLL = false;
6342             ANT_SET_CURSOR(Arrow);
6343         }
6344         else if( _Pressed && !m_MouseDrag && m_Resizable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_Width-m_Font->m_CharHeight && _X<m_PosX+m_Width && _Y>=m_PosY+m_Height-m_Font->m_CharHeight && _Y<m_PosY+m_Height )
6345         {
6346             m_MouseDrag = true;
6347             m_MouseDragResizeLR = true;
6348             m_MouseOriginX = _X;
6349             m_MouseOriginY = _Y;
6350             m_ValuesWidthRatio = (m_Width>0) ? (double)m_ValuesWidth/m_Width : 0;
6351             ANT_SET_CURSOR(BottomRight);
6352         }
6353         else if( !_Pressed && m_MouseDragResizeLR )
6354         {
6355             m_MouseDrag = false;
6356             m_MouseDragResizeLR = false;
6357             ANT_SET_CURSOR(Arrow);
6358         }
6359         else if( _Pressed && !m_IsPopupList && _Button==TW_MOUSE_LEFT && m_HighlightLabelsHeader )
6360         {
6361             int w = ComputeLabelsWidth(m_Font);
6362             if( w<m_Font->m_CharHeight )
6363                 w = m_Font->m_CharHeight;
6364             m_ValuesWidth = m_VarX2 - m_VarX0 - w;
6365             if( m_ValuesWidth<m_Font->m_CharHeight )
6366                 m_ValuesWidth = m_Font->m_CharHeight;
6367             if( m_ValuesWidth>m_VarX2 - m_VarX0 )
6368                 m_ValuesWidth = max(m_VarX2 - m_VarX0 - m_Font->m_CharHeight, 0);
6369             NotUpToDate();
6370             ANT_SET_CURSOR(Arrow);
6371         }
6372         else if( _Pressed && !m_IsPopupList && _Button==TW_MOUSE_LEFT && m_HighlightValuesHeader )
6373         {
6374             int w = ComputeValuesWidth(m_Font);
6375             if( w<2*m_Font->m_CharHeight )
6376                 w = 2*m_Font->m_CharHeight; // enough to draw a button
6377             m_ValuesWidth = w;
6378             if( m_ValuesWidth>m_VarX2 - m_VarX0 )
6379                 m_ValuesWidth = max(m_VarX2 - m_VarX0 - m_Font->m_CharHeight, 0);
6380             NotUpToDate();
6381             ANT_SET_CURSOR(Arrow);
6382         }
6383         else if( _Pressed && g_TwMgr->m_FontResizable && !m_IsPopupList && _X>=m_PosX+m_Font->m_CharHeight && _X<m_PosX+2*m_Font->m_CharHeight && _Y>m_PosY && _Y<m_PosY+m_Font->m_CharHeight )
6384         {
6385             // change font
6386             if( _Button==TW_MOUSE_LEFT )
6387             {
6388                 if( m_Font==g_DefaultSmallFont )
6389                     g_TwMgr->SetFont(g_DefaultNormalFont, true);
6390                 else if( m_Font==g_DefaultNormalFont )
6391                     g_TwMgr->SetFont(g_DefaultLargeFont, true);
6392                 else if( m_Font==g_DefaultLargeFont )
6393                     g_TwMgr->SetFont(g_DefaultSmallFont, true);
6394                 else
6395                     g_TwMgr->SetFont(g_DefaultNormalFont, true);
6396             }
6397             else if( _Button==TW_MOUSE_RIGHT )
6398             {
6399                 if( m_Font==g_DefaultSmallFont )
6400                     g_TwMgr->SetFont(g_DefaultLargeFont, true);
6401                 else if( m_Font==g_DefaultNormalFont )
6402                     g_TwMgr->SetFont(g_DefaultSmallFont, true);
6403                 else if( m_Font==g_DefaultLargeFont )
6404                     g_TwMgr->SetFont(g_DefaultNormalFont, true);
6405                 else
6406                     g_TwMgr->SetFont(g_DefaultNormalFont, true);
6407             }
6408
6409             ANT_SET_CURSOR(Arrow);
6410         }
6411         else if( _Pressed && m_Iconifiable && !m_IsPopupList && _Button==TW_MOUSE_LEFT && _X>=m_PosX+m_Width-2*m_Font->m_CharHeight && _X<m_PosX+m_Width-m_Font->m_CharHeight && _Y>m_PosY && _Y<m_PosY+m_Font->m_CharHeight )
6412         {
6413             // minimize
6414             g_TwMgr->Minimize(this);
6415             ANT_SET_CURSOR(Arrow);
6416         }
6417         else if( m_IsHelpBar && _Pressed && !g_TwMgr->m_IsRepeatingMousePressed && _X>=m_PosX+m_VarX0 && _X<m_PosX+m_Width-m_Font->m_CharHeight && _Y>m_PosY+m_Height-m_Font->m_CharHeight && _Y<m_PosY+m_Height )
6418         {
6419             /*
6420             const char *WebPage = "http://www.antisphere.com/Wiki/tools:anttweakbar";
6421             #if defined ANT_WINDOWS
6422                 ShellExecute(NULL, "open", WebPage, NULL, NULL, SW_SHOWNORMAL);
6423             #elif defined ANT_UNIX
6424                 // brute force: try all the possible browsers (I don't know how to find the default one; someone?)
6425                 char DefaultBrowsers[] = "firefox,chrome,opera,mozilla,konqueror,galeon,dillo,netscape";
6426                 char *browser = strtok(DefaultBrowsers, ",");
6427                 char cmd[256];
6428                 while(browser)
6429                 {
6430                     snprintf(cmd, sizeof(cmd), "%s \"%s\" 1>& null &", browser, WebPage);
6431                     if( system(cmd) ) {} // avoiding warn_unused_result
6432                     browser = strtok(NULL, ","); // grab the next browser
6433                 }
6434             #elif defined ANT_OSX
6435                 char cmd[256];
6436                 snprintf(cmd, sizeof(cmd), "open \"%s\" 1>& null &", WebPage);
6437                 if( system(cmd) ) {} // avoiding warn_unused_result
6438             #endif
6439             ANT_SET_CURSOR(Hand);
6440             */
6441         }
6442         else
6443         {
6444             CustomArea = true;
6445         }
6446     }
6447     else // minimized
6448     {
6449         if( _Pressed && m_HighlightMaximize )
6450         {
6451             m_HighlightMaximize = false;
6452             g_TwMgr->Maximize(this);
6453             ANT_SET_CURSOR(Arrow);
6454             Handled = true;
6455         }
6456     }
6457
6458     if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call
6459         if( _Pressed && !EditInPlaceActive && m_EditInPlace.m_Active )
6460             EditInPlaceEnd(true);
6461         
6462     // Handled by a custom widget?
6463     if( g_TwMgr!=NULL && (!Handled || CustomArea) && !m_IsMinimized && m_CustomRecords.size()>0 )
6464     {
6465         bool CustomHandled = false;
6466         for( int s=0; s<2; ++s )    // 2 iterations: first for custom widget having focus, second for others if no focused widget.
6467             for( CustomMap::iterator it=m_CustomRecords.begin(); it!=m_CustomRecords.end(); ++it )
6468             {
6469                 CTwMgr::CStructProxy *sProxy = it->first;
6470                 const CCustomRecord& r = it->second;
6471                 if( (s==1 || sProxy->m_CustomCaptureFocus) && !CustomHandled && sProxy!=NULL && sProxy->m_CustomMouseButtonCallback!=NULL && r.m_XMin<r.m_XMax && r.m_Y0<r.m_Y1 && r.m_YMin<=r.m_YMax && r.m_YMin>=r.m_Y0 && r.m_YMax<=r.m_Y1 )
6472                 {
6473                     if( sProxy->m_CustomCaptureFocus || (_X>=r.m_XMin && _X<r.m_XMax && _Y>=r.m_YMin && _Y<r.m_YMax) )
6474                     {
6475                         sProxy->m_CustomCaptureFocus = _Pressed;
6476                         CustomHandled = sProxy->m_CustomMouseButtonCallback(_Button, _Pressed, _X-r.m_XMin, _Y-r.m_Y0, r.m_XMax-r.m_XMin, r.m_Y1-r.m_Y0, sProxy->m_StructExtData, sProxy->m_StructClientData, this, r.m_Var);
6477                         s = 2; // force s-loop exit
6478                     }
6479                 }
6480                 else if( sProxy!=NULL )
6481                 {
6482                     sProxy->m_CustomCaptureFocus = false;   // force free focus, just in case.
6483                     ANT_SET_CURSOR(Arrow);
6484                 }
6485             }
6486         if( CustomHandled )
6487             Handled = true;
6488     }
6489
6490     return Handled;
6491 }
6492
6493
6494 //  ---------------------------------------------------------------------------
6495
6496 bool CTwBar::MouseWheel(int _Pos, int _PrevPos, int _MouseX, int _MouseY)
6497 {
6498     assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0);
6499     if( !m_UpToDate )
6500         Update();
6501     
6502     bool Handled = false;
6503     if( !m_IsMinimized && _MouseX>=m_PosX && _MouseX<m_PosX+m_Width && _MouseY>=m_PosY && _MouseY<m_PosY+m_Height )
6504     {
6505         if( _Pos>_PrevPos && m_FirstLine>0 )
6506         {
6507             --m_FirstLine;
6508             NotUpToDate();
6509         }
6510         else if( _Pos<_PrevPos && m_FirstLine<m_NbHierLines-m_NbDisplayedLines )
6511         {
6512             ++m_FirstLine;
6513             NotUpToDate();
6514         }
6515
6516         if( _Pos!=_PrevPos )
6517         {
6518             Handled = true;
6519             if( m_EditInPlace.m_Active )
6520                 EditInPlaceEnd(true);
6521         }
6522     }
6523
6524     return Handled;
6525 }
6526
6527 //  ---------------------------------------------------------------------------
6528
6529 CTwVarAtom *CTwVarGroup::FindShortcut(int _Key, int _Modifiers, bool *_DoIncr)
6530 {
6531     CTwVarAtom *Atom;
6532     int Mask = 0xffffffff;
6533     if( _Key>' ' && _Key<256 ) // don't test SHIFT if _Key is a common key
6534         Mask &= ~TW_KMOD_SHIFT;
6535
6536     // don't test KMOD_NUM and KMOD_CAPS modifiers coming from SDL
6537     Mask &= ~(0x1000);  // 0x1000 is the KMOD_NUM value defined in SDL_keysym.h
6538     Mask &= ~(0x2000);  // 0x2000 is the KMOD_CAPS value defined in SDL_keysym.h
6539
6540     // complete partial modifiers comming from SDL
6541     if( _Modifiers & TW_KMOD_SHIFT )
6542         _Modifiers |= TW_KMOD_SHIFT;
6543     if( _Modifiers & TW_KMOD_CTRL )
6544         _Modifiers |= TW_KMOD_CTRL;
6545     if( _Modifiers & TW_KMOD_ALT )
6546         _Modifiers |= TW_KMOD_ALT;
6547     if( _Modifiers & TW_KMOD_META )
6548         _Modifiers |= TW_KMOD_META;
6549
6550     for(size_t i=0; i<m_Vars.size(); ++i)
6551         if( m_Vars[i]!=NULL )
6552         {
6553             if( m_Vars[i]->IsGroup() )
6554             {
6555                 Atom = static_cast<CTwVarGroup *>(m_Vars[i])->FindShortcut(_Key, _Modifiers, _DoIncr);
6556                 if( Atom!=NULL )
6557                     return Atom;
6558             }
6559             else
6560             {
6561                 Atom = static_cast<CTwVarAtom *>(m_Vars[i]);
6562                 if( Atom->m_KeyIncr[0]==_Key && (Atom->m_KeyIncr[1]&Mask)==(_Modifiers&Mask) )
6563                 {
6564                     if( _DoIncr!=NULL )
6565                         *_DoIncr = true;
6566                     return Atom;
6567                 }
6568                 else if( Atom->m_KeyDecr[0]==_Key && (Atom->m_KeyDecr[1]&Mask)==(_Modifiers&Mask) )
6569                 {
6570                     if( _DoIncr!=NULL )
6571                         *_DoIncr = false;
6572                     return Atom;
6573                 }
6574             }
6575         }
6576     return NULL;
6577 }
6578
6579 bool CTwBar::KeyPressed(int _Key, int _Modifiers)
6580 {
6581     assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0);
6582     bool Handled = false;
6583     if( !m_UpToDate )
6584         Update();
6585
6586     if( _Key>0 && _Key<TW_KEY_LAST )
6587     {
6588         /* cf TranslateKey in TwMgr.cpp
6589         // CTRL special cases
6590         if( (_Modifiers&TW_KMOD_CTRL) && !(_Modifiers&TW_KMOD_ALT || _Modifiers&TW_KMOD_META) && _Key>0 && _Key<32 )
6591             _Key += 'a'-1;
6592
6593         // PAD translation (for SDL keysym)
6594         if( _Key>=256 && _Key<=272 ) // 256=SDLK_KP0 ... 272=SDLK_KP_EQUALS
6595         {
6596             bool Num = ((_Modifiers&TW_KMOD_SHIFT) && !(_Modifiers&0x1000)) || (!(_Modifiers&TW_KMOD_SHIFT) && (_Modifiers&0x1000)); // 0x1000 is SDL's KMOD_NUM
6597             _Modifiers &= ~TW_KMOD_SHIFT;   // remove shift modifier
6598             if( _Key==266 )          // SDLK_KP_PERIOD
6599                 _Key = Num ? '.' : TW_KEY_DELETE;
6600             else if( _Key==267 )     // SDLK_KP_DIVIDE
6601                 _Key = '/';
6602             else if( _Key==268 )     // SDLK_KP_MULTIPLY
6603                 _Key = '*';
6604             else if( _Key==269 )     // SDLK_KP_MINUS
6605                 _Key = '-';
6606             else if( _Key==270 )     // SDLK_KP_PLUS
6607                 _Key = '+';
6608             else if( _Key==271 )     // SDLK_KP_ENTER
6609                 _Key = TW_KEY_RETURN;
6610             else if( _Key==272 )     // SDLK_KP_EQUALS
6611                 _Key = '=';
6612             else if( Num )           // num SDLK_KP0..9
6613                 _Key += '0' - 256;
6614             else if( _Key==256 )     // non-num SDLK_KP01
6615                 _Key = TW_KEY_INSERT;
6616             else if( _Key==257 )     // non-num SDLK_KP1
6617                 _Key = TW_KEY_END;
6618             else if( _Key==258 )     // non-num SDLK_KP2
6619                 _Key = TW_KEY_DOWN;
6620             else if( _Key==259 )     // non-num SDLK_KP3
6621                 _Key = TW_KEY_PAGE_DOWN;
6622             else if( _Key==260 )     // non-num SDLK_KP4
6623                 _Key = TW_KEY_LEFT;
6624             else if( _Key==262 )     // non-num SDLK_KP6
6625                 _Key = TW_KEY_RIGHT;
6626             else if( _Key==263 )     // non-num SDLK_KP7
6627                 _Key = TW_KEY_HOME;
6628             else if( _Key==264 )     // non-num SDLK_KP8
6629                 _Key = TW_KEY_UP;
6630             else if( _Key==265 )     // non-num SDLK_KP9
6631                 _Key = TW_KEY_PAGE_UP;
6632         }
6633         */
6634
6635         /*
6636         string Str;
6637         TwGetKeyString(&Str, _Key, _Modifiers);
6638         printf("key: %d 0x%04xd %s\n", _Key, _Modifiers, Str.c_str());
6639         */
6640
6641         if( m_EditInPlace.m_Active )
6642         {
6643             Handled = EditInPlaceKeyPressed(_Key, _Modifiers);
6644         }
6645         else
6646         {
6647             bool BarActive = (m_DrawHandles || m_IsPopupList) && !m_IsMinimized;
6648             bool DoIncr = true;
6649             CTwVarAtom *Atom = m_VarRoot.FindShortcut(_Key, _Modifiers, &DoIncr);
6650             if( Atom!=NULL && Atom->m_Visible )
6651             {
6652                 if( !Atom->m_ReadOnly )
6653                 {
6654                     Atom->Increment( DoIncr ? +1 : -1 );
6655                     if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
6656                         return 1;
6657                     m_HighlightClickBtnAuto = g_TwMgr->m_Timer.GetTime();
6658                 }
6659                 NotUpToDate();
6660                 Show(Atom);
6661                 Handled = true;
6662             }
6663             else if( BarActive && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var )
6664             {
6665                 if( _Key==TW_KEY_RIGHT )
6666                 {
6667                     if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) 
6668                     {
6669                         CTwVarAtom *Atom = static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
6670                         bool Accept = !Atom->m_NoSlider || Atom->m_Type==TW_TYPE_BUTTON 
6671                                       || Atom->m_Type==TW_TYPE_BOOL8 || Atom->m_Type==TW_TYPE_BOOL16 || Atom->m_Type==TW_TYPE_BOOL32 || Atom->m_Type==TW_TYPE_BOOLCPP
6672                                       || IsEnumType(Atom->m_Type);
6673                         if( !Atom->IsReadOnly() && !m_IsPopupList && Accept )
6674                         {
6675                             Atom->Increment(+1);
6676                             if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
6677                                 return 1;
6678                             m_HighlightClickBtnAuto = g_TwMgr->m_Timer.GetTime();
6679                             NotUpToDate();
6680                         }
6681                     } 
6682                     else 
6683                     {
6684                         CTwVarGroup *Grp = static_cast<CTwVarGroup *>(m_HierTags[m_HighlightedLine].m_Var);
6685                         if( !Grp->m_Open )
6686                         {
6687                             Grp->m_Open = true;
6688                             NotUpToDate();
6689                         }
6690                     }
6691                     Handled = true;
6692                 }
6693                 else if( _Key==TW_KEY_LEFT )
6694                 {
6695                     if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) 
6696                     {
6697                         CTwVarAtom *Atom = static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
6698                         bool Accept = !Atom->m_NoSlider || Atom->m_Type==TW_TYPE_BUTTON 
6699                                       || Atom->m_Type==TW_TYPE_BOOL8 || Atom->m_Type==TW_TYPE_BOOL16 || Atom->m_Type==TW_TYPE_BOOL32 || Atom->m_Type==TW_TYPE_BOOLCPP
6700                                       || IsEnumType(Atom->m_Type);
6701                         if( !Atom->IsReadOnly() && Accept && !m_IsPopupList )
6702                         {
6703                             Atom->Increment(-1);
6704                             if( g_TwMgr==NULL ) // Mgr might have been destroyed by the client inside a callback call
6705                                 return 1;
6706                             m_HighlightClickBtnAuto = g_TwMgr->m_Timer.GetTime();
6707                             NotUpToDate();
6708                         }
6709                     } 
6710                     else 
6711                     {
6712                         CTwVarGroup *Grp = static_cast<CTwVarGroup *>(m_HierTags[m_HighlightedLine].m_Var);
6713                         if( Grp->m_Open )
6714                         {
6715                             Grp->m_Open = false;
6716                             NotUpToDate();
6717                         }
6718                     }
6719                     Handled = true;
6720                 }
6721                 else if( _Key==TW_KEY_RETURN )
6722                 {
6723                     if( !m_HierTags[m_HighlightedLine].m_Var->IsGroup() ) 
6724                     {
6725                         CTwVarAtom *Atom = static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
6726                         if( !Atom->IsReadOnly() )
6727                         {
6728                             if( Atom->m_Type==TW_TYPE_BUTTON || Atom->m_Type==TW_TYPE_BOOLCPP 
6729                                 || Atom->m_Type==TW_TYPE_BOOL8 || Atom->m_Type==TW_TYPE_BOOL16 || Atom->m_Type==TW_TYPE_BOOL32 )
6730                             {
6731                                 bool isPopup =  m_IsPopupList;
6732                                 Atom->Increment(+1);
6733                                 if( g_TwMgr==NULL // Mgr might have been destroyed by the client inside a callback call
6734                                     || isPopup )  // A popup destroys itself
6735                                     return 1;
6736                                 m_HighlightClickBtnAuto = g_TwMgr->m_Timer.GetTime();
6737                                 NotUpToDate();
6738                             } 
6739                             else // if( IsEnumType(Atom->m_Type) )
6740                             {
6741                                 // simulate a mouse click
6742                                 int y = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_LineSep) + m_Font->m_CharHeight/2;
6743                                 int x = m_PosX + m_VarX1 + 2;
6744                                 if( x>m_PosX+m_VarX2-2 ) 
6745                                     x = m_PosX + m_VarX2 - 2;
6746                                 MouseMotion(x, y);
6747                                 MouseButton(TW_MOUSE_LEFT, true, x, y);
6748                             }
6749                         }
6750                     } 
6751                     else 
6752                     {
6753                         CTwVarGroup *Grp = static_cast<CTwVarGroup *>(m_HierTags[m_HighlightedLine].m_Var);
6754                         Grp->m_Open = !Grp->m_Open;
6755                         NotUpToDate();
6756                     }
6757                     Handled = true;
6758                 }
6759                 else if( _Key==TW_KEY_UP )
6760                 {
6761                     --m_HighlightedLine;
6762                     if( m_HighlightedLine<0 )
6763                     {
6764                         m_HighlightedLine = 0;
6765                         if( m_FirstLine>0 )
6766                         {
6767                             --m_FirstLine;
6768                             NotUpToDate();
6769                         }
6770                     }
6771                     m_HighlightedLineLastValid = m_HighlightedLine;
6772                     Handled = true;
6773                 }
6774                 else if( _Key==TW_KEY_DOWN )
6775                 {
6776                     ++m_HighlightedLine;
6777                     if( m_HighlightedLine>=(int)m_HierTags.size() )
6778                     {
6779                         m_HighlightedLine = (int)m_HierTags.size() - 1;
6780                         if( m_FirstLine<m_NbHierLines-m_NbDisplayedLines )
6781                         {
6782                             ++m_FirstLine;
6783                             NotUpToDate();
6784                         }                    
6785                     }
6786                     m_HighlightedLineLastValid = m_HighlightedLine;
6787                     Handled = true;
6788                 }
6789                 else if( _Key==TW_KEY_ESCAPE && m_IsPopupList )
6790                 {
6791                     Handled = true;
6792                     CTwBar *LinkedBar = m_BarLinkedToPopupList;
6793                     TwDeleteBar(this);
6794                     g_TwMgr->m_PopupBar = NULL;                
6795                     if( LinkedBar!=NULL )
6796                         LinkedBar->m_DrawHandles = true;
6797                     return true; // this bar has been destroyed
6798                 }
6799             }
6800             else if( BarActive )
6801             {
6802                 if( _Key==TW_KEY_UP || _Key==TW_KEY_DOWN || _Key==TW_KEY_LEFT || _Key==TW_KEY_RIGHT || _Key==TW_KEY_RETURN )
6803                 {
6804                     if( m_HighlightedLineLastValid>=0 && m_HighlightedLineLastValid<(int)m_HierTags.size() )
6805                         m_HighlightedLine = m_HighlightedLineLastValid;
6806                     else if( m_HierTags.size()>0 )
6807                     {
6808                         if( _Key==TW_KEY_UP )
6809                             m_HighlightedLine = (int)m_HierTags.size()-1;
6810                         else
6811                             m_HighlightedLine = 0;
6812                     }
6813                     Handled = true;
6814                 }
6815                 else if( _Key==TW_KEY_ESCAPE && m_IsPopupList )
6816                 {
6817                     Handled = true;
6818                     CTwBar *LinkedBar = m_BarLinkedToPopupList;
6819                     TwDeleteBar(this);
6820                     g_TwMgr->m_PopupBar = NULL;                
6821                     if( LinkedBar!=NULL )
6822                         LinkedBar->m_DrawHandles = true;
6823                     return true; // this bar has been destroyed
6824                 }
6825             }
6826         }
6827     }
6828     return Handled;
6829 }
6830
6831 //  ---------------------------------------------------------------------------
6832
6833 bool CTwBar::KeyTest(int _Key, int _Modifiers)
6834 {
6835     assert(g_TwMgr->m_Graph && g_TwMgr->m_WndHeight>0 && g_TwMgr->m_WndWidth>0);
6836     bool Handled = false;
6837     if( !m_UpToDate )
6838         Update();
6839
6840     if( _Key>0 && _Key<TW_KEY_LAST )
6841     {
6842         if( m_EditInPlace.m_Active )
6843             Handled = true;
6844         else
6845         {
6846             bool BarActive = (m_DrawHandles || m_IsPopupList) && !m_IsMinimized;
6847             bool DoIncr;
6848             CTwVarAtom *Atom = m_VarRoot.FindShortcut(_Key, _Modifiers, &DoIncr);
6849             if( Atom!=NULL && Atom->m_Visible )
6850                 Handled = true;
6851             else if( BarActive && ( _Key==TW_KEY_RIGHT || _Key==TW_KEY_LEFT || _Key==TW_KEY_UP || _Key==TW_KEY_DOWN
6852                                     || _Key==TW_KEY_RETURN || (_Key==TW_KEY_ESCAPE && m_IsPopupList) ) )
6853                 Handled = true;
6854         }
6855     }
6856     return Handled;
6857 }
6858
6859 //  ---------------------------------------------------------------------------
6860
6861 bool CTwBar::Show(CTwVar *_Var)
6862 {
6863     if( _Var==NULL || !_Var->m_Visible )
6864         return false;
6865     if( !m_UpToDate )
6866         Update();
6867
6868     if( OpenHier(&m_VarRoot, _Var) )
6869     {
6870         if( !m_UpToDate )
6871             Update();
6872         int l = LineInHier(&m_VarRoot, _Var);
6873         if( l>=0 )
6874         {
6875             int NbLines = (m_VarY1-m_VarY0+1)/(m_Font->m_CharHeight+m_LineSep);
6876             if( NbLines<= 0 )
6877                 NbLines = 1;
6878             if( l<m_FirstLine || l>=m_FirstLine+NbLines )
6879             {
6880                 m_FirstLine = l-NbLines/2;
6881                 if( m_FirstLine<0 )
6882                     m_FirstLine = 0;
6883                 NotUpToDate();
6884                 Update();
6885                 if( m_NbDisplayedLines<NbLines )
6886                 {
6887                     m_FirstLine -= NbLines-m_NbDisplayedLines;
6888                     if( m_FirstLine<0 )
6889                         m_FirstLine = 0;                    
6890                     NotUpToDate();
6891                 }
6892             }
6893             m_HighlightedLine = l-m_FirstLine;
6894             return true;
6895         }
6896     }
6897
6898     return false;
6899 }
6900
6901 //  ---------------------------------------------------------------------------
6902
6903 bool CTwBar::OpenHier(CTwVarGroup *_Root, CTwVar *_Var)
6904 {
6905     assert( _Root!=NULL );
6906     for(size_t i=0; i<_Root->m_Vars.size(); ++i)
6907         if( _Root->m_Vars[i]!=NULL )
6908         {
6909             if( _Var==_Root->m_Vars[i] 
6910                 || (_Root->m_Vars[i]->IsGroup() && OpenHier(static_cast<CTwVarGroup *>(_Root->m_Vars[i]), _Var)) )
6911             {
6912                 _Root->m_Open = true;
6913                 NotUpToDate();
6914                 return true;
6915             }
6916         }
6917     return false;
6918 }
6919
6920 //  ---------------------------------------------------------------------------
6921
6922 int CTwBar::LineInHier(CTwVarGroup *_Root, CTwVar *_Var)
6923 {
6924     assert( _Root!=NULL );
6925     int l = 0;
6926     for(size_t i=0; i<_Root->m_Vars.size(); ++i)
6927         if( _Root->m_Vars[i]!=NULL && _Root->m_Vars[i]->m_Visible )
6928         {
6929             if( _Var==_Root->m_Vars[i] )
6930                 return l;
6931             else if( _Root->m_Vars[i]->IsGroup() && static_cast<CTwVarGroup *>(_Root->m_Vars[i])->m_Open )
6932             {
6933                 ++l;
6934                 int ll = LineInHier(static_cast<CTwVarGroup *>(_Root->m_Vars[i]), _Var);
6935                 if( ll>=0 )
6936                     return l+ll;
6937                 else
6938                     l += -ll-2;
6939             }
6940             ++l;
6941         }
6942     return -l-1;
6943 }
6944
6945 //  ---------------------------------------------------------------------------
6946
6947 void DrawArc(int _X, int _Y, int _Radius, float _StartAngleDeg, float _EndAngleDeg, color32 _Color) // angles in degree
6948 {
6949     ITwGraph *Gr = g_TwMgr->m_Graph;
6950     if( Gr==NULL || !Gr->IsDrawing() || _Radius==0 || _StartAngleDeg==_EndAngleDeg )
6951         return;
6952
6953     float startAngle = (float)M_PI*_StartAngleDeg/180;
6954     float endAngle = (float)M_PI*_EndAngleDeg/180;
6955     //float stepAngle = 8/(float)_Radius;   // segment length = 8 pixels
6956     float stepAngle = 4/(float)_Radius; // segment length = 4 pixels
6957     if( stepAngle>(float)M_PI/4 )
6958         stepAngle = (float)M_PI/4;
6959     bool fullCircle = fabsf(endAngle-startAngle)>=2.0f*(float)M_PI+fabsf(stepAngle);
6960     int numSteps;
6961     if( fullCircle )
6962     {
6963         numSteps = int((2.0f*(float)M_PI)/stepAngle);
6964         startAngle = 0;
6965         endAngle = 2.0f*(float)M_PI;
6966     }
6967     else
6968         numSteps = int(fabsf(endAngle-startAngle)/stepAngle);
6969     if( startAngle>endAngle )
6970         stepAngle = -stepAngle;
6971
6972     int x0 = int(_X + _Radius * cosf(startAngle) + 0.5f);
6973     int y0 = int(_Y - _Radius * sinf(startAngle) + 0.5f);
6974     int x1, y1;
6975     float angle = startAngle+stepAngle;
6976
6977     for( int i=0; i<numSteps; ++i, angle+=stepAngle )
6978     {
6979         x1 = int(_X + _Radius * cosf(angle) + 0.5f);
6980         y1 = int(_Y - _Radius * sinf(angle) + 0.5f);
6981         Gr->DrawLine(x0, y0, x1, y1, _Color, true);
6982         x0 = x1;
6983         y0 = y1;
6984     }
6985
6986     if( fullCircle )
6987     {
6988         x1 = int(_X + _Radius * cosf(startAngle) + 0.5f);
6989         y1 = int(_Y - _Radius * sinf(startAngle) + 0.5f);
6990     }
6991     else
6992     {
6993         x1 = int(_X + _Radius * cosf(endAngle) + 0.5f);
6994         y1 = int(_Y - _Radius * sinf(endAngle) + 0.5f);
6995     }
6996     Gr->DrawLine(x0, y0, x1, y1, _Color, true);
6997 }
6998
6999 //  ---------------------------------------------------------------------------
7000
7001 CTwBar::CRotoSlider::CRotoSlider()
7002 {
7003     m_Var = NULL;
7004     m_Active = false;
7005     m_ActiveMiddle = false;
7006     m_Subdiv = 256; // will be recalculated in RotoOnLButtonDown
7007 }
7008
7009 void CTwBar::RotoDraw()
7010 {
7011     ITwGraph *Gr = g_TwMgr->m_Graph;
7012     if( Gr==NULL || !Gr->IsDrawing() )
7013         return;
7014
7015     if( m_Roto.m_Active )
7016     {
7017         DrawArc(m_Roto.m_Origin.x, m_Roto.m_Origin.y, 32, 0, 360, m_ColRoto);
7018         DrawArc(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, 32, 0, 360, m_ColRoto);
7019         DrawArc(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, 32, 0, 360, m_ColRoto);
7020
7021         if( m_Roto.m_HasPrevious )
7022         {
7023             double varMax = RotoGetMax();
7024             double varMin = RotoGetMin();
7025             double varStep = RotoGetStep();
7026             if( varMax<DOUBLE_MAX && varMin>-DOUBLE_MAX && fabs(varStep)>DOUBLE_EPS && m_Roto.m_Subdiv>0 )
7027             {
7028                 double dtMax = 360.0*(varMax-m_Roto.m_ValueAngle0)/((double)m_Roto.m_Subdiv*varStep);//+2;
7029                 double dtMin = 360.0*(varMin-m_Roto.m_ValueAngle0)/((double)m_Roto.m_Subdiv*varStep);//-2;
7030
7031                 if( dtMax>=0 && dtMax<360 && dtMin<=0 && dtMin>-360 && fabs(dtMax-dtMin)<=360 )
7032                 {
7033                     int x1, y1, x2, y2;
7034                     double da = 2.0*M_PI/m_Roto.m_Subdiv;
7035
7036                     x1 = m_Roto.m_Origin.x + (int)(40*cos(-M_PI*(m_Roto.m_Angle0+dtMax)/180-da));
7037                     y1 = m_Roto.m_Origin.y + (int)(40*sin(-M_PI*(m_Roto.m_Angle0+dtMax)/180-da)+0.5);
7038                     x2 = m_Roto.m_Origin.x + (int)(40*cos(-M_PI*(m_Roto.m_Angle0+dtMax-10)/180-da));
7039                     y2 = m_Roto.m_Origin.y + (int)(40*sin(-M_PI*(m_Roto.m_Angle0+dtMax-10)/180-da)+0.5);
7040                     Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y, x1, y1, m_ColRotoBound, true);
7041                     Gr->DrawLine(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, x1+1, y1, m_ColRotoBound, true);
7042                     Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, x1, y1+1, m_ColRotoBound, true);
7043                     Gr->DrawLine(x1, y1, x2, y2, m_ColRotoBound, true);
7044                     Gr->DrawLine(x1+1, y1, x2+1, y2, m_ColRotoBound, true);
7045                     Gr->DrawLine(x1, y1+1, x2, y2+1, m_ColRotoBound, true);
7046
7047                     x1 = m_Roto.m_Origin.x + (int)(40*cos(-M_PI*(m_Roto.m_Angle0+dtMin)/180+da));
7048                     y1 = m_Roto.m_Origin.y + (int)(40*sin(-M_PI*(m_Roto.m_Angle0+dtMin)/180+da)+0.5);
7049                     x2 = m_Roto.m_Origin.x + (int)(40*cos(-M_PI*(m_Roto.m_Angle0+dtMin+10)/180+da));
7050                     y2 = m_Roto.m_Origin.y + (int)(40*sin(-M_PI*(m_Roto.m_Angle0+dtMin+10)/180+da)+0.5);
7051                     Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y, x1, y1, m_ColRotoBound, true);
7052                     Gr->DrawLine(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, x1+1, y1, m_ColRotoBound, true);
7053                     Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, x1, y1+1, m_ColRotoBound, true);
7054                     Gr->DrawLine(x1, y1, x2, y2, m_ColRotoBound, true);
7055                     Gr->DrawLine(x1+1, y1, x2+1, y2, m_ColRotoBound, true);
7056                     Gr->DrawLine(x1, y1+1, x2, y2+1, m_ColRotoBound, true);
7057                 }
7058             }
7059         }
7060
7061         Gr->DrawLine(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, m_Roto.m_Current.x+1, m_Roto.m_Current.y, m_ColRotoVal, true);
7062         Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, m_Roto.m_Current.x, m_Roto.m_Current.y+1, m_ColRotoVal, true);
7063         Gr->DrawLine(m_Roto.m_Origin.x, m_Roto.m_Origin.y, m_Roto.m_Current.x, m_Roto.m_Current.y, m_ColRotoVal, true);
7064
7065         if( fabs(m_Roto.m_AngleDT)>=1 )
7066         {
7067             DrawArc(m_Roto.m_Origin.x, m_Roto.m_Origin.y, 32, float(m_Roto.m_Angle0), float(m_Roto.m_Angle0+m_Roto.m_AngleDT-1), m_ColRotoVal);
7068             DrawArc(m_Roto.m_Origin.x+1, m_Roto.m_Origin.y, 32, float(m_Roto.m_Angle0), float(m_Roto.m_Angle0+m_Roto.m_AngleDT-1), m_ColRotoVal);
7069             DrawArc(m_Roto.m_Origin.x, m_Roto.m_Origin.y+1, 32, float(m_Roto.m_Angle0), float(m_Roto.m_Angle0+m_Roto.m_AngleDT-1), m_ColRotoVal);
7070         }
7071     }
7072 }
7073
7074 double CTwBar::RotoGetValue() const
7075 {
7076     assert(m_Roto.m_Var!=NULL);
7077     return m_Roto.m_Var->ValueToDouble();
7078 }
7079
7080 void CTwBar::RotoSetValue(double _Val)
7081 {
7082     assert(m_Roto.m_Var!=NULL);
7083     if( _Val!=m_Roto.m_CurrentValue )
7084     {
7085         m_Roto.m_CurrentValue = _Val;
7086         m_Roto.m_Var->ValueFromDouble(_Val);
7087         NotUpToDate();
7088     }
7089 }
7090
7091 double CTwBar::RotoGetMin() const
7092 {
7093     assert(m_Roto.m_Var!=NULL);
7094     double min = -DOUBLE_MAX;
7095     m_Roto.m_Var->MinMaxStepToDouble(&min, NULL, NULL);
7096     return min;
7097 }
7098
7099 double CTwBar::RotoGetMax() const
7100 {
7101     assert(m_Roto.m_Var!=NULL);
7102     double max = DOUBLE_MAX;
7103     m_Roto.m_Var->MinMaxStepToDouble(NULL, &max, NULL);
7104     return max;
7105 }
7106
7107 double CTwBar::RotoGetStep() const
7108 {
7109     assert(m_Roto.m_Var!=NULL);
7110     double step = 1;
7111     m_Roto.m_Var->MinMaxStepToDouble(NULL, NULL, &step);
7112     return step;
7113 }
7114
7115 double CTwBar::RotoGetSteppedValue() const
7116 {
7117     double d = m_Roto.m_PreciseValue-m_Roto.m_Value0;
7118     double n = int(d/RotoGetStep());
7119     return m_Roto.m_Value0 + RotoGetStep()*n;
7120 }
7121
7122 void CTwBar::RotoOnMouseMove(int _X, int _Y)
7123 {
7124     CPoint p(_X, _Y);
7125     if( m_Roto.m_Active )
7126     {
7127         m_Roto.m_Current = p;
7128         RotoSetValue(RotoGetSteppedValue());
7129         //DrawManip();
7130
7131         int ti = -1;
7132         double t = 0;
7133         float r = sqrtf(float(  (m_Roto.m_Current.x-m_Roto.m_Origin.x)*(m_Roto.m_Current.x-m_Roto.m_Origin.x) 
7134                               + (m_Roto.m_Current.y-m_Roto.m_Origin.y)*(m_Roto.m_Current.y-m_Roto.m_Origin.y)));
7135         if( r>m_RotoMinRadius )
7136         {
7137             t = - atan2(double(m_Roto.m_Current.y-m_Roto.m_Origin.y), double(m_Roto.m_Current.x-m_Roto.m_Origin.x));
7138             ti = (int((t/(2.0*M_PI)+1.0)*NB_ROTO_CURSORS+0.5)) % NB_ROTO_CURSORS;
7139             if( m_Roto.m_HasPrevious )
7140             {
7141                 CPoint v0 = m_Roto.m_Previous-m_Roto.m_Origin;
7142                 CPoint v1 = m_Roto.m_Current-m_Roto.m_Origin;
7143                 double l0 = sqrt(double(v0.x*v0.x+v0.y*v0.y));
7144                 double l1 = sqrt(double(v1.x*v1.x+v1.y*v1.y));
7145                 double dt = acos(max(-1+1.0e-30,min(1-1.0e-30,double(v0.x*v1.x+v0.y*v1.y)/(l0*l1))));
7146                 if( v0.x*v1.y-v0.y*v1.x>0 )
7147                     dt = - dt;
7148                 double preciseInc = double(m_Roto.m_Subdiv) * dt/(2.0*M_PI) * RotoGetStep();
7149                 if( preciseInc>RotoGetStep() || preciseInc<-RotoGetStep() )
7150                 {
7151                     m_Roto.m_PreciseValue += preciseInc;
7152                     if( m_Roto.m_PreciseValue>RotoGetMax() )
7153                     {
7154                         m_Roto.m_PreciseValue = RotoGetMax();
7155                         m_Roto.m_Value0 = RotoGetMax();
7156
7157                         double da = 360*(RotoGetMax()-m_Roto.m_ValueAngle0)/(double(m_Roto.m_Subdiv)*RotoGetStep());
7158                         m_Roto.m_Angle0 = ((int((t/(2.0*M_PI)+1.0)*360.0+0.5)) % 360) - da;
7159                         m_Roto.m_AngleDT = da;
7160                     }
7161                     else if( m_Roto.m_PreciseValue<RotoGetMin() )
7162                     {
7163                         m_Roto.m_PreciseValue = RotoGetMin();
7164                         m_Roto.m_Value0 = RotoGetMin();
7165
7166                         double da = 360*(RotoGetMin()-m_Roto.m_ValueAngle0)/(double(m_Roto.m_Subdiv)*RotoGetStep());
7167                         m_Roto.m_Angle0 = ((int((t/(2.0*M_PI)+1.0)*360.0+0.5)) % 360) - da;
7168                         m_Roto.m_AngleDT = da;
7169                     }
7170                     m_Roto.m_Previous = m_Roto.m_Current;
7171                     m_Roto.m_AngleDT += 180.0*dt/M_PI;
7172                 }
7173             }
7174             else
7175             {
7176                 m_Roto.m_Previous = m_Roto.m_Current;
7177                 m_Roto.m_Value0 = RotoGetValue();
7178                 m_Roto.m_PreciseValue = m_Roto.m_Value0;
7179                 m_Roto.m_HasPrevious = true;
7180                 m_Roto.m_Angle0 = (int((t/(2.0*M_PI)+1.0)*360.0+0.5)) % 360;
7181                 m_Roto.m_ValueAngle0 = m_Roto.m_Value0;
7182                 m_Roto.m_AngleDT = 0;
7183             }
7184         }
7185         else
7186         {
7187             if( m_Roto.m_HasPrevious )
7188             {
7189                 RotoSetValue(RotoGetSteppedValue());
7190                 m_Roto.m_Value0 = RotoGetValue();
7191                 m_Roto.m_ValueAngle0 = m_Roto.m_Value0;
7192                 m_Roto.m_PreciseValue = m_Roto.m_Value0;
7193                 m_Roto.m_Angle0 = 0;    
7194             }
7195             m_Roto.m_HasPrevious = false;
7196             m_Roto.m_AngleDT = 0;
7197         }
7198         if( ti>=0 && ti<NB_ROTO_CURSORS )
7199             ANT_SET_ROTO_CURSOR(ti);
7200         else
7201             ANT_SET_CURSOR(Center);
7202     }
7203     else
7204     {
7205         if( m_HighlightRotoBtn )
7206             ANT_SET_CURSOR(Point);
7207         else
7208             ANT_SET_CURSOR(Arrow);
7209     }
7210 }
7211
7212 void CTwBar::RotoOnLButtonDown(int _X, int _Y)
7213 {
7214     CPoint p(_X, _Y);
7215     if( !m_Roto.m_Active && m_HighlightedLine>=0 && m_HighlightedLine<(int)m_HierTags.size() && m_HierTags[m_HighlightedLine].m_Var && !m_HierTags[m_HighlightedLine].m_Var->IsGroup() )
7216     {
7217         m_Roto.m_Var = static_cast<CTwVarAtom *>(m_HierTags[m_HighlightedLine].m_Var);
7218         int y = m_PosY + m_VarY0 + m_HighlightedLine*(m_Font->m_CharHeight+m_LineSep) + m_Font->m_CharHeight/2;
7219         m_Roto.m_Origin = CPoint(p.x, y); //r.CenterPoint().y);
7220         m_Roto.m_Current = p;
7221         m_Roto.m_Active = true;
7222         m_Roto.m_HasPrevious = false;
7223         m_Roto.m_Angle0 = 0;
7224         m_Roto.m_AngleDT = 0;
7225         //SetCapture();
7226
7227         m_Roto.m_Value0 = RotoGetValue();
7228         m_Roto.m_CurrentValue = m_Roto.m_Value0;
7229         m_Roto.m_ValueAngle0 = m_Roto.m_Value0;
7230         m_Roto.m_PreciseValue = m_Roto.m_Value0;
7231         //RotoSetValue(RotoGetSteppedValue());  Not here
7232         //DrawManip();
7233
7234         m_Roto.m_Subdiv = m_RotoNbSubdiv;
7235         // re-adjust m_Subdiv if needed:
7236         double min=-DOUBLE_MAX, max=DOUBLE_MAX, step=1;
7237         m_Roto.m_Var->MinMaxStepToDouble(&min, &max, &step);
7238         if( fabs(step)>0 && min>-DOUBLE_MAX && max<DOUBLE_MAX )
7239         {
7240             double dsubdiv = fabs(max-min)/fabs(step)+0.5;
7241             if( dsubdiv<m_RotoNbSubdiv/3 )
7242                 m_Roto.m_Subdiv = 3*(int)dsubdiv;
7243         }
7244
7245         ANT_SET_CURSOR(Center);
7246     }
7247 }
7248
7249 void CTwBar::RotoOnLButtonUp(int /*_X*/, int /*_Y*/)
7250 {
7251     if( !m_Roto.m_ActiveMiddle )
7252     {
7253         //if( m_Roto.m_Var )
7254         //  RotoSetValue(RotoGetSteppedValue());
7255
7256         m_Roto.m_Var = NULL;
7257         m_Roto.m_Active = false;
7258     }
7259 }
7260
7261 void CTwBar::RotoOnMButtonDown(int _X, int _Y)
7262 {
7263     if( !m_Roto.m_Active )
7264     {
7265         m_Roto.m_ActiveMiddle = true;
7266         RotoOnLButtonDown(_X, _Y);
7267     }
7268 }
7269
7270 void CTwBar::RotoOnMButtonUp(int _X, int _Y)
7271 {
7272     if( m_Roto.m_ActiveMiddle )
7273     {
7274         m_Roto.m_ActiveMiddle = false;
7275         RotoOnLButtonUp(_X, _Y);
7276     }
7277 }
7278
7279
7280 //  ---------------------------------------------------------------------------
7281
7282 CTwBar::CEditInPlace::CEditInPlace()
7283 {
7284     assert( g_TwMgr!=NULL && g_TwMgr->m_Graph!=NULL );
7285
7286     m_Var = NULL;
7287     m_Active = false;
7288     m_EditTextObj = g_TwMgr->m_Graph->NewTextObj();
7289     m_EditSelTextObj = g_TwMgr->m_Graph->NewTextObj();
7290
7291     m_X = m_Y = m_Width = 0;
7292 }
7293
7294 CTwBar::CEditInPlace::~CEditInPlace()
7295 {
7296     assert( g_TwMgr!=NULL && g_TwMgr->m_Graph!=NULL );
7297
7298     if( m_EditTextObj )
7299         g_TwMgr->m_Graph->DeleteTextObj(m_EditTextObj);
7300     if( m_EditSelTextObj )
7301         g_TwMgr->m_Graph->DeleteTextObj(m_EditSelTextObj);
7302 }
7303
7304 bool CTwBar::EditInPlaceIsReadOnly()
7305 {
7306     if( m_EditInPlace.m_Var==NULL )
7307         return true;
7308     else if( m_EditInPlace.m_Var->m_ReadOnly )
7309         return true;
7310     else if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CDSTRING && ((m_EditInPlace.m_Var->m_Ptr==NULL && m_EditInPlace.m_Var->m_SetCallback==NULL) || (m_EditInPlace.m_Var->m_Ptr!=NULL && g_TwMgr->m_CopyCDStringToClient==NULL)) )
7311         return true;
7312     else if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CDSTDSTRING && m_EditInPlace.m_Var->m_SetCallback==NULL )
7313         return true;
7314     else if( m_EditInPlace.m_Var->m_Type==TW_TYPE_STDSTRING && ((m_EditInPlace.m_Var->m_Ptr==NULL && m_EditInPlace.m_Var->m_SetCallback==NULL) || (m_EditInPlace.m_Var->m_Ptr!=NULL && g_TwMgr->m_CopyStdStringToClient==NULL)) )
7315         return true;
7316     else
7317         return false;
7318 }
7319
7320 void CTwBar::EditInPlaceDraw()
7321 {
7322     if( !m_EditInPlace.m_Active || m_EditInPlace.m_Var==NULL || m_EditInPlace.m_Width<=0 )
7323         return;
7324
7325     // adjust m_FirstChar to see the caret, and extract the visible sub-string
7326     int i, StringLen = (int)m_EditInPlace.m_String.length();
7327     if( m_EditInPlace.m_FirstChar>m_EditInPlace.m_CaretPos )
7328         m_EditInPlace.m_FirstChar = m_EditInPlace.m_CaretPos;
7329     int SubstrWidth = 0;
7330     for( i=min(m_EditInPlace.m_CaretPos, StringLen-1); i>=0 && SubstrWidth<m_EditInPlace.m_Width; --i )
7331     {
7332         unsigned char u = m_EditInPlace.m_String.c_str()[i];
7333         SubstrWidth += m_Font->m_CharWidth[u];
7334     }
7335     int FirstChar = max(0, i);
7336     if( SubstrWidth>=m_EditInPlace.m_Width )
7337         FirstChar += 2;
7338     if( m_EditInPlace.m_FirstChar<FirstChar && FirstChar<StringLen )
7339         m_EditInPlace.m_FirstChar = FirstChar;
7340     if( m_EditInPlace.m_CaretPos==m_EditInPlace.m_FirstChar && m_EditInPlace.m_FirstChar>0 )
7341         --m_EditInPlace.m_FirstChar;
7342     SubstrWidth = 0;
7343     for( i=m_EditInPlace.m_FirstChar; i<StringLen && SubstrWidth<m_EditInPlace.m_Width; ++i )
7344     {
7345         unsigned char u = m_EditInPlace.m_String.c_str()[i];
7346         SubstrWidth += m_Font->m_CharWidth[u];
7347     }
7348     int LastChar = i;
7349     if( SubstrWidth>=m_EditInPlace.m_Width )
7350         --LastChar;
7351     string Substr = m_EditInPlace.m_String.substr( m_EditInPlace.m_FirstChar, LastChar-m_EditInPlace.m_FirstChar );
7352
7353     // compute caret x pos
7354     int CaretX = m_PosX + m_EditInPlace.m_X;
7355     for( i=m_EditInPlace.m_FirstChar; i<m_EditInPlace.m_CaretPos && i<StringLen; ++i )
7356     {
7357         unsigned char u = m_EditInPlace.m_String.c_str()[i];
7358         CaretX += m_Font->m_CharWidth[u];
7359     }
7360
7361     // draw edit text
7362     color32 ColText = EditInPlaceIsReadOnly() ? m_ColValTextRO : m_ColEditText;
7363     color32 ColBg = EditInPlaceIsReadOnly() ? m_ColValBg : m_ColEditBg;
7364     g_TwMgr->m_Graph->BuildText(m_EditInPlace.m_EditTextObj, &Substr, NULL, NULL, 1, m_Font, 0, m_EditInPlace.m_Width);
7365     g_TwMgr->m_Graph->DrawText(m_EditInPlace.m_EditTextObj, m_PosX+m_EditInPlace.m_X, m_PosY+m_EditInPlace.m_Y, ColText, ColBg);
7366
7367     // draw selected text
7368     string StrSelected = "";
7369     if( m_EditInPlace.m_CaretPos>m_EditInPlace.m_SelectionStart )
7370     {
7371         int FirstSel = max(m_EditInPlace.m_SelectionStart, m_EditInPlace.m_FirstChar);
7372         int LastSel = min(m_EditInPlace.m_CaretPos, LastChar);
7373         StrSelected = m_EditInPlace.m_String.substr( FirstSel, LastSel-FirstSel );
7374     }
7375     else
7376     {
7377         int FirstSel = max(m_EditInPlace.m_CaretPos, m_EditInPlace.m_FirstChar);
7378         int LastSel = min(m_EditInPlace.m_SelectionStart, LastChar);
7379         StrSelected = m_EditInPlace.m_String.substr( FirstSel, LastSel-FirstSel );
7380     }
7381     int SelWidth = 0;
7382     for( i=0; i<(int)StrSelected.length(); ++i )
7383     {
7384         unsigned char u = StrSelected.c_str()[i];
7385         SelWidth += m_Font->m_CharWidth[u];
7386     }
7387     if( SelWidth>0 && StrSelected.length()>0 )
7388     {
7389         color32 ColSelBg = EditInPlaceIsReadOnly() ? m_ColValTextRO : m_ColEditSelBg;
7390         g_TwMgr->m_Graph->BuildText(m_EditInPlace.m_EditSelTextObj, &StrSelected, NULL, NULL, 1, m_Font, 0, SelWidth);
7391         if ( m_EditInPlace.m_CaretPos>m_EditInPlace.m_SelectionStart )
7392             g_TwMgr->m_Graph->DrawText(m_EditInPlace.m_EditSelTextObj, CaretX-SelWidth, m_PosY+m_EditInPlace.m_Y, m_ColEditSelText, ColSelBg);
7393         else
7394             g_TwMgr->m_Graph->DrawText(m_EditInPlace.m_EditSelTextObj, CaretX, m_PosY+m_EditInPlace.m_Y, m_ColEditSelText, ColSelBg);
7395     }
7396
7397     // draw caret
7398     if( CaretX<=m_PosX+m_EditInPlace.m_X+m_EditInPlace.m_Width )
7399         g_TwMgr->m_Graph->DrawLine( CaretX, m_PosY+m_EditInPlace.m_Y+1, CaretX, m_PosY+m_EditInPlace.m_Y+m_Font->m_CharHeight, m_ColEditText );
7400 }
7401
7402 bool CTwBar::EditInPlaceAcceptVar(const CTwVarAtom* _Var)
7403 {
7404     if( _Var==NULL )
7405         return false;
7406     if( _Var->m_Type>=TW_TYPE_CHAR && _Var->m_Type<=TW_TYPE_DOUBLE )
7407         return true;
7408     if( _Var->m_Type==TW_TYPE_CDSTRING || _Var->m_Type==TW_TYPE_CDSTDSTRING || _Var->m_Type==TW_TYPE_STDSTRING )
7409         return true;
7410     if( IsCSStringType(_Var->m_Type) )
7411         return true;
7412
7413     return false;
7414 }
7415
7416 void CTwBar::EditInPlaceStart(CTwVarAtom* _Var, int _X, int _Y, int _Width)
7417 {
7418     if( m_EditInPlace.m_Active )
7419         EditInPlaceEnd(true);
7420
7421     m_EditInPlace.m_Active = true;
7422     m_EditInPlace.m_Var = _Var;
7423     m_EditInPlace.m_X = _X;
7424     m_EditInPlace.m_Y = _Y;
7425     m_EditInPlace.m_Width = _Width;
7426     m_EditInPlace.m_Var->ValueToString(&m_EditInPlace.m_String);
7427     if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CHAR )
7428         m_EditInPlace.m_String = m_EditInPlace.m_String.substr(0, 1);
7429     m_EditInPlace.m_CaretPos = (int)m_EditInPlace.m_String.length();
7430     if( EditInPlaceIsReadOnly() )
7431         m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos;
7432     else
7433         m_EditInPlace.m_SelectionStart = 0;
7434     m_EditInPlace.m_FirstChar = 0;
7435 }
7436
7437 void CTwBar::EditInPlaceEnd(bool _Commit)
7438 {
7439     if( _Commit && m_EditInPlace.m_Active && m_EditInPlace.m_Var!=NULL )
7440     {
7441         if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CDSTRING || m_EditInPlace.m_Var->m_Type==TW_TYPE_CDSTDSTRING )
7442         {
7443             if( m_EditInPlace.m_Var->m_SetCallback!=NULL )
7444             {
7445                 const char *String = m_EditInPlace.m_String.c_str();
7446                 m_EditInPlace.m_Var->m_SetCallback(&String, m_EditInPlace.m_Var->m_ClientData);
7447             }
7448             else if( m_EditInPlace.m_Var->m_Type!=TW_TYPE_CDSTDSTRING )
7449             {
7450                 char **StringPtr = (char **)m_EditInPlace.m_Var->m_Ptr;
7451                 if( StringPtr!=NULL && g_TwMgr->m_CopyCDStringToClient!=NULL )
7452                     g_TwMgr->m_CopyCDStringToClient(StringPtr, m_EditInPlace.m_String.c_str());
7453             }
7454         }
7455         else if( m_EditInPlace.m_Var->m_Type==TW_TYPE_STDSTRING )
7456         {   
7457             // this case should never happened: TW_TYPE_STDSTRING are converted to TW_TYPE_CDSTDSTRING by TwAddVar
7458             if( m_EditInPlace.m_Var->m_SetCallback!=NULL )
7459                 m_EditInPlace.m_Var->m_SetCallback(&(m_EditInPlace.m_String), m_EditInPlace.m_Var->m_ClientData);
7460             else
7461             {
7462                 string *StringPtr = (string *)m_EditInPlace.m_Var->m_Ptr;
7463                 if( StringPtr!=NULL && g_TwMgr->m_CopyStdStringToClient!=NULL )
7464                     g_TwMgr->m_CopyStdStringToClient(*StringPtr, m_EditInPlace.m_String);
7465             }
7466         }
7467         else if( IsCSStringType(m_EditInPlace.m_Var->m_Type) )
7468         {
7469             int n = TW_CSSTRING_SIZE(m_EditInPlace.m_Var->m_Type);
7470             if( n>0 )
7471             {
7472                 if( (int)m_EditInPlace.m_String.length()>n-1 )
7473                     m_EditInPlace.m_String.resize(n-1);
7474                 if( m_EditInPlace.m_Var->m_SetCallback!=NULL )
7475                     m_EditInPlace.m_Var->m_SetCallback(m_EditInPlace.m_String.c_str(), m_EditInPlace.m_Var->m_ClientData);
7476                 else if( m_EditInPlace.m_Var->m_Ptr!=NULL )
7477                 {
7478                     if( n>1 )
7479                         strncpy((char *)m_EditInPlace.m_Var->m_Ptr, m_EditInPlace.m_String.c_str(), n-1);
7480                     ((char *)m_EditInPlace.m_Var->m_Ptr)[n-1] = '\0';
7481                 }
7482             }
7483         }
7484         else
7485         {
7486             double Val = 0, Min = 0, Max = 0, Step = 0;
7487             int n = 0;
7488             if( m_EditInPlace.m_Var->m_Type==TW_TYPE_CHAR )
7489             {
7490                 unsigned char Char = 0;
7491                 n = sscanf(m_EditInPlace.m_String.c_str(), "%c", &Char);
7492                 Val = Char;
7493             }
7494             else
7495                 n = sscanf(m_EditInPlace.m_String.c_str(), "%lf", &Val);
7496             if( n==1 )
7497             {
7498                 m_EditInPlace.m_Var->MinMaxStepToDouble(&Min, &Max, &Step);
7499                 if( Val<Min )
7500                     Val = Min;
7501                 else if( Val>Max )
7502                     Val = Max;
7503                 m_EditInPlace.m_Var->ValueFromDouble(Val);
7504             }
7505         }
7506         if( g_TwMgr!=NULL ) // Mgr might have been destroyed by the client inside a callback call
7507             NotUpToDate();
7508     }
7509     m_EditInPlace.m_Active = false;
7510     m_EditInPlace.m_Var = NULL;
7511 }
7512
7513 bool CTwBar::EditInPlaceKeyPressed(int _Key, int _Modifiers)
7514 {
7515     if( !m_EditInPlace.m_Active )
7516         return false;
7517     bool Handled = true; // if EditInPlace is active, it catches all key events
7518     bool DoCopy = false, DoPaste = false;
7519
7520     switch( _Key )
7521     {
7522     case TW_KEY_ESCAPE:
7523         EditInPlaceEnd(false);
7524         break;
7525     case TW_KEY_RETURN:
7526         EditInPlaceEnd(true);
7527         break;
7528     case TW_KEY_LEFT:
7529         if( _Modifiers==TW_KMOD_SHIFT )
7530             m_EditInPlace.m_CaretPos = max(0, m_EditInPlace.m_CaretPos-1);
7531         else
7532         {
7533             if( m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos )
7534                 m_EditInPlace.m_CaretPos = min(m_EditInPlace.m_SelectionStart, m_EditInPlace.m_CaretPos);
7535             else
7536                 m_EditInPlace.m_CaretPos = max(0, m_EditInPlace.m_CaretPos-1);
7537             m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos;
7538         }
7539         break;
7540     case TW_KEY_RIGHT:
7541         if( _Modifiers==TW_KMOD_SHIFT )
7542             m_EditInPlace.m_CaretPos = min((int)m_EditInPlace.m_String.length(), m_EditInPlace.m_CaretPos+1);
7543         else
7544         {
7545             if( m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos )
7546                 m_EditInPlace.m_CaretPos = max(m_EditInPlace.m_SelectionStart, m_EditInPlace.m_CaretPos);
7547             else
7548                 m_EditInPlace.m_CaretPos = min((int)m_EditInPlace.m_String.length(), m_EditInPlace.m_CaretPos+1);
7549             m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos;
7550         }
7551         break;
7552     case TW_KEY_BACKSPACE:
7553         if( !EditInPlaceIsReadOnly() )
7554         {
7555             if( m_EditInPlace.m_SelectionStart==m_EditInPlace.m_CaretPos )
7556                 m_EditInPlace.m_SelectionStart = max(0, m_EditInPlace.m_CaretPos-1);
7557             EditInPlaceEraseSelect();
7558         }
7559         break;
7560     case TW_KEY_DELETE:
7561         if( !EditInPlaceIsReadOnly() )
7562         {
7563             if( m_EditInPlace.m_SelectionStart==m_EditInPlace.m_CaretPos )
7564                 m_EditInPlace.m_SelectionStart = min(m_EditInPlace.m_CaretPos+1, (int)m_EditInPlace.m_String.length());
7565             EditInPlaceEraseSelect();
7566         }
7567         break;
7568     case TW_KEY_HOME:
7569         m_EditInPlace.m_CaretPos = 0;
7570         if( _Modifiers!=TW_KMOD_SHIFT )
7571             m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos;
7572         break;
7573     case TW_KEY_END:
7574         m_EditInPlace.m_CaretPos = (int)m_EditInPlace.m_String.length();
7575         if( _Modifiers!=TW_KMOD_SHIFT )
7576             m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos;
7577         break;
7578     case TW_KEY_INSERT:
7579         if( _Modifiers==TW_KMOD_CTRL )
7580             DoCopy = true;
7581         else if( _Modifiers==TW_KMOD_SHIFT )
7582             DoPaste = true;
7583         break;
7584     default:
7585         if( _Modifiers==TW_KMOD_CTRL )
7586         {
7587             if( _Key=='c' || _Key=='C' )
7588                 DoCopy = true;
7589             else if( _Key=='v' || _Key=='V' )
7590                 DoPaste = true;
7591         }
7592         else if( _Key>=32 && _Key<=255 )
7593         {
7594             if( !EditInPlaceIsReadOnly() && m_EditInPlace.m_CaretPos>=0 && m_EditInPlace.m_CaretPos<=(int)m_EditInPlace.m_String.length() )
7595             {
7596                 if( m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos )
7597                     EditInPlaceEraseSelect();
7598                 string Str(1, (char)_Key);
7599                 m_EditInPlace.m_String.insert(m_EditInPlace.m_CaretPos, Str);
7600                 ++m_EditInPlace.m_CaretPos;
7601                 m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos;
7602             }
7603         }
7604     }
7605
7606     if( DoPaste && !EditInPlaceIsReadOnly() )
7607     {
7608         if( m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos )
7609             EditInPlaceEraseSelect();
7610         string Str = "";
7611         if( EditInPlaceGetClipboard(&Str) && Str.length()>0 )
7612         {
7613             m_EditInPlace.m_String.insert(m_EditInPlace.m_CaretPos, Str);
7614             m_EditInPlace.m_CaretPos += (int)Str.length();
7615             m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos;
7616         }
7617     }
7618     if( DoCopy )
7619     {
7620         string Str = "";
7621         if( m_EditInPlace.m_CaretPos>m_EditInPlace.m_SelectionStart )
7622             Str = m_EditInPlace.m_String.substr(m_EditInPlace.m_SelectionStart, m_EditInPlace.m_CaretPos-m_EditInPlace.m_SelectionStart);
7623         else if( m_EditInPlace.m_CaretPos<m_EditInPlace.m_SelectionStart )
7624             Str = m_EditInPlace.m_String.substr(m_EditInPlace.m_CaretPos, m_EditInPlace.m_SelectionStart-m_EditInPlace.m_CaretPos);
7625         EditInPlaceSetClipboard(Str);
7626     }
7627
7628     return Handled;
7629 }
7630
7631
7632 bool CTwBar::EditInPlaceEraseSelect()
7633 {
7634     assert(m_EditInPlace.m_Active);
7635     if( !EditInPlaceIsReadOnly() && m_EditInPlace.m_SelectionStart!=m_EditInPlace.m_CaretPos )
7636     {
7637         int PosMin = min( m_EditInPlace.m_CaretPos, m_EditInPlace.m_SelectionStart );
7638         m_EditInPlace.m_String.erase( PosMin, abs(m_EditInPlace.m_CaretPos - m_EditInPlace.m_SelectionStart) );
7639         m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos = PosMin;
7640         if( m_EditInPlace.m_FirstChar>PosMin )
7641             m_EditInPlace.m_FirstChar = PosMin;
7642         return true;
7643     }
7644     else
7645         return false;
7646 }
7647
7648
7649 bool CTwBar::EditInPlaceMouseMove(int _X, int _Y, bool _Select)
7650 {
7651     if ( !m_EditInPlace.m_Active || _Y<m_PosY+m_EditInPlace.m_Y || _Y>m_PosY+m_EditInPlace.m_Y+m_Font->m_CharHeight )
7652         return false;
7653
7654     int i, CaretX = m_PosX+m_EditInPlace.m_X;
7655     for( i=m_EditInPlace.m_FirstChar; i<(int)m_EditInPlace.m_String.length() && CaretX<m_PosX+m_EditInPlace.m_X+m_EditInPlace.m_Width; ++i )
7656     {
7657         unsigned char u = m_EditInPlace.m_String.c_str()[i];
7658         int CharWidth = m_Font->m_CharWidth[u];
7659         if( _X < CaretX + CharWidth / 2 )
7660             break;
7661         CaretX += CharWidth;
7662     }
7663     if( CaretX>=m_PosX+m_EditInPlace.m_X+m_EditInPlace.m_Width )
7664         i = max(0, i-1);
7665
7666     m_EditInPlace.m_CaretPos = i;
7667     if( !_Select )
7668         m_EditInPlace.m_SelectionStart = m_EditInPlace.m_CaretPos;
7669     return true;
7670 }
7671
7672
7673 bool CTwBar::EditInPlaceGetClipboard(std::string *_OutString)
7674 {
7675     assert( _OutString!=NULL );
7676     *_OutString = m_EditInPlace.m_Clipboard; // default implementation
7677
7678 #if defined ANT_WINDOWS
7679
7680     if( !IsClipboardFormatAvailable(CF_TEXT) )
7681         return false;
7682     if( !OpenClipboard(NULL) )
7683         return false;
7684     HGLOBAL TextHandle = GetClipboardData(CF_TEXT); 
7685     if( TextHandle!=NULL ) 
7686     { 
7687         const char *TextString = static_cast<char *>(GlobalLock(TextHandle));
7688         if( TextHandle!=NULL )
7689         {
7690             *_OutString = TextString;
7691             GlobalUnlock(TextHandle);
7692         } 
7693     }
7694     CloseClipboard(); 
7695
7696 #elif defined ANT_UNIX
7697
7698     if( g_TwMgr->m_CurrentXDisplay!=NULL )
7699     {
7700         int NbBytes = 0;
7701         char *Buffer = XFetchBytes(g_TwMgr->m_CurrentXDisplay, &NbBytes);
7702         if( Buffer!=NULL )
7703         {
7704             if( NbBytes>0 )
7705             {
7706                 char *Text = new char[NbBytes+1];
7707                 memcpy(Text, Buffer, NbBytes);
7708                 Text[NbBytes] = '\0';
7709                 *_OutString = Text;
7710                 delete[] Text;
7711             }
7712             XFree(Buffer);
7713         }
7714     }
7715
7716 #endif
7717
7718     return true;
7719 }
7720
7721
7722 bool CTwBar::EditInPlaceSetClipboard(const std::string& _String)
7723 {
7724     if( _String.length()<=0 )
7725         return false;   // keep last clipboard
7726     m_EditInPlace.m_Clipboard = _String; // default implementation
7727
7728 #if defined ANT_WINDOWS
7729
7730     if( !OpenClipboard(NULL) )
7731         return false;
7732     EmptyClipboard();
7733     HGLOBAL TextHandle = GlobalAlloc(GMEM_MOVEABLE, _String.length()+1);
7734     if( TextHandle==NULL )
7735     { 
7736         CloseClipboard(); 
7737         return false; 
7738     }
7739     char *TextString = static_cast<char *>(GlobalLock(TextHandle));
7740     memcpy(TextString, _String.c_str(), _String.length());
7741     TextString[_String.length()] = '\0';
7742     GlobalUnlock(TextHandle); 
7743     SetClipboardData(CF_TEXT, TextHandle);
7744     CloseClipboard();
7745
7746 #elif defined ANT_UNIX
7747
7748     if( g_TwMgr->m_CurrentXDisplay!=NULL )
7749     {
7750         XSetSelectionOwner(g_TwMgr->m_CurrentXDisplay, XA_PRIMARY, None, CurrentTime);
7751         char *Text = new char[_String.length()+1];
7752         memcpy(Text, _String.c_str(), _String.length());
7753         Text[_String.length()] = '\0';
7754         XStoreBytes(g_TwMgr->m_CurrentXDisplay, Text, _String.length());
7755         delete[] Text;
7756     }
7757
7758 #endif
7759
7760     return true;
7761 }
7762
7763
7764 //  ---------------------------------------------------------------------------
7765
7766