/*****************************************************
*
* UserPaneHandler(inHandlerCallRef, inEvent, inUserData) 
*
* Purpose:  called to handle the UserPane used as an embedder in the HIScrollView
*
* Inputs:   inHandlerCallRef    - reference to the current handler call chain
*           inEvent             - the event
*           inUserData          - app-specified data you passed in the call to InstallEventHandler
*
* Returns:  OSStatus            - noErr indicates the event was handled
*                                 eventNotHandledErr indicates the event was not handled and the Toolbox should take over
*/
static pascal OSStatus UserPaneHandler(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void * inUserData)
	{
	OSStatus status = eventNotHandledErr;
	HIViewRef userPane = (HIViewRef)inUserData;
	HIRect bounds;
	HIViewGetBounds(userPane, &bounds);
	
	// the following is a very straightforward simple yet complete implementation of the
	// kEventClassScrollable protocol which is enough to make the User Pane scrolls along its embedded content
	switch (GetEventKind(inEvent))
		{
#pragma mark *   kEventScrollableGetInfo
		case kEventScrollableGetInfo:
			{
			// we're being asked to return information about the scrolled view that we set as Event Parameters
			HISize lineSize = { 1, 1 }, imageSize = {3000, 2000};

			SetEventParameter(inEvent, kEventParamViewSize, typeHISize, sizeof(bounds.size), &bounds.size);
			SetEventParameter(inEvent, kEventParamImageSize, typeHISize, sizeof(imageSize), &imageSize);
			SetEventParameter(inEvent, kEventParamLineSize, typeHISize, sizeof(lineSize), &lineSize);
			SetEventParameter(inEvent, kEventParamOrigin, typeHIPoint, sizeof(bounds.origin), &bounds.origin);

			status = noErr;
			break;
			}

#pragma mark *   kEventScrollableScrollTo
		case kEventScrollableScrollTo:
			{
			// we're being asked to scroll, we just do a sanity check and ask for a redraw if the location is different
			HIPoint where;
			GetEventParameter(inEvent, kEventParamOrigin, typeHIPoint, NULL, sizeof(where), NULL, &where);

			if ((bounds.origin.y != where.y) || (bounds.origin.x != where.x))
				{
				HIViewSetBoundsOrigin(userPane, where.x, where.y);
				HIViewSetNeedsDisplay(userPane, true);
				}

			status = noErr;
			break;
			}
		}
	}   // UserPaneHandler
bool	AUCarbonViewBase::HandleEvent(EventHandlerCallRef inHandlerRef, EventRef event)
{	
#if !__LP64__
	UInt32 eclass = GetEventClass(event);
	UInt32 ekind = GetEventKind(event);
	ControlRef control;
	
	switch (eclass) {
		case kEventClassControl:
		{
			switch (ekind) {
			case kEventControlClick:
				GetEventParameter(event, kEventParamDirectObject, typeControlRef, NULL, sizeof(ControlRef), NULL, &control);
				if (control == mCarbonPane) {
					ClearKeyboardFocus(mCarbonWindow);
					return true;
				}
			}
		}
		break;
		
		case kEventClassScrollable:
		{
			switch (ekind) {
			case kEventScrollableGetInfo:
				{
					// [1/4]
					/*	<--	kEventParamImageSize (out, typeHISize)
					 *		On exit, contains the size of the entire scrollable view.
					 */
					HISize originalSize = { mBottomRight.h, mBottomRight.v };
					verify_noerr(SetEventParameter(event, kEventParamImageSize, typeHISize, sizeof(HISize), &originalSize));
					
					// [2/4]
					/*	<--	kEventParamViewSize (out, typeHISize)
					 *		On exit, contains the amount of the scrollable view that is
					 *		visible.
					 */
					HIViewRef parentView = HIViewGetSuperview(mCarbonPane);
					HIRect parentBounds;
					verify_noerr(HIViewGetBounds(parentView, &parentBounds));
					//HISize windowSize = {	float(windowBounds.right - windowBounds.left),
					//						float(windowBounds.bottom - windowBounds.top) };
					verify_noerr(SetEventParameter(event, kEventParamViewSize, typeHISize, sizeof(HISize), &(parentBounds.size)));
					
					// [3/4]
					/*	<--	kEventParamLineSize (out, typeHISize)
					 *		On exit, contains the amount that should be scrolled in
					 *		response to a single click on a scrollbar arrow.
					 */
					 HISize scrollIncrementSize = { 16.0f, float(20) };
					 verify_noerr(SetEventParameter(event, kEventParamLineSize, typeHISize, sizeof(HISize), &scrollIncrementSize));
					 
					// [4/4]
					/*	<-- kEventParamOrigin (out, typeHIPoint)
					 *		On exit, contains the scrollable viewÕs current origin (the
					 *		view-relative coordinate that is drawn at the top left
					 *		corner of its frame). These coordinates should always be
					 *		greater than or equal to zero. They should be less than or
					 *		equal to the viewÕs image size minus its view size.
					 */
					 verify_noerr(SetEventParameter(event, kEventParamOrigin, typeHIPoint, sizeof(HIPoint), &mCurrentScrollPoint));
				}
				return true;
				
			case kEventScrollableScrollTo:
				{
					/*
					 *  kEventClassScrollable / kEventScrollableScrollTo
					 *  
					 *  Summary:
					 *    Requests that an HIScrollViewÕs scrollable view should scroll to
					 *    a particular origin.
					 */
					
					/*	-->	kEventParamOrigin (in, typeHIPoint)
					 *		The new origin for the scrollable view. The origin
					 *		coordinates will vary from (0,0) to scrollable viewÕs image
					 *		size minus its view size.
					 */
					HIPoint pointToScrollTo;
					verify_noerr(GetEventParameter(event, kEventParamOrigin, typeHIPoint, NULL, sizeof(HIPoint), NULL, &pointToScrollTo));
					
					float xDelta = mCurrentScrollPoint.x - pointToScrollTo.x;
					float yDelta = mCurrentScrollPoint.y - pointToScrollTo.y;
					// move visible portion the appropriate amount
					verify_noerr(HIViewScrollRect(mCarbonPane, NULL, xDelta, yDelta));
					// set new content to be drawn
					verify_noerr(HIViewSetBoundsOrigin(mCarbonPane, pointToScrollTo.x, pointToScrollTo.y));
					
					mCurrentScrollPoint = pointToScrollTo;
				}
				return true;
				
			default:
				break;
			}
		}
		break;
		
		default:
			break;
	}
#endif
	return false;
}
Пример #3
0
/*----------------------------------------------------------------------------------------------------------*/
pascal OSStatus ScrollingTextViewHandler(EventHandlerCallRef inCaller, EventRef inEvent, void* inRefcon)
	{
	OSStatus result = eventNotHandledErr;
	ScrollingTextBoxData* myData = (ScrollingTextBoxData*)inRefcon;

	switch (GetEventClass(inEvent))
		{

		case kEventClassHIObject:
			switch (GetEventKind(inEvent))
				{
				case kEventHIObjectConstruct:
					{
					// allocate some instance data
					myData = (ScrollingTextBoxData*) calloc(1, sizeof(ScrollingTextBoxData));

					// get our superclass instance
					HIViewRef epView;
					GetEventParameter(inEvent, kEventParamHIObjectInstance, typeHIObjectRef, NULL, sizeof(epView), NULL, &epView);

					// remember our superclass in our instance data and initialize other fields
					myData->view = epView;

					// set the control ID so that we can find it later with HIViewFindByID
					result = SetControlID(myData->view, &kScrollingTextBoxViewID);

					// store our instance data into the event
					result = SetEventParameter(inEvent, kEventParamHIObjectInstance, typeVoidPtr, sizeof(myData), &myData);

					break;
					}

				case kEventHIObjectDestruct:
					{
					if (myData->theTimer != NULL) RemoveEventLoopTimer(myData->theTimer);
					CFRelease(myData->theText);
					free(myData);
					result = noErr;
					break;
					}

				case kEventHIObjectInitialize:
					{
					// always begin kEventHIObjectInitialize by calling through to the previous handler
					result = CallNextEventHandler(inCaller, inEvent);

					// if that succeeded, do our own initialization
					if (result == noErr)
						{
						GetEventParameter(inEvent, kEventParamScrollingText, typeCFStringRef, NULL, sizeof(myData->theText), NULL, &myData->theText);
						CFRetain(myData->theText);
						GetEventParameter(inEvent, kEventParamAutoScroll, typeBoolean, NULL, sizeof(myData->autoScroll), NULL, &myData->autoScroll);
						GetEventParameter(inEvent, kEventParamDelayBeforeAutoScroll, typeUInt32, NULL, sizeof(myData->delayBeforeAutoScroll), NULL, &myData->delayBeforeAutoScroll);
						GetEventParameter(inEvent, kEventParamDelayBetweenAutoScroll, typeUInt32, NULL, sizeof(myData->delayBetweenAutoScroll), NULL, &myData->delayBetweenAutoScroll);
						GetEventParameter(inEvent, kEventParamAutoScrollAmount, typeSInt16, NULL, sizeof(myData->autoScrollAmount), NULL, &myData->autoScrollAmount);
						myData->theTimer = NULL;
						}
					break;
					}

				default:
					break;
				}
			break;

		case kEventClassScrollable:
			switch (GetEventKind(inEvent))
				{
				case kEventScrollableGetInfo:
					{
					// we're being asked to return information about the scrolled view that we set as Event Parameters
					HISize imageSize = {50.0, myData->height};
					SetEventParameter(inEvent, kEventParamImageSize, typeHISize, sizeof(imageSize), &imageSize);
					HISize lineSize = {50.0, 20.0};
					SetEventParameter(inEvent, kEventParamLineSize, typeHISize, sizeof(lineSize), &lineSize);

					HIRect bounds;
					HIViewGetBounds(myData->view, &bounds);
					SetEventParameter(inEvent, kEventParamViewSize, typeHISize, sizeof(bounds.size), &bounds.size);
					SetEventParameter(inEvent, kEventParamOrigin, typeHIPoint, sizeof(myData->originPoint), &myData->originPoint);
					result = noErr;
					break;
					}

				case kEventScrollableScrollTo:
					{
					// we're being asked to scroll, we just do a sanity check and ask for a redraw
					HIPoint where;
					GetEventParameter(inEvent, kEventParamOrigin, typeHIPoint, NULL, sizeof(where), NULL, &where);

					HIViewSetNeedsDisplay(myData->view, true);

					myData->originPoint.y = (where.y < 0.0)?0.0:where.y;
					HIViewSetBoundsOrigin(myData->view, 0, myData->originPoint.y);

					break;
					}

				default:
					break;
				}
			break;

		case kEventClassControl:
			switch (GetEventKind(inEvent))
				{

				//	sets the feature of the view.

				case kEventControlInitialize:
					{
					result = CallNextEventHandler(inCaller, inEvent);
					if (result != noErr) break;

					UInt32 features = 0;
					result = GetEventParameter(inEvent, kEventParamControlFeatures, typeUInt32, NULL, sizeof(features), NULL, &features);
					if (result == noErr)
						features |= kControlSupportsEmbedding;
					else
						features = kControlSupportsEmbedding;

					result = SetEventParameter(inEvent, kEventParamControlFeatures, typeUInt32, sizeof features, &features);

					break;
					}

				//	Our parent view just changed dimensions, so we determined our new height.

				case kEventControlSetData:
					CFRelease(myData->theText);
					CFStringRef *p;
					GetEventParameter(inEvent, kEventParamControlDataBuffer, typePtr, NULL, sizeof(p), NULL, &p);
					myData->theText = *p;
					CFRetain(myData->theText);
					// fallthrough

				case kEventControlBoundsChanged:
					{
					HIRect bounds;
					HIViewGetBounds(myData->view, &bounds);

//
// If we're building on Panther (or later) then HIThemeGetTextDimensions is available, else we use GetThemeTextDimensions
//
#if PANTHER_BUILD
//
// Furthermore, if we're running on Panther then we can call HIThemeGetTextDimensions else we call GetThemeTextDimensions
//
					if (GetHIToolboxVersion() >= Panther_HIToolbox_Version)
						{
						HIThemeTextInfo textInfo = {0, kThemeStateActive, kScrollingTextBoxFontID, kHIThemeTextHorizontalFlushLeft, kHIThemeTextVerticalFlushTop, kHIThemeTextBoxOptionStronglyVertical, kHIThemeTextTruncationNone, 0, false};
						HIThemeGetTextDimensions(myData->theText, bounds.size.width - kMargin - kMargin, &textInfo, NULL, &myData->height, NULL);
						}
					else
#endif
						{
						Point pointBounds;
						pointBounds.h = (int)(bounds.size.width - kMargin - kMargin);
						GetThemeTextDimensions(myData->theText, kScrollingTextBoxFontID, kThemeStateActive, true, &pointBounds, NULL);
						myData->height = pointBounds.v;
						}

					myData->height += 2.0 * kMargin;

					HIViewSetNeedsDisplay(myData->view, true);

					result = eventNotHandledErr;
					break;
					}

				//	Draw the view.

				case kEventControlDraw:
					{
					CGContextRef context;
					result = GetEventParameter(inEvent, kEventParamCGContextRef, typeCGContextRef, NULL, sizeof(context), NULL, &context);

					HIRect bounds;
					HIViewGetBounds(myData->view, &bounds);

					CGContextSaveGState(context);
					CGAffineTransform transform = CGAffineTransformIdentity;
					// adjust the transform so the text doesn't draw upside down
					transform = CGAffineTransformScale(transform, 1, -1);
					CGContextSetTextMatrix(context, transform);

					// now that the proper parameters and configurations have been dealt with, let's draw
					result = ScrollingTextBoxDraw(context, &bounds, myData);

					CGContextRestoreGState(context);

					if (myData->autoScroll)
						CGContextStrokeRect(context, bounds);

					// we postpone starting the autoscroll timer until after we do our first drawing
					if ( (myData->autoScroll) && (myData->theTimer == NULL) )
						InstallEventLoopTimer(GetCurrentEventLoop(), TicksToEventTime(myData->delayBeforeAutoScroll), TicksToEventTime(myData->delayBetweenAutoScroll), myScrollingTextTimeProc, myData, &myData->theTimer);

					result = noErr;
					break;
					}

				default:
					break;
				}
			break;

		default:
			break;
		}

	return result;
	}