Retired Document
Important: This sample code may not represent best practices for current development. The project may use deprecated symbols and illustrate technologies and techniques that are no longer recommended.
HIEmbedder.cp
/* |
File: HIEmbedder.cp |
Contains: Demonstrates creating a simple embedder using the HIView APIs. |
Version: 1.0 |
Disclaimer: IMPORTANT: This Apple software is supplied to you by Apple Computer, Inc. |
("Apple") in consideration of your agreement to the following terms, and your |
use, installation, modification or redistribution of this Apple software |
constitutes acceptance of these terms. If you do not agree with these terms, |
please do not use, install, modify or redistribute this Apple software. |
In consideration of your agreement to abide by the following terms, and subject |
to these terms, Apple grants you a personal, non-exclusive license, under AppleÕs |
copyrights in this original Apple software (the "Apple Software"), to use, |
reproduce, modify and redistribute the Apple Software, with or without |
modifications, in source and/or binary forms; provided that if you redistribute |
the Apple Software in its entirety and without modifications, you must retain |
this notice and the following text and disclaimers in all such redistributions of |
the Apple Software. Neither the name, trademarks, service marks or logos of |
Apple Computer, Inc. may be used to endorse or promote products derived from the |
Apple Software without specific prior written permission from Apple. Except as |
expressly stated in this notice, no other rights or licenses, express or implied, |
are granted by Apple herein, including but not limited to any patent rights that |
may be infringed by your derivative works or by other works in which the Apple |
Software may be incorporated. |
The Apple Software is provided by Apple on an "AS IS" basis. APPLE MAKES NO |
WARRANTIES, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED |
WARRANTIES OF NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
PURPOSE, REGARDING THE APPLE SOFTWARE OR ITS USE AND OPERATION ALONE OR IN |
COMBINATION WITH YOUR PRODUCTS. |
IN NO EVENT SHALL APPLE BE LIABLE FOR ANY SPECIAL, INDIRECT, INCIDENTAL OR |
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE |
GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
ARISING IN ANY WAY OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION |
OF THE APPLE SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT, TORT |
(INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF APPLE HAS BEEN |
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
Copyright © 2003 Apple Computer, Inc., All Rights Reserved |
*/ |
#include <Carbon/Carbon.h> |
#include "HIEmbedder.h" |
#include "ShadeRect.h" |
#define kEmbedderDefaultHeight 1600.0 |
// structure in which we hold our custom push button's data |
typedef struct |
{ |
HIViewRef view; // the HIViewRef for our list |
HIPoint originPoint; |
} |
EmbedderData; |
pascal OSStatus ViewHandler(EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon); |
CFStringRef GetEmbedderClass(); |
/* |
* HICreateEmbedder() |
* |
* Summary: |
* Creates a simple embedder control. |
* |
* Parameters: |
* |
* outEmbedder: |
* On exit, contains the new control. |
* |
* Availability: |
* Mac OS X: in version 10.2 and later since it needs the HIView APIs |
* CarbonLib: not available |
* Non-Carbon CFM: not available |
*/ |
extern OSStatus |
HICreateEmbedder(HIViewRef * outEmbedder) |
{ |
*outEmbedder = NULL; |
HIObjectRef hiObject; |
OSStatus status = HIObjectCreate(GetEmbedderClass(), 0, &hiObject); |
if (status != noErr) goto exitCreate; |
HIViewSetVisible((HIViewRef)hiObject, true); |
*outEmbedder = (HIViewRef)hiObject; |
exitCreate: |
return status; |
} |
UInt32 GetHIToolboxVersion() |
{ |
CFBundleRef bundle; |
CFStringRef versionStr = NULL; |
static UInt32 version = 0; |
if (version != 0) return version; |
bundle = CFBundleGetBundleWithIdentifier( CFSTR("com.apple.HIToolbox") ); |
if ( bundle != NULL ) |
versionStr = (CFStringRef) CFBundleGetValueForInfoDictionaryKey( bundle, CFSTR("CFBundleShortVersionString") ); |
if ( versionStr != NULL && CFGetTypeID( versionStr ) == CFStringGetTypeID() ) |
{ |
int major = 0, minor = 0, bugfix = 0; |
char sz[20]; |
CFStringGetCString( versionStr, sz, sizeof( sz ), kCFStringEncodingUTF8 ); |
sscanf( sz, "%d.%d.%d", &major, &minor, &bugfix ); |
version = ( major << 8 ) + ( minor << 4 ) + bugfix; |
} |
return version; |
} |
OSStatus EmbedderViewDrawing(CGContextRef context, const HIRect * bounds, const EmbedderData * myData) |
{ |
HIRect FullBounds = { {0.0, 0.0}, {1000.0, kEmbedderDefaultHeight}}; |
// Alpha shading working only in Panther |
CGRGB inStartColor = {1.0, 0.0, 0.0, 0.8}, inEndColor = {0.0, 0.0, 1.0, 0.8}; |
ShadeRectColor(&inStartColor, &inEndColor, &FullBounds, context); |
return noErr; |
} |
/*----------------------------------------------------------------------------------------------------------*/ |
// ¥ GetEmbedderClass |
// Registers and returns an HIObject class for a simple embedder control. |
/*----------------------------------------------------------------------------------------------------------*/ |
CFStringRef GetEmbedderClass() |
{ |
// following code is pretty much boiler plate. |
static HIObjectClassRef theClass; |
if (theClass == NULL) |
{ |
static EventTypeSpec kFactoryEvents[] = |
{ |
// the next 3 messages are boiler plate |
{ kEventClassHIObject, kEventHIObjectConstruct }, |
{ kEventClassHIObject, kEventHIObjectInitialize }, |
{ kEventClassHIObject, kEventHIObjectDestruct }, |
// the next 2 messages are Scroll specific |
{ kEventClassScrollable, kEventScrollableGetInfo }, |
{ kEventClassScrollable, kEventScrollableScrollTo }, |
// the next message is Control specific |
{ kEventClassControl, kEventControlInitialize }, |
{ kEventClassControl, kEventControlDraw } |
}; |
HIObjectRegisterSubclass(kEmbedderClassID, kHIViewClassID, 0, ViewHandler, |
GetEventTypeCount(kFactoryEvents), kFactoryEvents, 0, &theClass); |
} |
return kEmbedderClassID; |
} |
/*----------------------------------------------------------------------------------------------------------*/ |
// ¥ ViewHandler |
// Event handler that implements our simple embedder control. |
/*----------------------------------------------------------------------------------------------------------*/ |
pascal OSStatus ViewHandler(EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon) |
{ |
OSStatus result = eventNotHandledErr; |
EmbedderData* myData = (EmbedderData*)inRefcon; |
switch (GetEventClass(inEvent)) |
{ |
case kEventClassHIObject: |
switch (GetEventKind(inEvent)) |
{ |
case kEventHIObjectConstruct: |
{ |
// allocate some instance data |
myData = (EmbedderData*) calloc(1, sizeof(EmbedderData)); |
// get our superclass instance |
HIViewRef epView; |
GetEventParameter(inEvent, kEventParamHIObjectInstance, typeHIObjectRef, NULL, sizeof(epView), NULL, &epView); |
// remember our superclass in our instance data and initialize other fields |
myData->view = epView; |
// set the control ID so that we can find it later with HIViewFindByID |
result = SetControlID(myData->view, &kEmbedderViewID); |
if (result != noErr) DebugStr("\pSetControlID failed!"); |
// store our instance data into the event |
result = SetEventParameter(inEvent, kEventParamHIObjectInstance, typeVoidPtr, sizeof(myData), &myData); |
break; |
} |
case kEventHIObjectDestruct: |
{ |
free(myData); |
result = noErr; |
break; |
} |
case kEventHIObjectInitialize: |
{ |
// always begin kEventHIObjectInitialize by calling through to the previous handler |
result = CallNextEventHandler(inCaller, inEvent); |
// if that succeeded, do our own initialization |
if (result == noErr) |
{ |
Rect itemRect = {20, 20, 40, 220 }; |
ControlRef outControl; |
result = CreatePushButtonControl(NULL, &itemRect, CFSTR("First Button"), &outControl); |
HIViewAddSubview(myData->view, outControl); |
OffsetRect(&itemRect, 40, 200); |
result = CreatePushButtonControl(NULL, &itemRect, CFSTR("Second Button"), &outControl); |
HIViewAddSubview(myData->view, outControl); |
OffsetRect(&itemRect, 40, 200); |
result = CreateSliderControl(NULL, &itemRect, 50, 0, 300, kControlSliderPointsDownOrRight, 0, true, NULL, &outControl); |
HIViewAddSubview(myData->view, outControl); |
OffsetRect(&itemRect, -40, 200); |
result = CreateProgressBarControl(NULL, &itemRect, 0, 0, 100, true, &outControl); |
HIViewAddSubview(myData->view, outControl); |
OffsetRect(&itemRect, -40, 200); itemRect.right += 100; itemRect.bottom -= 5; |
result = CreateEditUnicodeTextControl(NULL, &itemRect, CFSTR("This is an Unicode Edit Text control"), false, NULL, &outControl); |
itemRect.right -= 100; |
HIViewAddSubview(myData->view, outControl); |
OffsetRect(&itemRect, 40, 200); |
result = CreateScrollBarControl(NULL, &itemRect, 50, 0, 300, 0, true, NULL, &outControl); |
itemRect.bottom += 5; |
HIViewAddSubview(myData->view, outControl); |
OffsetRect(&itemRect, 40, 200); |
result = CreateCheckBoxControl(NULL, &itemRect, CFSTR("Check Box"), 0, true, &outControl); |
HIViewAddSubview(myData->view, outControl); |
OffsetRect(&itemRect, -80, 200); itemRect.right += 100; |
result = CreatePopupButtonControl(NULL, &itemRect, CFSTR("Popup Button"), 129, false, 120, teJustRight, normal, &outControl); |
HIViewAddSubview(myData->view, outControl); |
} |
break; |
} |
default: |
break; |
} |
break; |
case kEventClassScrollable: |
switch (GetEventKind(inEvent)) |
{ |
case kEventScrollableGetInfo: |
{ |
// we're being asked to return information about the scrolled view that we set as Event Parameters |
HISize imageSize = {50.0, kEmbedderDefaultHeight}; |
SetEventParameter(inEvent, kEventParamImageSize, typeHISize, sizeof(imageSize), &imageSize); |
HISize lineSize = {50.0, 20.0}; |
SetEventParameter(inEvent, kEventParamLineSize, typeHISize, sizeof(lineSize), &lineSize); |
HIRect bounds; |
HIViewGetBounds(myData->view, &bounds); |
SetEventParameter(inEvent, kEventParamViewSize, typeHISize, sizeof(bounds.size), &bounds.size); |
SetEventParameter(inEvent, kEventParamOrigin, typeHIPoint, sizeof(myData->originPoint), &myData->originPoint); |
result = noErr; |
break; |
} |
case kEventScrollableScrollTo: |
{ |
// we're being asked to scroll, we just do a sanity check and ask for a redraw |
HIPoint where; |
GetEventParameter(inEvent, kEventParamOrigin, typeHIPoint, NULL, sizeof(where), NULL, &where); |
HIViewSetNeedsDisplay(myData->view, true); |
myData->originPoint.y = (where.y < 0.0)?0.0:where.y; |
HIViewSetBoundsOrigin(myData->view, 0, myData->originPoint.y); |
// the "revealed" children won't be visible unless we hide/show the embedder itself |
// this is a Jaguar bug (#3126953) fixed in Panther |
if (GetHIToolboxVersion() < 0x130) |
{ |
HIViewSetVisible(myData->view, false); |
HIViewSetVisible(myData->view, true); |
} |
// some of the embedded controls (UnicodeText & ScrollBar) don't update correctly when scrolled |
// this is a Panther bug not fixed yet so unfortunately we have to maintained the following Hide/Show workaround |
if (GetHIToolboxVersion() >= 0x130) |
{ |
UInt16 i, numChildren; |
CountSubControls(myData->view, &numChildren); |
for (i=0; i<numChildren; i++) |
{ |
ControlRef subControl; |
GetIndexedSubControl(myData->view, i, &subControl); |
ControlKind controlKind; |
GetControlKind(subControl, &controlKind); |
if ( (controlKind.kind == kControlKindScrollBar) || (controlKind.kind == kControlKindEditUnicodeText) ) |
{ |
HIViewSetVisible(subControl, false); |
HIViewSetVisible(subControl, true); |
} |
} |
} |
break; |
} |
default: |
break; |
} |
break; |
case kEventClassControl: |
switch (GetEventKind(inEvent)) |
{ |
// sets the feature of the view. |
case kEventControlInitialize: |
{ |
result = CallNextEventHandler(inCaller, inEvent); |
if (result != noErr) break; |
UInt32 features = 0; |
result = GetEventParameter(inEvent, kEventParamControlFeatures, typeUInt32, NULL, sizeof(features), NULL, &features); |
if (result == noErr) |
features |= kControlSupportsEmbedding; |
else |
features = kControlSupportsEmbedding; |
result = SetEventParameter(inEvent, kEventParamControlFeatures, typeUInt32, sizeof features, &features); |
break; |
} |
// Draw the view. |
case kEventControlDraw: |
{ |
CGContextRef context; |
result = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(context), NULL, &context); |
if (result != noErr) {DebugStr("\pGetEventParameter failed for kEventControlDraw"); break;} |
HIRect bounds; |
HIViewGetBounds(myData->view, &bounds); |
CGContextSaveGState(context); |
CGAffineTransform transform = CGAffineTransformIdentity; |
// adjust the transform so the text doesn't draw upside down |
transform = CGAffineTransformScale(transform, 1, -1); |
CGContextSetTextMatrix(context, transform); |
// now that the proper parameters and configurations have been dealt with, let's draw |
EmbedderViewDrawing(context, &bounds, myData); |
CGContextRestoreGState(context); |
result = noErr; |
break; |
} |
default: |
break; |
} |
break; |
default: |
break; |
} |
return result; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-11-13