diff options
Diffstat (limited to 'cocoa/ScintillaView.mm')
-rw-r--r-- | cocoa/ScintillaView.mm | 1082 |
1 files changed, 1082 insertions, 0 deletions
diff --git a/cocoa/ScintillaView.mm b/cocoa/ScintillaView.mm new file mode 100644 index 000000000..d6b353256 --- /dev/null +++ b/cocoa/ScintillaView.mm @@ -0,0 +1,1082 @@ + +/** + * Implementation of the native Cocoa View that serves as container for the scintilla parts. + * + * Created by Mike Lischke. + * + * Copyright 2009 Sun Microsystems, Inc. All rights reserved. + * This file is dual licensed under LGPL v2.1 and the Scintilla license (http://www.scintilla.org/License.txt). + */ + +#import "ScintillaView.h" + +using namespace Scintilla; + +// Two additional cursors we need, which aren't provided by Cocoa. +static NSCursor* reverseArrowCursor; +static NSCursor* waitCursor; + +// The scintilla indicator used for keyboard input. +#define INPUT_INDICATOR INDIC_MAX - 1 + +@implementation InnerView + +@synthesize owner = mOwner; + +//-------------------------------------------------------------------------------------------------- + +- (NSView*) initWithFrame: (NSRect) frame +{ + self = [super initWithFrame: frame]; + + if (self != nil) + { + // Some initialization for our view. + mCurrentCursor = [NSCursor arrowCursor]; + mCurrentTrackingRect = 0; + mMarkedTextRange = NSMakeRange(NSNotFound, 0); + + [self registerForDraggedTypes:[NSArray arrayWithObjects: + NSStringPboardType, NSHTMLPboardType, NSFilenamesPboardType, nil]]; + } + + return self; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * When the view is resized we need to update our tracking rectangle and let the backend know. + */ +- (void) setFrame: (NSRect) frame +{ + [super setFrame: frame]; + + // Make the content also a tracking rectangle for mouse events. + if (mCurrentTrackingRect != 0) + [self removeTrackingRect: mCurrentTrackingRect]; + mCurrentTrackingRect = [self addTrackingRect: [self bounds] + owner: self + userData: nil + assumeInside: YES]; + mOwner.backend->Resize(); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Called by the backend if a new cursor must be set for the view. + */ +- (void) setCursor: (Window::Cursor) cursor +{ + switch (cursor) + { + case Window::cursorText: + mCurrentCursor = [NSCursor IBeamCursor]; + break; + case Window::cursorArrow: + mCurrentCursor = [NSCursor arrowCursor]; + break; + case Window::cursorWait: + mCurrentCursor = waitCursor; + break; + case Window::cursorHoriz: + mCurrentCursor = [NSCursor resizeLeftRightCursor]; + break; + case Window::cursorVert: + mCurrentCursor = [NSCursor resizeUpDownCursor]; + break; + case Window::cursorReverseArrow: + mCurrentCursor = reverseArrowCursor; + break; + case Window::cursorUp: + default: + mCurrentCursor = [NSCursor arrowCursor]; + break; + } + + // Trigger recreation of the cursor rectangle(s). + [[self window] invalidateCursorRectsForView: self]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * This method is called to give us the opportunity to define our mouse sensitive rectangle. + */ +- (void) resetCursorRects +{ + [super resetCursorRects]; + + // We only have one cursor rect: our bounds. + NSRect bounds = [self bounds]; + [self addCursorRect: [self bounds] cursor: mCurrentCursor]; + [mCurrentCursor setOnMouseEntered: YES]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Gets called by the runtime when the view needs repainting. + */ +- (void) drawRect: (NSRect) rect +{ + CGContextRef context = (CGContextRef) [[NSGraphicsContext currentContext] graphicsPort]; + + mOwner.backend->Draw(rect, context); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Windows uses a client coordinate system where the upper left corner is the origin in a window. + * We have to adjust for that. However by returning YES here, we are already done with that. + * Note that because of returning YES here most coordinates we use now (e.g. for painting, + * invalidating rectangles etc.) are given with +Y pointing down! + */ +- (BOOL) isFlipped +{ + return YES; +} + +//-------------------------------------------------------------------------------------------------- + +- (BOOL) isOpaque +{ + return YES; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Implement the "click through" behavior by telling the caller we accept the first mouse event too. + */ +- (BOOL) acceptsFirstMouse: (NSEvent *) theEvent +{ + return YES; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Make this view accepting events as first responder. + */ +- (BOOL) acceptsFirstResponder +{ + return YES; +} + +//-------------------------------------------------------------------------------------------------- + +// Adoption of NSTextInput protocol. + +- (NSAttributedString*) attributedSubstringFromRange: (NSRange) range +{ + return nil; +} + +//-------------------------------------------------------------------------------------------------- + +- (NSUInteger) characterIndexForPoint: (NSPoint) point +{ + return NSNotFound; +} + +//-------------------------------------------------------------------------------------------------- + +- (NSInteger) conversationIdentifier +{ + return (NSInteger) self; + +} + +//-------------------------------------------------------------------------------------------------- + +- (void) doCommandBySelector: (SEL) selector +{ + if ([self respondsToSelector:@selector(selector)]) + [self performSelector: selector withObject: nil]; +} + +//-------------------------------------------------------------------------------------------------- + +- (NSRect) firstRectForCharacterRange: (NSRange) range +{ + return NSZeroRect; +} + +//-------------------------------------------------------------------------------------------------- + +- (BOOL) hasMarkedText +{ + return mMarkedTextRange.length > 0; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * General text input. Used to insert new text at the current input position, replacing the current + * selection if there is any. + */ +- (void) insertText: (id) aString +{ + // Remove any previously marked text first. + [self removeMarkedText]; + + mOwner.backend->InsertText((NSString*) aString); +} + +//-------------------------------------------------------------------------------------------------- + +- (NSRange) markedRange +{ + return mMarkedTextRange; +} + +//-------------------------------------------------------------------------------------------------- + +- (NSRange) selectedRange +{ + int begin = [mOwner getGeneralProperty: SCI_GETSELECTIONSTART parameter: 0]; + int end = [mOwner getGeneralProperty: SCI_GETSELECTIONEND parameter: 0]; + return NSMakeRange(begin, end - begin); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Called by the input manager to set text which might be combined with further input to form + * the final text (e.g. composition of ^ and a to รข). + * + * @param aString The text to insert, either what has been marked already or what is selected already + * or simply added at the current insertion point. Depending on what is available. + * @param range The range of the new text to select (given relative to the insertion point of the new text). + */ +- (void) setMarkedText: (id) aString selectedRange: (NSRange) range +{ + // Since we did not return any valid attribute for marked text (see validAttributesForMarkedText) + // we can safely assume the passed in text is an NSString instance. + NSString* newText = (NSString*) aString; + int currentPosition = [mOwner getGeneralProperty: SCI_GETCURRENTPOS parameter: 0]; + + // Replace marked text if there is one. + if (mMarkedTextRange.length > 0) + { + // We have already marked text. Replace that. + [mOwner setGeneralProperty: SCI_SETSELECTIONSTART + parameter: mMarkedTextRange.location + value: 0]; + [mOwner setGeneralProperty: SCI_SETSELECTIONEND + parameter: mMarkedTextRange.location + mMarkedTextRange.length + value: 0]; + currentPosition = mMarkedTextRange.location; + } + + mOwner.backend->InsertText(newText); + + mMarkedTextRange.location = currentPosition; + mMarkedTextRange.length = [newText length]; + + // Mark the just inserted text. Keep the marked range for later reset. + [mOwner setGeneralProperty: SCI_SETINDICATORCURRENT parameter: INPUT_INDICATOR value: 0]; + [mOwner setGeneralProperty: SCI_INDICATORFILLRANGE + parameter: mMarkedTextRange.location + value: mMarkedTextRange.length]; + + // Select the part which is indicated in the given range. + if (range.length > 0) + { + [mOwner setGeneralProperty: SCI_SETSELECTIONSTART + parameter: currentPosition + range.location + value: 0]; + [mOwner setGeneralProperty: SCI_SETSELECTIONEND + parameter: currentPosition + range.location + range.length + value: 0]; + } +} + +//-------------------------------------------------------------------------------------------------- + +- (void) unmarkText +{ + if (mMarkedTextRange.length > 0) + { + [mOwner setGeneralProperty: SCI_SETINDICATORCURRENT parameter: INPUT_INDICATOR value: 0]; + [mOwner setGeneralProperty: SCI_INDICATORCLEARRANGE + parameter: mMarkedTextRange.location + value: mMarkedTextRange.length]; + mMarkedTextRange = NSMakeRange(NSNotFound, 0); + } +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Removes any currently marked text. + */ +- (void) removeMarkedText +{ + if (mMarkedTextRange.length > 0) + { + // We have already marked text. Replace that. + [mOwner setGeneralProperty: SCI_SETSELECTIONSTART + parameter: mMarkedTextRange.location + value: 0]; + [mOwner setGeneralProperty: SCI_SETSELECTIONEND + parameter: mMarkedTextRange.location + mMarkedTextRange.length + value: 0]; + mOwner.backend->InsertText(@""); + mMarkedTextRange = NSMakeRange(NSNotFound, 0); + } +} + +//-------------------------------------------------------------------------------------------------- + +- (NSArray*) validAttributesForMarkedText +{ + return nil; +} + +// End of the NSTextInput protocol adoption. + +//-------------------------------------------------------------------------------------------------- + +/** + * Generic input method. It is used to pass on keyboard input to Scintilla. The control itself only + * handles shortcuts. The input is then forwarded to the Cocoa text input system, which in turn does + * its own input handling (character composition via NSTextInput protocol): + */ +- (void) keyDown: (NSEvent *) theEvent +{ + mOwner.backend->KeyboardInput(theEvent); + NSArray* events = [NSArray arrayWithObject: theEvent]; + [self interpretKeyEvents: events]; +} + +//-------------------------------------------------------------------------------------------------- + +- (void) mouseDown: (NSEvent *) theEvent +{ + mOwner.backend->MouseDown(theEvent); +} + +//-------------------------------------------------------------------------------------------------- + +- (void) mouseDragged: (NSEvent *) theEvent +{ + mOwner.backend->MouseMove(theEvent); +} + +//-------------------------------------------------------------------------------------------------- + +- (void) mouseUp: (NSEvent *) theEvent +{ + mOwner.backend->MouseUp(theEvent); +} + +//-------------------------------------------------------------------------------------------------- + +- (void) mouseMoved: (NSEvent *) theEvent +{ + mOwner.backend->MouseMove(theEvent); +} + +//-------------------------------------------------------------------------------------------------- + +- (void) mouseEntered: (NSEvent *) theEvent +{ + mOwner.backend->MouseEntered(theEvent); +} + +//-------------------------------------------------------------------------------------------------- + +- (void) mouseExited: (NSEvent *) theEvent +{ + mOwner.backend->MouseExited(theEvent); +} + +//-------------------------------------------------------------------------------------------------- + +- (void) scrollWheel: (NSEvent *) theEvent +{ + mOwner.backend->MouseWheel(theEvent); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * The editor is getting the foreground control (the one getting the input focus). + */ +- (BOOL) becomeFirstResponder +{ + mOwner.backend->WndProc(SCI_SETFOCUS, 1, 0); + return YES; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * The editor is losing the input focus. + */ +- (BOOL) resignFirstResponder +{ + mOwner.backend->WndProc(SCI_SETFOCUS, 0, 0); + return YES; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Called when an external drag operation enters the view. + */ +- (NSDragOperation) draggingEntered: (id <NSDraggingInfo>) sender +{ + return mOwner.backend->DraggingEntered(sender); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Called frequently during an external drag operation if we are the target. + */ +- (NSDragOperation) draggingUpdated: (id <NSDraggingInfo>) sender +{ + return mOwner.backend->DraggingUpdated(sender); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Drag image left the view. Clean up if necessary. + */ +- (void) draggingExited: (id <NSDraggingInfo>) sender +{ + mOwner.backend->DraggingExited(sender); +} + +//-------------------------------------------------------------------------------------------------- + +- (BOOL) prepareForDragOperation: (id <NSDraggingInfo>) sender +{ + return YES; +} + +//-------------------------------------------------------------------------------------------------- + +- (BOOL) performDragOperation: (id <NSDraggingInfo>) sender +{ + return mOwner.backend->PerformDragOperation(sender); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Returns operations we allow as drag source. + */ +- (NSDragOperation) draggingSourceOperationMaskForLocal: (BOOL) flag +{ + return NSDragOperationCopy | NSDragOperationMove; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Drag operation is done. Notify editor. + */ +- (void) concludeDragOperation: (id <NSDraggingInfo>) sender +{ + // Clean up is the same as if we are no longer the drag target. + mOwner.backend->DraggingExited(sender); +} + +@end + +//-------------------------------------------------------------------------------------------------- + +@implementation ScintillaView + +@synthesize backend = mBackend; + +/** + * ScintiallView is a composite control made from an NSView and an embedded NSView that is + * used as canvas for the output (by the backend, using its CGContext), plus two scrollers. + */ + +//-------------------------------------------------------------------------------------------------- + +/** + * Initialize custom cursor. + */ ++ (void) initialize +{ + if (self == [ScintillaView class]) + { + NSBundle* bundle = [NSBundle bundleForClass: [ScintillaView class]]; + + NSString* path = [bundle pathForResource: @"mac_cursor_busy" ofType: @"png" inDirectory: nil]; + NSImage* image = [[[NSImage alloc] initWithContentsOfFile: path] autorelease]; + waitCursor = [[[NSCursor alloc] initWithImage: image hotSpot: NSMakePoint(2, 2)] retain]; + + path = [bundle pathForResource: @"mac_cursor_flipped" ofType: @"png" inDirectory: nil]; + image = [[[NSImage alloc] initWithContentsOfFile: path] autorelease]; + reverseArrowCursor = [[[NSCursor alloc] initWithImage: image hotSpot: NSMakePoint(12, 2)] retain]; + } +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Sends a new notification of the given type to the default notification center. + */ +- (void) sendNotification: (NSString*) notificationName +{ + NSNotificationCenter* center = [NSNotificationCenter defaultCenter]; + [center postNotificationName: notificationName object: self]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Notification function used by Scintilla to call us back (e.g. for handling clicks on the + * folder margin or changes in the editor). + */ +static void notification(intptr_t windowid, unsigned int iMessage, uintptr_t wParam, uintptr_t lParam) +{ + // WM_NOTIFY means we got a parent notification with a special notification structure. + // Here we don't really differentiate between parent and own notifications and handle both. + ScintillaView* editor; + switch (iMessage) + { + case WM_NOTIFY: + { + // Parent notification. Details are passed as SCNotification structure. + SCNotification* scn = reinterpret_cast<SCNotification*>(lParam); + editor = reinterpret_cast<InnerView*>(scn->nmhdr.idFrom).owner; + switch (scn->nmhdr.code) + { + case SCN_MARGINCLICK: + if (scn->margin == 2) + { + // Click on the folder margin. Toggle the current line if possible. + int line = [editor getGeneralProperty: SCI_LINEFROMPOSITION parameter: scn->position]; + [editor setGeneralProperty: SCI_TOGGLEFOLD parameter: line value: 0]; + }; + break; + case SCN_MODIFIED: + // Decide depending on the modification type what to do. + // There can be more than one modification carried by one notification. + if (scn->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) + [editor sendNotification: NSTextDidChangeNotification]; + break; + } + break; + } + case WM_COMMAND: + { + // Notifications for the editor itself. + ScintillaCocoa* backend = reinterpret_cast<ScintillaCocoa*>(lParam); + editor = backend->TopContainer(); + switch (wParam >> 16) + { + case SCEN_KILLFOCUS: + [editor sendNotification: NSTextDidEndEditingNotification]; + break; + case SCEN_SETFOCUS: // Nothing to do for now. + break; + } + break; + } + }; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Initialization of the view. Used to setup a few other things we need. + */ +- (id) initWithFrame: (NSRect) frame +{ + self = [super initWithFrame:frame]; + if (self) + { + mContent = [[[InnerView alloc] init] autorelease]; + mBackend = new ScintillaCocoa(mContent); + mContent.owner = self; + [self addSubview: mContent]; + + // Initialize the scrollers but don't show them yet. + // Pick an arbitrary size, just to make NSScroller selecting the proper scroller direction + // (horizontal or vertical). + NSRect scrollerRect = NSMakeRect(0, 0, 100, 10); + mHorizontalScroller = [[[NSScroller alloc] initWithFrame: scrollerRect] autorelease]; + [mHorizontalScroller setHidden: YES]; + [mHorizontalScroller setTarget: self]; + [mHorizontalScroller setAction: @selector(scrollerAction:)]; + [self addSubview: mHorizontalScroller]; + + scrollerRect.size = NSMakeSize(10, 100); + mVerticalScroller = [[[NSScroller alloc] initWithFrame: scrollerRect] autorelease]; + [mVerticalScroller setHidden: YES]; + [mVerticalScroller setTarget: self]; + [mVerticalScroller setAction: @selector(scrollerAction:)]; + [self addSubview: mVerticalScroller]; + + // Establish a connection from the back end to this container so we can handle situations + // which require our attention. + mBackend->RegisterNotifyCallback(nil, notification); + + // Setup a special indicator used in the editor to provide visual feedback for + // input composition, depending on language, keyboard etc. + [self setColorProperty: SCI_INDICSETFORE parameter: INPUT_INDICATOR fromHTML: @"#FF9A00"]; + [self setGeneralProperty: SCI_INDICSETUNDER parameter: INPUT_INDICATOR value: 1]; + [self setGeneralProperty: SCI_INDICSETSTYLE parameter: INPUT_INDICATOR value: INDIC_ROUNDBOX]; + [self setGeneralProperty: SCI_INDICSETALPHA parameter: INPUT_INDICATOR value: 100]; + } + return self; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Release the backend. + */ +- (void) dealloc +{ + delete mBackend; + [super dealloc]; +} + +//-------------------------------------------------------------------------------------------------- + +- (void) viewDidMoveToWindow +{ + [super viewDidMoveToWindow]; + + [self layout]; + + // Enable also mouse move events for our window (and so this view). + [[self window] setAcceptsMouseMovedEvents: YES]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Used to position and size the parts of the editor (content + scrollers). + */ +- (void) layout +{ + int scrollerWidth = [NSScroller scrollerWidth]; + + NSSize size = [self frame].size; + NSPoint hScrollerOrigin = {0, 0}; + NSPoint vScrollerOrigin = {size.width - scrollerWidth, 0}; + + if (![mVerticalScroller isHidden]) + { + // Consider user settings (left vs right vertical scrollbar). + BOOL isLeft = [[[NSUserDefaults standardUserDefaults] stringForKey: @"NSScrollerPosition"] + isEqualToString: @"left"]; + if (isLeft) + { + vScrollerOrigin.x = 0; + hScrollerOrigin.x = scrollerWidth; + }; + + size.width -= scrollerWidth; + } + if (![mHorizontalScroller isHidden]) + { + size.height -= scrollerWidth; + vScrollerOrigin.y += scrollerWidth; + }; + + NSRect contentRect = {hScrollerOrigin.x, vScrollerOrigin.y, size.width, size.height}; + [mContent setFrame: contentRect]; + + if (![mHorizontalScroller isHidden]) + [mHorizontalScroller setFrame: NSMakeRect(hScrollerOrigin.x, hScrollerOrigin.y, size.width, + scrollerWidth)]; + if (![mVerticalScroller isHidden]) + [mVerticalScroller setFrame: NSMakeRect(vScrollerOrigin.x, vScrollerOrigin.y, scrollerWidth, + size.height)]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Called by the backend to adjust the vertical scroller (range and page). + * + * @param range Determines the total size of the scroll area used in the editor. + * @param page Determines how many pixels a page is. + * @result Returns YES if anything changed, otherwise NO. + */ +- (BOOL) setVerticalScrollRange: (int) range page: (int) page +{ + BOOL result = NO; + BOOL hideScroller = page >= range; + + if ([mVerticalScroller isHidden] != hideScroller) + { + result = YES; + [mVerticalScroller setHidden: hideScroller]; + if (!hideScroller) + [mVerticalScroller setFloatValue: 0]; + [self layout]; + } + + if (!hideScroller) + { + [mVerticalScroller setEnabled: YES]; + + CGFloat currentProportion = [mVerticalScroller knobProportion]; + CGFloat newProportion = page / (CGFloat) range; + if (currentProportion != newProportion) + { + result = YES; + [mVerticalScroller setKnobProportion: newProportion]; + } + } + + return result; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Used to set the position of the vertical scroll thumb. + * + * @param position The relative position in the rang [0..1]; + */ +- (void) setVerticalScrollPosition: (float) position +{ + [mVerticalScroller setFloatValue: position]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Called by the backend to adjust the horizontal scroller (range and page). + * + * @param range Determines the total size of the scroll area used in the editor. + * @param page Determines how many pixels a page is. + * @result Returns YES if anything changed, otherwise NO. + */ +- (BOOL) setHorizontalScrollRange: (int) range page: (int) page +{ + BOOL result = NO; + BOOL hideScroller = page >= range; + + if ([mHorizontalScroller isHidden] != hideScroller) + { + result = YES; + [mHorizontalScroller setHidden: hideScroller]; + [self layout]; + } + + if (!hideScroller) + { + [mHorizontalScroller setEnabled: YES]; + + CGFloat currentProportion = [mHorizontalScroller knobProportion]; + CGFloat newProportion = page / (CGFloat) range; + if (currentProportion != newProportion) + { + result = YES; + [mHorizontalScroller setKnobProportion: newProportion]; + } + } + + return result; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Used to set the position of the vertical scroll thumb. + * + * @param position The relative position in the rang [0..1]; + */ +- (void) setHorizontalScrollPosition: (float) position +{ + [mHorizontalScroller setFloatValue: position]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Triggered by one of the scrollers when it gets manipulated by the user. Notify the backend + * about the change. + */ +- (void) scrollerAction: (id) sender +{ + float position = [sender floatValue]; + mBackend->DoScroll(position, [sender hitPart], sender == mHorizontalScroller); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Used to reposition our content depending on the size of the view. + */ +- (void) setFrame: (NSRect) newFrame +{ + [super setFrame: newFrame]; + [self layout]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Getter for the current text in raw form (no formatting information included). + */ +- (NSString*) string +{ + NSString *result = nil; + + char *buffer(0); + const int length = mBackend->WndProc(SCI_GETLENGTH, 0, 0); + if ( length > 0 ) + { + buffer = new char[length + 1]; + try + { + mBackend->WndProc(SCI_GETTEXT, length + 1, (sptr_t) buffer); + mBackend->WndProc(SCI_SETSAVEPOINT, 0, 0); + + result = [NSString stringWithUTF8String: buffer]; + delete[] buffer; + } + catch (...) + { + delete[] buffer; + buffer = 0; + } + } + + return result; +} + +//-------------------------------------------------------------------------------------------------- + +- (void) setEditable: (BOOL) editable +{ + mBackend->WndProc(SCI_SETREADONLY, editable ? 0 : 1, 0); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Setter for the current text (no formatting included). + */ +- (void) setString: (NSString*) aString +{ + const char* text = [aString UTF8String]; + mBackend->WndProc(SCI_SETTEXT, 0, (long) text); +} + +//-------------------------------------------------------------------------------------------------- + +- (InnerView*) content +{ + return mContent; +} + +- (void) setEditorProperty: (int) property wParam: (long) parameter lParam: (long) value +{ + mBackend->WndProc(property, parameter, value); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * This is a helper method to get a property in the backend, with native parameters. + * + * @param property Main property like SCI_STYLESETFORE for which a value is to get. + * @param parameter Additional info for this property like a parameter or index. + * @result A generic value which must be interpreted depending on the property queried. + */ +- (long) getEditorProperty: (int) property wParam: (long) parameter +{ + return mBackend->WndProc(property, parameter, 0); +} + + +//-------------------------------------------------------------------------------------------------- + +/** + * This is a helper method to set properties in the backend, with native parameters. + * + * @param property Main property like SCI_STYLESETFORE for which a value is to be set. + * @param parameter Additional info for this property like a parameter or index. + * @param value The actual value. It depends on the property what this parameter means. + */ +- (void) setGeneralProperty: (int) property parameter: (long) parameter value: (long) value +{ + mBackend->WndProc(property, parameter, value); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * This is a helper method to get a property in the backend, with native parameters. + * + * @param property Main property like SCI_STYLESETFORE for which a value is to get. + * @param parameter Additional info for this property like a parameter or index. + * @result A generic value which must be interpreted depending on the property queried. + */ +- (long) getGeneralProperty: (int) property parameter: (long) parameter +{ + return mBackend->WndProc(property, parameter, 0); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Specialized property setter for colors. + */ +- (void) setColorProperty: (int) property parameter: (long) parameter value: (NSColor*) value +{ + if ([value colorSpaceName] != NSDeviceRGBColorSpace) + value = [value colorUsingColorSpaceName: NSDeviceRGBColorSpace]; + long red = [value redComponent] * 255; + long green = [value greenComponent] * 255; + long blue = [value blueComponent] * 255; + + long color = (blue << 16) + (green << 8) + red; + mBackend->WndProc(property, parameter, color); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Another color property setting, which allows to specify the color as string like in HTML + * documents (i.e. with leading # and either 3 hex digits or 6). + */ +- (void) setColorProperty: (int) property parameter: (long) parameter fromHTML: (NSString*) fromHTML +{ + if ([fromHTML length] > 3 && [fromHTML characterAtIndex: 0] == '#') + { + bool longVersion = [fromHTML length] > 6; + int index = 1; + + char value[3] = {0, 0, 0}; + value[0] = [fromHTML characterAtIndex: index++]; + if (longVersion) + value[1] = [fromHTML characterAtIndex: index++]; + else + value[1] = value[0]; + + unsigned rawRed; + [[NSScanner scannerWithString: [NSString stringWithUTF8String: value]] scanHexInt: &rawRed]; + + value[0] = [fromHTML characterAtIndex: index++]; + if (longVersion) + value[1] = [fromHTML characterAtIndex: index++]; + else + value[1] = value[0]; + + unsigned rawGreen; + [[NSScanner scannerWithString: [NSString stringWithUTF8String: value]] scanHexInt: &rawGreen]; + + value[0] = [fromHTML characterAtIndex: index++]; + if (longVersion) + value[1] = [fromHTML characterAtIndex: index++]; + else + value[1] = value[0]; + + unsigned rawBlue; + [[NSScanner scannerWithString: [NSString stringWithUTF8String: value]] scanHexInt: &rawBlue]; + + long color = (rawBlue << 16) + (rawGreen << 8) + rawRed; + mBackend->WndProc(property, parameter, color); + } +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Specialized property getter for colors. + */ +- (NSColor*) getColorProperty: (int) property parameter: (long) parameter +{ + int color = mBackend->WndProc(property, parameter, 0); + float red = (color & 0xFF) / 255.0; + float green = ((color >> 8) & 0xFF) / 255.0; + float blue = ((color >> 16) & 0xFF) / 255.0; + NSColor* result = [NSColor colorWithDeviceRed: red green: green blue: blue alpha: 1]; + return result; +} + + +//-------------------------------------------------------------------------------------------------- + +/** + * Specialized property setter for references (pointers, addresses). + */ +- (void) setReferenceProperty: (int) property parameter: (long) parameter value: (const void*) value +{ + mBackend->WndProc(property, parameter, (sptr_t) value); +} + + +//-------------------------------------------------------------------------------------------------- + +/** + * Specialized property getter for references (pointers, addresses). + */ +- (const void*) getReferenceProperty: (int) property parameter: (long) parameter +{ + return (const void*) mBackend->WndProc(property, parameter, 0); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Specialized property setter for string values. + */ +- (void) setStringProperty: (int) property parameter: (long) parameter value: (NSString*) value +{ + const char* rawValue = [value UTF8String]; + mBackend->WndProc(property, parameter, (sptr_t) rawValue); +} + + +//-------------------------------------------------------------------------------------------------- + +/** + * Specialized property getter for string values. + */ +- (NSString*) getStringProperty: (int) property parameter: (long) parameter +{ + const char* rawValue = (const char*) mBackend->WndProc(property, parameter, 0); + return [NSString stringWithUTF8String: rawValue]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Specialized property setter for lexer properties, which are commonly passed as strings. + */ +- (void) setLexerProperty: (NSString*) name value: (NSString*) value +{ + const char* rawName = [name UTF8String]; + const char* rawValue = [value UTF8String]; + mBackend->WndProc(SCI_SETPROPERTY, (sptr_t) rawName, (sptr_t) rawValue); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * Specialized property getter for references (pointers, addresses). + */ +- (NSString*) getLexerProperty: (NSString*) name +{ + const char* rawName = [name UTF8String]; + const char* result = (const char*) mBackend->WndProc(SCI_SETPROPERTY, (sptr_t) rawName, 0); + return [NSString stringWithUTF8String: result]; +} + +@end + +//-------------------------------------------------------------------------------------------------- + |