diff options
author | Andrey Nazarov <skuller@skuller.net> | 2007-08-14 20:18:08 +0000 |
---|---|---|
committer | Andrey Nazarov <skuller@skuller.net> | 2007-08-14 20:18:08 +0000 |
commit | f294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch) | |
tree | e8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/ui_menu.c |
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/ui_menu.c')
-rw-r--r-- | source/ui_menu.c | 1629 |
1 files changed, 1629 insertions, 0 deletions
diff --git a/source/ui_menu.c b/source/ui_menu.c new file mode 100644 index 0000000..4db1b44 --- /dev/null +++ b/source/ui_menu.c @@ -0,0 +1,1629 @@ +/* +Copyright (C) 1997-2001 Id Software, Inc. + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +as published by the Free Software Foundation; either version 2 +of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + +See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + +*/ + +#include "ui_local.h" + +static color_t colorField = { 15, 128, 235, 100 }; +static color_t colorGray = { 127, 127, 127, 255 }; + +/* +================= +Common_DoEnter +================= +*/ +static int Common_DoEnter( menuCommon_t *item ) { + int ret; + + if( ( ret = item->parent->callback( item->id, QM_ACTIVATE, 0 ) ) != QMS_NOTHANDLED ) { + return ret; + } + + return QMS_SILENT; +} + +/* +=================================================================== + +ACTION CONTROL + +=================================================================== +*/ + +/* +================= +Action_Init +================= +*/ +static void Action_Init( menuAction_t *a ) { + if( !a->generic.name ) { + Com_Error( ERR_FATAL, "Action_Init: NULL a->generic.name" ); + } + + a->generic.rect.x = a->generic.x; + a->generic.rect.y = a->generic.y; + UI_StringDimensions( &a->generic.rect, a->generic.uiFlags, a->generic.name ); +} + + +/* +================= +Action_Draw +================= +*/ +static void Action_Draw( menuAction_t *a ) { + uint32 flags; + + flags = a->generic.uiFlags; + if( a->generic.flags & QMF_HASFOCUS ) { + flags |= UI_ALTCOLOR; + } + + UI_DrawString( a->generic.x, a->generic.y, NULL, + flags, a->generic.name ); + + +} + +/* +=================================================================== + +BITMAP CONTROL + +=================================================================== +*/ + +/* +================= +Bitmap_Init +================= +*/ +void Bitmap_Init( menuBitmap_t *b ) { + if( !b->generic.name ) { + Com_Error( ERR_FATAL, "Bitmap_Init: NULL b->generic.name" ); + } + + b->generic.rect.x = b->generic.x; + b->generic.rect.y = b->generic.y; + b->generic.rect.width = b->generic.width; + b->generic.rect.height = b->generic.height; + + b->pic = ref.RegisterPic( b->generic.name ); + if( !b->pic && b->errorImage ) { + b->pic = ref.RegisterPic( b->errorImage ); + } + +} + +/* +================= +Bitmap_Draw +================= +*/ +static void Bitmap_Draw( menuBitmap_t *b ) { + ref.DrawStretchPic( b->generic.x, b->generic.y, + b->generic.width, b->generic.height, b->pic ); +} + +/* +=================================================================== + +STATIC CONTROL + +=================================================================== +*/ + +/* +================= +Static_Init +================= +*/ +static void Static_Init( menuStatic_t *s ) { + if( !s->generic.name ) { + Com_Error( ERR_FATAL, "Static_Init: NULL s->generic.name" ); + } + + if( !s->maxChars ) { + s->maxChars = MAX_STRING_CHARS; + } + + s->generic.rect.x = s->generic.x; + s->generic.rect.y = s->generic.y; + + UI_StringDimensions( &s->generic.rect, + s->generic.uiFlags, s->generic.name ); + +} + +/* +================= +Static_Draw +================= +*/ +static void Static_Draw( menuStatic_t *s ) { + UI_DrawString( s->generic.x, s->generic.y, + ( s->generic.flags & QMF_CUSTOM_COLOR ) ? s->generic.color : NULL, + s->generic.uiFlags, s->generic.name ); +} + +/* +=================================================================== + +STATIC CONTROL + +=================================================================== +*/ + +/* +================= +Keybind_Init +================= +*/ +static void Keybind_Init( menuKeybind_t *k ) { + if( !k->generic.name ) { + Com_Error( ERR_FATAL, "Keybind_Init: NULL k->generic.name" ); + } + + k->generic.uiFlags &= ~( UI_LEFT | UI_RIGHT ); + + k->generic.rect.x = k->generic.x + LCOLUMN_OFFSET; + k->generic.rect.y = k->generic.y; + + UI_StringDimensions( &k->generic.rect, + k->generic.uiFlags | UI_RIGHT, k->generic.name ); + + k->generic.rect.x = k->generic.x; + k->generic.rect.y = k->generic.y; + + k->generic.rect.width += ( RCOLUMN_OFFSET - LCOLUMN_OFFSET ) + + Q_DrawStrlen( k->binding ) * SMALLCHAR_WIDTH; +} + +/* +================= +Keybind_Draw +================= +*/ +static void Keybind_Draw( menuKeybind_t *k ) { + char string[MAX_STRING_CHARS]; + byte *color; + uint32 flags; + + color = NULL; + flags = UI_ALTCOLOR; + if( k->generic.flags & QMF_HASFOCUS ) { + if( k->generic.parent->keywait ) { + //UI_DrawChar( k->generic.x + RCOLUMN_OFFSET / 2, k->generic.y, k->generic.uiFlags | UI_RIGHT, '=' ); + } else if( ( uis.realtime >> 8 ) & 1 ) { + UI_DrawChar( k->generic.x + RCOLUMN_OFFSET / 2, k->generic.y, k->generic.uiFlags | UI_RIGHT, 13 ); + } + } else { + if( k->generic.parent->keywait ) { + color = colorGray; + flags = 0; + } + } + + UI_DrawString( k->generic.x + LCOLUMN_OFFSET, k->generic.y, color, + k->generic.uiFlags | UI_RIGHT | flags, k->generic.name ); + + if( k->altbinding[0] ) { + Com_sprintf( string, sizeof( string ), "%s or %s", k->binding, k->altbinding ); + } else if( k->binding[0] ) { + strcpy( string, k->binding ); + } else { + strcpy( string, "???" ); + } + + UI_DrawString( k->generic.x + RCOLUMN_OFFSET, k->generic.y, color, + k->generic.uiFlags | UI_LEFT, string ); +} + +/* +=================================================================== + +FIELD CONTROL + +=================================================================== +*/ + +/* +================= +Field_Init +================= +*/ +static void Field_Init( menuField_t *f ) { + f->generic.uiFlags &= ~( UI_LEFT | UI_RIGHT ); + + f->generic.rect.x = f->generic.x + LCOLUMN_OFFSET; + f->generic.rect.y = f->generic.y; + + if( f->generic.name ) { + UI_StringDimensions( &f->generic.rect, + f->generic.uiFlags | UI_RIGHT, f->generic.name ); + } else { + f->generic.rect.width = 0; + f->generic.rect.height = SMALLCHAR_HEIGHT; + } + + f->generic.rect.width += RCOLUMN_OFFSET + + f->field.visibleChars * SMALLCHAR_WIDTH; + +} + + +/* +================= +Field_Draw +================= +*/ +static void Field_Draw( menuField_t *f ) { + uint32 flags; + + if( f->generic.name ) { + UI_DrawString( f->generic.x + LCOLUMN_OFFSET, f->generic.y, NULL, + f->generic.uiFlags | UI_RIGHT | UI_ALTCOLOR, f->generic.name ); + } + + ref.DrawFillEx( f->generic.x + RCOLUMN_OFFSET, f->generic.y, + f->field.visibleChars * SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT, colorField ); + + flags = f->generic.uiFlags; + if( f->generic.flags & QMF_HASFOCUS ) { + flags |= UI_DRAWCURSOR; + } + + IF_Draw( &f->field, f->generic.x + RCOLUMN_OFFSET, f->generic.y, + flags, uis.fontHandle ); +} + +/* +================= +Field_Key +================= +*/ +static int Field_Key( menuField_t *f, int key ) { + qboolean ret; + + ret = IF_KeyEvent( &f->field, key ); + return ret ? QMS_SILENT : QMS_NOTHANDLED; +} + +/* +================= +Field_Key +================= +*/ +static int Field_Char( menuField_t *f, int key ) { + int ret; + + if( f->generic.flags & QMF_NUMBERSONLY ) { + if( key < '0' || key > '9' ) { + return QMS_BEEP; + } + } + + ret = IF_CharEvent( &f->field, key ); + f->generic.parent->callback( f->generic.id, QM_CHANGE, ret ); + + return ret ? QMS_SILENT : QMS_NOTHANDLED; +} + +/* +=================================================================== + +SPIN CONTROL + +=================================================================== +*/ + +/* +================= +SpinControl_Init +================= +*/ +void SpinControl_Init( menuSpinControl_t *s ) { + const char **n; + int maxLength, length; + + s->generic.uiFlags &= ~( UI_LEFT | UI_RIGHT ); + + s->generic.rect.x = s->generic.x + LCOLUMN_OFFSET; + s->generic.rect.y = s->generic.y; + + UI_StringDimensions( &s->generic.rect, + s->generic.uiFlags | UI_RIGHT, s->generic.name ); + + maxLength = 0; + s->numItems = 0; + n = s->itemnames; + while( *n ) { + length = Q_DrawStrlen( *n ); + + if( maxLength < length ) { + maxLength = length; + } + s->numItems++; + n++; + } + + s->generic.rect.width += ( RCOLUMN_OFFSET - LCOLUMN_OFFSET ) + + maxLength * SMALLCHAR_WIDTH; + +} + +/* +================= +SpinControl_DoEnter +================= +*/ +static int SpinControl_DoEnter( menuSpinControl_t *s ) { + int oldvalue; + + oldvalue = s->curvalue; + s->curvalue++; + + if( s->curvalue == s->numItems ) + s->curvalue = 0; + + s->generic.parent->callback( s->generic.id, QM_CHANGE, oldvalue ); + + return QMS_MOVE; +} + +/* +================= +SpinControl_DoSlide +================= +*/ +static int SpinControl_DoSlide( menuSpinControl_t *s, int dir ) { + int oldvalue; + + oldvalue = s->curvalue; + s->curvalue += dir; + + if( s->curvalue < 0 ) { + s->curvalue = s->numItems - 1; + } else if( s->curvalue >= s->numItems ) { + s->curvalue = 0; + } + + s->generic.parent->callback( s->generic.id, QM_CHANGE, oldvalue ); + + return QMS_MOVE; + +} + +/* +================= +SpinControl_Draw +================= +*/ +static void SpinControl_Draw( menuSpinControl_t *s ) { + UI_DrawString( s->generic.x + LCOLUMN_OFFSET, s->generic.y, NULL, + s->generic.uiFlags | UI_RIGHT | UI_ALTCOLOR, s->generic.name ); + + if( s->generic.flags & QMF_HASFOCUS ) { + if( ( uis.realtime >> 8 ) & 1 ) { + UI_DrawChar( s->generic.x + RCOLUMN_OFFSET / 2, s->generic.y, + s->generic.uiFlags | UI_RIGHT, 13 ); + } + } + + UI_DrawString( s->generic.x + RCOLUMN_OFFSET, s->generic.y, NULL, + s->generic.uiFlags, s->itemnames[s->curvalue] ); +} + + +/* +=================================================================== + +LIST CONTROL + +=================================================================== +*/ + +/* +================= +MenuList_ValidatePrestep +================= +*/ +void MenuList_ValidatePrestep( menuList_t *l ) { + if( l->numItems <= l->maxItems || l->prestep < 0 ) { + l->prestep = 0; + return; + } + + if( l->prestep > l->numItems - l->maxItems ) { + l->prestep = l->numItems - l->maxItems; + } + +} + +/* +================= +MenuList_Init +================= +*/ +void MenuList_Init( menuList_t *l ) { + const char **n; + int height; + int i; + + l->numItems = 0; + if( l->itemnames ) { + n = l->itemnames; + while( *n ) { + l->numItems++; + n++; + } + } + + height = l->generic.height; + if( l->drawNames ) { + height -= MLIST_SPACING; + } + + l->maxItems = height / MLIST_SPACING; + + clamp( l->curvalue, 0, l->numItems - 1 ); + + MenuList_ValidatePrestep( l ); + + l->generic.rect.x = l->generic.x; + l->generic.rect.y = l->generic.y; + + l->generic.rect.width = 0; + for( i = 0; i < l->numcolumns; i++ ) { + l->generic.rect.width += l->columns[i].width; + } + + l->generic.rect.height = l->generic.height; + +} + +/* +================= +MenuList_SetValue +================= +*/ +void MenuList_SetValue( menuList_t *l, int value ) { + clamp( value, 0, l->numItems - 1 ); + + l->curvalue = value; + + // set prestep accordingly + if( l->numItems > l->maxItems ) { + if( l->prestep > l->curvalue ) { + l->prestep = l->curvalue; + } else if( l->prestep < l->curvalue - l->maxItems + 1 ) { + l->prestep = l->curvalue - l->maxItems + 1; + } + } else { + l->prestep = 0; + } + + l->generic.parent->callback( l->generic.id, QM_CHANGE, l->curvalue ); +} + + +/* +================= +MenuList_HitTest +================= +*/ +int MenuList_HitTest( menuList_t *l, int mx, int my ) { + const char **n; + int i; + vrect_t rect; + + if( !l->itemnames ) { + return -1; + } + + rect.x = l->generic.rect.x; + rect.y = l->generic.rect.y; + rect.width = l->generic.rect.width; + rect.height = MLIST_SPACING; + + if( l->drawNames ) { + rect.y += MLIST_SPACING; + } + + n = l->itemnames + l->prestep; + for( i = 0; i < l->maxItems && *n; i++ ) { + if( UI_CursorInRect( &rect, mx, my ) ) { + return n - l->itemnames; + } + + rect.y += MLIST_SPACING; + n++; + + } + + return -1; +} + +/* +================= +MenuList_Key +================= +*/ +static int MenuList_Key( menuList_t *l, int key ) { + int i; + + if( !l->itemnames ) { + return QMS_NOTHANDLED; + } + + if( key > 32 && key < 127 ) { + const char **n; + + if( uis.realtime > l->scratchTime + 1300 ) { + l->scratchCount = 0; + l->scratchTime = uis.realtime; + } + + if( l->scratchCount >= sizeof( l->scratch ) - 1 ) { + return QMS_NOTHANDLED; + } + + l->scratch[l->scratchCount++] = key; + l->scratch[l->scratchCount] = 0; + + //l->scratchTime = uis.realtime; + + if( !Q_stricmpn( l->itemnames[l->curvalue], + l->scratch, l->scratchCount ) ) + { + return QMS_NOTHANDLED; + } + + i = 0; + n = l->itemnames; + while( *n ) { + if( !Q_stricmpn( *n, l->scratch, l->scratchCount ) ) { + MenuList_SetValue( l, i ); + return QMS_SILENT; + } + i++; + n++; + } + + return QMS_NOTHANDLED; + } + + l->scratchCount = 0; + + switch( key ) { + case K_UPARROW: + case K_KP_UPARROW: + if( l->curvalue > 0 ) { + l->curvalue--; + l->generic.parent->callback( l->generic.id, QM_CHANGE, l->curvalue ); + + // scroll contents up + if( l->prestep > l->curvalue ) { + l->prestep = l->curvalue; + } + return QMS_MOVE; + } + return QMS_BEEP; + + case K_DOWNARROW: + case K_KP_DOWNARROW: + if( l->curvalue < l->numItems - 1 ) { + l->curvalue++; + l->generic.parent->callback( l->generic.id, QM_CHANGE, l->curvalue ); + + // scroll contents down + if( l->prestep < l->curvalue - l->maxItems + 1 ) { + l->prestep = l->curvalue - l->maxItems + 1; + } + return QMS_MOVE; + } + return QMS_BEEP; + + case K_HOME: + case K_KP_HOME: + l->prestep = 0; + return QMS_SILENT; + + case K_END: + case K_KP_END: + if( l->numItems > l->maxItems ) { + l->prestep = l->numItems - l->maxItems; + } + return QMS_SILENT; + + case K_MWHEELUP: + if( keys.IsDown( K_CTRL ) ) { + l->prestep -= 4; + } else { + l->prestep -= 2; + } + MenuList_ValidatePrestep( l ); + return QMS_SILENT; + + case K_MWHEELDOWN: + if( keys.IsDown( K_CTRL ) ) { + l->prestep += 4; + } else { + l->prestep += 2; + } + MenuList_ValidatePrestep( l ); + return QMS_SILENT; + + case K_PGUP: + case K_KP_PGUP: + l->prestep -= l->maxItems; + MenuList_ValidatePrestep( l ); + return QMS_SILENT; + + case K_PGDN: + case K_KP_PGDN: + l->prestep += l->maxItems; + MenuList_ValidatePrestep( l ); + return QMS_SILENT; + + case K_MOUSE1: + i = MenuList_HitTest( l, uis.mouseCoords[0], uis.mouseCoords[1] ); + if( i != -1 ) { + if( l->curvalue == i && uis.realtime - l->clickTime < DOUBLE_CLICK_DELAY ) { + return l->generic.parent->callback( l->generic.id, QM_ACTIVATE, i ); + } + l->clickTime = uis.realtime; + l->curvalue = i; + l->generic.parent->callback( l->generic.id, QM_CHANGE, i ); + } + return QMS_SILENT; + case K_MOUSE2: + case K_MOUSE3: + i = MenuList_HitTest( l, uis.mouseCoords[0], uis.mouseCoords[1] ); + if( i != -1 ) { + l->curvalue = i; + l->generic.parent->callback( l->generic.id, QM_CHANGE, i ); + } + return QMS_SILENT; + } + + return QMS_NOTHANDLED; +} + +/* +================= +MenuList_MouseMove +================= +*/ +int MenuList_MouseMove( menuList_t *l ) { + return QMS_NOTHANDLED; +} + +/* +================= +MenuList_DrawcolumnString +================= +*/ +static void MenuList_DrawcolumnString( int x, int y, uint32 flags, + menuListColumn_t *column, + const char *string ) +{ + clipRect_t rc; + + rc.left = x; + rc.right = x + column->width - 1; + rc.top = 0; + rc.bottom = 0; + + if( ( column->uiFlags & UI_CENTER ) == UI_CENTER ) { + x += column->width / 2; + } else if( column->uiFlags & UI_RIGHT ) { + x += column->width - MLIST_PRESTEP; + } else { + x += MLIST_PRESTEP; + } + + ref.SetClipRect( DRAW_CLIP_RIGHT|DRAW_CLIP_LEFT, &rc ); + UI_DrawString( x + 1, y + 1, NULL, column->uiFlags | flags, string ); + if( uis.glconfig.renderer == GL_RENDERER_SOFTWARE ) { + ref.SetClipRect( DRAW_CLIP_MASK, &uis.clipRect ); + } else { + ref.SetClipRect( DRAW_CLIP_DISABLED, NULL ); + } +} + + + +/* +================= +MenuList_Draw +================= +*/ +static void MenuList_Draw( menuList_t *l ) { + const char **n; + int x, y, xx, yy; + int i, j; + int width, height; + const char *s; + vrect_t rect; + float pageFrac, prestepFrac; + int barHeight; + + if( !l->itemnames ) { + return; + } + + x = l->generic.rect.x; + y = l->generic.rect.y; + width = l->generic.rect.width; + height = l->generic.rect.height; + + // draw header + if( l->drawNames ) { + xx = x; + for( j = 0; j < l->numcolumns; j++ ) { + ref.DrawFillEx( xx, y, + l->columns[j].width - 1, + MLIST_SPACING - 1, + colorField ); + + if( l->columns[j].name ) { + MenuList_DrawcolumnString( xx, y, UI_ALTCOLOR, + &l->columns[j], l->columns[j].name ); + } + xx += l->columns[j].width; + } + y += MLIST_SPACING; + height -= MLIST_SPACING; + } + + if( !( l->mlFlags & MLF_HIDE_SCROLLBAR ) && + ( !( l->mlFlags & MLF_HIDE_SCROLLBAR_EMPTY ) || l->numItems > l->maxItems ) ) + { + barHeight = height - MLIST_SPACING * 2; + yy = y + MLIST_SPACING; + + if( !( l->mlFlags & MLF_HIDE_BACKGROUND ) ) { + rect.x = x + width; + rect.y = yy; + rect.width = MLIST_SCROLLBAR_WIDTH - 1; + rect.height = barHeight; + + // draw scrollbar background + UIS_FillRectEx( &rect, colorField ); + } + + if( l->numItems > l->maxItems ) { + pageFrac = ( float )l->maxItems / l->numItems; + prestepFrac = ( float )l->prestep / l->numItems; + } else { + pageFrac = 1; + prestepFrac = 0; + } + + rect.x = x + width; + rect.y = yy + Q_rint( barHeight * prestepFrac ); + rect.width = MLIST_SCROLLBAR_WIDTH - 1; + rect.height = Q_rint( barHeight * pageFrac ); + + // draw scrollbar thumb + UIS_FillRectEx( &rect, colorField ); + + } + + xx = x; + for( j = 0; j < l->numcolumns; j++ ) { + ref.DrawFillEx( xx, y, + l->columns[j].width - 1, + height, + colorField ); + + xx += l->columns[j].width; + } + + yy = y; + n = l->itemnames + l->prestep; + for( i = 0; i < l->maxItems && *n; i++ ) { + // draw selection + if( !( l->generic.flags & QMF_DISABLED ) && ( n - l->itemnames == l->curvalue ) ) { + ref.DrawFillEx( x, yy, width - 1, MLIST_SPACING, colorField ); + } + + // draw contents + s = *n; + xx = x; + for( j = 0; j < l->numcolumns; j++ ) { + if( !*s ) { + break; + } + + MenuList_DrawcolumnString( xx, yy, 0, &l->columns[j], s ); + + xx += l->columns[j].width; + s += strlen( s ) + 1; + } + + yy += MLIST_SPACING; + n++; + } +} + +/* +================= +MenuList_GetSize +================= +*/ +void MenuList_GetSize( vrect_t *rc, menuList_t *l ) { + rc->x = l->generic.rect.x; + rc->y = l->generic.rect.y; + rc->width = l->generic.rect.width; + rc->height = l->generic.rect.height; + + // TODO: move this somewhere else... + if( !( l->mlFlags & MLF_HIDE_SCROLLBAR ) ) { + rc->width += MLIST_SCROLLBAR_WIDTH; + } +} + +/* +=================================================================== + +IMAGE LIST CONTROL + +=================================================================== +*/ + +/* +================= +ImageList_NumItems +================= +*/ +static int ImageList_NumItems( const imageList_t *l ) { + const qhandle_t *n; + int numItems; + + numItems = 0; + n = l->images; + while( *n ) { + numItems++; + n++; + } + + return numItems; +} + +/* +================= +ImageList_HitTest +================= +*/ +int ImageList_HitTest( imageList_t *l, int mx, int my ) { + int i, j; + int xx, yy; + const qhandle_t *pics; + vrect_t rect; + + pics = l->images + l->prestep; + + + xx = l->generic.x; + yy = l->generic.y; + + if( l->name ) { + yy += SMALLCHAR_HEIGHT * 2; + } + + for( i=0 ; i<l->numRows && *pics ; i++ ) { + xx = l->generic.x; + for( j=0 ; j<l->numcolumns && *pics ; j++ ) { + rect.x = xx; + rect.y = yy; + rect.width = l->imageWidth; + rect.height = l->imageHeight; + if( UI_CursorInRect( &rect, mx, my ) ) { + return l->prestep + i * l->numcolumns + j; + } + + xx += SMALLCHAR_WIDTH * 2 + l->imageWidth; + pics++; + + } + yy += SMALLCHAR_HEIGHT * 2 + l->imageHeight; + + } + + return -1; +} + +/* +================= +ImageList_UpdatePos +================= +*/ +static void ImageList_UpdatePos( imageList_t *l ) { + l->prestep = l->curvalue - l->curvalue % ( l->numRows * l->numcolumns ); + l->generic.parent->callback( l->generic.id, QM_CHANGE, l->curvalue ); +} + +/* +================= +ImageList_Key +================= +*/ +static int ImageList_Key( imageList_t *l, int key ) { + int i; + int screenPos, numItems; + + if( key > 32 && key < 127 ) { + const char **n; + + i = 0; + n = l->names; + while( *n ) { + if( Q_tolower( *n[0] ) == Q_tolower( key ) ) { + l->curvalue = i; + ImageList_UpdatePos( l ); + return QMS_SILENT; + } + i++; + n++; + } + + return QMS_NOTHANDLED; + } + + screenPos = l->curvalue % ( l->numRows * l->numcolumns ); + numItems = ImageList_NumItems( l ); + + switch( key ) { + case K_UPARROW: + case K_KP_UPARROW: + if( screenPos >= l->numcolumns ) { + l->curvalue -= l->numcolumns; + ImageList_UpdatePos( l ); + return QMS_MOVE; + } + return QMS_BEEP; + case K_DOWNARROW: + case K_KP_DOWNARROW: + if( screenPos < l->numRows * ( l->numcolumns - 1 ) && l->curvalue + l->numcolumns < numItems ) { + l->curvalue += l->numcolumns; + ImageList_UpdatePos( l ); + return QMS_MOVE; + } + return QMS_BEEP; + case K_LEFTARROW: + case K_KP_LEFTARROW: + if( screenPos % l->numcolumns > 0 ) { + l->curvalue--; + ImageList_UpdatePos( l ); + return QMS_MOVE; + } + if( l->curvalue >= l->numRows * l->numcolumns ) { + l->curvalue -= l->numRows * ( l->numcolumns - 1 ) + 1; + ImageList_UpdatePos( l ); + return QMS_MOVE; + } + return QMS_BEEP; + case K_RIGHTARROW: + case K_KP_RIGHTARROW: + if( screenPos % l->numcolumns < l->numcolumns - 1 && l->curvalue < numItems - 1 ) { + l->curvalue++; + ImageList_UpdatePos( l ); + return QMS_MOVE; + } + if( l->curvalue - l->curvalue % ( l->numRows * l->numcolumns ) < numItems - numItems % ( l->numRows * l->numcolumns ) ) { + l->curvalue += l->numRows * ( l->numcolumns - 1 ) + 1; + if( l->curvalue > numItems - 1 ) { + l->curvalue = ( numItems - 1 ) - ( numItems - 1 ) % l->numcolumns; + } + ImageList_UpdatePos( l ); + return QMS_MOVE; + } + return QMS_BEEP; + case K_HOME: + case K_KP_HOME: + l->prestep = 0; + return QMS_SILENT; + case K_END: + case K_KP_END: + l->prestep = ImageList_NumItems( l ) - l->numRows * l->numcolumns; + return QMS_SILENT; + case K_MWHEELUP: + case K_PGUP: + case K_KP_PGUP: + if( l->prestep > 0 ) { + l->prestep -= l->numRows * l->numcolumns; + } + return QMS_SILENT; + case K_MWHEELDOWN: + case K_PGDN: + case K_KP_PGDN: + if( l->prestep < ImageList_NumItems( l ) - l->numRows * l->numcolumns ) { + l->prestep += l->numRows * l->numcolumns; + } + return QMS_SILENT; + case K_MOUSE1: + i = ImageList_HitTest( l, uis.mouseCoords[0], uis.mouseCoords[1] ); + if( i != -1 ) { + if( l->curvalue == i && uis.realtime - l->clickTime < DOUBLE_CLICK_DELAY ) { + return l->generic.parent->callback( l->generic.id, QM_ACTIVATE, i ); + } + l->clickTime = uis.realtime; + l->curvalue = i; + ImageList_UpdatePos( l ); + } + return QMS_SILENT; + } + + return QMS_NOTHANDLED; +} + +/* +================= +ImageList_Draw +================= +*/ +static void ImageList_Draw( imageList_t *l ) { +#if 0 + int i, j; + int xx, yy; + const char **n; + const qhandle_t *pics; + color_t color = { 15, 128, 235, 255 }; + + pics = l->images + l->prestep; + n = l->names + l->prestep; + + xx = l->generic.x; + yy = l->generic.y; + + if( l->name ) { + UI_DrawString( xx + ( l->imageWidth + SMALLCHAR_WIDTH * 2 ) * l->numcolumns / 2, yy, colorGreen, UI_CENTER, l->name ); + yy += SMALLCHAR_HEIGHT * 2; + } + + for( i=0 ; i<l->numRows && *pics ; i++ ) { + xx = l->generic.x; + for( j=0 ; j<l->numcolumns && *pics ; j++ ) { + if( i * l->numcolumns + j == l->curvalue - l->prestep ) { + + color[3] = 255; + + UIS_DrawStretchPicByName( xx - 6, yy - 6, l->imageWidth + 12, l->imageHeight + 12, "frame" ); + } + + ref.DrawStretchPic( xx, yy, l->imageWidth, l->imageHeight, *pics ); + + if( *n ) { + UI_DrawString( xx + l->imageWidth / 2, yy + l->imageHeight, NULL, UI_CENTER, *n ); + } + xx += SMALLCHAR_WIDTH * 2 + l->imageWidth; + pics++; + n++; + } + yy += SMALLCHAR_HEIGHT * 2 + l->imageHeight; + + } +#endif +} + +/* +================= +ImageList_GetSize +================= +*/ +void ImageList_GetSize( vrect_t *rc, imageList_t *l ) { + rc->x = l->generic.x; + rc->y = l->generic.y; + rc->width = l->numcolumns * ( l->imageWidth + SMALLCHAR_WIDTH * 2 ); + rc->height = l->numRows * ( l->imageHeight + SMALLCHAR_HEIGHT * 2 ); +} + +/* +=================================================================== + +SLIDER CONTROL + +=================================================================== +*/ + +#define SLIDER_RANGE 10 + +static void Slider_Init( menuSlider_t *s ) { + if( s->curvalue > s->maxvalue ) + s->curvalue = s->maxvalue; + else if( s->curvalue < s->minvalue ) + s->curvalue = s->minvalue; +} + +static int Slider_Key( menuSlider_t *s, int key ) { + switch( key ) { + case K_END: + s->curvalue = s->maxvalue; + return QMS_MOVE; + case K_HOME: + s->curvalue = s->minvalue; + return QMS_MOVE; + } + + return QMS_NOTHANDLED; +} + + +/* +================= +Slider_DoSlide +================= +*/ +static int Slider_DoSlide( menuSlider_t *s, int dir ) { + int ret; + + s->curvalue += dir; + + if( s->curvalue > s->maxvalue ) + s->curvalue = s->maxvalue; + else if( s->curvalue < s->minvalue ) + s->curvalue = s->minvalue; + + if( ( ret = s->generic.parent->callback( s->generic.id, QM_CHANGE, s->curvalue ) ) != QMS_NOTHANDLED ) { + return ret; + } + + return QMS_SILENT; +} + +/* +================= +Slider_Draw +================= +*/ +static void Slider_Draw( menuSlider_t *s ) { + int i, flags; + float pos; + + flags = s->generic.uiFlags & ~( UI_LEFT | UI_RIGHT ); + + if( s->generic.flags & QMF_HASFOCUS ) { + if( ( uis.realtime >> 8 ) & 1 ) { + UI_DrawChar( s->generic.x + RCOLUMN_OFFSET / 2, s->generic.y, s->generic.uiFlags | UI_RIGHT, 13 ); + } + } + + UI_DrawString( s->generic.x + LCOLUMN_OFFSET, s->generic.y, NULL, + flags | UI_RIGHT | UI_ALTCOLOR, s->generic.name ); + + UI_DrawChar( s->generic.x + RCOLUMN_OFFSET, s->generic.y, flags | UI_LEFT, 128 ); + + for( i = 0 ; i < SLIDER_RANGE ; i++ ) + UI_DrawChar( RCOLUMN_OFFSET + s->generic.x + i * SMALLCHAR_WIDTH + SMALLCHAR_WIDTH, s->generic.y, flags | UI_LEFT, 129 ); + + UI_DrawChar( RCOLUMN_OFFSET + s->generic.x + i * SMALLCHAR_WIDTH + SMALLCHAR_WIDTH, s->generic.y, flags | UI_LEFT, 130 ); + + if( s->maxvalue <= s->minvalue ) { + pos = 0; + } else { + pos = ( s->curvalue - s->minvalue ) / + ( float )( s->maxvalue - s->minvalue ); + clamp( pos, 0, 1 ); + } + + UI_DrawChar( SMALLCHAR_WIDTH + RCOLUMN_OFFSET + s->generic.x + ( SLIDER_RANGE - 1 ) * SMALLCHAR_WIDTH * pos, s->generic.y, flags | UI_LEFT, 131 ); + +} + +/* +================= +Slider_GetSize +================= +*/ +static void Slider_GetSize( vrect_t *rc, menuSlider_t *s ) { + int len = strlen( s->generic.name ) * SMALLCHAR_WIDTH; + + rc->x = s->generic.x + LCOLUMN_OFFSET - len; + rc->y = s->generic.y; + + rc->width = 32 + len + ( SLIDER_RANGE + 2 ) * SMALLCHAR_WIDTH; + rc->height = SMALLCHAR_HEIGHT; +} + + +/* +=================================================================== + +MISC + +=================================================================== +*/ + +/* +================= +Separator_Draw +================= +*/ +static void Separator_Draw( menuSeparator_t *s ) { + if( s->generic.name ) + UI_DrawString( s->generic.x, s->generic.y, NULL, UI_RIGHT, s->generic.name ); +} + +/* +================= +Menu_AddItem +================= +*/ +void Menu_AddItem( menuFrameWork_t *menu, void *item ) { + if( menu->nitems >= MAXMENUITEMS ) { + return; + } + + menu->items[menu->nitems++] = item; + ((menuCommon_t *)item)->parent = menu; + + switch( ((menuCommon_t *)item)->type ) { + case MTYPE_FIELD: + Field_Init( (menuField_t *)item ); + break; + case MTYPE_SLIDER: + Slider_Init( (menuSlider_t *)item ); + break; + case MTYPE_LIST: + MenuList_Init( (menuList_t *)item ); + break; + case MTYPE_SPINCONTROL: + SpinControl_Init( (menuSpinControl_t *)item ); + break; + case MTYPE_ACTION: + Action_Init( (menuAction_t *)item ); + break; + case MTYPE_SEPARATOR: + //Separator_Init( (menuSeparator_t *)item ); + break; + case MTYPE_BITMAP: + Bitmap_Init( (menuBitmap_t *)item ); + break; + case MTYPE_IMAGELIST: + //ImageList_Init( (imageList_t *)item ); + break; + case MTYPE_STATIC: + Static_Init( (menuStatic_t *)item ); + break; + case MTYPE_KEYBIND: + Keybind_Init( (menuKeybind_t *)item ); + break; + default: + Com_Error( ERR_FATAL, "Menu_AddItem: unknown item type" ); + break; + } + + +} + +menuCommon_t *Menu_ItemAtCursor( menuFrameWork_t *m ) { + menuCommon_t *item; + int i; + + for( i=0 ; i<m->nitems ; i++ ) { + item = (menuCommon_t *)m->items[i]; + + if( item->flags & QMF_HASFOCUS ) { + return item; + } + } + + return NULL; + +} + +void Menu_SetFocus( menuCommon_t *focus ) { + menuFrameWork_t *menu; + menuCommon_t *item; + int i; + + if( focus->flags & QMF_HASFOCUS ) { + return; + } + + menu = focus->parent; + + for( i=0 ; i<menu->nitems ; i++ ) { + item = (menuCommon_t *)menu->items[i]; + + if( item == focus ) { + item->flags |= QMF_HASFOCUS; + menu->callback( item->id, QM_GOTFOCUS, 0 ); + } else if( item->flags & QMF_HASFOCUS ) { + item->flags &= ~QMF_HASFOCUS; + menu->callback( item->id, QM_LOSTFOCUS, 0 ); + } + } + +} + +/* +================= +Menu_AdjustCursor + +This function takes the given menu, the direction, and attempts +to adjust the menu's cursor so that it's at the next available +slot. +================= +*/ +int Menu_AdjustCursor( menuFrameWork_t *m, int dir ) { + menuCommon_t *item; + int cursor, pos; + int i; + + pos = 0; + for( i=0 ; i<m->nitems ; i++ ) { + item = (menuCommon_t *)m->items[i]; + + if( item->flags & QMF_HASFOCUS ) { + pos = i; + break; + } + } + + /* + ** crawl in the direction indicated until we find a valid spot + */ + cursor = pos; + if( dir == 1 ) { + do { + cursor++; + if( cursor >= m->nitems ) + cursor = 0; + + item = (menuCommon_t *)m->items[cursor]; + if( UI_IsItemSelectable( item ) ) + break; + } while( cursor != pos ); + } else { + do { + cursor--; + if( cursor < 0 ) + cursor = m->nitems - 1; + + item = (menuCommon_t *)m->items[cursor]; + if( UI_IsItemSelectable( item ) ) + break; + } while( cursor != pos ); + } + + Menu_SetFocus( item ); + + return QMS_MOVE; +} + + + + + +/* +================= +Menu_Draw +================= +*/ +void Menu_Draw( menuFrameWork_t *menu ) { + menuCommon_t *item; + int i; + +// +// draw contents +// + for( i = 0; i < menu->nitems; i++ ) { + item = ( menuCommon_t * )menu->items[i]; + if( item->flags & QMF_HIDDEN ) { + continue; + } + + switch( item->type ) { + case MTYPE_FIELD: + Field_Draw( (menuField_t *)item ); + break; + case MTYPE_SLIDER: + Slider_Draw( (menuSlider_t *)item ); + break; + case MTYPE_LIST: + MenuList_Draw( (menuList_t *)item ); + break; + case MTYPE_SPINCONTROL: + SpinControl_Draw( (menuSpinControl_t *)item ); + break; + case MTYPE_ACTION: + Action_Draw( (menuAction_t *)item ); + break; + case MTYPE_SEPARATOR: + Separator_Draw( (menuSeparator_t *)item ); + break; + case MTYPE_BITMAP: + Bitmap_Draw( (menuBitmap_t *)item ); + break; + case MTYPE_IMAGELIST: + ImageList_Draw( (imageList_t *)item ); + break; + case MTYPE_STATIC: + Static_Draw( (menuStatic_t *)item ); + break; + case MTYPE_KEYBIND: + Keybind_Draw( (menuKeybind_t *)item ); + break; + default: + Com_Error( ERR_FATAL, "Menu_Draw: unknown item type" ); + break; + } + } + +// +// draw status bar +// + if( menu->statusbar ) { + ref.DrawFill( 0, uis.glconfig.vidHeight - 8, uis.glconfig.vidWidth, 8, 4 ); + UI_DrawString( uis.glconfig.vidWidth / 2, uis.glconfig.vidHeight - 8, NULL, UI_CENTER, menu->statusbar ); + } + +} + +int Menu_SelectItem( menuFrameWork_t *s ) { + menuCommon_t *item; + + if( !( item = Menu_ItemAtCursor( s ) ) ) { + return QMS_NOTHANDLED; + } + + switch( item->type ) { + //case MTYPE_SLIDER: + // return Slider_DoSlide( (menuSlider_t *)item, 1 ); + case MTYPE_SPINCONTROL: + return SpinControl_DoEnter( (menuSpinControl_t *)item ); + case MTYPE_FIELD: + case MTYPE_ACTION: + case MTYPE_BITMAP: + case MTYPE_LIST: + case MTYPE_IMAGELIST: + case MTYPE_KEYBIND: + return Common_DoEnter( item ); + } + + return QMS_NOTHANDLED; +} + + + +int Menu_SlideItem( menuFrameWork_t *s, int dir ) { + menuCommon_t *item; + + if( !( item = Menu_ItemAtCursor( s ) ) ) { + return QMS_NOTHANDLED; + } + + switch( item->type ) { + case MTYPE_SLIDER: + return Slider_DoSlide( (menuSlider_t *)item, dir ); + case MTYPE_SPINCONTROL: + return SpinControl_DoSlide( (menuSpinControl_t *)item, dir ); + } + + return QMS_NOTHANDLED; + +} + +int Menu_KeyEvent( menuCommon_t *item, int key ) { + int ret; + + if( ( ret = item->parent->callback( item->id, QM_KEY, key ) ) != QMS_NOTHANDLED ) { + return ret; + } + + switch( item->type ) { + case MTYPE_FIELD: + return Field_Key( (menuField_t *)item, key ); + case MTYPE_LIST: + return MenuList_Key( (menuList_t *)item, key ); + case MTYPE_IMAGELIST: + return ImageList_Key( (imageList_t *)item, key ); + case MTYPE_SLIDER: + return Slider_Key( (menuSlider_t *)item, key ); + } + + return QMS_NOTHANDLED; +} + +int Menu_CharEvent( menuCommon_t *item, int key ) { + int ret; + + if( ( ret = item->parent->callback( item->id, QM_CHAR, key ) ) != QMS_NOTHANDLED ) { + return ret; + } + + switch( item->type ) { + case MTYPE_FIELD: + return Field_Char( (menuField_t *)item, key ); + } + + return QMS_NOTHANDLED; +} + +int Menu_MouseMove( menuCommon_t *item ) { + int ret; + + if( ( ret = item->parent->callback( item->id, QM_MOUSE, 0 ) ) != QMS_NOTHANDLED ) { + return ret; + } + + switch( item->type ) { + //case MTYPE_FIELD: + //return Field_MouseMove( (menuField_t *)item ); + case MTYPE_LIST: + return MenuList_MouseMove( (menuList_t *)item ); + //case MTYPE_IMAGELIST: + //return ImageList_MouseMove( (imageList_t *)item ); + } + + return QMS_NOTHANDLED; +} + + + +menuCommon_t *Menu_HitTest( menuFrameWork_t *menu, int mx, int my ) { + vrect_t rect; + int i; + menuCommon_t *item; + + for( i=0 ; i<menu->nitems ; i++ ) { + rect.x = rect.y = 999999; + rect.width = rect.height = -999999; + + item = (menuCommon_t *)menu->items[i]; + + if( item->flags & QMF_HIDDEN ) { + continue; + } + + switch( item->type ) { + default: + rect = item->rect; + break; + case MTYPE_SLIDER: + Slider_GetSize( &rect, (menuSlider_t *)item ); + break; + case MTYPE_LIST: + MenuList_GetSize( &rect, (menuList_t *)item ); + break; + case MTYPE_SEPARATOR: + break; + case MTYPE_IMAGELIST: + ImageList_GetSize( &rect, (imageList_t *)item ); + break; + } + + if( ui_debug->integer ) { + UIS_DrawRect( &rect, 1, 223 ); + } + + if( UI_CursorInRect( &rect, mx, my ) ) { + return item; + } + + } + + return NULL; + +} + + |