Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I have a bunch of drag-able widgets on screen. When I am dragging one of the widgets around, if I drag the mouse over another widget, that widget then gets "snagged" and is also dragged around.

While this is kind of a neat thing and I can think of a few game ideas based on that alone, that was not intended. :-P

Background Info

I have a Widget class that is the basis for my user interface controls. It has a bunch of properties that define it's size, position, image information, etc. It also defines some events, OnMouseOver, OnMouseOut, OnMouseClick, etc. All of the event handler functions are virtual, so that child objects can override them and make use of their implementation without duplicating code.

Widgets are not aware of each other. They cannot tell each other, "Hey, I'm dragging so bugger off!"

Source Code

Here's where the widget gets updated (every frame):

public virtual void Update( MouseComponent mouse, KeyboardComponent keyboard ) {
    // update position if the widget is being dragged
    if ( this.IsDragging ) {
        this.Left -= (int)( mouse.LastPosition.X - mouse.Position.X );
        this.Top -= (int)( mouse.LastPosition.Y - mouse.Position.Y );
    }
    ... // define and throw other events
    if ( !this.WasMouseOver && this.IsMouseOver && mouse.IsButtonDown( MouseButton.Left ) ) {
        this.IsMouseDown = true;
        this.MouseDown( mouse, new EventArgs() );
    }
    ... // define and throw other events
}

And here's the OnMouseDown event where the IsDraggable property gets set:

public virtual void OnMouseDown( object sender, EventArgs args ) {
    if ( this.IsDraggable ) {
        this.IsDragging = true;
    }
}

Problem

Looking at the source code, it's obvious why this is happening. The OnMouseDown event gets fired whenever the mouse is hovered over the Widget and when the left mouse button is "down" (but not necessarily in that order!). That means that even if I hold the mouse down somewhere else on screen, and simply move it over anything that IsDraggable, it will "hook" onto the mouse and go for a ride.

So, now that it's obvious that I'm Doing It Wrong™, how do I do this correctly?

share|improve this question
add comment

2 Answers

up vote 2 down vote accepted

It seems that you need some kind of a boolean variable telling you whether you are dragging something at this exact time, or not. Assuming that you can only drag one widget at a time, just check if draggingSomething is true, and if so, don't "hook" any new widgets on.

share|improve this answer
1  
I thought about adding a flag to the MouseComponent. Problem is that it creates this strange dependency between objects. I would rather the objects be more independent and handle their own states. Maybe I'm over-thinking things... +1 for the straight-forward solution. –  Cypher Sep 18 '12 at 20:28
    
I smell YAGNI. I don't see why, if you have an object already managing the widgets, you couldn't just include a flag... But well, it's your code, this is how I'd do it. It's just communication between objects, if you already have something implemented, then go for it I guess. –  akled Sep 18 '12 at 20:47
add comment

Only trigger the OnMouseDown event if the mouse was up before and is now down (all over the same element). Meaning you only trigger when the mouse is clicked on the current widget, and not by dragging a clicked mouse across multiple widgets. Means you need to keep track of the mouse state.

Keeping track of which widget the mouse is currently over would likely be very useful to you if you're not doing it already. When a mouse press is detected it can be picked up by whatever your GUI controller class is. The GUI controller will then send the event to the currently selected widget.

The currently selected widget gets updated something like so (this code is run by your GUI controller):

poll mouse position
walk tree into children and find bottom most child widget mouse is in
if underMouseWidget is different than the currentWidget
   currentWidget.mouseLeave()
   currentWidget = underMouseWidget
   currentWidget.mouseEnter()

Now that you have the current widget your GUI controller can handle events much easier. Like, a mouse click:

currentWidget.mouseClick(Button, Position)

This also means you always know where your mouse is, and your widgets know if they were the ones currently under the mouse when it was pressed.

share|improve this answer
    
The mouse state is tracked via the MouseComponent. –  Cypher Sep 18 '12 at 21:11
    
How can the Widget track if the mouse went down while hovering over it and then somehow not set the same flag when hovering over other Widgets that it does not know about? I can't use your logic of !this.WasMouseDown && this.IsMouseDown because that will be true by simply rolling over all elements with the mouse held down... hence the question. :) –  Cypher Sep 18 '12 at 21:13
    
I guess I can only suggest a slightly different way of doing things. Please see my edits. –  Byte56 Sep 18 '12 at 22:13
    
"Slightly different way of doing things" is why I'm here. :) It sounds like you're advocating the use of a manager class for the widgets. That's a good idea. –  Cypher Sep 18 '12 at 22:22
    
Indeed, a manager class has lots of nice features and centralizing the input controls is one of the really good ones. –  Byte56 Sep 18 '12 at 22:34
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.