void IGraphicsCarbon::CreateTextEntry(IControl* pControl, IText* pText, IRECT* pTextRect, const char* pString, IParam* pParam) { if (!pControl || mTextEntryView || !mIsComposited) return; // Only composited carbon supports text entry WindowRef window = mWindow; TXNFrameOptions txnFrameOptions = kTXNMonostyledTextMask | kTXNDisableDragAndDropMask | kTXNSingleLineOnlyMask; TXNObject txnObject = 0; TXNFrameID frameID = 0; TXNObjectRefcon txnObjectRefCon = 0; HIRect rct; HIViewGetFrame(this->mView, &rct); HIViewRef contentView; HIViewFindByID (HIViewGetRoot(this->mWindow), kHIViewWindowContentID, &contentView); HIViewConvertRect(&rct, HIViewGetSuperview((HIViewRef)this->mView), contentView); Rect rect = { rct.origin.y + pTextRect->T, rct.origin.x + pTextRect->L, rct.origin.y + pTextRect->B + 1, rct.origin.x + pTextRect->R + 1 }; if (TXNNewObject(NULL, window, &rect, txnFrameOptions, kTXNTextEditStyleFrameType, kTXNSingleStylePerTextDocumentResType, kTXNMacOSEncoding, &txnObject, &frameID, txnObjectRefCon) == noErr) { TXNSetFrameBounds(txnObject, rect.top, rect.left, rect.bottom, rect.right, frameID); mTextEntryView = txnObject; // Set the text to display by defualt TXNSetData(mTextEntryView, kTXNTextData, pString, strlen(pString)/*+1*/, kTXNStartOffset, kTXNEndOffset); // center aligned text has problems with uneven string lengths RGBColor tc; tc.red = pText->mTextEntryFGColor.R * 257; tc.green = pText->mTextEntryFGColor.G * 257; tc.blue = pText->mTextEntryFGColor.B * 257; TXNBackground bg; bg.bgType = kTXNBackgroundTypeRGB; bg.bg.color.red = pText->mTextEntryBGColor.R * 257; bg.bg.color.green = pText->mTextEntryBGColor.G * 257; bg.bg.color.blue = pText->mTextEntryBGColor.B * 257; TXNSetBackground(mTextEntryView, &bg); // Set justification SInt16 justification; Fract flushness; switch ( pText->mAlign ) { case IText::kAlignCenter: justification = kTXNCenter; // seems to be buggy wrt dragging and alignement with uneven string lengths flushness = kATSUCenterAlignment; break; case IText::kAlignFar: justification = kTXNFlushRight; flushness = kATSUEndAlignment; break; case IText::kAlignNear: default: justification = kTXNFlushLeft; flushness = kATSUStartAlignment; break; } TXNControlTag controlTag[1]; TXNControlData controlData[1]; controlTag[0] = kTXNJustificationTag; controlData[0].sValue = justification; TXNSetTXNObjectControls(mTextEntryView, false, 1, controlTag, controlData); ATSUFontID fontid = kATSUInvalidFontID; if (pText->mFont && pText->mFont[0]) { ATSUFindFontFromName(pText->mFont, strlen(pText->mFont), kFontFullName /* kFontFamilyName? */ , (FontPlatformCode)kFontNoPlatform, kFontNoScriptCode, kFontNoLanguageCode, &fontid); } // font (NOT working) TXNTypeAttributes attributes[3]; attributes[0].tag = kATSUFontTag; attributes[0].size = sizeof(ATSUFontID); attributes[0].data.dataPtr = &fontid; // size attributes[1].tag = kTXNQDFontSizeAttribute; attributes[1].size = kTXNFontSizeAttributeSize; attributes[1].data.dataValue = pText->mSize << 16; // color attributes[2].tag = kTXNQDFontColorAttribute; attributes[2].size = kTXNQDFontColorAttributeSize; attributes[2].data.dataPtr = &tc; // Finally set the attributes TXNSetTypeAttributes(mTextEntryView, 3, attributes, kTXNStartOffset, kTXNEndOffset); // Ensure focus remains consistent SetUserFocusWindow(window); AdvanceKeyboardFocus(window); // Set the focus to the edit window TXNFocus(txnObject, true); TXNSelectAll(mTextEntryView); TXNShowSelection(mTextEntryView, true); // The event types const static EventTypeSpec eventTypes[] = { { kEventClassMouse, kEventMouseMoved }, { kEventClassMouse, kEventMouseDown }, { kEventClassMouse, kEventMouseUp }, { kEventClassMouse, kEventMouseWheelMoved }, { kEventClassWindow, kEventWindowClosed }, { kEventClassWindow, kEventWindowDeactivated }, { kEventClassWindow, kEventWindowFocusRelinquish }, { kEventClassKeyboard, kEventRawKeyDown }, { kEventClassKeyboard, kEventRawKeyRepeat } }; // Install the event handler InstallWindowEventHandler(window, TextEntryHandler, GetEventTypeCount(eventTypes), eventTypes, this, &mTextEntryHandler); mEdControl = pControl; mEdParam = pParam; mTextEntryRect = *pTextRect; } }
OSStatus YASTControlAttachToExistingControl(ControlRef theControl) { OSStatus err; YASTControlVars *varsp; UInt32 outCommandID; EventHandlerRef controlEvents, windowEvents; TXNObject theTXNObject; RgnHandle outlineRegion; /* set up our locals */ controlEvents = windowEvents = NULL; theTXNObject = NULL; outlineRegion = NULL; varsp = NULL; err = noErr; /* allocate our private storage and set up initial settings*/ varsp = (YASTControlVars *) malloc(sizeof(YASTControlVars)); if (varsp == NULL) { err = memFullErr; } else { varsp->fInFocus = false; varsp->fIsActive = true; varsp->fTXNObjectActive = false; varsp->fControl = theControl; varsp->fTabMovesFocus = true; varsp->fDrawFocusBox = true; varsp->fFocusDrawState = false; varsp->fIsReadOnly = false; varsp->fRTextOutlineRegion = NULL; varsp->fWindow = GetControlOwner(theControl); varsp->fGrafPtr = GetWindowPort(varsp->fWindow); } /* set our control's command id. we don't actually use it, but it must be non-zero for our control to be sent command events. only set it if it has not already been set. */ err = GetControlCommandID(theControl, &outCommandID); if (err == noErr) { if (outCommandID == 0) { err = SetControlCommandID(theControl, 1); } } /* calculate the rectangles used by the control */ if (err == noErr) { outlineRegion = NewRgn(); if (outlineRegion == NULL) { err = memFullErr; } else { Rect bounds; varsp->fRTextOutlineRegion = outlineRegion; GetControlBounds(theControl, &bounds); YASTControlCalculateBounds(varsp, &bounds); } } /* create the new edit field */ if (err == noErr) { err = TXNNewObject(NULL, varsp->fWindow, &varsp->fRTextArea, kTXNWantVScrollBarMask | kTXNAlwaysWrapAtViewEdgeMask, kTXNTextEditStyleFrameType, kTXNTextensionFile, kTXNSystemDefaultEncoding, &theTXNObject, &varsp->fTXNFrameID, (TXNObjectRefcon) varsp); if (err == noErr) { varsp->fTXNObject = theTXNObject; } } /* set the field's background */ if (err == noErr) { RGBColor rgbWhite = {0xFFFF, 0xFFFF, 0xFFFF}; TXNBackground tback; tback.bgType = kTXNBackgroundTypeRGB; tback.bg.color = rgbWhite; TXNSetBackground( varsp->fTXNObject, &tback); } /* set the margins for easier selection and display */ if (err == noErr) { TXNControlData txnCControlData; TXNControlTag txnControlTag = kTXNMarginsTag; TXNMargins txnMargins = { 2, 3, 2, 1 }; /* t,l,b,r */ txnCControlData.marginsPtr = &txnMargins; (void) TXNSetTXNObjectControls( varsp->fTXNObject, false, 1, &txnControlTag, &txnCControlData ); } /* install our carbon event handlers */ if (err == noErr) { static EventHandlerUPP gTPEventHandlerUPP = NULL; if (gTPEventHandlerUPP == NULL) gTPEventHandlerUPP = NewEventHandlerUPP(YASTControlCarbonEventHandler); /* carbon event handlers for the control */ err = InstallEventHandler( GetControlEventTarget( theControl ), gTPEventHandlerUPP, (sizeof(gYASTControlEvents)/sizeof(EventTypeSpec)), gYASTControlEvents, varsp, &controlEvents); if (err == noErr) { varsp->fControlEvents = windowEvents; /* carbon event handlers for the control's window */ err = InstallEventHandler( GetWindowEventTarget( varsp->fWindow ), gTPEventHandlerUPP, (sizeof(gYASTControlWindowEvents)/sizeof(EventTypeSpec)), gYASTControlWindowEvents, varsp, &windowEvents); if (err == noErr) { varsp->fWindowEvents = windowEvents; } } } /* perform final activations and setup for our text field. Here, we assume that the window is going to be the 'active' window. */ if (err == noErr) { SetTextActivation(varsp, (varsp->fIsActive && varsp->fInFocus)); } /* clean up on error */ if (err != noErr) { if (controlEvents != NULL) RemoveEventHandler(controlEvents); if (windowEvents != NULL) RemoveEventHandler(windowEvents); if (theTXNObject != NULL) TXNDeleteObject(theTXNObject); if (outlineRegion != NULL) DisposeRgn(outlineRegion); if (varsp != NULL) free((void*) varsp); } /* all done */ return err; }