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.
HICustomPushButton.c
/* |
* File: HICustomPushButton.c of HICustomPushButton |
* |
* Contains: Demonstrates creating a simple custom push button using the HIView APIs. |
* |
* Version: 1.1 |
* |
* Created: 11/5/04 |
* |
* 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: Copyright © 2005 Apple Computer, Inc, All Rights Reserved |
*/ |
//**************************************************** |
#pragma mark * compilation directives * |
//**************************************************** |
#pragma mark - |
#pragma mark * includes & imports * |
#include "HICustomPushButton.h" |
//**************************************************** |
#pragma mark - |
#pragma mark * typedef's, struct's, enums, defines, etc. * |
// structure in which we hold our custom push button's data |
typedef struct |
{ |
HIViewRef view; // the HIViewRef for our button |
/* MoreStuff someMoreStuff; */ // More stuff if we need it, |
// we don't need anything for this custom push button |
// but this sample skeleton might be used for |
// something more ambitious. |
} |
CustomPushButtonData; |
#define kCustomPushButtonClassID CFSTR("com.apple.sample.dts.HICustomPushButton") |
//**************************************************** |
#pragma mark - |
#pragma mark * local (static) function prototypes * |
static pascal OSStatus Internal_HICustomPushButtonHandler(EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon); |
//**************************************************** |
#pragma mark - |
#pragma mark * exported globals * |
//**************************************************** |
#pragma mark - |
#pragma mark * local (static) globals * |
static UInt32 gWindowCount = 0; |
//**************************************************** |
#pragma mark - |
#pragma mark * exported function implementations * |
/***************************************************** |
* |
* Do_NewWindow() |
* |
* Purpose: called to create a new window, each other window will be created from APIs and the other one from Interface Builder |
* |
* Notes: called by Handle_CommandProcess() ("File/New" menu item), Handle_OpenApplication(). Handle_ReopenApplication() |
* |
* Inputs: none |
* |
* Returns: OSStatus - error code (0 == no error) |
*/ |
OSStatus Do_NewWindow(void) |
{ |
WindowRef aWindowRef = NULL; |
CFStringRef theTitle = NULL; |
OSStatus status; |
// Create a window |
Rect bounds = {0, 0, 360, 480}; |
status = CreateNewWindow(kDocumentWindowClass, kWindowStandardFloatingAttributes | kWindowStandardHandlerAttribute | kWindowCompositingAttribute | kWindowMetalAttribute, &bounds, &aWindowRef); |
require_noerr(status, CreateNewWindow); |
require(aWindowRef != NULL, CreateNewWindow); |
status = RepositionWindow(aWindowRef, NULL, kWindowCascadeOnMainScreen); |
require_noerr(status, RepositionWindow); |
HIViewRef contentView; |
status = HIViewFindByID(HIViewGetRoot(aWindowRef), kHIViewWindowContentID, &contentView); |
require_noerr(status, HIViewFindByID); |
// create the custom push button view |
HIViewRef customPushButton; |
status = HICustomPushButtonCreate(&customPushButton); |
require_noerr(status, HICustomPushButtonCreate); |
// place the view into the Window content view |
status = HIViewAddSubview(contentView, customPushButton); |
require_noerr(status, HIViewAddSubview); |
// position the view |
HIRect frame = { {110.0, 130.0}, {200.0, 40.0} }; |
HIViewSetFrame(customPushButton, &frame); |
// views are initially invisible, so make it visible |
HIViewSetVisible(customPushButton, true); |
// give the button a command so that it does something when pressed |
SetControlCommandID(customPushButton, kHICommandAbout); |
theTitle = CFStringCreateWithFormat(NULL, NULL, CFSTR("HICustomPushButton Window #%ld"), ++gWindowCount); |
require(theTitle != NULL, CFStringCreateWithFormat); |
status = SetWindowTitleWithCFString(aWindowRef, theTitle); |
require_noerr(status, SetWindowTitleWithCFString); |
// The window was created hidden so show it |
ShowWindow(aWindowRef); |
SetWindowModified(aWindowRef, false); |
HICustomPushButtonCreate: |
SetWindowTitleWithCFString: |
CFStringCreateWithFormat: |
if (theTitle != NULL) |
CFRelease(theTitle); |
SetWindowDefaultButton: |
SetControlCommandID: |
CreatePushButtonControl: |
HIViewAddSubview: |
CreateStaticTextControl: |
HIViewFindByID: |
RepositionWindow: |
CreateNewWindow: |
return status; |
} // Do_NewWindow |
/***************************************************** |
* |
* HICustomPushButtonCreate(outView) |
* |
* Purpose: registers a HIView custom class and installs the event handlers for that class |
* |
* Inputs: outView - returns the newly created HIView if successful |
* |
* Returns: OSStatus - error code (0 == no error) |
*/ |
OSStatus HICustomPushButtonCreate(HIViewRef *outView) |
{ |
OSStatus status; |
status = HIObjectCreate(GetCustomPushButtonClass(), 0, (HIObjectRef *)outView); |
require_noerr(status, HIObjectCreate); |
HIObjectCreate: |
return status; |
} // HICustomPushButtonCreate |
/***************************************************** |
* |
* GetCustomPushButtonClass() |
* |
* Purpose: registers a HIView custom class and installs the event handlers for that class |
* |
* Inputs: none |
* |
* Returns: CFStringRef - the class name |
*/ |
CFStringRef GetCustomPushButtonClass(void) |
{ |
// following code is pretty much boiler plate. |
static HIObjectClassRef theClass; |
if (theClass == NULL) |
{ |
static EventTypeSpec kFactoryEvents[] = |
{ |
// the next 2 messages are required |
{ kEventClassHIObject, kEventHIObjectConstruct }, |
{ kEventClassHIObject, kEventHIObjectDestruct }, |
// the next 3 messages are the actual minimum messages you need to |
// implement a simple custom push button: |
// |
// kEventControlHitTest has to be implemented so that you can |
// verify that the point passed in parameter is indeed in |
// an active part of your control. |
// Note: contrary to what you might think and what the name suggests |
// (HitTest), this message can be sent even when the button is |
// not down. Do not assume that you just got a click. |
// The Control Manager is just asking you to verify if a point |
// is in a part of your control, nothing more. |
// |
// kEventControlHiliteChanged, you get this message if the user just clicked |
// in your control, or has left the scope of your control while the |
// button is still down. In each case, that means a change of hilite. |
// most of the time, you should just react by asking for a redraw. |
// |
// kEventControlDraw, you need to draw your control (or part of it), |
// according to its state. |
// |
// and, for a simple custom push button, that's IT! |
// |
// You do not need to implement kEventControlHit since, for a push button, |
// it makes more sense to attach a command to it which will automatically |
// be invoked if the user releases the button while inside the control. |
// |
// You do not need to implement kEventControlClick since you implement |
// kEventControlHitTest which has to be implemented. That would be |
// redundant and, for a simple push button control, you don't need it. |
// |
// You do not need to implement kEventControlTrack since the tracking will |
// be done for you by the Control Manager which will repeatedly call your |
// kEventControlHitTest implementation to know what it's supposed to do. |
// You only need to implement kEventControlTrack if you want to do something |
// special while the user is tracking, like displaying a page number near the |
// thumb of the scroll bar that he is moving. |
{ kEventClassControl, kEventControlHitTest }, |
{ kEventClassControl, kEventControlHiliteChanged }, |
{ kEventClassControl, kEventControlDraw } |
}; |
HIObjectRegisterSubclass(kCustomPushButtonClassID, kHIViewClassID, 0, Internal_HICustomPushButtonHandler, |
GetEventTypeCount(kFactoryEvents), kFactoryEvents, 0, &theClass); |
} |
return kCustomPushButtonClassID; |
} // GetCustomPushButtonClass |
//**************************************************** |
#pragma mark - |
#pragma mark * local (static) function implementations * |
/*----------------------------------------------------------------------------------------------------------*/ |
// ¥ ViewHandler |
// Event handler that implements our custom push button. |
/*----------------------------------------------------------------------------------------------------------*/ |
static pascal OSStatus Internal_HICustomPushButtonHandler(EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon) |
{ |
OSStatus status = eventNotHandledErr; |
CustomPushButtonData * myData = (CustomPushButtonData*)inRefcon; |
switch (GetEventClass(inEvent)) |
{ |
case kEventClassHIObject: |
switch (GetEventKind(inEvent)) |
{ |
case kEventHIObjectConstruct: |
{ |
// allocate some instance data |
myData = (CustomPushButtonData*) calloc(1, sizeof(CustomPushButtonData)); |
require(myData != NULL, CantAllocateData); |
// get our superclass instance |
HIViewRef epView; |
status = GetEventParameter(inEvent, kEventParamHIObjectInstance, typeHIObjectRef, NULL, sizeof(epView), NULL, &epView); |
require_noerr(status, GetEventParameter); |
// remember our superclass in our instance data |
myData->view = epView; |
// store our instance data into the event |
status = SetEventParameter(inEvent, kEventParamHIObjectInstance, typeVoidPtr, sizeof(myData), &myData); |
require_noerr(status, SetEventParameter); |
break; |
} |
case kEventHIObjectDestruct: |
{ |
if (myData != NULL) free(myData); |
status = noErr; |
break; |
} |
default: |
break; |
} |
break; |
case kEventClassControl: |
switch (GetEventKind(inEvent)) |
{ |
// Draw the view. |
case kEventControlDraw: |
{ |
CGContextRef context; |
HIRect bounds; |
status = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(context), NULL, &context); |
require_noerr(status, GetEventParameter); |
HIViewGetBounds(myData->view, &bounds); |
if ((!IsControlHilited(myData->view)) || (!IsControlActive(myData->view))) |
CGContextSetGrayFillColor(context, 0.1, 0.3); |
else |
CGContextSetRGBFillColor(context, 0.1, 0.1, 1.0, 0.3); |
CGContextFillRect(context, bounds); |
status = noErr; |
break; |
} |
// Determine if a point is in the view. |
case kEventControlHitTest: |
{ |
HIPoint pt; |
HIRect bounds; |
// the point parameter is in view-local coords. |
status = GetEventParameter(inEvent, kEventParamMouseLocation, typeHIPoint, NULL, sizeof(pt), NULL, &pt); |
require_noerr(status, GetEventParameter); |
HIViewGetBounds(myData->view, &bounds); |
if (CGRectContainsPoint(bounds, pt)) |
{ |
ControlPartCode part = kControlButtonPart; |
status = SetEventParameter(inEvent, kEventParamControlPart, typeControlPartCode, sizeof(part), &part); |
require_noerr(status, SetEventParameter); |
} |
break; |
} |
// React to hilite changes by invalidating the view so that it will be redrawn. |
case kEventControlHiliteChanged: |
HIViewSetNeedsDisplay(myData->view, true); |
break; |
default: |
break; |
} |
break; |
default: |
break; |
} |
SetEventParameter: |
GetEventParameter: |
CantAllocateData: |
return status; |
} |
Copyright © 2005 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2005-10-17