/* ** Newton Developer Technical Support Sample Code ** ** Thumbnail-1, Shows how to use clRemoteView with a "live" clEditView ** ** by Bob Ebert, Newton Developer Technical Support ** ** Copyright © 1995 by Apple Computer, Inc. All rights reserved. ** ** You may incorporate this sample code into your applications without ** restriction. This sample code has been provided "AS IS" and the ** responsibility for its operation is 100% yours. You are not ** permitted to modify and redistribute the source as "DTS Sample Code." ** If you are going to re-distribute the source, we require that you ** make it clear in the source that the code was descended from ** Apple-provided sample code, but that you've made changes. */ This sample illustrates several useful things. 1) how to use a clRemoteView to do scaling. 2) how to hook a clRemoteView up to a clEditView (which takes extra work) 3) RecToggle, Status Bar buttons, Hardware Independent Sizing, etc. HOW TO USE A CLREMOTEVIEW TO DO SCALING clRemoteView is a very special purpose view class. It draws its first child view with that child's visible area scaled to fit exactly within the remote view's visible area. In the current release (1.3 as of this sample), clRemoteViews can only be used to shrink their children, they cannot be used to magnify. clRemoteView works by setting up an internal transformation when the view is opened, based on the child view's coordinates and it's coordinates. This transform is used when drawing the view's children, which results in scaling. Because clRemoteView bases its transform on the first child, and draws only the first child, errors result if you try to give a clRemoteView more than one (or less than one) child. Lemma: clRemoteViews must have exactly one child. Because clRemoteView only sets up this transform information when it is first opened, moving the view or its children causes strange results. Lemma: Whenever you move a clRemoteView on the screen, you must close and re-open it or it will not draw properly. (If you'd like to experiment with "improper" drawing, try commenting out the lines that close and re-open theRemoteView inside theFloater's viewClickScript, and comment in the line that has theRemoteView:Dirty) That's all there is to using a clRemoteView. Give it a child and open it. HOW TO HOOK A REMOTE VIEW UP TO AN EDIT VIEW A common thing to want to do is to set up the contents of a clRemoteView at run-time, possibly based on the contents of some other view, like a clEditView. Print Preview, for example, uses a clRemoteView with a print format child to show a thumbnail view of the printed page. A common clRemoteView-related mis-conception is that you can "point" the remote view at another view, that is, put some other view in the remote view's viewChildren or stepChildren slot, and it will scale that other view into itself. This is false. Just like any other view class, a clRemoteView creates its children when it is opened, and closes them when it is closed. If you try to put a view frame (as opposed to a template) in the viewChildren or stepChildren slot of a remote view, you'll get bus errors and other nasty view system exceptions. Don't do this. (For further reading on views vs templates, I highly recommend the article "Tales from the View System") Recall that clEditViews work by creating new clParagraph and clPolygon view children to hold the text, shapes, and ink that users create. You can get templates for these dynamically-created children by looking the 'viewChildren slot of the clEditView. To make a clRemoteView reflect a "live" clEditView, we share the templates between the edit and the remote view. That is, when we open the remote view, we set it's child's viewChildren slot to the same array that is in the clEditView's viewChildren frame. Normally this could prevent quite a problem, but clRemoteViews are "read only" and so we don't need to worry about both views trying to update the same array. If you look at theRemoteView's viewSetupChildrenScript, you'll see how this is done. The remote view's child is a clView with the viewFormat, viewLineSpacing, and viewChildren slots copied from the (open) clEditView. This is all OK. But it's actually more complicated than that, because of a clRemoteView bug. To explain the bug, I need to describe a view system optimization. clParagraphViews are expensive, and so the view system attempts to avoid drawing them when they are not visible. To figure out if a view is visible, the current system looks at the bounds of the view's parent and the view's grandparent. (Only two layers are looked at--another optimization.) If the paragraph view is not within the bounds of its parent or grandparent, it is not displayed. Unfortunately, the clRemoteView's bounds are usually significantly smaller than the bounds of it's child. It must be that way for scaling to happen. The view system optimization that prevents drawing "clipped" views doesn't take into account the transformation that clRemoteViews add, and so text views inside the clRemoteView's "scaling" child may not show up. To fix up this little optimization (which really helps most places) we have to add two new layers between the remote view and the "scaling" child. These wrapper views provide a parent and a grandparent to the scaling child, which fools the view system into thinking that all the children of the scaling view really are visible, and so they're drawn, scaled, into the clRemoteView. (Without this, the text children only show up if they're in the upper left-hand corner of the scaling child. You can experiment with this behavior by commenting out one (or both) of the "wrapper" children in theRemoteView's viewSetupChildrenScript.) These "wrapper" views aren't used for anything else, they're just there to fool the view system optimizer, and so it's best to make them as "lightweight" as possible. Plain old clViews with minimal formatting work well. RECTOGGLE, STATUS BAR BUTTONS, HARDWARE INDEPENDENT SIZING, ETC. The sample attempts to follow all known style guidelines. So the edit view uses vAnythingAllowed, and we provide a protoRecToggle inside the status bar. Similarly the "Thumbnail" button is sibling-justified to the close box. Finally the main app's viewSetupFormScript takes into account the varying sizes and does the right thing.