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 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
6 // Copyright (C) 2013 Laszlo KIS-ADAM (dfighter) <dfighter1985@gmail.com>
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/>.
25 #include "nel/misc/smart_ptr.h"
26 #include "nel/misc/array_2d.h"
28 #include "nel/gui/interface_element.h"
29 #include "game_share/scenario_entry_points.h"
32 class CInterfaceManager
;
36 class CEventDescriptor
;
38 class CGroupContainer
;
50 class CDynamicMapClient
;
56 extern const uint32 DEFAULT_ENTITY_MIN_OPACITY
;
59 struct IDisplayerUIHandle
;
62 class CDynamicMapClient
;
64 /** Base class for manipulation tools found in the R2 editor
65 * There's only one tool at a moment and mouse/keyboard events are routed to that tool
67 * \author Nicolas Vizerie
68 * \author Nevrax France
71 class CTool
: public CReflectableRefPtrTarget
, public NLMISC::IClassable
77 NLMISC::CVector Origin
;
79 NLMISC::CVector Right
;
86 Origin
= NLMISC::CVector::Null
;
87 Dir
= NLMISC::CVector::Null
;
88 Right
= NLMISC::CVector::Null
;
89 Up
= NLMISC::CVector::Null
;
95 //\TODO nico find a better place for this
96 enum TRayIntersectionType
{ NoIntersection
, ValidPacsPos
, InvalidPacsPos
};
98 typedef NLMISC::CSmartPtr
<CTool
> TSmartPtr
;
103 // Init parameters from script
104 virtual bool init(const CLuaObject
&/* parameters */) { return true; }
105 /** Get this tool name in the ui. This name is used to identify the tool in the ui (used by the r2.ToolUI:setActiveToolUIByName function defined in r2ed_ui.lua)
106 * May return "" if there's no ui associated with that tool
108 virtual const char *getToolUIName() const = 0;
109 virtual bool isCreationTool() const = 0;
110 virtual bool isPickTool() const {return false; }
113 // This update is called at each frame for the current tool just before rendering
114 virtual void updateBeforeRender() {}
115 // This update is called at each frame for the current tool just after rendering
116 virtual void updateAfterRender() = 0;
118 //////////////////////////
119 // EVENTS HANDLING //
120 //////////////////////////
122 /** Entry point for events handling.
123 * Methods where defined below for convenience for the most common events
124 * like 'onMouseLeftButtonDown' or 'onMouseRightButtonUp'.
125 * Default behaviour of this member function is to forward the event to these event handling methods.
127 * A deriver may handle events not listed below by redefining this method,
128 * possibly calling its parent version for events he is not interested in.
130 * \return true if the event has been handled by the tool
132 virtual bool handleEvent (const NLGUI::CEventDescriptor
&eventDesc
);
134 virtual void onFocusGained() {} // the app window gained the focus (there's no 'focus lost' event here because it reset current tool, so 'CTooll::cancel' will be called instead)
135 // IMPORTANT : Reacting to this should be unnecessary, as lost focus reset the current tool,
136 // defaulting to the 'SelectMove' tool, that handle this event correctly.
137 virtual bool onMouseLeftButtonDown() { return false; }
138 virtual bool onMouseLeftButtonUp() { releaseMouse(); return false; }
139 virtual bool onMouseRightButtonDown() { return false; }
140 virtual bool onMouseRightButtonUp() { return false; }
141 virtual bool onMouseMove() { return false; }
143 // call when this tool is just being activated
144 virtual void onActivate() {}
145 // special messages for shortcut keys
146 virtual bool onDeleteCmd() { return false; }
148 * Unlike the other onMousexxx method, these are actually called AFTER the camera event handling
149 * has been done. Doing the same in onMouseRightButtonUp or onMouseRightButtonDown
150 * instead would require that the user test if mouse button was not released after a camera
151 * move (in which case the click should not be handled of course)
153 * Usually the onMousexxxButtonUp are ususeful when working in pair with the associated 'mouse button down' event.
154 * Such events usually provoke a mouse capture (example : selectMoveTool)
156 virtual bool onMouseLeftButtonClicked() { return false; }
157 /** NB : if the onMouseRightButtonClicked isn't handled by the tool then
158 * editor will show the context menu
160 virtual bool onMouseRightButtonClicked();
161 // Called by editor just before a new tool is made current
162 virtual void cancel() = 0;
165 // when returning true -> ignore next click causing unselect
166 virtual bool getPreviousToolClickEndFlag(bool /* clear */ = true) { return false; }
169 // double click handling :
170 // 'startDoubleClickCheck' should be called when the 'onMouseLeftButtonClicked' msg is handled
171 // then checkDoubleClick' should be call on any subsequent onMouseLeftButtonDown. If
172 // the result is true then double click should be handled
173 void startDoubleClickCheck();
174 bool checkDoubleClick();
176 // test if one of the 'shift' keys is down
177 static bool isShiftDown();
179 // test if one of the 'ctrl' keys is down
180 static bool isCtrlDown();
182 //////////////////////
183 // HELPER FUNCTIONS //
184 //////////////////////
186 /** check which instance is under the mouse, possibly fading player in / out
187 * \param miniMapHandle if not NULL, pointer will be filled with the minimap ui element that is under the mouse
188 * \return NULL if there's no instance under the mouse
190 static CInstance
*checkInstanceUnderMouse(IDisplayerUIHandle
**miniMapHandle
= NULL
);
192 // helper : handle mouse over instance: highlight them when mouse is over & change mouse cursor accordingly
193 static void handleMouseOverInstance(const char *cursorDefault
,
194 const char *cursorOverUnselectedInstance
,
195 const char *cursorOverSelectedInstance
);
197 // handle player under cursor (fade in / fade out)
198 static void handleMouseOverPlayer(bool over
);
200 /** Default right button down handling :
201 * If an entity is highlighted,
202 * then select it and pop its menu
203 * \return true if the event was handled
205 bool defaultRightButtonDownHandling();
207 /** Capture the mouse
208 * - The ui won't receive events from the mouse
209 * - Maintaining the left button down doesn't trigger camera rotation any more.
210 * Useful for tools such as 'select', 'move' ...
212 static void captureMouse();
213 static void releaseMouse();
214 static bool isMouseCaptured();
216 // shortcut to get the ui
217 static CInterfaceManager
&getUI();
218 // Get mouse position
219 static void getMousePos(sint32
&x
, sint32
&y
) ;
220 // Get if mouse are clicked down and position of last down click
221 static void getMouseDown(bool &down
, sint32
&x
, sint32
&y
);
222 // Get if mouse are middle clicked down and position of last down click
223 static void getMouseMiddleDown(bool &down
, sint32
&x
, sint32
&y
);
224 // Get if mouse are right clicked down and position of last down click
225 static void getMouseRightDown(bool &down
, sint32
&x
, sint32
&y
);
226 // Get mouse x position
227 static sint32
getMouseX();
228 // Get mouse y position
229 static sint32
getMouseY();
230 // Set the current mouse cursor
231 static void setMouseCursor(const std::string
&cursorTexture
);
232 /** Compute a view vector (with its direction z set to 1) from coordinate of the mouse on screen
233 * If the mouse is on the island map, then a vector looking down from heights will be returned
235 static void computeWorldViewRay(sint32 posX
, sint32 posY
, CWorldViewRay
&dest
);
236 // specific test for the world map
237 static TRayIntersectionType
computeWorldMapIntersection(float x
, float y
, NLMISC::CVector
&inter
);
239 // get current screen size
240 static void getScreenSize(uint32
&scrW
, uint32
&scrH
);
241 // get current screen width
242 static uint32
getScreenWidth();
243 // get current screen height
244 static uint32
getScreenHeight();
245 // see if a point is in screen
246 static bool isInScreen(sint32 x
, sint32 y
);
247 // test whether the mouse is over the user interface
248 static bool isMouseOnUI();
249 // retriever ptr on world map in the ui
250 static CGroupMap
*getWorldMap();
251 // test whether the mouse is over the map
252 static CGroupMap
*isMouseOnWorldMap();
253 // test whether the mouse is over a container
254 static CGroupContainer
*isMouseOnContainer();
255 /** Compute collision of a segment with the landscape
256 * \param inter If return type is different from 'NoIntersection', then 'inter' is filled with the collision position
258 static TRayIntersectionType
computeLandscapeRayIntersection(const CWorldViewRay
&worldViewRay
, NLMISC::CVector
&inter
);
259 // Get pacs type at the given position, with the given threshold.
260 static TRayIntersectionType
getPacsType(const NLMISC::CVector
&pos
, float threshold
, NLPACS::UGlobalPosition
&destPos
);
262 // set context help for the current tool
263 static void setContextHelp(const ucstring
&contextHelp
);
265 // shortcut to get the interface to the server
266 CDynamicMapClient
&getDMC();
268 /** handle world map auto-panning feature, should be called whenever auto-pan should be done
269 * dx & dy are filled with delta of the map for this frame
271 void handleWorldMapAutoPan(sint32
&dx
, sint32
&dy
);
274 int luaIsPickTool(CLuaState
&ls
);
276 REFLECT_EXPORT_START(R2::CTool
, CReflectable
)
277 REFLECT_LUA_METHOD("isPickTool", luaIsPickTool
);
280 static NLMISC::CRGBA
getInvalidPosColor();
282 /** For derivers : additionnal checking can be done on the pos to choose
283 * Pos must at least be a valid pacs pos
284 * Default will check with a radius of 0.5 meter
286 static bool isValid2DPos(const NLMISC::CVector2f
&pos
);
289 sint64 _DoubleClickStartTime
;
290 sint32 _DoubleClickX
;
291 sint32 _DoubleClickY
;
292 uint64 _AutoPanLastHandlingFrame
;
293 sint64 _AutoPanDelay
;
295 static bool _MouseCaptured
;
296 static NLMISC::CRefPtr
<NLMISC::CCDBNodeLeaf
> _UserCharFade
;
298 /** compute the nearest valid surface at a given position from the island heightmap
299 * (heightmap must not be empty or an assertion is raised)
300 * \return true if a valid surface was found
302 static bool computeNearestValidSurfaceFromHeightMap(float x
, float y
, NLMISC::CVector
&inter
);
303 // trace a ray though the scene, using precise camera collision first, island packed collisions then.
304 static bool raytrace(const NLMISC::CVector
&segmentStart
, const NLMISC::CVector
&dir
, NLMISC::CVector
&inter
);
305 static bool isIslandValidPos(const NLMISC::CArray2D
<sint16
> &heightMap
, const CScenarioEntryPoints::CCompleteIsland
&islandDesc
, float x
, float y
);