Hello World: Part II, OpenDoc Views and Presentation Types

From EDM2
Jump to: navigation, search

by Robert Tycast

In this second instalment in our series of OpenDoc sample part code, we forge onward, taking the "Hello World" OpenDoc part presented in the last issue of The Developer Connection News and adding support for the standard four view types:

  • Frames
  • Large Icons
  • Small Icons
  • Thumbnails

First, a brief explanation of the concepts involved is in order:

Presentation Types

Presentation types are defined by OpenDoc parts corresponding to the various forms in which their data is rendered. For instance, a spreadsheet part may be able to render its data as a bar graph or a pie chart, in addition to the more familiar tabular form. Thus, the spreadsheet would be said to support three presentation types bar, pie, and table. Likewise a word processor could support an outline presentation as well as the standard draft. In any case, it's up to the part developer to decide how many and what presentation types a part supports.

View Types

OpenDoc defines four standard view types. While the part is free to support more view types, it must support the four standard ones Like the presentation type, the view type specifies how the part renders itself. But while the presentation type is a property of the part, a view type is more a property of the container into which the part is embedded. Parts can and should set the view type they prefer when a frame is embedded into them. The embedded part should then oblige.

  • Frame View Type - This is the most common view type and the one with which you are already familiar. When this view type is set, the part is free to render its content in the manner most natural to it (subject, of course, to its presentation type). Most documents have their embedded parts displayed as frames by default.
  • Small and Large Icon View Types - Icons have become a familiar way to compactly represent objects on a desktop. Minimized windows are presented this way as well as various objects in folder views OpenDoc documents can include parts that act as specialized containers, analogous to folders. Parts within these containers should render themselves as icons It is the container s job to make sure the parts get the message and, in turn, it's up to the parts to comply. The container communicates this information to the part via the frame. Whenever a new frame is added, the container sets the view type to either icon view (which corresponds to a 32x32 bitmap) or small icon view (a 16x16 bitmap) if space is limited.
  • Thumbnails - OpenDoc prescribes a special representation called a thumbnail view. A thumbnail is a miniature rendering of the part s content in a 64x64 space. It s up to the part to decide just how to implement a thumbnail. The major point to keep in mind is that a thumbnail is more closely related to a frame view than it is to an icon view. Implementing a thumbnail simply as a double-sized icon, while tempting in its simplicity, is clearly not within the spirit of a thumbnail.

Why do thumbnails? It turns out that many human factors studies have shown that users are very good at sorting data if they have good visual cues. Thumbnails, even though they are small representations of content, give users just the kind of visual information they need. Of course, there are other ways to use thumbnails This is just one example.

Implementing View Types

Now that you know what view types are, let s dive into the code and see how to implement them.

The first step is to define tokens for the four different view types. Tokens provide a shorthand way to refer to thumbnails, icons, and frames in the code.

Note: The source code referred to in this article can be found in the "Source Code from The Developer Connection News" category on your Developer Connection CD-ROM, disc 1.

In HELLO.IDL we define the following variables:

ODTypeToken         FrameView;
ODTypeToken         LargeIconView;
ODTypeToken         SmallIconView;
ODTypeToken         ThumbnailView;

In HELLO.CPP we initialize them. This can be done at part initialization.

somThis->Session        = su->GetSession(ev);
somThis->FrameView      = somThis->Session->Tokenize(ev, kODViewAsFrame);
somThis->LargeIconView  = somThis->Session->Tokenize(ev, kODViewAsLargeIcon);
somThis->SmallIconView  = somThis->Session->Tokenize(ev, kODViewAsSmallIcon);
somThis->ThumbnailView  = somThis->Session->Tokenize(ev, kODViewAsThumbnail);

Within our part we have four private methods to handle the four cases. We'll call them (appropriately) DrawFrameView, DrawIconView, DrawSmallIconView, and DrawThumbnailView. In IDL we code the following:

void    DrawFrameView(in ODFacet facet);
void    DrawIconView(in ODFacet facet);
void    DrawSmallIconView(in ODFacet facet);
void    DrawThumbnailView(in ODFacet facet);

In HELLO.CPP the original HelloPartDraw routine becomes our DrawFrameView method. Then in HelloPartDraw we add the following code, which determines the correct drawing routine for the view type.

ODFrame* frame = facet->GetFrame(ev);
ODTypeToken view = frame->GetViewType(ev);
if      ( view == somThis->FrameView )     somSelf->DrawFrameView(ev, facet);
else if ( view == somThis->LargeIconView ) somSelf->DrawIconView(ev, facet);
else if ( view == somThis->SmallIconView ) somSelf->DrawSmallIconView(ev,facet);
else if ( view == somThis->ThumbnailView ) somSelf->DrawThumbnailView(ev,facet);

Supporting the Icon View Types

