diff options
-rw-r--r-- | assets/ui/ingame.menu | 2 | ||||
-rw-r--r-- | assets/ui/ingame_options.menu | 33 | ||||
-rw-r--r-- | assets/ui/joinserver.menu | 3 | ||||
-rw-r--r-- | assets/ui/menudef.h | 3 | ||||
-rw-r--r-- | assets/ui/options.menu | 64 | ||||
-rw-r--r-- | assets/ui/tremulous_humanarmoury.menu | 10 | ||||
-rw-r--r-- | src/cgame/cg_main.c | 8 | ||||
-rw-r--r-- | src/sdl/sdl_glimp.c | 19 | ||||
-rw-r--r-- | src/ui/ui_local.h | 57 | ||||
-rw-r--r-- | src/ui/ui_main.c | 149 | ||||
-rw-r--r-- | src/ui/ui_shared.c | 1405 | ||||
-rw-r--r-- | src/ui/ui_shared.h | 96 |
12 files changed, 904 insertions, 945 deletions
diff --git a/assets/ui/ingame.menu b/assets/ui/ingame.menu index d51dba55..808287ea 100644 --- a/assets/ui/ingame.menu +++ b/assets/ui/ingame.menu @@ -35,7 +35,7 @@ visible MENU_FALSE fullScreen 0 outOfBoundsClick // this closes the window if it gets a click out of the rectangle - rect 0 0 640 48 + rect 0 0 1280 56 focusColor 1 .75 0 1 disableColor .5 .5 .5 1 backColor 0 0 0 1 diff --git a/assets/ui/ingame_options.menu b/assets/ui/ingame_options.menu index 62aec9b7..ad601938 100644 --- a/assets/ui/ingame_options.menu +++ b/assets/ui/ingame_options.menu @@ -24,6 +24,8 @@ #define SCONTENT_W (W-(SIDEBUTT_W+(2*BORDER))) #define SCONTENT_OFF (0-(SCONTENT_W/2)) +#define RESCOMBO_OFF 8 + #define ELEM_H 16 menuDef @@ -1585,17 +1587,36 @@ { name ghardware group optionsGrp - type ITEM_TYPE_COMBO + type ITEM_TYPE_TEXT text "Video Mode:" - feeder FEEDER_RESOLUTIONS - rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) SCONTENT_W ELEM_H + rect SCONTENT_X (SCONTENT_Y+(2*ELEM_H)) (SCONTENT_W/2) ELEM_H textalign ALIGN_RIGHT textvalign VALIGN_CENTER - textalignx SCONTENT_OFF textscale .25 forecolor 1 1 1 1 - visible MENU_FALSE - action + visible MENU_TRUE + } + + itemDef + { + name ghardware + group optionsGrp + rect (SCONTENT_X+(SCONTENT_W/2)+RESCOMBO_OFF) (SCONTENT_Y+(2*ELEM_H)) ((SCONTENT_W/2)-(2*RESCOMBO_OFF)) ELEM_H + type ITEM_TYPE_COMBOBOX + style WINDOW_STYLE_FILLED + elementwidth ((SCONTENT_W/2)-(2*BORDER)) + elementheight ELEM_H + dropitems 5 + textscale .25 + elementtype LISTBOX_TEXT + feeder FEEDER_RESOLUTIONS + border WINDOW_BORDER_FULL + borderColor 0.5 0.5 0.5 1 + forecolor 1 1 1 1 + backcolor 0 0 0 1 + outlinecolor 0.1 0.1 0.1 0.5 + visible MENU_TRUE + doubleclick { play "sound/misc/menu1.wav"; } diff --git a/assets/ui/joinserver.menu b/assets/ui/joinserver.menu index 29ad442a..3b86c7fd 100644 --- a/assets/ui/joinserver.menu +++ b/assets/ui/joinserver.menu @@ -206,7 +206,8 @@ rect (TOP_X+(2*TOPBUTT_W)) (TOP_Y+TOPBUTT_H) (TOPBUTT_W) (TOPBUTT_H) textalign ALIGN_LEFT textvalign VALIGN_CENTER - forecolor 1 1 1 1 + textalignx TOP_TOFF_X + forecolor 1 1 1 1 visible MENU_TRUE decoration } diff --git a/assets/ui/menudef.h b/assets/ui/menudef.h index 49792096..cd30f772 100644 --- a/assets/ui/menudef.h +++ b/assets/ui/menudef.h @@ -11,8 +11,9 @@ enum ITEM_TYPE_CHECKBOX, // check box ITEM_TYPE_EDITFIELD, // editable text, associated with a cvar ITEM_TYPE_SAYFIELD, // the chat field - ITEM_TYPE_COMBO, // drop down list + ITEM_TYPE_CYCLE, // cycling list ITEM_TYPE_LISTBOX, // scrollable list + ITEM_TYPE_COMBOBOX, // drop down scrollable list ITEM_TYPE_MODEL, // model ITEM_TYPE_OWNERDRAW, // owner draw, has an associated ownerdraw number ITEM_TYPE_NUMERICFIELD, // editable text, associated with a cvar diff --git a/assets/ui/options.menu b/assets/ui/options.menu index af602bc2..fc405a1a 100644 --- a/assets/ui/options.menu +++ b/assets/ui/options.menu @@ -3,14 +3,17 @@ { \\ FRONT END OPTIONS BOX \\ -#define X 0 -#define Y 20 -#define W 250 -#define H 280 -#define TOFF_X (0-(W/2)) -#define ELEM_H 16 -#define BUTT_W 35 -#define BUTT_H 35 +#define X 0 +#define Y 20 +#define W 250 +#define H ((10*(ELEM_H+ELEM_GAP))+120) +#define TOFF_X (0-(W/2)) +#define ELEM_H 16 +#define ELEM_GAP 4 +#define BUTT_W 35 +#define BUTT_H 35 +#define BORDER 10 +#define RESCOMBO_OFF 8 menuDef { @@ -66,7 +69,7 @@ text "Video Quality:" cvar "ui_glCustom" cvarFloatList { "High Quality" 0 "Normal" 1 "Fast" 2 "Fastest" 3 "Custom" 4 } - rect X (Y+ELEM_H) W ELEM_H + rect X (Y+(ELEM_H+ELEM_GAP)) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER @@ -82,17 +85,34 @@ itemDef { - type ITEM_TYPE_COMBO + type ITEM_TYPE_TEXT text "Video Mode:" - feeder FEEDER_RESOLUTIONS - rect X (Y+(2*ELEM_H)) W ELEM_H + rect X (Y+(2*(ELEM_H+ELEM_GAP))) (W/2) ELEM_H textalign ALIGN_RIGHT - textalignx TOFF_X textvalign VALIGN_CENTER textscale .25 forecolor 1 1 1 1 visible MENU_TRUE - action + } + + itemDef + { + rect ((W/2)+RESCOMBO_OFF) (Y+(2*(ELEM_H+ELEM_GAP))) ((W/2)-(2*BORDER)) ELEM_H + type ITEM_TYPE_COMBOBOX + style WINDOW_STYLE_FILLED + elementwidth ((W/2)-(2*BORDER)) + elementheight ELEM_H + dropitems 5 + textscale .25 + elementtype LISTBOX_TEXT + feeder FEEDER_RESOLUTIONS + border WINDOW_BORDER_FULL + borderColor 0.5 0.5 0.5 1 + forecolor 1 1 1 1 + backcolor 0 0 0 1 + outlinecolor 0.1 0.1 0.1 0.5 + visible MENU_TRUE + doubleclick { play "sound/misc/menu1.wav"; } @@ -103,7 +123,7 @@ type ITEM_TYPE_SLIDER text "Video Brightness:" cvarfloat "r_gamma" 1 .5 2 - rect X (Y+(3*ELEM_H)) W ELEM_H + rect X (Y+(3*(ELEM_H+ELEM_GAP))) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER @@ -119,7 +139,7 @@ type ITEM_TYPE_SLIDER text "Effects Volume:" cvarfloat "s_volume" 0.7 0 1 - rect X (Y+(4*ELEM_H)) W ELEM_H + rect X (Y+(4*(ELEM_H+ELEM_GAP))) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER @@ -133,7 +153,7 @@ type ITEM_TYPE_SLIDER text "Music Volume:" cvarfloat "s_musicvolume" 0.25 0 1 - rect X (Y+(5*ELEM_H)) W ELEM_H + rect X (Y+(5*(ELEM_H+ELEM_GAP))) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER @@ -147,7 +167,7 @@ type ITEM_TYPE_YESNO text "OpenAL Sound:" cvar "s_useOpenAL" - rect X (Y+(6*ELEM_H)) W ELEM_H + rect X (Y+(6*(ELEM_H+ELEM_GAP))) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER @@ -167,7 +187,7 @@ type ITEM_TYPE_SLIDER text "Mouse Sensitivity:" cvarfloat "sensitivity" 5 1 30 - rect X (Y+(7*ELEM_H)) W ELEM_H + rect X (Y+(7*(ELEM_H+ELEM_GAP))) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER @@ -181,7 +201,7 @@ type ITEM_TYPE_YESNO text "Invert Mouse:" cvar "ui_mousePitch" - rect X (Y+(8*ELEM_H)) W ELEM_H + rect X (Y+(8*(ELEM_H+ELEM_GAP))) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER @@ -203,7 +223,7 @@ text "Network Connection:" cvar "rate" cvarFloatList { "<=28.8k" 2500 "33.6k" 3000 "56k" 4000 "ISDN" 5000 "LAN/CABLE/xDSL" 25000 } - rect X (Y+(9*ELEM_H)) W ELEM_H + rect X (Y+(9*(ELEM_H+ELEM_GAP))) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER @@ -221,7 +241,7 @@ type ITEM_TYPE_YESNO text "Allow Auto Download:" cvar "cl_allowDownload" - rect X (Y+(10*ELEM_H)) W ELEM_H + rect X (Y+(10*(ELEM_H+ELEM_GAP))) W ELEM_H textalign ALIGN_RIGHT textalignx TOFF_X textvalign VALIGN_CENTER diff --git a/assets/ui/tremulous_humanarmoury.menu b/assets/ui/tremulous_humanarmoury.menu index 4234259e..2df829fe 100644 --- a/assets/ui/tremulous_humanarmoury.menu +++ b/assets/ui/tremulous_humanarmoury.menu @@ -72,12 +72,11 @@ backcolor 0.2 0.2 0.2 1 outlinecolor 0.1 0.1 0.1 0.5 visible MENU_TRUE + resetonfeederchange doubleclick { play "sound/misc/menu1.wav"; uiScript BuyFromArmoury; - reset selllist; - reset buylist; } } @@ -98,12 +97,11 @@ backcolor 0.2 0.2 0.2 1 outlinecolor 0.1 0.1 0.1 0.5 visible MENU_TRUE + resetonfeederchange doubleclick { play "sound/misc/menu1.wav"; uiScript SellToArmoury; - reset selllist; - reset buylist; } } @@ -145,8 +143,6 @@ { play "sound/misc/menu1.wav"; uiScript BuyFromArmoury; - reset selllist; - reset buylist; } } @@ -187,8 +183,6 @@ { play "sound/misc/menu1.wav"; uiScript SellToArmoury; - reset selllist; - reset buylist; } } } diff --git a/src/cgame/cg_main.c b/src/cgame/cg_main.c index 61888f92..4e7ca1ab 100644 --- a/src/cgame/cg_main.c +++ b/src/cgame/cg_main.c @@ -1349,7 +1349,7 @@ static qboolean CG_OwnerDrawHandleKey( int ownerDraw, int key ) } -static int CG_FeederCount( float feederID ) +static int CG_FeederCount( int feederID ) { int i, count = 0; @@ -1442,7 +1442,7 @@ static qboolean CG_ClientIsReady( int clientNum ) return Com_ClientListContains( &ready, clientNum ); } -static const char *CG_FeederItemText( float feederID, int index, int column, qhandle_t *handle ) +static const char *CG_FeederItemText( int feederID, int index, int column, qhandle_t *handle ) { int scoreIndex = 0; clientInfo_t *info = NULL; @@ -1530,12 +1530,12 @@ static const char *CG_FeederItemText( float feederID, int index, int column, qha return ""; } -static qhandle_t CG_FeederItemImage( float feederID, int index ) +static qhandle_t CG_FeederItemImage( int feederID, int index ) { return 0; } -static void CG_FeederSelection( float feederID, int index ) +static void CG_FeederSelection( int feederID, int index ) { int i, count; int team = ( feederID == FEEDER_ALIENTEAM_LIST ) ? TEAM_ALIENS : TEAM_HUMANS; diff --git a/src/sdl/sdl_glimp.c b/src/sdl/sdl_glimp.c index 0c765b66..58e9c7ed 100644 --- a/src/sdl/sdl_glimp.c +++ b/src/sdl/sdl_glimp.c @@ -120,8 +120,12 @@ static int GLimp_CompareModes( const void *a, const void *b ) const float ASPECT_EPSILON = 0.001f; SDL_Rect *modeA = *(SDL_Rect **)a; SDL_Rect *modeB = *(SDL_Rect **)b; - float aspectDiffA = fabs( ( (float)modeA->w / (float)modeA->h ) - glConfig.displayAspect ); - float aspectDiffB = fabs( ( (float)modeB->w / (float)modeB->h ) - glConfig.displayAspect ); + float aspectA = (float)modeA->w / (float)modeA->h; + float aspectB = (float)modeB->w / (float)modeB->h; + int areaA = modeA->w * modeA->h; + int areaB = modeB->w * modeB->h; + float aspectDiffA = fabs( aspectA - glConfig.displayAspect ); + float aspectDiffB = fabs( aspectB - glConfig.displayAspect ); float aspectDiffsDiff = aspectDiffA - aspectDiffB; if( aspectDiffsDiff > ASPECT_EPSILON ) @@ -129,12 +133,7 @@ static int GLimp_CompareModes( const void *a, const void *b ) else if( aspectDiffsDiff < -ASPECT_EPSILON ) return -1; else - { - if( modeA->w == modeB->w ) - return modeA->h - modeB->h; - else - return modeA->w - modeB->w; - } + return areaA - areaB; } /* @@ -165,8 +164,8 @@ static void GLimp_DetectAvailableModes(void) for( numModes = 0; modes[ numModes ]; numModes++ ); - if(numModes > 1) - qsort( modes+1, numModes-1, sizeof( SDL_Rect* ), GLimp_CompareModes ); + if( numModes > 1 ) + qsort( modes, numModes, sizeof( SDL_Rect* ), GLimp_CompareModes ); for( i = 0; i < numModes; i++ ) { diff --git a/src/ui/ui_local.h b/src/ui/ui_local.h index 46210d02..71e568fe 100644 --- a/src/ui/ui_local.h +++ b/src/ui/ui_local.h @@ -291,7 +291,8 @@ typedef struct int nextFindPlayerRefresh; resolution_t resolutions[ MAX_RESOLUTIONS ]; - int numResolutions; + int numResolutions; + int resolutionIndex; qboolean inGameLoad; @@ -315,28 +316,28 @@ void UI_FillRect( float x, float y, float width, float height, const float // void trap_Print( const char *string ); void trap_Error( const char *string ); -int trap_Milliseconds( void ); +int trap_Milliseconds( void ); void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ); void trap_Cvar_Update( vmCvar_t *vmCvar ); void trap_Cvar_Set( const char *var_name, const char *value ); -float trap_Cvar_VariableValue( const char *var_name ); +float trap_Cvar_VariableValue( const char *var_name ); void trap_Cvar_VariableStringBuffer( const char *var_name, char *buffer, int bufsize ); void trap_Cvar_SetValue( const char *var_name, float value ); void trap_Cvar_Reset( const char *name ); void trap_Cvar_Create( const char *var_name, const char *var_value, int flags ); void trap_Cvar_InfoStringBuffer( int bit, char *buffer, int bufsize ); -int trap_Argc( void ); +int trap_Argc( void ); void trap_Argv( int n, char *buffer, int bufferLength ); void trap_Cmd_ExecuteText( int exec_when, const char *text ); // don't use EXEC_NOW! -int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ); +int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ); void trap_FS_Read( void *buffer, int len, fileHandle_t f ); void trap_FS_Write( const void *buffer, int len, fileHandle_t f ); void trap_FS_FCloseFile( fileHandle_t f ); -int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ); +int trap_FS_GetFileList( const char *path, const char *extension, char *listbuf, int bufsize ); int trap_FS_Seek( fileHandle_t f, long offset, int origin ); // fsOrigin_t -qhandle_t trap_R_RegisterModel( const char *name ); -qhandle_t trap_R_RegisterSkin( const char *name ); -qhandle_t trap_R_RegisterShaderNoMip( const char *name ); +qhandle_t trap_R_RegisterModel( const char *name ); +qhandle_t trap_R_RegisterSkin( const char *name ); +qhandle_t trap_R_RegisterShaderNoMip( const char *name ); void trap_R_ClearScene( void ); void trap_R_AddRefEntityToScene( const refEntity_t *re ); void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ); @@ -347,51 +348,51 @@ void trap_R_SetClipRegion( const float *region ); void trap_R_DrawStretchPic( float x, float y, float w, float h, float s1, float t1, float s2, float t2, qhandle_t hShader ); void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ); void trap_UpdateScreen( void ); -int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName ); +int trap_CM_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, float frac, const char *tagName ); void trap_S_StartLocalSound( sfxHandle_t sfx, int channelNum ); sfxHandle_t trap_S_RegisterSound( const char *sample, qboolean compressed ); void trap_Key_KeynumToStringBuf( int keynum, char *buf, int buflen ); void trap_Key_GetBindingBuf( int keynum, char *buf, int buflen ); void trap_Key_SetBinding( int keynum, const char *binding ); -qboolean trap_Key_IsDown( int keynum ); -qboolean trap_Key_GetOverstrikeMode( void ); +qboolean trap_Key_IsDown( int keynum ); +qboolean trap_Key_GetOverstrikeMode( void ); void trap_Key_SetOverstrikeMode( qboolean state ); void trap_Key_ClearStates( void ); -int trap_Key_GetCatcher( void ); +int trap_Key_GetCatcher( void ); void trap_Key_SetCatcher( int catcher ); void trap_GetClipboardData( char *buf, int bufsize ); void trap_GetClientState( uiClientState_t *state ); void trap_GetGlconfig( glconfig_t *glconfig ); -int trap_GetConfigString( int index, char* buff, int buffsize ); -int trap_LAN_GetServerCount( int source ); +int trap_GetConfigString( int index, char* buff, int buffsize ); +int trap_LAN_GetServerCount( int source ); void trap_LAN_GetServerAddressString( int source, int n, char *buf, int buflen ); void trap_LAN_GetServerInfo( int source, int n, char *buf, int buflen ); -int trap_LAN_GetServerPing( int source, int n ); -int trap_LAN_GetPingQueueCount( void ); +int trap_LAN_GetServerPing( int source, int n ); +int trap_LAN_GetPingQueueCount( void ); void trap_LAN_ClearPing( int n ); void trap_LAN_GetPing( int n, char *buf, int buflen, int *pingtime ); void trap_LAN_GetPingInfo( int n, char *buf, int buflen ); void trap_LAN_LoadCachedServers( void ); void trap_LAN_SaveCachedServers( void ); void trap_LAN_MarkServerVisible( int source, int n, qboolean visible ); -int trap_LAN_ServerIsVisible( int source, int n ); -qboolean trap_LAN_UpdateVisiblePings( int source ); -int trap_LAN_AddServer( int source, const char *name, const char *addr ); +int trap_LAN_ServerIsVisible( int source, int n ); +qboolean trap_LAN_UpdateVisiblePings( int source ); +int trap_LAN_AddServer( int source, const char *name, const char *addr ); void trap_LAN_RemoveServer( int source, const char *addr ); void trap_LAN_ResetPings( int n ); -int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen ); -qboolean trap_GetNews( qboolean force ); -int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ); -int trap_MemoryRemaining( void ); +int trap_LAN_ServerStatus( const char *serverAddress, char *serverStatus, int maxLen ); +qboolean trap_GetNews( qboolean force ); +int trap_LAN_CompareServers( int source, int sortKey, int sortDir, int s1, int s2 ); +int trap_MemoryRemaining( void ); void trap_R_RegisterFont( const char *pFontname, int pointSize, fontInfo_t *font ); void trap_S_StopBackgroundTrack( void ); void trap_S_StartBackgroundTrack( const char *intro, const char *loop ); -int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits ); -e_status trap_CIN_StopCinematic( int handle ); -e_status trap_CIN_RunCinematic ( int handle ); +int trap_CIN_PlayCinematic( const char *arg0, int xpos, int ypos, int width, int height, int bits ); +e_status trap_CIN_StopCinematic( int handle ); +e_status trap_CIN_RunCinematic ( int handle ); void trap_CIN_DrawCinematic ( int handle ); void trap_CIN_SetExtents ( int handle, int x, int y, int w, int h ); -int trap_RealTime( qtime_t *qtime ); +int trap_RealTime( qtime_t *qtime ); void trap_R_RemapShader( const char *oldShader, const char *newShader, const char *timeOffset ); void trap_SetPbClStatus( int status ); diff --git a/src/ui/ui_main.c b/src/ui/ui_main.c index 46961723..9dd52c18 100644 --- a/src/ui/ui_main.c +++ b/src/ui/ui_main.c @@ -235,10 +235,14 @@ void AssetCache( void ) void UI_DrawSides( float x, float y, float w, float h, float size ) { + float sizeY; + UI_AdjustFrom640( &x, &y, &w, &h ); + sizeY = size * uiInfo.uiDC.yscale; size *= uiInfo.uiDC.xscale; - trap_R_DrawStretchPic( x, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader ); - trap_R_DrawStretchPic( x + w - size, y, size, h, 0, 0, 0, 0, uiInfo.uiDC.whiteShader ); + + trap_R_DrawStretchPic( x, y + sizeY, size, h - ( sizeY * 2.0f ), 0, 0, 0, 0, uiInfo.uiDC.whiteShader ); + trap_R_DrawStretchPic( x + w - size, y + sizeY, size, h - ( sizeY * 2.0f ), 0, 0, 0, 0, uiInfo.uiDC.whiteShader ); } void UI_DrawTopBottom( float x, float y, float w, float h, float size ) @@ -633,7 +637,7 @@ static char *stristr( char *str, char *charset ) UI_BuildFindPlayerList ================== */ -static void UI_FeederSelection( float feederID, int index ); +static void UI_FeederSelection( int feederID, int index ); static void UI_BuildFindPlayerList( qboolean force ) { @@ -1172,15 +1176,11 @@ void UI_Refresh( int realtime ) if( Menu_Count() > 0 ) { - // paint all the menus - Menu_PaintAll(); - // refresh server browser list - UI_DoServerRefresh(); - // refresh server status + Menu_UpdateAll( ); + Menu_PaintAll( ); + UI_DoServerRefresh( ); UI_BuildServerStatus( qfalse ); - // refresh find player list UI_BuildFindPlayerList( qfalse ); - // refresh news UI_UpdateNews( qfalse ); } @@ -3416,12 +3416,14 @@ static void UI_RunMenuScript( char **args ) } } +static int UI_FeederInitialise( int feederID ); + /* ================== UI_FeederCount ================== */ -static int UI_FeederCount( float feederID ) +static int UI_FeederCount( int feederID ) { if( feederID == FEEDER_CINEMATICS ) return uiInfo.movieCount; @@ -3480,7 +3482,12 @@ static int UI_FeederCount( float feederID ) else if( feederID == FEEDER_TREMHUMANBUILD ) return uiInfo.humanBuildCount; else if( feederID == FEEDER_RESOLUTIONS ) - return uiInfo.numResolutions; + { + if( UI_FeederInitialise( feederID ) == uiInfo.numResolutions ) + return uiInfo.numResolutions + 1; + else + return uiInfo.numResolutions; + } return 0; } @@ -3505,16 +3512,39 @@ static const char *UI_SelectedMap( int index, int *actual ) return ""; } -static const char *UI_FeederItemText( float feederID, int index, int column, qhandle_t *handle ) +static int GCD( int a, int b ) { - static char info[MAX_STRING_CHARS]; - static char hostname[1024]; - static char cleaned[1024]; - static char clientBuff[32]; - static char resolution[MAX_STRING_CHARS]; - static int lastColumn = -1; - static int lastTime = 0; + int c; + + while( b != 0 ) + { + c = a % b; + a = b; + b = c; + } + return a; +} + +static const char *UI_DisplayAspectString( int w, int h ) +{ + int gcd = GCD( w, h ); + + w /= gcd; + h /= gcd; + + // For some reason 8:5 is usually referred to as 16:10 + if( w == 8 && h == 5 ) + { + w = 16; + h = 10; + } + + return va( "%d:%d", w, h ); +} + +static const char *UI_FeederItemText( int feederID, int index, int column, qhandle_t *handle ) +{ if( handle ) *handle = -1; @@ -3527,7 +3557,12 @@ static const char *UI_FeederItemText( float feederID, int index, int column, qha { if( index >= 0 && index < UI_FeederCount( feederID ) ) { - int ping; + static char info[MAX_STRING_CHARS]; + static char clientBuff[ 32 ]; + static char cleaned[ MAX_STRING_CHARS ]; + static int lastColumn = -1; + static int lastTime = 0; + int ping; if( lastColumn != column || lastTime > uiInfo.uiDC.realTime + 5000 ) { @@ -3539,12 +3574,6 @@ static const char *UI_FeederItemText( float feederID, int index, int column, qha ping = atoi( Info_ValueForKey( info, "ping" ) ); - if( ping == -1 ) - { - // if we ever see a ping that is out of date, do a server refresh - // UI_UpdatePendingPings(); - } - UI_EscapeEmoticons( cleaned, Info_ValueForKey( info, "hostname" ), sizeof( cleaned ) ); switch( column ) @@ -3554,10 +3583,11 @@ static const char *UI_FeederItemText( float feederID, int index, int column, qha return Info_ValueForKey( info, "addr" ); else { + static char hostname[1024]; + if( ui_netSource.integer == AS_LOCAL ) { - Com_sprintf( hostname, sizeof( hostname ), "%s [%s]", - cleaned, + Com_sprintf( hostname, sizeof( hostname ), "%s [%s]", cleaned, netnames[atoi( Info_ValueForKey( info, "nettype" ) )] ); return hostname; } @@ -3573,13 +3603,12 @@ static const char *UI_FeederItemText( float feederID, int index, int column, qha label+= 1; Com_sprintf( hostname, sizeof( hostname ), "%s %s", - label, - cleaned ); + label, cleaned ); } else { Com_sprintf( hostname, sizeof( hostname ), "%s", - cleaned ); + cleaned ); } // Strip leading whitespace @@ -3619,17 +3648,12 @@ static const char *UI_FeederItemText( float feederID, int index, int column, qha else if( feederID == FEEDER_NEWS ) { if( index >= 0 && index < uiInfo.newsInfo.numLines ) - { return uiInfo.newsInfo.text[index]; - } } else if( feederID == FEEDER_FINDPLAYER ) { if( index >= 0 && index < uiInfo.numFoundPlayerServers ) - { - //return uiInfo.foundPlayerServerAddresses[index]; return uiInfo.foundPlayerServerNames[index]; - } } else if( feederID == FEEDER_PLAYER_LIST ) { @@ -3649,13 +3673,13 @@ static const char *UI_FeederItemText( float feederID, int index, int column, qha { case 1: // am I ignoring him - return ( Com_ClientListContains( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ], - uiInfo.clientNums[ index ] ) ) ? "X" : ""; + return Com_ClientListContains( &uiInfo.ignoreList[ uiInfo.myPlayerIndex ], + uiInfo.clientNums[ index ] ) ? "X" : ""; case 2: // is he ignoring me - return ( Com_ClientListContains( &uiInfo.ignoreList[ index ], - uiInfo.playerNumber ) ) ? "X" : ""; + return Com_ClientListContains( &uiInfo.ignoreList[ index ], + uiInfo.playerNumber ) ? "X" : ""; default: return uiInfo.playerNames[index]; @@ -3729,20 +3753,24 @@ static const char *UI_FeederItemText( float feederID, int index, int column, qha } else if( feederID == FEEDER_RESOLUTIONS ) { - int i; - int w = trap_Cvar_VariableValue( "r_width" ); - int h = trap_Cvar_VariableValue( "r_height" ); + static char resolution[MAX_STRING_CHARS]; + int w, h; - for( i = 0; i < uiInfo.numResolutions; i++ ) + if( index >= 0 && index < uiInfo.numResolutions ) { - if( w == uiInfo.resolutions[ i ].w && h == uiInfo.resolutions[ i ].h ) - { - Com_sprintf( resolution, sizeof( resolution ), "%dx%d", w, h ); - return resolution; - } + w = uiInfo.resolutions[ index ].w; + h = uiInfo.resolutions[ index ].h; + + Com_sprintf( resolution, sizeof( resolution ), "%dx%d (%s)", w, h, + UI_DisplayAspectString( w, h ) ); + + return resolution; } + w = (int)trap_Cvar_VariableValue( "r_width" ); + h = (int)trap_Cvar_VariableValue( "r_height" ); Com_sprintf( resolution, sizeof( resolution ), "Custom (%dx%d)", w, h ); + return resolution; } @@ -3750,7 +3778,7 @@ static const char *UI_FeederItemText( float feederID, int index, int column, qha } -static qhandle_t UI_FeederItemImage( float feederID, int index ) +static qhandle_t UI_FeederItemImage( int feederID, int index ) { if( feederID == FEEDER_MAPS ) { @@ -3770,7 +3798,7 @@ static qhandle_t UI_FeederItemImage( float feederID, int index ) return 0; } -static void UI_FeederSelection( float feederID, int index ) +static void UI_FeederSelection( int feederID, int index ) { static char info[MAX_STRING_CHARS]; @@ -3874,12 +3902,17 @@ static void UI_FeederSelection( float feederID, int index ) uiInfo.humanBuildIndex = index; else if( feederID == FEEDER_RESOLUTIONS ) { - trap_Cvar_Set( "r_width", va( "%d", uiInfo.resolutions[ index ].w ) ); - trap_Cvar_Set( "r_height", va( "%d", uiInfo.resolutions[ index ].h ) ); + if( index >= 0 && index < uiInfo.numResolutions ) + { + trap_Cvar_Set( "r_width", va( "%d", uiInfo.resolutions[ index ].w ) ); + trap_Cvar_Set( "r_height", va( "%d", uiInfo.resolutions[ index ].h ) ); + } + + uiInfo.resolutionIndex = index; } } -static int UI_FeederInitialise( float feederID ) +static int UI_FeederInitialise( int feederID ) { if( feederID == FEEDER_RESOLUTIONS ) { @@ -3892,6 +3925,8 @@ static int UI_FeederInitialise( float feederID ) if( w == uiInfo.resolutions[ i ].w && h == uiInfo.resolutions[ i ].h ) return i; } + + return uiInfo.numResolutions; } return 0; @@ -4605,7 +4640,8 @@ void UI_UpdateNews( qboolean begin ) trap_Cvar_VariableStringBuffer( "cl_newsString", newsString, sizeof( newsString ) ); - wrapped = Item_Text_Wrap( newsString, .25, 325 * uiInfo.uiDC.aspectScale ); + // FIXME remove magic width constant + wrapped = Item_Text_Wrap( newsString, 0.25f, 325 * uiInfo.uiDC.aspectScale ); for( c = wrapped; *c != '\0'; ++c ) { if( linePos == (MAX_NEWS_LINEWIDTH - 1) || *c == '\n' ) { @@ -4632,6 +4668,5 @@ void UI_UpdateNews( qboolean begin ) if( finished ) uiInfo.newsInfo.refreshActive = qfalse; - } diff --git a/src/ui/ui_shared.c b/src/ui/ui_shared.c index 2e54df2b..2199a449 100644 --- a/src/ui/ui_shared.c +++ b/src/ui/ui_shared.c @@ -66,6 +66,7 @@ static qboolean g_editingField = qfalse; static itemDef_t *g_bindItem = NULL; static itemDef_t *g_editItem = NULL; +static itemDef_t *g_comboBoxItem = NULL; menuDef_t Menus[MAX_MENUS]; // defined menus int menuCount = 0; // how many @@ -79,6 +80,8 @@ static int lastListBoxClickTime = 0; void Item_RunScript( itemDef_t *item, const char *s ); void Item_SetupKeywordHash( void ); static ID_INLINE qboolean Item_IsEditField( itemDef_t *item ); +static ID_INLINE qboolean Item_IsListBox( itemDef_t *item ); +static void Item_ListBox_SetStartPos( itemDef_t *item, int startPos ); void Menu_SetupKeywordHash( void ); int BindingIDFromName( const char *name ); qboolean Item_Bind_HandleKey( itemDef_t *item, int key, qboolean down ); @@ -430,7 +433,7 @@ exprList_t; /* ================= OpPrec - + Return a value reflecting operator precedence ================= */ @@ -964,9 +967,8 @@ void GradientBar_Paint( rectDef_t *rect, vec4_t color ) /* ================== Window_Init - + Initializes a window structure ( windowDef_t ) with defaults - ================== */ void Window_Init( Window *w ) @@ -1236,6 +1238,23 @@ void Menu_AspectCompensate( menuDef_t *menu ) } } +static int Menu_CompareItemTypes( const void *a, const void *b ) +{ + itemDef_t *itemA = *(itemDef_t **)a; + itemDef_t *itemB = *(itemDef_t **)b; + qboolean itemAIsList = Item_IsListBox( itemA ); + qboolean itemBIsList = Item_IsListBox( itemB ); + + if( itemAIsList && itemBIsList ) + return 0; + else if( itemAIsList ) + return 1; + else if( itemBIsList ) + return -1; + else + return 0; +} + void Menu_PostParse( menuDef_t *menu ) { if( menu == NULL ) @@ -1251,6 +1270,11 @@ void Menu_PostParse( menuDef_t *menu ) Menu_AspectCompensate( menu ); Menu_UpdatePosition( menu ); + + // Sort lists to the end of the array as they can potentially be drawn on top + // of other elements + if( menu->itemCount > 1 ) + qsort( menu->items, menu->itemCount, sizeof( itemDef_t* ), Menu_CompareItemTypes ); } itemDef_t *Menu_ClearFocus( menuDef_t *menu ) @@ -1576,6 +1600,7 @@ void Menus_CloseAll( void ) g_editingField = qfalse; g_waitingForKey = qfalse; + g_comboBoxItem = NULL; } @@ -1775,11 +1800,11 @@ void Script_Reset( itemDef_t *item, char **args ) if( resetItem ) { - if( resetItem->type == ITEM_TYPE_LISTBOX ) + if( Item_IsListBox( resetItem ) ) { - resetItem->cursorPos = 0; - resetItem->typeData.list->startPos = 0; - DC->feederSelection( resetItem->feederID, 0 ); + resetItem->cursorPos = DC->feederInitialise( resetItem->feederID ); + Item_ListBox_SetStartPos( resetItem, 0 ); + DC->feederSelection( resetItem->feederID, resetItem->cursorPos ); } } } @@ -2067,7 +2092,7 @@ float UI_Text_EmHeight( float scale ) /* ================ UI_AdjustFrom640 - + Adjusted for resolution and screen aspect ratio ================ */ @@ -2079,6 +2104,35 @@ void UI_AdjustFrom640( float *x, float *y, float *w, float *h ) *h *= DC->yscale; } +/* +================ +UI_SetClipRegion +================= +*/ +void UI_SetClipRegion( float x, float y, float w, float h ) +{ + vec4_t clip; + + UI_AdjustFrom640( &x, &y, &w, &h ); + + clip[ 0 ] = x; + clip[ 1 ] = y; + clip[ 2 ] = x + w; + clip[ 3 ] = y + h; + + trap_R_SetClipRegion( clip ); +} + +/* +================ +UI_ClearClipRegion +================= +*/ +void UI_ClearClipRegion( void ) +{ + trap_R_SetClipRegion( NULL ); +} + static void UI_Text_PaintChar( float x, float y, float scale, glyphInfo_t *glyph, float size ) { @@ -2290,19 +2344,19 @@ commandDef_t commandList[] = { {"close", &Script_Close}, // menu {"conditionalopen", &Script_ConditionalOpen}, // menu - {"exec", &Script_Exec}, // group/name + {"exec", &Script_Exec}, // group/name {"fadein", &Script_FadeIn}, // group/name {"fadeout", &Script_FadeOut}, // group/name {"hide", &Script_Hide}, // group/name {"open", &Script_Open}, // menu {"orbit", &Script_Orbit}, // group/name - {"play", &Script_Play}, // group/name + {"play", &Script_Play}, // group/name {"playlooped", &Script_playLooped}, // group/name {"reset", &Script_Reset}, // resets the state of the item argument {"setasset", &Script_SetAsset}, // works on this {"setbackground", &Script_SetBackground}, // works on this {"setcolor", &Script_SetColor}, // works on this - {"setcvar", &Script_SetCvar}, // group/name + {"setcvar", &Script_SetCvar}, // group/name {"setfocus", &Script_SetFocus}, // sets this background color to team color {"setitemcolor", &Script_SetItemColor}, // group/name {"setplayerhead", &Script_SetPlayerHead}, // sets this background color to team color @@ -2482,16 +2536,27 @@ qboolean Item_SetFocus( itemDef_t *item, float x, float y ) return qtrue; } -int Item_ListBox_MaxScroll( itemDef_t *item ) +static float Item_ListBox_HeightForNumItems( itemDef_t *item, int numItems ) +{ + listBoxDef_t *listPtr = item->typeData.list; + + return ( listPtr->elementHeight * numItems ) + 2.0f; +} + +static int Item_ListBox_NumItemsForItemHeight( itemDef_t *item ) { listBoxDef_t *listPtr = item->typeData.list; - int count = DC->feederCount( item->feederID ); - int max; - if( item->window.flags & WINDOW_HORIZONTAL ) - max = count - ( item->window.rect.w / listPtr->elementWidth ) + 1; + if( item->type == ITEM_TYPE_COMBOBOX ) + return listPtr->dropItems; else - max = count - ( item->window.rect.h / listPtr->elementHeight ) + 1; + return ( ( item->window.rect.h - 2.0f ) / listPtr->elementHeight ); +} + +int Item_ListBox_MaxScroll( itemDef_t *item ) +{ + int total = DC->feederCount( item->feederID ); + int max = total - Item_ListBox_NumItemsForItemHeight( item ); if( max < 0 ) return 0; @@ -2499,68 +2564,86 @@ int Item_ListBox_MaxScroll( itemDef_t *item ) return max; } -int Item_ListBox_ThumbPosition( itemDef_t *item ) -{ - float max, pos, size; - int startPos = item->typeData.list->startPos; +static float oldComboBoxY; +static float oldComboBoxH; - max = Item_ListBox_MaxScroll( item ); +static qboolean Item_ComboBox_MaybeCastToListBox( itemDef_t *item ) +{ + listBoxDef_t *listPtr = item->typeData.list; + qboolean cast = g_comboBoxItem != NULL && + ( item->type == ITEM_TYPE_COMBOBOX ); - if( item->window.flags & WINDOW_HORIZONTAL ) + if( cast ) { - size = item->window.rect.w - ( SCROLLBAR_WIDTH * 2 ) - 2; - - if( max > 0 ) - pos = ( size - SCROLLBAR_WIDTH ) / ( float ) max; - else - pos = 0; + oldComboBoxY = item->window.rect.y; + oldComboBoxH = item->window.rect.h; - pos *= startPos; - return item->window.rect.x + 1 + SCROLLBAR_WIDTH + pos; + item->window.rect.y += item->window.rect.h; + item->window.rect.h = Item_ListBox_HeightForNumItems( item, listPtr->dropItems ); + item->type = ITEM_TYPE_LISTBOX; } - else - { - size = item->window.rect.h - ( SCROLLBAR_HEIGHT * 2 ) - 2; - if( max > 0 ) - pos = ( size - SCROLLBAR_HEIGHT ) / ( float ) max; - else - pos = 0; + return cast; +} - pos *= startPos; - return item->window.rect.y + 1 + SCROLLBAR_HEIGHT + pos; +static void Item_ComboBox_MaybeUnCastFromListBox( itemDef_t *item, qboolean unCast ) +{ + if( unCast ) + { + item->window.rect.y = oldComboBoxY; + item->window.rect.h = oldComboBoxH; + item->type = ITEM_TYPE_COMBOBOX; } } -int Item_ListBox_ThumbDrawPosition( itemDef_t *item ) +static void Item_ListBox_SetStartPos( itemDef_t *item, int startPos ) { - int min, max; + listBoxDef_t *listPtr = item->typeData.list; + int total = DC->feederCount( item->feederID ); + int max = Item_ListBox_MaxScroll( item ); + + if( startPos < 0 ) + listPtr->startPos = 0; + else if( startPos > max ) + listPtr->startPos = max; + else + listPtr->startPos = startPos; + + listPtr->endPos = listPtr->startPos + MIN( ( total - listPtr->startPos ), + Item_ListBox_NumItemsForItemHeight( item ) ); +} +float Item_ListBox_ThumbPosition( itemDef_t *item ) +{ + float max, pos, size; + float startPos = (float)item->typeData.list->startPos; + + max = Item_ListBox_MaxScroll( item ); + size = SCROLLBAR_SLIDER_HEIGHT( item ); + + if( max > 0.0f ) + pos = ( size - SCROLLBAR_ARROW_HEIGHT ) / max; + else + pos = 0.0f; + + pos *= startPos; + + return SCROLLBAR_SLIDER_Y( item ) + pos; +} + +float Item_ListBox_ThumbDrawPosition( itemDef_t *item ) +{ if( itemCapture == item ) { - if( item->window.flags & WINDOW_HORIZONTAL ) - { - min = item->window.rect.x + SCROLLBAR_WIDTH + 1; - max = item->window.rect.x + item->window.rect.w - 2 * SCROLLBAR_WIDTH - 1; - - if( DC->cursorx >= min + SCROLLBAR_WIDTH / 2 && DC->cursorx <= max + SCROLLBAR_WIDTH / 2 ) - return DC->cursorx - SCROLLBAR_WIDTH / 2; - else - return Item_ListBox_ThumbPosition( item ); - } - else - { - min = item->window.rect.y + SCROLLBAR_HEIGHT + 1; - max = item->window.rect.y + item->window.rect.h - 2 * SCROLLBAR_HEIGHT - 1; + float min = SCROLLBAR_SLIDER_Y( item ); + float max = min + SCROLLBAR_SLIDER_HEIGHT( item ) - SCROLLBAR_ARROW_HEIGHT; + float halfThumbSize = SCROLLBAR_ARROW_HEIGHT / 2.0f; - if( DC->cursory >= min + SCROLLBAR_HEIGHT / 2 && DC->cursory <= max + SCROLLBAR_HEIGHT / 2 ) - return DC->cursory - SCROLLBAR_HEIGHT / 2; - else - return Item_ListBox_ThumbPosition( item ); - } + if( DC->cursory >= min + halfThumbSize && DC->cursory <= max + halfThumbSize ) + return DC->cursory - halfThumbSize; } - else - return Item_ListBox_ThumbPosition( item ); + + return Item_ListBox_ThumbPosition( item ); } float Item_Slider_ThumbPosition( itemDef_t *item ) @@ -2625,76 +2708,36 @@ int Item_ListBox_OverLB( itemDef_t *item, float x, float y ) count = DC->feederCount( item->feederID ); - if( item->window.flags & WINDOW_HORIZONTAL ) - { - // check if on left arrow - r.x = item->window.rect.x; - r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_HEIGHT; - r.w = SCROLLBAR_WIDTH; - r.h = SCROLLBAR_HEIGHT; - - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_LEFTARROW; - - // check if on right arrow - r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_WIDTH; + r.x = SCROLLBAR_SLIDER_X( item ); + r.y = SCROLLBAR_Y( item ); + r.w = SCROLLBAR_ARROW_WIDTH; + r.h = SCROLLBAR_ARROW_HEIGHT; - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_RIGHTARROW; - - // check if on thumb - thumbstart = Item_ListBox_ThumbPosition( item ); - - r.x = thumbstart; - - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_THUMB; - - r.x = item->window.rect.x + SCROLLBAR_WIDTH; - r.w = thumbstart - r.x; - - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_PGUP; - - r.x = thumbstart + SCROLLBAR_WIDTH; - r.w = item->window.rect.x + item->window.rect.w - SCROLLBAR_WIDTH; - - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_PGDN; - } - else - { - r.x = item->window.rect.x + item->window.rect.w - SCROLLBAR_WIDTH; - r.y = item->window.rect.y; - r.w = SCROLLBAR_WIDTH; - r.h = SCROLLBAR_HEIGHT; - - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_LEFTARROW; + if( Rect_ContainsPoint( &r, x, y ) ) + return WINDOW_LB_UPARROW; - r.y = item->window.rect.y + item->window.rect.h - SCROLLBAR_HEIGHT; + r.y = SCROLLBAR_SLIDER_Y( item ) + SCROLLBAR_SLIDER_HEIGHT( item ); - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_RIGHTARROW; + if( Rect_ContainsPoint( &r, x, y ) ) + return WINDOW_LB_DOWNARROW; - thumbstart = Item_ListBox_ThumbPosition( item ); - r.y = thumbstart; + thumbstart = Item_ListBox_ThumbPosition( item ); + r.y = thumbstart; - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_THUMB; + if( Rect_ContainsPoint( &r, x, y ) ) + return WINDOW_LB_THUMB; - r.y = item->window.rect.y + SCROLLBAR_HEIGHT; - r.h = thumbstart - r.y; + r.y = SCROLLBAR_SLIDER_Y( item ); + r.h = thumbstart - r.y; - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_PGUP; + if( Rect_ContainsPoint( &r, x, y ) ) + return WINDOW_LB_PGUP; - r.y = thumbstart + SCROLLBAR_HEIGHT; - r.h = item->window.rect.y + item->window.rect.h - SCROLLBAR_HEIGHT; + r.y = thumbstart + SCROLLBAR_ARROW_HEIGHT; + r.h = ( SCROLLBAR_SLIDER_Y( item ) + SCROLLBAR_SLIDER_HEIGHT( item ) ) - r.y; - if( Rect_ContainsPoint( &r, x, y ) ) - return WINDOW_LB_PGDN; - } + if( Rect_ContainsPoint( &r, x, y ) ) + return WINDOW_LB_PGDN; return 0; } @@ -2702,52 +2745,32 @@ int Item_ListBox_OverLB( itemDef_t *item, float x, float y ) void Item_ListBox_MouseEnter( itemDef_t *item, float x, float y ) { - rectDef_t r; - listBoxDef_t *listPtr = item->typeData.list; + rectDef_t r; + listBoxDef_t *listPtr = item->typeData.list; + int listBoxFlags = ( WINDOW_LB_UPARROW | WINDOW_LB_DOWNARROW | WINDOW_LB_THUMB | + WINDOW_LB_PGUP | WINDOW_LB_PGDN ); + int total = DC->feederCount( item->feederID ); - item->window.flags &= ~( WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | - WINDOW_LB_PGUP | WINDOW_LB_PGDN ); + item->window.flags &= ~listBoxFlags; item->window.flags |= Item_ListBox_OverLB( item, x, y ); - if( item->window.flags & WINDOW_HORIZONTAL ) - { - if( !( item->window.flags & ( WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | WINDOW_LB_THUMB | - WINDOW_LB_PGUP | WINDOW_LB_PGDN ) ) ) - { - // check for selection hit as we have exausted buttons and thumb - - if( listPtr->elementStyle == LISTBOX_IMAGE ) - { - r.x = item->window.rect.x; - r.y = item->window.rect.y; - r.h = item->window.rect.h - SCROLLBAR_HEIGHT; - r.w = item->window.rect.w - listPtr->drawPadding; - - if( Rect_ContainsPoint( &r, x, y ) ) - { - listPtr->cursorPos = ( int )( ( x - r.x ) / listPtr->elementWidth ) + listPtr->startPos; - - if( listPtr->cursorPos >= listPtr->endPos ) - listPtr->cursorPos = listPtr->endPos; - } - } - } - } - else if( !( item->window.flags & ( WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW | - WINDOW_LB_THUMB | WINDOW_LB_PGUP | WINDOW_LB_PGDN ) ) ) + if( !( item->window.flags & listBoxFlags ) ) { - r.x = item->window.rect.x; - r.y = item->window.rect.y; - r.w = item->window.rect.w - SCROLLBAR_WIDTH; - r.h = item->window.rect.h - listPtr->drawPadding; + r.x = SCROLLBAR_X( item ); + r.y = SCROLLBAR_Y( item ); + r.w = SCROLLBAR_W( item ); + r.h = listPtr->elementHeight * + MIN( Item_ListBox_NumItemsForItemHeight( item ), total ); if( Rect_ContainsPoint( &r, x, y ) ) { - listPtr->cursorPos = ( int )( ( y - 2 - r.y ) / listPtr->elementHeight ) + listPtr->startPos; + listPtr->cursorPos = (int)( ( y - r.y ) / listPtr->elementHeight ) + listPtr->startPos; - if( listPtr->cursorPos > listPtr->endPos ) - listPtr->cursorPos = listPtr->endPos; + if( listPtr->cursorPos >= listPtr->endPos ) + listPtr->cursorPos = listPtr->endPos - 1; } + else + listPtr->cursorPos = -1; } } @@ -2818,7 +2841,7 @@ void Item_MouseLeave( itemDef_t *item ) } Item_RunScript( item, item->mouseExit ); - item->window.flags &= ~( WINDOW_LB_RIGHTARROW | WINDOW_LB_LEFTARROW ); + item->window.flags &= ~( WINDOW_LB_DOWNARROW | WINDOW_LB_UPARROW ); } } @@ -2859,299 +2882,158 @@ qboolean Item_ListBox_HandleKey( itemDef_t *item, int key, qboolean down, qboole { listBoxDef_t *listPtr = item->typeData.list; int count = DC->feederCount( item->feederID ); - int max, viewmax; + int viewmax; if( force || ( Rect_ContainsPoint( &item->window.rect, DC->cursorx, DC->cursory ) && item->window.flags & WINDOW_HASFOCUS ) ) { - max = Item_ListBox_MaxScroll( item ); + viewmax = Item_ListBox_NumItemsForItemHeight( item ); - if( item->window.flags & WINDOW_HORIZONTAL ) + switch( key ) { - viewmax = ( item->window.rect.w / listPtr->elementWidth ); - - if( key == K_LEFTARROW || key == K_KP_LEFTARROW ) - { - if( !listPtr->notselectable ) + case K_MOUSE1: + case K_MOUSE2: + if( item->window.flags & WINDOW_LB_UPARROW ) + Item_ListBox_SetStartPos( item, listPtr->startPos - 1 ); + else if( item->window.flags & WINDOW_LB_DOWNARROW ) + Item_ListBox_SetStartPos( item, listPtr->startPos + 1 ); + else if( item->window.flags & WINDOW_LB_PGUP ) + Item_ListBox_SetStartPos( item, listPtr->startPos - viewmax ); + else if( item->window.flags & WINDOW_LB_PGDN ) + Item_ListBox_SetStartPos( item, listPtr->startPos + viewmax ); + else if( item->window.flags & WINDOW_LB_THUMB ) + break; // Handled by capture function + else { - listPtr->cursorPos--; + // Select an item + qboolean runDoubleClick = qfalse; + // Mouse isn't over an item if( listPtr->cursorPos < 0 ) - listPtr->cursorPos = 0; - - if( listPtr->cursorPos < listPtr->startPos ) - listPtr->startPos = listPtr->cursorPos; - - if( listPtr->cursorPos >= listPtr->startPos + viewmax ) - listPtr->startPos = listPtr->cursorPos - viewmax + 1; + break; - item->cursorPos = listPtr->cursorPos; - DC->feederSelection( item->feederID, item->cursorPos ); - } - else - { - listPtr->startPos--; + if( item->cursorPos != listPtr->cursorPos ) + { + item->cursorPos = listPtr->cursorPos; + DC->feederSelection( item->feederID, item->cursorPos ); + } - if( listPtr->startPos < 0 ) - listPtr->startPos = 0; - } + runDoubleClick = DC->realTime < lastListBoxClickTime && listPtr->doubleClick; + lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY; - return qtrue; - } + // Made a selection, so close combobox + if( g_comboBoxItem != NULL ) + { + if( listPtr->doubleClick ) + runDoubleClick = qtrue; - if( key == K_RIGHTARROW || key == K_KP_RIGHTARROW ) - { - if( !listPtr->notselectable ) - { - listPtr->cursorPos++; + g_comboBoxItem = NULL; + } - if( listPtr->cursorPos < listPtr->startPos ) - listPtr->startPos = listPtr->cursorPos; + if( runDoubleClick ) + Item_RunScript( item, listPtr->doubleClick ); + } - if( listPtr->cursorPos >= count ) - listPtr->cursorPos = count - 1; + break; - if( listPtr->cursorPos >= listPtr->startPos + viewmax ) - listPtr->startPos = listPtr->cursorPos - viewmax + 1; + case K_MWHEELUP: + Item_ListBox_SetStartPos( item, listPtr->startPos - 1 ); + break; - item->cursorPos = listPtr->cursorPos; - DC->feederSelection( item->feederID, item->cursorPos ); - } - else - { - listPtr->startPos++; + case K_MWHEELDOWN: + Item_ListBox_SetStartPos( item, listPtr->startPos + 1 ); + break; - if( listPtr->startPos >= count ) - listPtr->startPos = count - 1; - } + case K_ENTER: + // Invoke the doubleClick handler when enter is pressed + if( listPtr->doubleClick ) + Item_RunScript( item, listPtr->doubleClick ); - return qtrue; - } - } - else - { - viewmax = ( item->window.rect.h / listPtr->elementHeight ); + break; - if( key == K_UPARROW || key == K_KP_UPARROW ) - { + case K_PGUP: + case K_KP_PGUP: if( !listPtr->notselectable ) { - listPtr->cursorPos--; + listPtr->cursorPos -= viewmax; if( listPtr->cursorPos < 0 ) listPtr->cursorPos = 0; if( listPtr->cursorPos < listPtr->startPos ) - listPtr->startPos = listPtr->cursorPos; + Item_ListBox_SetStartPos( item, listPtr->cursorPos ); if( listPtr->cursorPos >= listPtr->startPos + viewmax ) - listPtr->startPos = listPtr->cursorPos - viewmax + 1; + Item_ListBox_SetStartPos( item, listPtr->cursorPos - viewmax + 1 ); item->cursorPos = listPtr->cursorPos; DC->feederSelection( item->feederID, item->cursorPos ); } else - { - listPtr->startPos--; - - if( listPtr->startPos < 0 ) - listPtr->startPos = 0; - } + Item_ListBox_SetStartPos( item, listPtr->startPos - viewmax ); - return qtrue; - } + break; - if( key == K_DOWNARROW || key == K_KP_DOWNARROW ) - { + case K_PGDN: + case K_KP_PGDN: if( !listPtr->notselectable ) { - listPtr->cursorPos++; + listPtr->cursorPos += viewmax; if( listPtr->cursorPos < listPtr->startPos ) - listPtr->startPos = listPtr->cursorPos; + Item_ListBox_SetStartPos( item, listPtr->cursorPos ); if( listPtr->cursorPos >= count ) listPtr->cursorPos = count - 1; if( listPtr->cursorPos >= listPtr->startPos + viewmax ) - listPtr->startPos = listPtr->cursorPos - viewmax + 1; + Item_ListBox_SetStartPos( item, listPtr->cursorPos - viewmax + 1 ); item->cursorPos = listPtr->cursorPos; DC->feederSelection( item->feederID, item->cursorPos ); } else - { - listPtr->startPos++; - - if( listPtr->startPos > max ) - listPtr->startPos = max; - } - - return qtrue; - } - } + Item_ListBox_SetStartPos( item, listPtr->startPos + viewmax ); - // mouse hit - if( key == K_MOUSE1 || key == K_MOUSE2 ) - { - if( item->window.flags & WINDOW_LB_LEFTARROW ) - { - listPtr->startPos--; - - if( listPtr->startPos < 0 ) - listPtr->startPos = 0; - } - else if( item->window.flags & WINDOW_LB_RIGHTARROW ) - { - // one down - listPtr->startPos++; - - if( listPtr->startPos > max ) - listPtr->startPos = max; - } - else if( item->window.flags & WINDOW_LB_PGUP ) - { - // page up - listPtr->startPos -= viewmax; - - if( listPtr->startPos < 0 ) - listPtr->startPos = 0; - } - else if( item->window.flags & WINDOW_LB_PGDN ) - { - // page down - listPtr->startPos += viewmax; - - if( listPtr->startPos > max ) - listPtr->startPos = max; - } - else if( item->window.flags & WINDOW_LB_THUMB ) - { - // Display_SetCaptureItem(item); - } - else - { - // select an item - - if( item->cursorPos != listPtr->cursorPos ) - { - item->cursorPos = listPtr->cursorPos; - DC->feederSelection( item->feederID, item->cursorPos ); - } - - if( DC->realTime < lastListBoxClickTime && listPtr->doubleClick ) - Item_RunScript( item, listPtr->doubleClick ); - - lastListBoxClickTime = DC->realTime + DOUBLE_CLICK_DELAY; - } - - return qtrue; - } - - // Scroll wheel - if( key == K_MWHEELUP ) - { - listPtr->startPos--; - - if( listPtr->startPos < 0 ) - listPtr->startPos = 0; - - return qtrue; - } - - if( key == K_MWHEELDOWN ) - { - listPtr->startPos++; - - if( listPtr->startPos > max ) - listPtr->startPos = max; - - return qtrue; - } - - // Invoke the doubleClick handler when enter is pressed - if( key == K_ENTER ) - { - if( listPtr->doubleClick ) - Item_RunScript( item, listPtr->doubleClick ); - - return qtrue; - } - - if( key == K_HOME || key == K_KP_HOME ) - { - // home - listPtr->startPos = 0; - return qtrue; - } + break; - if( key == K_END || key == K_KP_END ) - { - // end - listPtr->startPos = max; - return qtrue; + default: + // Not handled + return qfalse; } - if( key == K_PGUP || key == K_KP_PGUP ) - { - // page up - - if( !listPtr->notselectable ) - { - listPtr->cursorPos -= viewmax; - - if( listPtr->cursorPos < 0 ) - listPtr->cursorPos = 0; - - if( listPtr->cursorPos < listPtr->startPos ) - listPtr->startPos = listPtr->cursorPos; + return qtrue; + } - if( listPtr->cursorPos >= listPtr->startPos + viewmax ) - listPtr->startPos = listPtr->cursorPos - viewmax + 1; + return qfalse; +} - item->cursorPos = listPtr->cursorPos; - DC->feederSelection( item->feederID, item->cursorPos ); - } - else - { - listPtr->startPos -= viewmax; +qboolean Item_ComboBox_HandleKey( itemDef_t *item, int key, qboolean down, qboolean force ) +{ + if( g_comboBoxItem != NULL ) + { + qboolean result; - if( listPtr->startPos < 0 ) - listPtr->startPos = 0; - } + qboolean cast = Item_ComboBox_MaybeCastToListBox( item ); + result = Item_ListBox_HandleKey( item, key, down, force ); + Item_ComboBox_MaybeUnCastFromListBox( item, cast ); - return qtrue; - } + if( !result ) + g_comboBoxItem = NULL; - if( key == K_PGDN || key == K_KP_PGDN ) + return result; + } + else + { + if( force || ( Rect_ContainsPoint( &item->window.rect, DC->cursorx, DC->cursory ) && + item->window.flags & WINDOW_HASFOCUS ) ) { - // page down - - if( !listPtr->notselectable ) - { - listPtr->cursorPos += viewmax; - - if( listPtr->cursorPos < listPtr->startPos ) - listPtr->startPos = listPtr->cursorPos; - - if( listPtr->cursorPos >= count ) - listPtr->cursorPos = count - 1; - - if( listPtr->cursorPos >= listPtr->startPos + viewmax ) - listPtr->startPos = listPtr->cursorPos - viewmax + 1; - - item->cursorPos = listPtr->cursorPos; - DC->feederSelection( item->feederID, item->cursorPos ); - } - else + if( key == K_MOUSE1 || key == K_MOUSE2 ) { - listPtr->startPos += viewmax; + g_comboBoxItem = item; - if( listPtr->startPos > max ) - listPtr->startPos = max; + return qtrue; } - - return qtrue; } } @@ -3246,13 +3128,13 @@ const char *Item_Multi_Setting( itemDef_t *item ) return ""; } -qboolean Item_Combobox_HandleKey( itemDef_t *item, int key ) +qboolean Item_Cycle_HandleKey( itemDef_t *item, int key ) { - comboBoxDef_t *comboPtr = item->typeData.combo; + cycleDef_t *cyclePtr = item->typeData.cycle; qboolean mouseOver = Rect_ContainsPoint( &item->window.rect, DC->cursorx, DC->cursory ); int count = DC->feederCount( item->feederID ); - if( comboPtr ) + if( cyclePtr ) { if( item->window.flags & WINDOW_HASFOCUS ) { @@ -3260,9 +3142,9 @@ qboolean Item_Combobox_HandleKey( itemDef_t *item, int key ) key == K_ENTER || key == K_RIGHTARROW || key == K_DOWNARROW ) { if( count > 0 ) - comboPtr->cursorPos = ( comboPtr->cursorPos + 1 ) % count; + cyclePtr->cursorPos = ( cyclePtr->cursorPos + 1 ) % count; - DC->feederSelection( item->feederID, comboPtr->cursorPos ); + DC->feederSelection( item->feederID, cyclePtr->cursorPos ); return qtrue; } @@ -3270,9 +3152,9 @@ qboolean Item_Combobox_HandleKey( itemDef_t *item, int key ) key == K_LEFTARROW || key == K_UPARROW ) { if( count > 0 ) - comboPtr->cursorPos = ( count + comboPtr->cursorPos - 1 ) % count; + cyclePtr->cursorPos = ( count + cyclePtr->cursorPos - 1 ) % count; - DC->feederSelection( item->feederID, comboPtr->cursorPos ); + DC->feederSelection( item->feederID, cyclePtr->cursorPos ); return qtrue; } @@ -3541,16 +3423,15 @@ exit: return !releaseFocus; } -static void Scroll_ListBox_AutoFunc( void *p ) +static void _Scroll_ListBox_AutoFunc( scrollInfo_t *si ) { - scrollInfo_t *si = ( scrollInfo_t* )p; - if( DC->realTime > si->nextScrollTime ) { // need to scroll which is done by simulating a click to the item // this is done a bit sideways as the autoscroll "knows" that the item is a listbox // so it calls it directly Item_ListBox_HandleKey( si->item, si->scrollKey, qtrue, qfalse ); + si->nextScrollTime = DC->realTime + si->adjustValue; } @@ -3563,49 +3444,36 @@ static void Scroll_ListBox_AutoFunc( void *p ) } } -static void Scroll_ListBox_ThumbFunc( void *p ) +static void Scroll_ListBox_AutoFunc( void *p ) { scrollInfo_t *si = ( scrollInfo_t* )p; - rectDef_t r; - int pos, max; - - if( si->item->window.flags & WINDOW_HORIZONTAL ) - { - if( DC->cursorx == si->xStart ) - return; - r.x = si->item->window.rect.x + SCROLLBAR_WIDTH + 1; - r.y = si->item->window.rect.y + si->item->window.rect.h - SCROLLBAR_HEIGHT - 1; - r.w = si->item->window.rect.w - ( SCROLLBAR_WIDTH * 2 ) - 2; - r.h = SCROLLBAR_HEIGHT; - max = Item_ListBox_MaxScroll( si->item ); - // - pos = ( DC->cursorx - r.x - SCROLLBAR_WIDTH / 2 ) * max / ( r.w - SCROLLBAR_WIDTH ); + qboolean cast = Item_ComboBox_MaybeCastToListBox( si->item ); + _Scroll_ListBox_AutoFunc( si ); + Item_ComboBox_MaybeUnCastFromListBox( si->item, cast ); +} - if( pos < 0 ) - pos = 0; - else if( pos > max ) - pos = max; +static void _Scroll_ListBox_ThumbFunc( scrollInfo_t *si ) +{ + rectDef_t r; + int pos, max; - si->item->typeData.list->startPos = pos; - si->xStart = DC->cursorx; - } - else if( DC->cursory != si->yStart ) + if( DC->cursory != si->yStart ) { - r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_WIDTH - 1; - r.y = si->item->window.rect.y + SCROLLBAR_HEIGHT + 1; - r.w = SCROLLBAR_WIDTH; - r.h = si->item->window.rect.h - ( SCROLLBAR_HEIGHT * 2 ) - 2; + r.x = si->item->window.rect.x + si->item->window.rect.w - SCROLLBAR_ARROW_WIDTH - 1; + r.y = si->item->window.rect.y + SCROLLBAR_ARROW_HEIGHT + 1; + r.w = SCROLLBAR_ARROW_WIDTH; + r.h = si->item->window.rect.h - ( SCROLLBAR_ARROW_HEIGHT * 2 ) - 2; max = Item_ListBox_MaxScroll( si->item ); // - pos = ( DC->cursory - r.y - SCROLLBAR_HEIGHT / 2 ) * max / ( r.h - SCROLLBAR_HEIGHT ); + pos = ( DC->cursory - r.y - SCROLLBAR_ARROW_HEIGHT / 2 ) * max / ( r.h - SCROLLBAR_ARROW_HEIGHT ); if( pos < 0 ) pos = 0; else if( pos > max ) pos = max; - si->item->typeData.list->startPos = pos; + Item_ListBox_SetStartPos( si->item, pos ); si->yStart = DC->cursory; } @@ -3615,6 +3483,7 @@ static void Scroll_ListBox_ThumbFunc( void *p ) // this is done a bit sideways as the autoscroll "knows" that the item is a listbox // so it calls it directly Item_ListBox_HandleKey( si->item, si->scrollKey, qtrue, qfalse ); + si->nextScrollTime = DC->realTime + si->adjustValue; } @@ -3627,6 +3496,15 @@ static void Scroll_ListBox_ThumbFunc( void *p ) } } +static void Scroll_ListBox_ThumbFunc( void *p ) +{ + scrollInfo_t *si = ( scrollInfo_t* )p; + + qboolean cast = Item_ComboBox_MaybeCastToListBox( si->item ); + _Scroll_ListBox_ThumbFunc( si ); + Item_ComboBox_MaybeUnCastFromListBox( si->item, cast ); +} + static void Scroll_Slider_ThumbFunc( void *p ) { float x, value, cursorx; @@ -3662,20 +3540,20 @@ void Item_StartCapture( itemDef_t *item, int key ) switch( item->type ) { - case ITEM_TYPE_EDITFIELD: - case ITEM_TYPE_SAYFIELD: - case ITEM_TYPE_NUMERICFIELD: case ITEM_TYPE_LISTBOX: + case ITEM_TYPE_COMBOBOX: { + qboolean cast = Item_ComboBox_MaybeCastToListBox( item ); flags = Item_ListBox_OverLB( item, DC->cursorx, DC->cursory ); + Item_ComboBox_MaybeUnCastFromListBox( item, cast ); - if( flags & ( WINDOW_LB_LEFTARROW | WINDOW_LB_RIGHTARROW ) ) + if( flags & ( WINDOW_LB_UPARROW | WINDOW_LB_DOWNARROW ) ) { scrollInfo.nextScrollTime = DC->realTime + SCROLL_TIME_START; scrollInfo.nextAdjustTime = DC->realTime + SCROLL_TIME_ADJUST; scrollInfo.adjustValue = SCROLL_TIME_START; scrollInfo.scrollKey = key; - scrollInfo.scrollDir = ( flags & WINDOW_LB_LEFTARROW ) ? qtrue : qfalse; + scrollInfo.scrollDir = ( flags & WINDOW_LB_UPARROW ) ? qtrue : qfalse; scrollInfo.item = item; UI_InstallCaptureFunc( Scroll_ListBox_AutoFunc, &scrollInfo, 0 ); itemCapture = item; @@ -3786,12 +3664,15 @@ qboolean Item_HandleKey( itemDef_t *item, int key, qboolean down ) case ITEM_TYPE_CHECKBOX: return qfalse; - case ITEM_TYPE_COMBO: - return Item_Combobox_HandleKey( item, key ); + case ITEM_TYPE_CYCLE: + return Item_Cycle_HandleKey( item, key ); case ITEM_TYPE_LISTBOX: return Item_ListBox_HandleKey( item, key, down, qfalse ); + case ITEM_TYPE_COMBOBOX: + return Item_ComboBox_HandleKey( item, key, down, qfalse ); + case ITEM_TYPE_YESNO: return Item_YesNo_HandleKey( item, key ); @@ -3921,7 +3802,7 @@ static void Display_CloseCinematics( void ) Menu_CloseCinematics( &Menus[i] ); } -void Menus_Activate( menuDef_t *menu ) +void Menus_Activate( menuDef_t *menu ) { int i; qboolean onTopOfMenuStack = qfalse; @@ -3950,15 +3831,15 @@ void Menus_Activate( menuDef_t *menu ) for( i = 0; i < menu->itemCount; i++ ) // reset selection in listboxes when opened { - if( menu->items[ i ]->type == ITEM_TYPE_LISTBOX ) + if( Item_IsListBox( menu->items[ i ] ) ) { - menu->items[ i ]->cursorPos = 0; - menu->items[ i ]->typeData.list->startPos = 0; - DC->feederSelection( menu->items[ i ]->feederID, 0 ); + menu->items[ i ]->cursorPos = DC->feederInitialise( menu->items[ i ]->feederID ); + Item_ListBox_SetStartPos( menu->items[ i ], 0 ); + DC->feederSelection( menu->items[ i ]->feederID, menu->items[ i ]->cursorPos ); } - else if( menu->items[ i ]->type == ITEM_TYPE_COMBO ) + else if( menu->items[ i ]->type == ITEM_TYPE_CYCLE ) { - menu->items[ i ]->typeData.combo->cursorPos = + menu->items[ i ]->typeData.cycle->cursorPos = DC->feederInitialise( menu->items[ i ]->feederID ); } @@ -3977,10 +3858,10 @@ qboolean Menus_ReplaceActive( menuDef_t *menu ) if( openMenuCount < 1 ) return qfalse; - active = menuStack[ openMenuCount - 1]; + active = menuStack[ openMenuCount - 1 ]; - if( !( active->window.flags & WINDOW_HASFOCUS ) || - !( active->window.flags & WINDOW_VISIBLE ) ) + if( !( active->window.flags & WINDOW_HASFOCUS ) || + !( active->window.flags & WINDOW_VISIBLE ) ) { return qfalse; } @@ -3990,8 +3871,8 @@ qboolean Menus_ReplaceActive( menuDef_t *menu ) if( menu->itemCount != active->itemCount ) return qfalse; - - for( i = 0; i < menu->itemCount; i++ ) + + for( i = 0; i < menu->itemCount; i++ ) { if( menu->items[ i ]->type != active->items[ i ]->type ) return qfalse; @@ -4007,14 +3888,7 @@ qboolean Menus_ReplaceActive( menuDef_t *menu ) item.parent = menu; Item_RunScript( &item, menu->onOpen ); } - - for( i = 0; i < menu->itemCount; i++ ) - { - menu->items[ i ]->cursorPos = active->items[ i ]->cursorPos; - menu->items[ i ]->typeData.list->startPos = active->items[ i ]->typeData.list->startPos; - menu->items[ i ]->feederID = active->items[ i ]->feederID; - menu->items[ i ]->typeData.combo->cursorPos = active->items[ i ]->typeData.combo->cursorPos; - } + return qtrue; } @@ -4134,12 +4008,17 @@ void Menu_HandleKey( menuDef_t *menu, int key, qboolean down ) } } - // get the item with focus - for( i = 0; i < menu->itemCount; i++ ) + if( g_comboBoxItem == NULL ) { - if( menu->items[i]->window.flags & WINDOW_HASFOCUS ) - item = menu->items[i]; + // get the item with focus + for( i = 0; i < menu->itemCount; i++ ) + { + if( menu->items[i]->window.flags & WINDOW_HASFOCUS ) + item = menu->items[i]; + } } + else + item = g_comboBoxItem; if( item != NULL ) { @@ -4973,7 +4852,7 @@ void Item_Multi_Paint( itemDef_t *item ) UI_Text_Paint( item->textRect.x, item->textRect.y, item->textscale, newColor, text, 0, 0, item->textStyle ); } -void Item_Combobox_Paint( itemDef_t *item ) +void Item_Cycle_Paint( itemDef_t *item ) { vec4_t newColor; const char *text = ""; @@ -4984,8 +4863,8 @@ void Item_Combobox_Paint( itemDef_t *item ) else memcpy( &newColor, &item->window.foreColor, sizeof( vec4_t ) ); - if( item->typeData.combo ) - text = DC->feederItemText( item->feederID, item->typeData.combo->cursorPos, + if( item->typeData.cycle ) + text = DC->feederItemText( item->feederID, item->typeData.cycle->cursorPos, 0, NULL ); if( item->text ) @@ -5422,16 +5301,6 @@ qboolean Item_Bind_HandleKey( itemDef_t *item, int key, qboolean down ) } - -void AdjustFrom640( float *x, float *y, float *w, float *h ) -{ - //*x = *x * DC->scale + DC->bias; - *x *= DC->xscale; - *y *= DC->yscale; - *w *= DC->xscale; - *h *= DC->yscale; -} - void Item_Model_Paint( itemDef_t *item ) { float x, y, w, h; @@ -5456,7 +5325,7 @@ void Item_Model_Paint( itemDef_t *item ) w = item->window.rect.w - 2; h = item->window.rect.h - 2; - AdjustFrom640( &x, &y, &w, &h ); + UI_AdjustFrom640( &x, &y, &w, &h ); refdef.x = x; refdef.y = y; @@ -5524,294 +5393,222 @@ void Item_Model_Paint( itemDef_t *item ) } -void Item_Image_Paint( itemDef_t *item ) +void Item_ListBoxRow_Paint( itemDef_t *item, int row, int renderPos, qboolean highlight, qboolean scrollbar ) { - if( item == NULL ) - return; - - DC->drawHandlePic( item->window.rect.x + 1, item->window.rect.y + 1, - item->window.rect.w - 2, item->window.rect.h - 2, item->asset ); -} + float x, y, w; + listBoxDef_t *listPtr = item->typeData.list; + menuDef_t *menu = ( menuDef_t * )item->parent; + float one, two; -void Item_ListBox_Paint( itemDef_t *item ) -{ - float x, y, size, thumb; - int i, count; - qhandle_t image; - qhandle_t optionalImage; - listBoxDef_t *listPtr = item->typeData.list; - menuDef_t *menu = ( menuDef_t * )item->parent; - float one, two; + one = 1.0f * DC->aspectScale; + two = 2.0f * DC->aspectScale; - if( menu->window.aspectBias != ASPECT_NONE || item->window.aspectBias != ASPECT_NONE ) - { - one = 1.0f * DC->aspectScale; - two = 2.0f * DC->aspectScale; - } - else - { - one = 1.0f; - two = 2.0f; - } + x = SCROLLBAR_X( item ); + y = SCROLLBAR_Y( item ) + ( listPtr->elementHeight * renderPos ); + w = item->window.rect.w - ( two * item->window.borderSize ); - // the listbox is horizontal or vertical and has a fixed size scroll bar going either direction - // elements are enumerated from the DC and either text or image handles are acquired from the DC as well - // textscale is used to size the text, textalignx and textaligny are used to size image elements - // there is no clipping available so only the last completely visible item is painted - count = DC->feederCount( item->feederID ); + if( scrollbar ) + w -= SCROLLBAR_ARROW_WIDTH; - // default is vertical if horizontal flag is not here - if( item->window.flags & WINDOW_HORIZONTAL ) + if( listPtr->elementStyle == LISTBOX_IMAGE ) { - //FIXME: unmaintained cruft? + qhandle_t image = DC->feederItemImage( item->feederID, row ); - if( !listPtr->noscrollbar ) - { - // draw scrollbar in bottom of the window - // bar - x = item->window.rect.x + 1; - y = item->window.rect.y + item->window.rect.h - SCROLLBAR_HEIGHT - 1; - DC->drawHandlePic( x, y, SCROLLBAR_WIDTH, SCROLLBAR_HEIGHT, DC->Assets.scrollBarArrowLeft ); - x += SCROLLBAR_WIDTH - 1; - size = item->window.rect.w - ( SCROLLBAR_WIDTH * 2 ); - DC->drawHandlePic( x, y, size + 1, SCROLLBAR_HEIGHT, DC->Assets.scrollBar ); - x += size - 1; - DC->drawHandlePic( x, y, SCROLLBAR_WIDTH, SCROLLBAR_HEIGHT, DC->Assets.scrollBarArrowRight ); - // thumb - thumb = Item_ListBox_ThumbDrawPosition( item );//Item_ListBox_ThumbPosition(item); + UI_SetClipRegion( x, y, listPtr->elementWidth, listPtr->elementHeight ); - if( thumb > x - SCROLLBAR_WIDTH - 1 ) - thumb = x - SCROLLBAR_WIDTH - 1; + if( image ) + DC->drawHandlePic( x + one, y + 1.0f, listPtr->elementWidth - two, listPtr->elementHeight - 2.0f, image ); - DC->drawHandlePic( thumb, y, SCROLLBAR_WIDTH, SCROLLBAR_HEIGHT, DC->Assets.scrollBarThumb ); - // - listPtr->endPos = listPtr->startPos; + if( highlight && row == item->cursorPos ) + { + DC->drawRect( x, y, listPtr->elementWidth, listPtr->elementHeight, + item->window.borderSize, item->window.borderColor ); } - size = item->window.rect.w - 2; - // items - // size contains max available space + UI_ClearClipRegion( ); + } + else + { + const float m = UI_Text_EmHeight( item->textscale ); + char text[ MAX_STRING_CHARS ]; + qhandle_t optionalImage; - if( listPtr->elementStyle == LISTBOX_IMAGE ) + if( listPtr->numColumns > 0 ) { - // fit = 0; - x = item->window.rect.x + 1; - y = item->window.rect.y + 1; + int j; - for( i = listPtr->startPos; i < count; i++ ) + for( j = 0; j < listPtr->numColumns; j++ ) { - // always draw at least one - // which may overdraw the box if it is too small for the element - image = DC->feederItemImage( item->feederID, i ); + float columnPos; + float width, height, yOffset; - if( image ) - DC->drawHandlePic( x + 1, y + 1, listPtr->elementWidth - 2, listPtr->elementHeight - 2, image ); - - if( i == item->cursorPos ) + if( menu->window.aspectBias != ASPECT_NONE || item->window.aspectBias != ASPECT_NONE ) { - DC->drawRect( x, y, listPtr->elementWidth - 1, listPtr->elementHeight - 1, - item->window.borderSize, item->window.borderColor ); + columnPos = ( listPtr->columnInfo[ j ].pos + 4.0f ) * DC->aspectScale; + width = listPtr->columnInfo[ j ].width * DC->aspectScale; } - - listPtr->endPos++; - size -= listPtr->elementWidth; - - if( size < listPtr->elementWidth ) + else { - listPtr->drawPadding = size; //listPtr->elementWidth - size; - break; + columnPos = ( listPtr->columnInfo[ j ].pos + 4.0f ); + width = listPtr->columnInfo[ j ].width; } - x += listPtr->elementWidth; - // fit++; - } - } - } - else - { - if( !listPtr->noscrollbar ) - { - // draw scrollbar to right side of the window - x = item->window.rect.x + item->window.rect.w - SCROLLBAR_WIDTH - one; - y = item->window.rect.y + 1; - DC->drawHandlePic( x, y, SCROLLBAR_WIDTH, SCROLLBAR_HEIGHT, DC->Assets.scrollBarArrowUp ); - y += SCROLLBAR_HEIGHT - 1; - - listPtr->endPos = listPtr->startPos; - size = item->window.rect.h - ( SCROLLBAR_HEIGHT * 2 ); - DC->drawHandlePic( x, y, SCROLLBAR_WIDTH, size + 1, DC->Assets.scrollBar ); - y += size - 1; - DC->drawHandlePic( x, y, SCROLLBAR_WIDTH, SCROLLBAR_HEIGHT, DC->Assets.scrollBarArrowDown ); - // thumb - thumb = Item_ListBox_ThumbDrawPosition( item );//Item_ListBox_ThumbPosition(item); + height = listPtr->columnInfo[ j ].width; + yOffset = y + ( ( listPtr->elementHeight - height ) / 2.0f ); - if( thumb > y - SCROLLBAR_HEIGHT - 1 ) - thumb = y - SCROLLBAR_HEIGHT - 1; + Q_strncpyz( text, DC->feederItemText( item->feederID, row, j, &optionalImage ), sizeof( text ) ); - DC->drawHandlePic( x, thumb, SCROLLBAR_WIDTH, SCROLLBAR_HEIGHT, DC->Assets.scrollBarThumb ); - } + UI_SetClipRegion( x + columnPos, yOffset, width, height ); - // adjust size for item painting - size = item->window.rect.h - 2; + if( optionalImage >= 0 ) + DC->drawHandlePic( x + columnPos, yOffset, width, height, optionalImage ); + else if( text[ 0 ] ) + { + float alignOffset = 0.0f, tw; - if( listPtr->elementStyle == LISTBOX_IMAGE ) - { - // fit = 0; - x = item->window.rect.x + one; - y = item->window.rect.y + 1; + tw = UI_Text_Width( text, item->textscale, 0 ); - for( i = listPtr->startPos; i < count; i++ ) - { - // always draw at least one - // which may overdraw the box if it is too small for the element - image = DC->feederItemImage( item->feederID, i ); + switch( listPtr->columnInfo[ j ].align ) + { + case ALIGN_LEFT: + alignOffset = 0.0f; + break; - if( image ) - DC->drawHandlePic( x + one, y + 1, listPtr->elementWidth - two, listPtr->elementHeight - 2, image ); + case ALIGN_RIGHT: + alignOffset = width - tw; + break; - if( i == item->cursorPos ) - { - DC->drawRect( x, y, listPtr->elementWidth - one, listPtr->elementHeight - 1, - item->window.borderSize, item->window.borderColor ); - } + case ALIGN_CENTER: + alignOffset = ( width / 2.0f ) - ( tw / 2.0f ); + break; - listPtr->endPos++; - size -= listPtr->elementWidth; + default: + alignOffset = 0.0f; + } - if( size < listPtr->elementHeight ) - { - listPtr->drawPadding = listPtr->elementHeight - size; - break; + UI_Text_Paint( x + columnPos + alignOffset, + y + m + ( ( listPtr->elementHeight - m ) / 2.0f ), + item->textscale, item->window.foreColor, text, 0, + 0, item->textStyle ); } - y += listPtr->elementHeight; - // fit++; + UI_ClearClipRegion( ); } } else { - float m = UI_Text_EmHeight( item->textscale ); - x = item->window.rect.x + one; - y = item->window.rect.y + 1; + float offset; - for( i = listPtr->startPos; i < count; i++ ) - { - char text[ MAX_STRING_CHARS ]; - // always draw at least one - // which may overdraw the box if it is too small for the element + if( menu->window.aspectBias != ASPECT_NONE || item->window.aspectBias != ASPECT_NONE ) + offset = 4.0f * DC->aspectScale; + else + offset = 4.0f; - if( listPtr->numColumns > 0 ) - { - int j; + Q_strncpyz( text, DC->feederItemText( item->feederID, row, 0, &optionalImage ), sizeof( text ) ); - for( j = 0; j < listPtr->numColumns; j++ ) - { - float columnPos; - float width, height; + UI_SetClipRegion( x, y, w, listPtr->elementHeight ); - if( menu->window.aspectBias != ASPECT_NONE || item->window.aspectBias != ASPECT_NONE ) - { - columnPos = ( listPtr->columnInfo[ j ].pos + 4.0f ) * DC->aspectScale; - width = listPtr->columnInfo[ j ].width * DC->aspectScale; - } - else - { - columnPos = ( listPtr->columnInfo[ j ].pos + 4.0f ); - width = listPtr->columnInfo[ j ].width; - } + if( optionalImage >= 0 ) + DC->drawHandlePic( x + offset, y, listPtr->elementHeight, listPtr->elementHeight, optionalImage ); + else if( text[ 0 ] ) + { + UI_Text_Paint( x + offset, y + m + ( ( listPtr->elementHeight - m ) / 2.0f ), + item->textscale, item->window.foreColor, text, 0, + 0, item->textStyle ); + } - height = listPtr->columnInfo[ j ].width; + UI_ClearClipRegion( ); + } - Q_strncpyz( text, DC->feederItemText( item->feederID, i, j, &optionalImage ), sizeof( text ) ); + if( highlight && row == item->cursorPos ) + DC->fillRect( x, y, w, listPtr->elementHeight, item->window.outlineColor ); + } +} - if( optionalImage >= 0 ) - { - DC->drawHandlePic( x + columnPos, y + ( ( listPtr->elementHeight - height ) / 2.0f ), - width, height, optionalImage ); - } - else if( text[ 0 ] ) - { - int alignOffset = 0.0f, tw; +void Item_ListBox_Paint( itemDef_t *item ) +{ + float size; + int i; + listBoxDef_t *listPtr = item->typeData.list; + int count = DC->feederCount( item->feederID ); + qboolean scrollbar = !listPtr->noscrollbar && + count > Item_ListBox_NumItemsForItemHeight( item ); - tw = UI_Text_Width( text, item->textscale, 0 ); + if( scrollbar ) + { + float x = SCROLLBAR_SLIDER_X( item ); + float y = SCROLLBAR_Y( item ); + float thumbY = Item_ListBox_ThumbDrawPosition( item ); - // Shorten the string if it's too long + // Up arrow + DC->drawHandlePic( x, y, SCROLLBAR_ARROW_WIDTH, SCROLLBAR_ARROW_HEIGHT, DC->Assets.scrollBarArrowUp ); + y = SCROLLBAR_SLIDER_Y( item ); - while( tw > width && strlen( text ) > 0 ) - { - text[ strlen( text ) - 1 ] = '\0'; - tw = UI_Text_Width( text, item->textscale, 0 ); - } + // Scroll bar + size = SCROLLBAR_SLIDER_HEIGHT( item ); + DC->drawHandlePic( x, y, SCROLLBAR_ARROW_WIDTH, size, DC->Assets.scrollBar ); + y = SCROLLBAR_SLIDER_Y( item ) + size; - switch( listPtr->columnInfo[ j ].align ) - { - case ALIGN_LEFT: - alignOffset = 0.0f; - break; + // Down arrow + DC->drawHandlePic( x, y, SCROLLBAR_ARROW_WIDTH, SCROLLBAR_ARROW_HEIGHT, DC->Assets.scrollBarArrowDown ); - case ALIGN_RIGHT: - alignOffset = width - tw; - break; + // Thumb + DC->drawHandlePic( x, thumbY, SCROLLBAR_ARROW_WIDTH, SCROLLBAR_ARROW_HEIGHT, DC->Assets.scrollBarThumb ); + } - case ALIGN_CENTER: - alignOffset = ( width / 2.0f ) - ( tw / 2.0f ); - break; + // Paint rows + for( i = listPtr->startPos; i < listPtr->endPos; i++ ) + Item_ListBoxRow_Paint( item, i, i - listPtr->startPos, qtrue, scrollbar ); +} - default: - alignOffset = 0.0f; - } +void Item_Paint( itemDef_t *item ); - UI_Text_Paint( x + columnPos + alignOffset, - y + m + ( ( listPtr->elementHeight - m ) / 2.0f ), - item->textscale, item->window.foreColor, text, 0, - 0, item->textStyle ); - } - } - } - else - { - float offset; +void Item_ComboBox_Paint( itemDef_t *item ) +{ + float x, y, h; - if( menu->window.aspectBias != ASPECT_NONE || item->window.aspectBias != ASPECT_NONE ) - offset = 4.0f * DC->aspectScale; - else - offset = 4.0f; + x = SCROLLBAR_SLIDER_X( item ); + y = SCROLLBAR_Y( item ); + h = item->window.rect.h - 2.0f; - Q_strncpyz( text, DC->feederItemText( item->feederID, i, 0, &optionalImage ), sizeof( text ) ); + // Down arrow + DC->drawHandlePic( x, y, SCROLLBAR_ARROW_WIDTH, h, DC->Assets.scrollBarArrowDown ); - if( optionalImage >= 0 ) - DC->drawHandlePic( x + offset, y, listPtr->elementHeight, listPtr->elementHeight, optionalImage ); - else if( text[ 0 ] ) - { - UI_Text_Paint( x + offset, y + m + ( ( listPtr->elementHeight - m ) / 2.0f ), - item->textscale, item->window.foreColor, text, 0, - 0, item->textStyle ); - } - } + Item_ListBoxRow_Paint( item, item->cursorPos, 0, qfalse, qtrue ); - if( i == item->cursorPos ) - { - DC->fillRect( x, y, item->window.rect.w - SCROLLBAR_WIDTH - ( two * item->window.borderSize ), - listPtr->elementHeight, item->window.outlineColor ); - } + if( g_comboBoxItem != NULL ) + { + qboolean cast = Item_ComboBox_MaybeCastToListBox( item ); + Item_Paint( item ); + Item_ComboBox_MaybeUnCastFromListBox( item, cast ); + } +} - listPtr->endPos++; - size -= listPtr->elementHeight; +void Item_ListBox_Update( itemDef_t *item ) +{ + listBoxDef_t *listPtr = item->typeData.list; + int feederCount = DC->feederCount( item->feederID ); - if( size < listPtr->elementHeight ) - { - listPtr->drawPadding = listPtr->elementHeight - size; - break; - } + if( listPtr->lastFeederCount != feederCount ) + { + if( listPtr->resetonfeederchange ) + { + item->cursorPos = DC->feederInitialise( item->feederID ); + Item_ListBox_SetStartPos( item, 0 ); + DC->feederSelection( item->feederID, item->cursorPos ); + } + else + { + // Make sure endPos is up-to-date + Item_ListBox_SetStartPos( item, listPtr->startPos ); - y += listPtr->elementHeight; - // fit++; - } + // If the selection is off the end now, select the last element + if( item->cursorPos >= feederCount ) + item->cursorPos = feederCount - 1; } } - // FIXME: hacky fix to off-by-one bug - listPtr->endPos--; + listPtr->lastFeederCount = feederCount; } void Item_OwnerDraw_Paint( itemDef_t *item ) @@ -5893,6 +5690,15 @@ void Item_OwnerDraw_Paint( itemDef_t *item ) } +void Item_Update( itemDef_t *item ) +{ + if( item == NULL ) + return; + + if( Item_IsListBox( item ) ) + Item_ListBox_Update( item ); +} + void Item_Paint( itemDef_t *item ) { vec4_t red; @@ -6067,7 +5873,7 @@ void Item_Paint( itemDef_t *item ) if( !( item->window.flags & WINDOW_VISIBLE ) ) return; - Window_Paint( &item->window, parent->fadeAmount , parent->fadeClamp, parent->fadeCycle ); + Window_Paint( &item->window, parent->fadeAmount, parent->fadeClamp, parent->fadeCycle ); if( DC->getCVarValue( "ui_developer" ) ) { @@ -6095,17 +5901,17 @@ void Item_Paint( itemDef_t *item ) case ITEM_TYPE_CHECKBOX: break; - case ITEM_TYPE_COMBO: - Item_Combobox_Paint( item ); + case ITEM_TYPE_CYCLE: + Item_Cycle_Paint( item ); break; case ITEM_TYPE_LISTBOX: Item_ListBox_Paint( item ); break; - //case ITEM_TYPE_IMAGE: - // Item_Image_Paint(item); - // break; + case ITEM_TYPE_COMBOBOX: + Item_ComboBox_Paint( item ); + break; case ITEM_TYPE_MODEL: Item_Model_Paint( item ); @@ -6185,9 +5991,14 @@ void Menu_ScrollFeeder( menuDef_t *menu, int feeder, qboolean down ) for( i = 0; i < menu->itemCount; i++ ) { - if( menu->items[i]->feederID == feeder ) + itemDef_t *item = menu->items[ i ]; + + if( item->feederID == feeder ) { - Item_ListBox_HandleKey( menu->items[i], ( down ) ? K_DOWNARROW : K_UPARROW, qtrue, qtrue ); + qboolean cast = Item_ComboBox_MaybeCastToListBox( item ); + Item_ListBox_HandleKey( item, down ? K_DOWNARROW : K_UPARROW, qtrue, qtrue ); + Item_ComboBox_MaybeUnCastFromListBox( item, cast ); + return; } } @@ -6214,10 +6025,10 @@ void Menu_SetFeederSelection( menuDef_t *menu, int feeder, int index, const char { if( menu->items[i]->feederID == feeder ) { - if( menu->items[i]->type == ITEM_TYPE_LISTBOX && index == 0 ) + if( Item_IsListBox( menu->items[i] ) && index == 0 ) { menu->items[ i ]->typeData.list->cursorPos = 0; - menu->items[ i ]->typeData.list->startPos = 0; + Item_ListBox_SetStartPos( menu->items[ i ], 0 ); } menu->items[i]->cursorPos = index; @@ -6297,12 +6108,41 @@ void Item_Init( itemDef_t *item ) item->window.aspectBias = ASPECT_NONE; } +static qboolean Item_HandleMouseMove( itemDef_t *item, float x, float y, int pass, qboolean focusSet ) +{ + if( Rect_ContainsPoint( &item->window.rect, x, y ) ) + { + if( pass == 1 ) + { + if( item->type == ITEM_TYPE_TEXT && item->text ) + { + if( !Rect_ContainsPoint( Item_CorrectedTextRect( item ), x, y ) ) + return qtrue; + } + + // if we are over an item + if( IsVisible( item->window.flags ) ) + { + // different one + Item_MouseEnter( item, x, y ); + + if( !focusSet ) + focusSet = Item_SetFocus( item, x, y ); + } + } + + return qtrue; + } + + return qfalse; +} + void Menu_HandleMouseMove( menuDef_t *menu, float x, float y ) { int i, pass; qboolean focusSet = qfalse; - - itemDef_t *overItem; + qboolean result; + qboolean cast; if( menu == NULL ) return; @@ -6319,65 +6159,60 @@ void Menu_HandleMouseMove( menuDef_t *menu, float x, float y ) if( g_waitingForKey || g_editingField ) return; + if( g_comboBoxItem != NULL ) + { + Item_SetFocus( g_comboBoxItem, x, y ); + focusSet = qtrue; + } + // FIXME: this is the whole issue of focus vs. mouse over.. // need a better overall solution as i don't like going through everything twice for( pass = 0; pass < 2; pass++ ) { for( i = 0; i < menu->itemCount; i++ ) { + itemDef_t *item = menu->items[ i ]; + // turn off focus each item // menu->items[i].window.flags &= ~WINDOW_HASFOCUS; - if( !( menu->items[i]->window.flags & ( WINDOW_VISIBLE | WINDOW_FORCED ) ) ) + if( !( item->window.flags & ( WINDOW_VISIBLE | WINDOW_FORCED ) ) ) continue; // items can be enabled and disabled based on cvars - if( menu->items[i]->cvarFlags & ( CVAR_ENABLE | CVAR_DISABLE ) && - !Item_EnableShowViaCvar( menu->items[i], CVAR_ENABLE ) ) + if( item->cvarFlags & ( CVAR_ENABLE | CVAR_DISABLE ) && + !Item_EnableShowViaCvar( item, CVAR_ENABLE ) ) continue; - if( menu->items[i]->cvarFlags & ( CVAR_SHOW | CVAR_HIDE ) && - !Item_EnableShowViaCvar( menu->items[i], CVAR_SHOW ) ) + if( item->cvarFlags & ( CVAR_SHOW | CVAR_HIDE ) && + !Item_EnableShowViaCvar( item, CVAR_SHOW ) ) continue; + cast = Item_ComboBox_MaybeCastToListBox( item ); + result = Item_HandleMouseMove( item, x, y, pass, focusSet ); + Item_ComboBox_MaybeUnCastFromListBox( item, cast ); - - if( Rect_ContainsPoint( &menu->items[i]->window.rect, x, y ) ) - { - if( pass == 1 ) - { - overItem = menu->items[i]; - - if( overItem->type == ITEM_TYPE_TEXT && overItem->text ) - { - if( !Rect_ContainsPoint( Item_CorrectedTextRect( overItem ), x, y ) ) - continue; - } - - // if we are over an item - if( IsVisible( overItem->window.flags ) ) - { - // different one - Item_MouseEnter( overItem, x, y ); - // Item_SetMouseOver(overItem, qtrue); - - // if item is not a decoration see if it can take focus - - if( !focusSet ) - focusSet = Item_SetFocus( overItem, x, y ); - } - } - } - else if( menu->items[i]->window.flags & WINDOW_MOUSEOVER ) + if( !result && item->window.flags & WINDOW_MOUSEOVER ) { - Item_MouseLeave( menu->items[i] ); - Item_SetMouseOver( menu->items[i], qfalse ); + Item_MouseLeave( item ); + Item_SetMouseOver( item, qfalse ); } } } } +void Menu_Update( menuDef_t *menu ) +{ + int i; + + if( menu == NULL ) + return; + + for( i = 0; i < menu->itemCount; i++ ) + Item_Update( menu->items[ i ] ); +} + void Menu_Paint( menuDef_t *menu, qboolean forcePaint ) { int i; @@ -6385,7 +6220,7 @@ void Menu_Paint( menuDef_t *menu, qboolean forcePaint ) if( menu == NULL ) return; - if( !( menu->window.flags & WINDOW_VISIBLE ) && !forcePaint ) + if( !( menu->window.flags & WINDOW_VISIBLE ) && !forcePaint ) return; if( menu->window.ownerDrawFlags && DC->ownerDrawVisible && !DC->ownerDrawVisible( menu->window.ownerDrawFlags ) ) @@ -6501,9 +6336,10 @@ itemDataType_t Item_DataType( itemDef_t *item ) return TYPE_NONE; case ITEM_TYPE_LISTBOX: + case ITEM_TYPE_COMBOBOX: return TYPE_LIST; - case ITEM_TYPE_COMBO: + case ITEM_TYPE_CYCLE: return TYPE_COMBO; case ITEM_TYPE_EDITFIELD: @@ -6544,6 +6380,24 @@ static ID_INLINE qboolean Item_IsEditField( itemDef_t *item ) /* =============== +Item_IsListBox +=============== +*/ +static ID_INLINE qboolean Item_IsListBox( itemDef_t *item ) +{ + switch( item->type ) + { + case ITEM_TYPE_LISTBOX: + case ITEM_TYPE_COMBOBOX: + return qtrue; + + default: + return qfalse; + } +} + +/* +=============== Item Keyword Parse functions =============== */ @@ -6693,21 +6547,21 @@ qboolean ItemParse_noscrollbar( itemDef_t *item, int handle ) return qtrue; } -// auto wrapped -qboolean ItemParse_wrapped( itemDef_t *item, int handle ) +// resetonfeederchange +qboolean ItemParse_resetonfeederchange( itemDef_t *item, int handle ) { - item->window.flags |= WINDOW_WRAPPED; + item->typeData.list->resetonfeederchange = qtrue; return qtrue; } - -// horizontalscroll -qboolean ItemParse_horizontalscroll( itemDef_t *item, int handle ) +// auto wrapped +qboolean ItemParse_wrapped( itemDef_t *item, int handle ) { - item->window.flags |= WINDOW_HORIZONTAL; + item->window.flags |= WINDOW_WRAPPED; return qtrue; } + // type <integer> qboolean ItemParse_type( itemDef_t *item, int handle ) { @@ -6730,13 +6584,14 @@ qboolean ItemParse_type( itemDef_t *item, int handle ) switch( item->type ) { case ITEM_TYPE_LISTBOX: + case ITEM_TYPE_COMBOBOX: item->typeData.list = UI_Alloc( sizeof( listBoxDef_t ) ); memset( item->typeData.list, 0, sizeof( listBoxDef_t ) ); break; - case ITEM_TYPE_COMBO: - item->typeData.combo = UI_Alloc( sizeof( comboBoxDef_t ) ); - memset( item->typeData.combo, 0, sizeof( comboBoxDef_t ) ); + case ITEM_TYPE_CYCLE: + item->typeData.cycle = UI_Alloc( sizeof( cycleDef_t ) ); + memset( item->typeData.cycle, 0, sizeof( cycleDef_t ) ); break; case ITEM_TYPE_EDITFIELD: @@ -6771,19 +6626,23 @@ qboolean ItemParse_type( itemDef_t *item, int handle ) } // elementwidth, used for listbox image elements -// uses textalignx for storage qboolean ItemParse_elementwidth( itemDef_t *item, int handle ) { return PC_Float_Parse( handle, &item->typeData.list->elementWidth ); } // elementheight, used for listbox image elements -// uses textaligny for storage qboolean ItemParse_elementheight( itemDef_t *item, int handle ) { return PC_Float_Parse( handle, &item->typeData.list->elementHeight ); } +// dropitems, number of items to drop from a combobox +qboolean ItemParse_dropitems( itemDef_t *item, int handle ) +{ + return PC_Int_Parse( handle, &item->typeData.list->dropItems ); +} + // feeder <int> qboolean ItemParse_feeder( itemDef_t *item, int handle ) { @@ -7353,10 +7212,11 @@ keywordHash_t itemParseKeywords[] = { {"decoration", ItemParse_decoration, TYPE_ANY}, {"notselectable", ItemParse_notselectable, TYPE_LIST}, {"noscrollbar", ItemParse_noscrollbar, TYPE_LIST}, + {"resetonfeederchange", ItemParse_resetonfeederchange, TYPE_LIST}, {"wrapped", ItemParse_wrapped, TYPE_ANY}, - {"horizontalscroll", ItemParse_horizontalscroll, TYPE_ANY}, {"elementwidth", ItemParse_elementwidth, TYPE_LIST}, {"elementheight", ItemParse_elementheight, TYPE_LIST}, + {"dropitems", ItemParse_dropitems, TYPE_LIST}, {"feeder", ItemParse_feeder, TYPE_ANY}, {"elementtype", ItemParse_elementtype, TYPE_LIST}, {"columns", ItemParse_columns, TYPE_LIST}, @@ -7493,15 +7353,14 @@ void Item_InitControls( itemDef_t *item ) if( item == NULL ) return; - if( item->type == ITEM_TYPE_LISTBOX ) + if( Item_IsListBox( item ) ) { item->cursorPos = 0; if( item->typeData.list ) { item->typeData.list->cursorPos = 0; - item->typeData.list->startPos = 0; - item->typeData.list->endPos = 0; + Item_ListBox_SetStartPos( item, 0 ); item->typeData.list->cursorPos = 0; } } @@ -7994,6 +7853,14 @@ int Menu_Count( void ) return menuCount; } +void Menu_UpdateAll( void ) +{ + int i; + + for( i = 0; i < openMenuCount; i++ ) + Menu_Update( menuStack[ i ] ); +} + void Menu_PaintAll( void ) { int i; @@ -8012,7 +7879,7 @@ void Menu_PaintAll( void ) } for( i = 0; i < openMenuCount; i++ ) - Menu_Paint( menuStack[i], qfalse ); + Menu_Paint( menuStack[ i ], qfalse ); if( DC->getCVarValue( "ui_developer" ) ) { diff --git a/src/ui/ui_shared.h b/src/ui/ui_shared.h index 462a4bb4..29224757 100644 --- a/src/ui/ui_shared.h +++ b/src/ui/ui_shared.h @@ -42,34 +42,34 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MAX_OPEN_MENUS 16 #define WINDOW_MOUSEOVER 0x00000001 // mouse is over it, non exclusive -#define WINDOW_HASFOCUS 0x00000002 // has cursor focus, exclusive +#define WINDOW_HASFOCUS 0x00000002 // has cursor focus, exclusive #define WINDOW_VISIBLE 0x00000004 // is visible -#define WINDOW_GREY 0x00000008 // is visible but grey ( non-active ) -#define WINDOW_DECORATION 0x00000010 // for decoration only, no mouse, keyboard, etc.. +#define WINDOW_GREY 0x00000008 // is visible but grey ( non-active ) +#define WINDOW_DECORATION 0x00000010 // for decoration only, no mouse, keyboard, etc.. #define WINDOW_FADINGOUT 0x00000020 // fading out, non-active -#define WINDOW_FADINGIN 0x00000040 // fading in +#define WINDOW_FADINGIN 0x00000040 // fading in #define WINDOW_MOUSEOVERTEXT 0x00000080 // mouse is over it, non exclusive -#define WINDOW_INTRANSITION 0x00000100 // window is in transition -#define WINDOW_FORECOLORSET 0x00000200 // forecolor was explicitly set ( used to color alpha images or not ) -#define WINDOW_HORIZONTAL 0x00000400 // for list boxes and sliders, vertical is default this is set of horizontal -#define WINDOW_LB_LEFTARROW 0x00000800 // mouse is over left/up arrow -#define WINDOW_LB_RIGHTARROW 0x00001000 // mouse is over right/down arrow -#define WINDOW_LB_THUMB 0x00002000 // mouse is over thumb +#define WINDOW_INTRANSITION 0x00000100 // window is in transition +#define WINDOW_FORECOLORSET 0x00000200 // forecolor was explicitly set ( used to color alpha images or not ) +#define WINDOW_HORIZONTAL 0x00000400 // for list boxes and sliders, vertical is default this is set of horizontal +#define WINDOW_LB_UPARROW 0x00000800 // mouse is over up arrow +#define WINDOW_LB_DOWNARROW 0x00001000 // mouse is over down arrow +#define WINDOW_LB_THUMB 0x00002000 // mouse is over thumb #define WINDOW_LB_PGUP 0x00004000 // mouse is over page up #define WINDOW_LB_PGDN 0x00008000 // mouse is over page down -#define WINDOW_ORBITING 0x00010000 // item is in orbit +#define WINDOW_ORBITING 0x00010000 // item is in orbit #define WINDOW_OOB_CLICK 0x00020000 // close on out of bounds click #define WINDOW_WRAPPED 0x00080000 // wrap text -#define WINDOW_FORCED 0x00100000 // forced open +#define WINDOW_FORCED 0x00100000 // forced open #define WINDOW_POPUP 0x00200000 // popup -#define WINDOW_BACKCOLORSET 0x00400000 // backcolor was explicitly set -#define WINDOW_TIMEDVISIBLE 0x00800000 // visibility timing ( NOT implemented ) +#define WINDOW_BACKCOLORSET 0x00400000 // backcolor was explicitly set +#define WINDOW_TIMEDVISIBLE 0x00800000 // visibility timing ( NOT implemented ) // CGAME cursor type bits -#define CURSOR_NONE 0x00000001 -#define CURSOR_ARROW 0x00000002 -#define CURSOR_SIZER 0x00000004 +#define CURSOR_NONE 0x00000001 +#define CURSOR_ARROW 0x00000002 +#define CURSOR_SIZER 0x00000004 #ifdef CGAME #define STRING_POOL_SIZE 128*1024 @@ -82,16 +82,16 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define MAX_EDITFIELD 256 #define ITEM_VALUE_OFFSET 8 -#define ART_FX_BASE "menu/art/fx_base" -#define ART_FX_BLUE "menu/art/fx_blue" -#define ART_FX_CYAN "menu/art/fx_cyan" -#define ART_FX_GREEN "menu/art/fx_grn" -#define ART_FX_RED "menu/art/fx_red" -#define ART_FX_TEAL "menu/art/fx_teal" -#define ART_FX_WHITE "menu/art/fx_white" -#define ART_FX_YELLOW "menu/art/fx_yel" +#define ART_FX_BASE "menu/art/fx_base" +#define ART_FX_BLUE "menu/art/fx_blue" +#define ART_FX_CYAN "menu/art/fx_cyan" +#define ART_FX_GREEN "menu/art/fx_grn" +#define ART_FX_RED "menu/art/fx_red" +#define ART_FX_TEAL "menu/art/fx_teal" +#define ART_FX_WHITE "menu/art/fx_white" +#define ART_FX_YELLOW "menu/art/fx_yel" -#define ASSET_GRADIENTBAR "ui/assets/gradientbar2.tga" +#define ASSET_GRADIENTBAR "ui/assets/gradientbar2.tga" #define ASSET_SCROLLBAR "ui/assets/scrollbar.tga" #define ASSET_SCROLLBAR_ARROWDOWN "ui/assets/scrollbar_arrow_dwn_a.tga" #define ASSET_SCROLLBAR_ARROWUP "ui/assets/scrollbar_arrow_up_a.tga" @@ -100,9 +100,19 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define ASSET_SCROLL_THUMB "ui/assets/scrollbar_thumb.tga" #define ASSET_SLIDER_BAR "ui/assets/slider2.tga" #define ASSET_SLIDER_THUMB "ui/assets/sliderbutt_1.tga" -#define SCROLLBAR_SIZE 16.0f -#define SCROLLBAR_WIDTH (SCROLLBAR_SIZE*DC->aspectScale) -#define SCROLLBAR_HEIGHT SCROLLBAR_SIZE + +#define SCROLLBAR_ARROW_SIZE 16.0f +#define SCROLLBAR_ARROW_WIDTH (SCROLLBAR_ARROW_SIZE*DC->aspectScale) +#define SCROLLBAR_ARROW_HEIGHT SCROLLBAR_ARROW_SIZE +#define SCROLLBAR_SLIDER_X(_item) (_item->window.rect.x+_item->window.rect.w- \ + SCROLLBAR_ARROW_WIDTH-DC->aspectScale) +#define SCROLLBAR_SLIDER_Y(_item) (SCROLLBAR_Y(_item)+SCROLLBAR_ARROW_HEIGHT) +#define SCROLLBAR_SLIDER_HEIGHT(_item) (_item->window.rect.h-(SCROLLBAR_ARROW_HEIGHT*2.0f)-2.0f) +#define SCROLLBAR_X(_item) (_item->window.rect.x+DC->aspectScale) +#define SCROLLBAR_Y(_item) (_item->window.rect.y+1.0f) +#define SCROLLBAR_W(_item) (SCROLLBAR_SLIDER_X(_item)-SCROLLBAR_X(_item)) +#define SCROLLBAR_H(_item) (_item->window.rect.h-2.0f) + #define SLIDER_WIDTH (96.0f*DC->aspectScale) #define SLIDER_HEIGHT 16.0f #define SLIDER_THUMB_WIDTH (12.0f*DC->aspectScale) @@ -191,24 +201,31 @@ typedef struct listBoxDef_s { int startPos; int endPos; - int drawPadding; int cursorPos; + float elementWidth; float elementHeight; int elementStyle; + int dropItems; + int numColumns; columnInfo_t columnInfo[MAX_LB_COLUMNS]; + const char *doubleClick; + qboolean notselectable; qboolean noscrollbar; + + qboolean resetonfeederchange; + int lastFeederCount; } listBoxDef_t; -typedef struct comboBoxDef_s +typedef struct cycleDef_s { int cursorPos; } -comboBoxDef_t; +cycleDef_t; typedef struct editFieldDef_s { @@ -300,7 +317,7 @@ typedef struct itemDef_s listBoxDef_t *list; editFieldDef_t *edit; multiDef_t *multi; - comboBoxDef_t *combo; + cycleDef_t *cycle; modelDef_t *model; } typeData; // type specific data pointers } @@ -407,11 +424,11 @@ typedef struct qboolean ( *getOverstrikeMode )( void ); void ( *startLocalSound )( sfxHandle_t sfx, int channelNum ); qboolean ( *ownerDrawHandleKey )( int ownerDraw, int key ); - int ( *feederCount )( float feederID ); - const char *( *feederItemText )( float feederID, int index, int column, qhandle_t *handle ); - qhandle_t ( *feederItemImage )( float feederID, int index ); - void ( *feederSelection )( float feederID, int index ); - int ( *feederInitialise )( float feederID ); + int ( *feederCount )( int feederID ); + const char *( *feederItemText )( int feederID, int index, int column, qhandle_t *handle ); + qhandle_t ( *feederItemImage )( int feederID, int index ); + void ( *feederSelection )( int feederID, int index ); + int ( *feederInitialise )( int feederID ); void ( *keynumToStringBuf )( int keynum, char *buf, int buflen ); void ( *getBindingBuf )( int keynum, char *buf, int buflen ); void ( *setBinding )( int keynum, const char *binding ); @@ -475,6 +492,7 @@ qboolean PC_String_Parse( int handle, const char **out ); qboolean PC_Script_Parse( int handle, const char **out ); int Menu_Count( void ); void Menu_New( int handle ); +void Menu_UpdateAll( void ); void Menu_PaintAll( void ); menuDef_t *Menus_ActivateByName( const char *p ); menuDef_t *Menus_ReplaceActiveByName( const char *p ); @@ -510,6 +528,8 @@ void Controls_GetConfig( void ); void Controls_SetConfig( qboolean restart ); void Controls_SetDefaults( void ); +void trap_R_SetClipRegion( const float *region ); + //for cg_draw.c void Item_Text_Wrapped_Paint( itemDef_t *item ); const char *Item_Text_Wrap( const char *text, float scale, float width ); |