mirror of
https://git.code.sf.net/p/quake/quakeforge
synced 2024-11-26 22:31:05 +00:00
a35c33b397
options menu.
562 lines
9.5 KiB
C++
562 lines
9.5 KiB
C++
/*
|
|
options_util.qc
|
|
|
|
Utilities for the options menu
|
|
|
|
Copyright (C) 2002 Robin Redeker <elmex@x-paste.de>
|
|
|
|
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:
|
|
|
|
Free Software Foundation, Inc.
|
|
59 Temple Place - Suite 330
|
|
Boston, MA 02111-1307, USA
|
|
*/
|
|
|
|
#include "cvar.h"
|
|
#include "draw.h"
|
|
#include "system.h"
|
|
#include "string.h"
|
|
#include "key.h"
|
|
|
|
#include "Array.h"
|
|
#include "gui/Text.h"
|
|
#include "gui/Rect.h"
|
|
#include "gui/Slider.h"
|
|
#include "options_util.h"
|
|
|
|
@implementation MenuGroup
|
|
-(id) init
|
|
{
|
|
if ((self = [super init]))
|
|
current = base = 0;
|
|
}
|
|
|
|
-(void)setBase:(integer)b
|
|
{
|
|
if (b >= [views count])
|
|
b = [views count] - 1;
|
|
if (b < 0)
|
|
b = 0;
|
|
current = base = b;
|
|
}
|
|
|
|
- (integer) keyEvent:(integer)key unicode:(integer)unicode down:(integer)down
|
|
{
|
|
switch (key) {
|
|
case QFK_DOWN:
|
|
case QFM_WHEEL_DOWN:
|
|
[self next];
|
|
return 1;
|
|
case QFK_UP:
|
|
case QFM_WHEEL_UP:
|
|
[self prev];
|
|
return 1;
|
|
default:
|
|
return [[views getItemAt:current]
|
|
keyEvent:key
|
|
unicode:unicode
|
|
down:down];
|
|
}
|
|
}
|
|
|
|
-(void) next
|
|
{
|
|
if (++current >= [views count])
|
|
current = base;
|
|
}
|
|
|
|
-(void) prev
|
|
{
|
|
if (--current < base)
|
|
current = [views count] - 1;
|
|
}
|
|
|
|
- (void) draw
|
|
{
|
|
local View cur;
|
|
|
|
[super draw];
|
|
cur = (View) [views getItemAt:current];
|
|
opt_cursor (cur.xabs - 8, cur.yabs);
|
|
}
|
|
@end
|
|
|
|
|
|
@implementation CvarObject
|
|
-(id)init
|
|
{
|
|
self = [super init];
|
|
name = str_new ();
|
|
return self;
|
|
}
|
|
|
|
-(id)initWithCvar:(string)cvname
|
|
{
|
|
self = [self init];
|
|
str_copy (name, cvname);
|
|
return self;
|
|
}
|
|
|
|
-(void)dealloc
|
|
{
|
|
str_free (name);
|
|
}
|
|
@end
|
|
|
|
@implementation CvarToggle
|
|
-(void)toggle
|
|
{
|
|
Cvar_Toggle (name);
|
|
}
|
|
|
|
-(BOOL)value
|
|
{
|
|
return Cvar_GetInteger (name);
|
|
}
|
|
@end
|
|
|
|
@implementation MouseToggle
|
|
-(void)toggle
|
|
{
|
|
if (Cvar_GetFloat ("m_pitch") < 0) {
|
|
Cvar_SetFloat ("m_pitch", 0.022);
|
|
} else {
|
|
Cvar_SetFloat ("m_pitch", -0.022);
|
|
}
|
|
}
|
|
|
|
-(BOOL)value
|
|
{
|
|
return Cvar_GetFloat ("m_pitch") < 0;
|
|
}
|
|
@end
|
|
|
|
@implementation RunToggle
|
|
-(void)toggle
|
|
{
|
|
if (Cvar_GetFloat ("cl_forwardspeed") < 400) {
|
|
Cvar_SetFloat ("cl_forwardspeed", 400);
|
|
Cvar_SetFloat ("cl_backspeed", 400);
|
|
} else {
|
|
Cvar_SetFloat ("cl_forwardspeed", 200);
|
|
Cvar_SetFloat ("cl_backspeed", 200);
|
|
}
|
|
}
|
|
|
|
-(BOOL)value
|
|
{
|
|
return Cvar_GetFloat ("cl_forwardspeed") >= 400;
|
|
}
|
|
@end
|
|
|
|
@implementation CvarToggleView
|
|
|
|
-(void)update
|
|
{
|
|
[value setText:[toggle value] ? "On" : "Off"];
|
|
}
|
|
|
|
-(id)initWithBounds:(Rect)aRect title:(string)_title :(CvarToggle)_toggle
|
|
{
|
|
local Rect rect;
|
|
|
|
self = [super initWithBounds:aRect];
|
|
|
|
toggle = _toggle;
|
|
|
|
rect = [[Rect alloc] initWithComponents:0 :0 :strlen (_title) * 8 :8];
|
|
title = [[Text alloc] initWithBounds:rect text:_title];
|
|
|
|
rect.size.width = 3 * 8;
|
|
rect.origin.x = xlen - rect.size.width;
|
|
value = [[Text alloc] initWithBounds:rect];
|
|
|
|
[self addView:title];
|
|
[self addView:value];
|
|
|
|
[self update];
|
|
|
|
return self;
|
|
}
|
|
|
|
-(void)toggle
|
|
{
|
|
[toggle toggle];
|
|
[self update];
|
|
}
|
|
|
|
- (integer) keyEvent:(integer)key unicode:(integer)unicode down:(integer)down
|
|
{
|
|
switch (key) {
|
|
case QFK_RETURN:
|
|
case QFM_BUTTON1:
|
|
[self toggle];
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation CvarColor
|
|
-(void)next
|
|
{
|
|
local float val = Cvar_GetFloat (name);
|
|
val = min_max_cnt (0, 13, 1, val, 1);
|
|
Cvar_SetFloat (name, val);
|
|
}
|
|
|
|
-(void)prev
|
|
{
|
|
local float val = Cvar_GetFloat (name);
|
|
val = min_max_cnt (0, 13, 1, val, 0);
|
|
Cvar_SetFloat (name, val);
|
|
}
|
|
|
|
-(integer)value
|
|
{
|
|
return Cvar_GetInteger (name);
|
|
}
|
|
@end
|
|
|
|
@implementation CvarColorView
|
|
-(id)initWithBounds:(Rect)aRect :(CvarColor)_color
|
|
{
|
|
self = [self initWithBounds:aRect];
|
|
color = _color;
|
|
return self;
|
|
}
|
|
|
|
-(void)next
|
|
{
|
|
[color next];
|
|
}
|
|
|
|
-(void)prev
|
|
{
|
|
[color prev];
|
|
}
|
|
|
|
-(void)draw
|
|
{
|
|
local integer xl;
|
|
xl = xlen / 8 - 2;
|
|
text_box (xabs, yabs, xl, ylen / 8 - 2);
|
|
xl = (xl + 1) & ~1; // text_box only does multiples of 2
|
|
Draw_Fill (xabs + 8, yabs + 8, xl * 8, ylen - 16,
|
|
[color value] * 16 + 8);
|
|
}
|
|
|
|
- (integer) keyEvent:(integer)key unicode:(integer)unicode down:(integer)down
|
|
{
|
|
switch (key) {
|
|
case QFK_DOWN:
|
|
case QFM_WHEEL_DOWN:
|
|
[self next];
|
|
return 1;
|
|
case QFK_UP:
|
|
case QFM_WHEEL_UP:
|
|
[self prev];
|
|
return 1;
|
|
}
|
|
}
|
|
@end
|
|
|
|
@implementation CvarRange
|
|
|
|
-(id)initWithCvar:(string)cvname min:(float)_min max:(float)_max step:(float)_step
|
|
{
|
|
self = [super init];
|
|
|
|
name = str_new ();
|
|
str_copy (name, cvname);
|
|
min = _min;
|
|
max = _max;
|
|
step = _step;
|
|
|
|
return self;
|
|
}
|
|
|
|
-(void)inc
|
|
{
|
|
local float val = Cvar_GetFloat (name);
|
|
val = min_max_cnt (min, max, step, val, 1);
|
|
Cvar_SetFloat (name, val);
|
|
}
|
|
|
|
-(void)dec
|
|
{
|
|
local float val = Cvar_GetFloat (name);
|
|
val = min_max_cnt (min, max, step, val, 0);
|
|
Cvar_SetFloat (name, val);
|
|
}
|
|
|
|
-(float)value
|
|
{
|
|
return Cvar_GetFloat (name);
|
|
}
|
|
|
|
-(integer)percentage
|
|
{
|
|
return to_percentage(min, max, Cvar_GetFloat (name));
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation CvarRangeView
|
|
|
|
-(void)update
|
|
{
|
|
[slider setIndex:[range percentage]];
|
|
[value setText:ftos ([range value])];
|
|
}
|
|
|
|
-(id)initWithBounds:(Rect)aRect title:(string)_title sliderWidth:(integer)width :(CvarRange)_range
|
|
{
|
|
local Rect rect;
|
|
|
|
self = [super initWithBounds:aRect];
|
|
|
|
range = _range;
|
|
|
|
rect = [[Rect alloc] initWithComponents:0 :0 :strlen (_title) * 8 :8];
|
|
title = [[Text alloc] initWithBounds:rect text:_title];
|
|
|
|
rect.origin.x += rect.size.width + 8;
|
|
rect.size.width = width;
|
|
if (rect.origin.x + rect.size.width > xlen)
|
|
rect.size.width = xlen - rect.origin.x;
|
|
slider = [[Slider alloc] initWithBounds:rect size:100];
|
|
|
|
rect.origin.x += rect.size.width + 8;
|
|
rect.size.width = xlen - rect.origin.x;
|
|
value = [[Text alloc] initWithBounds:rect];
|
|
|
|
[self addView:title];
|
|
[self addView:slider];
|
|
[self addView:value];
|
|
|
|
[self update];
|
|
|
|
return self;
|
|
}
|
|
|
|
-(void)inc
|
|
{
|
|
[range inc];
|
|
[self update];
|
|
}
|
|
|
|
-(void)dec
|
|
{
|
|
[range dec];
|
|
[self update];
|
|
}
|
|
|
|
- (integer) keyEvent:(integer)key unicode:(integer)unicode down:(integer)down
|
|
{
|
|
switch (key) {
|
|
case QFK_RIGHT:
|
|
[self inc];
|
|
return 1;
|
|
case QFK_LEFT:
|
|
[self dec];
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation CrosshairCvar
|
|
-(void) next
|
|
{
|
|
local integer val = Cvar_GetInteger (name);
|
|
Cvar_SetInteger (name, (val + 1) % 4);
|
|
}
|
|
|
|
-(integer) crosshair
|
|
{
|
|
return Cvar_GetInteger (name);
|
|
}
|
|
@end
|
|
|
|
@implementation CrosshairView
|
|
{
|
|
CrosshairCvar crosshair;
|
|
}
|
|
|
|
-(id)initWithBounds:(Rect)aRect :(CrosshairCvar)_crosshair
|
|
{
|
|
self = [self initWithBounds:aRect];
|
|
crosshair = _crosshair;
|
|
return self;
|
|
}
|
|
|
|
-(void) next
|
|
{
|
|
[crosshair next];
|
|
}
|
|
|
|
-(void) draw
|
|
{
|
|
Draw_Fill (xabs, yabs, xlen, ylen, 0);
|
|
Draw_Crosshair ([crosshair crosshair], xabs + xlen / 2, yabs + ylen / 2);
|
|
}
|
|
|
|
- (integer) keyEvent:(integer)key unicode:(integer)unicode down:(integer)down
|
|
{
|
|
switch (key) {
|
|
case QFK_RETURN:
|
|
case QFM_BUTTON1:
|
|
[self next];
|
|
return 1;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
@end
|
|
void traceon () = #0;
|
|
@implementation ProxyView
|
|
|
|
-(id)initWithBounds:(Rect)aRect title:(View)aTitle view:(View)aView
|
|
{
|
|
self = [super initWithBounds:aRect];
|
|
if (!self)
|
|
return self;
|
|
|
|
title = aTitle;
|
|
view = aView;
|
|
return self;
|
|
}
|
|
|
|
- (integer) keyEvent:(integer)key unicode:(integer)unicode down:(integer)down
|
|
{
|
|
return [view keyEvent:key unicode:unicode down:down];
|
|
}
|
|
|
|
- (void) draw
|
|
{
|
|
[title draw];
|
|
[view draw];
|
|
}
|
|
|
|
- (void) setBasePos: (Point) pos
|
|
{
|
|
[super setBasePos:pos];
|
|
local Point point = [[Point alloc] initWithComponents:xabs :yabs];
|
|
[title setBasePos:point];
|
|
[view setBasePos:point];
|
|
[point release];
|
|
}
|
|
|
|
@end
|
|
|
|
/*
|
|
opt_cursor
|
|
|
|
function for drawing the cursor
|
|
*/
|
|
void (integer x, integer y)
|
|
opt_cursor =
|
|
{
|
|
// use time becaus we want a nice rotaing cursor
|
|
Draw_Character (x, y, 12 + (integer) (time * 4) & 1);
|
|
};
|
|
|
|
/*
|
|
draw_item
|
|
|
|
Draws a item with a specific spacing between label and value to
|
|
position x, y.
|
|
Used as helper function for draw_val_item.
|
|
*/
|
|
void (integer x, integer y, integer spacing, string spacechar,
|
|
string label, string valstr)
|
|
draw_item =
|
|
{
|
|
local integer i;
|
|
|
|
Draw_String (x, y, label);
|
|
for (i = x + (integer) strlen (label) * 8; i < (x+spacing); i += 8) {
|
|
Draw_String (i, y, spacechar);
|
|
}
|
|
Draw_String (x + spacing, y, valstr);
|
|
};
|
|
|
|
/*
|
|
draw_val_item
|
|
|
|
Draws a nice menu item.
|
|
Use this function for a consistent look of menu items!
|
|
Example:
|
|
<Label>.....:<valstr>
|
|
spacing are the number of the points to put
|
|
*/
|
|
void (integer x, integer y, integer spacing, string label, string valstr)
|
|
draw_val_item =
|
|
{
|
|
draw_item (x, y, spacing, ".", label, ":" + valstr);
|
|
};
|
|
|
|
/*
|
|
to_percentage
|
|
|
|
Calculates the percentage of a value relative
|
|
to a min and max value.
|
|
*/
|
|
integer (float min, float max, float val)
|
|
to_percentage =
|
|
{
|
|
local float max_v = (max - min);
|
|
local integer perc;
|
|
|
|
val -= min;
|
|
|
|
if (val > max_v) {
|
|
val = max_v;
|
|
}
|
|
if (val < 0) {
|
|
val = 0;
|
|
}
|
|
perc = (integer) ((val / max_v) * 100);
|
|
|
|
return perc;
|
|
};
|
|
|
|
/*
|
|
min_max_cnt
|
|
|
|
Increases or decreases a value by take care of the bordervalues.
|
|
min, max are the borders.
|
|
step is the step by in-/de-creasing.
|
|
cntflag should be true for increasing and false for decreasing
|
|
*/
|
|
float (float min, float max, float step, float val, integer cntflag)
|
|
min_max_cnt =
|
|
{
|
|
if (cntflag) {
|
|
val += step;
|
|
} else {
|
|
val -= step;
|
|
}
|
|
|
|
if (val > max) {
|
|
val = max;
|
|
} else if (val < min) {
|
|
val = min;
|
|
}
|
|
return val;
|
|
};
|