mirror of
https://github.com/textmate/textmate.git
synced 2026-04-28 03:00:34 -04:00
Refactor how we send text field movement keys to a table view
The code is now easier to reuse.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
#import "OakChooser.h"
|
||||
#import "ui/TableView.h"
|
||||
#import "ui/TableViewAction.h"
|
||||
#import "ui/SearchField.h"
|
||||
#import <OakAppKit/OakAppKit.h>
|
||||
#import <OakAppKit/OakUIConstructionFunctions.h>
|
||||
@@ -31,7 +32,7 @@ NSMutableAttributedString* CreateAttributedStringWithMarkedUpRanges (std::string
|
||||
return res;
|
||||
}
|
||||
|
||||
@interface OakChooser () <NSWindowDelegate, NSTableViewDataSource, NSTableViewDelegate>
|
||||
@interface OakChooser () <NSWindowDelegate, NSTextFieldDelegate, NSTableViewDataSource, NSTableViewDelegate>
|
||||
@end
|
||||
|
||||
static void* kFirstResponderBinding = &kFirstResponderBinding;
|
||||
@@ -48,6 +49,7 @@ static void* kFirstResponderBinding = &kFirstResponderBinding;
|
||||
[_searchField.cell setSendsSearchStringImmediately:YES];
|
||||
if(![NSApp isFullKeyboardAccessEnabled])
|
||||
_searchField.focusRingType = NSFocusRingTypeNone;
|
||||
_searchField.delegate = self;
|
||||
|
||||
NSTableColumn* tableColumn = [[NSTableColumn alloc] initWithIdentifier:@"name"];
|
||||
tableColumn.dataCell = [[NSTextFieldCell alloc] initTextCell:@""];
|
||||
@@ -64,7 +66,6 @@ static void* kFirstResponderBinding = &kFirstResponderBinding;
|
||||
tableView.target = self;
|
||||
tableView.dataSource = self;
|
||||
tableView.delegate = self;
|
||||
tableView.linkedTextField = _searchField;
|
||||
if(nil != &NSAccessibilitySharedFocusElementsAttribute)
|
||||
[_searchField.cell accessibilitySetOverrideValue:@[tableView] forAttribute:NSAccessibilitySharedFocusElementsAttribute];
|
||||
_tableView = tableView;
|
||||
@@ -118,6 +119,7 @@ static void* kFirstResponderBinding = &kFirstResponderBinding;
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_searchField.delegate = nil;
|
||||
[_searchField unbind:NSValueBinding];
|
||||
[_window removeObserver:self forKeyPath:@"firstResponder" context:kFirstResponderBinding];
|
||||
|
||||
@@ -168,6 +170,15 @@ static void* kFirstResponderBinding = &kFirstResponderBinding;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================================================
|
||||
// = Forward Search Field Movement Actions to TableView =
|
||||
// ======================================================
|
||||
|
||||
- (BOOL)control:(NSControl*)aControl textView:(NSTextView*)aTextView doCommandBySelector:(SEL)aCommand
|
||||
{
|
||||
return OakPerformTableViewActionFromSelector(self.tableView, aCommand, aTextView);
|
||||
}
|
||||
|
||||
// ==============
|
||||
// = Properties =
|
||||
// ==============
|
||||
|
||||
@@ -1,75 +1,5 @@
|
||||
#import "TableView.h"
|
||||
#import <OakFoundation/NSString Additions.h>
|
||||
#import <OakAppKit/OakAppKit.h> // Accessibility API missing from 10.7/10.8 SDK.
|
||||
#import <oak/algorithm.h>
|
||||
|
||||
// ========================================
|
||||
// = Forward NSTextField Movement Actions =
|
||||
// ========================================
|
||||
|
||||
@interface OakTextFieldMovementDelegate : NSObject <NSTextFieldDelegate>
|
||||
@property (nonatomic, weak) NSTableView* tableView;
|
||||
@end
|
||||
|
||||
static NSString* const kUserDefaultsEnableLoopFilterList = @"enableLoopFilterList";
|
||||
|
||||
@implementation OakTextFieldMovementDelegate
|
||||
- (void)moveSelectedRowByOffset:(NSInteger)anOffset extendingSelection:(BOOL)extend sender:(id)sender
|
||||
{
|
||||
if([_tableView numberOfRows])
|
||||
{
|
||||
if(_tableView.allowsMultipleSelection == NO)
|
||||
extend = NO;
|
||||
|
||||
NSInteger row = [_tableView selectedRow] + anOffset;
|
||||
NSInteger numberOfRows = [_tableView numberOfRows];
|
||||
if(abs(anOffset) == 1 && numberOfRows && [[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsEnableLoopFilterList])
|
||||
row = (row + numberOfRows) % numberOfRows;
|
||||
else row = oak::cap((NSInteger)0, row, numberOfRows - 1);
|
||||
|
||||
[_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:extend];
|
||||
[_tableView scrollRowToVisible:row];
|
||||
}
|
||||
}
|
||||
|
||||
- (int)visibleRows { return (int)floor(NSHeight([_tableView visibleRect]) / ([_tableView rowHeight]+[_tableView intercellSpacing].height)) - 1; }
|
||||
|
||||
- (void)moveUp:(id)sender { [self moveSelectedRowByOffset:-1 extendingSelection:NO sender:sender]; }
|
||||
- (void)moveDown:(id)sender { [self moveSelectedRowByOffset:+1 extendingSelection:NO sender:sender]; }
|
||||
- (void)moveUpAndModifySelection:(id)sender { [self moveSelectedRowByOffset:-1 extendingSelection:YES sender:sender]; }
|
||||
- (void)moveDownAndModifySelection:(id)sender { [self moveSelectedRowByOffset:+1 extendingSelection:YES sender:sender]; }
|
||||
- (void)movePageUp:(id)sender { [self moveSelectedRowByOffset:-[self visibleRows] extendingSelection:NO sender:sender]; }
|
||||
- (void)movePageDown:(id)sender { [self moveSelectedRowByOffset:+[self visibleRows] extendingSelection:NO sender:sender]; }
|
||||
- (void)moveToBeginningOfDocument:(id)sender { [self moveSelectedRowByOffset:-(INT_MAX >> 1) extendingSelection:NO sender:sender]; }
|
||||
- (void)moveToEndOfDocument:(id)sender { [self moveSelectedRowByOffset:+(INT_MAX >> 1) extendingSelection:NO sender:sender]; }
|
||||
|
||||
- (void)pageUp:(id)sender { [self movePageUp:sender]; }
|
||||
- (void)pageDown:(id)sender { [self movePageDown:sender]; }
|
||||
- (void)scrollPageUp:(id)sender { [self movePageUp:sender]; }
|
||||
- (void)scrollPageDown:(id)sender { [self movePageDown:sender]; }
|
||||
- (void)scrollToBeginningOfDocument:(id)sender { [self moveToBeginningOfDocument:sender]; }
|
||||
- (void)scrollToEndOfDocument:(id)sender { [self moveToEndOfDocument:sender]; }
|
||||
|
||||
- (IBAction)insertNewline:(id)sender { [NSApp sendAction:@selector(accept:) to:nil from:sender]; }
|
||||
- (IBAction)insertNewlineIgnoringFieldEditor:(id)sender { [NSApp sendAction:@selector(accept:) to:nil from:sender]; }
|
||||
- (IBAction)cancelOperation:(id)sender { [NSApp sendAction:@selector(cancel:) to:nil from:sender]; }
|
||||
|
||||
- (BOOL)control:(NSControl*)aControl textView:(NSTextView*)aTextView doCommandBySelector:(SEL)aCommand
|
||||
{
|
||||
static auto const forward = new std::set<SEL>{ @selector(moveUp:), @selector(moveDown:), @selector(moveUpAndModifySelection:), @selector(moveDownAndModifySelection:), @selector(pageUp:), @selector(pageDown:), @selector(movePageUp:), @selector(movePageDown:), @selector(scrollPageUp:), @selector(scrollPageDown:), @selector(moveToBeginningOfDocument:), @selector(moveToEndOfDocument:), @selector(scrollToBeginningOfDocument:), @selector(scrollToEndOfDocument:), @selector(insertNewline:), @selector(insertNewlineIgnoringFieldEditor:), @selector(cancelOperation:) };
|
||||
if(aCommand == @selector(deleteToBeginningOfLine:) && [aControl.window tryToPerform:@selector(delete:) with:aControl])
|
||||
return YES;
|
||||
else if(forward->find(aCommand) != forward->end() && [self respondsToSelector:aCommand])
|
||||
return [NSApp sendAction:aCommand to:self from:aControl];
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
|
||||
// ========================================
|
||||
|
||||
@interface OakInactiveTableView ()
|
||||
@property (nonatomic) OakTextFieldMovementDelegate* textFieldMovementDelegate;
|
||||
@end
|
||||
|
||||
@implementation OakInactiveTableView
|
||||
- (NSCell*)preparedCellAtColumn:(NSInteger)column row:(NSInteger)row
|
||||
@@ -99,21 +29,6 @@ static NSString* const kUserDefaultsEnableLoopFilterList = @"enableLoopFilterLis
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)setLinkedTextField:(NSTextField*)aTextField
|
||||
{
|
||||
_textFieldMovementDelegate = [OakTextFieldMovementDelegate new];
|
||||
_textFieldMovementDelegate.tableView = self;
|
||||
|
||||
_linkedTextField.delegate = nil;
|
||||
_linkedTextField = aTextField;
|
||||
_linkedTextField.delegate = _textFieldMovementDelegate;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
_linkedTextField.delegate = nil;
|
||||
}
|
||||
|
||||
- (void)setDrawAsHighlighted:(BOOL)flag
|
||||
{
|
||||
if(_drawAsHighlighted == flag)
|
||||
|
||||
1
Frameworks/OakFilterList/src/ui/TableViewAction.h
Normal file
1
Frameworks/OakFilterList/src/ui/TableViewAction.h
Normal file
@@ -0,0 +1 @@
|
||||
BOOL OakPerformTableViewActionFromSelector (NSTableView* tableView, SEL selector, NSTextView* textView);
|
||||
72
Frameworks/OakFilterList/src/ui/TableViewAction.mm
Normal file
72
Frameworks/OakFilterList/src/ui/TableViewAction.mm
Normal file
@@ -0,0 +1,72 @@
|
||||
#import "TableViewAction.h"
|
||||
#import <oak/algorithm.h>
|
||||
|
||||
static NSString* const kUserDefaultsEnableLoopFilterList = @"enableLoopFilterList";
|
||||
|
||||
@interface OakTableViewActionHelper : NSResponder
|
||||
@property (nonatomic) NSTableView* tableView;
|
||||
@end
|
||||
|
||||
@implementation OakTableViewActionHelper
|
||||
+ (instancetype)tableViewActionHelperWithTableView:(NSTableView*)aTableView
|
||||
{
|
||||
OakTableViewActionHelper* helper = [[self alloc] init];
|
||||
helper.tableView = aTableView;
|
||||
return helper;
|
||||
}
|
||||
|
||||
- (void)moveSelectedRowByOffset:(NSInteger)anOffset extendingSelection:(BOOL)extend sender:(id)sender
|
||||
{
|
||||
if([_tableView numberOfRows])
|
||||
{
|
||||
if(_tableView.allowsMultipleSelection == NO)
|
||||
extend = NO;
|
||||
|
||||
NSInteger row = [_tableView selectedRow] + anOffset;
|
||||
NSInteger numberOfRows = [_tableView numberOfRows];
|
||||
if(abs(anOffset) == 1 && numberOfRows && [[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsEnableLoopFilterList])
|
||||
row = (row + numberOfRows) % numberOfRows;
|
||||
else row = oak::cap((NSInteger)0, row, numberOfRows - 1);
|
||||
|
||||
[_tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:extend];
|
||||
[_tableView scrollRowToVisible:row];
|
||||
}
|
||||
}
|
||||
|
||||
- (int)visibleRows { return (int)floor(NSHeight([_tableView visibleRect]) / ([_tableView rowHeight]+[_tableView intercellSpacing].height)) - 1; }
|
||||
|
||||
- (void)moveUp:(id)sender { [self moveSelectedRowByOffset:-1 extendingSelection:NO sender:sender]; }
|
||||
- (void)moveDown:(id)sender { [self moveSelectedRowByOffset:+1 extendingSelection:NO sender:sender]; }
|
||||
- (void)moveUpAndModifySelection:(id)sender { [self moveSelectedRowByOffset:-1 extendingSelection:YES sender:sender]; }
|
||||
- (void)moveDownAndModifySelection:(id)sender { [self moveSelectedRowByOffset:+1 extendingSelection:YES sender:sender]; }
|
||||
- (void)movePageUp:(id)sender { [self moveSelectedRowByOffset:-[self visibleRows] extendingSelection:NO sender:sender]; }
|
||||
- (void)movePageDown:(id)sender { [self moveSelectedRowByOffset:+[self visibleRows] extendingSelection:NO sender:sender]; }
|
||||
- (void)moveToBeginningOfDocument:(id)sender { [self moveSelectedRowByOffset:-(INT_MAX >> 1) extendingSelection:NO sender:sender]; }
|
||||
- (void)moveToEndOfDocument:(id)sender { [self moveSelectedRowByOffset:+(INT_MAX >> 1) extendingSelection:NO sender:sender]; }
|
||||
|
||||
- (void)pageUp:(id)sender { [self movePageUp:sender]; }
|
||||
- (void)pageDown:(id)sender { [self movePageDown:sender]; }
|
||||
- (void)scrollPageUp:(id)sender { [self movePageUp:sender]; }
|
||||
- (void)scrollPageDown:(id)sender { [self movePageDown:sender]; }
|
||||
- (void)scrollToBeginningOfDocument:(id)sender { [self moveToBeginningOfDocument:sender]; }
|
||||
- (void)scrollToEndOfDocument:(id)sender { [self moveToEndOfDocument:sender]; }
|
||||
|
||||
- (IBAction)insertNewline:(id)sender { [NSApp sendAction:@selector(accept:) to:nil from:sender]; }
|
||||
- (IBAction)insertNewlineIgnoringFieldEditor:(id)sender { [NSApp sendAction:@selector(accept:) to:nil from:sender]; }
|
||||
- (IBAction)cancelOperation:(id)sender { [NSApp sendAction:@selector(cancel:) to:nil from:sender]; }
|
||||
|
||||
- (BOOL)doCommandBySelector:(SEL)aSelector withSender:(id)aSender
|
||||
{
|
||||
static auto const forward = new std::set<SEL>{ @selector(moveUp:), @selector(moveDown:), @selector(moveUpAndModifySelection:), @selector(moveDownAndModifySelection:), @selector(pageUp:), @selector(pageDown:), @selector(movePageUp:), @selector(movePageDown:), @selector(scrollPageUp:), @selector(scrollPageDown:), @selector(moveToBeginningOfDocument:), @selector(moveToEndOfDocument:), @selector(scrollToBeginningOfDocument:), @selector(scrollToEndOfDocument:), @selector(insertNewline:), @selector(insertNewlineIgnoringFieldEditor:), @selector(cancelOperation:) };
|
||||
if(forward->find(aSelector) != forward->end() && [self respondsToSelector:aSelector])
|
||||
return [NSApp sendAction:aSelector to:self from:aSender];
|
||||
return NO;
|
||||
}
|
||||
@end
|
||||
|
||||
BOOL OakPerformTableViewActionFromSelector (NSTableView* tableView, SEL selector, NSTextView* textView)
|
||||
{
|
||||
if(selector == @selector(deleteToBeginningOfLine:) && [textView.window tryToPerform:@selector(delete:) with:textView])
|
||||
return YES;
|
||||
return [[OakTableViewActionHelper tableViewActionHelperWithTableView:tableView] doCommandBySelector:selector withSender:textView];
|
||||
}
|
||||
Reference in New Issue
Block a user