1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
6 // Copyright (C) 2020 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as
10 // published by the Free Software Foundation, either version 3 of the
11 // License, or (at your option) any later version.
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/gui/view_pointer.h"
24 #include "nel/gui/widget_manager.h"
25 #include "nel/gui/view_renderer.h"
26 #include "nel/gui/group_paragraph.h"
27 #include "nel/gui/group_container.h"
28 #include "nel/misc/xml_auto_ptr.h"
29 #include "nel/misc/algo.h"
32 using namespace NLMISC
;
38 NLMISC_REGISTER_OBJECT(CViewBase
, CViewPointer
, std::string
, "generic_pointer");
43 bool CViewPointer::hwMouse
= true;
45 // --------------------------------------------------------------------------------------------------------------------
46 CViewPointer::CViewPointer (const TCtorParam
¶m
)
47 : CViewPointerBase(param
)
66 // The pointer must be draw over ALL layers
67 _RenderLayer
= VR_LAYER_MAX
;
68 _Color
= CRGBA(255,255,255,255);
69 _LastHightLight
= NULL
;
71 _ForceStringMode
= false;
73 _StringCursorHardware
= NULL
;
76 void CViewPointer::forceLink()
81 // +++ VIEW SPECIFIC +++
83 // --------------------------------------------------------------------------------------------------------------------
84 bool CViewPointer::parse (xmlNodePtr cur
,CInterfaceGroup
* parentGroup
)
88 if (! CViewBase::parse(cur
, parentGroup
) )
94 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_default");
95 if (prop
) _TxDefault
= NLMISC::toLowerAscii ((const char *) prop
);
97 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_move_window");
98 if (prop
) _TxMoveWindow
= NLMISC::toLowerAscii ((const char *) prop
);
100 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_resize_BR_TL");
101 if (prop
) _TxResizeBRTL
= NLMISC::toLowerAscii ((const char *) prop
);
103 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_resize_BL_TR");
104 if (prop
) _TxResizeBLTR
= NLMISC::toLowerAscii ((const char *) prop
);
106 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_resize_TB");
107 if (prop
) _TxResizeTB
= NLMISC::toLowerAscii ((const char *) prop
);
109 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_resize_LR");
110 if (prop
) _TxResizeLR
= NLMISC::toLowerAscii ((const char *) prop
);
112 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_rotate");
113 if (prop
) _TxRotate
= NLMISC::toLowerAscii ((const char *) prop
);
115 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_scale");
116 if (prop
) _TxScale
= NLMISC::toLowerAscii ((const char *) prop
);
118 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_colpick");
119 if (prop
) _TxColPick
= NLMISC::toLowerAscii ((const char *) prop
);
121 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_pan");
122 if (prop
) _TxPan
= NLMISC::toLowerAscii ((const char *) prop
);
124 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_can_pan");
125 if (prop
) _TxCanPan
= NLMISC::toLowerAscii ((const char *) prop
);
127 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_pan_r2");
128 if (prop
) _TxPanR2
= NLMISC::toLowerAscii ((const char *) prop
);
130 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"tx_can_pan_r2");
131 if (prop
) _TxCanPanR2
= NLMISC::toLowerAscii ((const char *) prop
);
133 prop
= (char*) xmlGetProp (cur
, (xmlChar
*)"color");
134 if (prop
) _Color
= convertColor(prop
);
139 // --------------------------------------------------------------------------------------------------------------------
140 class CCtrlDepthEntry
145 bool operator<(const CCtrlDepthEntry
&o
) const
147 // Inverse Test => descending order
148 return Depth
>o
.Depth
;
152 // --------------------------------------------------------------------------------------------------------------------
153 void CViewPointer::draw ()
155 // Do not display the pointer if not visible.
159 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
161 if ( CWidgetManager::getInstance()->isIngame() )
164 // Create the string cursor instance
165 std::vector
<std::pair
<std::string
,std::string
> > templateParams
;
166 templateParams
.push_back (std::pair
<std::string
,std::string
>("id", "string_cursor"));
168 _StringCursor
= CWidgetManager::getInstance()->getParser()->createGroupInstance("string_cursor", "", templateParams
);
170 _StringCursor
->setParentPos(CWidgetManager::getInstance()->getElementFromId("ui:interface"));
172 templateParams
.clear();
173 templateParams
.push_back (std::pair
<std::string
,std::string
>("id", "string_cursor_hardware"));
174 _StringCursorHardware
= CWidgetManager::getInstance()->getParser()->createGroupInstance("string_cursor_hardware", "", templateParams
);
175 if (_StringCursorHardware
)
176 _StringCursorHardware
->setParentPos(CWidgetManager::getInstance()->getElementFromId("ui:interface"));
180 if(getModulateGlobalColor())
181 col
.modulateFromColor (_Color
, CWidgetManager::getInstance()->getGlobalColor());
185 //col.A = (uint8)(((sint32)col.A*((sint32)pIM->getGlobalColor().A+1))>>8);
188 if (_LastHightLight
!= NULL
)
190 _LastHightLight
->setHighLighted(false,0);
191 _LastHightLight
= NULL
;
194 if ( CWidgetManager::getInstance()->getCapturePointerLeft() != NULL
&& CWidgetManager::getInstance()->isMouseHandlingEnabled())
196 CCtrlMover
*pCM
= dynamic_cast<CCtrlMover
*>( CWidgetManager::getInstance()->getCapturePointerLeft());
197 if ((pCM
!= NULL
) && (pCM
->canMove() == true))
199 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(pCM
->getParent());
200 if (pGC
!= NULL
&& !pGC
->isLocked())
202 pGC
->setHighLighted(true, 255);
203 _LastHightLight
= pGC
;
208 if (_TxIdDefault
== -2)
210 _TxIdDefault
= rVR
.getTextureIdFromName(_TxDefault
);
212 if (_TxIdMoveWindow
== -2)
214 _TxIdMoveWindow
= rVR
.getTextureIdFromName (_TxMoveWindow
);
215 _TxIdResizeBRTL
= rVR
.getTextureIdFromName (_TxResizeBRTL
);
216 _TxIdResizeBLTR
= rVR
.getTextureIdFromName (_TxResizeBLTR
);
217 _TxIdResizeTB
= rVR
.getTextureIdFromName (_TxResizeTB
);
218 _TxIdResizeLR
= rVR
.getTextureIdFromName (_TxResizeLR
);
219 _TxIdRotate
= rVR
.getTextureIdFromName (_TxRotate
);
220 _TxIdScale
= rVR
.getTextureIdFromName (_TxScale
);
221 _TxIdColPick
= rVR
.getTextureIdFromName (_TxColPick
);
222 _TxIdPan
= rVR
.getTextureIdFromName (_TxPan
);
223 _TxIdCanPan
= rVR
.getTextureIdFromName (_TxCanPan
);
224 _TxIdPanR2
= rVR
.getTextureIdFromName (_TxPanR2
);
225 _TxIdCanPanR2
= rVR
.getTextureIdFromName (_TxCanPanR2
);
229 const vector
<CCtrlBase
*> &rICL
= CWidgetManager::getInstance()->getCtrlsUnderPointer ();
232 // Draw the captured cursor
233 CCtrlBase
*pCB
= CWidgetManager::getInstance()->getCapturePointerLeft();
236 if (drawResizer(pCB
,col
)) return;
237 if (drawColorPicker(pCB
,col
)) return;
238 if (drawRotate(pCB
,col
)) return;
239 if (drawPan(pCB
,col
)) return;
240 if (drawCustom(pCB
)) return;
241 drawCursor(_TxIdDefault
, col
, 0);
245 const vector
<CViewBase
*> &vUP
= CWidgetManager::getInstance()->getViewsUnderPointer ();
247 for(uint i
=0;i
<vUP
.size();i
++)
249 CViewLink
*vLink
= dynamic_cast<CViewLink
*>(vUP
[i
]);
255 if (vLink
->getMouseOverShape(tooltip
, rot
, col
))
258 sint32 texId
= rVR
.getTextureIdFromName ("curs_pick.tga");
260 CInterfaceGroup
*stringCursor
= hwMouse
? _StringCursorHardware
: _StringCursor
;
263 stringCursor
->setX(_PointerX
);
264 stringCursor
->setY(_PointerY
);
265 stringCursor
->updateCoords();
266 stringCursor
->draw();
267 // if in hardware mode, force to draw the default cursor no matter what..
269 drawCursor(texId
, col
, 0);
273 drawCursor(texId
, col
, 0);
280 // Draw if capture right
281 pCB
= CWidgetManager::getInstance()->getCapturePointerRight();
284 // Is it a 3d scene ?
285 if (drawScale(pCB
,col
)) return;
286 drawCursor(_TxIdDefault
, col
, 0);
290 bool overModalWindow
= false;
293 // is the cursor currently over a modal window ?
294 CInterfaceGroup
*currModal
= CWidgetManager::getInstance()->getModalWindow();
297 sint32 xPos
= _XReal
+ _OffsetX
;
298 sint32 yPos
= _YReal
+ _OffsetY
;
299 overModalWindow
= currModal
->isIn(xPos
, yPos
, _WReal
, _HReal
);
302 // Draw the cursor type that are under the pointer
303 if (CWidgetManager::getInstance()->isMouseHandlingEnabled())
305 // Sorts the controls according to their depth, to approximate as best the CapturePointerLeft algo.
306 // Especially important so that Resizers controls get the precedence over the move control (else could randomly bug like in chat group)
307 static vector
<CCtrlDepthEntry
> sortedControls
;
308 sortedControls
.clear();
309 for(uint i
=0;i
<rICL
.size();i
++)
313 // NB: not the exact CInterfaceManager getDepth test here, but should work fine
314 cde
.Depth
= cde
.Ctrl
->getParentDepth() + cde
.Ctrl
->getDeltaDepth();
315 sortedControls
.push_back(cde
);
317 std::sort(sortedControls
.begin(), sortedControls
.end());
319 // Then draw the correct cursor
320 for (uint32 i
= 0; i
< sortedControls
.size(); ++i
)
322 CCtrlBase
*pCB
= sortedControls
[i
].Ctrl
;
326 if (!pCB
->isSonOf(currModal
)) continue;
329 if (drawBrowse(pCB
, col
)) return;
330 if (drawResizer(pCB
,col
)) return;
331 if (drawColorPicker(pCB
,col
)) return;
332 if (drawLink (pCB
, col
)) return;
333 if (drawCustom(pCB
)) return;
335 // test for move highlight
336 if (_LastHightLight
== NULL
)
338 CCtrlMover
*pCM
= dynamic_cast<CCtrlMover
*>(pCB
);
339 if ( (pCM
!= NULL
) && (pCM
->canMove() == true) )
341 CGroupContainer
*pGC
= dynamic_cast<CGroupContainer
*>(pCM
->getParent());
342 if (pGC
!= NULL
&& !pGC
->isLocked())
344 if (CWidgetManager::getInstance()->getCapturePointerLeft() != pCM
)
345 pGC
->setHighLighted(true, 128);
347 pGC
->setHighLighted(true, 255);
348 _LastHightLight
= pGC
;
356 if (CWidgetManager::getInstance()->isMouseHandlingEnabled())
360 const vector
<CInterfaceGroup
*> &rIGL
= CWidgetManager::getInstance()->getGroupsUnderPointer ();
361 for (uint32 i
= 0; i
< rIGL
.size(); ++i
)
363 CInterfaceGroup
*pG
= rIGL
[i
];
366 if (!pG
->isSonOf(currModal
)) continue;
368 if (drawPan (pG
, col
)) return;
369 if (drawBrowse(pG
, col
)) return;
374 if (_StringMode
&& CWidgetManager::getInstance()->isMouseHandlingEnabled())
376 CInterfaceGroup
*stringCursor
= hwMouse
? _StringCursorHardware
: _StringCursor
;
379 stringCursor
->setX(_PointerX
);
380 stringCursor
->setY(_PointerY
);
381 stringCursor
->updateCoords();
382 stringCursor
->draw();
383 // if in hardware mode, force to draw the default cursor no matter what..
386 drawCursor(_TxIdDefault
, col
, 0);
392 // Draw the default cursor
393 drawCursor(_TxIdDefault
, col
, 0);
397 // --------------------------------------------------------------------------------------------------------------------
398 bool CViewPointer::drawCustom(CCtrlBase
* pCB
)
403 if (pCB
->getMouseOverShape(texName
, rot
, col
))
405 if (texName
[0] == '@')
407 const string
&tooltipInfos
= texName
.substr(1);
409 vector
<string
> tooltipInfosList
;
410 splitString(tooltipInfos
, "@", tooltipInfosList
);
411 texName
= tooltipInfosList
[0];
412 tooltip
= tooltipInfosList
[1];
414 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
415 sint32 texId
= rVR
.getTextureIdFromName (texName
);
417 CInterfaceGroup
*stringCursor
= hwMouse
? _StringCursorHardware
: _StringCursor
;
420 stringCursor
->setX(_PointerX
);
421 stringCursor
->setY(_PointerY
);
422 stringCursor
->updateCoords();
423 stringCursor
->draw();
424 // if in hardware mode, force to draw the default cursor no matter what..
426 drawCursor(texId
, col
, 0);
430 drawCursor(texId
, col
, 0);
436 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
437 sint32 texId
= rVR
.getTextureIdFromName (texName
);
438 drawCursor(texId
, col
, 0);
449 // --------------------------------------------------------------------------------------------------------------------
450 void CViewPointer::setStringMode (bool stringCursor
)
452 _StringMode
= stringCursor
;
455 // --------------------------------------------------------------------------------------------------------------------
456 void CViewPointer::setString(const std::string
&str
, CInterfaceGroup
*target
)
460 CInterfaceElement
*element
= target
->getView ("fake_txt");
463 CViewText
*text
= dynamic_cast<CViewText
*> (element
);
467 element
= target
->getView ("real_txt");
470 CViewText
*text
= dynamic_cast<CViewText
*> (element
);
474 target
->updateCoords();
475 target
->updateCoords();
476 _ContextString
= str
;
481 // --------------------------------------------------------------------------------------------------------------------
482 void CViewPointer::setString (const std::string
&str
)
484 if (_ContextString
!= str
)
486 setString(str
, _StringCursor
);
487 setString(str
, _StringCursorHardware
);
491 // --------------------------------------------------------------------------------------------------------------------
492 void CViewPointer::drawCursor(sint32 texId
, NLMISC::CRGBA col
, uint8 rot
)
494 CViewRenderer
&rVR
= *CViewRenderer::getInstance();
495 sint32 xPos
= _XReal
+ _OffsetX
;
496 sint32 yPos
= _YReal
+ _OffsetY
;
499 rVR
.draw11RotFlipBitmap (_RenderLayer
, xPos
, yPos
, rot
, false, texId
, col
);
503 // set new cursor for the hardware mouse
504 std::string name
= rVR
.getTextureNameFromId(texId
);
505 rVR
.getDriver()->setCursor(name
, col
, rot
, (uint32
) std::max(getX() - xPos
, (sint32
) 0), (uint32
) std::max(getY() - yPos
, (sint32
) 0));