//----------------------------------------------------------------------------- // Purpose: Called whenever a panel is constructed //----------------------------------------------------------------------------- void CVGui::PanelCreated(VPanel *panel) { UtlHandle_t h = m_HandleTable.AddHandle(); m_HandleTable.SetHandle( h, panel ); #if DUMP_PANEL_LIST int nCount = m_HandleTable.GetHandleCount(); int nActualCount = 0; for ( int i = 0; i < nCount; ++i ) { UtlHandle_t h = m_HandleTable.GetHandleFromIndex( i ); if ( m_HandleTable.IsHandleValid( h ) ) { ++nActualCount; } } if ( nActualCount >= WARN_PANEL_NUMBER ) { FILE *file1 = fopen("panellist.txt", "w"); if (file1 != NULL) { fprintf(file1, "Too many panels...listing them all.\n"); int panelIndex; for (panelIndex = 0; panelIndex < nCount; ++panelIndex) { UtlHandle_t h = m_HandleTable.GetHandleFromIndex( i ); VPanel *pPanel = m_HandleTable.GetHandle( h ); IClientPanel *ipanel = ( pPanel ) ? pPanel->Client() : NULL; if ( ipanel ) fprintf(file1, "panel %d: name: %s classname: %s\n", panelIndex, ipanel->GetName(), ipanel->GetClassName()); else fprintf(file1, "panel %d: can't get ipanel\n", panelIndex); } fclose(file1); } } Assert( nActualCount < WARN_PANEL_NUMBER ); #endif // DUMP_PANEL_LIST ((VPanel *)panel)->SetHPanel( h ); g_pSurface->AddPanel((VPANEL)panel); }
//----------------------------------------------------------------------------- // Purpose: message pump // loops through and sends all active messages // note that more messages may be posted during the process //----------------------------------------------------------------------------- bool CVGui::DispatchMessages() { int time = g_pSystem->GetTimeMillis(); m_InDispatcher = true; bool doneWork = (m_MessageQueue.Count() > 12); bool bUsingDelayedQueue = (m_DelayedMessageQueue.Count() > 0); // Need two passes because we send the mouse move message after all // other messages are done, but the mouse move message may itself generate // some more messages int nPassCount = 0; while ( nPassCount < 2 ) { while (m_MessageQueue.Count() > 0 || (m_SecondaryQueue.Count() > 0) || bUsingDelayedQueue) { // get the first message MessageItem_t *messageItem = NULL; int messageIndex = 0; // use the secondary queue until it empties. empty it after each message in the // primary queue. this makes primary messages completely resolve bool bUsingSecondaryQueue = (m_SecondaryQueue.Count() > 0); if (bUsingSecondaryQueue) { doneWork = true; messageIndex = m_SecondaryQueue.Head(); messageItem = &m_SecondaryQueue[messageIndex]; } else if (bUsingDelayedQueue) { if (m_DelayedMessageQueue.Count() >0) { messageItem = (MessageItem_t*)&m_DelayedMessageQueue.ElementAtHead(); } if (!messageItem || messageItem->_arrivalTime > time) { // no more items in the delayed message queue, move to the system queue bUsingDelayedQueue = false; continue; } } else { messageIndex = m_MessageQueue.Head(); messageItem = &m_MessageQueue[messageIndex]; } // message debug code if ( m_bDebugMessages ) { char *qname = bUsingSecondaryQueue ? "Secondary" : "Primary"; if (strcmp(messageItem->_params->GetName(), "Tick") && strcmp(messageItem->_params->GetName(), "MouseFocusTicked") && strcmp(messageItem->_params->GetName(), "KeyFocusTicked") && strcmp(messageItem->_params->GetName(), "CursorMoved")) { if (!stricmp(messageItem->_params->GetName(), "command")) { g_pIVgui->DPrintf2( "%s Queue dispatching command( %s, %s -- %i )\n", qname, messageItem->_params->GetName(), messageItem->_params->GetString("command"), messageItem->_messageID ); } else { g_pIVgui->DPrintf2( "%s Queue dispatching( %s -- %i )\n", qname ,messageItem->_params->GetName(), messageItem->_messageID ); } } } // send it KeyValues *params = messageItem->_params; // Deal with special internal cursor movement messages if ( messageItem->_messageTo == 0xFFFFFFFF ) { if ( !Q_stricmp( params->GetName(), "SetCursorPosInternal" ) ) { int nXPos = params->GetInt( "xpos", 0 ); int nYPos = params->GetInt( "ypos", 0 ); g_pInput->UpdateCursorPosInternal( nXPos, nYPos ); } } else { VPanel *vto = (VPanel *)g_pIVgui->HandleToPanel(messageItem->_messageTo); if (vto) { // Msg("Sending message: %s to %s\n", params ? params->GetName() : "\"\"", vto->GetName() ? vto->GetName() : "\"\""); vto->SendMessage(params, g_pIVgui->HandleToPanel(messageItem->_from)); } } // free the keyvalues memory // we can't reference the messageItem pointer anymore since the queue might have moved in memory if (params) { params->deleteThis(); } // remove it from the queue if (bUsingSecondaryQueue) { m_SecondaryQueue.Remove(messageIndex); } else if (bUsingDelayedQueue) { m_DelayedMessageQueue.RemoveAtHead(); } else { m_MessageQueue.Remove(messageIndex); } } ++nPassCount; if ( nPassCount == 1 ) { // Specifically post the current mouse position as a message g_pInput->PostCursorMessage(); } } // Make sure the windows cursor is in the right place after processing input // Needs to be done here because a message provoked by the cursor moved // message may move the cursor also g_pInput->HandleExplicitSetCursor( ); m_InDispatcher = false; return doneWork; }
//----------------------------------------------------------------------------- // Purpose: Calculates which panel the cursor is currently over and sets it up // as the current mouse focus. //----------------------------------------------------------------------------- void CInputWin32::UpdateMouseFocus(int x, int y) { // find the panel that has the focus VPanel *focus = NULL; InputContext_t *pContext = GetInputContext( m_hContext ); if (!pContext->_rootPanel) { if (surface()->IsCursorVisible() && surface()->IsWithin(x, y)) { // faster version of code below // checks through each popup in order, top to bottom windows for (int i = surface()->GetPopupCount() - 1; i >= 0; i--) { VPanel *popup = (VPanel *)surface()->GetPopup(i); VPanel *panel = popup; bool wantsMouse = panel->IsMouseInputEnabled(); bool isVisible; do { isVisible = panel->IsVisible(); panel = panel->GetParent(); } while ( isVisible && panel && panel->GetParent() ); // only consider panels that want mouse input if ( wantsMouse && isVisible ) { focus = (VPanel *)popup->Client()->IsWithinTraverse(x, y, false); if (focus) break; } } if (!focus) { focus = (VPanel *)((VPanel *)surface()->GetEmbeddedPanel())->Client()->IsWithinTraverse(x, y, false); } } } else { focus = (VPanel *)((VPanel *)(pContext->_rootPanel))->Client()->IsWithinTraverse(x, y, false); } // mouse focus debugging code /* static VPanel *oldFocus = (VPanel *)0x0001; if (oldFocus != focus) { oldFocus = focus; if (focus) { ivgui()->DPrintf2("mouse over: (%s, %s)\n", focus->GetName(), focus->GetClassName()); } else { ivgui()->DPrintf2("mouse over: (NULL)\n"); } } */ // check if we are in modal state, // and if we are make sure this panel is a child of us. if (!IsChildOfModalPanel((VPANEL)focus)) { // should this be _appModalPanel? focus = NULL; } SetMouseFocus((VPANEL)focus); }
//----------------------------------------------------------------------------- // Purpose: Sets the new mouse focus // won't override _mouseCapture settings // Input : newMouseFocus - //----------------------------------------------------------------------------- void CInputWin32::SetMouseFocus(VPANEL newMouseFocus) { // check if we are in modal state, // and if we are make sure this panel is a child of us. if (!IsChildOfModalPanel(newMouseFocus)) { return; } bool wantsMouse, isPopup; // = popup->GetMouseInput(); VPanel *panel = (VPanel *)newMouseFocus; InputContext_t *pContext = GetInputContext( m_hContext ); if ( newMouseFocus ) { do { wantsMouse = panel->IsMouseInputEnabled(); isPopup = panel->IsPopup(); panel = panel->GetParent(); } while ( wantsMouse && !isPopup && panel && panel->GetParent() ); // only consider panels that want mouse input } // if this panel doesn't want mouse input don't let it get focus if (newMouseFocus && !wantsMouse) { return; } if ((VPANEL)pContext->_mouseOver != newMouseFocus || (!pContext->_mouseCapture && (VPANEL)pContext->_mouseFocus != newMouseFocus) ) { pContext->_oldMouseFocus = pContext->_mouseOver; pContext->_mouseOver = (VPanel *)newMouseFocus; //tell the old panel with the mouseFocus that the cursor exited if (pContext->_oldMouseFocus != NULL) { // only notify of entry if the mouse is not captured or we're a child of the captured panel if ( !pContext->_mouseCapture || pContext->_oldMouseFocus->HasParent(pContext->_mouseCapture) ) { ivgui()->PostMessage((VPANEL)pContext->_oldMouseFocus, new KeyValues("CursorExited"), NULL); } } //tell the new panel with the mouseFocus that the cursor entered if (pContext->_mouseOver != NULL) { // only notify of entry if the mouse is not captured or we're a child of the captured panel if ( !pContext->_mouseCapture || pContext->_mouseOver->HasParent(pContext->_mouseCapture) ) { ivgui()->PostMessage((VPANEL)pContext->_mouseOver, new KeyValues("CursorEntered"), NULL); } } // set where the mouse is currently over // mouse capture overrides destination if ( pContext->_mouseCapture ) { pContext->_mouseFocus = pContext->_mouseCapture; } else { pContext->_mouseFocus = pContext->_mouseOver; } } }
//----------------------------------------------------------------------------- // Purpose: Calculate the new key focus //----------------------------------------------------------------------------- VPanel *CInputWin32::CalculateNewKeyFocus() { InputContext_t *pContext = GetInputContext(m_hContext); // get the top-order panel VPanel *top = NULL; VPanel *wantedKeyFocus = NULL; if (!pContext->_rootPanel) { if (surface()->GetPopupCount() > 0) { // find the highest-level window that is both visible and a popup int index = surface()->GetPopupCount(); while (index) { top = (VPanel *)surface()->GetPopup(--index); // traverse the heirachy and check if the popup really is visible if (top->IsPopup() && top->IsVisible() && top->IsKeyBoardInputEnabled() && !surface()->IsMinimized((VPANEL)top)) { bool IsVisible = top->IsVisible(); VPanel *p = top->GetParent(); // drill down the heirachy checking that everything is visible while(p && IsVisible) { if( p->IsVisible()==false) { IsVisible=false; break; } p=p->GetParent(); } if (IsVisible && !surface()->IsMinimized((VPANEL)top) ) { break; } } top = NULL; } } } else { top = (VPanel *)pContext->_rootPanel; } if (top) { // ask the top-level panel for what it considers to be the current focus wantedKeyFocus = (VPanel *)top->Client()->GetCurrentKeyFocus(); if (!wantedKeyFocus) { wantedKeyFocus = top; } } // check to see if any of this surfaces panels have the focus if (!surface()->HasFocus()) { wantedKeyFocus=NULL; } // check if we are in modal state, // and if we are make sure this panel is a child of us. if (!IsChildOfModalPanel((VPANEL)wantedKeyFocus)) { wantedKeyFocus=NULL; } return wantedKeyFocus; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CInputWin32::RunFrame() { InputContext_t *pContext = GetInputContext(m_hContext); if (m_hContext == DEFAULT_INPUT_CONTEXT) { _updateToggleButtonState = true; /* FIXME: add the set cursor call? // make sure the cursor looks like it is supposed to if (pContext->_mouseFocus) { pContext->_mouseFocus->Client()->InternalSetCursor(); }*/ } // tick whoever has the focus if (pContext->_keyFocus) { // when modal dialogs are up messages only get sent to the dialogs children. if (IsChildOfModalPanel((VPANEL)pContext->_keyFocus)) { ivgui()->PostMessage((VPANEL)pContext->_keyFocus, new KeyValues("KeyFocusTicked"), NULL); } } // tick whoever has the focus if (pContext->_mouseFocus) { // when modal dialogs are up messages only get sent to the dialogs children. if (IsChildOfModalPanel((VPANEL)pContext->_mouseFocus)) { ivgui()->PostMessage((VPANEL)pContext->_mouseFocus, new KeyValues("MouseFocusTicked"), NULL); } } //clear mouse and key states for (int i = 0; i < MOUSE_LAST; i++) { pContext->_mousePressed[i] = 0; pContext->_mouseDoublePressed[i] = 0; pContext->_mouseReleased[i] = 0; } for (i = 0; i < KEY_LAST; i++) { pContext->_keyPressed[i] = 0; pContext->_keyTyped[i] = 0; pContext->_keyReleased[i] = 0; } VPanel *wantedKeyFocus = CalculateNewKeyFocus(); // make sure old and new focus get painted if (pContext->_keyFocus != wantedKeyFocus) { if (pContext->_keyFocus != NULL) { pContext->_keyFocus->Client()->InternalFocusChanged(true); // send a message to the window saying that it's losing focus ivgui()->PostMessage((VPANEL)pContext->_keyFocus, new KeyValues("KillFocus"), NULL); pContext->_keyFocus->Client()->Repaint(); // repaint the nearest popup as well, since it will need to redraw after losing focus VPanel *dlg = pContext->_keyFocus; while (dlg && !dlg->IsPopup()) { dlg = dlg->GetParent(); } if (dlg) { dlg->Client()->Repaint(); } } if (wantedKeyFocus != NULL) { wantedKeyFocus->Client()->InternalFocusChanged(false); // send a message to the window saying that it's gaining focus ivgui()->PostMessage((VPANEL)wantedKeyFocus, new KeyValues("SetFocus"), NULL); wantedKeyFocus->Client()->Repaint(); // repaint the nearest popup as well, since it will need to redraw after gaining focus VPanel *dlg = wantedKeyFocus; while (dlg && !dlg->IsPopup()) { dlg = dlg->GetParent(); } if (dlg) { dlg->Client()->Repaint(); } } // accept the focus request pContext->_keyFocus = wantedKeyFocus; if (pContext->_keyFocus) { pContext->_keyFocus->MoveToFront(); } } }