bool Screen::MouseInput(int32_t iButton, int32_t iX, int32_t iY, DWORD dwKeyParam, Dialog *pForDlg, class C4Viewport *pForVP) { // help mode and button pressed: Abort help and discard button if (Game.MouseControl.IsHelp()) { switch (iButton) { case C4MC_Button_None: // just movement break; case C4MC_Button_LeftDown: case C4MC_Button_RightDown: // special for left/right down: Just ignore them, but don't stop help yet // help should be stopped on button-up, so these won't be processed iButton = C4MC_Button_None; break; default: // buttons stop help Game.MouseControl.AbortHelp(); iButton = C4MC_Button_None; break; } } // forward to mouse Mouse.Input(iButton, iX, iY, dwKeyParam); // dragging if (Mouse.pDragElement) { int32_t iX2=iX, iY2=iY; Mouse.pDragElement->ScreenPos2ClientPos(iX2, iY2); if (!Mouse.IsLDown()) { // stop dragging Mouse.pDragElement->StopDragging(Mouse, iX2, iY2, dwKeyParam); Mouse.pDragElement = NULL; } else { // continue dragging Mouse.pDragElement->DoDragging(Mouse, iX2, iY2, dwKeyParam); } } // backup previous MouseOver-element Mouse.pPrevMouseOverElement = Mouse.pMouseOverElement; Mouse.pMouseOverElement = NULL; bool fProcessed = false; // active context menu? if (!pForVP && pContext && pContext->CtxMouseInput(Mouse, iButton, iX, iY, dwKeyParam)) { // processed by context menu: OK! } // otherwise: active dlg and inside screen? (or direct forward to specific dlg/viewport dlg) else if (rcBounds.Contains(iX, iY) || pForDlg || pForVP) { // context menu open but mouse down command issued? close context then if (pContext && (iButton == C4MC_Button_LeftDown || iButton == C4MC_Button_RightDown)) AbortContext(true); // get client pos if (!pForDlg && !pForVP) { C4Rect &rcClientArea = GetClientRect(); iX -= rcClientArea.x; iY -= rcClientArea.y; } // exclusive mode: process active dialog only if (IsExclusive() && !pForDlg && !pForVP) { if (pActiveDlg && pActiveDlg->IsVisible() && !pActiveDlg->IsFading()) { // bounds check to dlg: only if not dragging C4Rect &rcDlgBounds = pActiveDlg->GetBounds(); if (Mouse.IsLDown() || rcDlgBounds.Contains(iX, iY)) // forward to active dialog pActiveDlg->MouseInput(Mouse, iButton, iX - rcDlgBounds.x, iY - rcDlgBounds.y, dwKeyParam); else Mouse.pMouseOverElement = NULL; } else // outside dialog: own handling (for screen context menu) Window::MouseInput(Mouse, iButton, iX, iY, dwKeyParam); } else { // non-exclusive mode: process all dialogs; make them active on left-click Dialog *pDlg; for (Element *pEl = pLast; pEl; pEl = pEl->GetPrev()) if (pDlg = pEl->GetDlg()) if (pDlg->IsShown()) { // if specified: process specified dlg only if (pForDlg && pDlg != pForDlg) continue; // if specified: process specified viewport only bool fIsExternalDrawDialog = pDlg->IsExternalDrawDialog(); C4Viewport *pVP = fIsExternalDrawDialog ? pDlg->GetViewport() : NULL; if (pForVP && pForVP != pVP) continue; // calc offset C4Rect &rcDlgBounds = pDlg->GetBounds(); int32_t iOffX=0, iOffY=0; // special handling for viewport dialogs if (fIsExternalDrawDialog) { // ignore external drawing dialogs without a viepwort assigned if (!pVP) continue; // always clip to viewport bounds C4Rect rcOut(pVP->GetOutputRect()); if (!rcOut.Contains(iX + rcBounds.x, iY + rcBounds.y)) continue; // viewport dialogs: Offset determined by viewport position iOffX = rcOut.x; iOffY = rcOut.y; } // hit test; or special: dragging possible outside active dialog if (rcDlgBounds.Contains(iX-iOffX, iY-iOffY) || (pDlg == pActiveDlg && Mouse.pDragElement)) { // Okay; do input pDlg->MouseInput(Mouse, iButton, iX - rcDlgBounds.x - iOffX, iY - rcDlgBounds.y - iOffY, dwKeyParam); // dlgs may destroy GUI if (!IsGUIValid()) return false; // CAUTION: pDlg may be invalid now! // set processed-flag manually fProcessed = true; // inactive dialogs get activated by clicks if (Mouse.IsLDown() && pDlg != pActiveDlg) // but not viewport dialogs! if (!pDlg->IsExternalDrawDialog()) ActivateDialog(pDlg); // one dlg only; break loop here break; } } } // check valid GUI; might be destroyed by mouse input if (!IsGUIValid()) return false; } // check if MouseOver has changed if (Mouse.pPrevMouseOverElement != Mouse.pMouseOverElement) { // send events if (Mouse.pPrevMouseOverElement) Mouse.pPrevMouseOverElement->MouseLeave(Mouse); if (Mouse.pMouseOverElement) Mouse.pMouseOverElement->MouseEnter(Mouse); } // return whether anything processed it return fProcessed || Mouse.pDragElement || (Mouse.pMouseOverElement && Mouse.pMouseOverElement!=this) || pContext; }