Drawing the Part
Every part editor must implement itsDraw
method so it can display the visible portion of its content on demand, in response to theDraw
call. Most part editors perform drawing of their content synchronously; that is, they allow OpenDoc to call theDraw
method of their part editor object (ODPart
subclass). OpenDoc calls theDraw
method whenever portions of the document are marked invalid, as when the user scrolls a part's content into view. However, part editors can also draw asynchronously by calling their ownDraw
method. For example, a part that represents a clock would need to update and redraw its display every second.To display its content, a part must have at least one frame, and it may have more than one frame, even in a single window. Part editors can display their content in different frames simultaneously, and they can display them differently in the same frame at different times.
During drawing, the part editor is responsible for examining the frame and displaying the correct information in the frame, properly transformed and clipped. If additional information is needed to perform rendering properly, the part editor may store it in the part info field of the frame or the facet.
The proper way to render a part on a particular display device may also vary depending on whether the device is static or dynamic. A part editor can use the
isDynamic
flag of the canvas object to determine the nature of the interaction style and draw its part accordingly. For example, it may draw scroll bars on a dynamic canvas but omit them for a static one.The basic steps to perform in drawing are as follows:
In SamplePart, these steps are accomplished by the
- Prepare the platform graphics environment for drawing.
- Get the view type, the presentation if required, and any other information needed to determine the proper display method, such as selection state, highlight state, and the state of the stationery flag.
- Render the content appropriately.
- Restore the old graphics environment.
Draw
method and three subroutine methods to handle the four standard view types: frame, large icon, small icon, and thumbnail. In addition,SamplePart
has methods that prepare for drawing and handle various other situations affecting imaging behavior. The following sections discuss these methods.The Draw Method
OpenDoc calls the part object'sDraw
method whenever a facet of a part's display frame intersects the invalidated portion of an OpenDoc window. Parts may call their ownDraw
method whenever their content needs to be rendered onto a canvas.The
SamplePart
object's implementation of theDraw
method performs the following actions:
Listing 2-15 shows the implementation of the
- Focuses the Mac OS drawing environment.
TheSamplePart
object'sDraw
method focuses the Mac OS QuickDraw port, origin, and clip shape for drawing in the facet passed into theDraw
method. SamplePart accomplishes this by instantiating a stack-based object (here namedinitiateDrawing
) of classCFocus
, which is defined in the OpenDoc utility file FocusLib.cpp. TheCFocus
constructor saves the old port, origin, and clip shape and sets the new ones properly. At the end of theDraw
method, when control passes out of its scope, theCFocus
object is automatically deleted, and its destructor restores the port, origin, and clip shape previously in force.
- Gets the view type of the frame to which the current facet belongs.
The method gets a pointer to the frame from the facet, a pointer to which is passed in from OpenDoc with theDraw
call. The frame is queried for its view type.
- Draws the part's content appropriately for the view type.
SamplePart has a separate method for each view type that can draw its content properly, and it branches to the appropriate one.
Draw
method.
void SamplePart::Draw( Environment* ev, ODFacet* facet, ODShape* invalidShape ) { SOM_Trace("SamplePart","Draw"); CFocus initiateDrawing(ev, facet, invalidShape); ODTypeToken view = facet->GetFrame(ev)->GetViewType(ev); if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView ) this->DrawIconView(ev, facet); else if ( view == gGlobals->fThumbnailView ) this->DrawThumbnailView(ev, facet); else this->DrawFrameView(ev, facet); }The DrawIconView Method
TheSamplePart
object's internalDrawIconView
method draws an appropriate version of the frame's icon.The
DrawIconView
method performs the following actions:
Listing 2-16 shows the implementation of the
- Sets the icon transform type.
The method checks the facet's highlight state. If the facet is highlighted, the method will display the selected version of the icon. If a part window exists, it will display the version of the icon indicating that it is also open.
- Draws the icon.
The method sets the size of the rectangle in which to display the icon correctly and calls the Mac OS Toolbox routinePlotIconID
to draw the correct version of the icon according to its icon transform type. Large icons are drawn in a 32-by-32-pixel rectangle; small icons are drawn in a 16-by-16-pixel rectangle.
DrawIconView
method.Listing 2-16
DrawIconView
method
void SamplePart::DrawIconView( Environment* ev, ODFacet* facet ) { SOM_Trace("SamplePart","DrawIconView"); Rect iconRect; IconTransformType transformType = ttNone; CFrameInfo* frameInfo; ODFrame* frame; ODTypeToken viewType; frame = facet->GetFrame(ev); viewType= frame->GetViewType(ev); frameInfo = (CFrameInfo*) frame->GetPartInfo(ev); if ( facet->GetHighlight(ev) == kODFullHighlight ) transformType = ttSelected; if ( frameInfo->HasPartWindow() && frameInfo->GetPartWindow()->IsShown(ev) ) transformType |= ttOpen; if ( viewType == gGlobals->fLargeIconView ) SetRect(&iconRect, 0, 0, kODLargeIconSize, kODLargeIconSize); else // ( viewType == gGlobals->fSmallIconView ) SetRect(&iconRect, 0, 0, kODSmallIconSize, kODSmallIconSize); CUsingLibraryResources res; PlotIconID(&iconRect, atAbsoluteCenter, transformType, kBaseResourceID); }The DrawThumbnailView Method
Normally, a thumbnail view of a frame is a 64-by-64-pixel representation of its actual content. However, SamplePart has no intrinsic content, so itsDrawThumbnailView
method simply displays a'PICT'
resource, a handle to which was previously stored in thefThumbnail
field of the part's global variable structure. The same strategy is appropriate for parts that have been newly created from stationery and have no content yet. When the user has added content a "real" thumbnail can be created.The
DrawThumbnailView
method performs the following actions:
Listing 2-17 shows the implementation of the
- Sets the bounding rectangle of the thumbnail.
The method retrieves the bounding rectangle of the thumbnail picture resource by dereferencing its handle and sets the drawing offset accordingly.
- Draws the picture.
The method calls the QuickDraw routineDrawPicture
to draw the picture resource at the proper position.
DrawThumbnailView
method.Listing 2-17
DrawThumbnailView
method
void SamplePart::DrawThumbnailView( Environment*ev, ODFacet*/*facet*/ ) { SOM_Trace("SamplePart","DrawThumbnailView"); LoadThumbnail(ev, &gGlobals->fThumbnail); Rect bounds = (**(PicHandle) gGlobals->fThumbnail).picFrame; OffsetRect(&bounds, -bounds.left, -bounds.top); DrawPicture((PicHandle) gGlobals->fThumbnail, &bounds); }The DrawFrameView Method
The implementation of theSamplePart
object's internalDrawFrameView
method (called by the part'sDraw
method) renders the full content view of the part when the view type is frame. SamplePart has no intrinsic content; the frame view simply draws two text strings with stylistic variations.The
DrawFrameView
method performs the following actions:
Listing 2-18 shows the implementation of the
- Gets the facet's frame and canvas, the frame shape, and the QuickDraw region of the frame area.
The method uses the facet passed as a parameter to get the frame. If the frame has a source frame, the method uses the source frame instead. The method gets a reference to the facet's canvas, which represents its underlying platform-specific drawing system (QuickDraw), so that the frame shape is returned in the correct coordinate system. The method then gets the shape and QuickDraw region of the frame.
- Sets the font characteristics.
The method calculates the height of the frame and sets the font size to 80% of the frame height. Then it sets the font to be the default application font for the current script system and sets its variation to be bold and condensed.
- Gets the text string to be drawn.
Before acquiring the string resource to draw, you must set up the resource chain so the resources contained in your dynamic library are available. This is handled in theDrawFrameView
method by the OpenDoc utility routineBeginUsingLibraryResources
, which is defined in the file UseRsrcM.cpp. At this point the method saves the QuickDraw pen state and resets it to normal, acquires the individual string from the resource, and moves the pen to an appropriate baseline position in preparation for drawing the text.
- Draws the text.
The method calls the QuickDraw routineDrawString
to render a text string acquired from its string resource onto the screen, using the font characteristics calculated previously. If the facet's highlight state iskODFullHighlight
, indicating that the part is selected, the method fills in the background of the drawing port with the highlight color. The method then draws another text string acquired from its string resource, this time at the fixed point size of 24 points, centered in the frame, and in color reversed from its background.
- Restores the resource chain and port characteristics.
The method callsEndUsingLibraryResources
to restore the resource chain as configured prior to callingBeginUsingLibraryResources
. You must call the ending routine if you have called the beginning routine, so you must not throw an exception between the two calls. If an exception is likely, therefore, you should save it and throw it after callingEndUsingLibraryResources
. Last, the method restores the QuickDraw graphics port and resets its text font, size, and variation.
DrawFrameView
method.Listing 2-18
DrawFrameView
method
void SamplePart::DrawFrameView( Environment* ev, ODFacet* facet ) { SOM_Trace("SamplePart","DrawFrameView"); ODFrame* frame; ODUShort frameHeight = 0; ODUShort frameWidth = 0; RgnHandle frameRgn; FontInfo finfo; Str63 defaultString; CFrameInfo* frameInfo; GrafPtr port; GetPort(&port); EraseRect(&port->portRect); frameInfo = (CFrameInfo*) facet->GetFrame(ev)->GetPartInfo(ev); if ( frameInfo->HasSourceFrame() ) frame = frameInfo->GetSourceFrame(ev); else frame = facet->GetFrame(ev); ODCanvas* biasCanvas = facet->GetCanvas(ev); TempODShape frameShape = frame->AcquireFrameShape(ev, biasCanvas); frameRgn = frameShape->GetQDRegion(ev); frameHeight = (**frameRgn).rgnBBox.bottom - (**frameRgn).rgnBBox.top; frameWidth = (**frameRgn).rgnBBox.right - (**frameRgn).rgnBBox.left; ODUShort size = port->txSize; ODUShort font = port->txFont; Style face = port->txFace; TextSize((ODUShort)(frameHeight * 0.8)); TextFont(1); TextFace(bold + condense); GetFontInfo(&finfo); ODSLong rfRef; rfRef = BeginUsingLibraryResources(); { PenState penState; GetPenState(&penState); PenNormal(); GetIndString(defaultString, kMenuStringResID, kDefaultContent1ID); MoveTo((frameWidth / 2) - (StringWidth(defaultString) / 2), frameHeight - (finfo.descent - 2)); DrawString(defaultString); if ( facet->GetHighlight(ev) == kODFullHighlight ) { UInt8 mode = LMGetHiliteMode(); BitClr(&mode,pHiliteBit); LMSetHiliteMode(mode); InvertRect(&port->portRect); } TextMode(srcXor); TextSize(24); TextFace(bold + extend); GetIndString(defaultString, kMenuStringResID, kDefaultContent2ID); MoveTo((frameWidth / 2) - (StringWidth(defaultString) / 2), (frameHeight / 2) + 6); DrawString(defaultString); SetPenState(&penState); } EndUsingLibraryResources(rfRef); // Restore port chararcteristics. SetPort(port); port->txSize = size; port->txFont = font; port->txFace = face; }The ViewTypeChanged Method
OpenDoc calls a part'sViewTypeChanged
method when the view type of one of the part's display frames has been modified, such as when the user changes the view type in the Part Info dialog box. In general, theViewTypeChanged
method should set up the facilities needed for a part to display itself with a particular view type.The
SamplePart
object's implementation of theViewTypeChanged
method performs the following actions:
Listing 2-19 shows the implementation of the
- Gets the view type of the frame.
For this purpose, theODFrame
class provides aGetViewType
method, which returns a tokenized string representing the view type.
- If thumbnail is the view type, prepares the thumbnail view.
In this case,ViewTypeChanged
calls theSamplePart
object's internal methodGenerateThumbnail
. TheGenerateThumbnail
method creates a 64-by-64-pixel representation of the current display frame. In SamplePart, this method calls the SamplePartutility method
LoadThumbnail
, which simply returns a handle to a preexisting'PICT'
resource. The method puts a pointer to the thumbnail into the global variables structure. If theGenerateThumbnail
method is unable to load the resource for some reason, it defaults to the regular frame view and throws the error returned by the Resource Manager as an exception (or, if there is no Resource Manager error, the method throws theresNotFound
error).
- Changes the frame's used shape to match the new view type.
The method calls theSamplePart
object's internal methodCalcNewUsedShape
to calculate the appropriate used shape for the new view type. If the view type is frame view, theCalcNewUsedShape
method intentionally returns a null used shape, which resets the used shape to exactly the frame shape. Otherwise, theCalcNewUsedShape
method returns a used shape equal to the appropriate icon or thumbnail view.
- Invalidates the frame.
TheViewTypeChanged
method invalidates the frame, calls the frame'sChangeUsedShape
method with the new used shape, and then invalidates the frame again.
ViewTypeChanged
method, Listing 2-20 shows theGenerateThumbnail
method, Listing 2-21 shows theLoadThumbnail
method, and Listing 2-22 shows theCalcNewUsedShape
method.Listing 2-19
ViewTypeChanged
method
void SamplePart::ViewTypeChanged( Environment* ev, ODFrame* frame ) { SOM_Trace("SamplePart","ViewTypeChanged"); ODTypeTokenview = frame->GetViewType(ev); if ( view == gGlobals->fThumbnailView ) this->GenerateThumbnail(ev, frame); TempODShape newUsedShape = this->CalcNewUsedShape(ev, frame); frame->Invalidate(ev, kODNULL, kODNULL); frame->ChangeUsedShape(ev, newUsedShape, kODNULL); frame->Invalidate(ev, kODNULL, kODNULL); }Listing 2-20GenerateThumbnail
method
void SamplePart::GenerateThumbnail( Environment* ev, ODFrame* frame ) { SOM_Trace("SamplePart","GenerateThumbnail"); LoadThumbnail(ev, &gGlobals->fThumbnail); if ( gGlobals->fThumbnail == kODNULL ) { frame->ChangeViewType(ev, gGlobals->fFrameView); THROW_IF_ERROR((ODError)ResError()); THROW(resNotFound); } }Listing 2-21LoadThumbnail
method
void LoadThumbnail(Environment* ev, Handle* thumbnail) { if ( *thumbnail ) return; ODSLong rfRef; rfRef = BeginUsingLibraryResources(); { *thumbnail = (Handle) GetPicture(kThumbnailPicture); } EndUsingLibraryResources(rfRef); }Listing 2-22CalcNewUsedShape
method
ODShape* SamplePart::CalcNewUsedShape( Environment* ev, ODFrame* frame ) { SOM_Trace("SamplePart","CalcNewUsedShape"); ODShape* usedShape = kODNULL; ODVolatile(usedShape); RgnHandle usedRgn; ODVolatile(usedRgn); ODTypeToken view = frame->GetViewType(ev); if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView || view == gGlobals->fThumbnailView ) { TRY Rect bounds; usedRgn = ODNewRgn(); if ( view == gGlobals->fLargeIconView || view == gGlobals->fSmallIconView ) { CUsingLibraryResources res; SetRect(&bounds, 0, 0, (view == gGlobals->fLargeIconView) ? kODLargeIconSize : kODSmallIconSize, (view == gGlobals->fLargeIconView) ? kODLargeIconSize : kODSmallIconSize); THROW_IF_ERROR( IconIDToRgn(usedRgn, &bounds, atAbsoluteCenter, kBaseResourceID) ); } else if ( view == gGlobals->fThumbnailView ) { bounds = (**(PicHandle)gGlobals->fThumbnail).picFrame; RectRgn(usedRgn,&bounds); } usedShape = frame->CreateShape(ev); usedShape->SetQDRegion(ev, usedRgn); CATCH_ALL ODSafeReleaseObject(usedShape); ODDisposeHandle((ODHandle)usedRgn); usedShape = kODNULL; ENDTRY } return usedShape; }The GeometryChanged Method
OpenDoc calls theGeometryChanged
method when the external transform or clip shape of a facet belonging to the part's display frame changes. The only action of theSamplePart
object's implementation of the method is to invalidate the clip shape of the facet, causing it to be redrawn.Listing 2-23 shows the implementation of the
GeometryChanged
method.Listing 2-23
GeometryChanged
method
void SamplePart::GeometryChanged( Environment* ev, ODFacet* facet, ODBoolean clipShapeChanged, ODBoolean /* externalTransformChanged */ ) { SOM_Trace("SamplePart","GeometryChanged"); if ( clipShapeChanged ) facet->Invalidate(ev, kODNULL, kODNULL); }The HighlightChanged Method
OpenDoc calls a part'sHighlightChanged
method when the highlight state of one of its display frame's facets changes. The method is responsible for redrawing the facet's content with highlighting that is consistent with that of the containing part in which this part is embedded.The
SamplePart
object's implementation of theHighlightChanged
method gets a reference to the facet's frame, then (if its view type is not a frame view) simply invalidates the frame, causing its content to be redrawn. If the frame's view type is a frame view, the method does nothing.Listing 2-24 shows the implementation of the
HighlightChanged
method.Listing 2-24
HighlightChanged
method
void SamplePart::HighlightChanged(Environment* ev, ODFacet* facet) { ODFrame* frame = facet->GetFrame(ev); if ( frame->GetViewType(ev) != gGlobals->fFrameView ) frame->Invalidate(ev, kODNULL, kODNULL); }The FacetAdded Method
OpenDoc calls theFacetAdded
method when the containing part (or OpenDoc) adds a facet to one of the part's display frames. The part's basic responsibility in response to theFacetAdded
method call is to prepare to draw the content visible in the new facet.The
SamplePart
object's implementation ofFacetAdded
retrieves the facet's frame and the frame's info object. If the facet's frame is the root frame of a window, the method marks the frame for activation whenever the window is selected.Finally, the method handles the possibility of the frame having a hidden part window. If the frame had become invisible previously, it would have hidden any part window it had. Therefore, the method checks to see if this is the first facet added to the frame, indicating that it is just becoming visible; if so, and if the frame has a part window, the method shows the part window.
Listing 2-25 shows the implementation of the
FacetAdded
method.Listing 2-25
FacetAdded
method
void SamplePart::FacetAdded( Environment* ev, ODFacet* facet ) { SOM_Trace("SamplePart","FacetAdded"); ODFrame* frame = facet->GetFrame(ev); CFrameInfo* frameInfo = (CFrameInfo*) frame->GetPartInfo(ev); if ( frame->IsRoot(ev) ) { frameInfo->SetActiveFacet(facet); frameInfo->SetFrameReactivate(kODTrue); } if ( (CountFramesFacets(ev, frame) == 1) ) { TempODWindow window = frameInfo->AcquirePartWindow(ev); if ( window ) window->Show(ev); } }The FacetRemoved Method
OpenDoc calls a part'sFacetRemoved
method when the containing part or OpenDoc removes a facet from one of this part's display frames.The
SamplePart
object's implementation ofFacetRemoved
retrieves the facet's frame, and, if the frame indicates that this is the active facet, the method marks that indication false. Finally, if the facet being removed is the last facet belonging to its frame, and if its containing frame is null, the method hides the frame's part window, if it has one.Listing 2-26 shows the implementation of the
FacetRemoved
method.Listing 2-26
FacetRemoved
method
void SamplePart::FacetRemoved( Environment* ev, ODFacet* facet ) { SOM_Trace("SamplePart","FacetRemoved"); ODFrame* frame = facet->GetFrame(ev); TempODFramecontainingFrame = frame->AcquireContainingFrame(ev); CFrameInfo*frameInfo = (CFrameInfo*) frame->GetPartInfo(ev); if ( ODObjectsAreEqual(ev, frameInfo->GetActiveFacet(), facet) ) frameInfo->SetActiveFacet(kODNULL); if ( (CountFramesFacets(ev, frame) == 0) && (containingFrame == kODNULL) ) { TempODWindow window = frameInfo->AcquirePartWindow(ev); if ( window ) window->Hide(ev); } }
Main | Page One | What's New | Apple Computer, Inc. | Find It | Contact Us | Help