diff options
Diffstat (limited to 'cocoa/ScintillaView.mm')
-rw-r--r-- | cocoa/ScintillaView.mm | 231 |
1 files changed, 231 insertions, 0 deletions
diff --git a/cocoa/ScintillaView.mm b/cocoa/ScintillaView.mm index 51cb0af5f..491aba572 100644 --- a/cocoa/ScintillaView.mm +++ b/cocoa/ScintillaView.mm @@ -64,6 +64,7 @@ static NSCursor *cursorFromEnum(Window::Cursor cursor) [currentCursors addObject: [reverseArrowCursor retain]]; } [self setClientView:[aScrollView documentView]]; + self.accessibilityLabel = @"Scintilla Margin"; } return self; } @@ -122,6 +123,12 @@ static NSCursor *cursorFromEnum(Window::Cursor cursor) owner.backend->MouseUp(theEvent); } +// Not a simple button so return failure +- (BOOL)accessibilityPerformPress +{ + return NO; +} + /** * This method is called to give us the opportunity to define our mouse sensitive rectangle. */ @@ -167,6 +174,14 @@ static NSCursor *cursorFromEnum(Window::Cursor cursor) [self registerForDraggedTypes: [NSArray arrayWithObjects: NSStringPboardType, ScintillaRecPboardType, NSFilenamesPboardType, nil]]; + + // Set up accessibility in the text role + self.accessibilityElement = TRUE; + self.accessibilityEnabled = TRUE; + self.accessibilityLabel = NSLocalizedString(@"Scintilla", nil); // No real localization + self.accessibilityRoleDescription = @"source code editor"; + self.accessibilityRole = NSAccessibilityTextAreaRole; + self.accessibilityIdentifier = @"Scintilla"; } return self; @@ -931,6 +946,222 @@ sourceOperationMaskForDraggingContext: (NSDraggingContext) context return mOwner.backend->WndProc(SCI_GETREADONLY, 0, 0) == 0; } +#pragma mark - NSAccessibility + +//-------------------------------------------------------------------------------------------------- + +// Adoption of NSAccessibility protocol. +// NSAccessibility wants to pass ranges in UTF-16 code units, not bytes (like Scintilla) +// or characters. +// Needs more testing with non-ASCII and non-BMP text. +// Needs to take account of folding and wraping. + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Text of the whole document as a string. + */ +- (id) accessibilityValue { + const sptr_t length = [mOwner message: SCI_GETLENGTH]; + return mOwner.backend->RangeTextAsString(NSMakeRange(0,static_cast<int>(length))); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Line of the caret. + */ +- (NSInteger) accessibilityInsertionPointLineNumber { + const int caret = static_cast<int>([mOwner message: SCI_GETCURRENTPOS]); + const NSRange rangeCharactersCaret = mOwner.backend->CharactersFromPositions(NSMakeRange(caret, 0)); + return mOwner.backend->VisibleLineForIndex(rangeCharactersCaret.location); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Not implemented and not called by VoiceOver. + */ +- (NSRange)accessibilityRangeForPosition:(NSPoint)point { + return NSMakeRange(0,0); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Number of characters in the whole document. + */ +- (NSInteger) accessibilityNumberOfCharacters { + sptr_t length = [mOwner message: SCI_GETLENGTH]; + const NSRange posRange = mOwner.backend->CharactersFromPositions(NSMakeRange(length, 0)); + return posRange.location; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : The selection text as a string. + */ +- (NSString *) accessibilitySelectedText { + const sptr_t positionBegin = [mOwner message: SCI_GETSELECTIONSTART]; + const sptr_t positionEnd = [mOwner message: SCI_GETSELECTIONEND]; + const NSRange posRangeSel = NSMakeRange(positionBegin, positionEnd-positionBegin); + return mOwner.backend->RangeTextAsString(posRangeSel); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : The character range of the main selection. + */ +- (NSRange) accessibilitySelectedTextRange { + const sptr_t positionBegin = [mOwner message: SCI_GETSELECTIONSTART]; + const sptr_t positionEnd = [mOwner message: SCI_GETSELECTIONEND]; + const NSRange posRangeSel = NSMakeRange(positionBegin, positionEnd-positionBegin); + return mOwner.backend->CharactersFromPositions(posRangeSel); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : The setter for accessibilitySelectedTextRange. + * This method is the only setter required for reasonable VoiceOver behaviour. + */ +- (void) setAccessibilitySelectedTextRange: (NSRange) range { + NSRange rangePositions = mOwner.backend->PositionsFromCharacters(range); + [mOwner message: SCI_SETSELECTION wParam: rangePositions.location lParam:NSMaxRange(rangePositions)]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Range of the glyph at a character index. + * Currently doesn't try to handle composite characters. + */ +- (NSRange) accessibilityRangeForIndex: (NSInteger)index { + sptr_t length = [mOwner message: SCI_GETLENGTH]; + const NSRange rangeLength = mOwner.backend->CharactersFromPositions(NSMakeRange(length, 0)); + NSRange rangePositions = NSMakeRange(length, 0); + if (index < rangeLength.location) { + rangePositions = mOwner.backend->PositionsFromCharacters(NSMakeRange(index, 1)); + } + return mOwner.backend->CharactersFromPositions(rangePositions); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : All the text ranges. + * Currently only returns the main selection. + */ +- (NSArray<NSValue *>*) accessibilitySelectedTextRanges { + const sptr_t positionBegin = [mOwner message: SCI_GETSELECTIONSTART]; + const sptr_t positionEnd = [mOwner message: SCI_GETSELECTIONEND]; + const NSRange posRangeSel = NSMakeRange(positionBegin, positionEnd-positionBegin); + NSRange rangeCharacters = mOwner.backend->CharactersFromPositions(posRangeSel); + NSValue *valueRange = [NSValue valueWithRange:(NSRange)rangeCharacters]; + return @[valueRange]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Character range currently visible. + */ +- (NSRange) accessibilityVisibleCharacterRange { + const sptr_t lineTopVisible = [mOwner message: SCI_GETFIRSTVISIBLELINE]; + const sptr_t lineTop = [mOwner message:SCI_DOCLINEFROMVISIBLE wParam:lineTopVisible]; + const sptr_t lineEndVisible = lineTopVisible + [mOwner message: SCI_LINESONSCREEN] - 1; + const sptr_t lineEnd = [mOwner message:SCI_DOCLINEFROMVISIBLE wParam:lineEndVisible]; + const sptr_t posStartView = [mOwner message: SCI_POSITIONFROMLINE wParam: lineTop]; + const sptr_t posEndView = [mOwner message: SCI_GETLINEENDPOSITION wParam: lineEnd]; + const NSRange posRangeSel = NSMakeRange(posStartView, posEndView-posStartView); + return mOwner.backend->CharactersFromPositions(posRangeSel); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Character range of a line. + */ +- (NSRange)accessibilityRangeForLine:(NSInteger)line { + return mOwner.backend->RangeForVisibleLine(line); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Line number of a text position in characters. + */ +- (NSInteger)accessibilityLineForIndex:(NSInteger)index { + return mOwner.backend->VisibleLineForIndex(index); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : A rectangle that covers a range which will be shown as the + * VoiceOver cursor. + * Producing a nice rectangle is a little tricky particularly when including new + * lines. Needs to improve the case where parts of two lines are included. + */ +- (NSRect)accessibilityFrameForRange:(NSRange)range { + const NSRect rectInView = mOwner.backend->FrameForRange(range); + const NSRect rectInWindow = [[[self superview] superview] convertRect:rectInView toView:nil]; + return [self.window convertRectToScreen:rectInWindow]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : A range of text as a string. + */ +- (NSString *) accessibilityStringForRange:(NSRange)range { + const NSRange posRange = mOwner.backend->PositionsFromCharacters(range); + return mOwner.backend->RangeTextAsString(posRange); +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : A range of text as an attributed string. + * Currently no attributes are set. + */ +- (NSAttributedString *) accessibilityAttributedStringForRange:(NSRange)range { + const NSRange posRange = mOwner.backend->PositionsFromCharacters(range); + NSString *result = mOwner.backend->RangeTextAsString(posRange); + return [[[NSMutableAttributedString alloc] initWithString:result] autorelease]; +} + +//-------------------------------------------------------------------------------------------------- + +/** + * NSAccessibility : Show the context menu at the caret. + */ +- (BOOL)accessibilityPerformShowMenu { + const sptr_t caret = [mOwner message: SCI_GETCURRENTPOS]; + NSRect rect; + rect.origin.x = [mOwner message: SCI_POINTXFROMPOSITION wParam: 0 lParam: caret]; + rect.origin.y = [mOwner message: SCI_POINTYFROMPOSITION wParam: 0 lParam: caret]; + rect.origin.y += [mOwner message: SCI_TEXTHEIGHT wParam: 0 lParam: 0]; + rect.size.width = 1.0; + rect.size.height = 1.0; + NSRect rectInWindow = [[[self superview] superview] convertRect:rect toView:nil]; + NSPoint pt = rectInWindow.origin; + NSEvent *event = [NSEvent mouseEventWithType: NSRightMouseDown + location: pt + modifierFlags: 0 + timestamp: 0 + windowNumber: [[self window] windowNumber] + context: nil + eventNumber: 0 + clickCount: 1 + pressure: 0.0]; + NSMenu *menu = mOwner.backend->CreateContextMenu(event); + [NSMenu popUpContextMenu:menu withEvent:event forView:self]; + return YES; +} + //-------------------------------------------------------------------------------------------------- - (void) dealloc |