#ifndef MOUSEAPI_H #define MOUSEAPI_H #include "OrxonoxPrereqs.h" #include "util/OgreForwardRefs.h" #include "graphics/Camera.h" #include #include #include #include #include #include #include #include #include "CameraManager.h" #include #include "core/GUIManager.h" #include "core/input/KeyBinderManager.h" #include "tools/interfaces/Tickable.h" #include "core/singleton/ScopedSingletonIncludes.h" /* this class implements a basic mouse-api * supported are mouse-clicks (left, right, mousewheel, ...) and scrolling * * mouse-clicks always are asscociated with an ingame element that has a position and a sphere with a certain radius around it * if the cursor is inside this sphere and a button is pressed, a user-defined function will be called * * scrolling can either be global (independent of where the cursor is) or local (same as a mouse-click) * in both cases a user-defined function will be called * * in short the class works by storing every element that can be clicked / scrolled on in a list * everytime a button is clicked or the mousewheel is turned, the list gets traversed and every element checked if it is clicked / scrolled on * checking happens by casting a ray from the camera through the mouse-cursor and testing if it intersects the sphere of the element * * to make it work, one has to add mouseapi in LINK_LIBRARIES in the file CMakeLists.txt of the level * see CMakeLists.txt in MouseAPIExample */ namespace orxonox { typedef uint ClickableElementID; typedef uint ScrollableElementID; class MouseAPI : public InputHandler, public Singleton,public Tickable { friend class Singleton; private: // Elements that can be clicked on are stored as clickableElement struct clickableElement { ClickableElementID id; Vector3 position; float radius; std::list buttons; std::function onClickedFunction; clickableElement(ClickableElementID id,const Vector3& position,float radius,const std::list& buttons,std::function onClickedFunction):id(id),position(position), radius(radius), buttons(buttons), onClickedFunction(onClickedFunction){} }; /* Elements that can be "scrolled on" are stored as scrollElement * there are 2 diffrent types, hence the overloaded constructor: * 1) the function is called whenever one scrolls, independet from position of element and cursor * 2) the function is only called when the cursor is placed over the element (identical to the clickableElement) */ struct scrollElement { ScrollableElementID id; bool considerPosition; Vector3 position; float radius; std::function onScrolledFunction; // constructor for scrollElement type 1 scrollElement(ScrollableElementID id,std::function onScrolledFunction):id(id),considerPosition(false), onScrolledFunction(onScrolledFunction){} // constructor fro scrollElement type 2 scrollElement(ScrollableElementID id,const Vector3& position, float radius, std::function onScrolledFunction):id(id),considerPosition(true), position(position), radius(radius), onScrolledFunction(onScrolledFunction){} }; // pointer to our class (required by singleton) static MouseAPI* singletonPtr_s; // lists with all our Elements that can be clicked / scrolled on std::list clickEvents; std::list scrollEvents; // pointer to the game-camera Ogre::Camera *cam ; // pointer to our input-state InputState* state; // true => MouseAPI has been activated, false => MouseAPI has not been activated bool active = false; Ogre::PanelOverlayElement* cursor; public: MouseAPI(); ~MouseAPI(); virtual void tick(float dt) override; /* everytime a mousebutton is pressed, this function is called and checks if the cursor is over an element that can be clicked on * if yes, the function associated with this element will be called with the corresponding button as argument */ virtual void buttonPressed (MouseButtonCode::ByEnum button) override; // not used virtual void buttonReleased(MouseButtonCode::ByEnum button) override{} // not used virtual void buttonHeld (MouseButtonCode::ByEnum button) override{} // not used virtual void mouseMoved (IntVector2 abs, IntVector2 rel, IntVector2 clippingSize) override; /* everytime someone scrolls, this function is called and checks for all scrollElements, wheter a position is required and wheter the curser is over said position * if yes, the function associated with this element will be called * if there is an element without position-requirement and an element the cursor is over, both their functions will be called */ virtual void mouseScrolled (int abs, int rel) override; /* add a clickableElement to the list * see mouseapiexample for an example-implementation * Arguments: * position: the point that needs to be clicked * radius: radius of the sphere around the position; if the cursor is inside this radius, the function will be executed (because clicking on a single point is pretty hard) * buttons: the function will only be called, if one of these buttons is pressed * onClickedFunction: the function that will be called */ ClickableElementID addClickableElement(const Vector3& position,float radius,const std::list& buttons,std::function onClickedFunction); /* add a scrollElement to the list * see mouseapiexample for an example-implementation * Arguments: * position: the point the cursor needs to be over * radius: radius of the sphere around the position; if the cursor is inside this radius, the function will be executed * onScrolledFunction: the function that will be called */ ScrollableElementID addScrollElement(const Vector3& position,float radius,std::function onScrolledFunction); /* add a scrollElement to the list * Arguments: * onScrolledFunction: the function that will be called, no matter where the cursor is */ ScrollableElementID addScrollElement(std::function onScrolledFunction); /* change the position of a clickableElement * Arguments: * id: the ClickableElementID of the element * position: the new position of the element * Return: * true if successfull * false if not successfull */ bool changePositionOfClickableElement(ClickableElementID id,const Vector3& position); /* change the position of a scrollElement * Arguments: * id: the ScrollableElementID of the element * position: the new position of the element * Return: * true if successfull * false if not successfull */ bool changePositionOfScrollableElement(ScrollableElementID id,const Vector3& position); /* change the radius of a clickableElement * Arguments: * id: the ClickableElementID of the element * radius: the new radius of the element * Return: * true if successfull * false if not successfull */ bool changeRadiusOfClickableElement(ClickableElementID id,float radius); /* change the radius of a scrollElement * Arguments: * id: the ScrollableElementID of the element * radius: the new radius of the element * Return: * true if successfull * false if not successfull */ bool changeRadiusOfScrollableElement(ScrollableElementID id,float radius); /* remove a clickableElement * Arguments: * id: the ClickableElementID of the element * Return: * true if successfull * false if not successfull */ bool deleteClickableElement(ClickableElementID id); /* remove a scrollElement * Arguments: * id: the ScrollableElementID of the element * Return: * true if successfull * false if not successfull */ bool deleteScrollableElement(ScrollableElementID id); /* get the current radius of a clickableElement * Arguments: * id: the ClickableElementID of the element */ float getRadiusClick(ClickableElementID id); /* get the current radius of a scrollElement * Arguments: * id: the ScrollableElementID of the element */ float getRadiusScroll(ScrollableElementID id); /* get the current relative Position of the cursor * returns a value between 0 and 1 for both x and y component * (0,0) top left corner, (1,1) bottom right corner */ Vector2 getMousePosition(); /* activate the MouseAPI * has to be called after the level has been created (i.e. inside the xml-port * can be called multiple times, since the function checks the status of MouseAPI and does nothing if it already is active */ void activate(); // returns true if MouseAPI is active, false otherwise static bool isActive(){return singletonPtr_s != nullptr && getInstance().active;} /* deactivate the MouseAPI * has to be called, when the level gets closed (i.e. inside the level-destructor) * the function does nothing if MouseAPI is not active */ void deactivate(); }; } #endif // MOUSEAPI_H