fteqw/quakec/menusys/menusys/mitem_desktop.qc
Spoike 934a97c53e fix some compile issues (errors and warnings). sdl, ode, vulkan.
fix q2bsp textures.
fix some vulkan validation issues.
MOVE_OTHERONLY is now an official feature (replacing MOVE_ONLYENT which is now removed, same functionality, better behaved behaviour).
network up edited brushes on initial connect. still needs more work for entity editing, but should otherwise be okay for now.
add sys_browserredirect console command for emscripten builds (can be used to trigger window redirections - including download requests)

git-svn-id: https://svn.code.sf.net/p/fteqw/code/trunk@5001 fc73d0e0-1445-4013-8a0c-d673dee63da5
2016-07-15 12:26:24 +00:00

455 lines
12 KiB
C++

/***************************************************************************
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
#ifndef MENU
float sb_showscores;
#endif
void() mitem_desktop::mitem_desktop =
{
#define menu_font_win autocvar(menu_font_win, "")
#define menu_font autocvar(menu_font, "")
#define menu_font_fallback autocvar(gl_font, "")
queryscreensize();
//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 != "" && !strncmp(cvar_string("sys_platform"), "Win", 3))
fontname = menu_font_win;
else if (menu_font != "")
fontname = menu_font;
drawfont = loadfont("", fontname, "8 12 16", -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)
{
#ifdef CSQC
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)
{
#ifdef CSQC
if (numclientseats > 3)
localcmd("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("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;
};
#ifndef MENU
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 =
{
#ifndef MENU
//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__)
{
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
{
drawgame_helper(0, '0 0', ui.screensize);
}
}
#endif
super::item_draw(pos);
if (ui.kgrabs == this)
{
#ifndef MENU
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)
{
if (drawgetimagesize(autocvar_cl_cursor) == '0 0')
ui.drawcharacter(ui.mousepos - [stringwidth("+", TRUE, '4 4')*0.5, 4], '+', '8 8', '1 1 1', 1, 0);
else
ui.drawpic(ui.mousepos - autocvar_cl_cursorbias*'1 1', autocvar_cl_cursor, autocvar_cl_cursorsize*'1 1', '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;
};
//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:
#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;
};
void() gah =
{
items_keypress_(0, 0,0,0,0);
};
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;
};