I'm just getting back into GameMaker, since it's been a while. Upgraded to Studio 2 since it's all shiny and new and stuff.
My test code is quite simple:
/// #description Update position each step
x = clamp(mouse_x, sprite_width/2, room_width-sprite_width/2);
And it works just fine... provided the mouse is within the game window. As soon as the mouse strays outside, it stops updating. This is kind of a problem if I want to make a basic Breakout-type game, since it's very easy for the mouse to stray up or down during gameplay, and losing just because your mouse clipped the title bar of the window is a bit gutting.
Is there a setting I'm missing somewhere? I'm sure older versions of GameMaker updated mouse_x no matter where the mouse was...
I have never used Studio 2, but you could try keeping the mouse inside the game window like so:
/// #description Update position each step
mouse_x = clamp(mouse_x, sprite_width/2, room_width-sprite_width/2);
x = mouse_x;
Related
I have an iPad app (in C#) with a custom UIView that allows input via touch and Apple Pencil stylus touches. I am trying to integrate support for trackpad/mouse indirect (cursor, or "pointer" as Apple calls it).
I got hover working using HoverGestureRecognizer. I got right-click and control-click working using normal touch Began/Moved/Ended/Cancelled events and checking for .type == .indirectPointer and then checking if the control key modifier in event.ModifierFlags is set, or if event.ButtonMask == secondary.
I have spent a lot of time searching through the documentation on the Apple Developer website, starting here and branching out:
UIApplicationSupportsIndirectInputEvents
Somehow I cannot find the API that the system calls in my code when a two-finger trackpad scroll (or mouse scrollwheel scroll) occurs. (On another view that is a scrollview, I can get the scrollview's scroll event when I do a two-finger scroll, since this is built-in to iPadOS 13.4+ for scroll views, but my custom view is not a scroll view, it just has some scrollable areas inside of it.)
Things I tried:
UISwipeGestureRecognizer. Nothing was called for two-finger trackpad scroll gesture.
UIPanGestureRecognizer. Nothing.
Subclassing UIScrollView and adding a UIScrollViewDelegate, just to see if it would work... Nothing.
Subclassing GestureRecognizer and adding that, then overriding ShouldReceive(UIEvent evt) but that was never called.
What does iPadOS 13.4+ convert the trackpad two-finger scroll gesture into? Can I get this as some sort of event? The documentation linked above is pretty disappointingly barebones, but it mentions UIEvent.EventType.scroll but not how or when or where the system will call any of my methods with an event of that type. Pretty infuriating. They should just spell this out more clearly.
Answers in Swift or C# are welcomed.
OK, strangely I thought I tried PanGestureRecognizer, but I must have set it up wrong. The example code project by Apple, Integrating Pointer Interactions into Your iPad App had the answer (C# code):
panRecognizer = new UIPanGestureRecognizer(() => {
Console.WriteLine("panned -- " + panRecognizer.VelocityInView(this));
});
panRecognizer.AllowedScrollTypesMask = UIScrollTypeMask.Continuous;
AddGestureRecognizer(panRecognizer);
Glad I figured this out!
Background
I'm building an application which runs in the background, and where the mouse cursor is moved programmatically into a dialog when the dialog "pops up". I have done this using QCursor.setPos
Problem
The problem I'm having is that if the mouse button is pressed down when the user is interacting with something outside the application this might lead to unwanted things happening. For example if the user is changing the volume and the mouse is moved the volume might go to max or min
Question
Is there any way (in Qt) to do a mouseup programmatically?
If I do this before changing the position of the cursor it seems to me that there is less risk of problems (though there might be other problems resulting from this approach)
Something seems to have changed in Qt 5: you can't get a drop or move event if you don't move at least one pixel from the start point where you were when QDrag::exec() was called. Try putting a breakpoint in the dropEvent of the Draggable Icons Sample, then click a boat and release it without moving the mouse. That generates an "ignore" without any drop signal.
(This is on Kubuntu 13.10 with Qt 5.1.)
When teaching how to start a drag operation, the documentation suggests you might use manhattanDistance() to determine if the mouse has moved enough to really qualify as "the user intending to start a drag". But you don't have to use that; you can start up a QDrag on the click itself.
Anyone know of a workaround to have that same kind of choice on the drop side, or is that choice gone completely? :-/
Why I care: I've long had frustrations trying to get a tight control on mouse behavior in GUI apps—Qt included. There seems to be no trustworthy state transition diagram you can draw of the invariants. It's a house of cards you can disprove very easily with simple tests like:
virtual void enterEvent(QEvent * event) {
Q_ASSERT(!_entered);
_entered = true;
}
virtual void leaveEvent(QEvent * event) {
Q_ASSERT(_entered);
_entered = false;
}
This breaks all kinds of ways, and how it breaks depends on the platform. (For the moment I'll talk about Kubuntu 13.10 with Qt 5.1.) If you press the mouse button and drag out of the widget, you'll receive a leaveEvent when you cross the boundary...and then another leaveEvent when the button is released. If you leave the window and activate another app in a window on screen and then click inside the widget to reactivate the Qt app, you'll get two consecutive enterEvents.
Repeat this pattern for every mouse event, and try and get a solid hold on the invariants...good luck! Nailing these down into a bulletproof app that "knows" it's state and doesn't fall apart (especially in the face of wild clicking and alt-Tabbing) is a bit of a lost cause.
This isn't good if your program does allocations and has heavy processing, and doesn't want to do a lot of sweeping under the rug (e.g. "Oh, I was doing some processing in response to being entered... but I just got entered again without a leave. Hm, I guess that happens! Throw the current calculations away and start again...")
In the past what I've done is to handle all my mouse operations (even simple clicking) with drag & drop. Getting the OS drag & drop facility involved in the operation tended to produce a more robust experience. I can only presume this is because the testers actually had to consider things like task switching with alt-Tab, etc. and not cause multiple drop operations or just forget that an operation had been started.
But the "baked in at a level deeper than the framework" aspect actually makes this one-pixel-move requirement impossible to change. I tried to hack around it by setting a timer event, then faking a QMouseEvent to bump the cursor to a new position once the drag was in effect. However, I surmise that the drag and drop is hooked in at the platform level, and doesn't consult the ordinary Qt event queue: src/plugins/platforms/xcb/qxcbdrag.cpp
The issue has--as of 1-May-2014--been acknowledged as a bug by the Qt team:
https://bugreports.qt-project.org/browse/QTBUG-34331
It seems that me bountying it here finally brought it to their attention, though it did not generate any SO answers I could accept to finalize the issue. So I'm writing and accepting my own. Good work, me. (?) Sorry for not having a better answer. :-/
There is another unfortunate side effect of the Qt5 change, pointed out by a "Dmitry Mordvinov":
Same problem here. Additionally app events are not handled till the first mouse event after drag started and this is really nasty bug. For example all app animations are suspended during that moment or application hangs up when you try to drag with touch monitor.
#dvvrd had to work around it, but felt the workaround was too ugly to share. So it seems that if you're affected by the problem, the right thing to do is go weigh in...and add your voice to the issue tracker to perhaps raise the priority of a solution.
(Or even better: patch it and submit the patch. 'tis open source, after all...)
I'm implementing Qt's drag and drop API across Windows and X. When I pick up an object in the app running on X and drag it, it leaves a white ghost trail of itself on the window underneath, as if the window underneath is being slow to repaint where the dragged object was previously obscuring part of itself.
I believe that this is symptomatic of the same problem that Qt has just solved with resizing windows causing flicker in child widgets on X windows - i.e. the dragged object is treated as a separate native window and therefore X handles the clipping from the dragged object to the window underneath. Since X does this in a different way to Qt, we get the ghosting effect.
Has anyone experienced the same problems? One solution that comes to mind is to use the same technique as detailed in the blog article linked above and stop the dragged object being treated as a native window, presumably at the cost of drag and drop being limited to my application only (I have no problem with this). Would anyone know how to force drag and drop operations to be internal only?
EDIT: I'm using QDrag::setPixmap to set the graphical representation of the dragged object - it is important that I retain this in favour of a standard drag cursor as this interface is being used on a touchscreen device and will hence have no visible cursor.
I'm now of the opinion that short of editing and then compiling my own build of Qt (not an option for me), I can't force drag and drop operations to be internal only.
Equally, I can't find any way of getting rid of the ghost trail by tweaking my window manager settings or using a compositing window manager (thanks anyway though #atomice). Using OpenGL as the renderer increases the screen repaint speed slightly, but is not perfect and introduces its own problems (see Starting a Qt drag operation on X11 w/ OpenGL causes screen flicker). I would still be very interested to hear any ideas though.
I have, however, got a workaround for my problem which works on both Windows and X. Here's a simplified version:
void DoDrag()
{
//Prepare the graphical representation of the drag
mDragRepresenter = new QWidget(QApplication::activeWindow());
mDragRepresenter->setAttribute(Qt::WA_TransparentForMouseEvents);
mDragRepresenter->SetPixmap(GenerateDragPixmap());
RepositionDragRepresenter();
mDragRepresenter->show();
QTimer UpdateTimer;
connect(&UpdateTimer, SIGNAL(timeout()), this, SLOT(RepositionDragRepresenter()));
UpdateTimer.start(40);
//Start the drag (modal operation)
Qt::DropAction ResultingAction = Drag->exec(Qt::CopyAction);
UpdateTimer.stop();
delete mDragRepresenter;
}
void RepositionDragRepresenter()
{
mDragRepresenter->move(QApplication::activeWindow()->mapFromGlobal(QCursor::pos()) - mDragRepresenterHotSpot);
}
An X11 window is only created for a drag operation if a QDrag::mimeData()->hasImage() is true. If you modify your code so it doesn't use an image then you will just get a drag cursor instead which won't trigger a repaint of the windows underneath.
You don't specify what kind of object you are dragging or how you are setting up the drag operation. Can you add some code to show that?
I need to keep a NativeWindow I am creating on top of the main window of the application.
Currently I am using alwaysInFront = true, which is not limited to the windows in the application. I can successfully synchronize the minimize/restore/move/resize actions, so the top window behaves appropriately in those cases. Even though using this option has the drawback that if I alt-tab to other application the window goes on top of the other application.
Because of the above I am trying to get it to work without using the alwaysInFront. I have tried using orderInFrontOf and orderToFront, which gets it in place but when I click an area in the main window the top one becomes hidden i.e. air makes it the top one.
I have tried capturing activate/deactivate events but it only happens on the first click, so on the second click the top window becomes hidden again. I also tried making the top window active when the main one becomes active, but that causes the main one to loose focus and I can't click on anything.
Ps. I am doing this to improve the behavior of a HTMLOverlay I am using - see Flex Air HTMLLoader blank pop up window when flash content is loaded
Listening for Event.DEACTIVATE and calling event.preventDefault() should work. Not sure if that is what you have tried, but I have an app where that does the trick.
I ended up turning on/off the alwaysInFront option based on whether the main window or the top window were active i.e. if none where active I turned it off. This was additionally to what I mentioned in the question.
That way when the user switches to another application, the window doesn't go on top of the other apps. I still would prefer a solution where I don't have to use the alwaysInFront option, or even better an alternate solution to the flex loading flash in external sites issue I linked to above.
Ps. I will try to check with the owner of the HTMLOverlay to submit a patch (its an improvement, although its tied to an app that doesn't open extra windows when opening the overlay).
Update: I have committed the changes to the HTMLOverlay.
I'm trying to do something very similar. In an AIR application, I have one large full screen window which is essentially the "desktop". I always want this window to stay behind all other windows in my app. There are, however, some items on the "desktop" window that need to be clickable.
There appears to be no clean way to force a window to maintain its position in the window ordering.
What I've settled on so far, which isn't perfect, is to make all other windows in my app use the alwaysOnTop property but bind this to a global var (ugh) that I maintain to track the overall application level active/inactive state. This way, when I switch to another app, my windows don't float above the all other app windows - they correctly move behind as expected.
Then, I have a regular (alwaysOnTop=false) window that is fully transparent as an "overlay" to the desktop window on which I can place various interactive controls. This window is OK to come forward since it's transparent and my other windows are alwaysOnTop.
Finally, and crucially, I install three event listeners on the "desktop" window as follows:
protected function onApplicationComplete(event:Event):void
{
this.addEventListener(MouseEvent.MOUSE_DOWN, onClickHandler, true,1000,true);
this.addEventListener(MouseEvent.CLICK, onClickHandler, true,1000,true);
this.nativeWindow.addEventListener(Event.ACTIVATE, onActivateWindow,false,-1);
}
protected function onActivateWindow(event:Event):void
{
trace("sent via activate to back");
orderInBackOf(bigTransparentWindow);
}
protected function onClickHandler(event:MouseEvent):void
{
trace("sent via click to back");
orderInBackOf(bigTransparentWindow);
}
I'm not entirely happy with all this since there is still some occasionally noticeable flicker of objects in the overlay window - it appears that the "Desktop" window gets ordered in front of it, an update of some sort happens, and then it gets forced behind again.
Any better solutions welcome!