/* 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 HIViewReHTTP/1.1 200 OK Connection: keep-alive Connection: keep-alive Content-Disposition: inline; filename="TView.cxx" Content-Disposition: inline; filename="TView.cxx" Content-Length: 46548 Content-Length: 46548 Content-Security-Policy: default-src 'none' Content-Security-Policy: default-src 'none' Content-Type: text/plain; charset=UTF-8 Content-Type: text/plain; charset=UTF-8 Date: Wed, 22 Oct 2025 17:13:10 UTC ETag: "00a354ae7e56459d5dfbe96d580d54ff59c0f004" ETag: "00a354ae7e56459d5dfbe96d580d54ff59c0f004" Expires: Sat, 20 Oct 2035 17:13:10 GMT Expires: Sat, 20 Oct 2035 17:13:11 GMT Last-Modified: Wed, 22 Oct 2025 17:13:10 GMT Last-Modified: Wed, 22 Oct 2025 17:13:11 GMT Server: OpenBSD httpd Server: OpenBSD httpd X-Content-Type-Options: nosniff X-Content-Type-Options: nosniff /* 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