/////////////////////////////// // Create a new view window // void CG_mvCreate(int pID) { cg_window_t *w; if(CG_mvClientLocate(pID) != NULL) return; w = CG_windowAlloc(WFX_MULTIVIEW, 100); if(w == NULL) return; // Window specific w->id = WID_NONE; w->x = (cg.mv_cnt == 0) ? 0 : 30 + (12 * pID); w->y = (cg.mv_cnt == 0) ? 0 : 300 + (5 * pID); w->w = (cg.mv_cnt == 0) ? 640 : 128; w->h = (cg.mv_cnt == 0) ? 480 : 96; w->mvInfo = (pID & MV_PID) | MV_SELECTED; w->state = (cg.mv_cnt == 0) ? WSTATE_COMPLETE : WSTATE_START; if(cg.mv_cnt == 0) { cg.mvCurrentMainview = w; cg.mvCurrentActive = cg.mvCurrentMainview; if(cg_specHelp.integer > 0 && !cg.demoPlayback) { CG_ShowHelp_On(&cg.spechelpWindow); } } cg.mv_cnt++; }
/////////////////////////// // Delete a view window // void CG_mvFree( int pID ) { cg_window_t *w = CG_mvClientLocate( pID ); if ( w != NULL ) { // Free it in mvDraw() w->targetTime = 100; w->time = trap_Milliseconds(); w->state = WSTATE_SHUTDOWN; } }
// Mouse overlay for controlling multiview windows void CG_cursorUpdate(void) { int i, j, x; float nx, ny; int nSelectedWindow = -1; cg_window_t *w; cg_windowHandler_t *wh = &cg.winHandler; qboolean fFound = qfalse, fUpdateOverlay = qfalse; qboolean fSelect, fResize; // Get cursor current position (when connected to a server) if(!cg.demoPlayback) { // Allow for limbo'd updates as well trap_GetUserCmd(trap_GetCurrentCmdNumber(), &cg_pmove.cmd); nx = 640.0 * (65536.0 - cg_pmove.cmd.angles[1]) / 65536.0; ny = 480.0 / 65536.0 * ((int_m_pitch.value < 0.0) ? (65536.0 - cg_pmove.cmd.angles[0]) : cg_pmove.cmd.angles[0]); fSelect = ((cg_pmove.cmd.buttons & BUTTON_ATTACK) != 0); if(cgs.cursorX == (int)nx && cgs.cursorY == (int)ny && !fSelect) { return; } fResize = ((cg_pmove.cmd.buttons & BUTTON_SPRINT) != 0); cgs.cursorUpdate = cg.time + 5000; cgs.cursorX = nx; cgs.cursorY = ny; } else { // Already updated in the keycatcher nx = cgs.cursorX; ny = cgs.cursorY; fSelect = cgs.fSelect; fResize = cgs.fResize; } // For mm4 cg.mvCurrentActive = cg.mvCurrentMainview; // For overlay highlights for(i=0; i<cg.mvTotalClients; i++) { cg.mvOverlay[i].fActive = qfalse; } for(i=wh->numActiveWindows-1; i>=0; i--) { w = &wh->window[wh->activeWindows[i]]; if((w->effects & WFX_MULTIVIEW) && w != cg.mvCurrentMainview) { // Mouse/window detection // If the current window is selected, and the button is down, then allow the update // to occur, as quick mouse movements can move it past the window borders if(!fFound && ( ((w->mvInfo & MV_SELECTED) && fSelect) || (!fSelect && nx >= w->x && nx < w->x + w->w && ny >= w->y && ny < w->y + w->h) )) { if(!(w->mvInfo & MV_SELECTED)) { w->mvInfo |= MV_SELECTED; nSelectedWindow = i; } // If not dragging/resizing, prime for later update if(!fSelect) { w->m_x = -1.0f; w->m_y = -1.0f; } else { if(w->m_x > 0 && w->m_y > 0) { if(fResize) { w->w += nx - w->m_x; if(w->x + w->w > 640-2) w->w = 640 - 2 - w->x; if(w->w < 64) w->w = 64; w->h += ny - w->m_y; if(w->y + w->h > 480-2) w->h = 480 - 2 - w->y; if(w->h < 48) w->h = 48; } else { w->x += nx - w->m_x; if(w->x + w->w > 640-2) w->x = 640 - 2 - w->w; if(w->x < 2) w->x = 2; w->y += ny - w->m_y; if(w->y + w->h > 480-2) w->y = 480 - 2 - w->h; if(w->y < 2) w->y = 2; } } w->m_x = nx; w->m_y = ny; } fFound = qtrue; cg.mvCurrentActive = w; // Reset mouse info for window if it loses focuse } else if(w->mvInfo & MV_SELECTED) { fUpdateOverlay = qtrue; w->m_x = -1.0f; w->m_y = -1.0f; w->mvInfo &= ~MV_SELECTED; if(fFound) break; // Small optimization: we've found a new window, and cleared the old focus } } } nx = (float)(MVINFO_RIGHT - (MVINFO_TEXTSIZE * 3)); ny = (float)(MVINFO_TOP + (MVINFO_TEXTSIZE + 1)); // Highlight corresponding active window's overlay element if(fFound) { for(i=0; i<cg.mvTotalClients; i++) { if(cg.mvOverlay[i].pID == (cg.mvCurrentActive->mvInfo & MV_PID)) { cg.mvOverlay[i].fActive = qtrue; break; } } } // Check MV overlay detection here for better perf with more text elements // General boundary check else { // Ugh, have to loop through BOTH team lists int vOffset = 0; for(i=TEAM_AXIS; i<=TEAM_ALLIES; i++) { if(cg.mvTotalTeam[i] == 0) continue; if(cgs.cursorX >= nx && cgs.cursorY >= ny && cgs.cursorX < MVINFO_RIGHT && cgs.cursorY < ny + (cg.mvTotalTeam[i] * (MVINFO_TEXTSIZE + 1))) { int pos = (int)(cgs.cursorY - ny) / (MVINFO_TEXTSIZE + 1); if(pos < cg.mvTotalTeam[i]) { int x = MVINFO_RIGHT - cg.mvOverlay[(cg.mvTeamList[i][pos])].width; int y = MVINFO_TOP + vOffset + ((pos + 1) * (MVINFO_TEXTSIZE + 1)); // See if we're really over something if(cgs.cursorX >= x && cgs.cursorY >= y && cgs.cursorX <= MVINFO_RIGHT && cgs.cursorY <= y + MVINFO_TEXTSIZE) { // Perform any other window handling here for MV // views based on element selection cg.mvOverlay[(cg.mvTeamList[i][pos])].fActive = qtrue; w = CG_mvClientLocate(cg.mvOverlay[(cg.mvTeamList[i][pos])].pID); if(w != NULL) { cg.mvCurrentActive = w; } if(fSelect) { if(w != NULL) { // Swap window-view with mainview if(w != cg.mvCurrentMainview) { CG_mvMainviewSwap(w); } } else { // Swap non-view with mainview cg.mvCurrentMainview->mvInfo = (cg.mvCurrentMainview->mvInfo & ~MV_PID) | (cg.mvOverlay[cg.mvTeamList[i][pos]].pID & MV_PID); fUpdateOverlay = qtrue; } } } } } vOffset += (cg.mvTotalTeam[i] + 2) * (MVINFO_TEXTSIZE + 1); ny += vOffset; } } // If we have a new highlight, reorder so our highlight is always // drawn last (on top of all other windows) if(nSelectedWindow >= 0) { fUpdateOverlay = qtrue; x = wh->activeWindows[nSelectedWindow]; for(j=nSelectedWindow; j<wh->numActiveWindows-1; j++) { wh->activeWindows[j] = wh->activeWindows[j+1]; } wh->activeWindows[wh->numActiveWindows-1] = x; } // Finally, sync the overlay, if needed if(fUpdateOverlay) { CG_mvOverlayUpdate(); } }