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