/*************************************************************************** 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