Added autorun setting. Fixed greying of options that are not supported by the engine. Fixed keyboard navigation for general widgets (special menus might still be annoying). git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5285 fc73d0e0-1445-4013-8a0c-d673dee63da5
332 lines
9.5 KiB
C++
332 lines
9.5 KiB
C++
/***************************************************************************
|
|
window-like menu.
|
|
interactable - basically just a container for the items in the menu, but also handles killing them+itself when the user presses escape.
|
|
|
|
these items will automatically be added to the desktop/workspace thing
|
|
Call it.item_remove() to pop the menu.
|
|
Regular items can be added to the menu by first spawning them, then calling menu_additem to actually add it to the desired menu in the right place.
|
|
*/
|
|
|
|
class mitem_menu : mitem_frame
|
|
{
|
|
vector draginfo; //x, y, resizeflags={0:none, 1:left, 2:bottom, 4:right, 8:top, 16:move}
|
|
|
|
virtual float(vector pos, float scan, float char, float down) item_keypress;
|
|
virtual void(mitem newfocus, float flag) item_focuschange;
|
|
virtual void(vector pos) item_draw;
|
|
|
|
virtual void() item_remove =
|
|
{
|
|
strunzone(item_text);
|
|
super::item_remove();
|
|
};
|
|
|
|
nonvirtual float(vector pos) whichgrabhandle;
|
|
nonvirtual void(vector pos, float handle) drawgrabhandle;
|
|
void() mitem_menu =
|
|
{
|
|
item_text = strzone(item_text);
|
|
item_scale = 8;
|
|
item_rgb = MENUBACK_RGB;
|
|
item_alpha = MENUBACK_ALPHA;
|
|
|
|
if (item_framesize == '0 0 0')
|
|
item_framesize = '4 16 4';
|
|
|
|
item_size[0] += item_framesize[0];
|
|
item_size[1] += item_framesize[1]+item_framesize[2];
|
|
|
|
item_flags |= IF_SELECTABLE;
|
|
|
|
#ifdef CSQC
|
|
cprint("");
|
|
#endif
|
|
};
|
|
|
|
//same as mitem, but does not propogate to parent.
|
|
virtual string(string key) get =
|
|
{
|
|
return cvar_string(key);
|
|
};
|
|
virtual void(string key, string newval) set =
|
|
{
|
|
cvar_set(key, newval);
|
|
};
|
|
};
|
|
|
|
void(mitem newfocus, float flag) mitem_menu::item_focuschange =
|
|
{
|
|
if (flag & IF_KFOCUSED)
|
|
{
|
|
//move the window to the top of the z-order when it gets focus.
|
|
if (item_flags & IF_KFOCUSED)
|
|
totop();
|
|
//release grabs if someone else took focus.
|
|
else if (ui.mgrabs == this)
|
|
{
|
|
ui.mgrabs = __NULL__;
|
|
draginfo[2] = 0;
|
|
}
|
|
}
|
|
|
|
super::item_focuschange(newfocus, flag);
|
|
};
|
|
|
|
void(vector pos, float handle) mitem_menu::drawgrabhandle =
|
|
{
|
|
if ((handle & 3) == 3)
|
|
{
|
|
//bottom left
|
|
drawfill(pos + [0, item_size[1]-item_framesize[2]], [item_framesize[0], item_framesize[2]], '1 1 0', 1, 0);
|
|
handle &~= 3;
|
|
}
|
|
if ((handle & 6) == 6)
|
|
{
|
|
//bottom right
|
|
drawfill(pos + [item_size[0]-item_framesize[0], item_size[1]-item_framesize[2]], [item_framesize[0], item_framesize[2]], '1 1 0', 1, 0);
|
|
handle &~= 6;
|
|
}
|
|
if (handle & 1)
|
|
{
|
|
//left
|
|
drawfill(pos + [0, 0], [item_framesize[0], item_size[1]], '1 1 0', 1, 0);
|
|
}
|
|
if (handle & 2)
|
|
{
|
|
//bottom
|
|
drawfill(pos + [0, item_size[1]-item_framesize[2]], [item_size[0], item_framesize[2]], '1 1 0', 1, 0);
|
|
}
|
|
if (handle & 4)
|
|
{
|
|
//right
|
|
drawfill(pos + [item_size[0]-item_framesize[0], 0], [item_framesize[0], item_size[1]], '1 1 0', 1, 0);
|
|
}
|
|
};
|
|
|
|
float(vector pos) mitem_menu::whichgrabhandle =
|
|
{
|
|
//handle dragging and resizing.
|
|
if (mouseinbox(pos, [item_size[0]-item_framesize[1], item_framesize[1]]))
|
|
{
|
|
//drag
|
|
return 16;
|
|
}
|
|
else if (this.item_flags & IF_RESIZABLE)
|
|
{
|
|
if (mouseinbox(pos + [0, item_size[1]-item_framesize[2]], [item_framesize[0], item_framesize[2]]))
|
|
{
|
|
//bottom-left
|
|
return 3;
|
|
}
|
|
else if (mouseinbox(pos + [item_size[0]-item_framesize[0], item_size[1]-item_framesize[2]], [item_framesize[0], item_framesize[2]]))
|
|
{
|
|
//bottom-right
|
|
return 6;
|
|
}
|
|
else if (mouseinbox(pos + [0, 0], [item_framesize[0], item_size[1]]))
|
|
{
|
|
//left
|
|
return 1;
|
|
}
|
|
else if (mouseinbox(pos + [0, item_size[1]-item_framesize[2]], [item_size[0], item_framesize[2]]))
|
|
{
|
|
//bottom
|
|
return 2;
|
|
}
|
|
else if (mouseinbox(pos + [item_size[0]-item_framesize[0], 0], [item_framesize[0], item_size[1]]))
|
|
{
|
|
//right
|
|
return 4;
|
|
}
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
float(vector pos, float scan, float char, float down) mitem_menu::item_keypress =
|
|
{
|
|
if (scan == K_MOUSE1 && (down&1))
|
|
{
|
|
if (!(item_flags & IF_NOKILL) && mouseinbox(pos + [item_size[0]-item_framesize[1], 0], item_framesize[1] * '1 1'))
|
|
{
|
|
localcmd(strcat(item_command, "\n")); //console command to exec if someone clicks the close button.
|
|
this.item_remove();
|
|
return TRUE;
|
|
}
|
|
draginfo[2] = this::whichgrabhandle(pos);
|
|
if (draginfo[2])
|
|
ui.mgrabs = this;
|
|
if (draginfo[2] & (1|16))
|
|
draginfo[0] = ui.mousepos[0] - pos_x;
|
|
if (draginfo[2] & 2)
|
|
draginfo[1] = (ui.mousepos[1] - pos_y - item_size[1]) + item_position[1];
|
|
if (draginfo[2] & 4)
|
|
draginfo[0] = ui.mousepos[0] - pos_x - item_size[0] + item_position[0];
|
|
if (draginfo[2] & (8|16))
|
|
draginfo[1] = ui.mousepos[1] - pos_y;
|
|
if (draginfo[2])
|
|
return TRUE;
|
|
}
|
|
else if (scan == K_MOUSE1 && draginfo[2])
|
|
{
|
|
if (!draginfo[2] && (item_flags & IF_RESIZABLE))
|
|
{
|
|
//if they dropped the window at the top of the screen, make sure its fullscreened to match how it was drawn...
|
|
queryscreensize();
|
|
if (ui.mousepos[1] < 8)
|
|
item_size = ui.screensize;
|
|
if (this.item_resized)
|
|
item_resized();
|
|
}
|
|
ui.mgrabs = __NULL__;
|
|
draginfo[2] = 0;
|
|
return TRUE;
|
|
}
|
|
|
|
if (!super::item_keypress(pos, scan, char, down))
|
|
{
|
|
down &= 1;
|
|
if (scan == K_ESCAPE && down)
|
|
{
|
|
if (this.item_flags & IF_NOKILL)
|
|
return FALSE;
|
|
else
|
|
{
|
|
localcmd(strcat(this.item_command, "\n")); //console command to exec if someone clicks the close button.
|
|
this.item_remove();
|
|
return TRUE;
|
|
}
|
|
}
|
|
else if (scan == K_UPARROW && down)
|
|
menu_selectnextitem(this, TRUE);
|
|
else if (scan == K_DOWNARROW && down)
|
|
menu_selectnextitem(this, FALSE);
|
|
else if (scan == K_MOUSE2 && down && !(this.item_flags & IF_NOKILL))
|
|
{ //unhandled right click closes menus, if we're allowed
|
|
localcmd(strcat(item_command, "\n")); //console command to exec if someone clicks the close button.
|
|
this.item_remove();
|
|
return TRUE;
|
|
}
|
|
else if (scan >= K_MOUSE1 && scan <= K_MWHEELDOWN)
|
|
return TRUE; //don't let the parent take unhandled mouse events.
|
|
else
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
};
|
|
void(vector pos) mitem_menu::item_draw =
|
|
{
|
|
float inset;
|
|
vector efsize = item_size;
|
|
if (draginfo[2])
|
|
{
|
|
if (draginfo[2] & 1)
|
|
{ //resize left
|
|
local float nmax = item_position[0] + item_size[0];
|
|
local float nmin = item_position[0] + item_size[0];
|
|
nmin = ui.mousepos[0] - (pos_x - item_position[0]) - draginfo[0];
|
|
if (nmax-nmin < 128)
|
|
nmin = nmax - 128;
|
|
pos_x -= item_position[0];
|
|
item_position[0] = nmin;
|
|
pos_x += item_position[0];
|
|
item_size[0] = nmax - nmin;
|
|
if (item_resized)
|
|
item_resized();
|
|
}
|
|
if (draginfo[2] & 2)
|
|
{ //resize bottom
|
|
item_size[1] = ui.mousepos[1] - (pos_y - item_position[1]) - draginfo[1];
|
|
if (item_size[1] < 16)
|
|
item_size[1] = 16;
|
|
if (item_resized)
|
|
item_resized();
|
|
}
|
|
if (draginfo[2] & 4)
|
|
{ //resize right
|
|
item_size[0] = ui.mousepos[0] - (pos_x - item_position[0]) - draginfo[0];
|
|
if (item_size[0] < 128)
|
|
item_size[0] = 128;
|
|
if (item_resized)
|
|
item_resized();
|
|
}
|
|
efsize = item_size;
|
|
if (draginfo[2]&16)
|
|
{
|
|
queryscreensize();
|
|
if (ui.mousepos[1] < 8 && (item_flags & IF_RESIZABLE))
|
|
{
|
|
//make it look as though its fullscreen, without destroying its actual size.
|
|
//yes, we will fake-resize everything inside.
|
|
item_position = '0 0';
|
|
|
|
item_size = ui.screensize;
|
|
if (this.item_resized)
|
|
this.item_resized();
|
|
item_size = efsize;
|
|
efsize = ui.screensize;
|
|
}
|
|
else if (item_size == ui.screensize && (item_flags & IF_RESIZABLE))
|
|
{
|
|
item_size = item_size*0.5;
|
|
draginfo[0] = draginfo[0]*0.5;
|
|
if (this.item_resized)
|
|
this.item_resized();
|
|
efsize = item_size;
|
|
}
|
|
else
|
|
{
|
|
item_position = ui.mousepos - (pos - item_position) - draginfo;
|
|
item_position[2] = 0;
|
|
if (item_flags & IF_RESIZABLE)
|
|
if (item_resized)
|
|
item_resized();
|
|
}
|
|
}
|
|
}
|
|
|
|
//bound it to the screen... just in case the screen got resized or something
|
|
if (item_position[0] > ui.screensize[0] - item_size[0]*0.25)
|
|
item_position[0] = ui.screensize[0] - item_size[0]*0.25;
|
|
if (item_position[1] > ui.screensize[1] - item_framesize[1])
|
|
item_position[1] = ui.screensize[1] - item_framesize[1];
|
|
if (item_position[0] < item_size[0]*-0.75)
|
|
item_position[0] = item_size[0]*-0.75;
|
|
if (item_position[1] < 0)
|
|
item_position[1] = 0;
|
|
|
|
local float drag = 0;
|
|
if (draginfo[2])
|
|
drag = draginfo[2];
|
|
else if (item_flags & IF_MFOCUSED)
|
|
drag = this::whichgrabhandle(pos);
|
|
if (drag)
|
|
this::drawgrabhandle(pos, drag);
|
|
|
|
ui.drawfill(pos, efsize, item_rgb, item_alpha, 0);
|
|
local vector col = '1 1 1';
|
|
if (item_flags & IF_KFOCUSED)
|
|
col_x = 0;
|
|
if ((item_flags & IF_MFOCUSED) && mouseinbox(pos, [efsize_x-item_framesize[1], item_framesize[1]]))
|
|
col_z = 0;
|
|
inset = (item_framesize[1]-item_scale)*0.5;
|
|
ui.drawstring(pos + '1 1'*inset, item_text, item_scale*'1 1', col, 1, 0);
|
|
if (!(item_flags & IF_NOKILL))
|
|
{
|
|
if (mouseinbox(pos + [efsize_x-item_framesize[1], 0], item_framesize[1]*'1 1'))
|
|
col = '1 1 0';
|
|
else
|
|
col = '1 1 1';
|
|
ui.drawstring(pos + [efsize_x+inset-item_framesize[1], inset], "X", item_scale*'1 1', col, 1, 0);
|
|
}
|
|
super::item_draw(pos);
|
|
};
|
|
mitem_menu(mitem_frame desktop, string mname, vector sz) menu_spawn =
|
|
{
|
|
mitem_menu n = spawn(mitem_menu, item_text:mname, item_framesize:'4 16 4', item_size:sz);
|
|
|
|
// n.item_flags |= IF_RESIZABLE;
|
|
|
|
if (desktop)
|
|
desktop.addr(n, RS_X_MIN_PARENT_MIN | RS_X_MAX_OWN_MIN | RS_Y_MIN_PARENT_MIN | RS_Y_MAX_OWN_MIN, (desktop.item_size - n.item_size) * 0.5, n.item_size);
|
|
return n;
|
|
};
|