aboutsummaryrefslogtreecommitdiffhomepage
path: root/cocoa/ScintillaView.mm
diff options
context:
space:
mode:
Diffstat (limited to 'cocoa/ScintillaView.mm')
-rw-r--r--cocoa/ScintillaView.mm231
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