Friday, June 17, 2011

Flex: dragDropEvent is not dispatched if feedback is set to none

A few days ago I posted about how setting the useRollOver style to false on a List control also prevents the itemRollOver event from firing on that same control:

Flex: Changing useRollOver style affects itemRollOver event

In other words, what I thought would only affect the visual appearance of a component turned out to also have an impact on the components logic. I realized that some time ago I ran in to that same scenario in the context of drag & drop. I thought I'd share that here as well.

So, basically, I was implementing some drag and drop functionality for our application. When the user started a drag action I changed some parameters in the application to reflect that a dragging was currently under way. When the user stopped his dragging I was relying on the dragDropEvent to restore the application to its original state or update it depending on the drop location.

The above was implemented and was working fine. Next step was to show different cursor icons depending on which areas of the screen the user was currently dragging over, the green plus for allowed drop locations and the red cross for prohibited locations. This was easily accomplished by using the DragManager.showFeedback function passing it DragManager.COPY or DragManager.NONE respectively. Unfortunately it showed that this change also caused the implemented logic to fail. The dragDropEvent handler was just not invoked if the feedback was set to none.

Looking back at it now, I suppose it kind of makes sense and my implementation became a bit more clear after reorganizing it to account for the encountered issue. Still, it took me a while to figure it out and I also couldn't find any mentioning of this 'feature' in the documentation. It just doesn't feel right when changing the visual feedback of your application also affects the functionality. MVC, anyone?

Tuesday, June 14, 2011

Flex: Changing useRollOver style affects itemRollOver event

The other day I ran into a bug in our application that was a bit unintuitive to track down. Suddenly the context menus used on a Tree component in our application started to behave weird. Anytime the context menu was opened the menu items in it referred to the first item in the Tree rather than to the item below the mouse cursor. To give some context, this is how the context menu logic for the Tree component is setup:

We have a variable called 'lastRollOverIndex' that is updated whenever the user hovers an item in the Tree. This variable is updated with the Tree index of the last rolled over item using the itemRollOver event of the Tree control. Whenever the user then right clicks the Tree control the lastRollOverIndex is used to get the item currently under the mouse cursor and the statuses and captions of the context menu items are updated accordingly before the context menu is shown to the user.

And now, seemingly out of the blue, the above functionality failed to work. So I started going through the recent change sets in our repository to try to find out what could be the cause of this problem. Interestingly, the search showed that no changes had been made to any files containing the logic for the above, the only change between a working and a non-working version of the application was some updates to the stylesheet.

But, could that really be? Updating some styles to changes the visual appearance of the application would also cause the logic of the same to fail? Well, answer is yes.

So one of the changes in the stylesheets was setting useRollOver to false for all List components to turn of the highlighting of items while hovering the list. Since a Tree is an extension of a List the change also applies to Tree components. So far, so good. But now we come to the unexpected part. Turns out, setting the useRollOver style also prevents the itemRollOver event from being dispatched which in turn killed the logic for our context menus. At least to me, this was not what I expected, and from what I could find in the documentation it is also not mentioned there.

So in order to disable the highlighting but still allow the itemRollOver events to fire I chose to override the drawItem function of the Tree control:

protected override function drawItem(item:IListItemRenderer,
    selected:Boolean = false,
    highlighted:Boolean = false,
    caret:Boolean = false,
    transition:Boolean = false):void
{
    super.drawItem(item, selected, false, caret, transition);
}