Re: How to make 'filter' child panels? [SOLVED -- sort of]
Re: How to make 'filter' child panels? [SOLVED -- sort of]
- Subject: Re: How to make 'filter' child panels? [SOLVED -- sort of]
- From: Cem Karan <email@hidden>
- Date: Wed, 14 Feb 2007 10:00:52 -0500
Well, its been a few weeks of thinking and playing with code, and I
figure I should tell everyone what I've figured out, just in case
anyone else needs to do this. Reread the original message for an
explanation of what I was working on (http://lists.apple.com/archives/
cocoa-dev/2007/Jan/msg00944.html), or the rest of this won't make any
sense.
Short answer, it is possible, but while the window code is easy,
keeping track of what to display is not.
Long answer, you are actually creating a new window server subsystem,
and you will be required to keep track of all that is going on. In
talking with Ryan Stevens, and in experimenting a little on my own,
here are the kinds of problems I discovered:
1) There may be multiple parent windows, which may be overlapping
each other. If these were photos and you were using a sheet of
plastic to filter out some color, then you would expect that a filter
that overlaps more than one photo would filter all photos below it.
If two photos overlap, then you'll only see the one that is on top.
2) Filter windows may overlap each other, which leads to interesting
questions; when does a filter window filter another filter window?
To give a made-up example, imagine that you have something like an
onion that is in layers. Each filter window you have peels away one
layer. If you put two filter windows above each other, should they
'add' and remove two layers? This is important because of question 3.
3) What about mouse events and key events? Which window gets it?
Imagine that you have an X-ray view into the inside of an object.
When you click on the thing in the filter window, what you really
want to do is manipulate the inside of the object 'owned' by the
parent window. But if there are multiple layers of filters, and some
provide things like dialog balloons, you may actually want to edit
the dialog balloon that is in a lower layer. Thus, just passing the
click through to the window below doesn't quite work, nor does
grabbing it directly in the filter window.
To solve all of this, I decided to mimic what Apple already provides
as much as possible. Note that my solution is 1) incomplete and 2)
horribly slow and unoptimized.
First off, starting with the easy part, making semi-transparent
windows, I figured out what Matt Gemmell was doing in his code (see
the original message for where to get it), and figured out how I was
going to synchronize a filter window's contents with some other
window. I made a scrollview that was the child of the filter panel.
To calculate the size of the scrollview, I first calculate the
minimum size rect to completely encompass all monitors attached to
the system (see below). Then set the scrollview size to be twice
that height, and 3 times that width. When the filter panel moves,
you programmatically move the scrollview in the opposite direction,
making the contents of the scrollview appear to remain motionless.
If that was all there was to it, then you'd just need a scrollview
that was the size of that minimum encompassing rect. The problem is
that it is possible move the parent windows completely off the
screen. Fortunately, the biggest you can make a single window is the
size of the encompassing rect, and the furthest you can move it is
off the screen to the left or right, or drag it all the way down (I
haven't run into a case where you can manually push a window up above
the menu bar, if I do, I'll just extend the scrollview upwards).
That is the reason for the size of the scrollview.
+-------------+----------------+
|\\\\\\\\\\\\\| |
|\\\\\\\\\\\\\| |
+-------------+ Monitor 1 |
| | |
| Monitor 2 | |
| +----------------+
| |\\\\\\\\\\\\\\\\|
+-------------+----------------|
Within the scrollview, I draw NSImages that I prepare offscreen.
These images can be moved wherever I need via a simple translation,
which is how I handle the movement of parent windows. Now, because
of how people expect objects to interact, I'm able to cut down on
drawing and processing time quite a bit when windows are moved. When
you move a window in my app, it will always be made key and ordered
to the front. No-one psychologically expects a filter to filter
something above it, only things that are below it. Thus, until the
window stops moving, and a filter is above it, I don't have to
calculate any affine transforms, which, when there are many different
filter windows up at once, can save some time. One thing I have not
tried (which I should) is to calculate the offscreen affine
transforms of all filter window images as soon as a parent window is
dropped. The general usage pattern seems to be to move a window,
drop it, then grab a filter and look at the window that was just
dropped.
Now, all of that said, the really hard part is deciding which data to
display. I really haven't come up with a good general solution to
this, mostly because of the use cases and requests that I keep
getting, but here is the hack that I have so far. Note that quite a
bit of this is planning work, but my experiments seem to suggest it
will work, so if you see something wrong, go ahead and holler.
Filter windows, parent windows, etc. are all flat; no filter window
is a child of any other window. This was the only way that I could
solve the problem of a filter window overlapping two parent windows.
All filter windows listen for movement and resize notifications from
all parent windows. Thus, whenever a new parent window is created or
destroyed, I have to update all filter window's notification
mechanisms. If a filter window is able to show information from
another filter window, then they will both listen to notifications
from each other. Each window and filter window draws its information
from a single central store, which has 'layers' associated with it
(call them dimensions, or columns in a database, or whatever you
want). There is also a central controller that keeps track of the
ordering of windows (does anyone know of a better way of doing
this???). When a window's data changes, the controller notifies that
window and all windows that are ordered above it that a change
occurred. Each window will then check the store to see what new
image information needs to be calculated, if any.
I have no idea if this method will work or not, I haven't implemented
the whole data store concept yet, and if there are dozens of filter
windows that need to be updated at one time, I'm sure that it will
cause a massive headache. On paper, and with a couple of scratch
tests, it looks good though.
Hope this helps someone else, sorry about the length of this message,
Cem Karan
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden