All About the Little Green Glob
Pages: 1, 2
Another thing to notice is that when the image is zoomed, the window dumbly does nothing to accommodate the changes in the information being displayed. Both of these things can be fixed with one simple line of code that takes advantage of window zooming.
Quit the application and open IAWindowController.m in Project Builder. At the very end of the method -scaleImageTo: append the single line of code:
[[self window] zoom:nil];
NSWindow's -zoom: method is the same method invoked when the user clicks on the window zoom button. We're invoking it directly in response to any zoom activity, and thus ensuring that the image is displayed as best as it can be. Effectively, the application pushes the green button for you whenever the scale of the image changes. The reason this takes care of the problem of the incorrectly sized initial window is the line of code executed in windowDidLoad:
[self scaleImageTo:1.0];
By sending this message whenever the application opens a new document, we always zoom the window to fit the current image.
Now, compile and run the application again, and let's look at one other bit of behavior. Open an image and enter some large-scale value, such as 1000 percent, that will make the image much larger than the screen. Did you notice what happened? Cocoa's window-zooming mechanism knows when the window will be larger than the screen. If we return a standard frame that is larger than the useable area of the screen, which excludes the menu bar and the dock, the window will know and simply make itself as large as the useable area.
So, given this built-in behavior, why should we bother testing the size of stdFrame against the default frame ourselves? Compare the two images below. The image on the left uses the built-in size restriction mechanism; in the image on the right I compare stdFrame against defaultFrame. Do you see the difference?
Size restriction using the built-in behavior is shown on the top. Size restriction implemented by ourselves using the default frame is shown on the bottom. |
|
Also in Programming with Cocoa |
The difference is subtle, but one that is important to me as a user. The difference is the presence of a thin (approximately 10 pixels) empty strip below the window. The default frame treats this area as off-limits, just like the dock and the menu bar. The utility of this is that we have a convenient spot to click through the windows or the desktop in the background. If you think this is important like I do, then continue reading as we implement our own version of size constraint using the default frame.
When taking the default frame into account there are two things to consider. First is the obvious case of stdFrame being larger than the default frame. We handle this case in the x and y directions independently. So if stdFrame is wider than the default frame, we set the width of stdFrame to the width of defaultFrame, and set the x origin of stdFrame to the origin of defaultFrame. The same goes for the vertical direction. If stdFrame is higher than defaultFrame, then we set the height of stdFrame and the y origin of stdFrame to those values of defaultFrame.
The second thing we must consider are situations when the size of stdFrame isn't larger than the default frame, but part of the window may be off the screen. We handle this by moving stdFrame back onto the window. Let's take a look at the modifications to our method to see how this all fits together:
- (NSRect)windowWillUseStandardFrame:(NSWindow *)sender
defaultFrame:(NSRect)defaultFrame
{
float stdX, stdY, stdW, stdH, defX, defY, defW, defH;
// get the y-origin of the scroll view for use in computing newHeight
int svOffset = [[[view superview] superview] frame].origin.y;
NSSize viewSize = [view frame].size;
float newHeight = viewSize.height + svOffset;
float newWidth = viewSize.width;
NSRect stdFrame = [NSWindow contentRectForFrameRect:[sender frame]
styleMask:[sender styleMask]];
stdFrame.origin.y += stdFrame.size.height;
stdFrame.origin.y -= newHeight;
stdFrame.size.height = newHeight;
stdFrame.size.width = newWidth;
stdFrame = [NSWindow frameRectForContentRect:stdFrame
styleMask:[sender styleMask]];
stdX = stdFrame.origin.x;
stdY = stdFrame.origin.y;
stdW = stdFrame.size.width;
stdH = stdFrame.size.height;
defX = defaultFrame.origin.x;
defY = defaultFrame.origin.y;
defW = defaultFrame.size.width;
defH = defaultFrame.size.height;
if ( stdH > defH ) {
stdFrame.size.height = defH;
stdFrame.origin.y = defY;
} else if ( stdY < defY ) {
stdFrame.origin.y = defY;
}
if ( stdW > defW ) {
stdFrame.size.width = defW;
stdFrame.origin.x = defX;
} else if ( stdX < defX ) {
stdFrame.origin.x = defX;
}
return stdFrame;
}
The first thing added in this implementation over the previous one was the string of float variable declarations. These are used just after the previous method ended as a convenience in the following if statements. As you can see, we assign to each of these eight variables the values of the different parts of the two frames we wish to compare.
Following that are two if statements, conceptually alike, but operating on the two dimensions of the window. First we look at the vertical dimensions of the two frames. In the first if statement we check to see if the height of the standard frame is greater than the height of the default frame. If this is true, then we set the height of stdFrame to defH (which is the height of the default frame), and the vertical origin of stdFrame to that of the default frame (defY).
If this first conditional is false we move on to check whether the bottom of the standard frame is below the bottom of the screen. If it is, we reset the standard frame's origin to that of the default origin (again, only in the y direction), and move on. We don't have to worry about translating the origin of stdFrame up to defFrame's origin (making the top of the window higher than the screen) since in the first conditional we checked to make sure the height of stdFrame was less than defaultFrame.
So that's the logic behind using the default frame. What we did for the y direction is exactly how we do it for the x direction, except Ys are replaced by Xs and Hs by Ws. Go ahead and compile ImageApp and give it a run to try out this newest change.
Now that we know how window zooming works in Cocoa, we'll all have happier users of the software we create. If you're interested you can download the project containing the changes we made to ImageApp today. In the next column we're going to learn how we can further polish ImageApp.
You must be logged in to the O'Reilly Network to post a talkback.
Showing messages 1 through 7 of 7.
-
focus object selection methods: the spare desktop border vs the click-thru windowframe
2002-05-26 17:25:41 zahadum [Reply | View]
re: window-frame sizing for spare border for access to desktop ...
here is a thought/question about how the cocoa windowing classes access quartz ...
we already know that the Aqua UI conventions for a display context can present multiple windowframes with various levels of opacicty, as an alternative to the standard frame-clipping approach that blocks out that the (view of the) state of of other windowframes ....
and using quartz compositing is indeed a nice way to 'compress' multiple channels of visual information to the user ....
but this access method is only one-way: there is no corresponding accessor quartz method (supported in the aqua conventions) for "drilling down" through multiple layers of the over-layed windowframes, in order to be able to select a new focus object underneath the current focus object ...
the existing aqua conventions still force us to wade through the windowframes manually (even if we at least now have the elegance of knowing more clearly what our target is) ...
so a question: would it be easy to use a cocoa delegate method to gather-up all the context information for the objects which lay underneath (or over) the a given windowframe ... for the purpose of passing this list into a small aqua widget that overridges one of the windowframe controls ....
eg, a alt_mouse event to the scroll-bars might allow the user to cycle through to a 'proxy' of the the windowcontrols for all of the other windowframes open on the desktop (ie not docked) ...
this is broadly similar to the idea used when a keyboard command (eg alt-tab) is used to cycling through a (text) list of active processes or open files; except in this case, it is the direct manipulation of the intermediate object that allows the user to graphicaly click-thru down into windowframes underneath, rather than selecting an item indirectly from a pop-up textlist.
any thoughts? -
focus object selection methods thoughts
2002-06-22 10:20:56 psheldon [Reply | View]
I felt dwarfed by your discussion, however, applauding someone with greater gifts has shown me my own wisdom with Michele's post on drag enabling. I therefore applaud by "actively listening" to each of your points, only here it is actively writing.
...various levels of opacicty...
You introduced Aqua UI conventions for display ---context--- as opposed to merely being focused on forground window you get this context depth.
...'compress' multiple channels...
The quartz compositing with opacity depth cue lets the user have accessible channels in a context that, in effect, might be considered a compression much as an outliner. Compression (just as a channel you might tune in) means information accessibility, not necessarily information there.
...this access method is only one-way...
What desktop metaphor can be used to coordinate this learning to see in 3D with learning to control in 3D so us kittens with blinders really learn to see 3D context.
...existing aqua conventions still force us to wade through the windowframes manually...
I could imagine a widget that would present the layers of windows in their order and then on mouseover event mark the window for a click to make it foreground. That would be a nice 3D desktop metaphor involving only a 1D widget to compliment the 2D desktop.
...cocoa delegate method to gather-up all the context information...
In the old os 9 there is something called a window list attached to the app. I suspect Next Step has a similar thing in os x. That has gathered up the information.
...aqua widget that overridges one of the windowframe controls...
A neat confusing of words overrides for overridges that precisely captures the flow of your thoughts. Perhaps this should be called the overridges override of the windowframe controls.
...alt_mouse event to the scroll-bars...
Don't like it attached to a particular window, but where would I like to send the alt_mouse event to?
What of a special menu with mouseover event marking window as augmenting Aqua UI conventions?
;-)
-
help viewer shows "better" than help viewer
2002-05-21 07:40:23 psheldon [Reply | View]
We get comfortable techniques and don't read all the introductions to instructions all that much. I just learned something from an introduction.
Click on Help Viewer then on link, Developer Help Center, then link, Using Developer Documentation. About 3 inches down comes a paragraph, From the Code Editor. Evidentally, from the code, you can press option key down and double click and that takes you to the project builder's help html browser to the precise spot on the page of the code item. Again, unlike Help Viewer, links go to the spot on a page. Further find is enabled and the text is copy/pastable into your own notes.
-
Initial Window and Large images
2002-05-17 21:52:48 johnts [Reply | View]
I noticed now, when the app starts, there is a really, tiny, empty window on the screen - maybe 10 pixels wide.
Also, if an image is opened, that is larger then the screen, it is pushed over too far to the right and too far down, even going behing the dock (my dock is on the bottom).
jt -
Initial Window and Large images, noticed too, amplifying with further observations
2002-05-20 08:29:28 psheldon [Reply | View]
The initial window has no initial picture to define it's size. I suspect that is why a thin version appears. If I touch the grow region, it becomes accessible to dragging for a resize.
You observe large images having incorrect defaultFrame. I try to formulate a clear working or "not working" hypothesis. Since NSWindow allegedly declares as implemented by the delegates developed method, some code in NSWindow supplying defaultFrame to our procedure has a bug. It seems to me you found a bug in the cocoa frameworks.
I didn't know where to get images larger than my screen to get any amplification on your observation of defaultFrame's errant behavior, however, I got some other odd (to my imperfect understanding) behavior.
I used the grow region and window titlebar drag region to make a stdFrame go bigger than screen and found no event excited the adjustment of origen and extent. I don't know on what event the redefinition of stdFrame is fired.
I am going to try adding the procedure to the last columns version that had an initial picture and Michele's drag and drop augmentation to see what I fall into serendipitously.
Help viewer NSWindow ask got me "Using window notifications and delegate methods" sounded like a Feb.20,2002 advertisement. Documentation of extremely complicated things must start out that way to give writers time to write and good readers who wish to participate with that documentation in a community must forgive this.
So I might physically hop around my developer cd's to see if there was a later installment and, multithreading my search strategy in my own brain's software, investigate what an indexed sherlock or marshmallow librarian can find me better than help viewer in the html doc's. That way I concurrently catch the possibility that later docs were already there and are not to be found on a newer cd. I call this a shallow search, not assuming that a solution is to be found in any one particular venue but executive timeslicing my efforts so as to insure "halting doesn't become a problem". -
windowWillUseStandardFrame in Help Viewer clarified my confusion
2002-05-20 13:20:58 psheldon [Reply | View]
I had hypothesized, incorrectly, that the little green glob toggled between stdFrame and defaultFrame. Not so. That early working hypothesis had blocked my understanding of what was going on. Help Viewer said defaultFrame provided by the sort of computer screen you are on (and, by my observations missing the too big picture you have, seemed, to my remiss observation, provided correctly by the call to delegate in NSWindow's machinary). stdFrame is the thing that fills the screen less dock and a little space on the bottom to grab at and activate the windows below.
Mike Beam had successfully reawakened with terse comments on delegates my urges toward hypertext. I had to read that passage over and over realizing it was seminal and wanting to get it right. My windowWillUseStandardFrame find confirmed a working hypothesis mnemonic : "A delegate owns his constituency as a commodity because he pays the price of pleasing them in his representation". My excitement here matches when Steve Weyer mentored me in newtonscript. He too built hypertext and would say terse things with suggested hypertext readings. With such people you don't feel like a pest, but actually useful. Good mentoring. Wish I could do that terse suggestive stuff more. I think you have to be really familiar with a language to get that provacative terse mentoring style.
I seem to be getting hope for such familiarity, even in my alternate physics ventures.
I tried two things,
1. reinstall of May 2002 developer cd and
2. adding the little green glob to the app with an initial picture and all of Michele's drag et al augmentation.
I tell about these numbered experiments below :
1. The reinstall window showed me zero k for all stuff including documentation. That was why I ignored the ungreyed checked documentation, sdk etc. Now I demanded restall of the ungreyed checked and it spent several minutes doing something, but the documentation that I said looked as sparse as a 20 Feb 2002 ad still looked as sparse. I was moved to "bounce elsewhere" to avoid "the halting problem".
2. I added textual code to the augmented last column's project and that code didn't work. I went in inspector attributes on the window and checked resize under controls. Appropriate connection to delegate file's owner was already there. The thin sliver of a window did not challenge my eyesight, since there was a default picture which gave the window its size. Otherwise, the code did work and as "badly" as before. So, there was no missing method to redraw the window after user's unintelligent dragging. I was moved to "bounce elsewhere" to avoid "the halting problem".
1. I suddenly took a leap out of generalities that had bought me "the ad" and instead asked Help Viewer about the method, windowWillUseStandardFrame. From the writeup I got that intelligent justification of stdFrame was handled, not user's unintelligent dragging and making his toggle wierd.
Neither help viewer nor current sherlock got me to the place of text searched for on a page, but only to the html page. In fact, sherlock wouldn't launch the browser from a double click on the html file. I suspect, from other bumping around, that aliasing and enabling inside sherlock goes wierd for docs inside package or bundle contents.
I had to open the volume from sherlock and have the finder click open in the browser. The finder had no knowledge of the contents sherlock had been looking for, so I got a whole page there at the top. I was forced to adapt and learn about the pages organization, that may have been bad or good, I suspect that sherlock 3, as spoken of in keynote, will amend my need to adapt. I may, however, want to adapt anyway, to learn about how some good writers organize a highly complex set of "digital assets".
;-)






It strikes me that making sure that part of the desktop is visible so that it can be clicked on to switch to the Finder is a hangover from OS 9 days. It is no longer necessary, since the Dock, which already reserves screen estate, has an icon which will achieve the same.