Simulating icon selection and drag selection
October 15, 2000
by Pat McClellan
Dear Multimedia Handyman,
I would be grateful if you might point out a way of creating a click and drag function that will allow for the selection of sprites within the area of selection.
Justin
Dear Justin,
It's really strange that I haven't had this request before, considering that this selection function is so common in our everyday interactions with computers. Of course, it's the simple stuff like this that will undoubtedly get complicated, because simple, intuitive kinds of things are often, in reality, quite nuanced. Let's take a look at all of the behavioral details that are involved in click-selection and drag-selection of icons in a window. (There may be some minor differences between Mac and Windows, but I've written the code to work using both the shift or control key.)
- Click on an icon to select (mouseDown, not mouseUp).
- Click it again and it remains selected.
- Click on a second icon: the first icon is deselected, and the second icon is selected.
- Hold down shift (Mac) or control (Windows) and click another icon for a multi-selection.
- Hold down shift (Mac) or control (Windows) and click a selected icon to deselect it.
- Click on the background to deselect all icons.
- Click and drag on the background to create a rectangular selection area. Any icon intersecting that selection area is selected.
- Hold shift/control, click and drag on the background to select any previously unselected icons and to deselect any previously selected icons.
- If you drag an icon, you actually drag a "ghost" image of it while the original remains static. When you release it, the icon moves to that spot.
- If you have multiple icons selected and you drag one of them, the whole group moves. (I didn't include this in the demo; you can tackle this part on your own.)
- Icons can be set to snap to grid points (also not in this demo).
- I completely ignored double clicking operations.
Director 7 download for Mac or Windows.
I started by creating icons for both the selected and deselected states. There's also a sprite for the background (even though it's all white) because I need to attach a behavior to it for the deselect and drag-select. Finally, I added a sprite for the window overlay (the borders and header of the window). This sprite goes on top of all the others and uses a transparent background to cut a hole in the white middle.
The Lingo for this is contained in two behaviors: one for the icon sprites, and one for the background. It's a bit tedious, but not complicated -- little more than if-then statements and simple list operations -- so, rather than explaining it line by line, I'll walk you through all the concepts.
Since more than one icon can be selected at once, I'm going to keep track of all the selected icons using a list in the global variable gSelectedList. The behavior on each of the selectable sprites will have access to this list. Additionally, the behavior will need to have properties for the selected and deselected cast members, the rect of the sprite, as well as its current state (selected or not).
When you click on an icon, the mouseDown behavior will check to see if it is already selected (pState). Next, it will check gSelectedList to see if any other icons are selected. If others are selected, you'll need to decide whether to deselect them or not; this is conditional on whether the shift or control key is down. If shift/control is down, that indicates the user wants to select more than one icon, so the current icon will be selected without deselecting the others. Indicate that it is selected by changing its member and adding its spriteNum value to the gSelectedList variable. If the shift/control key is not down, then a message will be sent out to all the sprites in gSelectedList, telling them to deselect themselves and remove themselves from gSelectedList.
Moving on to the background sprite's behavior, the simplest operation is a click-release without a drag on the background. This click-release should deselect all selected sprites, which is accomplished by sending a message to all sprites in gSelectedList that tells them to deselect themselves and remove themselves from gSelectedList.
The drag-selection function involves two parts: representing the selection rectangle, and selecting or deselecting the appropriate icons. To represent the selection rectangle, I used a simple shape member in a sprite channel above all the icons and below the window overlay. This sprite starts off-stage. When you mouseDown on the background, that mouseLoc is saved as the pDownLoc. As you move the mouse around (holding the mouseDown), the behavior uses the pDownLoc as one corner of a rect and the current mouseLoc as the opposite corner. These rect coordinates are used to set the rect of the bounding rectangle sprite. In addition, a message containing these rect coordinates is sent to all sprites so they can assess whether they should be selected or not.
When the icon sprites receive the dragSelectSprite message with the rect coordinates, they check to see whether their own rect is intersected by the selection rect. If so, the behavior must consider whether it was already selected, as well as whether the shift/control key is down. It gets a bit convoluted in the logic, so you can sort through the code when you have some time to kill.
Finally, the draggable icon with ghost image is handled as follows. I made the clickable icons moveable by selecting that option in the sprite panel of the property inspector. When you mouseDown on the icon, the blend is set to 40%. When you release it, the blend returns to 100%. I used a substitute sprite to hold the original position of the sprite. To do this, a substitute sprite is placed offstage. When the mouseDown occurs on an icon, the substitute sprite is set to that location and the appropriate member is swapped in. When the mouse is released, the substitute sprite is reset offstage.
That should get you most of the way there. Good luck with your program.
Copyright 1997-2024, Director Online. Article content copyright by respective authors.