Mouse Events
Last Updated: Oct 13th, 2024
Here we're going to make some buttons that respond to mouse input.class LButton { public: //Button dimensions static constexpr int kButtonWidth = 300; static constexpr int kButtonHeight = 200; //Initializes internal variables LButton(); //Sets top left position void setPosition( float x, float y ); //Handles mouse event void handleEvent( SDL_Event* e ); //Shows button sprite void render(); private: enum eButtonSprite { eButtonSpriteMouseOut = 0, eButtonSpriteMouseOverMotion = 1, eButtonSpriteMouseDown = 2, eButtonSpriteMouseUp = 3 }; //Top left position SDL_FPoint mPosition; //Currently used global sprite eButtonSprite mCurrentSprite; };
Here is our buttons class. It has constants for the dimensions, a constructor, a function to set its position, a function to handle events, and a function to render it.
Then we have an enumeration to define the different mouse states with their corresponding sprite, an SDL_FPoint to define the position of the button, and an
Then we have an enumeration to define the different mouse states with their corresponding sprite, an SDL_FPoint to define the position of the button, and an
eButtonSprite
to define the current sprite index.
//LButton Implementation LButton::LButton(): mPosition{ 0.f, 0.f }, mCurrentSprite{ eButtonSpriteMouseOut } { } void LButton::setPosition( float x, float y ) { mPosition.x = x; mPosition.y = y; }
Here are the functions used to initialize and position the button.
void LButton::handleEvent( SDL_Event* e ) { //If mouse event happened if( e->type == SDL_EVENT_MOUSE_MOTION || e->type == SDL_EVENT_MOUSE_BUTTON_DOWN || e->type == SDL_EVENT_MOUSE_BUTTON_UP ) { //Get mouse position float x = -1.f, y = -1.f; SDL_GetMouseState( &x, &y ); //Check if mouse is in button bool inside = true; //Mouse is left of the button if( x < mPosition.x ) { inside = false; } //Mouse is right of the button else if( x > mPosition.x + kButtonWidth ) { inside = false; } //Mouse above the button else if( y < mPosition.y ) { inside = false; } //Mouse below the button else if( y > mPosition.y + kButtonHeight ) { inside = false; }
Here is where we start handling mouse events.
First we check if it's a
If a mouse event happened, we then get the mouse position with SDL_GetMouseState. We then check if the mouse is inside the button. We do this by testing if it is left of the button, right of the button, above the button, or below the button. If it is not left/right/above/below the button, then it must be inside.
First we check if it's a
SDL_EVENT_MOUSE_MOTION
type which corresponds with an SDL_MouseMotionEvent or a SDL_EVENT_MOUSE_BUTTON_DOWN
/SDL_EVENT_MOUSE_BUTTON_UP
type which
corresponds with an SDL_MouseButtonEvent.If a mouse event happened, we then get the mouse position with SDL_GetMouseState. We then check if the mouse is inside the button. We do this by testing if it is left of the button, right of the button, above the button, or below the button. If it is not left/right/above/below the button, then it must be inside.
//Mouse is outside button if( !inside ) { mCurrentSprite = eButtonSpriteMouseOut; } //Mouse is inside button else { //Set mouse over sprite switch( e->type ) { case SDL_EVENT_MOUSE_MOTION: mCurrentSprite = eButtonSpriteMouseOverMotion; break; case SDL_EVENT_MOUSE_BUTTON_DOWN: mCurrentSprite = eButtonSpriteMouseDown; break; case SDL_EVENT_MOUSE_BUTTON_UP: mCurrentSprite = eButtonSpriteMouseUp; break; } } } }
If the mouse is outside the button, we set it to the mouse out sprite. If the mouse is inside the button, we set the mouse over sprite on a mouse motion, and mouse up/down sprite on mouse button up/down.
void LButton::render() { //Define sprites SDL_FRect spriteClips[] = { { 0.f, 0 * kButtonHeight, kButtonWidth, kButtonHeight }, { 0.f, 1 * kButtonHeight, kButtonWidth, kButtonHeight }, { 0.f, 2 * kButtonHeight, kButtonWidth, kButtonHeight }, { 0.f, 3 * kButtonHeight, kButtonWidth, kButtonHeight }, }; //Show current button sprite gButtonSpriteTexture.render( mPosition.x, mPosition.y, &spriteClips[ mCurrentSprite ] ); }
In the rendering function, we define the clip rectangles for the sprites and render the current sprite based on the input from the event handler.
//Place buttons constexpr int kButtonCount = 4; LButton buttons[ kButtonCount ]; buttons[ 0 ].setPosition( 0, 0 ); buttons[ 1 ].setPosition( kScreenWidth - LButton::kButtonWidth, 0 ); buttons[ 2 ].setPosition( 0, kScreenHeight - LButton::kButtonHeight ); buttons[ 3 ].setPosition( kScreenWidth - LButton::kButtonWidth, kScreenHeight - LButton::kButtonHeight );
Before we enter the main loop, we define the buttons by placing them in each corner of the screen.
//Get event data while( SDL_PollEvent( &e ) ) { //If event is quit type if( e.type == SDL_EVENT_QUIT ) { //End the main loop quit = true; } //Handle button events for( int i = 0; i < kButtonCount; ++i ) { buttons[ i ].handleEvent( &e ); } }
Here we're passing the event from the event loop to our buttons.
//Fill the background SDL_SetRenderDrawColor( gRenderer, 0xFF, 0xFF, 0xFF, 0xFF ); SDL_RenderClear( gRenderer ); //Render buttons for( int i = 0; i < kButtonCount; i++ ) { buttons[ i ].render(); } //Update screen SDL_RenderPresent( gRenderer ); }
And here we're rendering the buttons to the screen.