I am creating a game in SDL2 and C . While I have a lot of experience in other programming languages, I haven't coded in C for years, and wanted to try it out again. Anyways, I've discovered a C library called SDL2 and decided to create a game. The idea for the game is still not chosen, but I am trying to create a "virtual window", which is basically just a rectangle you can drag around and show content in it. I've done almost everything, except the drag part. I want to drag the window's toolbar, and move the whole window with it according to my mouse position. Basically, I want to put the mouse in the toolbar, and when clicked and dragged, I want the whole window move with the mouse, but almost all of my attempts are that the whole window teleports at the end of my mouse, so I can't move it to the left, only to the right and down. I've found a potential way, which is included in the source code, but the window always switches positions. I don't really know how to explain this, but it switches e.g at one frame, the X is 68, at the next it's 271, and at the next one it's 67 (68-1), and at the next it's 270 (271-1) etc. I am including the source code with my post.
The "Window" class:
class Window {
public:
int x, y, w, h;
SDL_Color winc, wintc;
bool draggable;
int titleh;
Window(int wx, int wy, int ww, int wh, SDL_Color window_color = {255, 255, 255, 255}, SDL_Color window_title_color = {200, 200, 200, 255}) {
x = wx;
y = wy;
w = ww;
h = wh;
winc = window_color;
wintc = window_title_color;
draggable = true;
titleh = 50;
}
void Render(SDL_Renderer* renderer) {
SDL_Rect _t;
_t.x = x;
_t.y = y;
_t.w = w;
_t.h = h;
SDL_SetRenderDrawColor(renderer, winc.r, winc.g, winc.b, winc.a);
SDL_RenderFillRect(renderer, &_t);
SDL_Rect title;
title.x = x;
title.y = y;
title.w = w;
title.h = titleh;
SDL_SetRenderDrawColor(renderer, wintc.r, wintc.g, wintc.b, wintc.a);
SDL_RenderFillRect(renderer, &title);
int tx, ty;
if (draggable == true and isdown == true and mx > x and mx < (x w) and my > y and my < (y titleh)) {
tx = x;
ty = y;
x = mx - tx;
y = my - ty;
}
}
};
The whole file:
// Library includes
#include <SDL2/SDL.h>
#include <stdio.h>
bool isdown = false;
int mx, my;
// Screen rendering helper
void on_render(SDL_Window* window, SDL_Renderer* renderer);
// Concatenation (probably not spelt correctly but idrc) for easier use
const char * concat(const char * one, const char * two) {
char * buffer = new char[strlen(one) strlen(two) 1];
strcpy(buffer, one);
strcat(buffer, two);
return buffer;
}
// Main method, required for performing application run
int main(int argc, const char * argv[]) {
SDL_Renderer *renderer = NULL; // Initialize the renderer
SDL_Event event = { 0 }; // Create a null event
SDL_Window *win = NULL; // Initialize a window
int exit = 0; // If exit is 1, win closes
// Window pre-modifiers
const char * appName = "test";
// SDL VIDEO mode initialization and error check
if(SDL_Init(SDL_INIT_VIDEO) == -1) {
printf("SDL_Init() failed with \"%s.\"", SDL_GetError());
return 1;
}
// Create the window and load it into a previously defined variable
win = SDL_CreateWindow(concat(appName, " - Initialization in progress"), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 600, SDL_WINDOW_SHOWN);
// Window creation was unsuccessfull
if(!win) {
printf("SDL_CreateWindow() failed with \"%s.\"", SDL_GetError());
return -1;
}
// Creating renderer
renderer = SDL_CreateRenderer(win, -1, SDL_RENDERER_ACCELERATED);
// If renderer failed to load...
if(!renderer) {
printf("SDL_CreateRenderer() failed with \"%s.\"", SDL_GetError());
return -1;
}
// Everything has gone OK, thus the window can be renamed
SDL_SetWindowTitle(win, appName);
// Game loop, as said previously, false = 0, true = 1.
// while !exit |
// while not exit <- |
// while exit is 0 (false) <-
while (!exit) {
// Event loop
if (SDL_WaitEvent(&event)) {
// Event types
switch(event.type) {
case SDL_QUIT:
exit = 1; // Exit = 1, thus app is being exitted
break;
case SDL_KEYDOWN:
if(event.key.keysym.sym == SDLK_ESCAPE) exit = 1; // If ESC is pressed
break;
case SDL_MOUSEBUTTONUP:
isdown = false;
break;
case SDL_MOUSEBUTTONDOWN:
isdown = true;
break;
case SDL_MOUSEMOTION:
mx = event.motion.x;
my = event.motion.y;
break;
case SDL_WINDOWEVENT:
switch(event.window.event) {
case SDL_WINDOWEVENT_CLOSE: // macOS and/or other OSes rely on right click Quit to fully exit out of an application. This makes it easier by just hitting the close button.
exit = 1;
break;
}
break;
default: break;
}
}
// Render the screen
on_render(win, renderer);
// Swap buffers to display
SDL_RenderPresent(renderer);
}
// Cleanup
SDL_DestroyRenderer(renderer);
SDL_DestroyWindow(win);
SDL_Quit();
return 0;
}
class Window {
public:
int x, y, w, h;
SDL_Color winc, wintc;
bool draggable;
int titleh;
Window(int wx, int wy, int ww, int wh, SDL_Color window_color = {255, 255, 255, 255}, SDL_Color window_title_color = {200, 200, 200, 255}) {
x = wx;
y = wy;
w = ww;
h = wh;
winc = window_color;
wintc = window_title_color;
draggable = true;
titleh = 50;
}
void Render(SDL_Renderer* renderer) {
SDL_Rect _t;
_t.x = x;
_t.y = y;
_t.w = w;
_t.h = h;
SDL_SetRenderDrawColor(renderer, winc.r, winc.g, winc.b, winc.a);
SDL_RenderFillRect(renderer, &_t);
SDL_Rect title;
title.x = x;
title.y = y;
title.w = w;
title.h = titleh;
SDL_SetRenderDrawColor(renderer, wintc.r, wintc.g, wintc.b, wintc.a);
SDL_RenderFillRect(renderer, &title);
int tx, ty;
if (draggable == true and isdown == true and mx > x and mx < (x w) and my > y and my < (y titleh)) {
tx = x;
ty = y;
x = mx - tx;
y = my - ty;
}
}
};
Window test1 = Window(300, 200, 300, 200);
void on_render(SDL_Window* window, SDL_Renderer* renderer) {
SDL_Rect wind = { 0 };
SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
SDL_RenderClear(renderer);
SDL_GetWindowSize(window, &wind.w, &wind.h);
test1.Render(renderer);
}
CodePudding user response:
The problem is that event.motion.x (mx) and event.motion.y (my) are your mouse coordinates relative to your application window.
As you don't add any offset into the calculation of your new Window-object position, rendering will start at these coordinates.
You could, for example, do something like this, to center the mouse-pointer in your Window-object:
//Mouse-cursor will stay in the middle of the Window-object
x = mx - w / 2;
y = my - h / 2;
Or you could keep the position of your mouse-cursor inside your Window-object like this:
class Window
{
private:
//Are the offsets already calculated?
bool offset_calculated = false;
//...
}
In your Window-object Render-function:
if (draggable == true and isdown == true and mx > x and mx < (x w) and my > y and my < (y titleh))
{
if(!offset_calculated)
{
//Calculate x- and y-offset once per click
offsetx = mx - x;
offsety = my - y;
offset_calculated = true;
}
//Keep mouse-cursor position inside of the Window-object
x = mx - offsetx;
y = my - offsety;
}
else
{
offset_calculated = false;
}
Documentation: https://wiki.libsdl.org/SDL_MouseMotionEvent