Apart from their size differences, large and small icons are handled almost the same way. Large icons are displayed in a 32x32 pel square, while small icons use a quarter of that area (16x16). A bitmap called HELLO.BMP has been created with the icon editor utility The resource compiler and linker bind the bitmap to HELLO.DLL The bitmap is referred to in the code as IDB_BMP1, a value that we define in our header file, HELLO.H.

#define  IDB_BMP1         100

and in the resource definition file, HELLO.RC.

BITMAP  IDB_BMP1      hello.bmp

To display the icon, we use Presentation Manager (PM) routine, GpiWCBitBlt even though a WinDrawBitmap call would be more convenient. This is so that when we implement printing in a later version of our part, the icon can be rendered to a printer as well as to the screen.

ODFrame* displayFrame = facet->GetFrame(ev);
ODRect rect;
displayFrame->GetUsedShape(ev)->GetBoundingBox(ev,  rect);
ODRECTL frameRect(rect);
HBITMAP hbm, hbmNew, hbmOld;
POINTL aptl[4], ptl = {frameRect xright, frameRect yTop};
somSelf->SetOrigin(ev, facet);
DosQueryModuleHandle(hello, hmodDLL);
HPS hps = facet->GetCanvas(ev)->GetPlatformCanvas(ev);
hbm = GpiLoadBitmap(hps, hmodDLL, IDB_BMP1, size, size);

bmp cbFix = sizeof(bmp);
GpiQueryBitmapInfoHeader(hbm, bmp);
   aptl[0] x = frameRect xLeft;
   aptl[0] y = frameRect yBottom;
   aptl[1] x = frameRect xRight;
   aptl[1] y = frameRect yTop;
   aptl[2] x = aptl[2] y = 0;
   aptl[3] x = bmp cx;
   aptl[3] y = bmp cy;

GpiWCBitBlt(hps, hbm, 4, aptl, ROP_SRCCOPY, BBO_IGNORE);

Handling ViewTypeChanged

ViewTypeChanged is an ODPart method we need to support our new views. It's here that we do any setup necessary for the view type. For icons, we set our used shape to the size of the icon, and then invalidate our containing frame to make sure that our draw routine gets called We force our container to recalculate its clipping to correspond to our new used shape before it redraws itself.

ODShape* newUsedShape = new ODShape();

ODRect thumbNailRect = { 0, MAKEFIXED(32,0), MAKEFIXED(32,0),0};
newUsedShape->SetRectangle(ev,  thumbNailRect);
facet->GetFrame(ev)->ChangeUsedShape(ev, newUsedShape);

Simple Thumbnails

For a simple implementation of a thumbnail, get a reduced used shape and redraw the frame by calling the DrawFrameView method directly:

somSelf->DrawFrameView(ev, facet);

This technique is simple appropriate for some types of parts. But with a part like Hello World, most of the content will be clipped away. As a result, it will be difficult to tell our thumbnail from that of a normal container part. For a large category of parts and part content, we need a different implementation of thumbnails.

Scaled Thumbnails

A better way to implement thumbnails (on systems that support scaling transforms) is to scale the part s rendering so that it fits the 64x64 square specified for thumbnails. We can use the PM graphics engine s scaling transforms for our thumbnails.

else if ( view == somThis->ThumbnailView )
ODShape* newUsedShape = new ODShape();
newUsedShape->SetRectangle(ev,  thumbNailRect);
frame->ChangeUsedShape(ev, newUsedShape);
somSelf->CalcAndSetScalingTransform(ev, frame, view);

The internal method CalcAndSetScalingTransform creates the scaling factor we need to fit our current content into a 64x64 square.

ODShape* frameShape = frame->GetFrameShape(ev);
ODTransform* scaledTransform = new ODTransform;
ODFixed thumbnailSize = MAKEFIXED(64,0);
ODTransform* internalTransform;
ODPoint scale;
ODFixed bottom;
ODFixed side;
ODFloat m;
ODFloat n;
ODFloat ratio;
ODRect boundingBox;

internalTransform = frame->GetInternalTransform(ev);
frameShape->GetBoundingBox(ev,  boundingBox);

bottom = boundingBox right-boundingBox left;
side = boundingBox top-boundingBox bottom;
n = ODFixedToFloat(thumbnailSize);
if (side >= bottom) m = ODFixedToFloat(side);
 else  m = ODFixedToFloat(bottom);
ratio = m/n;

scale x = scale y = ODFloatToFixed(ratio);
scaledTransform->CopyFrom(ev, internalTransform); 

scaledTransform->ScaleDownBy( ev,  scale);
frame->ChangeInternalTransform( ev, scaledTransform);

Hello World II

Those are the basics Details can be found in the Hello World source on your accompanying Developer Connection for OS/2 CD-ROM Refer to the README file there and you ll do just fine And stay tuned for Hello World III!!!


Figure 1. Hello II as Frame, Thumbnail, Small, and Large Icon Views

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation