// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/> // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. #include "stdpch.h" #include "../input.h" // #include "view_pointer.h" #include "interface_manager.h" #include "view_renderer.h" #include "ctrl_col_pick.h" #include "group_paragraph.h" #include "group_html.h" #include "group_map.h" // #include "nel/misc/xml_auto_ptr.h" // #include "group_container.h" #include "interface_3d_scene.h" // #include "../r2/editor.h" using namespace std; using namespace NLMISC; NLMISC_REGISTER_OBJECT(CViewBase, CViewPointer, std::string, "pointer"); // -------------------------------------------------------------------------------------------------------------------- CViewPointer::CViewPointer (const TCtorParam ¶m) : CViewBase(param), _Buttons(NLMISC::noButton) { _PointerX = _PointerY = _PointerOldX = _PointerOldY = _PointerDownX = _PointerDownY = 0; _PointerDown = false; _PointerVisible = true; _TxIdDefault = -2; _TxIdMoveWindow = -2; _TxIdResizeBRTL = -2; _TxIdResizeBLTR = -2; _TxIdResizeTB = -2; _TxIdResizeLR = -2; _TxIdRotate = -2; _TxIdScale = -2; _TxIdColPick = -2; _TxIdPan = -2; _TxIdCanPan = -2; _TxIdPanR2 = -2; _TxIdCanPanR2 = -2; // The pointer must be draw over ALL layers _RenderLayer= VR_LAYER_MAX; _Color = CRGBA(255,255,255,255); _LastHightLight = NULL; _StringMode = false; _ForceStringMode = false; _StringCursor = NULL; } // +++ VIEW SPECIFIC +++ // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::parse (xmlNodePtr cur,CInterfaceGroup * parentGroup) { CXMLAutoPtr prop; if (! CViewBase::parse(cur, parentGroup) ) return false; _OffsetX = getX(); _OffsetY = getY(); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_default"); if (prop) _TxDefault = (const char *) prop; _TxDefault = NLMISC::strlwr (_TxDefault); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_move_window"); if (prop) _TxMoveWindow = (const char *) prop; _TxMoveWindow = NLMISC::strlwr (_TxMoveWindow); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_resize_BR_TL"); if (prop) _TxResizeBRTL = (const char *) prop; _TxResizeBRTL = NLMISC::strlwr (_TxResizeBRTL); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_resize_BL_TR"); if (prop) _TxResizeBLTR = (const char *) prop; _TxResizeBLTR = NLMISC::strlwr (_TxResizeBLTR); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_resize_TB"); if (prop) _TxResizeTB = (const char *) prop; _TxResizeTB = NLMISC::strlwr (_TxResizeTB); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_resize_LR"); if (prop) _TxResizeLR = (const char *) prop; _TxResizeLR = NLMISC::strlwr (_TxResizeLR); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_rotate"); if (prop) _TxRotate = (const char *) prop; _TxRotate = NLMISC::strlwr (_TxRotate); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_scale"); if (prop) _TxScale = (const char *) prop; _TxScale = NLMISC::strlwr (_TxScale); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_colpick"); if (prop) _TxColPick = (const char *) prop; _TxColPick = NLMISC::strlwr (_TxColPick); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_pan"); if (prop) _TxPan = (const char *) prop; _TxPan = NLMISC::strlwr (_TxPan); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_can_pan"); if (prop) _TxCanPan = (const char *) prop; _TxCanPan = NLMISC::strlwr (_TxCanPan); if (ClientCfg.R2EDEnabled) { prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_pan_r2"); if (prop) _TxPanR2 = (const char *) prop; _TxPanR2 = NLMISC::strlwr (_TxPanR2); prop = (char*) xmlGetProp (cur, (xmlChar*)"tx_can_pan_r2"); if (prop) _TxCanPanR2 = (const char *) prop; _TxCanPanR2 = NLMISC::strlwr (_TxCanPanR2); } prop = (char*) xmlGetProp (cur, (xmlChar*)"color"); if (prop) _Color = convertColor(prop); return true; } // -------------------------------------------------------------------------------------------------------------------- class CCtrlDepthEntry { public: CCtrlBase *Ctrl; uint Depth; bool operator<(const CCtrlDepthEntry &o) const { // Inverse Test => descending order return Depth>o.Depth; } }; // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::draw () { // Do not display the pointer if not visible. if(!_PointerVisible) return; CInterfaceManager *pIM = CInterfaceManager::getInstance(); CViewRenderer &rVR = pIM->getViewRenderer(); if (pIM->isInGame()) if (!_StringCursor) { // Create the string cursor instance std::vector<std::pair<std::string,std::string> > templateParams; templateParams.push_back (std::pair<std::string,std::string>("id", "string_cursor")); _StringCursor = pIM->createGroupInstance("string_cursor", "", templateParams); if (_StringCursor) _StringCursor->setParentPos(pIM->getElementFromId("ui:interface")); templateParams.clear(); templateParams.push_back (std::pair<std::string,std::string>("id", "string_cursor_hardware")); _StringCursorHardware = pIM->createGroupInstance("string_cursor_hardware", "", templateParams); if (_StringCursorHardware) _StringCursorHardware->setParentPos(pIM->getElementFromId("ui:interface")); } CRGBA col; if(getModulateGlobalColor()) col.modulateFromColor (_Color, pIM->getGlobalColor()); else col= _Color; //col.A = (uint8)(((sint32)col.A*((sint32)pIM->getGlobalColor().A+1))>>8); col.A = _Color.A; if (_LastHightLight != NULL) { _LastHightLight->setHighLighted(false,0); _LastHightLight = NULL; } if (pIM->getCapturePointerLeft() != NULL && pIM->isMouseHandlingEnabled()) { CCtrlMover *pCM = dynamic_cast<CCtrlMover*>(pIM->getCapturePointerLeft()); if ((pCM != NULL) && (pCM->canMove() == true)) { CGroupContainer *pGC = dynamic_cast<CGroupContainer *>(pCM->getParent()); if (pGC != NULL && !pGC->isLocked()) { pGC->setHighLighted(true, 255); _LastHightLight = pGC; } } } if (_TxIdDefault == -2) { _TxIdDefault = rVR.getTextureIdFromName (_TxDefault); _TxIdMoveWindow = rVR.getTextureIdFromName (_TxMoveWindow); _TxIdResizeBRTL = rVR.getTextureIdFromName (_TxResizeBRTL); _TxIdResizeBLTR = rVR.getTextureIdFromName (_TxResizeBLTR); _TxIdResizeTB = rVR.getTextureIdFromName (_TxResizeTB); _TxIdResizeLR = rVR.getTextureIdFromName (_TxResizeLR); _TxIdRotate = rVR.getTextureIdFromName (_TxRotate); _TxIdScale = rVR.getTextureIdFromName (_TxScale); _TxIdColPick = rVR.getTextureIdFromName (_TxColPick); _TxIdPan = rVR.getTextureIdFromName (_TxPan); _TxIdCanPan = rVR.getTextureIdFromName (_TxCanPan); if (ClientCfg.R2EDEnabled) { _TxIdPanR2 = rVR.getTextureIdFromName (_TxPanR2); _TxIdCanPanR2 = rVR.getTextureIdFromName (_TxCanPanR2); } } const vector<CCtrlBase *> &rICL = pIM->getCtrlsUnderPointer (); // Draw the captured cursor CCtrlBase *pCB = pIM->getCapturePointerLeft(); if (pCB != NULL) { if (drawResizer(pCB,col)) return; //if (drawMover(pCB,col)) return; if (drawColorPicker(pCB,col)) return; if (drawRotate(pCB,col)) return; if (drawPan(pCB,col)) return; if (drawCustom(pCB)) return; drawCursor(_TxIdDefault, col, 0); return; } const vector<CViewBase *> &vUP = pIM->getViewsUnderPointer (); for(uint i=0;i<vUP.size();i++) { CViewLink *vLink = dynamic_cast<CViewLink*>(vUP[i]); if (vLink != NULL) { string tooltip; uint8 rot; if (vLink->getMouseOverShape(tooltip, rot, col)) { setString(ucstring(tooltip)); sint32 texId = rVR.getTextureIdFromName ("curs_pick.tga"); CInterfaceGroup *stringCursor = IsMouseCursorHardware() ? _StringCursorHardware : _StringCursor; if (stringCursor) { stringCursor->setX(_PointerX); stringCursor->setY(_PointerY); stringCursor->updateCoords(); stringCursor->draw(); // if in hardware mode, force to draw the default cursor no matter what.. if (IsMouseCursorHardware()) drawCursor(texId, col, 0); } else { drawCursor(texId, col, 0); } return; } } } // Draw if capture right pCB = pIM->getCapturePointerRight(); if (pCB != NULL) { // Is it a 3d scene ? if (drawScale(pCB,col)) return; drawCursor(_TxIdDefault, col, 0); return; } bool overModalWindow = false; // is the cursor currently over a modal window ? CInterfaceGroup *currModal = pIM->getModalWindow(); if (currModal) { sint32 xPos = _XReal + _OffsetX; sint32 yPos = _YReal + _OffsetY; overModalWindow = currModal->isIn(xPos, yPos, _WReal, _HReal); } // Draw the cursor type that are under the pointer if (pIM->isMouseHandlingEnabled()) { // Sorts the controls according to their depth, to approximate as best the CapturePointerLeft algo. // Especially important so that Resizers controls get the precedence over the move control (else could randomly bug like in chat group) static vector<CCtrlDepthEntry> sortedControls; sortedControls.clear(); for(uint i=0;i<rICL.size();i++) { CCtrlDepthEntry cde; cde.Ctrl= rICL[i]; // NB: not the exact CInterfaceManager getDepth test here, but should work fine cde.Depth= cde.Ctrl->getParentDepth() + cde.Ctrl->getDeltaDepth(); sortedControls.push_back(cde); } std::sort(sortedControls.begin(), sortedControls.end()); // Then draw the correct cursor for (uint32 i = 0; i < sortedControls.size(); ++i) { CCtrlBase *pCB = sortedControls[i].Ctrl; if (overModalWindow) { if (!pCB->isSonOf(currModal)) continue; } if (drawBrowse(pCB, col)) return; if (drawResizer(pCB,col)) return; if (drawColorPicker(pCB,col)) return; if (drawLink (pCB, col)) return; if (drawCustom(pCB)) return; // test for move highlight if (_LastHightLight == NULL) { CCtrlMover *pCM = dynamic_cast<CCtrlMover*>(pCB); if ( (pCM != NULL) && (pCM->canMove() == true) ) { CGroupContainer *pGC = dynamic_cast<CGroupContainer *>(pCM->getParent()); if (pGC != NULL && !pGC->isLocked()) { if (pIM->getCapturePointerLeft() != pCM) pGC->setHighLighted(true, 128); else pGC->setHighLighted(true, 255); _LastHightLight = pGC; break; } } } //if (drawMover(pCB,col)) return; } } if (pIM->isMouseHandlingEnabled()) { if (rICL.empty()) { const vector<CInterfaceGroup *> &rIGL = pIM->getGroupsUnderPointer (); for (uint32 i = 0; i < rIGL.size(); ++i) { CInterfaceGroup *pG = rIGL[i]; if (overModalWindow) { if (!pG->isSonOf(currModal)) continue; } if (drawPan (pG, col)) return; if (drawBrowse(pG, col)) return; } } } if (_StringMode && pIM->isMouseHandlingEnabled()) { CInterfaceGroup *stringCursor = IsMouseCursorHardware() ? _StringCursorHardware : _StringCursor; if (stringCursor) { stringCursor->setX(_PointerX); stringCursor->setY(_PointerY); stringCursor->updateCoords(); stringCursor->draw(); // if in hardware mode, force to draw the default cursor no matter what.. if (IsMouseCursorHardware()) { drawCursor(_TxIdDefault, col, 0); } } } else { // Draw the default cursor drawCursor(_TxIdDefault, col, 0); } } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawResizer(CCtrlBase* pCB, CRGBA col) { CCtrlResizer *pCR = dynamic_cast<CCtrlResizer*>(pCB); if (pCR != NULL) { CGroupContainer *parent = dynamic_cast<CGroupContainer *>(pCR->getParent()); if (parent && !parent->isLocked()) { sint32 texID= -1; switch(pCR->getRealResizerPos()) { case Hotspot_BR: case Hotspot_TL: texID = _TxIdResizeBRTL; break; case Hotspot_BL: case Hotspot_TR: texID = _TxIdResizeBLTR; break; case Hotspot_MR: case Hotspot_ML: texID = _TxIdResizeLR; break; case Hotspot_TM: case Hotspot_BM: texID = _TxIdResizeTB; break; default: return false; break; } drawCursor(texID, col, false); return true; } } return false; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawMover(CCtrlBase* pCB, CRGBA col) { CCtrlMover *pCM = dynamic_cast<CCtrlMover*>(pCB); if ((pCM != NULL) && (pCM->canMove() == true)) { drawCursor(_TxIdMoveWindow, col, 0); return true; } return false; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawRotate (CCtrlBase* pCB, CRGBA col) { CInterface3DScene *pI3DS = dynamic_cast<CInterface3DScene *>(pCB); if (pI3DS != NULL) { drawCursor(_TxIdRotate, col, 0); return true; } return false; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawScale (CCtrlBase* pCB, CRGBA col) { CInterface3DScene *pI3DS = dynamic_cast<CInterface3DScene *>(pCB); if (pI3DS != NULL) { drawCursor(_TxIdScale, col, 0); return true; } return false; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawColorPicker (CCtrlBase* pCB, CRGBA col) { CCtrlColPick *pCCP = dynamic_cast<CCtrlColPick*>(pCB); if (pCCP != NULL) { drawCursor(_TxIdColPick, col, 0); return true; } return false; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawLink (CCtrlBase* pCB, CRGBA col) { CCtrlLink *pCCP = dynamic_cast<CCtrlLink*>(pCB); if (pCCP != NULL) { drawCursor(_TxIdColPick, col, 0); return true; } return false; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawBrowse (CCtrlBase* pCB, CRGBA col) { CGroupHTML *pCGH = dynamic_cast<CGroupHTML *>(pCB); if (pCGH != NULL) { if (pCGH->isBrowsing()) { static uint8 rot =0; drawCursor(_TxIdRotate, col, rot>>3); rot = (rot+1) & 0x1f; return true; } } return false; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawPan(CCtrlBase* pCB, NLMISC::CRGBA col) { CGroupMap *gm = dynamic_cast<CGroupMap *>(pCB); if (gm) { sint32 texId; if (ClientCfg.R2EDEnabled && R2::getEditor().getCurrentTool()) { /** If cursor is set to anything other than the default cursor, use that cursor (because action can be performed on the map * by the current tool */ if (_TxDefault == "curs_default.tga") { texId = gm->isPanning() ? _TxIdPanR2 : _TxIdCanPanR2; } else return false; } else { texId = gm->isPanning() ? _TxIdPan : _TxIdCanPan; } drawCursor(texId, col, 0); return true; } return false; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::drawCustom(CCtrlBase* pCB) { string texName; uint8 rot; NLMISC::CRGBA col; if (pCB->getMouseOverShape(texName, rot, col)) { if (texName[0] == '@') { const string &tooltipInfos = texName.substr(1); string tooltip; vector<string> tooltipInfosList; splitString(tooltipInfos, "@", tooltipInfosList); texName = tooltipInfosList[0]; tooltip = tooltipInfosList[1]; nlinfo(tooltip.c_str()); setString(ucstring(tooltip)); CInterfaceManager *pIM = CInterfaceManager::getInstance(); CViewRenderer &rVR = pIM->getViewRenderer(); sint32 texId = rVR.getTextureIdFromName (texName); CInterfaceGroup *stringCursor = IsMouseCursorHardware() ? _StringCursorHardware : _StringCursor; if (stringCursor) { stringCursor->setX(_PointerX); stringCursor->setY(_PointerY); stringCursor->updateCoords(); stringCursor->draw(); // if in hardware mode, force to draw the default cursor no matter what.. if (IsMouseCursorHardware()) drawCursor(texId, col, 0); } else { drawCursor(texId, col, 0); } return true; } else { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CViewRenderer &rVR = pIM->getViewRenderer(); sint32 texId = rVR.getTextureIdFromName (texName); drawCursor(texId, col, 0); return true; } } return false; } // +++ SET +++ // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::setPointerPos (sint32 x, sint32 y) { if (_PointerDown) { if (!_PointerDrag) { if (((_PointerX - _PointerDownX) != 0) || ((_PointerY - _PointerDownY) != 0)) { _PointerDrag = true; } } } _PointerOldX = getX(); _PointerOldY = getY(); _PointerX = x; _PointerY = y; } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::setPointerDispPos (sint32 x, sint32 y) { setX (x); setY (y); updateCoords (); } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::resetPointerPos () { _PointerOldX = _PointerX; _PointerOldY = _PointerY; } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::setPointerDown (bool pd) { _PointerDown = pd; if (_PointerDown == true) { _PointerDownX = _PointerX; _PointerDownY = _PointerY; } if (_PointerDown == false) _PointerDrag = false; } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::setPointerDownString (const std::string &s) { _PointerDownString = s; } // +++ GET +++ // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::getPointerPos (sint32 &x, sint32 &y) { x = _PointerX; y = _PointerY; } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::getPointerDispPos (sint32 &x, sint32 &y) { x = getX(); y = getY(); } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::getPointerOldPos (sint32 &x, sint32 &y) { x = _PointerOldX; y = _PointerOldY; } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::getPointerDownPos (sint32 &x, sint32 &y) { x = _PointerDownX; y = _PointerDownY; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::getPointerDown () { return _PointerDown; } // -------------------------------------------------------------------------------------------------------------------- bool CViewPointer::getPointerDrag () { return _PointerDrag; } // -------------------------------------------------------------------------------------------------------------------- std::string CViewPointer::getPointerDownString () { return _PointerDownString; } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::setStringMode (bool stringCursor) { _StringMode = stringCursor; } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::setString (const ucstring &str, CInterfaceGroup *target) { if (target) { CInterfaceElement *element = target->getView ("fake_txt"); if (element) { CViewText *text = dynamic_cast<CViewText*> (element); if (text) text->setText(str); } element = target->getView ("real_txt"); if (element) { CViewText *text = dynamic_cast<CViewText*> (element); if (text) text->setText(str); } target->updateCoords(); target->updateCoords(); _ContextString = str; } } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::setString (const ucstring &str) { if (_ContextString != str) { setString(str, _StringCursor); setString(str, _StringCursorHardware); } } // -------------------------------------------------------------------------------------------------------------------- void CViewPointer::drawCursor(sint32 texId, NLMISC::CRGBA col, uint8 rot) { CInterfaceManager *pIM = CInterfaceManager::getInstance(); CViewRenderer &rVR = pIM->getViewRenderer(); sint32 xPos = _XReal + _OffsetX; sint32 yPos = _YReal + _OffsetY; if (!IsMouseCursorHardware()) { rVR.draw11RotFlipBitmap (_RenderLayer, xPos, yPos, rot, false, texId, col); } else { // set new cursor for the hardware mouse std::string name = rVR.getTextureNameFromId(texId); rVR.getDriver()->setCursor(name, col, rot, (uint32) std::max(getX() - xPos, (sint32) 0), (uint32) std::max(getY() - yPos, (sint32) 0)); } }