gui.temp.h

00001 
00095 #include "ctl/ctldef.h"
00096 #include "ctl/mstime.h"
00097 
00098 #ifndef OPC_H
00099 #include "opc.h"
00100 #endif
00101 
00102 #ifndef GUI_H
00103 #include "gui.h"
00104 #endif
00105 
00106 #if ( !defined(GUI_SELECT) || !defined(GUI_GetKeyPress) || !defined(GUI_ClearKeyPress) )
00107 #error The GUI_GetKeyPress macro and GUI_SELECT must be defined for GUI to know how to tab and select.
00108 #endif
00109 
00110 #if !defined(GUI_GetPointer) && !defined(GUI_TABLEFT) && !defined(GUI_TABRIGHT) && !defined(GUI_TABUP) && !defined(GUI_TABDOWN) && !defined(GUI_TAB) && !defined(GUI_TABBACK)
00111 #error Without a pointer, tabbing must be defined for GUI_getkeybits.  As a minimum, one tab and one select.
00112 #endif
00113 
00114 #if !defined(GUI_PICK)
00115 #define GUI_PICK GUI_SELECT
00116 #endif
00117 
00118 #if !defined(GUI_MSTime)
00119 #error No realtime function defined
00120 #endif
00121 
00122 #if !defined(GUI_RepeatPause)
00123 #define GUI_RepeatPause(rate)   132
00124 #endif
00125 
00126 #if !defined(GUI_DefaultRepeat)
00127 #define GUI_DefaultRepeat       66
00128 #endif
00129 
00130 #ifndef GUI_Tabsound
00131 #define GUI_Tabsound()
00132 #endif
00133 
00134 #ifndef GUI_SelectSound
00135 #define GUI_SelectSound()
00136 #endif
00137 
00138 #ifndef GUI_CheckSound
00139 #define GUI_CheckSound()
00140 #endif
00141 
00142 #ifndef GUI_UncheckSound
00143 #define GUI_UncheckSound()
00144 #endif
00145 
00146 #ifndef GUI_ScrollSound
00147 #define GUI_ScrollSound()
00148 #endif
00149 
00150 #ifndef GUI_Font
00151 #define GUI_Font( font )    (font)
00152 #endif
00153 
00154 #ifndef GUI_Random
00155 #include <stdlib.h>
00156 #define GUI_Random() rand()
00157 #define GUI_RAND_MAX RAND_MAX
00158 #endif
00159 
00160 #ifndef GUI_DrawText
00161 #define GUI_ONELINE 0   
00162 #define GUI_LEFT    0   
00163 #define GUI_CENTER  1   
00164 #define GUI_RIGHT   2   
00165 #define GUI_TOP     0   
00166 #define GUI_VCENTER 4   
00167 #define GUI_BOTTOM  8   
00177 #define GUI_DrawText( opc, prcBounds, flags, sz, count )
00178 
00186 #define GUI_MeasureText( prcBounds, flags, sz, count )
00187 
00188 #elif !defined(GUI_MeasureText)
00189 #error GUI_MeasureText is required if you define GUI_DrawText
00190 #endif
00191 
00197 bool GUI_tableft( GUI* gui )
00198 {
00199     int tabPrev = gui->focus < 0 ? 0 : gui->focus;
00200     bool bWrap = false;
00201     unsigned mask;
00202     int tab = -1;
00203     const GUI_Control* control = GUI_Control_Get( gui, tabPrev );
00204     /* Convert control index to htab index */
00205     pointer_foreach_const(GUI_Control* const,gui->htab,gui->cControl, curr )
00206     {
00207         if( *curr == control )
00208         {
00209             tab = tabPrev = (int)(curr - gui->htab);
00210             break;
00211         }
00212     }
00213     /* We should have found the value */
00214     assert( tab != -1 );
00215     /* Search htab for control */
00216     do
00217     {
00218         if( --tab < 0 )
00219         {
00220             tab = gui->cControl-1;
00221             bWrap = true;
00222         }
00223         control = gui->htab[tab];
00224         mask = GUI_Control_Mask( gui, control );
00225         if( !(mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) )
00226             break;
00227     }
00228     while( tab != tabPrev );
00229     /* Convert htab index to control index */
00230     if( tab != tabPrev )
00231         _GUI_SetFocus( gui, (int)(control-gui->list) );
00232     return bWrap;
00233 }
00234 
00240 bool GUI_tabright( GUI* gui )
00241 {
00242     int tabPrev = gui->focus < 0 ? 0 : gui->focus;
00243     bool bWrap = false;
00244     unsigned mask;
00245     int tab = -1;
00246     const GUI_Control* control = GUI_Control_Get( gui, tabPrev );
00247     /* Convert control index to htab index */
00248     pointer_foreach_const(GUI_Control* const,gui->htab,gui->cControl, curr )
00249     {
00250         if( *curr == control )
00251         {
00252             tab = tabPrev = (int)(curr - gui->htab);
00253             break;
00254         }
00255     }
00256     /* We should have found the value */
00257     assert( tab != -1 );
00258     /* Search htab for control */
00259     do
00260     {
00261         if( ++tab >= gui->cControl )
00262         {
00263             tab = 0;
00264             bWrap = true;
00265         }
00266         control = gui->htab[tab];
00267         mask = GUI_Control_Mask( gui, control );
00268         if( !(mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) )
00269             break;
00270     }
00271     while( tab != tabPrev );
00272     /* Convert htab index to control index */
00273     if( tab != tabPrev )
00274         _GUI_SetFocus( gui, (int)(control-gui->list) );
00275     return bWrap;
00276 }
00277 
00283 bool GUI_tabup( GUI* gui )
00284 {
00285     int tabPrev = gui->focus < 0 ? 0 : gui->focus;
00286     bool bWrap = false;
00287     unsigned mask;
00288     int tab = -1;
00289     const GUI_Control* control = GUI_Control_Get( gui, tabPrev );
00290     /* Convert control index to vtab index */
00291     pointer_foreach_const(GUI_Control* const,gui->vtab,gui->cControl, curr )
00292     {
00293         if( *curr == control )
00294         {
00295             tab = tabPrev = (int)(curr - gui->vtab);
00296             break;
00297         }
00298     }
00299     /* We should have found the value */
00300     assert( tab != -1 );
00301     /* Search vtab for control */
00302     do
00303     {
00304         if( --tab < 0 )
00305         {
00306             tab = gui->cControl-1;
00307             bWrap = true;
00308         }
00309         control = gui->vtab[tab];
00310         mask = GUI_Control_Mask( gui, control );
00311         if( !(mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) )
00312             break;
00313     }
00314     while( tab != tabPrev );
00315     /* Convert vtab index to control index */
00316     if( tab != tabPrev )
00317         _GUI_SetFocus( gui, (int)(control-gui->list) );
00318     return bWrap;
00319 }
00320 
00326 bool GUI_tabdown( GUI* gui )
00327 {
00328     int tabPrev = gui->focus < 0 ? 0 : gui->focus;
00329     bool bWrap = false;
00330     unsigned mask;
00331     int tab = -1;
00332     const GUI_Control* control = GUI_Control_Get( gui, tabPrev );
00333     /* Convert control index to vtab index */
00334     pointer_foreach_const(GUI_Control* const,gui->vtab,gui->cControl, curr )
00335     {
00336         if( *curr == control )
00337         {
00338             tab = tabPrev = (int)(curr - gui->vtab);
00339             break;
00340         }
00341     }
00342     /* We should have found the value */
00343     assert( tab != -1 );
00344     /* Search vtab for control */
00345     do
00346     {
00347         if( ++tab >= gui->cControl )
00348         {
00349             tab = 0;
00350             bWrap = true;
00351         }
00352         control = gui->vtab[tab];
00353         mask = GUI_Control_Mask( gui, control );
00354         if( !(mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) )
00355             break;
00356     }
00357     while( tab != tabPrev );
00358     /* Convert vtab index to control index */
00359     if( tab != tabPrev )
00360         _GUI_SetFocus( gui, (int)(control-gui->list) );
00361     return bWrap;
00362 }
00363 
00364 #if ( defined(GUI_TABLEFT) || defined(GUI_TABRIGHT) || defined(GUI_TABUP) || defined(GUI_TABDOWN) || defined(GUI_TAB) || defined(GUI_TABBACK) )
00365 
00370 bool GUI_tabhandler( struct GUI* gui )
00371 {
00372     unsigned keypress = GUI_GetKeyPress();
00373     int prev = gui->focus;
00374     if( !keypress )
00375         return false;
00376 #if defined(GUI_TABLEFT)
00377     else if( keypress == GUI_TABLEFT
00378 #if defined(GUI_TABBACK)
00379         || keypress == GUI_TABBACK
00380 #endif
00381         )
00382     {
00383         /* If focus wrapped and we have a parent, do focus for parent */
00384         if( GUI_tableft( gui ) && gui->parent && !GUI_tableft( gui->parent ) )
00385         {
00386             gui->focus = -1;
00387         }
00388         else
00389         {
00390             GUI_ClearKeyPress();
00391         }
00392     }
00393 #endif
00394 #if defined(GUI_TABRIGHT)
00395     else if( keypress == GUI_TABRIGHT
00396 #if defined(GUI_TAB)
00397         || keypress == GUI_TAB
00398 #endif
00399         )
00400     {
00401         if( GUI_tabright( gui ) && gui->parent && !GUI_tabright( gui->parent ) )
00402         {
00403             gui->focus = -1;
00404         }
00405         else
00406         {
00407             GUI_ClearKeyPress();
00408         }
00409     }
00410 #endif
00411 #if defined(GUI_TABUP)
00412     else if( keypress == GUI_TABUP)
00413     {
00414         if( GUI_tabup( gui ) && gui->parent && !GUI_tabup( gui->parent ) )
00415         {
00416             gui->focus = -1;
00417         }
00418         else
00419         {
00420             GUI_ClearKeyPress();
00421         }
00422     }
00423 #endif
00424 #if defined(GUI_TABDOWN)
00425     else if( keypress == GUI_TABDOWN)
00426     {
00427         if( GUI_tabdown( gui ) && gui->parent && !GUI_tabdown( gui->parent ) )
00428         {
00429             gui->focus = -1;
00430         }
00431         else
00432         {
00433             GUI_ClearKeyPress();
00434         }
00435     }
00436 #endif
00437     if( gui->focus != prev )
00438     {
00439         GUI_Tabsound();
00440         return true;
00441     }
00442     return false;
00443 }
00444 #endif
00445 
00447 void _GUI_Dirty_Rect( GUI* gui, const Rect* prc )
00448 {
00449 #ifdef SIMPLE_DIRTY
00450     RectUnionRect( gui->dirty, *prc )
00451 #else
00452     /* Assert: There should be a dirty rectangle list */
00453     assert( gui->cdirty );
00454     /* 
00455      * Assert: We shouldn't be adding to dirty list while traversing it. 
00456      * It leads to hard to track down graphical glitches.
00457      */
00458     assert( !(gui->mask & GUIM_INPAINT) );
00459     ClipRect_add( gui->cdirty, prc );
00460 #endif
00461 }
00462 
00470 bool GUI_Control_Paint( const struct GUI* gui, const GUI_Control* control, OPC* opc )
00471 {
00472     GUI_Control_State* state = GUI_Control_Data( gui, control );
00473     if( state->mask & GUICS_INVISIBLE )
00474     {
00475         return false;
00476     }
00477     else
00478     {
00479         Rect bound;
00480         GUI_Control_Bound( gui, control, &bound );
00481         /* Just take intersection of dirty region and this control, and paint that */
00482         RectIntRect( bound, gui->dirty );
00483         if( RectEmpty( bound ) )
00484             return false;
00485         OPC_NAMING(Clip)( opc, &gui->opc, &bound );
00486     }
00487     return true;
00488 }
00489 
00495 bool _GUI_IsOpen( GUI* gui )
00496 {
00497     return gui && (gui->mask & GUIM_ALIVE);
00498 }
00499 
00506 int _GUI_SetFocus( GUI* gui, int ifocus )
00507 {
00508     int focusPrev;
00509     assert(gui);
00510     focusPrev = gui->focus;
00511     gui->focus = ifocus;
00512     if( gui->focus >= 0 && gui->focus < gui->cControl )
00513     {
00514         if( GUI_Control_IsFocused( gui, gui->list + gui->focus ) )
00515         {
00516             if( focusPrev != gui->focus )
00517             {
00518                 GUI_Control_Dirty( gui, gui->list + gui->focus );
00519                 gui->mask |= GUIM_FOCUSCHANGED;
00520             }
00521         }
00522         else
00523             GUI_tabright( gui );
00524     }
00525     if( focusPrev != gui->focus )
00526     {
00527         if( focusPrev >= 0 && focusPrev < gui->cControl )
00528         {
00529             GUI_Control_Dirty( gui, gui->list + focusPrev );
00530             gui->mask |= GUIM_FOCUSCHANGED;
00531         }
00532     }
00533     return focusPrev;
00534 }
00535 
00540 void _GUI_CallNotifies( GUI* gui )
00541 {
00542     /* Now deliver any notifications that were raised */
00543     assert(gui);
00544     for( gui->iControl = 0; gui->iControl < gui->cControl; ++gui->iControl )
00545     {
00546         GUI_Control_State* data = GUI_Control_Get_Data( gui, gui->iControl );
00547         if( data->mask & GUICS_NOTIFY )
00548         {
00549             gui->handler(gui, GUI_Notify);
00550             data->mask &= ~GUICS_NOTIFY;
00551         }
00552     }
00553 }
00554 
00559 void _GUI_Heartbeat( GUI* gui )
00560 {
00561     /*
00562      * When layering multiple GUIs...
00563      * 1. Cycle all GUIs.
00564      * 2. Do any focus-change notifications
00565      * 3. Accumulate 'dirty' regions and make all GUI dirty regions the same
00566      * 4. Paint all GUIs
00567      * 5. Invoke notifies
00568      */
00569     assert(gui);
00570     if( GUI_IsOpen( gui ) )
00571         gui->handler( gui, GUI_Cycle );
00572     if( GUI_IsOpen( gui ) && (gui->mask & GUIM_FOCUSCHANGED) )
00573     {
00574         gui->mask &= ~GUIM_FOCUSCHANGED;
00575         gui->handler( gui, GUI_Focus );
00576     }
00577     if( GUI_IsOpen( gui ) )
00578     {
00579         gui->handler( gui, GUI_Paint );
00580 #ifndef SIMPLE_DIRTY
00581         ClipRect_clear( gui->cdirty );
00582 #endif
00583         _GUI_CallNotifies( gui );
00584     }
00585 }
00586 
00587 
00588 bool _GUI_Control_IsFocused( const GUI* gui, const GUI_Control* control )
00589 {
00590     return (gui->list + gui->focus) == control && !(GUI_Control_Mask( gui, control ) & (GUICS_INVISIBLE|GUICS_NOFOCUS));
00591 }
00592 
00593 bool _GUI_Control_IsHidden( const GUI* gui, int index ) 
00594 {
00595     return 0 != (GUI_Control_Data( gui, GUI_Control_Get( gui, index ) )->mask & GUICS_INVISIBLE);
00596 }
00597 
00598 void _GUI_Control_Hide( GUI* gui, int index )
00599 {
00600     if( !GUI_Control_IsHidden( gui, index ) )
00601     {
00602         if( gui->focus == index )
00603             GUI_tabright( gui );
00604         GUI_Control_Set_Dirty( gui, index );
00605         GUI_Control_Data( gui, GUI_Control_Get( gui, index ) )->mask |= GUICS_INVISIBLE;
00606     }
00607 }
00608 
00609 void _GUI_Control_Show( GUI* gui, int index )
00610 {
00611     if( GUI_Control_IsHidden( gui, index ) )
00612     {
00613         GUI_Control_Data( gui, GUI_Control_Get( gui, index ) )->mask &= ~GUICS_INVISIBLE;
00614         GUI_Control_Set_Dirty( gui, index );
00615         if( gui->focus == index )
00616             GUI_tabright( gui );
00617     }
00618 }
00619 
00620 bool _GUI_Control_IsDisabled( const GUI* gui, int index )   
00621 {
00622     return 0 != (GUI_Control_Data( gui, GUI_Control_Get( gui, index ) )->mask & GUICS_NOFOCUS);
00623 }
00624 void _GUI_Control_Enable( GUI* gui, int index )
00625 {
00626     if( GUI_Control_IsDisabled( gui, index ) )
00627     {
00628         GUI_Control_Data( gui, GUI_Control_Get( gui, index ) )->mask &= ~GUICS_NOFOCUS;
00629         GUI_Control_Set_Dirty( gui, index );
00630         if( gui->focus == index )
00631             GUI_tabright( gui );
00632     }
00633 }
00634 void _GUI_Control_Disable( GUI* gui, int index )
00635 {
00636     if( !GUI_Control_IsDisabled( gui, index ) )
00637     {
00638         if( gui->focus == index )
00639             GUI_tabright( gui );
00640         GUI_Control_Data( gui, GUI_Control_Get( gui, index ) )->mask |= GUICS_NOFOCUS;
00641         GUI_Control_Set_Dirty( gui, index );
00642     }
00643 }
00644 
00645 
00659 bool _GUI_Explode_Set( GUI* gui, int times, int divide, int first, int last )
00660 {
00661     bool alldone = true;
00662     assertobjptr(gui);
00663     assert( first >= 0 && first < gui->cControl );
00664     assert( last >= first && last < gui->cControl );
00665     {
00666         pointer_foreach_const( GUI_Control, gui->list+first, (1+last-first), control )
00667         {
00668             GUI_Control_State* state = GUI_Control_Data( gui, control );
00669             if( state->offx || state->offy )
00670             {
00671                 Rect bound;
00672                 GUI_Control_Bound( gui, control, &bound );
00673                 if( 
00674                     (( times > divide ) && !RectOutside(bound,gui->opc.clip)) ||
00675                     (( times < divide ) && (state->offx || state->offy) ) )
00676                 {
00677                     GUI_Control_Dirty( gui, control );
00678                     state->offx = (int16)(state->offx * times / divide);
00679                     state->offy = (int16)(state->offy * times / divide);
00680                     GUI_Control_Dirty( gui, control );
00681                     alldone = false;
00682                 }
00683             }
00684         }
00685     }
00686     return alldone;
00687 }
00688 bool _GUI_Explode( GUI* gui, int times, int divide )
00689 {
00690     return _GUI_Explode_Set( gui, times, divide, 0, gui->cControl-1 );
00691 }
00692 
00704 void _GUI_Sweep_Set( GUI* gui, int x, int y, int times, int divide, int from, int to )
00705 {
00706     assertobjptr(gui);
00707     assert( from >= 0 && from < gui->cControl );
00708     assert( to >= from && to < gui->cControl );
00709     {
00710         pointer_foreach_const( GUI_Control, gui->list + from, 1+to-from, control )
00711         {
00712             _GUI_Offset_Control( gui, control, x, y );
00713             x = x * times / divide;
00714             y = y * times / divide;
00715         }
00716     }
00717 }
00718 void _GUI_Sweep( GUI* gui, int x, int y, int times, int divide )
00719 {
00720     _GUI_Sweep_Set( gui, x,y, times, divide, 0, gui->cControl-1 );
00721 }
00722 
00731 void _GUI_Offset_Group( GUI* gui, int from, int to, int x, int y )
00732 {
00733     assert( from >= 0 && from < gui->cControl );
00734     assert( to >= from && to < gui->cControl );
00735     {
00736         pointer_foreach_const( GUI_Control, gui->list + from, 1+to-from, control )
00737             _GUI_Offset_Control( gui, control, x, y );
00738     }
00739 }
00740 
00748 void _GUI_Offset_Control( GUI* gui, const GUI_Control* control, int x, int y )
00749 {
00750     GUI_Control_State* state = GUI_Control_Data( gui, control );
00751     GUI_Control_Dirty( gui, control );
00752     state->offx = (int16)x;
00753     state->offy = (int16)y;
00754     GUI_Control_Dirty( gui, control );
00755 }
00756 
00763 void _GUI_Control_Set_Offset( GUI* gui, int index, int px, int py )
00764 {
00765     const GUI_Control* control = GUI_Control_Get( gui, index );
00766     GUI_Control_State* state = GUI_Control_Data( gui, control );
00767     GUI_Control_Dirty( gui, control );
00768     state->offx = (int16)px;
00769     state->offy = (int16)py;
00770     GUI_Control_Dirty( gui, control );
00771 }
00772 
00779 void _GUI_Move( GUI* gui, int x, int y )
00780 { 
00781     if( gui->offx != x || gui->offy != y )
00782     {
00783         gui->offx = x; 
00784         gui->offy = y; 
00785         GUI_Dirty_Rect( gui, &gui->opc.clip ); 
00786     }
00787 }
00788 
00789 
00796 bool _GUI_Motion( GUI* gui, int tx, int ty )
00797 {
00798     if( gui->offx == tx && gui->offy == ty )
00799         return true;
00800     GUI_Dirty( gui );
00801     gui->offx = (tx + gui->offx) / 2;
00802     gui->offy = (ty + gui->offy) / 2;
00803     if( abs(gui->offx - tx) <= 8 && abs(gui->offy - ty) <= 8 )
00804     {
00805         gui->offx = tx;
00806         gui->offy = ty;
00807     }
00808     GUI_Dirty( gui );
00809     return false;
00810 }
00811 
00812 #ifndef NDEBUG
00813 
00818 const GUI_Control* _GUI_Control_Get( const GUI* gui, int index )
00819 {
00820     /* Assert we're looking at a valid index */
00821     assertobjptr(gui);
00822     assert( index >= 0 && index < gui->cControl );
00823     return gui->list + index;
00824 }
00825 
00831 GUI_Control_State* _GUI_Control_Data( const GUI* gui, const GUI_Control* control )
00832 {
00833     assertobjptr(gui);
00834     assertobjptr(control);
00835     /* The control data shouldn't be inside GUI base record */
00836     assert( control->offData >= sizeof(GUI) );
00837     return (GUI_Control_State*)((uint8*)gui + control->offData);
00838 }
00839 
00840 #endif
00841 
00849 void GUI_Def_State( GUI* gui, const GUI_Control* control, unsigned initmask, unsigned align )
00850 {
00851     GUI_Control_State* state = GUI_Control_Data( gui, control );
00852     state->mask = initmask;
00853     state->offx = state->offy = 0;
00854     state->text = NULL;
00855     state->align = align;
00856     state->frames = control->state;
00857     state->cFrames = control->cState;
00858 }
00859 
00867 void _GUI_Control_SetFrames( GUI* gui, int index, const OPCShape* const* frames, size_t cFrames )
00868 {
00869     GUI_Control_State* state = (GUI_Control_State*)GUI_Control_Get_Data( gui, index ); 
00870     state->frames = frames;
00871     state->cFrames = cFrames;
00872     GUI_Control_Set_Dirty( gui,index ); 
00873 }
00874 
00881 void _GUI_Control_SetText( GUI* gui, int index, const GUI_CHAR* szText)
00882 { 
00883     GUI_Control_Get_Data( gui,index )->text = szText; 
00884     GUI_Control_Set_Dirty( gui,index ); 
00885 }
00886 
00893 void _GUI_Control_SetJustify( GUI* gui, int index, unsigned just )
00894 {
00895     GUI_Control_Get_Data( gui,index )->align = just; 
00896     GUI_Control_Set_Dirty( gui,index );
00897 }
00898 
00906 void _GUI_Control_SetupText( GUI* gui, int index, const GUI_CHAR* szText, unsigned just )
00907 { 
00908     GUI_Control_State* state = (GUI_Control_State*)GUI_Control_Get_Data( gui, index ); 
00909     state->text = szText; 
00910     state->align = just;
00911     GUI_Control_Set_Dirty( gui, index ); 
00912 }
00913 
00919 void _GUI_Control_Dirty( GUI* gui, const GUI_Control* control )
00920 {
00921     GUI_Control_State* state = GUI_Control_Data( gui, control );
00922     if( !(state->mask & GUICS_INVISIBLE) )
00923     {
00924         Rect bound = (control)->bound;
00925         RectMoveBy(bound,gui->offx+state->offx,gui->offy+state->offy);
00926         GUI_Dirty_Rect( gui, &bound );
00927     }
00928 }
00929 
00936 void _GUI_Control_Bound( GUI* gui, const GUI_Control* control, Rect* bound )
00937 {
00938     GUI_Control_State* state = GUI_Control_Data( gui, control );
00939     *bound = (control)->bound;
00940     RectMoveBy(*bound,gui->offx+state->offx,gui->offy+state->offy);
00941 }
00942 
00943 
00944 
00945 
00946 /* Certain controls are pseudo-controls */
00947 #define GUI_Ctrl_ArtResource    GUI_Ctrl_Invalid
00948 #define GUI_Ctrl_PaletteData    GUI_Ctrl_Invalid
00949 #define GUI_Ctrl_Background     GUI_Ctrl_Invalid
00950 #define GUI_Ctrl_Overlay        GUI_Ctrl_Invalid
00951 
00952 
00953 #define XENUM(tag,verbose,data) static void GUI_Ctrl_##verbose( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg );
00954 EDEF_HANDLERS(XENUM)
00955 #undef XENUM
00956 #define XENUM(tag,verbose,data) GUI_Ctrl_##verbose,
00957 static const GUI_Ctrl_handler lutHandlers[] =
00958 {
00959     EDEF_HANDLERS(XENUM)
00960 };
00961 #undef XENUM
00962 
00970 void GUI_Control_handle( struct GUI* gui, const GUI_Control* control, GUI_Message msg )
00971 {
00972     assertobjptr(gui);
00973     assertobjptr(control);
00974     {
00975         GUIHandlers index = control->type;
00976         assert( index >= 0 && index < GUIHandlers_COUNT );
00977         lutHandlers[index]( gui, control, msg );
00978     }
00979 }
00980 
00984 void GUI_Ctrl_Invalid( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
00985 {
00986 }
00987 
00991 void GUI_Ctrl_StaticFrame( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
00992 {
00993     switch( msg )
00994     {
00995     case GUI_Paint:
00996         {
00997             GUI_Control_State* state = GUI_Control_Data( gui, control );
00998             OPC opc;
00999             if( ((state->frames && state->cFrames) || (state->text && *state->text)) && GUI_Control_Paint( gui, control, &opc ) )
01000             {
01001                 Rect bound;
01002                 GUI_Control_Bound( gui, control, &bound );
01003                 if( state->frames && state->cFrames )
01004                 {
01005                     OPC_NAMING(Shape)( &opc, *state->frames, bound.left, bound.top );
01006                 }
01007                 if( state->text && *state->text )
01008                 {
01009                     /* Draw any text that goes with the button */
01010                     GUI_DrawText( &opc, &bound, state->align, state->text, ~0u );
01011                 }
01012             }
01013         }
01014         break;
01015     case GUI_Init:
01016         GUI_Def_State(gui,control,GUICS_NOFOCUS,GUI_CENTER|GUI_VCENTER);
01017         return;
01018 
01019     default:
01020         break;
01021     }
01022 }
01023 
01027 void GUI_Ctrl_Button( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
01028 {
01029     switch( msg )
01030     {
01031     case GUI_Cycle:
01032         {
01033             /* Handle keys/events */
01034             GUI_Button_State* state = (GUI_Button_State*)GUI_Control_Data( gui, control );
01035             if( !state->basic.frames )
01036             {
01037                 if( GUI_Control_IsFocused( gui, control ) )
01038                     GUI_tabright(gui);
01039                 return;
01040             }
01041             if( GUI_Control_IsFocused( gui, control ) )
01042             {
01043                 #if ( defined(GUI_TABLEFT) || defined(GUI_TABRIGHT) || defined(GUI_TABUP) || defined(GUI_TABDOWN) )
01044                 if( GUI_tabhandler( gui ) )
01045                 {
01046                     state->tracking = guibs_Neutral;
01047                     return;
01048                 }
01049                 #endif
01050                 switch( state->tracking )
01051                 {
01052                 default:
01053                 case guibs_Neutral:
01054                     /* We're waiting for focus */
01055                     state->tracking = guibs_Focus;
01056                     GUI_Control_Dirty( gui, control );
01057                     /* Fall-through now that we're focused */
01058                 case guibs_Focus:
01059                     /* We have focus */
01060 #if defined(GUI_GetPointer)
01061                     if( GUI_GetKeyPress() & GUI_PICK )
01062                     {
01063                         int x,y;
01064                         Rect bound;
01065                         GUI_Control_Bound( gui, control, &bound );
01066                         GUI_GetPointer(x,y);
01067                         if( !RectPtInRect(bound,x,y) )
01068                         {
01069                             break;
01070                         }
01071                     }
01072 #endif
01073 #ifdef GUI_GetKeyHeld
01074                     if( GUI_GetKeyPress() & (GUI_SELECT|GUI_PICK) )
01075                     {
01076                         if( state->basic.frames[guibs_Selected] )
01077                         {
01078                             state->tracking = guibs_Selected;
01079                             GUI_ClearKeyPress();
01080                             GUI_Control_Dirty( gui, control );
01081                             break;
01082                         }
01083 #endif
01084                         state->tracking = guibs_Focus;
01085                         GUI_Control_Dirty( gui, control );
01086                         GUI_SelectSound();
01087                         GUI_Control_Notify( gui, control );
01088                     }
01089                     break;
01090 
01091                 case guibs_Selected:
01092 #ifdef GUI_GetKeyHeld
01093 #if defined(GUI_GetPointer)
01094                     if( GUI_GetKeyHeld() == GUI_PICK )
01095                     {
01096                         int x,y;
01097                         Rect bound;
01098                         GUI_Control_Bound( gui, control, &bound );
01099                         GUI_GetPointer(x,y);
01100                         if( !RectPtInRect(bound,x,y) )
01101                         {
01102                             state->tracking = guibs_Focus;
01103                             GUI_Control_Dirty( gui, control );
01104                             break;
01105                         }
01106                     }
01107 #endif
01108                     if( (GUI_GetKeyHeld() & (GUI_SELECT|GUI_PICK)) )
01109                         break;
01110 #endif
01111                     state->tracking = guibs_Focus;
01112                     GUI_Control_Dirty( gui, control );
01113                     GUI_SelectSound();
01114                     GUI_Control_Notify( gui, control );
01115                     break;
01116                 }
01117             }
01118             else
01119             {
01120                 if( state->tracking != guibs_Neutral )
01121                 {
01122                     state->tracking = guibs_Neutral;
01123                     GUI_Control_Dirty( gui, control );
01124                 }
01125             }
01126         }
01127         break;
01128     case GUI_Paint:
01129         {
01130             GUI_Button_State* state = (GUI_Button_State*)GUI_Control_Data( gui, control );
01131             OPC opc;
01132             if( state->basic.frames && GUI_Control_Paint( gui, control, &opc ) )
01133             {
01134                 Rect bound;
01135                 GUI_Control_Bound( gui, control, &bound );
01136                 /* Draw bottom focus, if present */
01137                 if( GUI_Control_IsFocused( gui, control ) )
01138                     OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_FocusUnder], bound.left,bound.top );
01139                 switch( state->tracking )
01140                 {
01141                 default:
01142                 case guibs_Focus:
01143                     if( state->basic.frames[guibs_Focus] )
01144                         OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_Focus], bound.left,bound.top );
01145                     else if( state->basic.frames[guibs_Neutral] )
01146                         OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_Neutral], bound.left,bound.top );
01147                     else
01148                         OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_Selected], bound.left,bound.top );
01149                     break;
01150                 case guibs_Neutral:
01151                     OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_Neutral], bound.left,bound.top );
01152                     break;
01153                 case guibs_Selected:
01154                     if( state->basic.frames[guibs_Selected] )
01155                         OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_Selected], bound.left,bound.top );
01156                     else if( state->basic.frames[guibs_Focus] )
01157                         OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_Focus], bound.left,bound.top );
01158                     else
01159                         OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_Neutral], bound.left,bound.top );
01160                     break;
01161                 }
01162                 if( state->basic.text && *state->basic.text )
01163                 {
01164                     /* Draw any text that goes with the button */
01165                     GUI_DrawText( &opc, &bound, state->basic.align, state->basic.text, ~0u );
01166                 }
01167                 /* Draw top focus, if present */
01168                 if( GUI_Control_IsFocused( gui, control ) )
01169                     OPC_NAMING(Shape)( &opc, state->basic.frames[guibs_FocusOver], bound.left,bound.top );
01170             }
01171         }
01172         break;
01173     case GUI_Init:
01174         {
01175             GUI_Button_State* state = (GUI_Button_State*)GUI_Control_Data( gui, control );
01176             GUI_Def_State(gui,control,GUICS_DEFAULT,GUI_CENTER|GUI_VCENTER);
01177             state->tracking = guibs_Neutral;
01178         }
01179         break;
01180     default:
01181         break;
01182     }
01183 }
01184 
01188 void GUI_Ctrl_Checkbox( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
01189 {
01190     switch( msg )
01191     {
01192     case GUI_Cycle:
01193         {
01194             /* Handle keys/events */
01195             GUI_Checkbox_State* state = (GUI_Checkbox_State*)GUI_Control_Data( gui, control );
01196             if( !state->basic.frames )
01197             {
01198                 if( GUI_Control_IsFocused( gui, control ) )
01199                     GUI_tabright(gui);
01200                 return;
01201             }
01202             if( GUI_Control_IsFocused( gui, control ) )
01203             {
01204                 #if ( defined(GUI_TABLEFT) || defined(GUI_TABRIGHT) || defined(GUI_TABUP) || defined(GUI_TABDOWN) )
01205                 if( GUI_tabhandler( gui ) )
01206                     return;
01207                 #endif
01208                 if( GUI_GetKeyPress() & (GUI_SELECT|GUI_PICK) )
01209                 {
01210                     if( state->bCheck )
01211                     {
01212                         state->bCheck = false;
01213                         GUI_UncheckSound();
01214                     }
01215                     else
01216                     {
01217                         state->bCheck = true;
01218                         GUI_CheckSound();
01219                     }
01220                     GUI_Control_Notify( gui, control );
01221                     GUI_Control_Dirty( gui, control );
01222                     GUI_ClearKeyPress();
01223                 }
01224             }
01225         }
01226         break;
01227     case GUI_Paint:
01228         {
01229             GUI_Checkbox_State* state = (GUI_Checkbox_State*)GUI_Control_Data( gui, control );
01230             OPC opc;
01231             if( GUI_Control_Paint( gui, control, &opc ) && state->basic.frames )
01232             {
01233                 Rect bound;
01234                 GUI_Control_Bound( gui, control, &bound );
01235                 if( state->basic.text && *state->basic.text )
01236                 {
01237                     /* Draw any text that goes with the button */
01238                     Rect rCheck;
01239                     OPC_NAMING(Shape_Bound)( &rCheck, state->basic.frames[state->bCheck ? guics_Checked : guics_Unchecked], bound.left,bound.top );
01240                     if( GUI_Control_IsFocused( gui, control ) )
01241                     {
01242                         Rect rFocus;
01243                         OPC_NAMING(Shape_Bound)( &rFocus, state->basic.frames[guics_Focus], bound.left,bound.top );
01244                         RectUnionRect( rCheck, rFocus );
01245                     }
01246                     /* state->align is for text alignment, so this looks backwards */
01247                     switch( state->basic.align & (GUI_LEFT|GUI_CENTER|GUI_RIGHT) )
01248                     {
01249                     default:
01250                     case GUI_LEFT:
01251                     case GUI_CENTER:
01252                         RectLeftTo( rCheck, bound.left );
01253                         bound.left = rCheck.right;
01254                         break;
01255                     case GUI_RIGHT:
01256                         RectRightTo( rCheck, bound.right );
01257                         bound.right = rCheck.left;
01258                         break;
01259                     }
01260                     switch( state->basic.align & (GUI_TOP|GUI_VCENTER|GUI_BOTTOM) )
01261                     {
01262                     default:
01263                     case GUI_TOP:
01264                     case GUI_VCENTER:
01265                         RectBottomTo( rCheck, bound.bottom );
01266                         bound.bottom = rCheck.top;
01267                         break;
01268                     case GUI_BOTTOM:
01269                         RectTopTo( rCheck, bound.top );
01270                         bound.top = rCheck.bottom;
01271                         break;
01272                     }
01273                     GUI_DrawText( &opc, &bound, state->basic.align, state->basic.text, ~0u );
01274                 }
01275                 else 
01276                 {
01277                     OPC_NAMING(Shape)( &opc, state->basic.frames[state->bCheck ? guics_Checked : guics_Unchecked], bound.left,bound.top );
01278                     if( GUI_Control_IsFocused( gui, control ) )
01279                         OPC_NAMING(Shape)( &opc, state->basic.frames[guics_Focus], bound.left,bound.top );
01280                 }
01281             }
01282         }
01283         break;
01284     case GUI_Init:
01285         {
01286             GUI_Checkbox_State* state = (GUI_Checkbox_State*)GUI_Control_Data( gui, control );
01287             GUI_Def_State(gui,control,GUICS_DEFAULT,GUI_LEFT);
01288             state->bCheck = false;
01289         }
01290         break;
01291     default:
01292         break;
01293     }
01294 }
01295 
01303 bool _GUI_Checkbox_SetCheck( GUI* gui, int index, bool bCheck)
01304 {
01305     bool bOld;
01306     const GUI_Control* control = GUI_Control_Get( gui, index );
01307     GUI_Checkbox_State* state = (GUI_Checkbox_State*)GUI_Control_Data( gui, control );
01308     GUI_Assert_Type( gui, index, guih_Checkbox );
01309     bOld = state->bCheck;
01310     state->bCheck = 0 != (bCheck);
01311     if( !(state->basic.mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) )
01312         state->basic.mask |= GUICS_NOTIFY;
01313     GUI_Control_Dirty( gui, control );
01314     return bOld;
01315 }
01316 
01317 
01321 void GUI_Ctrl_Animation( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
01322 {
01323     switch( msg )
01324     {
01325     case GUI_Cycle:
01326         {
01327             GUI_Animation_State* state = (GUI_Animation_State*)GUI_Control_Data( gui, control );
01328             unsigned mscurr = (unsigned)GUI_MSTime();
01329             if( !state->basic.frames || (state->basic.mask & GUICS_INVISIBLE) )
01330                 return;
01331             if( (mscurr-state->msprev) >= state->msframe )
01332             {
01333                 switch( state->aDir )
01334                 {
01335                 case gad_Stop:
01336                 default:
01337                     return;
01338                 case gad_ForwardOneshot:
01339                     if( ++state->iFrame >= (int)state->basic.cFrames )
01340                     {
01341                         state->iFrame = state->basic.cFrames-1;
01342                         GUI_Control_Notify( gui, control );
01343                         state->aDir = gad_Stop;
01344                     }
01345                     GUI_Control_Dirty( gui, control );
01346                     break;
01347                 case gad_BackwardOneshot:
01348                     if( --state->iFrame < 0 )
01349                     {
01350                         state->iFrame = 0;
01351                         GUI_Control_Notify( gui, control );
01352                         state->aDir = gad_Stop;
01353                     }
01354                     GUI_Control_Dirty( gui, control );
01355                     break;
01356                 case gad_ForwardLoop:
01357                     if( ++state->iFrame >= (int)state->basic.cFrames )
01358                         state->iFrame = 0;
01359                     GUI_Control_Dirty( gui, control );
01360                     break;
01361                 case gad_BackwardLoop:
01362                     if( --state->iFrame < 0 )
01363                         state->iFrame = (int)state->basic.cFrames-1;
01364                     GUI_Control_Dirty( gui, control );
01365                     break;
01366                 case gad_ForwardPingPong:
01367                     if( ++state->iFrame >= (int)state->basic.cFrames-1 )
01368                     {
01369                         state->iFrame = (int)state->basic.cFrames-1;
01370                         state->aDir = gad_BackwardPingPong;
01371                     }
01372                     GUI_Control_Dirty( gui, control );
01373                     break;
01374                 case gad_BackwardPingPong:
01375                     if( --state->iFrame <= 0 )
01376                     {
01377                         state->iFrame = 0;
01378                         state->aDir = gad_ForwardPingPong;
01379                         GUI_Control_Dirty( gui, control );
01380                     }
01381                     GUI_Control_Dirty( gui, control );
01382                     break;
01383                 case gad_Random:
01384                     {
01385                         int nextFrame;
01386                         do {
01387                             nextFrame = GUI_Random() % state->basic.cFrames;
01388                         } while( nextFrame == state->iFrame );
01389                         state->iFrame = nextFrame;
01390                         GUI_Control_Dirty( gui, control );
01391                     }
01392                     break;
01393                 }
01394                 state->msprev = mscurr;
01395             }
01396         }
01397         break;
01398     case GUI_Paint:
01399         {
01400             GUI_Animation_State* state = (GUI_Animation_State*)GUI_Control_Data( gui, control );
01401             OPC opc;
01402             if( state->basic.frames && state->basic.cFrames && GUI_Control_Paint( gui, control, &opc ) )
01403             {
01404                 Rect bound;
01405                 GUI_Control_Bound( gui, control, &bound );
01406                 if( state->iFrame < 0 )
01407                 {
01408                     state->iFrame = 0;
01409                 }
01410                 else if( state->iFrame >= (int)state->basic.cFrames )
01411                 {
01412                     state->iFrame = state->basic.cFrames-1;
01413                 }
01414                 OPC_NAMING(Shape)( &opc, state->basic.frames[state->iFrame], bound.left,bound.top );
01415                 if( state->basic.text && *state->basic.text )
01416                 {
01417                     /* Draw any text that goes with the button */
01418                     GUI_DrawText( &opc, &bound, state->basic.align, state->basic.text, ~0u );
01419                 }
01420             }
01421         }
01422         break;
01423     case GUI_Init:
01424         {
01425             GUI_Animation_State* state = (GUI_Animation_State*)GUI_Control_Data( gui, control );
01426             GUI_Def_State(gui,control,GUICS_NOFOCUS,GUI_CENTER|GUI_VCENTER);
01427             state->iFrame = 0;
01428             state->aDir = state->basic.cFrames > 1 ? gad_ForwardLoop : gad_Stop;
01429             state->msframe = 100;
01430             state->msprev = 0;
01431         }
01432         break;
01433     default:
01434         break;
01435     }
01436 }
01437 
01444 int _GUI_Animation_SetFrame( GUI* gui, int index, int frame )
01445 {
01446     const GUI_Control* control = GUI_Control_Get( gui, index );
01447     GUI_Animation_State* state = (GUI_Animation_State*)GUI_Control_Data( gui, control );
01448     int frPrev = state->iFrame;
01449     GUI_Assert_Type( gui, index, guih_Animation );
01450     if( state->basic.cFrames > 0 )
01451         state->iFrame = (frame + state->basic.cFrames) % state->basic.cFrames;
01452     else
01453         state->iFrame = 0;
01454     state->aDir = gad_Stop;
01455     if( frPrev != state->iFrame )
01456         GUI_Control_Dirty( gui, control );
01457     return frPrev;
01458 }
01459 
01468 void _GUI_Animation_SetAnim( GUI* gui, int index, GUI_AnimDir animdir, int startFrame, unsigned msFrameTime )
01469 {
01470     const GUI_Control* control = GUI_Control_Get( gui, index );
01471     GUI_Animation_State* state = (GUI_Animation_State*)GUI_Control_Data( gui, control );
01472     GUI_Assert_Type( gui, index, guih_Animation );
01473     state->iFrame = max(0,min(startFrame,(int)state->basic.cFrames));
01474     state->msframe = msFrameTime;
01475     state->msprev = (unsigned)GUI_MSTime();
01476     state->aDir = animdir;
01477     GUI_Control_Dirty( gui, control );
01478 }
01479 
01480 
01486 void GUI_Ctrl_Scrollbar( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
01487 {
01488     GUI_Scrollbar_State* state = (GUI_Scrollbar_State*)GUI_Control_Data( gui, control );
01489     const OPCShape* frame = NULL;
01490     const OPCShape* cthumb = NULL;
01491     bool bFocus = GUI_Control_IsFocused( gui, control );
01492     Rect bound;
01493     int w,h;
01494     GUI_Control_Bound( gui, control, &bound );
01495     w = RectWide(bound);
01496     h = RectHigh(bound);
01497 
01498 /* Calculate where to draw cthumb */
01499 #define CalcPos(value,x,y)\
01500     {\
01501         int vtotal = state->vmax-state->vmin;\
01502         int vcurr = min(max(value,state->vmin),state->vmax);\
01503         if( w > h )\
01504         {\
01505             x = bound.left + (w * ((vcurr)-state->vmin) / vtotal);\
01506             y = bound.top  + (h/2);\
01507         }\
01508         else\
01509         {\
01510             x = bound.left + (w/2);\
01511             y = bound.bottom - (h * ((vcurr)-state->vmin) / vtotal);\
01512         }\
01513     }
01514 
01515 #define CalcThumb(x,y)\
01516     {\
01517         x = (x - cthumb->xOff) - (cthumb->wide/2);\
01518         y = (y - cthumb->yOff) - (cthumb->high/2);\
01519     }
01520 
01521 #if defined(GUI_GetKeyHeld)
01522 #define SB_SETUP_REPEAT(key) \
01523     if( state->msRepeat && key != state->keyPrev )\
01524     {\
01525         state->msPrev = (unsigned)GUI_MSTime() + GUI_RepeatPause(state->msRepeat);\
01526         state->keyPrev = (key);\
01527     }
01528 #define SB_REPEAT_CANCEL() \
01529     {\
01530         state->msPrev = 0;\
01531         state->keyPrev = 0;\
01532     }
01533 #else
01534 #define SB_SETUP_REPEAT(key)
01535 #define SB_REPEAT_CANCEL()
01536 #endif
01537 
01538     switch( msg )
01539     {
01540     case GUI_Cycle:
01541         if( state->basic.frames )
01542         {
01543             cthumb = bFocus && state->basic.frames[guisp_ThumbFocus] ? state->basic.frames[guisp_ThumbFocus] : state->basic.frames[guisp_Thumb];
01544             frame = state->basic.frames[guisp_Frame];
01545             if( bFocus )
01546             {
01547                 int value = state->value;
01548                 unsigned keypress;
01549 #if defined(GUI_GetKeyHeld)
01550                 if( state->keyPrev && state->msRepeat )
01551                 {
01552                     keypress = GUI_GetKeyHeld() & state->keyPrev;
01553                     if( keypress && state->msPrev )
01554                     {
01555                         unsigned mstime = (unsigned)GUI_MSTime();
01556                         if( mstime > state->msPrev && mstime - state->msPrev >= state->msRepeat )
01557                         {
01558                             state->msPrev = mstime;
01559                         }
01560                         else
01561                         {
01562                             keypress = 0;
01563                         }
01564                     }
01565                     else
01566                     {
01567                         SB_REPEAT_CANCEL();
01568                     }
01569                 }
01570                 else
01571 #endif
01572                 {
01573                     keypress = GUI_GetKeyPress();
01574                 }
01575 
01576                 /*
01577                  * Take inventory of tabs
01578                  * If we have only one tab, select will cycle/wrap
01579                  * If we have two tabs, holding select will move cthumb
01580                  * Four tabs, moving in directions cthumb travels moves cthumb,
01581                  *  moving in other directions tabs
01582                  */
01583 #if defined(GUI_GetPointer)
01584                 {
01585                     int x, y;
01586                     GUI_GetPointer(x,y);
01587                     /*
01588                      * If we have GUI_GetPointer and GUI_GetKeyHeld, then dragging
01589                      *  pointer or clicking/tapping moves cthumb
01590                      * If we have GUI_GetPointer and not GUI_GetKeyHeld, then
01591                      *  only clicking/tapping moves cthumb
01592                      */
01593                     if( RectPtInRect( bound, x, y ) )
01594                     {
01595                     #if defined(GUI_GetKeyHeld)
01596                         if( GUI_PICK == GUI_GetKeyPress() || GUI_PICK == GUI_GetKeyHeld() )
01597                     #else
01598                         if( GUI_PICK == GUI_GetKeyPress() && RectPtInRect( bound, x, y ) )
01599                     #endif
01600                         {
01601                             /* Pointer/cursor is inside, mouse is held */
01602                             int vtotal = state->vmax-state->vmin;
01603                             if( w > h )
01604                             {
01605                                 int offset = x - bound.left;
01606                                 int mod = max(h/vtotal,1);
01607                                 int offsetdown = offset/mod*mod;
01608                                 int offsetup = (offset+mod)/mod*mod;
01609                                 if( offset-offsetdown < offsetup-offset )
01610                                     value = (vtotal * offsetdown / w );
01611                                 else
01612                                     value = (vtotal * offsetup / w );
01613                             }
01614                             else
01615                             {
01616                                 int offset = bound.bottom - y;
01617                                 int mod = max(h/vtotal,1);
01618                                 int offsetdown = offset/mod*mod;
01619                                 int offsetup = (offset+mod)/mod*mod;
01620                                 if( offset-offsetdown < offsetup-offset )
01621                                     value = (vtotal * offsetdown / h );
01622                                 else
01623                                     value = (vtotal * offsetup / h );
01624                             }
01625                         }
01626                     }
01627                 }
01628 #endif
01629 #if (defined(GUI_TABLEFT) && defined(GUI_TABRIGHT) && defined(GUI_TABUP) && defined(GUI_TABDOWN))
01630                 if( w > h )
01631                 {
01632                     if( GUI_TABLEFT == keypress )
01633                     {
01634                         value--;
01635                         if( value < state->vmin )
01636                             value = state->vmin;
01637                         SB_SETUP_REPEAT(keypress);
01638                     }
01639                     else if( GUI_TABRIGHT == keypress )
01640                     {
01641                         value++;
01642                         if( value > state->vmax )
01643                             value = state->vmax;
01644                         SB_SETUP_REPEAT(keypress);
01645                     }
01646                     else if( GUI_tabhandler( gui ) )
01647                     {
01648                         SB_REPEAT_CANCEL();
01649                         state->oldValue = state->value+1;
01650                     }
01651                 }
01652                 else
01653                 {
01654                     if( GUI_TABUP == keypress )
01655                     {
01656                         value++;
01657                         if( value > state->vmax )
01658                             value = state->vmax;
01659                         SB_SETUP_REPEAT(keypress);
01660                     }
01661                     else if( GUI_TABDOWN == keypress )
01662                     {
01663                         value--;
01664                         if( value < state->vmin )
01665                             value = state->vmin;
01666                         SB_SETUP_REPEAT(keypress);
01667                     }
01668                     else if( GUI_SELECT == keypress )
01669                     {
01670                         value++;
01671                         if( value > state->vmax )
01672                             value = state->vmin;
01673                         SB_SETUP_REPEAT(keypress);
01674                     }
01675                     else if( GUI_tabhandler( gui ) )
01676                     {
01677                         SB_REPEAT_CANCEL();
01678                         state->oldValue = state->value+1;
01679                     }
01680                 }
01681 #elif !defined(GUI_GetPointer) && (defined(GUI_TAB) || defined(GUI_TABLEFT) || defined(GUI_TABRIGHT) || defined(GUI_TABUP) || defined(GUI_TABDOWN))
01682                 /* For less than 4-way tab, select cycles through scrolling, and other tabs skip over */
01683                 if( GUI_SELECT == keypress )
01684                 {
01685                     value++;
01686                     if( value > state->vmax )
01687                         value = state->vmin;
01688                     SB_SETUP_REPEAT(keypress);
01689                 }
01690                 else 
01691                 {
01692                     SB_REPEAT_CANCEL();
01693                     if( GUI_tabhandler( gui ) )
01694                     {
01695                         state->oldValue = state->value+1;
01696                     }
01697                 }
01698 #endif
01699                 /* Nothing bailed? Set new value */
01700                 state->value = value;
01701             }
01702             else
01703             {
01704                 SB_REPEAT_CANCEL();
01705             }
01706             if( state->oldValue != state->value )
01707             {
01708                 Rect rthumb;
01709                 int x,y;
01710 
01711                 /* Mark control bounds dirty */
01712                 GUI_Dirty_Rect( gui, &bound );
01713 
01714                 /* Mark old cthumb position dirty */
01715                 CalcPos(state->oldValue, x,y);
01716                 CalcThumb(x,y);
01717                 OPC_NAMING(Shape_Bound)( &rthumb, cthumb, x, y );
01718                 GUI_Dirty_Rect( gui, &rthumb );
01719 
01720                 /* Mark new cthumb position dirty */
01721                 CalcPos(state->value, x,y);
01722                 CalcThumb(x,y);
01723                 OPC_NAMING(Shape_Bound)( &rthumb, cthumb, x, y );
01724                 GUI_Dirty_Rect( gui, &rthumb );
01725 
01726                 state->oldValue = state->value;
01727 
01728                 /* Make noise, if defined */
01729                 GUI_ScrollSound();
01730                 GUI_Control_Notify( gui, control );
01731             }
01732         }
01733         else
01734         {
01735             if( GUI_Control_IsFocused( gui, control ) )
01736                 GUI_tabright(gui);
01737             SB_REPEAT_CANCEL();
01738             return;
01739         }
01740         break;
01741 
01742     case GUI_Paint:
01743         if( state->basic.frames )
01744         {
01745             OPC opc;
01746             if( GUI_Control_Paint( gui, control, &opc ) )
01747             {
01748                 int x,y;
01749                 const OPCShape* shape;
01750                 cthumb = bFocus && state->basic.frames[guisp_ThumbFocus] ? state->basic.frames[guisp_ThumbFocus] : state->basic.frames[guisp_Thumb];
01751                 frame = bFocus && state->basic.frames[guisp_Focus] ? state->basic.frames[guisp_Focus] : state->basic.frames[guisp_Frame];
01752                 CalcPos(state->value, x,y);
01753 
01754                 /* Draw frame, if present */
01755                 OPC_NAMING(Shape)( &opc, frame, bound.left,bound.top );
01756 
01757                 /* Draw focus underlay, if present */
01758                 if( bFocus )
01759                     OPC_NAMING(Shape)( &opc, state->basic.frames[guisp_FocusUnder], bound.left,bound.top );
01760 
01761                 /* Draw low half of fill */
01762                 shape = state->basic.frames[guisp_Fill1];
01763                 if( shape )
01764                 {
01765                     OPC clip;
01766                     Rect scaling;
01767                     OPC_NAMING(Shape_Bound)( &scaling, shape, bound.left,bound.top );
01768                     if( w > h )
01769                         scaling.right = x+1;
01770                     else
01771                         scaling.bottom = y+1;
01772                     OPC_NAMING(Clip)( &clip, &opc, &scaling );
01773                     OPC_NAMING(Shape)( &clip, shape, bound.left,bound.top );
01774                 }
01775 
01776                 /* Draw high half of fill */
01777                 shape = state->basic.frames[guisp_Fill2];
01778                 if( shape )
01779                 {
01780                     OPC clip;
01781                     Rect scaling;
01782                     if( w > h )
01783                         scaling.left = x;
01784                     else
01785                         scaling.top = y;
01786                     OPC_NAMING(Shape_Bound)( &scaling, shape, bound.left,bound.top );
01787                     OPC_NAMING(Clip)( &clip, &opc, &scaling );
01788                     OPC_NAMING(Shape)( &clip, shape, bound.left,bound.top );
01789                 }
01790 
01791                 if( state->basic.text && *state->basic.text )
01792                 {
01793                     /* Draw any text that goes with the control */
01794                     GUI_DrawText( &opc, &bound, state->basic.align, state->basic.text, ~0u );
01795                 }
01796 
01797                 /* Draw focus highlight, if present */
01798                 if( bFocus )
01799                     OPC_NAMING(Shape)( &opc, state->basic.frames[guisp_FocusOver], bound.left,bound.top );
01800 
01801                 /* Draw thumb */
01802                 CalcThumb(x,y);
01803                 OPC_NAMING(Shape)( &gui->opc, cthumb, x,y ); /* deliberately uses 'gui' clipping instead of control clipping */
01804             }
01805         }
01806         break;
01807     case GUI_Init:
01808         {
01809             GUI_Def_State(gui,control,GUICS_DEFAULT,GUI_CENTER|GUI_VCENTER);
01810             SB_REPEAT_CANCEL();
01811             state->msRepeat = GUI_DefaultRepeat;
01812             state->vmax = 10;
01813             state->value = 5;
01814             state->vmin = 0;
01815             state->oldValue = -1;
01816         }
01817         break;
01818     default:
01819         break;
01820     }
01821 #undef CalcThumb
01822 #undef CalcPos
01823 #undef SB_SETUP_REPEAT
01824 #undef SB_REPEAT_CANCEL
01825 }
01826 
01836 int _GUI_Scrollbar_SetValue( struct GUI* gui, int idControl, int newValue, int minValue, int maxValue )
01837 {
01838     int oldvalue;
01839     GUI_Scrollbar_State* tmpScrollbarState = (GUI_Scrollbar_State*)GUI_Control_Get_Data( (gui), (idControl) );
01840     GUI_Assert_Type( (gui), (idControl), guih_Scrollbar );
01841     tmpScrollbarState->vmin = (minValue);
01842     tmpScrollbarState->vmax = (maxValue);
01843     tmpScrollbarState->oldValue = -1-newValue;
01844     oldvalue = tmpScrollbarState->value;
01845     tmpScrollbarState->value = newValue;
01846     if( !(tmpScrollbarState->basic.mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) )
01847         tmpScrollbarState->basic.mask |= GUICS_NOTIFY;
01848     return oldvalue;
01849 }
01850 
01851 
01855 void GUI_Ctrl_Ticker( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
01856 {
01857     switch( msg )
01858     {
01859     case GUI_Cycle:
01860         {
01861             GUI_Ticker_State* state = (GUI_Ticker_State*)GUI_Control_Data( gui, control );
01862             unsigned mscurr = (unsigned)GUI_MSTime();
01863             if( (!state->basic.frames && !state->basic.text) || (state->basic.mask & GUICS_INVISIBLE) )
01864                 return;
01865             if( mscurr < state->msprev )
01866             {
01867                 /* Delay or wrap? */
01868                 if( state->msprev - mscurr > 30000u )
01869                     state->msprev = mscurr;
01870                 else
01871                     return;
01872             }
01873             if( (mscurr-state->msprev) >= state->msframe )
01874             {
01875                 if( state->tWide > RectWide(control->bound) )
01876                 {
01877                     state->offset++;
01878                     if( state->offset > state->tWide )
01879                     {
01880                         if( state->szNext )
01881                         {
01882                             /* If we have 'next' text, notify when it's used (and more text can be set) */
01883                             /* Otherwise, it just loops the same thing forever without notifying */
01884                             GUI_Ticker_SetText( gui, GUI_Control_Index( gui, control ), state->szNext );
01885                             state->szNext = NULL;
01886                             GUI_Control_Notify( gui, control );
01887                         }
01888                         else
01889                         {
01890                             state->offset = 0;
01891                         }
01892                     }
01893                     GUI_Control_Dirty( gui, control );
01894                 }
01895                 state->msprev = mscurr;
01896             }
01897         }
01898         break;
01899     case GUI_Paint:
01900         {
01901             OPC opc;
01902             if( GUI_Control_Paint( gui, control, &opc ) )
01903             {
01904                 GUI_Ticker_State* state = (GUI_Ticker_State*)GUI_Control_Data( gui, control );
01905                 Rect bound;
01906                 GUI_Control_Bound( gui, control, &bound );
01907                 if( state->basic.text )
01908                 {
01909                     /* If total width is greater than bounding box, scroll it. */
01910                     /* Just draw it twice and let clipping take care of the rest */
01911                     Rect tBound = bound;
01912                     tBound.left = tBound.left - state->offset;
01913                     tBound.right = tBound.left + state->tWide;
01914                     GUI_DrawText( &opc, &tBound, GUI_ONELINE|GUI_VCENTER, state->basic.text, ~0u );
01915                     tBound.left += state->tWide;
01916                     tBound.right += state->tWide;
01917                     if( tBound.left < bound.right )
01918                         GUI_DrawText( &opc, &tBound, GUI_ONELINE|GUI_VCENTER, state->basic.text, ~0u );
01919                 }
01920                 else
01921                 {
01922                     /* If total width is greater than bounding box, scroll it. */
01923                     /* Just draw it twice and let clipping take care of the rest */
01924                     int xOff = bound.left - state->offset;
01925                     {
01926                         pointer_foreach_const( OPCShape*, state->basic.frames, control->cState, shape )
01927                         {
01928                             OPC_NAMING(Shape)( &opc, *shape, xOff-(*shape)->xOff, bound.top - (*shape)->yOff );
01929                             xOff += (*shape)->wide;
01930                         }
01931                     }
01932                     if( xOff < bound.right )
01933                     {
01934                         pointer_foreach_const( OPCShape*, state->basic.frames, control->cState, shape )
01935                         {
01936                             OPC_NAMING(Shape)( &opc, *shape, xOff-(*shape)->xOff, bound.top - (*shape)->yOff );
01937                             xOff += (*shape)->wide;
01938                         }
01939                     }
01940                 }
01941             }
01942         }
01943         break;
01944     case GUI_Init:
01945         {
01946             GUI_Ticker_State* state = (GUI_Ticker_State*)GUI_Control_Data( gui, control );
01947             GUI_Def_State(gui,control,GUICS_NOFOCUS,GUI_LEFT);
01948             GUI_Ticker_SetText( gui, GUI_Control_Index(gui,control), NULL );
01949             state->msframe = 33; /*(About 30FPS, when timed by video, will always be 'time') */
01950             state->msprev = (unsigned)GUI_MSTime() + 3000u;
01951             state->szNext = NULL;
01952         }
01953         break;
01954     default:
01955         break;
01956     }
01957 }
01958 
01965 void _GUI_Ticker_SetText( struct GUI* gui, int idControl, const GUI_CHAR* sz )
01966 {
01967     const GUI_Control* control = GUI_Control_Get( gui, idControl );
01968     GUI_Ticker_State* state = (GUI_Ticker_State*)GUI_Control_Data( gui, control );
01969     GUI_Assert_Type( gui, idControl, guih_Ticker );
01970     if( sz )
01971     {
01972         Rect bounds = RectAutoClear();
01973         GUI_MeasureText( &bounds, GUI_ONELINE, sz, ~0u );
01974         state->basic.text = sz;
01975         state->offset = 0;
01976         state->tWide = RectWide(bounds);
01977     }
01978     else
01979     {
01980         state->basic.text = NULL;
01981         state->offset = 0;
01982         state->tWide = 0;
01983         {
01984             pointer_foreach_const( OPCShape*, state->basic.frames, control->cState, curr )
01985                 state->tWide += (*curr)->wide;
01986         }
01987     }
01988 }
01989 
01993 void _GUI_Ticker_SetSpeed( struct GUI* gui, int idControl, unsigned msDelay, unsigned msframe )
01994 {
01995     const GUI_Control* control = GUI_Control_Get( gui, idControl );
01996     GUI_Ticker_State* state = (GUI_Ticker_State*)GUI_Control_Data( gui, control );
01997     state->msframe = msframe;
01998     state->msprev = (unsigned)GUI_MSTime() + msDelay;
01999 }
02000 
02001 /*
02002  * Do shape in tumbler window, heeding alignment
02003  */
02004 static void GUI_AlignShape( const OPC* opc, const Rect* rBound, const OPCShape* shape, unsigned mask )
02005 {
02006     Rect rAligned = *rBound;
02007     Rect rShape;
02008     OPC_NAMING(Shape_Bound)( &rShape, shape, rBound->left, rBound->top );
02009     rAligned = rShape;
02010     switch( mask & 0xc ) 
02011     {
02012     case GUI_VCENTER:
02013         RectCenterOnY(rAligned,RectCenterY(*rBound));
02014         break;
02015     case GUI_BOTTOM:
02016         RectBottomTo(rAligned,rBound->bottom);
02017         break;
02018     default:
02019         break;
02020     }
02021     switch( mask & 3 )
02022     {
02023     default:
02024         break;
02025     case GUI_CENTER:
02026         RectCenterOnX(rAligned,RectCenterX(*rBound));
02027         break;
02028     case GUI_RIGHT:
02029         RectRightTo(rAligned,rBound->right);
02030         break;
02031     }
02032     OPC_NAMING(Shape)( opc, shape, rBound->left+(rAligned.left-rShape.left), rBound->top+(rAligned.top-rShape.top) );
02033     
02034 }
02035 
02036 /*
02037  * Work out where control parts are, and what the clipping window should be, based on what images are defined
02038  */
02039 static void GUI_Ctrl_Tumbler_Rects( struct GUI* gui, const struct GUI_Control* control, Rect* rWin, Rect* rLeft, Rect* rRight )
02040 {
02041     GUI_Tumbler_State* state = (GUI_Tumbler_State*)GUI_Control_Data( gui, control );
02042     Rect bound;
02043     GUI_Control_Bound( gui, control, &bound );
02044     OPC_NAMING(Shape_Bound)( rLeft, state->basic.frames[guitb_LBn]?state->basic.frames[guitb_LBn]:state->basic.frames[guitb_LBnHi], bound.left, bound.top );
02045     OPC_NAMING(Shape_Bound)( rRight, state->basic.frames[guitb_RBn]?state->basic.frames[guitb_RBn]:state->basic.frames[guitb_RBnHi], bound.left, bound.top );
02046     if( control->params )
02047     {
02048         *rWin = *((const Rect*)control->params);
02049         RectMoveBy(*rWin, bound.left, bound.top );
02050     }
02051     else
02052     {
02053         if( state->basic.frames[guitb_Overlay] )
02054             OPC_NAMING(Shape_Bound)( rWin, state->basic.frames[guitb_Overlay], bound.left, bound.top );
02055         else if( state->basic.frames[guitb_FocusOver] )
02056             OPC_NAMING(Shape_Bound)( rWin, state->basic.frames[guitb_FocusOver], bound.left, bound.top );
02057         else if( state->basic.frames[guitb_Under] )
02058             OPC_NAMING(Shape_Bound)( rWin, state->basic.frames[guitb_Under], bound.left, bound.top );
02059         else if( state->basic.frames[guitb_FocusUnder] )
02060             OPC_NAMING(Shape_Bound)( rWin, state->basic.frames[guitb_FocusUnder], bound.left, bound.top );
02061         else
02062             *rWin = bound;
02063     }
02064 }
02065 
02069 void GUI_Ctrl_Tumbler( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
02070 {
02071     GUI_Tumbler_State* state = (GUI_Tumbler_State*)GUI_Control_Data( gui, control );
02072     Rect bound;
02073     GUI_Control_Bound( gui, control, &bound );
02074 #if defined(GUI_GetKeyHeld)
02075 #define TB_SETUP_REPEAT(key) \
02076     if( state->msRepeat && key != state->keyPrev )\
02077     {\
02078         state->msPrev = (unsigned)GUI_MSTime() + GUI_RepeatPause(state->msRepeat);\
02079         state->keyPrev = (key);\
02080     }
02081 #define TB_REPEAT_CANCEL() \
02082     {\
02083         state->msPrev = 0;\
02084         state->keyPrev = 0;\
02085     }
02086 #else
02087 #define TB_SETUP_REPEAT(key)
02088 #define TB_REPEAT_CANCEL()
02089 #endif
02090     switch( msg )
02091     {
02092     case GUI_Cycle:
02093         if( (state->basic.mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) )
02094             return;
02095         if( state->cStates )
02096         {
02097             Rect rRightArrow, rLeftArrow, rWin;
02098             GUI_Ctrl_Tumbler_Rects( gui, control, &rWin, &rLeftArrow, &rRightArrow );
02099             if( state->stateCurr != state->statePrev )
02100             {
02101                 GUI_Control_Dirty( gui, control );
02102                 /* 
02103                  * Transition states from one to another
02104                  * Take state->cTransition cycles to do it
02105                  */
02106                 if( state->cTransition > 0 )
02107                 {
02108                     state->offPrev += RectWide(rWin) / state->cTransition;
02109                     if( state->cTransition && state->offPrev >= RectWide(rWin) )
02110                     {
02111                         /*
02112                          * Finished (or no) transition, so carry on with cyclic duties
02113                          */
02114                         state->statePrev = state->stateCurr;
02115                         state->offPrev = 0;
02116                         return;
02117                     }
02118                     else
02119                     {
02120                         /*
02121                          * Don't accept more input until scroll's done
02122                          */
02123                         return;
02124                     }
02125                 }
02126                 else
02127                 {
02128                     state->statePrev = state->stateCurr;
02129                     state->offPrev = 0;
02130                 }
02131             }
02132             if( GUI_Control_IsFocused( gui, control ) )
02133             {
02134                 unsigned keypress;
02135 #if defined(GUI_GetKeyHeld)
02136                 if( state->keyPrev && state->msRepeat )
02137                 {
02138                     keypress = GUI_GetKeyHeld() & state->keyPrev;
02139                     if( keypress && state->msPrev )
02140                     {
02141                         unsigned mstime = (unsigned)GUI_MSTime();
02142                         if( mstime > state->msPrev && mstime - state->msPrev >= state->msRepeat )
02143                         {
02144                             state->msPrev = mstime;
02145                         }
02146                         else
02147                         {
02148                             keypress = 0;
02149                         }
02150                     }
02151                     else
02152                     {
02153                         TB_REPEAT_CANCEL();
02154                     }
02155                 }
02156                 else
02157 #endif
02158                 {
02159                     keypress = GUI_GetKeyPress();
02160                 }
02161 
02162                 /*
02163                  * If this has focus, take over 
02164                  */
02165 #if defined(GUI_GetPointer)
02166                 if( keypress == GUI_PICK )
02167                 {
02168                     int x,y;
02169                     GUI_GetPointer(x,y);
02170                     if( RectPtInRect( rRightArrow, x,y) )
02171                     {
02172                         state->stateCurr++;
02173                         if( state->stateCurr >= state->cStates )
02174                             state->stateCurr = 0;
02175                         GUI_ClearKeyPress();
02176                         TB_SETUP_REPEAT(keypress);
02177                     }
02178                     else if( RectPtInRect( rLeftArrow, x,y ) )
02179                     {
02180                         state->stateCurr--;
02181                         if( state->stateCurr < 0 )
02182                             state->stateCurr = state->cStates - 1;
02183                         GUI_ClearKeyPress();
02184                         TB_SETUP_REPEAT(keypress);
02185                     }
02186                     else
02187                     {
02188                         TB_REPEAT_CANCEL();
02189                     }
02190                 }
02191 #endif
02192 #if (defined(GUI_TABLEFT) && defined(GUI_TABRIGHT) && defined(GUI_TABUP) && defined(GUI_TABDOWN))
02193                 if( abs(rLeftArrow.top - rRightArrow.top) > abs(rLeftArrow.left - rRightArrow.left) )
02194                 {
02195                     if( GUI_TABUP == keypress )
02196                     {
02197                         state->stateCurr--;
02198                         if( state->stateCurr < 0 )
02199                             state->stateCurr = state->cStates - 1;
02200                         GUI_ClearKeyPress();
02201                         TB_SETUP_REPEAT(keypress);
02202                     }
02203                     else if( GUI_TABDOWN == keypress )
02204                     {
02205                         state->stateCurr++;
02206                         if( state->stateCurr >= state->cStates )
02207                             state->stateCurr = 0;
02208                         GUI_ClearKeyPress();
02209                         TB_SETUP_REPEAT(keypress);
02210                     }
02211                     else if( GUI_tabhandler( gui ) )
02212                     {
02213                         TB_REPEAT_CANCEL();
02214                         return;
02215                     }
02216                 }
02217                 else
02218                 {
02219                     if( GUI_TABLEFT == keypress )
02220                     {
02221                         state->stateCurr--;
02222                         if( state->stateCurr < 0 )
02223                             state->stateCurr = state->cStates - 1;
02224                         GUI_ClearKeyPress();
02225                         TB_SETUP_REPEAT(keypress);
02226                     }
02227                     else if( GUI_TABRIGHT == keypress )
02228                     {
02229                         state->stateCurr++;
02230                         if( state->stateCurr >= state->cStates )
02231                             state->stateCurr = 0;
02232                         GUI_ClearKeyPress();
02233                         TB_SETUP_REPEAT(keypress);
02234                     }
02235                     else if( GUI_tabhandler( gui ) )
02236                     {
02237                         TB_REPEAT_CANCEL();
02238                         return;
02239                     }
02240                 }
02241 #elif !defined(GUI_GetPointer) && (defined(GUI_TAB) || defined(GUI_TABLEFT) || defined(GUI_TABRIGHT) || defined(GUI_TABUP) || defined(GUI_TABDOWN))
02242                 /*
02243                  * If we don't have more than one or two tab buttons, don't waste them on the emulation
02244                  */
02245                 if( GUI_SELECT == keypress )
02246                 {
02247                     state->stateCurr++;
02248                     if( state->stateCurr >= state->cStates )
02249                         state->stateCurr = 0;
02250                     GUI_ClearKeyPress();
02251                     TB_SETUP_REPEAT(keypress);
02252                 }
02253                 else if( GUI_tabhandler( gui ) )
02254                 {
02255                     TB_REPEAT_CANCEL();
02256                     return;
02257                 }
02258 #endif
02259                 if( state->stateCurr != state->statePrev )
02260                 {
02261                     GUI_Tabsound();
02262                     GUI_Control_Notify( gui, control );
02263                 }
02264             }
02265             else
02266             {
02267                 TB_REPEAT_CANCEL();
02268             }
02269         }
02270         else 
02271         {
02272             if( GUI_Control_IsFocused( gui, control ) )
02273                 GUI_tabright(gui);
02274             TB_REPEAT_CANCEL();
02275             return;
02276         }
02277         break;
02278     case GUI_Paint:
02279         {
02280             OPC opc;
02281             if( !state->cStates || !state->basic.frames || (state->basic.mask & GUICS_INVISIBLE) )
02282                 return;
02283             if( GUI_Control_Paint( gui, control, &opc ) )
02284             {
02285                 Rect rRightArrow, rLeftArrow, rWin;
02286                 bool bFocus = GUI_Control_IsFocused( gui, control );
02287                 const OPCShape* la = state->basic.frames[guitb_LBn];
02288                 const OPCShape* ra = state->basic.frames[guitb_RBn];
02289                 int offx = 0,offy = 0;
02290                 GUI_Ctrl_Tumbler_Rects( gui, control, &rWin, &rLeftArrow, &rRightArrow );
02291                 if( bFocus && state->basic.frames[guitb_FocusUnder] )
02292                 {
02293                     OPC_NAMING(Shape)( &opc, state->basic.frames[guitb_FocusUnder], bound.left, bound.top );
02294                 }
02295                 else
02296                 {
02297                     OPC_NAMING(Shape)( &opc, state->basic.frames[guitb_Under], bound.left, bound.top );
02298                 }
02299                 if( state->offPrev )
02300                 {
02301                     if( state->statePrev == 0 && state->stateCurr == state->cStates-1 )
02302                     {
02303                         /* Wrapped least to max */
02304                         la = state->basic.frames[guitb_LBnHi];
02305                         if( rLeftArrow.bottom < rRightArrow.top )
02306                         {
02307                             /* Vertical orientation */
02308                             offy = state->offPrev;
02309                         }
02310                         else
02311                         {
02312                             /* Horizontal orientation */
02313                             offx = state->offPrev;
02314                         }
02315                     }
02316                     else if( state->statePrev == state->cStates-1 && state->stateCurr == 0 )
02317                     {
02318                         /* Wrapped max to least */
02319                         ra = state->basic.frames[guitb_RBnHi];
02320                         if( rLeftArrow.bottom < rRightArrow.top )
02321                         {
02322                             /* Vertical orientation */
02323                             offy = -state->offPrev;
02324                         }
02325                         else
02326                         {
02327                             /* Horizontal orientation */
02328                             offx = -state->offPrev;
02329                         }
02330                     }
02331                     else if( state->statePrev < state->stateCurr )
02332                     {
02333                         /* Went bigger */
02334                         ra = state->basic.frames[guitb_RBnHi];
02335                         if( rLeftArrow.bottom < rRightArrow.top )
02336                         {
02337                             /* Vertical orientation */
02338                             offy = -state->offPrev;
02339                         }
02340                         else
02341                         {
02342                             /* Horizontal orientation */
02343                             offx = -state->offPrev;
02344                         }
02345                     }
02346                     else if( state->statePrev > state->stateCurr )
02347                     {
02348                         /* Went smaller */
02349                         la = state->basic.frames[guitb_LBnHi];
02350                         if( rLeftArrow.bottom < rRightArrow.top )
02351                         {
02352                             /* Vertical orientation */
02353                             offy = state->offPrev;
02354                         }
02355                         else
02356                         {
02357                             /* Horizontal orientation */
02358                             offx = state->offPrev;
02359                         }
02360                     }
02361                 }
02362                 /* Draw previous and current at offset */
02363                 if( state->states || state->tstates )
02364                 {
02365                     OPC opcbound;
02366                     OPC_NAMING(Clip)( &opcbound, &opc, &rWin );
02367                     if( offx )
02368                     {
02369                         RectLeftTo( rWin, rWin.left+offx );
02370                     }
02371                     else if( offy )
02372                     {
02373                         RectTopTo( rWin, rWin.top+offy );
02374                     }
02375                     if( offx || offy )
02376                     {
02377                         if( state->states )
02378                             GUI_AlignShape( &opcbound, &rWin, state->states[state->statePrev], state->ialign );
02379                         if( state->tstates )
02380                             GUI_DrawText( &opcbound, &rWin, state->basic.align, state->tstates[state->statePrev], ~0u );
02381                     }
02382                     if( offx < 0 )
02383                     {
02384                         RectLeftTo( rWin, rWin.left+RectWide(rWin) );
02385                     }
02386                     else if( offx > 0 )
02387                     {
02388                         RectLeftTo( rWin, rWin.left-RectWide(rWin) );
02389                     }
02390                     if( offy < 0 )
02391                     {
02392                         RectTopTo( rWin, rWin.top+RectHigh(rWin) );
02393                     }
02394                     else if( offy > 0 )
02395                     {
02396                         RectTopTo( rWin, rWin.top-RectHigh(rWin) );
02397                     }
02398                     if( state->states )
02399                         GUI_AlignShape( &opcbound, &rWin, state->states[state->stateCurr], state->ialign );
02400                     if( state->tstates )
02401                         GUI_DrawText( &opcbound, &rWin, state->basic.align, state->tstates[state->stateCurr], ~0u );
02402                 }
02403                 OPC_NAMING(Shape)( &opc, state->basic.frames[guitb_Overlay], bound.left, bound.top );
02404                 if( state->basic.text && *state->basic.text )
02405                 {
02406                     /* Draw any text that goes with the button */
02407                     GUI_DrawText( &opc, &bound, state->basic.align, state->basic.text, ~0u );
02408                 }
02409                 if( bFocus )
02410                 {
02411                     OPC_NAMING(Shape)( &opc, state->basic.frames[guitb_FocusOver], bound.left, bound.top );
02412                     /* Show arrows when focused, hide when not */
02413                     OPC_NAMING(Shape)( &opc, la, bound.left, bound.top );
02414                     OPC_NAMING(Shape)( &opc, ra, bound.left, bound.top );
02415                 }
02416             }
02417         }
02418         break;
02419     case GUI_Init:
02420         {
02421             GUI_Def_State(gui,control,GUICS_DEFAULT,GUI_CENTER|GUI_BOTTOM);
02422             TB_REPEAT_CANCEL();
02423             if( state->basic.cFrames > GUITumblerParts_COUNT )
02424             {
02425                 GUI_Tumbler_Setup( gui, GUI_Control_Index( gui, control ), state->basic.frames + GUITumblerParts_COUNT, GUI_CENTER|GUI_VCENTER, NULL, GUI_CENTER|GUI_BOTTOM, state->basic.cFrames - GUITumblerParts_COUNT, 8, 0 );
02426             }
02427             else
02428             {
02429                 GUI_Tumbler_Setup( gui, GUI_Control_Index( gui, control ), NULL, GUI_CENTER|GUI_VCENTER, NULL, GUI_CENTER|GUI_BOTTOM, 0, 5, 0 );
02430             }
02431         }
02432         break;
02433     default:
02434         break;
02435     }
02436 #undef TB_SETUP_REPEAT
02437 #undef TB_REPEAT_CANCEL
02438 }
02439 
02452 void _GUI_Tumbler_Setup( GUI* gui, int id, const OPCShape* const* shapes, unsigned shapeAlign, const GUI_CHAR* const* szz, unsigned szzAlign, size_t count, int transition, int curr )
02453 {
02454     const GUI_Control* control = GUI_Control_Get( gui, id );
02455     GUI_Tumbler_State* state = (GUI_Tumbler_State*)GUI_Control_Data( gui, control );
02456     GUI_Assert_Type( gui, id, guih_Tumbler );
02457     state->basic.align = szzAlign;
02458     state->offPrev = 0;
02459     state->states = shapes;
02460     state->tstates = szz;
02461     state->cStates = (int)count;
02462     state->cTransition = transition;
02463     state->ialign = shapeAlign;
02464     state->stateCurr = state->statePrev = curr;
02465     state->msRepeat = GUI_DefaultRepeat;
02466     if( count && !(state->basic.mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) )
02467         state->basic.mask |= GUICS_NOTIFY;
02468     GUI_Control_Dirty( gui, control );
02469 }
02470 
02477 void _GUI_Tumbler_SetFrame( GUI* gui, int id, int curr )
02478 {
02479     const GUI_Control* control = GUI_Control_Get( gui, id );
02480     GUI_Tumbler_State* state = (GUI_Tumbler_State*)GUI_Control_Data( gui, control );
02481     GUI_Assert_Type( gui, id, guih_Tumbler );
02482     state->offPrev = 0;
02483     state->stateCurr = curr;
02484     state->basic.mask |= GUICS_NOTIFY;
02485     GUI_Control_Dirty( gui, control );
02486 }
02487 
02488 
02494 void GUI_Ctrl_GUI( struct GUI* gui, const struct GUI_Control* control, GUI_Message msg )
02495 {
02496     GUI_Control_State* state = GUI_Control_Data( gui, control );
02497     GUI* pGui = (GUI*)(state+1);
02498     /*
02499      * Rather than assert the order of initialization, just make sure gui's set up
02500      */
02501     pGui->parent = gui;
02502     pGui->control = control;
02503     switch( msg )
02504     {
02505     case GUI_PaintCtrl:
02506     case GUI_CycleCtrl:
02507         return;
02508 
02509     case GUI_Focus:
02510         /* Embedded GUI control focus */
02511         if( GUI_Control_IsFocused( gui, control ) )
02512         {
02513             /* We have gained focus */
02514             if( pGui->focus < 0 )
02515             {
02516                 GUI_SetFocus(pGui,0);
02517                 GUI_Control_Dirty( gui, control );
02518             }
02519         }
02520         else
02521         {
02522             /* We have lost focus */
02523             if( pGui->focus != -1 )
02524             {
02525                 /* De-focus this it we were embedded, and lost focus */
02526                 pGui->focus = -1;
02527                 GUI_Control_Dirty( gui, control );
02528             }
02529         }
02530         return;
02531 
02532     case GUI_Cycle:
02533         /* Dump out of cycle */
02534         if( state->mask & GUICS_INVISIBLE )
02535             return;
02536 
02537         /* Cycle GUI handler */
02538         pGui->offx = gui->offx + state->offx + control->bound.left;
02539         pGui->offy = gui->offy + state->offy + control->bound.top;
02540         if( (state->mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) != (GUICS_INVISIBLE|GUICS_NOFOCUS) )
02541             pGui->handler( pGui, GUI_Cycle );
02542         /* Do notifies in contained gui */
02543         GUI_CallNotifies(pGui);
02544 #ifdef SIMPLE_DIRTY
02545         RectUnionRect( gui->dirty, pGui->dirty );
02546 #endif
02547         return;
02548 
02549     case GUI_Paint:
02550         /* Offset to match parent panning */
02551         pGui->dirty = gui->dirty;
02552         pGui->offx = gui->offx + state->offx + control->bound.left;
02553         pGui->offy = gui->offy + state->offy + control->bound.top;
02554         pGui->handler( pGui, GUI_Paint );
02555         return;
02556 
02557     case GUI_Init:
02558         /* Actual initialization should be invoked by user's GUI_Init handler */
02559         GUI_Def_State(gui,control,GUICS_DEFAULT,GUI_LEFT);
02560         return;
02561 
02562     case GUI_Destroy:
02563     default:
02564         break;
02565     }
02566     pGui->handler( pGui, msg );
02567 }
02568 
02569 
02576 void _GUI_Default( struct GUI* gui, GUI_Message msg )
02577 {
02578     switch( msg )
02579     {
02580 
02581     case GUI_CycleCtrl:
02582         /*
02583             Cycle a control:
02584                 Control ID is in iControl
02585                 Call default before/after your hook to control (or never) how your handling is mixed with the control
02586         */
02587         GUI_Control_handle( gui, GUI_Control_Get( gui, gui->iControl ), GUI_Cycle );
02588         break;
02589 
02590     case GUI_PaintCtrl:
02591         /*
02592             Paint a control:
02593                 Control ID is in iControl
02594                 Call default before/after your hook to control (or never) how your content is mixed with the control
02595         */
02596         GUI_Control_handle( gui, GUI_Control_Get( gui, gui->iControl ), GUI_Paint );
02597         break;
02598 
02599     case GUI_Cycle:
02600         {
02601             /* Clear notifies */
02602             pointer_foreach_const( GUI_Control, gui->list, gui->cControl, control )
02603             {
02604                 GUI_Control_State* state = GUI_Control_Data( gui, control );
02605                 state->mask &= ~GUICS_NOTIFY;
02606             }
02607         }
02608 #ifdef GUI_GetPointer
02609         /* Do pointer/mouse/finger focus magic */
02610         if( !gui->parent || GUI_Control_IsFocused( gui->parent, gui->control ) )
02611         {
02612             int x, y;
02613             Rect bound;
02614             GUI_GetPointer( x, y );
02615             {
02616                 pointer_foreach_const_reverse( GUI_Control, gui->list, gui->cControl, control )
02617                 {
02618                     GUI_Control_Bound( gui, control, &bound );
02619                     if( !(GUI_Control_Data( gui, control )->mask & (GUICS_INVISIBLE|GUICS_NOFOCUS)) && RectPtInRect( bound, x, y ) )
02620                     {
02621                         if( gui->focus >= 0 )
02622                         {
02623                             const GUI_Control* oldFocus = GUI_Control_Get( gui, gui->focus );
02624                             if( oldFocus != control )
02625                             {
02626                                 GUI_Control_Dirty( gui, oldFocus );
02627                                 GUI_Control_Dirty( gui, control );
02628                                 gui->focus = control - gui->list;
02629                                 gui->mask |= GUIM_FOCUSCHANGED;
02630                             }
02631                         }
02632                         else
02633                         {
02634                             gui->focus = control - gui->list;
02635                             GUI_Control_Dirty( gui, control );
02636                             gui->mask |= GUIM_FOCUSCHANGED;
02637                         }
02638                         break;
02639                     }
02640                 }
02641             }
02642         }
02643 #endif
02644         /* Now cycle the controls */
02645         for( gui->iControl = 0; gui->iControl < gui->cControl; ++gui->iControl )
02646             gui->handler(gui, GUI_CycleCtrl);
02647         break;
02648 
02649     case GUI_Paint: 
02650         /*
02651             Redraw the GUI, if it's dirty
02652             Hook and call GUI_Default afterwards to draw things behind under application control
02653             Hook and call GUI_Default before to draw things on top under application control
02654             Use GUI_PaintCtrl, or define a sf_, if you have something specific to do in the middle
02655         */
02656         {
02657             OPC opc;
02658             const Rect* curr;
02659 #ifdef SIMPLE_DIRTY
02660             if( RectEmpty(gui->dirty) )
02661             {
02662                 return;
02663             }
02664             else
02665             {
02666                 curr = &gui->dirty;
02667             }
02668             gui->mask |= GUIM_INPAINT;
02669 #else
02670             int cDirty;
02671             if( gui->parent )
02672             {
02673                 /* Child windows don't iterate the dirty list recursively */
02674                 curr = &gui->parent->dirty;
02675                 cDirty = 1;
02676             }
02677             else
02678             {
02679                 /* Top-level windows need to iterate whole list */
02680                 curr = gui->cdirty->dirty;
02681                 cDirty = gui->cdirty->cDirty;
02682             }
02683             /* Let external code know that paint is going on */
02684             gui->mask |= GUIM_INPAINT;
02685             while( cDirty-- )
02686 #endif  
02687             {
02688                 /* Set our 'dirty' rectangle */
02689                 gui->dirty = *curr;
02690                 OPC_NAMING(Clip)( &opc, &gui->opc, curr );
02691                 /* Render background */
02692                 OPC_NAMING(Shape)( &opc, gui->bg, gui->offx,gui->offy );
02693                 /* Render controls in order */
02694                 for( gui->iControl = 0; gui->iControl < gui->cControl; ++gui->iControl )
02695                 {
02696 
02697                     if( !( GUI_Control_Get_Mask( gui, gui->iControl ) & GUICS_INVISIBLE) )
02698                     {
02699                         gui->handler(gui, GUI_PaintCtrl);
02700                     }
02701                 }
02702                 /* Render overlay */
02703                 OPC_NAMING(Shape)( &opc, gui->ov, gui->offx,gui->offy );
02704                 curr++;
02705             }
02706             /* Let external code know that paint is finished */
02707             gui->mask &= ~GUIM_INPAINT;
02708             /* It's up to external code to clear the dirty list */
02709         }
02710         RectClear(gui->dirty);
02711         break;
02712 
02713     case GUI_Init:  /* Do initializations, if it's dirty */
02714         {
02715             /* Initialize trivial dirty rectangle handler */
02716             GUI_Dirty( gui );
02717             {
02718                 /* Initialize controls */
02719                 pointer_foreach_const( GUI_Control, gui->list, gui->cControl, control )
02720                     GUI_Control_handle( gui, control, GUI_Init );
02721             }
02722             /* Set focus at earliest enabled, visible control */
02723             GUI_SetFocus( gui, 0 );
02724             gui->mask = GUIM_ALIVE;
02725         }
02726         break;
02727 
02728     case GUI_Destroy: /* If anything grabbed up a resource, release it. */
02729         {
02730             pointer_foreach_const( GUI_Control, gui->list, gui->cControl, control )
02731                 GUI_Control_handle( gui, control, GUI_Destroy );
02732             GUI_Dirty_Rect( gui, &gui->opc.clip );
02733             gui->cControl = 0; /* Note, if we were in Cycle, Notify, Paint, etc. loops, this stops it. */
02734             gui->mask = 0;
02735         }
02736         break;
02737 
02738     /* Eatme events */
02739     case GUI_Focus:
02740     case GUI_Notify:
02741     default:
02742         break;
02743     }
02744 }
02745 
02746 #ifndef NO_GUI_BLIB
02747 
02748 #include "ctl/blib.h"
02749 /*
02750  * Lookup how big various mutable data for controls are in memory
02751  */
02752 #define XENUM(tag,verbose,data) sizeof(data),
02753 static const size_t lutRequirements[] =
02754 {
02755     EDEF_HANDLERS(XENUM)
02756 };
02757 #undef XENUM
02758 
02776 size_t GUI_BlibNeeds( const void* pData, size_t size, size_t myExtra )
02777 {
02778     /*
02779      * Data is BLIB of BLIBs.
02780      * Tally what each control needs for a total, either so you can allocate
02781      * or so you can assert some static buffer has enough.
02782      */
02783     const BLIB* blib = pData;
02784     if( BLIB_Valid( blib, size ) && BLIB_User(blib) == *((uint32*)"GUI") )
02785     {
02786         size_t ret = (sizeof(GUI) + myExtra + 7) & ~7u;
02787         BLIB_foreach(blib,curr)
02788         {
02789             const BLIB* blibCurr = (const BLIB*)curr;
02790             uint32 user = BLIB_User( blibCurr );
02791             if( user >= GUIHandlers_COUNT )
02792                 return 0;
02793             /* That's size of control data, sizeof control struct in list, sizeof vtab entry, sizeof sprite table */
02794             switch( user )
02795             {
02796             case guih_Invalid: default:
02797                 return 0;
02798 
02799             case guih_Background:
02800             case guih_Overlay:
02801                 break;
02802 
02803             case guih_GUI:
02804             case guih_ArtResource:
02805             case guih_StaticFrame:
02806             case guih_Button:
02807             case guih_Checkbox:
02808             case guih_Animation:
02809             case guih_Scrollbar:
02810             case guih_Ticker:
02811             case guih_Tumbler:
02812                 ret += lutRequirements[user] + sizeof(GUI_Control) + sizeof(GUI_Control*) + sizeof(GUI_Control*) + (BLIB_Count( blibCurr ) * sizeof(OPCShape*));
02813                 break;
02814 
02815             }
02816         }
02817         return ret;
02818     }
02819     return 0;
02820 }
02821 
02822 /* Sort by x, then y */
02823 int qsGCA_vtab( const GUI_Control** p1, const GUI_Control** p2 )
02824 {
02825     int diffX, diffY, x1, y1, x2, y2;
02826     RectCenterPt((*p1)->bound,x1,y1);
02827     RectCenterPt((*p2)->bound,x2,y2);
02828     diffY = y1-y2;
02829     diffX = x1-x2;
02830     if( abs( diffX ) > GUI_TAB_IGNORE )
02831         return diffX;
02832     return diffY;
02833 }
02834 
02835 
02836 /* Sort by y, then x */
02837 int qsGCA_htab( const GUI_Control** p1, const GUI_Control** p2 )
02838 {
02839     int diffX, diffY, x1, y1, x2, y2;
02840     RectCenterPt((*p1)->bound,x1,y1);
02841     RectCenterPt((*p2)->bound,x2,y2);
02842     diffY = y1-y2;
02843     diffX = x1-x2;
02844     if( abs(diffY) > GUI_TAB_IGNORE )
02845         return diffY;
02846     return diffX;
02847 }
02848 
02880 GUI* GUI_BlibInit( const void* pData, size_t size, size_t myExtra, void* pguiBuff, GUI_handler handler, void* param, const OPC* opc
02881 #ifdef SIMPLE_DIRTY
02882     )
02883 #else
02884   , ClipRect* cliprect )
02885 #endif
02886 {
02887     GUI* gui = (GUI*)pguiBuff;
02888     const BLIB* blib = pData;
02889     myExtra = (myExtra + 7) & ~7;
02890     if( BLIB_Valid( blib, size ) && BLIB_User(blib) == *((uint32*)"GUI") )
02891     {
02892         /*
02893          * Pass 1: Work out where things begin and end
02894          */
02895         GUI_Control* list;          /* Main control table */
02896         GUI_Control** htab;         /* Main control table */
02897         GUI_Control** vtab;         /* Vertical tab table */
02898         const OPCShape** sptab;     /* Sprite lookup table */
02899         {
02900             size_t offset = (sizeof(GUI) + myExtra + 7) & ~7u;
02901             size_t count = 0;
02902             size_t cControl = 0;
02903             BLIB_foreach(blib,curr)
02904             {
02905                 const BLIB* blibCurr = (const BLIB*)curr;
02906                 GUIHandlers user = (GUIHandlers)BLIB_User( blibCurr );
02907                 if( user >= GUIHandlers_COUNT )
02908                     return 0;
02909                 switch( user )
02910                 {
02911                 case guih_Invalid: default:
02912                     return NULL;
02913 
02914                 case guih_Background:
02915                     gui->bg = (const OPCShape*)(BLIB_SIZE( blib ) ? BLIB_ELEMENT_PTR( blibCurr, 0 ) : NULL);
02916                     break;
02917                 case guih_Overlay:
02918                     gui->ov = (const OPCShape*)(BLIB_SIZE( blib ) ? BLIB_ELEMENT_PTR( blibCurr, 0 ) : NULL);
02919                     break;
02920 
02921                 case guih_ArtResource:
02922                     count++;
02923                     break;
02924                 case guih_GUI:
02925                     user = guih_StaticFrame;
02926                 case guih_StaticFrame:
02927                 case guih_Button:
02928                 case guih_Checkbox:
02929                 case guih_Animation:
02930                 case guih_Scrollbar:
02931                 case guih_Ticker:
02932                 case guih_Tumbler:
02933                     offset += lutRequirements[user];
02934                     count++;
02935                     cControl++;
02936                     break;
02937                 }
02938             }
02939             /* Work out beginnings of various tables */
02940             gui->parent = NULL;
02941             gui->list = list = (GUI_Control*)((uint8*)pguiBuff + offset);
02942             gui->htab = htab = (GUI_Control**)(list + count);
02943             gui->vtab = vtab = (GUI_Control**)(htab + count);
02944             sptab = (const OPCShape**)(vtab + count);
02945             gui->bg = gui->ov = NULL;
02946             gui->cControl = cControl;
02947             gui->focus = 0;
02948             gui->offx = gui->offy = 0;
02949             gui->opc = *opc;
02950             gui->param = param;
02951 #ifndef GUI_NO_GENERATOR
02952             state_init( gui->state );
02953 #endif
02954             gui->dirty = opc->clip;
02955 #ifndef SIMPLE_DIRTY
02956             gui->cdirty = cliprect;
02957 #endif
02958             gui->handler = handler ? handler : _GUI_Default;
02959         }
02960         /*
02961          * Pass 2: Now that we know where things go, put things in it
02962          */
02963         {
02964             size_t offset = sizeof(GUI);
02965             BLIB_foreach(blib,curr)
02966             {
02967                 const BLIB* blibCurr = (const BLIB*)curr;
02968                 GUIHandlers user = (GUIHandlers)BLIB_User( blibCurr );
02969                 switch( user )
02970                 {
02971                 case guih_Invalid: default:
02972                     return NULL;
02973 
02974                 case guih_Background:
02975                     gui->bg = (const OPCShape*)(BLIB_SIZE( blib ) ? BLIB_ELEMENT_PTR( blibCurr, 0 ) : NULL);
02976                     break;
02977                 case guih_Overlay:
02978                     gui->ov = (const OPCShape*)(BLIB_SIZE( blib ) ? BLIB_ELEMENT_PTR( blibCurr, 0 ) : NULL);
02979                     break;
02980 
02981                 case guih_GUI:
02982                     user = guih_StaticFrame;
02983                 case guih_ArtResource:
02984                 case guih_StaticFrame:
02985                 case guih_Button:
02986                 case guih_Checkbox:
02987                 case guih_Animation:
02988                 case guih_Scrollbar:
02989                 case guih_Ticker:
02990                 case guih_Tumbler:
02991                     list->type = user;
02992                     list->offData = offset;
02993                     /*
02994                      * Element 0 of the BLIB is the bounding box for the control
02995                      * Element 1~BLIB_COUNT( blib ) are sprites
02996                      */     
02997                     assert( BLIB_COUNT( blibCurr ) >= 1 );
02998                     list->cState = BLIB_COUNT( blibCurr )-1;
02999                     list->state = list->cState ? sptab : NULL;
03000                     assert( BLIB_ELEMENT_SIZE( blibCurr, 0 ) == sizeof(Rect) );
03001                     list->bound = *((const Rect*)BLIB_ELEMENT_PTR( blibCurr, 0 ));
03002                     list->params = NULL;
03003                     {
03004                         size_t ishape;
03005                         for( ishape = 1; ishape <= list->cState; ++ishape )
03006                         {
03007                             const OPCShape* shape = (const OPCShape*)(BLIB_ELEMENT_SIZE( blibCurr, ishape ) ? BLIB_ELEMENT_PTR( blibCurr, ishape ) : NULL);
03008                             *sptab++ = shape;
03009                         }
03010                     }
03011                     offset += lutRequirements[user];
03012                     *htab++ = list;
03013                     *vtab++ = list++;
03014                     break;
03015                 }
03016             }
03017         }
03018         /* Sort tabbing arrays */
03019         array_qsort( GUI_Control*, (GUI_Control**)gui->htab, gui->cControl, qsGCA_htab );
03020         array_qsort( GUI_Control*, (GUI_Control**)gui->vtab, gui->cControl, qsGCA_vtab );
03021 
03022         /* We built it, so initialize it & run with it */
03023         gui->handler(gui,GUI_Init);
03024         return gui;
03025     }
03026     return NULL;
03027 }
03028 #endif /* NO_GUI_BLIB */

Generated on Fri Jan 2 15:28:34 2009 for Squat by  doxygen 1.5.6