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.
StrokeAccumulationPane.cpp
/* |
File: StrokeAccumulationPane.cpp |
Contains: Defintion of StrokeAccumulationPane class which manages content in a single |
tab control content area, and registration & callback functions for HIView model. |
Version: InkSample 1.1 |
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 (c) 2003 Apple Computer, Inc. All rights reserved. |
*/ |
#include <Carbon/Carbon.h> |
#include <iostream> // for std::cerr output |
#include "InkDefines.h" |
#include "StrokeAccumulationPane.h" |
#include "MLTEUtils.h" |
#include "InkSampleUtils.h" |
extern UInt32 gInkAppWritingMode; |
// ----------------------------------------------------------------------------- |
// ClassID |
// ----------------------------------------------------------------------------- |
CFStringRef gStrokeAccumulationPaneClassID = CFSTR( "com.apple.inksample.strokeaccumulation" ); |
// ----------------------------------------------------------------------------- |
// ClassRef |
// ----------------------------------------------------------------------------- |
static HIObjectClassRef gStrokeAccumulationPaneHIObjClassRef = NULL; |
// ----------------------------------------------------------------------------- |
// Internal C Function Prototypes |
// ----------------------------------------------------------------------------- |
static pascal OSStatus |
StrokeAccumulationPaneEventHandler( EventHandlerCallRef inCallRef, |
EventRef inEvent, void* inUserData ); |
static OSStatus |
StrokeAccumulationPaneConstruct( EventHandlerCallRef inCallRef, |
EventRef inEvent ); |
// ----------------------------------------------------------------------------- |
// Class Constructor - more important initialization occurs in Initialize |
// ----------------------------------------------------------------------------- |
StrokeAccumulationPane::StrokeAccumulationPane( HIViewRef parentInstance ) |
{ |
fTextInputHandler = NULL; |
fInkEventHandler = NULL; |
fMenuEventHandler = NULL; |
//fMouseEventHandler = NULL; |
fTabletEventHandler = NULL; |
fParentInstance = parentInstance; |
fHIViewWindow = NULL; |
} |
// ----------------------------------------------------------------------------- |
// Class Destructor |
// ----------------------------------------------------------------------------- |
StrokeAccumulationPane::~StrokeAccumulationPane( void ) |
{ |
if ( fTabletEventHandler != NULL ) |
{ |
verify_noerr( ::RemoveEventHandler( fTabletEventHandler ) ); |
fTextInputHandler = NULL; |
} |
if ( fMenuEventHandler != NULL ) |
{ |
verify_noerr( RemoveEventHandler( fMenuEventHandler ) ); |
fMenuEventHandler = NULL; |
} |
if ( fInkEventHandler != NULL ) |
{ |
verify_noerr( RemoveEventHandler( fInkEventHandler ) ); |
fInkEventHandler = NULL; |
} |
if ( fTextInputHandler != NULL ) |
{ |
verify_noerr( RemoveEventHandler( fTextInputHandler ) ); |
fTextInputHandler = NULL; |
} |
if( fMLTEObj != NULL ) |
TXNDeleteObject( fMLTEObj ); |
// text view will auto dispose when fTXNObj goes out of context & destructs |
return; |
} |
// ----------------------------------------------------------------------------- |
// Initialize [PUBLIC] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::Initialize( EventRef inEvent ) |
{ |
OSStatus status = paramErr; |
Rect userPaneBounds; |
Rect drawPaneBounds = {0,0,0,0}; |
Rect textViewBounds; |
Rect windowBounds; |
ControlID drawingPaneID = { 'DrAw', 0 }; |
ControlRef drawingPane = NULL; |
fHIViewWindow = NULL; |
fMLTEObj = NULL; |
fInkingStroke = false; |
// the parent control is the user pane control |
// created in IB in the nib |
fHIViewWindow = GetControlOwner( fParentInstance ); |
fWindowRef = FrontNonFloatingWindow(); |
// we use the parent control to define the bounds of this pane |
GetControlBounds( fParentInstance, &userPaneBounds ); |
GetWindowPortBounds( fHIViewWindow, &windowBounds ); |
status = GetControlByID( fHIViewWindow, &drawingPaneID, &drawingPane ); |
if( status == noErr ) |
GetControlBounds( drawingPane, &drawPaneBounds ); |
else |
status = noErr; |
ActivateControl( fParentInstance ); |
status = this->InstallMenuHandlersOnTarget( GetWindowEventTarget(fHIViewWindow) ); |
require_noerr( status, Initialize_err ); |
status = this->InstallInkHandlersOnTarget( GetWindowEventTarget(fHIViewWindow) ); // on window |
require_noerr( status, Initialize_err ); |
status = this->InstallTabletHandlersOnTarget( GetWindowEventTarget(fHIViewWindow) ); |
require_noerr( status, Initialize_err ); |
// text view will auto init |
// Init Textension occurs when fTXNObj constructor is first called |
// mlte object is smaller than userpane bounds |
textViewBounds.top = userPaneBounds.top; |
textViewBounds.bottom = userPaneBounds.bottom; |
textViewBounds.left = userPaneBounds.left; |
textViewBounds.right = userPaneBounds.right; |
status = this->TextViewCreate( fHIViewWindow, textViewBounds ); |
if( drawPaneBounds.top != drawPaneBounds.bottom ) |
fInkAreaBounds = drawPaneBounds; |
else |
{ |
fInkAreaBounds.top = userPaneBounds.top; |
fInkAreaBounds.bottom = userPaneBounds.bottom; |
fInkAreaBounds.left = textViewBounds.right + 20; |
fInkAreaBounds.right = fInkAreaBounds.left + (textViewBounds.right-textViewBounds.left); |
} |
Initialize_err: |
return status; |
} |
OSStatus |
StrokeAccumulationPane::Draw( EventRef inEvent ) |
{ |
this->TextViewDraw(); |
this->MyInkViewDrawPhrase(); |
if( fHIViewWindow != NULL ) |
{ |
CGrafPtr port = GetWindowPort( this->GetWindow() ); |
QDFlushPortBuffer( port, NULL ); |
} |
return noErr; |
} |
OSStatus |
StrokeAccumulationPane::Deactivate( EventRef inEvent ) |
{ |
this->TextViewFocus( false ); |
this->MyInkViewErase(); |
return noErr; |
} |
OSStatus |
StrokeAccumulationPane::Activate( EventRef inEvent ) |
{ |
this->TextViewFocus( true ); |
return noErr; |
} |
// ----------------------------------------------------------------------------- |
// Initialize [PUBLIC] - init any class globals here? |
// ----------------------------------------------------------------------------- |
void |
StrokeAccumulationPane::StaticInit() |
{ |
return; |
}; |
#pragma mark --- |
#pragma mark CARBON EVENTS |
#pragma mark --- |
// ----------------------------------------------------------------------------- |
// InstallMenuHandlersOnTarget [PRIVATE] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::InstallMenuHandlersOnTarget( EventTargetRef targetRef ) |
{ |
static const EventTypeSpec sAppEvents[] = |
{ |
{ kEventClassCommand, kEventCommandProcess }, |
{ kEventClassCommand, kEventCommandUpdateStatus } |
}; |
OSStatus status = InstallEventHandler( targetRef, StrokeAccumulationPane::MenuEventHandler, |
GetEventTypeCount( sAppEvents ), |
sAppEvents, this, &fMenuEventHandler ); |
return status; |
} |
// ----------------------------------------------------------------------------- |
// InstallTextInputHandlersOnTarget [PRIVATE] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::InstallTextInputHandlersOnTarget( EventTargetRef targetRef ) |
{ |
static const EventTypeSpec kTextInputEvents[] = |
{ |
{ kEventClassCommand, kEventCommandProcess }, |
{ kEventClassCommand, kEventCommandUpdateStatus }, |
{ kEventClassKeyboard, kEventRawKeyDown }, |
{ kEventClassControl, kEventControlVisibilityChanged }, |
{ kEventClassService, kEventServiceGetTypes }, |
{ kEventClassService, kEventServiceCopy }, |
{ kEventClassService, kEventServicePaste } |
}; |
OSStatus status = InstallEventHandler( targetRef, StrokeAccumulationPane::TextInputHandler, |
GetEventTypeCount( kTextInputEvents ), |
kTextInputEvents, this, &fTextInputHandler ); |
require_noerr( status, InstallTextInputHandlersOnTarget_err ); |
InstallTextInputHandlersOnTarget_err: |
return status; |
} |
OSStatus |
StrokeAccumulationPane::InstallInkHandlersOnTarget( EventTargetRef targetRef ) |
{ |
static const EventTypeSpec kInkEvents[] = |
{ |
{ kEventClassInk, kEventInkText }, |
{ kEventClassInk, kEventInkGesture } |
}; |
OSStatus status = InstallEventHandler( targetRef, StrokeAccumulationPane::InkHandler, |
GetEventTypeCount( kInkEvents ), |
kInkEvents, this, &fInkEventHandler ); |
require_noerr( status, InstallInkHandlersOnTarget_err ); |
InstallInkHandlersOnTarget_err: |
return status; |
} |
// ----------------------------------------------------------------------------- |
// InstallTabletHandlersOnTarget [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::InstallTabletHandlersOnTarget( EventTargetRef targetRef ) |
{ |
static const EventTypeSpec sMouseEvents[] = |
{ |
{ kEventClassMouse, kEventMouseDown }, |
{ kEventClassMouse, kEventMouseUp }, |
{ kEventClassMouse, kEventMouseMoved }, |
{ kEventClassMouse, kEventMouseDragged } |
}; |
OSStatus status = ::InstallEventHandler( targetRef, StrokeAccumulationPane::TabletEventHandler, |
GetEventTypeCount( sMouseEvents ), |
sMouseEvents, this, &fTabletEventHandler ); |
return status; |
} |
// ----------------------------------------------------------------------------- |
// MenuEventHandler [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::MenuEventHandler( EventHandlerCallRef inHandlerRef, |
EventRef inEvent, void* userData ) |
{ |
OSStatus status = eventNotHandledErr; |
HICommand hiCommand; |
StrokeAccumulationPane* thisPane = (StrokeAccumulationPane*)userData; |
UInt32 eventKind = GetEventKind( inEvent ); |
require_action( thisPane->IsParentVisible(), NotFocus_err, status = eventNotHandledErr ); |
switch ( GetEventClass( inEvent ) ) |
{ |
case kEventClassCommand: |
{ |
status = GetEventParameter( inEvent, kEventParamDirectObject, typeHICommand, |
NULL, sizeof( HICommand ), NULL, (void *) &hiCommand ); |
require_noerr( status, HandleCommandEvent_err ); |
if( eventKind == kEventProcessCommand |
&& ( hiCommand.attributes & kHICommandFromMenu ) == true ) |
status = thisPane->ProcessHICommand( hiCommand ); |
} |
break; |
default: |
status = eventNotHandledErr; |
break; |
} |
HandleCommandEvent_err: |
NotFocus_err: |
#if DEBUG_ERROR_LOGS |
if( status != eventNotHandledErr ) |
std::cerr << "StrokeAccumulationPane::MenuEventHandler got status: " << status << std::endl; |
#endif |
return status; |
} |
// ----------------------------------------------------------------------------- |
// TextInputHandler [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextInputHandler( EventHandlerCallRef inHandlerRef, |
EventRef inEvent, void* userData ) |
{ |
OSStatus status = eventNotHandledErr; |
StrokeAccumulationPane* thisPane = (StrokeAccumulationPane*)userData; |
require_action( thisPane->IsParentVisible(), NotFocus_err, status = eventNotHandledErr ); |
NotFocus_err: |
return eventNotHandledErr; |
} |
// ----------------------------------------------------------------------------- |
// TabletEventHandler [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TabletEventHandler( EventHandlerCallRef inHandlerRef, |
EventRef inEvent, void* userData ) |
{ |
OSStatus status = eventNotHandledErr; |
StrokeAccumulationPane* thisPane = (StrokeAccumulationPane*)userData; |
UInt32 tabletEventType = 0; |
UInt32 mouseEventKind = 0; |
// don't do anything if this pane is not the front most active |
require_action( thisPane->IsMyWindowActive(), NotFocus_err, status = eventNotHandledErr ); |
require_action( thisPane->IsParentVisible(), NotFocus_err, status = eventNotHandledErr ); |
// must be a mouse event |
require( GetEventClass( inEvent ) == kEventClassMouse, NotTabletEvent_err ); |
// what kind of tablet event? |
status = GetEventParameter( inEvent, kEventParamTabletEventType, typeUInt32, |
NULL, sizeof(UInt32), NULL, &tabletEventType ); |
require_action( status == noErr, CantGetTabletEventType_err, status = eventNotHandledErr ); |
// reset status to not handled |
status = eventNotHandledErr; |
// Is this mouse event from a tablet? |
if( tabletEventType == kEventTabletPoint ) |
{ |
mouseEventKind = GetEventKind( inEvent ); |
switch( mouseEventKind ) |
{ |
// these are the event kinds that indicate we're inking or ending inking |
case kEventMouseDown: |
case kEventMouseUp: |
case kEventMouseDragged: |
status = thisPane->HandleTabletPoint( inHandlerRef, inEvent, mouseEventKind ); |
break; |
default: |
// any other kind - like mouse moved - we won't handle |
status = eventNotHandledErr; |
break; |
} |
} |
// is this a mouse down event from the actual mouse - not tablet? |
else if( mouseEventKind == kEventMouseDown ) |
{ |
// non tablet mouse down events |
status = thisPane->HandleMouseDown( inHandlerRef, inEvent, mouseEventKind ); |
} |
CantGetTabletEventType_err: |
NotTabletEvent_err: |
#if DEBUG_ERROR_LOGS |
if( status != eventNotHandledErr ) |
std::cerr << "StrokeAccumulationPane::TabletEventHandler got status: " << status << std::endl; |
else |
std::cerr << "StrokeAccumulationPane::TabletEventHandler got status: eventNotHandledErr" << std::endl; |
#endif |
NotFocus_err: |
return status; |
} |
// ----------------------------------------------------------------------------- |
// InkHandler [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::InkHandler( EventHandlerCallRef inCallRef, EventRef inEvent, |
void* inUserData ) |
{ |
OSStatus status = eventNotHandledErr; |
StrokeAccumulationPane* thisPane = (StrokeAccumulationPane*)inUserData; |
#if DEBUG_EVENT_TRACING |
std::cerr << "Call StrokeAccumulationPane::InkHandler..." << std::endl; |
#endif |
require_action( thisPane->IsParentVisible(), NotFocus_err, status = eventNotHandledErr ); |
switch( GetEventKind( inEvent ) ) |
{ |
case kEventInkText: |
{ |
status = thisPane->HandleInkTextEvent( inCallRef, inEvent ); |
} |
break; |
case kEventInkGesture: |
{ |
status = thisPane->HandleGestureEvent( inCallRef, inEvent ); |
} |
break; |
} |
NotFocus_err: |
#if DEBUG_ERROR_LOGS |
if( status == eventNotHandledErr ) |
std::cerr << "StrokeAccumulationPane::InkHandler won't handle the event" << std::endl; |
#endif |
return status; |
} |
// ----------------------------------------------------------------------------- |
// HandleInkTextEvent [PRIVATE] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::HandleInkTextEvent( EventHandlerCallRef inCallRef, EventRef inEvent ) |
{ |
OSStatus status = noErr; |
InkTextRef inkRef = NULL; |
CFStringRef cfString = NULL; |
Boolean isShortCut = false; |
#if DEBUG_EVENT_TRACING |
std::cerr << "kEventInkText event..." << std::endl; |
#endif |
status = GetEventParameter( inEvent, kEventParamInkKeyboardShortcut, typeBoolean, |
NULL, sizeof(Boolean), NULL, &isShortCut ); |
if( isShortCut ) |
{ |
this->UISignalInkEvent( kMyInkShortcutEventSignal ); |
return eventNotHandledErr; |
} |
this->UISignalInkEvent( kMyInkTextEventSignal ); |
status = GetEventParameter( inEvent, kEventParamInkTextRef, typePtr, |
NULL, sizeof(Ptr), NULL, &inkRef ); |
require_noerr( status, CantGetInkRef ); |
CFRetain( inkRef ); |
cfString = InkTextCreateCFString( inkRef, 0 ); |
require_action( cfString != NULL, CantGetString, status = eventNotHandledErr ); |
status = this->TextViewAppendCFString( cfString ); |
require_noerr( status, CantSetString ); |
// auto space between words |
this->TextViewAppendString( " ", 1 ); |
CantSetString: |
if( cfString != NULL ) |
CFRelease( cfString ); |
CantGetString: |
CantGetInkRef: |
if (status==noErr) |
return noErr; |
else |
return eventNotHandledErr; |
} |
// ----------------------------------------------------------------------------- |
// HandleGestureEvent [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::HandleGestureEvent( EventHandlerCallRef inCallRef, EventRef inEvent ) |
{ |
OSErr status = noErr; |
UInt32 gestureKind = NULL; |
HICommand hiCmd; |
HIRect bounds; |
Boolean hasHotSpot; |
HIPoint hotspot; |
status = GetEventParameter( inEvent, kEventParamInkGestureKind, |
typeUInt32, NULL, sizeof(UInt32), |
NULL, &gestureKind ); |
require_noerr( status, CantGetGestureKind ); |
this->UISignalInkEvent( gestureKind ); |
status = GetEventParameter( inEvent, kEventParamInkGestureBounds, |
typeHIRect, NULL, sizeof(HIRect), |
NULL, &bounds ); |
require_noerr( status, CantGetGestureBounds ); |
status = GetEventParameter( inEvent, kEventParamInkGestureHotspot, |
typeHIPoint, NULL, sizeof(HIPoint), |
NULL, &hotspot ); |
hasHotSpot = (status == noErr); |
switch( gestureKind ) |
{ |
/* Context-independent (non-tentative) gestures */ |
case kInkGestureUndo: //'undo' |
hiCmd.commandID = kHICommandUndo; |
status = TextViewProcessHICommand( hiCmd ); |
break; |
case kInkGestureCut: //'cut ' |
hiCmd.commandID = kHICommandCut; |
status = TextViewProcessHICommand( hiCmd ); |
break; |
case kInkGestureCopy: //'copy' |
hiCmd.commandID = kHICommandCopy; |
status = TextViewProcessHICommand( hiCmd ); |
break; |
case kInkGesturePaste: //'past' |
hiCmd.commandID = kHICommandPaste; |
if( hasHotSpot == true ) |
{ |
status = this->TextViewSetOffsetWithHIPoint( hotspot ); |
} |
status = TextViewProcessHICommand( hiCmd ); |
break; |
case kInkGestureClear: //'cler' |
hiCmd.commandID = kHICommandClear; |
status = TextViewProcessHICommand( hiCmd ); |
break; |
case kInkGestureSelectAll: //'sall' |
hiCmd.commandID = kHICommandSelectAll; |
status = TextViewProcessHICommand( hiCmd ); |
break; |
case kInkGestureEscape: //'esc ' |
hiCmd.commandID = kHICommandCancel; |
status = TextViewProcessHICommand( hiCmd ); |
break; |
case kInkGestureTab: //'tab ' |
{ |
if( hasHotSpot == true ) |
{ |
status = this->TextViewSetOffsetWithHIPoint( hotspot ); |
} |
// insert at the current insertion point, or replace the current selection, with a tab |
status = TextViewReplaceString( "\t", 1, kTXNUseCurrentSelection, kTXNUseCurrentSelection ); |
} |
break; |
case kInkGestureLeftSpace: //'lspc' |
case kInkGestureRightSpace: //'rspc' |
{ |
if( hasHotSpot == true ) |
{ |
status = this->TextViewSetOffsetWithHIPoint( hotspot ); |
} |
// insert at the current insertion point, or replace the current selection, with a |
// space. We're not distinguishing between left or right spaces. |
status = TextViewReplaceString( " ", kTXNUseCurrentSelection, kTXNUseCurrentSelection ); |
} |
break; |
case kInkGestureLeftReturn: //'lrtn' |
case kInkGestureRightReturn: //'rrtn' |
{ |
if( hasHotSpot == true ) |
{ |
status = this->TextViewSetOffsetWithHIPoint( hotspot ); |
} |
// insert at the current insertion point, or replace the current selection, with a |
// return. We're not distinguishing between left or right returns. |
status = TextViewReplaceString( "\r", kTXNUseCurrentSelection, kTXNUseCurrentSelection ); |
} |
break; |
case kInkGestureDelete: //'del ' |
hiCmd.commandID = kHICommandClear; |
// maybe check context and set selection here based on bounding box |
status = TextViewProcessHICommand( hiCmd ); |
break; |
/* Context-dependent (tentative) gestures*/ |
case kInkGestureJoin: //'join' |
status = TextViewJoin( bounds ); |
break; |
default: |
break; |
} |
CantGetGestureBounds: |
CantGetGestureKind: |
if (status==noErr) |
return noErr; |
else |
return eventNotHandledErr; |
} |
// ----------------------------------------------------------------------------- |
// HandleTabletPoint [PROTECTED] - do ink data collection or phrase termination |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::HandleTabletPoint( EventHandlerCallRef inCallRef, EventRef inEvent, UInt32 mouseEventKind ) |
{ |
#pragma unused( inCallRef ) |
OSStatus status = eventNotHandledErr; |
Point qdGlobalPoint; |
GrafPtr savePort; |
// where is the mouse? |
status = GetEventParameter(inEvent, kEventParamMouseLocation, |
typeQDPoint, NULL, sizeof(Point), |
NULL, (void*) &qdGlobalPoint); |
require_action( status == noErr, TabletEvent_err, status = eventNotHandledErr ); |
// Move the point into local coordinates, from now on this is really qdLOCALPoint... |
GetPort( &savePort ); |
SetPortWindowPort( this->GetWindow() ); |
GlobalToLocal( &qdGlobalPoint ); |
SetPort( savePort ); |
// reset status, we're not handing anything yet |
status = eventNotHandledErr; |
// is the mouse inside the bounds of my ink view? |
if( MyInkViewPointInInkView( qdGlobalPoint ) ) |
{ |
// did the mouse just touch down - indicating the start of a stroke? |
if( mouseEventKind == kEventMouseDown ) |
fInkingStroke = true; // start inking stroke |
// we expect kEventMouseDown, kEventMouseUp, or kEventMouseDragged |
// We collect ink data for mouse down and mouse drag, and end collection |
// on mouse up. |
// Is this not mouse up? and if so are we in the middle of inking? |
if( mouseEventKind != kEventMouseUp && fInkingStroke == true ) |
{ |
HIPoint location; |
TabletPointRec tabletPt; |
UInt32 modifiers; |
// Get the full-resolution, floating point mouse location |
status = GetEventParameter( inEvent, kEventParamMouseLocation, |
typeHIPoint, NULL /*outActualType*/, sizeof( location ), |
NULL /*outActualSize*/, &location ); |
require_noerr( status, TabletEvent_err ); |
// Get the tablet data record |
status = GetEventParameter(inEvent, kEventParamTabletPointRec, |
typeTabletPointRec, NULL, sizeof(TabletPointRec), |
NULL, (void*) &tabletPt); |
require_noerr( status, TabletEvent_err ); |
// Get any keyboard modifiers in use |
status = GetEventParameter( inEvent, kEventParamKeyModifiers, typeUInt32, |
NULL, sizeof( modifiers ), NULL, &modifiers ); |
require_noerr( status, TabletEvent_err ); |
// Add all the above gathered InkPoint data into our inkpoint array |
AddPoint( location, tabletPt, modifiers ); |
// inval and draw our ink view |
status = this->MyInkViewInvalidate(); |
// instantly draw this point data |
this->MyInkViewDrawPoint( location, tabletPt.pressure); |
} |
// Above condition was false so this is a mouse up? |
// Were we in the middle of inking at the time? |
// If so, we want to terminate stroke data collection and add the |
// stroke to the current ink phrase |
else if( fInkingStroke == true ) |
{ |
AddStroke(); // this will also clear & reset the array of inkpoint data |
fInkingStroke = false; // not inking any more |
status = noErr; // yes we handled this event |
} |
} |
else // The mouse is not inside the Ink View bounds |
{ |
// Were we inking? Terminate stroke if so |
if( fInkingStroke == true ) |
{ |
AddStroke(); // this will also clear & reset the array of inkpoint data |
fInkingStroke = false; // not inking any more |
status = noErr; // yes we handled this event |
} |
// If this was a mouse down, maybe it is on our button to do ink |
// phrase termination? |
if( mouseEventKind == kEventMouseDown ) |
{ |
ControlRef controlHit = NULL; |
short part = 0; |
ControlID controlID = { 0,0 }; |
// did we hit a control? |
controlHit = FindControlUnderMouse( qdGlobalPoint, this->GetWindow(), &part); |
require_action( controlHit != NULL, TabletEvent_err, status = eventNotHandledErr ); |
status = GetControlID( controlHit, &controlID ); |
require_action( status == noErr, TabletEvent_err, status = eventNotHandledErr ); |
// is the control our terminate ink phrase button? |
if( controlID.signature == kMyInkPhraseTerminateForStroke ) |
{ |
this->MyInkViewTerminateInking(); |
return noErr; |
} |
// is the control hit our erase custom ink area button? |
else if( controlID.signature == kMyEraseCustomInkButton ) |
{ |
this->MyInkViewErase(); |
return noErr; |
} |
// some other control was hit |
// we won't handle it |
else |
status = eventNotHandledErr; |
} |
} |
TabletEvent_err: |
return status; |
} |
// ----------------------------------------------------------------------------- |
// HandleMouseDown [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::HandleMouseDown( EventHandlerCallRef inCallRef, EventRef inEvent, UInt32 mouseEventKind ) |
{ |
OSStatus status = eventNotHandledErr; |
Point qdGlobalPoint; // the local |
GrafPtr savePort; |
status = GetEventParameter(inEvent, kEventParamMouseLocation, |
typeQDPoint, NULL, sizeof(Point), |
NULL, (void*) &qdGlobalPoint); |
require_action( status == noErr, MouseDownEvent_err, status = eventNotHandledErr ); |
// Move the point into local coordinates, from now on this is really qdLOCALPoint... |
GetPort( &savePort ); |
SetPortWindowPort( this->GetWindow() ); |
GlobalToLocal( &qdGlobalPoint ); |
SetPort( savePort ); |
status = eventNotHandledErr; |
switch( mouseEventKind ) |
{ |
case kEventMouseDown: |
{ |
ControlRef controlHit = NULL; |
short part = 0; |
controlHit = FindControlUnderMouse( qdGlobalPoint, this->GetWindow(), &part); |
if( controlHit != NULL ) |
{ |
ControlID controlID = { 0,0 }; |
status = GetControlID( controlHit, &controlID ); |
if( status == noErr ) |
{ |
// is the control our terminate ink phrase button? |
if( controlID.signature == kMyInkPhraseTerminateForStroke ) |
{ |
this->MyInkViewTerminateInking(); |
return noErr; |
} |
// is the control hit our erase custom ink area button? |
else if( controlID.signature == kMyEraseCustomInkButton ) |
{ |
this->MyInkViewErase(); |
return noErr; |
} |
// some other control was hit |
// we won't handle it |
status = eventNotHandledErr; |
} |
else |
status = eventNotHandledErr; |
} |
} |
break; |
default: |
status = eventNotHandledErr; |
} |
MouseDownEvent_err: |
return status; |
} |
// ----------------------------------------------------------------------------- |
// AddPoint [PROTECTED] - Add the InkPoint data in our array to the current ink phrase |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::AddPoint( HIPoint location, TabletPointRec tabletPt, UInt32 modifiers ) |
{ |
#if DEBUG_EVENT_TRACING |
std::cerr << "Add point..." << std::endl; |
#endif |
// make a CISInkPoint object and push it onto the vector of InkPoints |
CISInkPoint inkPoint( location, tabletPt, modifiers ); |
// vector for data accumulation |
fInkPointsArray.push_back(inkPoint); |
// also put a copy in the vector used only for drawing |
fInkPointsToDrawArray.push_back(inkPoint); |
return noErr; |
} |
// ----------------------------------------------------------------------------- |
// AddStroke [PROTECTED] - Add the InkPoint data in our array to the current ink phrase |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::AddStroke() |
{ |
UInt32 pointCount = fInkPointsArray.size(); |
#if DEBUG_EVENT_TRACING |
std::cerr << "Add stroke..." << std::endl; |
#endif |
// allocate space for an InkPoint array |
InkPoint* inkPointArray = new InkPoint[pointCount]; |
if( inkPointArray != NULL ) |
{ |
// copy data from vector to array |
for( UInt16 i = 0; i < pointCount; i++ ) |
{ |
inkPointArray[i].point = fInkPointsArray[i].fInkPointRec.point; |
inkPointArray[i].tabletPointData = fInkPointsArray[i].fInkPointRec.tabletPointData; |
inkPointArray[i].keyModifiers = fInkPointsArray[i].fInkPointRec.keyModifiers; |
} |
// add stroke |
InkAddStrokeToCurrentPhrase( pointCount, inkPointArray ); |
// clear the vector |
fInkPointsArray.clear(); |
// delete allocated memory |
delete[] inkPointArray; |
} |
return noErr; |
} |
// ----------------------------------------------------------------------------- |
// ProcessHICommand [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::ProcessHICommand( const HICommand& hiCommand ) |
{ |
OSStatus status = eventNotHandledErr; |
switch( hiCommand.commandID ) |
{ |
default: |
status = this->TextViewProcessHICommand( hiCommand ); |
} |
return status; |
} |
#pragma mark --- |
#pragma mark TEXT VIEW INTERFACE |
#pragma mark --- |
// ----------------------------------------------------------------------------- |
// TextViewCreate [PUBLIC] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewCreate( WindowRef window, Rect& bounds ) |
{ |
OSStatus status = paramErr; |
fMLTEObj = MLTECreateObject( window, bounds ); |
if( fMLTEObj != NULL ) |
status = noErr; |
return status; |
} |
// ----------------------------------------------------------------------------- |
// TextViewSetVisibility [PUBLIC] |
// ----------------------------------------------------------------------------- |
void |
StrokeAccumulationPane::TextViewSetVisibility( Boolean vis ) |
{ |
if( vis == false ) // unfocus before going invisible |
TextViewFocus(false); |
MLTESetObjectVisibility(fMLTEObj, vis); |
if( vis == true ) |
TextViewFocus(true); // focus after going visible |
} |
// ----------------------------------------------------------------------------- |
// TextViewDraw [PUBLIC] |
// ----------------------------------------------------------------------------- |
void |
StrokeAccumulationPane::TextViewDraw() |
{ |
::TXNDraw( fMLTEObj, NULL ); |
} |
// ----------------------------------------------------------------------------- |
// TextViewFocus [PUBLIC] |
// ----------------------------------------------------------------------------- |
void |
StrokeAccumulationPane::TextViewFocus( Boolean focus) |
{ |
::TXNFocus( fMLTEObj, focus ); |
} |
// ----------------------------------------------------------------------------- |
// TextViewAppendCFString [PUBLIC] - append a CFString to the text view for this pane |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewAppendCFString( CFStringRef cfString ) |
{ |
if( cfString != NULL ) |
{ |
#if MY_DEBUG |
OutputCFStringToStdErr( cfString ); |
#endif |
return MLTESetCFStringToObject( fMLTEObj, cfString, kTXNEndOffset, kTXNEndOffset ); |
} |
return paramErr; |
} |
// ----------------------------------------------------------------------------- |
// TextViewAppendString [PUBLIC] - append a C string to the text view for this pane |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewAppendString( char* str, CFIndex len ) |
{ |
if( str != NULL ) |
{ |
#if MY_DEBUG |
std::cerr << str; |
#endif |
return MLTESetStringToObject( fMLTEObj, str, len, kTXNEndOffset, kTXNEndOffset ); |
} |
return paramErr; |
} |
// ----------------------------------------------------------------------------- |
// TextViewReplaceCFString [PROTECTED] |
// |
// Replace whatever is at the given offsets of text view for this pane |
// with the CFString parameter |
// |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewReplaceCFString( CFStringRef cfString, UInt32 start, UInt32 end ) |
{ |
if( cfString != NULL ) |
{ |
#if MY_DEBUG |
std::cerr << "Replacing offsets start: " << start << " to end: " << end << " with: "; |
OutputCFStringToStdErr( cfString ); |
std::cerr << std::endl; |
#endif |
return MLTESetCFStringToObject( fMLTEObj, cfString, start, end ); |
} |
return paramErr; |
} |
// ----------------------------------------------------------------------------- |
// TextViewReplaceString [PROTECTED] |
// |
// Replace whatever is at the given offsets of text view for this pane |
// with the string parameter |
// |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewReplaceString( char* str, CFIndex len, UInt32 start, UInt32 end ) |
{ |
#if MY_DEBUG |
if( str != NULL && len > 0 ) |
std::cerr << "Replacing offsets start: " << start << " to end: " << end << " with: " |
<< str << std::endl; |
#endif |
return MLTESetStringToObject( fMLTEObj, str, len, start, end ); |
} |
// ----------------------------------------------------------------------------- |
// TextViewProcessHICommand [PUBLIC] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewProcessHICommand(const HICommand& cmd) |
{ |
return MLTEProcessHICommand(fMLTEObj, cmd ); |
} |
// ----------------------------------------------------------------------------- |
// TextViewKeyDown [PUBLIC] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewKeyDown( UniChar uChar ) |
{ |
return paramErr; |
} |
// ----------------------------------------------------------------------------- |
// TextViewSetSelectionOffsets [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewSetSelectionOffsets( UInt32 start, UInt32 end ) |
{ |
return ::TXNSetSelection( fMLTEObj, start, end ); |
} |
// ----------------------------------------------------------------------------- |
// TextViewSetOffsetWithHIPoint [PUBLIC] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewSetOffsetWithHIPoint( HIPoint pt ) |
{ |
OSStatus status = paramErr; |
UInt32 offset = kTXNUseCurrentSelection; |
status = TextViewHIPointToOffset( pt, offset ); |
if( status == noErr ) |
status = TextViewSetSelectionOffsets( offset, offset ); |
else |
{ |
Point qdPoint = {0,0}; |
GrafPtr savePort; |
GetPort(&savePort); |
SetPortWindowPort( this->GetWindow() ); |
HIPointToQDPoint( pt, qdPoint ); |
GlobalToLocal( &qdPoint ); |
SetPort( savePort ); |
// mysterious coordinate mismatch requires this correction |
qdPoint.v -=20; |
qdPoint.h +=5; |
status = TextViewSetOffsetWithQDPoint( qdPoint ); |
} |
return status; |
} |
// ----------------------------------------------------------------------------- |
// TextViewSetOffsetWithQDPoint [PUBLIC] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewSetOffsetWithQDPoint( Point pt ) |
{ |
OSStatus status = paramErr; |
UInt32 offset = kTXNUseCurrentSelection; |
status = TextViewQDPointToOffset( pt, offset ); |
if( status == noErr ) |
status = TextViewSetSelectionOffsets( offset, offset ); |
return status; |
} |
// ----------------------------------------------------------------------------- |
// TextViewHIPointToOffset [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewHIPointToOffset( HIPoint& hiPoint, UInt32& offset ) |
{ |
return MLTEGlobalHIPointToOffset( fMLTEObj, hiPoint, offset ); |
} |
// ----------------------------------------------------------------------------- |
// TextViewQDPointToOffset [PROTECTED] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewQDPointToOffset( Point& pt, UInt32& offset ) |
{ |
return TXNPointToOffset( fMLTEObj, pt, &offset ); |
} |
// ----------------------------------------------------------------------------- |
// TextViewJoin [PUBLIC] |
// ----------------------------------------------------------------------------- |
OSStatus |
StrokeAccumulationPane::TextViewJoin( HIRect bounds ) |
{ |
return paramErr; |
} |
OSStatus |
StrokeAccumulationPane::UISignalInkEvent( UInt32 signalInkEventKind ) |
{ |
OSStatus status = paramErr; |
ControlRef staticTextControl = NULL; |
ControlID controlID; |
controlID.signature = kMyStaticTextInkStrokeAccumPane; |
controlID.id = 1; |
char string[50]; |
string[0] = 0; // default to zero terminated |
status = GetControlByID( fHIViewWindow, &controlID, &staticTextControl); |
if( status == noErr && IsValidControlHandle(staticTextControl) ) |
{ |
GetStringForInkUISignal( signalInkEventKind, string ); |
status = SetControlData( staticTextControl, kControlEntireControl /*part*/, |
kControlEditTextTextTag, strlen(string), string ); |
require_noerr( status, fail_updatecontrol); |
Draw1Control( staticTextControl ); |
} |
fail_updatecontrol: |
return status; |
} |
#pragma mark --- |
#pragma mark INK VIEW FUNCTIONS |
#pragma mark --- |
OSStatus |
StrokeAccumulationPane::MyInkViewInvalidate() |
{ |
OSStatus status; |
CGrafPtr port = GetWindowPort( this->GetWindow() ); |
status = InvalWindowRect( this->GetWindow(), &fInkAreaBounds ); |
QDFlushPortBuffer( port, NULL ); |
return status; |
} |
OSStatus |
StrokeAccumulationPane::MyInkViewDrawPhrase() |
{ |
Rect clipRect = fInkAreaBounds; |
GrafPtr savePort; |
RgnHandle saveClip = NewRgn(); |
UInt32 pointCount = fInkPointsToDrawArray.size(); |
Point qdPoint; |
Point lastQDPoint; |
GetPort(&savePort); |
SetPortWindowPort( fWindowRef ); |
GetClip( saveClip ); |
MacInsetRect( &clipRect, -2, -2 ); |
ClipRect( &clipRect ); |
ForeColor( blackColor ); // black frame |
MacFrameRect( &fInkAreaBounds ); |
ForeColor( redColor ); // red lines |
if( pointCount > 0 ) |
{ |
HIPointToQDPoint( fInkPointsToDrawArray[0].fInkPointRec.point, lastQDPoint ); |
GlobalToLocal( &lastQDPoint ); |
MoveTo( lastQDPoint.h, lastQDPoint.v ); |
if( pointCount > 1 ) |
{ |
for( UInt16 i = 1; i < pointCount; i++ ) |
{ |
HIPointToQDPoint( fInkPointsToDrawArray[i].fInkPointRec.point, qdPoint ); |
GlobalToLocal( &qdPoint ); |
LineTo( qdPoint.h, qdPoint.v ); |
lastQDPoint = qdPoint; |
} |
} else |
LineTo( lastQDPoint.h, lastQDPoint.v ); |
} |
SetClip( saveClip ); |
SetPort( savePort ); |
DisposeRgn( saveClip ); |
return noErr; |
} |
OSStatus |
StrokeAccumulationPane::MyInkViewDrawPoint( HIPoint hiPt, SInt16 pressure ) |
{ |
Rect clipRect = fInkAreaBounds; |
GrafPtr savePort; |
CGrafPtr thisPort = GetWindowPort( this->GetWindow() ); |
RgnHandle saveClip = NewRgn(); |
GetPort(&savePort); |
GetClip( saveClip ); |
SetPort( thisPort ); |
Point qdPoint; |
HIPointToQDPoint( hiPt, qdPoint ); |
GlobalToLocal( &qdPoint ); |
Rect inkDot = { qdPoint.v-2, qdPoint.h-2, qdPoint.v+2, qdPoint.h+2 }; |
ForeColor( redColor ); |
PaintOval(&inkDot); |
QDFlushPortBuffer( thisPort, NULL ); |
SetClip( saveClip ); |
SetPort( savePort ); |
DisposeRgn( saveClip ); |
return noErr; |
} |
void |
StrokeAccumulationPane::MyInkViewTerminateInking() |
{ |
// if( InkIsInking() ) |
InkTerminateCurrentPhrase(kInkSourceApplication); |
fInkPointsArray.clear(); |
fInkPointsToDrawArray.clear(); |
} |
OSStatus |
StrokeAccumulationPane::MyInkViewErase() |
{ |
Rect eraseRect = fInkAreaBounds; |
MacInsetRect( &eraseRect, -1, -1 ); |
GrafPtr savePort; |
CGrafPtr thisPort = GetWindowPort( this->GetWindow() ); |
RgnHandle saveClip = NewRgn(); |
GetPort(&savePort); |
GetClip( saveClip ); |
SetPort( thisPort ); |
EraseRect( &eraseRect ); |
InvalWindowRect( this->GetWindow(), &eraseRect ); |
QDFlushPortBuffer( thisPort, NULL ); |
SetClip( saveClip ); |
SetPort( savePort ); |
DisposeRgn( saveClip ); |
return noErr; |
}; |
Boolean |
StrokeAccumulationPane::MyInkViewPointInInkView( Point qdPoint ) |
{ |
if( qdPoint.v > fInkAreaBounds.top |
&& qdPoint.v < fInkAreaBounds.bottom |
&& qdPoint.h > fInkAreaBounds.left |
&& qdPoint.h < fInkAreaBounds.right |
) |
return true; |
return false; |
}; |
#pragma mark --- |
#pragma mark CISINKPOINT CLASS MEMBER FUNCTIONS |
#pragma mark --- |
StrokeAccumulationPane::CISInkPoint::CISInkPoint( HIPoint& hiPt, TabletPointRec tabletData, UInt32 keyMods ) |
{ |
fInkPointRec.point = hiPt; |
fInkPointRec.tabletPointData = tabletData; |
fInkPointRec.keyModifiers = keyMods; |
} |
// copy constructor is required by <vector> to allow copy into the vector |
StrokeAccumulationPane::CISInkPoint::CISInkPoint( const StrokeAccumulationPane::CISInkPoint& orig ) |
{ |
fInkPointRec.point = orig.fInkPointRec.point; |
fInkPointRec.tabletPointData = orig.fInkPointRec.tabletPointData; |
fInkPointRec.keyModifiers = orig.fInkPointRec.keyModifiers; |
} |
StrokeAccumulationPane::CISInkPoint& |
StrokeAccumulationPane::CISInkPoint::operator=( const StrokeAccumulationPane::CISInkPoint& orig ) |
{ |
if( &orig != this ) |
{ |
fInkPointRec.point = orig.fInkPointRec.point; |
fInkPointRec.tabletPointData = orig.fInkPointRec.tabletPointData; |
fInkPointRec.keyModifiers = orig.fInkPointRec.keyModifiers; |
} |
return *this; |
} |
// this function is required by <vector> to allow sorting |
Boolean |
StrokeAccumulationPane::CISInkPoint::operator<( const CISInkPoint& orig ) |
{ |
if( fInkPointRec.point.x < orig.fInkPointRec.point.x |
|| fInkPointRec.point.y < orig.fInkPointRec.point.y ) |
return true; |
return false; |
} |
#pragma mark --- |
#pragma mark HIVIEW SETUP |
#pragma mark --- |
// ----------------------------------------------------------------------------- |
// StrokeAccumulationPaneRegister [EXPORT] |
// |
// Register the class description of our pane with the HIView system |
// This will cause our callbacks to be invoked when an object in a |
// window with our gStrokeAccumulationPaneClassID is created |
// ----------------------------------------------------------------------------- |
OSStatus StrokeAccumulationPaneRegister( void ) |
{ |
OSStatus status = noErr; |
// check to see if we've already registered the class. If not, then go ahead |
// and register it. |
if ( gStrokeAccumulationPaneHIObjClassRef == NULL ) |
{ |
// what our pane can handle |
static const EventTypeSpec eventTypes[] = |
{ |
{ kEventClassHIObject, kEventHIObjectConstruct }, |
{ kEventClassHIObject, kEventHIObjectInitialize }, |
{ kEventClassHIObject, kEventHIObjectDestruct }, |
{ kEventClassControl, kEventControlInitialize }, |
{ kEventClassControl, kEventControlDraw }, |
{ kEventClassControl, kEventControlActivate }, |
{ kEventClassControl, kEventControlDeactivate }, |
{ kEventClassControl, kEventControlVisibilityChanged } |
}; |
// register the pane with the HIObject system |
status = HIObjectRegisterSubclass( gStrokeAccumulationPaneClassID, |
kHIViewClassID, 0/*optionBits*/, |
StrokeAccumulationPaneEventHandler, |
GetEventTypeCount( eventTypes ), |
eventTypes, NULL/*constructData*/, |
&gStrokeAccumulationPaneHIObjClassRef ); |
check_noerr( status ); |
} |
return status; |
} |
// ----------------------------------------------------------------------------- |
// StrokeAccumulationPaneConstruct [INTERNAL] |
// |
// If a window containing an object matching our |
// gStrokeAccumulationPaneClassID is created, this callback is invoked, |
// and we instantiate an instance of the StrokeAccumulationPane class |
// ----------------------------------------------------------------------------- |
static |
OSStatus StrokeAccumulationPaneConstruct( EventHandlerCallRef inCallRef, EventRef inEvent ) |
{ |
OSStatus status; |
// save off the default instance data |
HIViewRef defaultInstanceData; |
status = GetEventParameter( inEvent, kEventParamHIObjectInstance, typeHIObjectRef, |
NULL, sizeof( HIObjectRef ), NULL, &defaultInstanceData ); |
check_noerr( status ); |
// allocate our own custom C++ object |
StrokeAccumulationPane *newPane = new StrokeAccumulationPane( defaultInstanceData ); |
// store a pointer to it as a param that will be carried in event callbacks |
status = SetEventParameter( inEvent, kEventParamHIObjectInstance, typeVoidPtr, |
sizeof( HIObjectRef ), (void *) &newPane ); |
check_noerr( status ); |
return status; |
} |
// ----------------------------------------------------------------------------- |
// StrokeAccumulationPaneEventHandler [INTERNAL] |
// ----------------------------------------------------------------------------- |
static pascal OSStatus |
StrokeAccumulationPaneEventHandler( EventHandlerCallRef inCallRef, EventRef inEvent, |
void *inUserData ) |
{ |
OSStatus status = eventNotHandledErr; |
UInt32 eventClass = GetEventClass( inEvent ); |
UInt32 eventKind = GetEventKind( inEvent ); |
// easier to understand in C++ semantics |
StrokeAccumulationPane *thisPane = (StrokeAccumulationPane *) inUserData; |
switch ( eventClass ) |
{ |
// handle our HIObject events here |
case kEventClassHIObject: |
{ |
switch ( eventKind ) |
{ |
case kEventHIObjectConstruct: |
status = StrokeAccumulationPaneConstruct( inCallRef, inEvent ); |
break; |
case kEventHIObjectInitialize: |
// for this one, we need to call the parent class for |
// any initialization that they need to do |
status = CallNextEventHandler( inCallRef, inEvent ); |
check_noerr( status ); |
if ( status == noErr ) |
{ |
check( thisPane != NULL ); |
status = thisPane->Initialize( inEvent ); |
} |
break; |
case kEventHIObjectDestruct: |
check( thisPane != NULL ); |
delete thisPane; |
status = noErr; |
break; |
} |
} |
break; |
// handle our control class events here |
// These events are sent to the userPane control |
// which will be our proxy target for the |
// StrokeAccumulationPane object. |
case kEventClassControl: |
{ |
switch ( eventKind ) |
{ |
case kEventControlInitialize: |
status = noErr; |
break; |
case kEventControlDraw: |
status = thisPane->Draw( inEvent ); |
break; |
case kEventControlActivate: |
status = thisPane->Activate( inEvent ); |
break; |
case kEventControlDeactivate: |
status = thisPane->Deactivate( inEvent ); |
break; |
// the tab pane is switching in or out of view |
case kEventControlVisibilityChanged: |
{ |
Boolean becomeVisible = thisPane->IsParentVisible(); |
// first terminate inking if going to non visible state |
if( becomeVisible == false ) |
thisPane->MyInkViewTerminateInking(); |
// later operations may tell text view to draw |
// so set visibility state before performing those operations |
thisPane->TextViewSetVisibility( becomeVisible ); |
// switching into view? |
if( becomeVisible ) |
{ |
// turn everything on |
thisPane->Activate( inEvent ); |
InkSetApplicationWritingMode(kInkWriteNowhereInApp); |
gInkAppWritingMode = kInkWriteNowhereInApp; |
//InkSetPhraseTerminationMode(kInkTerminationNone); |
InkSetDrawingMode(kInkDrawNothing); |
} |
else // or switching out of view? |
{ |
// turn everything off |
thisPane->Deactivate( inEvent ); |
InkSetApplicationWritingMode(kInkWriteAnywhereInApp); |
gInkAppWritingMode = kInkWriteAnywhereInApp; |
//InkSetPhraseTerminationMode(kInkTerminationAll); |
InkSetDrawingMode(kInkDrawInkAndWritingGuides); |
} |
} |
break; |
} |
} |
break; |
} |
return status; |
} |
Copyright © 2003 Apple Computer, Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2003-10-27