summaryrefslogtreecommitdiff
path: root/source/ui_menu.c
diff options
context:
space:
mode:
authorAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
committerAndrey Nazarov <skuller@skuller.net>2007-08-14 20:18:08 +0000
commitf294db4ccf45f6274e65260dd6f9a2c5faa94313 (patch)
treee8cf1ba2bfe9c8417eec17faf912442f52fc4ef2 /source/ui_menu.c
Initial import of the new Q2PRO tree.
Diffstat (limited to 'source/ui_menu.c')
-rw-r--r--source/ui_menu.c1629
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;
+
+}
+
+