How do I capture(trap) a mouse in a window in c++? - c++

I am writing a tile map editor in SFML and C++. I have been having all sorts of troubles with the mouse. I am using the built in SFML Mouse:: static functions and recently managed to get a custom cursor moving on the screen and pointing accurately to a tile by doing as follows:`
Sprite cursor;
bool focus = false;
RenderWindow window(VideoMode(512, 288), "Tilemap editor");
window.setFramerateLimit(60);
Texture cursorTexture;
if(!cursorTexture.loadFromFile("Graphics/Cursor.png")) {
std::cout << "Failed to load cursor texture\n";
return 0;
}
cursor.setTexture(cursorTexture);
Mouse::setPosition(mousePos);
While(window.isOpen()) {
window.setMouseCursorVisible(focus);
if(Mouse::getPosition().x != lastMousePos.x) {
mousePos.x = mousePos.x + (Mouse::getPosition().x - lastMousePos.x);
}
if(Mouse::getPosition().y != lastMousePos.y) {
mousePos.y = mousePos.y + (Mouse::getPosition().y - lastMousePos.y);
}
cursor.setPosition(mousePos.x, mousePos.y);
lastMousePos = Mouse::getPosition();
window.clear();
window.draw(cursor)
window.display()
}
The built-in Mouse functions only display relativity to the desktop or the window and as I am using this app in a small window in which my view moves, I can't use either. The solution above moves a cursor independent of the desktop and with the ability to move the cursor if and when I want to move my view.
The issue is that my mouse will move off the side of the app when I try to click items in the top left corner.
Is there a good cross-platform (I'm on Linux BTW) way to trap the mouse inside of the window unless I enter a keystroke (like a VM window)? Also, is there a better way to do cross-platform mouse support in general? SFML kinda sucks. (Code obviously needs to be in a main function and the namespace must be sf with SFML/Graphics.hpp included)

There is already a method for that.
void setMouseCursorGrabbed (bool grabbed)
// Grab or release the mouse cursor.
You can also use these methods to convert your screen coordinates to mouse coordinates and vice versa.
Vector2f mapPixelToCoords (const Vector2i &point) const
// Convert a point from target coordinates to world coordinates, using the current view.
Vector2f mapPixelToCoords (const Vector2i &point, const View &view) const
// Convert a point from target coordinates to world coordinates.
Vector2i mapCoordsToPixel (const Vector2f &point) const
// Convert a point from world coordinates to target coordinates, using the current view.
Vector2i mapCoordsToPixel (const Vector2f &point, const View &view) const
// Convert a point from world coordinates to target coordinates.
sf::RenderWindow Class Reference

Related

How to know a sprite position inside a view, relative to window?

I have this sprite of a car that moves with varied speed.
It is inside a view and the view is moved to the left to keep the car always in the center of the window.
The view accompanies the displacement of the car, ie it is shifted to the left as the car accelerates or brakes.
This way the car will always appear in the center.
But if for example it is overtaken by another car, it will be left behind.
For it not to disappear from the window, I have to zoom in the view so that all the cars appear.
But for this, I need to know the position of the car in relation to the window (not in relation to the view).
getGlobalBounds().left or getPosition().x show the same value, which is the position relative to the view, not relative to the window, as shown in the image.
How to know a sprite position inside a view, relative to window?
After several hours of research, I finally find the easy way of achieve this. And yes, it was ridiculously easy.
But first, I would like to clear up some misconceptions.
getGlobalBounds().left or getPosition().x show the same value,
which is the position relative to the view, not relative to the
window, as shown in the image.
In fact, those methods return the position in the world, not in the view nor in the window.
You can have, for instance, a 500x500 window, with a 400x400 view, in a 10000x10000 world. You can place things in the world, outside of the view or the window. When the world is rendered, then the transformations of the view (translations, rotations, zoom, ...) are applied to the world and things are finally shown in the window.
To know where a coordinate in the world is represented in the window (or any other RenderTarget) and vice versa, SFML actually have a couple of functions:
RenderTarget.mapCoordsToPixel(Vector2f point)
Given a point in the world gives you the corresponding point in the RenderTarget.
RenderTarget.mapPixelToCoords(Vector2f point)
Given a point in the RenderTarget gives you the corresponding point in the world. (this is useful to map mouse clicks to corresponding points in your world)
Result
Code
int main()
{
RenderWindow window({ 500, 500 }, "SFML Views", Style::Close);
sf::View camera(sf::FloatRect(0, 0, window.getSize().x, window.getSize().y));
sf::Vector2f orig(window.getSize().x / 2, window.getSize().y / 2);
camera.setCenter(orig);
sf::Font f;
f.loadFromFile("C:/Windows/Fonts/Arial.ttf");
sf::Text t;
t.setFont(f);
sf::RectangleShape r;
r.setPosition(10, 10);
r.setSize(sf::Vector2f(20, 20));
r.setOutlineColor(sf::Color::Blue);
r.setFillColor(sf::Color::Blue);
t.setPosition(10, 40);
while (window.isOpen())
{
for (Event event; window.pollEvent(event);)
if (event.type == Event::Closed)
window.close();
else if (event.type == Event::KeyPressed){
camera.move(-3, 0);
camera.rotate(5.0);
camera.zoom(1.1);
}
auto realPos = window.mapCoordsToPixel(r.getPosition());
std::string str = "Pos: (" + std::to_string(realPos.x) +","+ std::to_string(realPos.y) + ")";
t.setString(str);
window.clear();
window.setView(camera);
window.draw(r);
window.draw(t);
window.display();
}
return EXIT_SUCCESS;
}

How to zoom in a QgraphicsView using pushbuttons?

I'm building a very simple image editor on Qt creator.I have my image displayed on a QGraphicsView and i want to give the user the ability to zoom in and out by a pushbutton.
I've searched a lot and found how to zoom in and out through the mouse wheel.As i am very new to Qt i can't adjust it to the pushbutton because i don't understand everything clearly.
I' ve tried this(without understanding completely what i'm doing)but the result isn't the wanted.It zooms in only once and quite abruptly.I want a smoother zoom and as many times as i want.
void MainWindow::on_pushButton_clicked(){
QMatrix matrix;
ui->graphicsView->setTransformationAnchor(QGraphicsView::AnchorViewCenter);
matrix.scale(1.0,1.0);
ui->graphicsView->setMatrix(matrix);
ui->graphicsView->scale(1,-1);
}
I would be very grateful if you guys can help
Below is how I implemented zooming in my subclass of QGraphicsView. Note that you'd need to pass in different values of "zoom" to get different magnifications as the zoom factor is an absolute value, not a relative one.
(The optMousePos argument can be set to point to a QPoint indicating the spot that should be the central-point of the zoom transformation, or it can be left NULL if you don't care about that. I use it because I zoom in and out based on the user turning the wheel in his mouse, and when doing that, the user usually wants to zoom in towards the point where his mouse point is currently positioned, rather than in towards the center of the graphics area)
qreal _zoom = 0.0;
[...]
void MyQGraphWidgetSubclass :: SetZoomFactor(qreal zoom, const QPoint * optMousePos)
{
if ((zoom != _zoom)&&(zoom >= 0.02f)&&(zoom <= 1000000.0f))
{
QPointF oldPos;
if (optMousePos) oldPos = mapToScene(*optMousePos);
// Remember what point we were centered on before...
_zoom = zoom;
QMatrix m;
m.scale(_zoom, _zoom);
setMatrix(m);
if (optMousePos)
{
const QPointF newPos = mapFromScene(oldPos);
const QPointF move = newPos-*optMousePos;
horizontalScrollBar()->setValue(move.x() + horizontalScrollBar()->value());
verticalScrollBar()->setValue(move.y() + verticalScrollBar()->value());
}
}
}
void MyQGraphWidgetSubclass :: wheelEvent(QWheelEvent* event)
{
QPoint pos = event->pos();
SetZoomFactor(_zoom*pow(1.2, event->delta() / 240.0), &pos);
event->accept();
}

Getting center of specific screen in virtual desktop qt

Hey guys i need to get resolution of specific screen in virtual desktop under qt and move window around given screen. I tried
QRect screenSize = desktopWidget.availableGeometry(desktopWidget.screen(ui.monitorNumberComboBox->currentIndex()));
and now when i execute
void MyWindow::setCoordinates(int x, int y)
{
this->move((x-(this->width())/2),(y-(this->height()/2)));
//sets center of window on given coordinates
}
window->setCoordinates(screenSize.width()/2, screenSize.height()/2);
it works great but only for primary screen. Is there a possibility to use it for different screen, selected by index?
I think you need to call:
[..]
QPoint center = screenSize.center(); // Get the center of the screen rect.
window->setCoordinates(center.x(), center.y());

convert window coordinates to 3D world coordinates with glut function glutMouseFunc()

I am trying to get the 3D coordinates of a mouse click C++/OpengGL with the glut function glutMouseFunc(). So I created a function like this:
void mouse(int button, int state, int x, int y){
if(button == GLUT_LEFT_BUTTON && state == GLUT_DOWN)
{
mouse_x=x;
mouse_y=y;
}
}
The function gets the window coordinates of the click of the mouse and i use it with the glut function glutMouseFunc() like this:
glutMouseFunc(mouse);
My question is how would I modify the coordinates given by the mouse function so I could use them in a 3D world. My exact purpose would be the following: to be able to see if I have clicked on a 3D shape drawn in the world.
[EDIT] Would it be easier to transform the coordinates of the 3D object to 2D window coordinates and then compare it to the coordinates of the mouse click?
Mouse click does not correspond to a point in 3d space, but to a ray.
In any case, you use gluUnProject.
If you know scene "depth" under cursor, then you can get 3d position of a click - by passing depth via winZ parameter.
If you don't know depth, pass 0.0 in winZ parameter, to get start of the ray, and 1.0 to get the "end". You'll have to calculate yourself if this ray hits anything.

Trapping the mouse?

I'm using GLUT and developing a FPS game. I need a way to trap the mouse so that the camera continues to move because right now when the mouse position exceeds the monitor limit, there is no way to calculate change in X or change in Y. How can I 'trap' the mouse with GLUT?
Thanks
I'd recommend using a ready-made engine like OGRE 3D instead, but if you really want to reinvent the wheel, here's how...
In all cases I'm aware of, PC FPS games "trap" the pointer by registering a mouse motion callback, noting the relative motion, and then warping the pointer back to the center of the window.
Here's some code I wrote to add mouse input to a sample ping-pong table in an OpenGL with C++ course a year or two ago:
void resetPointer() {
glutWarpPointer(TABLE_X/2, TABLE_Y/2);
lastMousePos = TABLE_Y/2;
}
void mouseFunc(int sx, int sy) {
if (!started) { return; }
int vertMotion = lastMousePos - sy;
lastMousePos = sy;
player1.move(vertMotion);
// Keep the pointer from leaving the window.
if (fabs(TABLE_X/2 - sx) > 25 || fabs(TABLE_Y/2 - sy) > 25) {
resetPointer();
}
}
// This goes in with your "start new game" code if you want a menu
resetPointer();
glutSetCursor(GLUT_CURSOR_NONE);
glutPassiveMotionFunc(mouseFunc);
It only tracks vertical motion, but adding horizontal is trivial.