|
|
1.1.1.2 ! root 1: /* ! 2: Copyright (C) 1997-2001 Id Software, Inc. ! 3: ! 4: This program is free software; you can redistribute it and/or ! 5: modify it under the terms of the GNU General Public License ! 6: as published by the Free Software Foundation; either version 2 ! 7: of the License, or (at your option) any later version. ! 8: ! 9: This program is distributed in the hope that it will be useful, ! 10: but WITHOUT ANY WARRANTY; without even the implied warranty of ! 11: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ! 12: ! 13: See the GNU General Public License for more details. ! 14: ! 15: You should have received a copy of the GNU General Public License ! 16: along with this program; if not, write to the Free Software ! 17: Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ! 18: ! 19: */ 1.1 root 20: #include <string.h> 21: #include <ctype.h> 22: 23: #include "client.h" 24: #include "qmenu.h" 25: 26: static void Action_DoEnter( menuaction_s *a ); 27: static void Action_Draw( menuaction_s *a ); 28: static void Menu_DrawStatusBar( const char *string ); 29: static void Menulist_DoEnter( menulist_s *l ); 30: static void MenuList_Draw( menulist_s *l ); 31: static void Separator_Draw( menuseparator_s *s ); 32: static void Slider_DoSlide( menuslider_s *s, int dir ); 33: static void Slider_Draw( menuslider_s *s ); 34: static void SpinControl_DoEnter( menulist_s *s ); 35: static void SpinControl_Draw( menulist_s *s ); 36: static void SpinControl_DoSlide( menulist_s *s, int dir ); 37: 38: #define RCOLUMN_OFFSET 16 39: #define LCOLUMN_OFFSET -16 40: 41: extern refexport_t re; 42: extern viddef_t viddef; 43: 44: #define VID_WIDTH viddef.width 45: #define VID_HEIGHT viddef.height 46: 47: #define Draw_Char re.DrawChar 48: #define Draw_Fill re.DrawFill 49: 50: void Action_DoEnter( menuaction_s *a ) 51: { 52: if ( a->generic.callback ) 53: a->generic.callback( a ); 54: } 55: 56: void Action_Draw( menuaction_s *a ) 57: { 58: if ( a->generic.flags & QMF_LEFT_JUSTIFY ) 59: { 60: if ( a->generic.flags & QMF_GRAYED ) 61: Menu_DrawStringDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name ); 62: else 63: Menu_DrawString( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name ); 64: } 65: else 66: { 67: if ( a->generic.flags & QMF_GRAYED ) 68: Menu_DrawStringR2LDark( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name ); 69: else 70: Menu_DrawStringR2L( a->generic.x + a->generic.parent->x + LCOLUMN_OFFSET, a->generic.y + a->generic.parent->y, a->generic.name ); 71: } 72: if ( a->generic.ownerdraw ) 73: a->generic.ownerdraw( a ); 74: } 75: 76: qboolean Field_DoEnter( menufield_s *f ) 77: { 78: if ( f->generic.callback ) 79: { 80: f->generic.callback( f ); 81: return true; 82: } 83: return false; 84: } 85: 86: void Field_Draw( menufield_s *f ) 87: { 88: int i; 89: char tempbuffer[128]=""; 90: 91: if ( f->generic.name ) 92: Menu_DrawStringR2LDark( f->generic.x + f->generic.parent->x + LCOLUMN_OFFSET, f->generic.y + f->generic.parent->y, f->generic.name ); 93: 94: strncpy( tempbuffer, f->buffer + f->visible_offset, f->visible_length ); 95: 96: Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y - 4, 18 ); 97: Draw_Char( f->generic.x + f->generic.parent->x + 16, f->generic.y + f->generic.parent->y + 4, 24 ); 98: 99: Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y - 4, 20 ); 100: Draw_Char( f->generic.x + f->generic.parent->x + 24 + f->visible_length * 8, f->generic.y + f->generic.parent->y + 4, 26 ); 101: 102: for ( i = 0; i < f->visible_length; i++ ) 103: { 104: Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y - 4, 19 ); 105: Draw_Char( f->generic.x + f->generic.parent->x + 24 + i * 8, f->generic.y + f->generic.parent->y + 4, 25 ); 106: } 107: 108: Menu_DrawString( f->generic.x + f->generic.parent->x + 24, f->generic.y + f->generic.parent->y, tempbuffer ); 109: 110: if ( Menu_ItemAtCursor( f->generic.parent ) == f ) 111: { 112: int offset; 113: 114: if ( f->visible_offset ) 115: offset = f->visible_length; 116: else 117: offset = f->cursor; 118: 119: if ( ( ( int ) ( Sys_Milliseconds() / 250 ) ) & 1 ) 120: { 121: Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8, 122: f->generic.y + f->generic.parent->y, 123: 11 ); 124: } 125: else 126: { 127: Draw_Char( f->generic.x + f->generic.parent->x + ( offset + 2 ) * 8 + 8, 128: f->generic.y + f->generic.parent->y, 129: ' ' ); 130: } 131: } 132: } 133: 134: qboolean Field_Key( menufield_s *f, int key ) 135: { 136: extern int keydown[]; 137: 138: switch ( key ) 139: { 140: case K_KP_SLASH: 141: key = '/'; 142: break; 143: case K_KP_MINUS: 144: key = '-'; 145: break; 146: case K_KP_PLUS: 147: key = '+'; 148: break; 149: case K_KP_HOME: 150: key = '7'; 151: break; 152: case K_KP_UPARROW: 153: key = '8'; 154: break; 155: case K_KP_PGUP: 156: key = '9'; 157: break; 158: case K_KP_LEFTARROW: 159: key = '4'; 160: break; 161: case K_KP_5: 162: key = '5'; 163: break; 164: case K_KP_RIGHTARROW: 165: key = '6'; 166: break; 167: case K_KP_END: 168: key = '1'; 169: break; 170: case K_KP_DOWNARROW: 171: key = '2'; 172: break; 173: case K_KP_PGDN: 174: key = '3'; 175: break; 176: case K_KP_INS: 177: key = '0'; 178: break; 179: case K_KP_DEL: 180: key = '.'; 181: break; 182: } 183: 184: if ( key > 127 ) 185: { 186: switch ( key ) 187: { 188: case K_DEL: 189: default: 190: return false; 191: } 192: } 193: 194: /* 195: ** support pasting from the clipboard 196: */ 197: if ( ( toupper( key ) == 'V' && keydown[K_CTRL] ) || 198: ( ( ( key == K_INS ) || ( key == K_KP_INS ) ) && keydown[K_SHIFT] ) ) 199: { 200: char *cbd; 201: 202: if ( ( cbd = Sys_GetClipboardData() ) != 0 ) 203: { 204: strtok( cbd, "\n\r\b" ); 205: 206: strncpy( f->buffer, cbd, f->length - 1 ); 207: f->cursor = strlen( f->buffer ); 208: f->visible_offset = f->cursor - f->visible_length; 209: if ( f->visible_offset < 0 ) 210: f->visible_offset = 0; 211: 212: free( cbd ); 213: } 214: return true; 215: } 216: 217: switch ( key ) 218: { 219: case K_KP_LEFTARROW: 220: case K_LEFTARROW: 221: case K_BACKSPACE: 222: if ( f->cursor > 0 ) 223: { 224: memmove( &f->buffer[f->cursor-1], &f->buffer[f->cursor], strlen( &f->buffer[f->cursor] ) + 1 ); 225: f->cursor--; 226: 227: if ( f->visible_offset ) 228: { 229: f->visible_offset--; 230: } 231: } 232: break; 233: 234: case K_KP_DEL: 235: case K_DEL: 236: memmove( &f->buffer[f->cursor], &f->buffer[f->cursor+1], strlen( &f->buffer[f->cursor+1] ) + 1 ); 237: break; 238: 239: case K_KP_ENTER: 240: case K_ENTER: 241: case K_ESCAPE: 242: case K_TAB: 243: return false; 244: 245: case K_SPACE: 246: default: 247: if ( !isdigit( key ) && ( f->generic.flags & QMF_NUMBERSONLY ) ) 248: return false; 249: 250: if ( f->cursor < f->length ) 251: { 252: f->buffer[f->cursor++] = key; 253: f->buffer[f->cursor] = 0; 254: 255: if ( f->cursor > f->visible_length ) 256: { 257: f->visible_offset++; 258: } 259: } 260: } 261: 262: return true; 263: } 264: 265: void Menu_AddItem( menuframework_s *menu, void *item ) 266: { 267: if ( menu->nitems == 0 ) 268: menu->nslots = 0; 269: 270: if ( menu->nitems < MAXMENUITEMS ) 271: { 272: menu->items[menu->nitems] = item; 273: ( ( menucommon_s * ) menu->items[menu->nitems] )->parent = menu; 274: menu->nitems++; 275: } 276: 277: menu->nslots = Menu_TallySlots( menu ); 278: } 279: 280: /* 281: ** Menu_AdjustCursor 282: ** 283: ** This function takes the given menu, the direction, and attempts 284: ** to adjust the menu's cursor so that it's at the next available 285: ** slot. 286: */ 287: void Menu_AdjustCursor( menuframework_s *m, int dir ) 288: { 289: menucommon_s *citem; 290: 291: /* 292: ** see if it's in a valid spot 293: */ 294: if ( m->cursor >= 0 && m->cursor < m->nitems ) 295: { 296: if ( ( citem = Menu_ItemAtCursor( m ) ) != 0 ) 297: { 298: if ( citem->type != MTYPE_SEPARATOR ) 299: return; 300: } 301: } 302: 303: /* 304: ** it's not in a valid spot, so crawl in the direction indicated until we 305: ** find a valid spot 306: */ 307: if ( dir == 1 ) 308: { 309: while ( 1 ) 310: { 311: citem = Menu_ItemAtCursor( m ); 312: if ( citem ) 313: if ( citem->type != MTYPE_SEPARATOR ) 314: break; 315: m->cursor += dir; 316: if ( m->cursor >= m->nitems ) 317: m->cursor = 0; 318: } 319: } 320: else 321: { 322: while ( 1 ) 323: { 324: citem = Menu_ItemAtCursor( m ); 325: if ( citem ) 326: if ( citem->type != MTYPE_SEPARATOR ) 327: break; 328: m->cursor += dir; 329: if ( m->cursor < 0 ) 330: m->cursor = m->nitems - 1; 331: } 332: } 333: } 334: 335: void Menu_Center( menuframework_s *menu ) 336: { 337: int height; 338: 339: height = ( ( menucommon_s * ) menu->items[menu->nitems-1])->y; 340: height += 10; 341: 342: menu->y = ( VID_HEIGHT - height ) / 2; 343: } 344: 345: void Menu_Draw( menuframework_s *menu ) 346: { 347: int i; 348: menucommon_s *item; 349: 350: /* 351: ** draw contents 352: */ 353: for ( i = 0; i < menu->nitems; i++ ) 354: { 355: switch ( ( ( menucommon_s * ) menu->items[i] )->type ) 356: { 357: case MTYPE_FIELD: 358: Field_Draw( ( menufield_s * ) menu->items[i] ); 359: break; 360: case MTYPE_SLIDER: 361: Slider_Draw( ( menuslider_s * ) menu->items[i] ); 362: break; 363: case MTYPE_LIST: 364: MenuList_Draw( ( menulist_s * ) menu->items[i] ); 365: break; 366: case MTYPE_SPINCONTROL: 367: SpinControl_Draw( ( menulist_s * ) menu->items[i] ); 368: break; 369: case MTYPE_ACTION: 370: Action_Draw( ( menuaction_s * ) menu->items[i] ); 371: break; 372: case MTYPE_SEPARATOR: 373: Separator_Draw( ( menuseparator_s * ) menu->items[i] ); 374: break; 375: } 376: } 377: 378: item = Menu_ItemAtCursor( menu ); 379: 380: if ( item && item->cursordraw ) 381: { 382: item->cursordraw( item ); 383: } 384: else if ( menu->cursordraw ) 385: { 386: menu->cursordraw( menu ); 387: } 388: else if ( item && item->type != MTYPE_FIELD ) 389: { 390: if ( item->flags & QMF_LEFT_JUSTIFY ) 391: { 392: Draw_Char( menu->x + item->x - 24 + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) ); 393: } 394: else 395: { 396: Draw_Char( menu->x + item->cursor_offset, menu->y + item->y, 12 + ( ( int ) ( Sys_Milliseconds()/250 ) & 1 ) ); 397: } 398: } 399: 400: if ( item ) 401: { 402: if ( item->statusbarfunc ) 403: item->statusbarfunc( ( void * ) item ); 404: else if ( item->statusbar ) 405: Menu_DrawStatusBar( item->statusbar ); 406: else 407: Menu_DrawStatusBar( menu->statusbar ); 408: 409: } 410: else 411: { 412: Menu_DrawStatusBar( menu->statusbar ); 413: } 414: } 415: 416: void Menu_DrawStatusBar( const char *string ) 417: { 418: if ( string ) 419: { 420: int l = strlen( string ); 421: int maxrow = VID_HEIGHT / 8; 422: int maxcol = VID_WIDTH / 8; 423: int col = maxcol / 2 - l / 2; 424: 425: Draw_Fill( 0, VID_HEIGHT-8, VID_WIDTH, 8, 4 ); 426: Menu_DrawString( col*8, VID_HEIGHT - 8, string ); 427: } 428: else 429: { 430: Draw_Fill( 0, VID_HEIGHT-8, VID_WIDTH, 8, 0 ); 431: } 432: } 433: 434: void Menu_DrawString( int x, int y, const char *string ) 435: { 436: unsigned i; 437: 438: for ( i = 0; i < strlen( string ); i++ ) 439: { 440: Draw_Char( ( x + i*8 ), y, string[i] ); 441: } 442: } 443: 444: void Menu_DrawStringDark( int x, int y, const char *string ) 445: { 446: unsigned i; 447: 448: for ( i = 0; i < strlen( string ); i++ ) 449: { 450: Draw_Char( ( x + i*8 ), y, string[i] + 128 ); 451: } 452: } 453: 454: void Menu_DrawStringR2L( int x, int y, const char *string ) 455: { 456: unsigned i; 457: 458: for ( i = 0; i < strlen( string ); i++ ) 459: { 460: Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1] ); 461: } 462: } 463: 464: void Menu_DrawStringR2LDark( int x, int y, const char *string ) 465: { 466: unsigned i; 467: 468: for ( i = 0; i < strlen( string ); i++ ) 469: { 470: Draw_Char( ( x - i*8 ), y, string[strlen(string)-i-1]+128 ); 471: } 472: } 473: 474: void *Menu_ItemAtCursor( menuframework_s *m ) 475: { 476: if ( m->cursor < 0 || m->cursor >= m->nitems ) 477: return 0; 478: 479: return m->items[m->cursor]; 480: } 481: 482: qboolean Menu_SelectItem( menuframework_s *s ) 483: { 484: menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s ); 485: 486: if ( item ) 487: { 488: switch ( item->type ) 489: { 490: case MTYPE_FIELD: 491: return Field_DoEnter( ( menufield_s * ) item ) ; 492: case MTYPE_ACTION: 493: Action_DoEnter( ( menuaction_s * ) item ); 494: return true; 495: case MTYPE_LIST: 496: // Menulist_DoEnter( ( menulist_s * ) item ); 497: return false; 498: case MTYPE_SPINCONTROL: 499: // SpinControl_DoEnter( ( menulist_s * ) item ); 500: return false; 501: } 502: } 503: return false; 504: } 505: 506: void Menu_SetStatusBar( menuframework_s *m, const char *string ) 507: { 508: m->statusbar = string; 509: } 510: 511: void Menu_SlideItem( menuframework_s *s, int dir ) 512: { 513: menucommon_s *item = ( menucommon_s * ) Menu_ItemAtCursor( s ); 514: 515: if ( item ) 516: { 517: switch ( item->type ) 518: { 519: case MTYPE_SLIDER: 520: Slider_DoSlide( ( menuslider_s * ) item, dir ); 521: break; 522: case MTYPE_SPINCONTROL: 523: SpinControl_DoSlide( ( menulist_s * ) item, dir ); 524: break; 525: } 526: } 527: } 528: 529: int Menu_TallySlots( menuframework_s *menu ) 530: { 531: int i; 532: int total = 0; 533: 534: for ( i = 0; i < menu->nitems; i++ ) 535: { 536: if ( ( ( menucommon_s * ) menu->items[i] )->type == MTYPE_LIST ) 537: { 538: int nitems = 0; 539: const char **n = ( ( menulist_s * ) menu->items[i] )->itemnames; 540: 541: while (*n) 542: nitems++, n++; 543: 544: total += nitems; 545: } 546: else 547: { 548: total++; 549: } 550: } 551: 552: return total; 553: } 554: 555: void Menulist_DoEnter( menulist_s *l ) 556: { 557: int start; 558: 559: start = l->generic.y / 10 + 1; 560: 561: l->curvalue = l->generic.parent->cursor - start; 562: 563: if ( l->generic.callback ) 564: l->generic.callback( l ); 565: } 566: 567: void MenuList_Draw( menulist_s *l ) 568: { 569: const char **n; 570: int y = 0; 571: 572: Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y, l->generic.name ); 573: 574: n = l->itemnames; 575: 576: Draw_Fill( l->generic.x - 112 + l->generic.parent->x, l->generic.parent->y + l->generic.y + l->curvalue*10 + 10, 128, 10, 16 ); 577: while ( *n ) 578: { 579: Menu_DrawStringR2LDark( l->generic.x + l->generic.parent->x + LCOLUMN_OFFSET, l->generic.y + l->generic.parent->y + y + 10, *n ); 580: 581: n++; 582: y += 10; 583: } 584: } 585: 586: void Separator_Draw( menuseparator_s *s ) 587: { 588: if ( s->generic.name ) 589: Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->generic.name ); 590: } 591: 592: void Slider_DoSlide( menuslider_s *s, int dir ) 593: { 594: s->curvalue += dir; 595: 596: if ( s->curvalue > s->maxvalue ) 597: s->curvalue = s->maxvalue; 598: else if ( s->curvalue < s->minvalue ) 599: s->curvalue = s->minvalue; 600: 601: if ( s->generic.callback ) 602: s->generic.callback( s ); 603: } 604: 605: #define SLIDER_RANGE 10 606: 607: void Slider_Draw( menuslider_s *s ) 608: { 609: int i; 610: 611: Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET, 612: s->generic.y + s->generic.parent->y, 613: s->generic.name ); 614: 615: s->range = ( s->curvalue - s->minvalue ) / ( float ) ( s->maxvalue - s->minvalue ); 616: 617: if ( s->range < 0) 618: s->range = 0; 619: if ( s->range > 1) 620: s->range = 1; 621: Draw_Char( s->generic.x + s->generic.parent->x + RCOLUMN_OFFSET, s->generic.y + s->generic.parent->y, 128); 622: for ( i = 0; i < SLIDER_RANGE; i++ ) 623: Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 129); 624: Draw_Char( RCOLUMN_OFFSET + s->generic.x + i*8 + s->generic.parent->x + 8, s->generic.y + s->generic.parent->y, 130); 625: Draw_Char( ( int ) ( 8 + RCOLUMN_OFFSET + s->generic.parent->x + s->generic.x + (SLIDER_RANGE-1)*8 * s->range ), s->generic.y + s->generic.parent->y, 131); 626: } 627: 628: void SpinControl_DoEnter( menulist_s *s ) 629: { 630: s->curvalue++; 631: if ( s->itemnames[s->curvalue] == 0 ) 632: s->curvalue = 0; 633: 634: if ( s->generic.callback ) 635: s->generic.callback( s ); 636: } 637: 638: void SpinControl_DoSlide( menulist_s *s, int dir ) 639: { 640: s->curvalue += dir; 641: 642: if ( s->curvalue < 0 ) 643: s->curvalue = 0; 644: else if ( s->itemnames[s->curvalue] == 0 ) 645: s->curvalue--; 646: 647: if ( s->generic.callback ) 648: s->generic.callback( s ); 649: } 650: 651: void SpinControl_Draw( menulist_s *s ) 652: { 653: char buffer[100]; 654: 655: if ( s->generic.name ) 656: { 657: Menu_DrawStringR2LDark( s->generic.x + s->generic.parent->x + LCOLUMN_OFFSET, 658: s->generic.y + s->generic.parent->y, 659: s->generic.name ); 660: } 661: if ( !strchr( s->itemnames[s->curvalue], '\n' ) ) 662: { 663: Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, s->itemnames[s->curvalue] ); 664: } 665: else 666: { 667: strcpy( buffer, s->itemnames[s->curvalue] ); 668: *strchr( buffer, '\n' ) = 0; 669: Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y, buffer ); 670: strcpy( buffer, strchr( s->itemnames[s->curvalue], '\n' ) + 1 ); 671: Menu_DrawString( RCOLUMN_OFFSET + s->generic.x + s->generic.parent->x, s->generic.y + s->generic.parent->y + 10, buffer ); 672: } 673: } 674:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.