/* File: TView.cp 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 © 2002 Apple Computer, Inc., All Rights Reserved */ /* NOTE: This is NOWHERE near a completely exhaustive implementation of a view. There are many more carbon events one could intercept and hook into this. */ #include "TView.h" //----------------------------------------------------------------------------------- // constants //----------------------------------------------------------------------------------- // const EventTypeSpec kHIObjectEvents[] = { { kEventClassHIObject, kEventHIObjectConstruct }, { kEventClassHIObject, kEventHIObjectInitialize }, { kEventClassHIObject, kEventHIObjectDestruct } }; const EventTypeSpec kHIViewEvents[] = { { kEventClassCommand, kEventCommandProcess }, { kEventClassCommand, kEventCommandUpdateStatus }, { kEventClassControl, kEventControlInitialize }, { kEventClassControl, kEventControlDraw }, { kEventClassControl, kEventControlHitTest }, { kEventClassControl, kEventControlGetPartRegion }, { kEventClassControl, kEventControlGetData }, { kEventClassControl, kEventControlSetData }, { kEventClassControl, kEventControlGetOptimalBounds }, { kEventClassControl, kEventControlBoundsChanged }, { kEventClassControl, kEventControlTrack }, { kEventClassControl, kEventControlGetSizeConstraints }, { kEventClassControl, kEventControlHit }, { kEventClassControl, kEventControlHiliteChanged }, { kEventClassControl, kEventControlActivate }, { kEventClassControl, kEventControlDeactivate }, { kEventClassControl, kEventControlValueFieldChanged }, { kEventClassControl, kEventControlTitleChanged }, { kEventClassControl, kEventControlEnabledStateChanged }, }; // This param name was accidentally left unexported for // the release of Jaguar. const EventParamName kEventParamControlLikesDrag = 'cldg'; //----------------------------------------------------------------------------------- // TView constructor //----------------------------------------------------------------------------------- // TView::TView( HIViewRef inControl ) : fViewRef( inControl ) { verify_noerr( InstallEventHandler( GetControlEventTarget( fViewRef ), ViewEventHandler, GetEventTypeCount( kHIViewEvents ), kHIViewEvents, this, &fHandler ) ); mouseEventHandler = NULL; fAutoInvalidateFlags = 0; debugPrint = false; } //----------------------------------------------------------------------------------- // TView destructor //----------------------------------------------------------------------------------- // TView::~TView() { // If we have installed our custom mouse events handler on the window, // go forth and remove it. Note: -1 is used to indicate that no handler has // been installed yet, but we want to once we get a window. if ( mouseEventHandler != NULL && mouseEventHandler != reinterpret_cast( -1 ) ) RemoveEventHandler( mouseEventHandler ); mouseEventHandler = NULL; } //----------------------------------------------------------------------------------- // Initialize //----------------------------------------------------------------------------------- // Called during HIObject construction, this is your subclasses' chance to extract // any parameters it might have added to the initialization event passed into the // HIObjectCreate call. // OSStatus TView::Initialize( TCarbonEvent& /*inEvent*/ ) { return noErr; } //----------------------------------------------------------------------------------- // GetBehaviors //----------------------------------------------------------------------------------- // Returns our behaviors. Any subclass that overrides this should OR in its behaviors // into the inherited behaviors. // UInt32 TView::GetBehaviors() { return kControlSupportsDataAccess | kControlSupportsGetRegion; } //----------------------------------------------------------------------------------- // Draw //----------------------------------------------------------------------------------- // Draw your view. You should draw based on VIEW coordinates, not frame coordinates. // void TView::Draw( RgnHandle /*inLimitRgn*/, CGContextRef /*inContext*/ ) { } //----------------------------------------------------------------------------------- // HitTest //----------------------------------------------------------------------------------- // Asks your view to return what part of itself (if any) is hit by the point given // to it. The point is in VIEW coordinates, so you should get the view rect to do // bounds checking. // ControlPartCode TView::HitTest( const HIPoint& /*inWhere*/ ) { return kControlNoPart; } //----------------------------------------------------------------------------------- // GetRegion //----------------------------------------------------------------------------------- // This is called when someone wants to know certain metrics regarding this view. // The base class does nothing. Subclasses should handle their own parts, such as // the content region by overriding this method. The structure region is, by default, // the view's bounds. If a subclass does not have a region for a given part, it // should always call the inherited method. // OSStatus TView::GetRegion( ControlPartCode inPart, RgnHandle outRgn ) { #pragma unused( inPart, outRgn ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // PrintDebugInfo //----------------------------------------------------------------------------------- // This is called when asked to print debugging information. // void TView::PrintDebugInfo() { } //----------------------------------------------------------------------------------- // GetData //----------------------------------------------------------------------------------- // Gets some data from our view. Subclasses should override to handle their own // defined data tags. If a tag is not understood by the subclass, it should call the // inherited method. As a convienience, we map the request for ControlKind into our // GetKind method. // OSStatus TView::GetData( OSType inTag, ControlPartCode inPart, Size inSize, Size* outSize, void* inPtr ) { #pragma unused( inPart ) OSStatus err = noErr; switch( inTag ) { case kControlKindTag: if ( inPtr ) { if ( inSize != sizeof( ControlKind ) ) err = errDataSizeMismatch; else ( *(ControlKind *) inPtr ) = GetKind(); } *outSize = sizeof( ControlKind ); break; default: err = eventNotHandledErr; break; } return err; } //----------------------------------------------------------------------------------- // SetData //----------------------------------------------------------------------------------- // Sets some data on our control. Subclasses should override to handle their own // defined data tags. If a tag is not understood by the subclass, it should call the // inherited method. // OSStatus TView::SetData( OSType inTag, ControlPartCode inPart, Size inSize, const void* inPtr ) { #pragma unused( inTag, inPart, inSize, inPtr ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // GetOptimalSize //----------------------------------------------------------------------------------- // Someone wants to know this view's optimal size and text baseline, probably to help // do some type of layout. The base class does nothing, but subclasses should // override and do something meaningful here. // OSStatus TView::GetOptimalSize( HISize* outSize, float* outBaseLine ) { #pragma unused( outSize, outBaseLine ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // GetSizeConstraints //----------------------------------------------------------------------------------- // Someone wants to know this view's minimum and maximum sizes, probably to help // do some type of layout. The base class does nothing, but subclasses should // override and do something meaningful here. // OSStatus TView::GetSizeConstraints( HISize* outMin, HISize* outMax ) { #pragma unused( outMin, outMax ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // BoundsChanged //----------------------------------------------------------------------------------- // The bounds of our view have changed. Subclasses can override here to make note // of it and flush caches, etc. The base class does nothing. // OSStatus TView::BoundsChanged( UInt32 inOptions, const HIRect& inOriginalBounds, const HIRect& inCurrentBounds, RgnHandle inInvalRgn ) { #pragma unused( inOptions, inOriginalBounds, inCurrentBounds, inInvalRgn ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // ControlHit //----------------------------------------------------------------------------------- // The was hit. Subclasses can overide to care about what part was hit. // OSStatus TView::ControlHit( ControlPartCode inPart, UInt32 inModifiers ) { #pragma unused( inPart, inModifiers ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // HiliteChanged //----------------------------------------------------------------------------------- // The hilite of our view has changed. Subclasses can override here to make note // of it and flush caches, etc. The base class does nothing. // OSStatus TView::HiliteChanged( ControlPartCode inOriginalPart, ControlPartCode inCurrentPart, RgnHandle inInvalRgn ) { #pragma unused( inOriginalPart, inCurrentPart, inInvalRgn ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // DragEnter //----------------------------------------------------------------------------------- // A drag has entered our bounds. The Drag and Drop interface also should have been // activated or else this method will NOT be called. If true is returned, this view // likes the drag and will receive drag within/leave/receive messages as appropriate. // If false is returned, it is assumed the drag is not valid for this view, and no // further drag activity will flow into this view unless the drag leaves and is // re-entered. // bool TView::DragEnter( DragRef inDrag ) { #pragma unused( inDrag ) return false; } //----------------------------------------------------------------------------------- // DragWithin //----------------------------------------------------------------------------------- // A drag has moved within our bounds. In order for this method to be called, the // view must have signaled the drag as being desirable in the DragEnter method. The // Drag and Drop interface also should have been activated. // bool TView::DragWithin( DragRef inDrag ) { #pragma unused( inDrag ) return false; } //----------------------------------------------------------------------------------- // DragLeave //----------------------------------------------------------------------------------- // A drag has left. Deal with it. Subclasses should override as necessary. The // Drag and Drop interface should be activated in order for this method to be valid. // The drag must have also been accepted in the DragEnter method, else this method // will NOT be called. // bool TView::DragLeave( DragRef inDrag ) { #pragma unused( inDrag ) return false; } //----------------------------------------------------------------------------------- // DragReceive //----------------------------------------------------------------------------------- // Deal with receiving a drag. By default we return dragNotAcceptedErr. I'm not sure // if this is correct, or eventNotHandledErr. Time will tell... // OSStatus TView::DragReceive( DragRef inDrag ) { #pragma unused( inDrag ) return dragNotAcceptedErr; } //----------------------------------------------------------------------------------- // Track //----------------------------------------------------------------------------------- // Default tracking method. Subclasses should override as necessary. We do nothing // here in the base class, so we return eventNotHandledErr. // OSStatus TView::Track( TCarbonEvent& inEvent, ControlPartCode* outPart ) { #pragma unused( inEvent, outPart ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // SetFocusPart //----------------------------------------------------------------------------------- // Handle focusing. Our base behavior is to punt. // OSStatus TView::SetFocusPart( ControlPartCode inDesiredFocus, RgnHandle inInvalidRgn, Boolean inFocusEverything, ControlPartCode* outActualFocus ) { #pragma unused( inDesiredFocus, inInvalidRgn, inFocusEverything, outActualFocus ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // ProcessCommand //----------------------------------------------------------------------------------- // Process a command. Subclasses should override as necessary. // OSStatus TView::ProcessCommand( const HICommand& inCommand ) { #pragma unused( inCommand ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // UpdateCommandStatus //----------------------------------------------------------------------------------- // Update the status for a command. Subclasses should override as necessary. // OSStatus TView::UpdateCommandStatus( const HICommand& inCommand ) { #pragma unused( inCommand ) return eventNotHandledErr; } OSStatus TView::MouseDown(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ , TCarbonEvent& /*inEvent*/) { return eventNotHandledErr; } OSStatus TView::MouseUp(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) { return eventNotHandledErr; } OSStatus TView::MouseDragged(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) { return eventNotHandledErr; } OSStatus TView::MouseEntered(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) { return eventNotHandledErr; } OSStatus TView::MouseExited(HIPoint& /*inMouseLocation*/, UInt32 /*inKeyModifiers*/, EventMouseButton /*inMouseButton*/, UInt32 /*inClickCount*/ ) { return eventNotHandledErr; } OSStatus TView::MouseWheelMoved( EventMouseWheelAxis /*inAxis*/, SInt32 /*inDelta*/, UInt32 /*inKeyModifiers*/ ) { return eventNotHandledErr; } OSStatus TView::ContextualMenuClick( HIPoint& /*inMouseLocation*/ ) { return eventNotHandledErr; } //----------------------------------------------------------------------------------- // ActivateInterface //----------------------------------------------------------------------------------- // This routine is used to allow a subclass to turn on a specific event or suite of // events, like Drag and Drop. This allows us to keep event traffic down if we are // not interested, but register for the events if we are. // OSStatus TView::ActivateInterface( TView::Interface inInterface ) { OSStatus result = noErr; switch( inInterface ) { case kDragAndDrop: { static const EventTypeSpec kDragEvents[] = { { kEventClassControl, kEventControlDragEnter }, { kEventClassControl, kEventControlDragLeave }, { kEventClassControl, kEventControlDragWithin }, { kEventClassControl, kEventControlDragReceive } }; result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kDragEvents ), kDragEvents ); SetControlDragTrackingEnabled( GetViewRef(), true); } break; case kKeyboardFocus: { static const EventTypeSpec kKeyboardFocusEvents[] = { { kEventClassControl, kEventControlSetFocusPart }, { kEventClassTextInput, kEventTextInputUnicodeForKeyEvent }, }; result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kKeyboardFocusEvents ), kKeyboardFocusEvents ); } break; case kMouse: { if ( mouseEventHandler == NULL ) { // This case is quite different: Mouse events are delivered to the window, not the controls. // mouse wheel events are the exception: They ARE delivered to the control static const EventTypeSpec kControlMouseEvents[] = { { kEventClassMouse, kEventMouseWheelMoved }, { kEventClassControl, kEventControlContextualMenuClick }, // So we can reinstall our events when the window changes { kEventClassControl, kEventControlOwningWindowChanged }, }; result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kControlMouseEvents ), kControlMouseEvents ); } if ( this->GetOwner() != NULL ) { // We use "-1" to indicate that we want to install an event handler once we get a window if ( mouseEventHandler != NULL && mouseEventHandler != reinterpret_cast( -1 ) ) { result = RemoveEventHandler( mouseEventHandler ); } mouseEventHandler = NULL; static const EventTypeSpec kWindowMouseEvents[] = { { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseDragged }, }; result = InstallEventHandler( GetWindowEventTarget( this->GetOwner() ), WindowEventHandler, GetEventTypeCount( kWindowMouseEvents ), kWindowMouseEvents, this, &mouseEventHandler ); } // If we have no window yet. Set the mouseEventHandler to -1 so when we get one we // will install the event handler else { mouseEventHandler = reinterpret_cast( -1 ); } } break; case kMouseTracking: { { static const EventTypeSpec kControlMouseEvents[] = { { kEventClassMouse, kEventMouseEntered }, // only works if mousetracking is started { kEventClassMouse, kEventMouseExited }, // only works if mousetracking is started }; result = AddEventTypesToHandler( fHandler, GetEventTypeCount( kControlMouseEvents ), kControlMouseEvents ); } } //default: // assert( false ); } return result; } OSStatus TView::InstallTimer( EventTimerInterval inFireDelay, EventLoopTimerRef* outTimer ) { return InstallEventLoopTimer( GetCurrentEventLoop(), inFireDelay, inFireDelay, TimerEventHandler, this, outTimer ); } //----------------------------------------------------------------------------------- // RegisterSubclass //----------------------------------------------------------------------------------- // This routine should be called by subclasses so they can be created as HIObjects. // OSStatus TView::RegisterSubclass( CFStringRef inID, ConstructProc inProc ) { return HIObjectRegisterSubclass( inID, kHIViewClassID, 0, ObjectEventHandler, GetEventTypeCount( kHIObjectEvents ), kHIObjectEvents, (void*) inProc, NULL ); } //----------------------------------------------------------------------------------- // ObjectEventHandler //----------------------------------------------------------------------------------- // Our static event handler proc. We handle any HIObject based events directly in // here at present. // pascal OSStatus TView::ObjectEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ) { OSStatus result = eventNotHandledErr; TView* view = (TView*) inUserData; TCarbonEvent event( inEvent ); switch ( event.GetClass() ) { case kEventClassHIObject: switch ( event.GetKind() ) { case kEventHIObjectConstruct: { ControlRef control; // ControlRefs are HIObjectRefs TView* view; result = event.GetParameter( kEventParamHIObjectInstance, typeHIObjectRef, (HIObjectRef*)&control ); require_noerr( result, ParameterMissing ); // on entry for our construct event, we're passed the // creation proc we registered with for this class. // we use it now to create the instance, and then we // replace the instance parameter data with said instance // as type void. result = (*(ConstructProc)inUserData)( control, &view ); if ( result == noErr ) event.SetParameter( kEventParamHIObjectInstance, typeVoidPtr, view ); } break; case kEventHIObjectInitialize: result = CallNextEventHandler( inCallRef, inEvent ); if ( result == noErr ) result = view->Initialize( event ); break; case kEventHIObjectDestruct: delete view; break; } break; } ParameterMissing: return result; } //----------------------------------------------------------------------------------- // ViewEventHandler //----------------------------------------------------------------------------------- // Our static event handler proc. We handle all non-HIObject events here. // pascal OSStatus TView::ViewEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ) { OSStatus result; TView* view = (TView*) inUserData; TCarbonEvent event( inEvent ); //if (view->debugPrint) // fprintf(stderr,"TView::ViewEventHandler\n"); result = view->HandleEvent( inCallRef, event ); return result; } pascal OSStatus TView::WindowEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, void* inUserData ) { TView* view = reinterpret_cast( inUserData ); TCarbonEvent event( inEvent ); const WindowRef window = view->GetOwner(); if (NULL == window) return eventNotHandledErr; // If the window is not active, let the standard window handler execute. if ( ! IsWindowActive( window ) ) return eventNotHandledErr; if (view->debugPrint) fprintf(stderr,"TView::WindowEventHandler\n"); const HIViewRef rootView = HIViewGetRoot( window ); if (NULL == rootView) return eventNotHandledErr; // TODO: On OS X 10.3, test if this bug still exists // This is a hack to work around a bug in the OS. See: // http://lists.apple.com/archives/carbon-development/2002/Sep/29/keventmousemovedeventsno.004.txt OSStatus err; if ( event.GetKind() == kEventMouseMoved ) { // We need to set some parameters correctly event.SetParameter( kEventParamWindowRef, window ); HIPoint ptMouse; event.GetParameter( kEventParamMouseLocation, &ptMouse ); // convert screen coords to window relative Rect bounds; err = GetWindowBounds( window, kWindowStructureRgn, &bounds ); if( err == noErr ) { ptMouse.x -= bounds.left; ptMouse.y -= bounds.top; event.SetParameter( kEventParamWindowMouseLocation, ptMouse ); } } HIViewRef targetView = NULL; err = HIViewGetViewForMouseEvent( rootView, inEvent, &targetView ); //if (view->debugPrint) // fprintf(stderr,"TView::WindowEventHandler root[%08X] viewRef[%08X] targetView[%08X]\n", rootView, view->GetViewRef(), targetView); if ( targetView == view->GetViewRef() || event.GetKind() == kEventMouseDragged ) { return view->HandleEvent( inCallRef, event ); } return eventNotHandledErr; } pascal void TView::TimerEventHandler( EventLoopTimerRef inTimer, void* view ) { reinterpret_cast( view )->TimerFired( inTimer ); } //----------------------------------------------------------------------------------- // HandleEvent //----------------------------------------------------------------------------------- // Our object's virtual event handler method. I'm not sure if we need this these days. // We used to do various things with it, but those days are long gone... // OSStatus TView::HandleEvent( EventHandlerCallRef inCallRef, TCarbonEvent& inEvent ) { #pragma unused( inCallRef ) OSStatus result = eventNotHandledErr; HIPoint where; OSType tag; void * ptr; Size size, outSize; UInt32 features; RgnHandle region = NULL; ControlPartCode part; RgnHandle invalRgn; switch ( inEvent.GetClass() ) { case kEventClassCommand: { HICommand command; result = inEvent.GetParameter( kEventParamDirectObject, &command ); require_noerr( result, MissingParameter ); switch ( inEvent.GetKind() ) { case kEventCommandProcess: result = ProcessCommand( command ); break; case kEventCommandUpdateStatus: result = UpdateCommandStatus( command ); break; } } break; case kEventClassControl: switch ( inEvent.GetKind() ) { case kEventControlInitialize: features = GetBehaviors(); inEvent.SetParameter( kEventParamControlFeatures, features ); result = noErr; break; case kEventControlDraw: { CGContextRef context = NULL; inEvent.GetParameter( kEventParamRgnHandle, ®ion ); inEvent.GetParameter( kEventParamCGContextRef, typeCGContextRef, &context ); Draw( region, context ); result = noErr; } break; case kEventControlHitTest: inEvent.GetParameter( kEventParamMouseLocation, typeHIPoint, &where ); part = HitTest( where ); inEvent.SetParameter( kEventParamControlPart, typeControlPartCode, part ); result = noErr; break; case kEventControlGetPartRegion: inEvent.GetParameter( kEventParamControlPart, typeControlPartCode, &part ); inEvent.GetParameter( kEventParamControlRegion, ®ion ); result = GetRegion( part, region ); break; case kEventControlGetData: inEvent.GetParameter( kEventParamControlPart, typeControlPartCode, &part ); inEvent.GetParameter( kEventParamControlDataTag, typeEnumeration, &tag ); inEvent.GetParameter( kEventParamControlDataBuffer, typePtr, (Ptr*)&ptr ); inEvent.GetParameter( kEventParamControlDataBufferSize, typeLongInteger, &size ); result = GetData( tag, part, size, &outSize, ptr ); if ( result == noErr ) verify_noerr( inEvent.SetParameter( kEventParamControlDataBufferSize, typeLongInteger, outSize ) ); break; case kEventControlSetData: inEvent.GetParameter( kEventParamControlPart, typeControlPartCode, &part ); inEvent.GetParameter( kEventParamControlDataTag, typeEnumeration, &tag ); inEvent.GetParameter( kEventParamControlDataBuffer, typePtr, (Ptr*)&ptr ); inEvent.GetParameter( kEventParamControlDataBufferSize, typeLongInteger, &size ); result = SetData( tag, part, size, ptr ); break; case kEventControlGetOptimalBounds: { HISize size; float floatBaseLine; result = GetOptimalSize( &size, &floatBaseLine ); if ( result == noErr ) { Rect bounds; SInt16 baseLine; GetControlBounds( GetViewRef(), &bounds ); bounds.bottom = bounds.top + (SInt16)size.height; bounds.right = bounds.left + (SInt16)size.width; baseLine = (SInt16)floatBaseLine; inEvent.SetParameter( kEventParamControlOptimalBounds, bounds ); inEvent.SetParameter( kEventParamControlOptimalBaselineOffset, typeShortInteger, baseLine ); } } break; case kEventControlBoundsChanged: { HIRect prevRect, currRect; UInt32 attrs; inEvent.GetParameter( kEventParamAttributes, &attrs ); inEvent.GetParameter( kEventParamOriginalBounds, &prevRect ); inEvent.GetParameter( kEventParamCurrentBounds, &currRect ); inEvent.GetParameter( kEventParamControlInvalRgn, &invalRgn ); result = BoundsChanged( attrs, prevRect, currRect, invalRgn ); if ( mouseEventHandler != NULL ) { ActivateInterface( kMouse ); } } break; case kEventControlHit: { UInt32 modifiers; inEvent.GetParameter( kEventParamControlPart, typeControlPartCode, &part ); inEvent.GetParameter( kEventParamKeyModifiers, &modifiers ); result = ControlHit( part, modifiers ); } break; case kEventControlHiliteChanged: { ControlPartCode prevPart, currPart; inEvent.GetParameter( kEventParamControlPreviousPart, typeControlPartCode, &prevPart ); inEvent.GetParameter( kEventParamControlCurrentPart, typeControlPartCode, &currPart ); inEvent.GetParameter( kEventParamControlInvalRgn, &invalRgn ); result = HiliteChanged( prevPart, currPart, invalRgn ); if ( GetAutoInvalidateFlags() & kAutoInvalidateOnHilite ) Invalidate(); } break; case kEventControlActivate: result = ActiveStateChanged(); if ( GetAutoInvalidateFlags() & kAutoInvalidateOnActivate ) Invalidate(); break; case kEventControlDeactivate: result = ActiveStateChanged(); if ( GetAutoInvalidateFlags() & kAutoInvalidateOnActivate ) Invalidate(); break; case kEventControlValueFieldChanged: result = ValueChanged(); if ( GetAutoInvalidateFlags() & kAutoInvalidateOnValueChange ) Invalidate(); break; case kEventControlTitleChanged: result = TitleChanged(); if ( GetAutoInvalidateFlags() & kAutoInvalidateOnTitleChange ) Invalidate(); break; case kEventControlEnabledStateChanged: result = EnabledStateChanged(); if ( GetAutoInvalidateFlags() & kAutoInvalidateOnEnable ) Invalidate(); break; case kEventControlDragEnter: case kEventControlDragLeave: case kEventControlDragWithin: { DragRef drag; bool likesDrag; inEvent.GetParameter( kEventParamDragRef, &drag ); switch ( inEvent.GetKind() ) { case kEventControlDragEnter: likesDrag = DragEnter( drag ); // Why only if likesDrag? What if it doesn't? No parameter? if ( likesDrag ) result = inEvent.SetParameter( kEventParamControlLikesDrag, likesDrag ); break; case kEventControlDragLeave: DragLeave( drag ); result = noErr; break; case kEventControlDragWithin: DragWithin( drag ); result = noErr; break; } } break; case kEventControlDragReceive: { DragRef drag; inEvent.GetParameter( kEventParamDragRef, &drag ); result = DragReceive( drag ); } break; case kEventControlTrack: { ControlPartCode part; result = Track( inEvent, &part ); if ( result == noErr ) verify_noerr( inEvent.SetParameter( kEventParamControlPart, typeControlPartCode, part ) ); } break; case kEventControlGetSizeConstraints: { HISize minSize, maxSize; result = GetSizeConstraints( &minSize, &maxSize ); if ( result == noErr ) { verify_noerr( inEvent.SetParameter( kEventParamMinimumSize, minSize ) ); verify_noerr( inEvent.SetParameter( kEventParamMaximumSize, maxSize ) ); } } break; case kEventControlSetFocusPart: { ControlPartCode desiredFocus; RgnHandle invalidRgn; Boolean focusEverything; ControlPartCode actualFocus; result = inEvent.GetParameter( kEventParamControlPart, typeControlPartCode, &desiredFocus ); require_noerr( result, MissingParameter ); inEvent.GetParameter( kEventParamControlInvalRgn, &invalidRgn ); focusEverything = false; // a good default in case the parameter doesn't exist inEvent.GetParameter( kEventParamControlFocusEverything, &focusEverything ); result = SetFocusPart( desiredFocus, invalidRgn, focusEverything, &actualFocus ); if ( result == noErr ) verify_noerr( inEvent.SetParameter( kEventParamControlPart, typeControlPartCode, actualFocus ) ); } break; case kEventControlOwningWindowChanged: { // If our owning window has changed, reactivate the mouse interface if ( mouseEventHandler != NULL ) { ActivateInterface( kMouse ); } } break; case kEventControlContextualMenuClick: { HIPoint ptMouse; inEvent.GetParameter( kEventParamMouseLocation, &ptMouse ); result = ContextualMenuClick( ptMouse ); } break; // some other kind of Control event default: break; } break; case kEventClassTextInput: result = TextInput( inEvent ); break; case kEventClassMouse: { result = inEvent.GetParameter( kEventParamWindowMouseLocation, typeHIPoint, &where ); HIViewConvertPoint( &where, NULL, fViewRef ); UInt32 inKeyModifiers; result = inEvent.GetParameter( kEventParamKeyModifiers, &inKeyModifiers ); if( result != noErr ) inKeyModifiers = 0; EventMouseButton inMouseButton = 0; result = inEvent.GetParameter( kEventParamMouseButton, typeMouseButton, &inMouseButton ); if (noErr != result) // assume no button is pressed if there is no button info inMouseButton = 0; UInt32 inClickCount; result = inEvent.GetParameter( kEventParamClickCount, &inClickCount ); if( result != noErr ) inClickCount = 0; switch ( inEvent.GetKind() ) { case kEventMouseWheelMoved: { EventMouseWheelAxis inAxis; result = inEvent.GetParameter( kEventParamMouseWheelAxis, typeMouseWheelAxis, &inAxis ); SInt32 inDelta; result = inEvent.GetParameter( kEventParamMouseWheelDelta, typeSInt32, &inDelta ); result = MouseWheelMoved( inAxis, inDelta, inKeyModifiers ); break; } case kEventMouseDown: result = MouseDown( where, inKeyModifiers, inMouseButton, inClickCount, inEvent ); break; case kEventMouseUp: result = MouseUp( where, inKeyModifiers, inMouseButton, inClickCount ); break; case kEventMouseExited: result = MouseExited( where, inKeyModifiers, inMouseButton, inClickCount ); break; case kEventMouseEntered: result = MouseEntered( where, inKeyModifiers, inMouseButton, inClickCount ); break; case kEventMouseMoved: case kEventMouseDragged: result = MouseDragged( where, inKeyModifiers, inMouseButton, inClickCount ); break; default:; } break; } // some other event class default: break; } MissingParameter: return result; } //----------------------------------------------------------------------------------- // CreateInitializationEvent //----------------------------------------------------------------------------------- // Create a basic intialization event containing the parent control and bounds. At // present we set the bounds to empty and the parent to NULL. In theory, after creating // this event, any subclass could add its own parameter to receive in its // Initialize method. // EventRef TView::CreateInitializationEvent() { OSStatus result = noErr; EventRef event; result = CreateEvent( NULL, kEventClassHIObject, kEventHIObjectInitialize, GetCurrentEventTime(), 0, &event ); require_noerr_action( result, CantCreateEvent, event = NULL ); CantCreateEvent: return event; } //----------------------------------------------------------------------------------- // Frame //----------------------------------------------------------------------------------- // HIRect TView::Frame() { HIRect frame; HIViewGetFrame( GetViewRef(), &frame ); return frame; } //----------------------------------------------------------------------------------- // SetFrame //----------------------------------------------------------------------------------- // OSStatus TView::SetFrame( const HIRect& inFrame ) { OSStatus err; err = HIViewSetFrame( GetViewRef(), &inFrame ); return err; } //----------------------------------------------------------------------------------- // Bounds //----------------------------------------------------------------------------------- // HIRect TView::Bounds() { HIRect bounds; HIViewGetBounds( GetViewRef(), &bounds ); return bounds; } //----------------------------------------------------------------------------------- // Show //----------------------------------------------------------------------------------- // OSStatus TView::Show() { return HIViewSetVisible( GetViewRef(), true ); } //----------------------------------------------------------------------------------- // Hide //----------------------------------------------------------------------------------- // OSStatus TView::Hide() { return HIViewSetVisible( GetViewRef(), false ); } //----------------------------------------------------------------------------------- // GetEventTarget //----------------------------------------------------------------------------------- // EventTargetRef TView::GetEventTarget() { return HIObjectGetEventTarget( (HIObjectRef) GetViewRef() ); } //----------------------------------------------------------------------------------- // AddSubView //----------------------------------------------------------------------------------- // OSStatus TView::AddSubView( TView* inSubView ) { return HIViewAddSubview( GetViewRef(), inSubView->GetViewRef() );; } //----------------------------------------------------------------------------------- // RemoveFromSuperView //----------------------------------------------------------------------------------- // OSStatus TView::RemoveFromSuperView() { return HIViewRemoveFromSuperview( GetViewRef() ); } //----------------------------------------------------------------------------------- // GetHilite //----------------------------------------------------------------------------------- // ControlPartCode TView::GetHilite() { return GetControlHilite( GetViewRef() ); } //----------------------------------------------------------------------------------- // GetValue //----------------------------------------------------------------------------------- // SInt32 TView::GetValue() { return GetControl32BitValue( GetViewRef() ); } //----------------------------------------------------------------------------------- // SetValue //----------------------------------------------------------------------------------- // void TView::SetValue( SInt32 inValue ) { SetControl32BitValue( GetViewRef(), inValue ); } //----------------------------------------------------------------------------------- // GetMinimum //----------------------------------------------------------------------------------- // SInt32 TView::GetMinimum() { return GetControlMinimum( GetViewRef() ); } //----------------------------------------------------------------------------------- // SetMinimum //----------------------------------------------------------------------------------- // void TView::SetMinimum( SInt32 inMinimum ) { SetControlMinimum( GetViewRef(), inMinimum ); } //----------------------------------------------------------------------------------- // GetMaximum //----------------------------------------------------------------------------------- // SInt32 TView::GetMaximum() { return GetControlMaximum( GetViewRef() ); } //----------------------------------------------------------------------------------- // SetMaximum //----------------------------------------------------------------------------------- // void TView::SetMaximum( SInt32 inMaximum ) { SetControlMaximum( GetViewRef(), inMaximum ); } //----------------------------------------------------------------------------------- // GetOwner //----------------------------------------------------------------------------------- // WindowRef TView::GetOwner() { return GetControlOwner( GetViewRef() ); } //----------------------------------------------------------------------------------- // Hilite //----------------------------------------------------------------------------------- // void TView::Hilite( ControlPartCode inPart) { return HiliteControl( GetViewRef(), inPart ); } //----------------------------------------------------------------------------------- // Invalidate //----------------------------------------------------------------------------------- // OSStatus TView::Invalidate() { return HIViewSetNeedsDisplay( GetViewRef(), true ); } void TView::TimerFired( EventLoopTimerRef inTimer ) { #pragma unused( inTimer ) } //----------------------------------------------------------------------------------- // IsVisible //----------------------------------------------------------------------------------- // Boolean TView::IsVisible() { return IsControlVisible( GetViewRef() ); } //----------------------------------------------------------------------------------- // IsEnabled //----------------------------------------------------------------------------------- // Boolean TView::IsEnabled() { return IsControlEnabled( GetViewRef() ); } //----------------------------------------------------------------------------------- // IsActive //----------------------------------------------------------------------------------- // Boolean TView::IsActive() { return IsControlActive( GetViewRef() ); } //----------------------------------------------------------------------------------- // ActiveStateChanged //----------------------------------------------------------------------------------- // Default activation method. Subclasses should override as necessary. We do nothing // here in the base class, so we return eventNotHandledErr. // OSStatus TView::ActiveStateChanged() { return eventNotHandledErr; } //----------------------------------------------------------------------------------- // ValueChanged //----------------------------------------------------------------------------------- // Default value changed method. Subclasses should override as necessary. We do // nothing here in the base class, so we return eventNotHandledErr. // OSStatus TView::ValueChanged() { return eventNotHandledErr; } //----------------------------------------------------------------------------------- // TitleChanged //----------------------------------------------------------------------------------- // Default title changed method. Subclasses should override as necessary. We // do nothing here in the base class, so we return eventNotHandledErr. // OSStatus TView::TitleChanged() { return eventNotHandledErr; } //----------------------------------------------------------------------------------- // EnabledStateChanged //----------------------------------------------------------------------------------- // Default enable method. Subclasses should override as necessary. We // do nothing here in the base class, so we return eventNotHandledErr. // OSStatus TView::EnabledStateChanged() { return eventNotHandledErr; } //----------------------------------------------------------------------------------- // TextInput //----------------------------------------------------------------------------------- // Default text (Unicode) input method. Subclasses should override as necessary. We // do nothing here in the base class, so we return eventNotHandledErr. // OSStatus TView::TextInput( TCarbonEvent& inEvent ) { #pragma unused( inEvent ) return eventNotHandledErr; } //----------------------------------------------------------------------------------- // ChangeAutoInvalidateFlags //----------------------------------------------------------------------------------- // Change behavior for auto-invalidating views on certain actions. // void TView::ChangeAutoInvalidateFlags( OptionBits inSetThese, OptionBits inClearThese ) { fAutoInvalidateFlags = ( ( fAutoInvalidateFlags | inSetThese ) & ( ~inClearThese ) ); }