467 lines
12 KiB
Plaintext
467 lines
12 KiB
Plaintext
/***************************************************************************
|
|
desktop and top-level functions.
|
|
*/
|
|
|
|
#ifdef USEPOINTERS
|
|
typedef mitem mitem_desktop;
|
|
#else
|
|
class mitem_desktop : mitem_frame
|
|
{
|
|
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; //draws the game, then calls mitem_frame::item_draw for children.
|
|
#ifndef MENU
|
|
virtual void(float seat, vector minpos, vector size) drawgame = __NULL__; //if overridden, should call renderscene and then draw whatever hud it needs to. this will do splitscreen efficiently and automatically.
|
|
#endif
|
|
void() mitem_desktop; //the constructor. uninteresting. just ensures the size defaults to fullscreen.
|
|
};
|
|
#endif
|
|
|
|
#if !defined(MENU) && !defined(CSQC_SIMPLE)
|
|
float sb_showscores;
|
|
#endif
|
|
|
|
float drawfont;
|
|
float(string fontname, string fontmaps, string sizes, float slot, optional float fix_scale, optional float fix_voffset) loadfont = #357;
|
|
|
|
void() mitem_desktop::mitem_desktop =
|
|
{
|
|
#define menu_font_win autocvar(menu_font_win, "cour")
|
|
#define menu_font autocvar(menu_font, "cour")
|
|
#define menu_font_fallback autocvar(gl_font, "")
|
|
queryscreensize();
|
|
|
|
if (checkextension("DP_GFX_FONTS"))
|
|
{
|
|
//make sure we have a font that can cope with slightly up-scaled stuff.
|
|
//windows is special because we can load from the system fonts
|
|
string fontname = menu_font_fallback;
|
|
if (menu_font_win != "" && !strncasecmp(cvar_string("sys_platform"), "Win", 3))
|
|
fontname = menu_font_win;
|
|
else if (menu_font != "")
|
|
fontname = menu_font;
|
|
drawfont = loadfont("", fontname, "8 12 16 outline=1", -1);
|
|
}
|
|
|
|
item_text = "desktop";
|
|
if (!item_flags)
|
|
{
|
|
item_size = ui.screensize;
|
|
item_flags = IF_SELECTABLE | IF_MFOCUSED | IF_KFOCUSED | IF_RESIZABLE | IF_NOCURSOR;
|
|
}
|
|
|
|
if (!ui.kgrabs && !ui.mgrabs && (item_flags & IF_NOCURSOR))
|
|
{
|
|
ui.kgrabs = this;
|
|
ui.mgrabs = this;
|
|
}
|
|
};
|
|
|
|
void(mitem newfocus, float flag) mitem_desktop::item_focuschange =
|
|
{
|
|
super::item_focuschange(newfocus, flag);
|
|
|
|
if (flag & IF_KFOCUSED)
|
|
{
|
|
//if we're deselecting the current one, reenable grabs
|
|
if (newfocus == __NULL__)
|
|
{
|
|
if(item_flags & IF_NOCURSOR)
|
|
{
|
|
ui.kgrabs = this;
|
|
ui.mgrabs = this;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ui.kgrabs == this)
|
|
{
|
|
ui.kgrabs = __NULL__;
|
|
ui.mgrabs = __NULL__;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
//the interact flag says that the mouse is held down on the desktop
|
|
float(vector pos, float scan, float char, float down) mitem_desktop::item_keypress =
|
|
{
|
|
float oldfl = item_flags;
|
|
|
|
if (down & 2)
|
|
{
|
|
down &= 1;
|
|
//if we're grabbing, then cancel if they press escape, otherwise block other items from taking the keys.
|
|
if (scan >= K_MOUSE1 && scan <= K_MOUSE5)
|
|
return 2; //block other wigits, don't cancel the event so the engine still does its thing
|
|
else
|
|
{
|
|
if (scan == K_ESCAPE && down)
|
|
{
|
|
local mitem sc;
|
|
//block the keyevent if we already have menus loaded but not focused (select one if we do).
|
|
for (sc = item_children; sc; sc = sc.item_next)
|
|
{
|
|
if (sc.item_flags & IF_SELECTABLE)
|
|
{
|
|
if (!item_kactivechild)
|
|
item_focuschange(sc, IF_KFOCUSED);
|
|
return 3;
|
|
}
|
|
}
|
|
//make sure our code takes it, instead of showing the engine menu...
|
|
#ifdef MENU
|
|
m_toggle(0);
|
|
return 3;
|
|
#else
|
|
return 2|CSQC_ConsoleCommand("togglemenu");
|
|
#endif
|
|
}
|
|
return 2;
|
|
}
|
|
}
|
|
|
|
if (mitem_frame::item_keypress(pos, scan, char, down))
|
|
return TRUE;
|
|
|
|
if (scan == K_MOUSE1 && down)
|
|
{
|
|
#if defined(CSQC) && defined(FTE_SPLITSCREEN)
|
|
if (numclientseats)
|
|
localcmd("in_forcesplitclient 0\n");
|
|
#endif
|
|
if (item_flags & IF_NOCURSOR)
|
|
{
|
|
ui.kgrabs = this;
|
|
ui.mgrabs = this;
|
|
}
|
|
return TRUE;
|
|
}
|
|
if (scan == K_MOUSE2 && down)
|
|
{
|
|
#if defined(CSQC) && defined(FTE_SPLITSCREEN)
|
|
if (numclientseats > 3)
|
|
localcmd(strcat("in_forcesplitclient ", ftos(1 + ((ui.mousepos[0]>ui.screensize[0]/2)?1:0) + ((ui.mousepos[1]>ui.screensize[1]/2)?2:0)), "\n"));
|
|
else if (numclientseats > 1)
|
|
localcmd(strcat("in_forcesplitclient ", ftos(1 + floor(ui.mousepos[1]*numclientseats/ui.screensize[1])), "\n"));
|
|
else if (numclientseats)
|
|
localcmd("in_forcesplitclient 0\n");
|
|
#endif
|
|
if (item_flags & IF_NOCURSOR)
|
|
{
|
|
ui.kgrabs = this;
|
|
ui.mgrabs = this;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
#ifdef CSQC
|
|
//catch otherwise unhangled escape presses, just to be sure we can use escape to toggle the menu
|
|
if (scan == K_ESCAPE && down)
|
|
{
|
|
return CSQC_ConsoleCommand("togglemenu");
|
|
}
|
|
#endif
|
|
return FALSE;
|
|
};
|
|
|
|
#if !defined(MENU) && !defined(CSQC_SIMPLE)
|
|
static vector(vector v) vtodpp =
|
|
{
|
|
//so fucking disgustingly ugly.
|
|
if (dp_workarounds)
|
|
{
|
|
v_x *= cvar("vid_width") / cvar("vid_conwidth");
|
|
v_y *= cvar("vid_height") / cvar("vid_conheight");
|
|
}
|
|
return v;
|
|
};
|
|
|
|
//vector pmove_org;
|
|
void(float seat, vector minpos, vector size) mitem_desktop::drawgame_helper =
|
|
{
|
|
if not(seat)
|
|
{
|
|
clearscene();
|
|
addentities(MASK_ENGINE|MASK_VIEWMODEL);
|
|
}
|
|
else
|
|
{
|
|
setviewprop(VF_LPLAYER, seat);
|
|
setproperty(VF_VIEWENTITY, player_localentnum);
|
|
addentities(MASK_VIEWMODEL); //don't do mask_engine because that's already done
|
|
}
|
|
// if (dp_workarounds)
|
|
// setproperty(VF_ORIGIN, pmove_org);
|
|
setproperty(VF_MIN, minpos);
|
|
setproperty(VF_SIZE, vtodpp(size));
|
|
|
|
setproperty(VF_DRAWCROSSHAIR, (ui.mgrabs == this));
|
|
|
|
drawgame(seat, minpos, size);
|
|
if (mouseinbox(minpos, size))
|
|
{
|
|
ui.havemouseworld = TRUE;
|
|
ui.mouseworldnear = unproject([ui.mousepos[0], ui.mousepos[1], 0]);
|
|
ui.mouseworldfar = unproject([ui.mousepos[0], ui.mousepos[1], 100000]);
|
|
}
|
|
};
|
|
#endif
|
|
|
|
void(vector pos) mitem_desktop::item_draw =
|
|
{
|
|
#if !defined(MENU) && !defined(CSQC_SIMPLE)
|
|
//menuqc picks up the game/console as a background
|
|
string constate = serverkey("constate");
|
|
if (constate != "" && constate != "active") //allow empty, so things still kinda work with dp too.
|
|
{
|
|
drawfill(pos, ui.screensize, '0 0 0', 1, 0);
|
|
}
|
|
else if (this.drawgame != __NULL__)
|
|
{
|
|
#ifdef FTE_SPLITSCREEN
|
|
if (numclientseats > 3)
|
|
{
|
|
drawgame_helper(0, [0, 0], 0.5*ui.screensize);
|
|
drawgame_helper(1, [ui.screensize[0]*0.5, 0], 0.5*ui.screensize);
|
|
drawgame_helper(2, [0, ui.screensize[1]*0.5], 0.5*ui.screensize);
|
|
drawgame_helper(3, [ui.screensize[0]*0.5, ui.screensize[1]*0.5], 0.5*ui.screensize);
|
|
setviewprop(VF_LPLAYER, 0);
|
|
}
|
|
else if (numclientseats > 2)
|
|
{
|
|
drawgame_helper(0, [0, 0], [ui.screensize[0], ui.screensize[1]*0.333]);
|
|
drawgame_helper(1, [0, ui.screensize[1]*0.333], [ui.screensize[0], ui.screensize[1]*0.333]);
|
|
drawgame_helper(2, [0, ui.screensize[1]*0.666], [ui.screensize[0], ui.screensize[1]*0.333]);
|
|
setviewprop(VF_LPLAYER, 0);
|
|
}
|
|
else if (numclientseats > 1)
|
|
{
|
|
drawgame(0, [0, 0], [ui.screensize[0], ui.screensize[1]*0.5]);
|
|
drawgame(1, [0, ui.screensize[1]*0.5], [ui.screensize[0], ui.screensize[1]*0.5]);
|
|
setviewprop(VF_LPLAYER, 0);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
drawgame_helper(0, '0 0', ui.screensize);
|
|
}
|
|
}
|
|
#endif
|
|
super::item_draw(pos);
|
|
|
|
if (ui.kgrabs == this)
|
|
{
|
|
#if defined(CSQC) && !defined(CSQC_SIMPLE)
|
|
if (sb_showscores && ui.mgrabs == this)
|
|
ui.mgrabs = __NULL__;
|
|
else
|
|
#endif
|
|
if (!ui.mgrabs)
|
|
ui.mgrabs = this;
|
|
}
|
|
};
|
|
|
|
|
|
var string autocvar_cl_cursor = "gfx/cursor.lmp";
|
|
var float autocvar_cl_cursorsize = 32;
|
|
var float autocvar_cl_cursorbias = 4;
|
|
|
|
static var float oldgrabstate; //to work around a DP bug (as well as unnecessary spam)
|
|
|
|
void(float force) items_updategrabs =
|
|
{
|
|
if (!ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR))
|
|
{
|
|
if (!oldgrabstate || force)
|
|
{
|
|
oldgrabstate = TRUE;
|
|
#ifdef MENU
|
|
setkeydest(2);
|
|
setmousetarget(2);
|
|
#else
|
|
setcursormode(TRUE);
|
|
//setcursormode(TRUE, autocvar_cl_cursor, autocvar_cl_cursorbias*'1 1', autocvar_cl_cursorscale);
|
|
#endif
|
|
}
|
|
}
|
|
else if (oldgrabstate || force)
|
|
{
|
|
oldgrabstate = FALSE;
|
|
#ifdef MENU
|
|
setkeydest(0);
|
|
setmousetarget(1);
|
|
#else
|
|
setcursormode(FALSE);
|
|
#endif
|
|
}
|
|
};
|
|
|
|
void(mitem_desktop desktop) items_draw =
|
|
{
|
|
queryscreensize();
|
|
|
|
#ifdef MENU
|
|
ui.mousepos = getmousepos();
|
|
#else
|
|
if (ui.havemouseworld)
|
|
ui.havemouseworld = 2; //stale, but not too stale
|
|
#endif
|
|
|
|
if (desktop.item_size != ui.screensize)
|
|
{
|
|
desktop.item_size = ui.screensize;
|
|
desktop.item_resized();
|
|
}
|
|
ui.drawrectmax = ui.screensize;
|
|
|
|
desktop.item_draw(desktop.item_position);
|
|
drawresetcliparea();
|
|
|
|
items_updategrabs(FALSE);
|
|
if (dp_workarounds && oldgrabstate)
|
|
{
|
|
// //hopefully dp isn't broken and reports non-zero sizes for files that failed.
|
|
// if (drawgetimagesize(autocvar_cl_cursor) == '0 0')
|
|
// ui.drawpic(ui.mousepos - autocvar_cl_cursorbias*'1 1', autocvar_cl_cursor, autocvar_cl_cursorsize*'1 1', '1 1 1', 1, 0);
|
|
// else
|
|
ui.drawcharacter(ui.mousepos - [stringwidth("+", TRUE, '4 4')*0.5, 4], '+', '8 8', '1 1 1', 1, 0);
|
|
}
|
|
|
|
#ifndef MENU
|
|
if (ui.havemouseworld == 2) //if its still stale then its totally invalid.
|
|
ui.havemouseworld = FALSE;
|
|
#endif
|
|
ui.oldmousepos = ui.mousepos;
|
|
};
|
|
|
|
#ifdef CSQC
|
|
//items_keypress has quite strong dimorphism. These are meant to tailored to the target's available event notifications, rather than being really rather annoying.
|
|
csqconly float(mitem_desktop desktop, float evtype, float scanx, float chary, float devid) items_keypress =
|
|
{
|
|
local float result = FALSE;
|
|
vector pos;
|
|
mitem p;
|
|
switch(evtype)
|
|
{
|
|
case IE_KEYDOWN:
|
|
case IE_KEYUP:
|
|
if (scanx == K_SHIFT)
|
|
ui.shiftheld = evtype==IE_KEYDOWN;
|
|
#ifdef HEIRACHYDEBUG
|
|
if (scanx == K_F1 && evtype == IE_KEYDOWN)
|
|
{
|
|
mitem_printtree(desktop, "items_keypress", __LINE__);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
if (scanx >= K_MOUSE1 && scanx <= K_MOUSE5)
|
|
{
|
|
if (ui.mgrabs)
|
|
{
|
|
pos = '0 0 0';
|
|
for (p = ui.mgrabs; p; p = p.item_parent)
|
|
pos += p.item_position;
|
|
result = ui.mgrabs.item_keypress(pos, scanx, chary, (evtype == IE_KEYDOWN)|2);
|
|
if (result & 2)
|
|
{
|
|
ui.mousedown = 0;
|
|
return result & 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ui.kgrabs)
|
|
{
|
|
pos = '0 0 0';
|
|
for (p = ui.kgrabs; p; p = p.item_parent)
|
|
pos += p.item_position;
|
|
result = ui.kgrabs.item_keypress(pos, scanx, chary, (evtype == IE_KEYDOWN)|2);
|
|
if (result & 2)
|
|
return result & 1;
|
|
}
|
|
}
|
|
if (desktop && desktop.item_keypress)
|
|
result = desktop.item_keypress(desktop.item_position, scanx, chary, evtype == IE_KEYDOWN);
|
|
if (scanx >= K_MOUSE1 && scanx <= K_MOUSE5)
|
|
{
|
|
if (evtype == IE_KEYDOWN)
|
|
ui.mousedown |= pow(1, scanx-K_MOUSE1);
|
|
else
|
|
ui.mousedown &~= pow(1, scanx-K_MOUSE1);
|
|
}
|
|
result = result & 1;
|
|
break;
|
|
case IE_MOUSEDELTA:
|
|
result = !ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR);
|
|
if (result)
|
|
{
|
|
queryscreensize();
|
|
ui.mousepos[0] = bound(0, ui.mousepos[0]+scanx, ui.screensize[0]);
|
|
ui.mousepos[1] = bound(0, ui.mousepos[1]+chary, ui.screensize[1]);
|
|
}
|
|
break;
|
|
case IE_MOUSEABS:
|
|
ui.mousepos[0] = scanx;
|
|
ui.mousepos[1] = chary;
|
|
result = !ui.mgrabs || !(ui.mgrabs.item_flags & IF_NOCURSOR);
|
|
break;
|
|
}
|
|
return result;
|
|
};
|
|
#endif
|
|
|
|
#ifdef MENU
|
|
menuonly float(mitem_desktop desktop, float scan, float char, float down) items_keypress =
|
|
{
|
|
local float result = FALSE;
|
|
local vector pos;
|
|
local mitem p;
|
|
ui.mousepos = getmousepos();
|
|
queryscreensize();
|
|
#ifdef HEIRACHYDEBUG
|
|
if (scan == K_F1 && down)
|
|
{
|
|
mitem_printtree(desktop, "items_keypress", __LINE__);
|
|
return TRUE;
|
|
}
|
|
#endif
|
|
|
|
if (scan >= K_MOUSE1 && scan <= K_MOUSE5)
|
|
{
|
|
if (ui.mgrabs)
|
|
{
|
|
pos = '0 0 0';
|
|
for (p = ui.mgrabs; p; p = p.item_parent)
|
|
pos += p.item_position;
|
|
result = ui.mgrabs.item_keypress(pos, scan, char, (down)|2);
|
|
if (result & 2)
|
|
{
|
|
ui.mousedown = 0;
|
|
return result & 1;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (ui.kgrabs)
|
|
{
|
|
pos = '0 0 0';
|
|
for (p = ui.kgrabs; p; p = p.item_parent)
|
|
pos += p.item_position;
|
|
result = ui.kgrabs.item_keypress(pos, scan, char, (down)|2);
|
|
if (result & 2)
|
|
return result & 1;
|
|
}
|
|
}
|
|
|
|
if (desktop && desktop.item_keypress)
|
|
result = desktop.item_keypress(desktop.item_position, scan, char, down);
|
|
|
|
return result;
|
|
};
|
|
#endif
|
|
|
|
|