views:

107

answers:

2

I have two windows, each with a round NSView:

------------------     ------------
|X-+ Oscillator  |     |X-+ Mixer |
|----------------|     |----------|
|                |     |          |
|        O       |     |     O    |
|                |     |          |
|                |     |          |
------------------     ------------

Both windows are in a seperate NIB. I want to be able to draw a line between the two round NSViews at runtime, using drag'n'drop, just like connecting IBOutlets in Interface Builder:

------------------     ------------
|X-+ Oscillator  |     |X-+ Mixer |
|----------------|     |----------|
|                |     |          |
|        O-------+-----+-----O    |
|                |     |          |
|                |     |          |
------------------     ------------

I also want to be able to determine to which NSViews the NSViews are connected using the drawn lines. I need this to connect Oscillators to Mixers. I also want to be able to remove the connections by dragging into empty space.

Can anyone explain me how to do this? Thanks.

+2  A: 

The problem is having a view into which you can draw that spans the two windows' combined rects (or the screen or screens they're on). This is typically done with a borderless, transparent "overlay window." There are lots of examples of a borderless, transparent window available online.

On the start of the drag, the overlay window appears (but is invisible to the user) positioned over your drawing area. As the drag is updated, you draw your line, translating the overlay view coordinates to/from the source/target view coordinates. When the drag is complete, do some animation (like a fade or a blink) then order out the overlay window.

Joshua Nozzi
A: 

Hi Koning. I think the biggest problem with your approach is the fact that you have two separate windows, one with the oscillator view, and one with the mixer. If you could change your design so as to display all synthesizer components (or maybe radio frequency components - not sure what you're doing!) in a single window, then your problems will get much simpler.

As Joshua said, one approach is to use an invisible overlay window which just shows the link. But if you're really using two separate windows then you can't (as Joshua suggests) order out the overlay window at the end of the drag. If you do that, the link will disappear at the end of the drag. If you want the link to continue to be displayed (think of Interface Builder or - better yet - Quartz Composer) then you need some mechanism to persistently display the link. This is especially true if you want to, at a later point, allow the user to remove the link.

I'd strongly suggest building your interface around a single window. Also, consider using Core Animation to display each link as a layer.

Dave

Dave Jewell
If the connection is intended to persist, then the overlay window would simply stay ... it's not that difficult to adapt. The only real challenge to an ever-present overlay is allowing clicks to fall through.
Joshua Nozzi
Yes, it would be possible to make the overlay window method work persistently. But as you say, that introduces issues with click throughs, and then what do you do in the general case where you have multiple entities with multiple connections between them? You've either got to use one overlay window per link (ughh), or add new links to an existing overlay window which might need to resize to span all linked entities. The more I think about this, the more I think that a cleaner solution is to just do it all in one window. This is just the sort of problem that CALayer solves beautifully.
Dave Jewell
In the case of a persistent window, it can remain the size of the screen (or all screens). The click-through problem really isn't that big a deal and there are already code samples floating around. As to the complexity, sure it's difficult, but not so difficult that a multi-window approach should be trashed because of it. If the OPs requirements are multiple windows and a solution is possible, then it's best to address the original requirements.
Joshua Nozzi