aboutsummaryrefslogtreecommitdiffstats
path: root/MASShortcutView.m
diff options
context:
space:
mode:
Diffstat (limited to 'MASShortcutView.m')
-rw-r--r--MASShortcutView.m428
1 files changed, 0 insertions, 428 deletions
diff --git a/MASShortcutView.m b/MASShortcutView.m
deleted file mode 100644
index 27e6ae7..0000000
--- a/MASShortcutView.m
+++ /dev/null
@@ -1,428 +0,0 @@
-#import "MASShortcutView.h"
-#import "MASShortcut.h"
-
-#define HINT_BUTTON_WIDTH 23.0
-#define BUTTON_FONT_SIZE 11.0
-#define SEGMENT_CHROME_WIDTH 6.0
-
-#pragma mark -
-
-@interface MASShortcutView () // Private accessors
-
-@property (nonatomic, getter = isHinting) BOOL hinting;
-@property (nonatomic, copy) NSString *shortcutPlaceholder;
-
-@end
-
-#pragma mark -
-
-@implementation MASShortcutView {
- NSButtonCell *_shortcutCell;
- NSInteger _shortcutToolTipTag;
- NSInteger _hintToolTipTag;
- NSTrackingArea *_hintArea;
-}
-
-@synthesize enabled = _enabled;
-@synthesize hinting = _hinting;
-@synthesize shortcutValue = _shortcutValue;
-@synthesize shortcutPlaceholder = _shortcutPlaceholder;
-@synthesize shortcutValueChange = _shortcutValueChange;
-@synthesize recording = _recording;
-
-#pragma mark -
-
-- (id)initWithFrame:(CGRect)frameRect
-{
- self = [super initWithFrame:frameRect];
- if (self) {
- _shortcutCell = [[NSButtonCell alloc] init];
- _shortcutCell.buttonType = NSPushOnPushOffButton;
- _shortcutCell.font = [[NSFontManager sharedFontManager] convertFont:_shortcutCell.font toSize:BUTTON_FONT_SIZE];
- _enabled = YES;
- [self resetShortcutCellStyle];
- }
- return self;
-}
-
-- (void)dealloc
-{
- [self activateEventMonitoring:NO];
- [self activateResignObserver:NO];
-}
-
-#pragma mark - Public accessors
-
-- (void)setEnabled:(BOOL)flag
-{
- if (_enabled != flag) {
- _enabled = flag;
- [self updateTrackingAreas];
- self.recording = NO;
- [self setNeedsDisplay:YES];
- }
-}
-
-- (void)setAppearance:(MASShortcutViewAppearance)appearance
-{
- if (_appearance != appearance) {
- _appearance = appearance;
- [self resetShortcutCellStyle];
- [self setNeedsDisplay:YES];
- }
-}
-
-- (void)resetShortcutCellStyle
-{
- switch (_appearance) {
- case MASShortcutViewAppearanceDefault: {
- _shortcutCell.bezelStyle = NSRoundRectBezelStyle;
- break;
- }
- case MASShortcutViewAppearanceTexturedRect: {
- _shortcutCell.bezelStyle = NSTexturedRoundedBezelStyle;
- break;
- }
- case MASShortcutViewAppearanceRounded: {
- _shortcutCell.bezelStyle = NSRoundedBezelStyle;
- break;
- }
- }
-}
-
-- (void)setRecording:(BOOL)flag
-{
- // Only one recorder can be active at the moment
- static MASShortcutView *currentRecorder = nil;
- if (flag && (currentRecorder != self)) {
- currentRecorder.recording = NO;
- currentRecorder = flag ? self : nil;
- }
-
- // Only enabled view supports recording
- if (flag && !self.enabled) return;
-
- if (_recording != flag) {
- _recording = flag;
- self.shortcutPlaceholder = nil;
- [self resetToolTips];
- [self activateEventMonitoring:_recording];
- [self activateResignObserver:_recording];
- [self setNeedsDisplay:YES];
- }
-}
-
-- (void)setShortcutValue:(MASShortcut *)shortcutValue
-{
- _shortcutValue = shortcutValue;
- [self resetToolTips];
- [self setNeedsDisplay:YES];
-
- if (self.shortcutValueChange) {
- self.shortcutValueChange(self);
- }
-}
-
-- (void)setShortcutPlaceholder:(NSString *)shortcutPlaceholder
-{
- _shortcutPlaceholder = shortcutPlaceholder.copy;
- [self setNeedsDisplay:YES];
-}
-
-#pragma mark - Drawing
-
-- (BOOL)isFlipped
-{
- return YES;
-}
-
-- (void)drawInRect:(CGRect)frame withTitle:(NSString *)title alignment:(NSTextAlignment)alignment state:(NSInteger)state
-{
- _shortcutCell.title = title;
- _shortcutCell.alignment = alignment;
- _shortcutCell.state = state;
- _shortcutCell.enabled = self.enabled;
-
- switch (_appearance) {
- case MASShortcutViewAppearanceDefault: {
- [_shortcutCell drawWithFrame:frame inView:self];
- break;
- }
- case MASShortcutViewAppearanceTexturedRect: {
- [_shortcutCell drawWithFrame:CGRectOffset(frame, 0.0, 1.0) inView:self];
- break;
- }
- case MASShortcutViewAppearanceRounded: {
- [_shortcutCell drawWithFrame:CGRectOffset(frame, 0.0, 1.0) inView:self];
- break;
- }
- }
-}
-
-- (void)drawRect:(CGRect)dirtyRect
-{
- if (self.shortcutValue) {
- [self drawInRect:self.bounds withTitle:MASShortcutChar(self.recording ? kMASShortcutGlyphEscape : kMASShortcutGlyphDeleteLeft)
- alignment:NSRightTextAlignment state:NSOffState];
-
- CGRect shortcutRect;
- [self getShortcutRect:&shortcutRect hintRect:NULL];
- NSString *title = (self.recording
- ? (_hinting
- ? NSLocalizedString(@"Use Old Shortuct", @"Cancel action button for non-empty shortcut in recording state")
- : (self.shortcutPlaceholder.length > 0
- ? self.shortcutPlaceholder
- : NSLocalizedString(@"Type New Shortcut", @"Non-empty shortcut button in recording state")))
- : _shortcutValue ? _shortcutValue.description : @"");
- [self drawInRect:shortcutRect withTitle:title alignment:NSCenterTextAlignment state:self.isRecording ? NSOnState : NSOffState];
- }
- else {
- if (self.recording)
- {
- [self drawInRect:self.bounds withTitle:MASShortcutChar(kMASShortcutGlyphEscape) alignment:NSRightTextAlignment state:NSOffState];
-
- CGRect shortcutRect;
- [self getShortcutRect:&shortcutRect hintRect:NULL];
- NSString *title = (_hinting
- ? NSLocalizedString(@"Cancel", @"Cancel action button in recording state")
- : (self.shortcutPlaceholder.length > 0
- ? self.shortcutPlaceholder
- : NSLocalizedString(@"Type Shortcut", @"Empty shortcut button in recording state")));
- [self drawInRect:shortcutRect withTitle:title alignment:NSCenterTextAlignment state:NSOnState];
- }
- else
- {
- [self drawInRect:self.bounds withTitle:NSLocalizedString(@"Record Shortcut", @"Empty shortcut button in normal state")
- alignment:NSCenterTextAlignment state:NSOffState];
- }
- }
-}
-
-#pragma mark - Mouse handling
-
-- (void)getShortcutRect:(CGRect *)shortcutRectRef hintRect:(CGRect *)hintRectRef
-{
- CGRect shortcutRect, hintRect;
- CGFloat hintButtonWidth = HINT_BUTTON_WIDTH;
- switch (self.appearance) {
- case MASShortcutViewAppearanceTexturedRect: hintButtonWidth += 2.0; break;
- case MASShortcutViewAppearanceRounded: hintButtonWidth += 3.0; break;
- default: break;
- }
- CGRectDivide(self.bounds, &hintRect, &shortcutRect, hintButtonWidth, CGRectMaxXEdge);
- if (shortcutRectRef) *shortcutRectRef = shortcutRect;
- if (hintRectRef) *hintRectRef = hintRect;
-}
-
-- (BOOL)locationInShortcutRect:(CGPoint)location
-{
- CGRect shortcutRect;
- [self getShortcutRect:&shortcutRect hintRect:NULL];
- return CGRectContainsPoint(shortcutRect, [self convertPoint:location fromView:nil]);
-}
-
-- (BOOL)locationInHintRect:(CGPoint)location
-{
- CGRect hintRect;
- [self getShortcutRect:NULL hintRect:&hintRect];
- return CGRectContainsPoint(hintRect, [self convertPoint:location fromView:nil]);
-}
-
-- (void)mouseDown:(NSEvent *)event
-{
- if (self.enabled) {
- if (self.shortcutValue) {
- if (self.recording) {
- if ([self locationInHintRect:event.locationInWindow]) {
- self.recording = NO;
- }
- }
- else {
- if ([self locationInShortcutRect:event.locationInWindow]) {
- self.recording = YES;
- }
- else {
- self.shortcutValue = nil;
- }
- }
- }
- else {
- if (self.recording) {
- if ([self locationInHintRect:event.locationInWindow]) {
- self.recording = NO;
- }
- }
- else {
- self.recording = YES;
- }
- }
- }
- else {
- [super mouseDown:event];
- }
-}
-
-#pragma mark - Handling mouse over
-
-- (void)updateTrackingAreas
-{
- [super updateTrackingAreas];
-
- if (_hintArea) {
- [self removeTrackingArea:_hintArea];
- _hintArea = nil;
- }
-
- // Forbid hinting if view is disabled
- if (!self.enabled) return;
-
- CGRect hintRect;
- [self getShortcutRect:NULL hintRect:&hintRect];
- NSTrackingAreaOptions options = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingAssumeInside);
- _hintArea = [[NSTrackingArea alloc] initWithRect:hintRect options:options owner:self userInfo:nil];
- [self addTrackingArea:_hintArea];
-}
-
-- (void)setHinting:(BOOL)flag
-{
- if (_hinting != flag) {
- _hinting = flag;
- [self setNeedsDisplay:YES];
- }
-}
-
-- (void)mouseEntered:(NSEvent *)event
-{
- self.hinting = YES;
-}
-
-- (void)mouseExited:(NSEvent *)event
-{
- self.hinting = NO;
-}
-
-void *kUserDataShortcut = &kUserDataShortcut;
-void *kUserDataHint = &kUserDataHint;
-
-- (void)resetToolTips
-{
- if (_shortcutToolTipTag) {
- [self removeToolTip:_shortcutToolTipTag], _shortcutToolTipTag = 0;
- }
- if (_hintToolTipTag) {
- [self removeToolTip:_hintToolTipTag], _hintToolTipTag = 0;
- }
-
- if ((self.shortcutValue == nil) || self.recording || !self.enabled) return;
-
- CGRect shortcutRect, hintRect;
- [self getShortcutRect:&shortcutRect hintRect:&hintRect];
- _shortcutToolTipTag = [self addToolTipRect:shortcutRect owner:self userData:kUserDataShortcut];
- _hintToolTipTag = [self addToolTipRect:hintRect owner:self userData:kUserDataHint];
-}
-
-- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(CGPoint)point userData:(void *)data
-{
- if (data == kUserDataShortcut) {
- return NSLocalizedString(@"Click to record new shortcut", @"Tooltip for non-empty shortcut button");
- }
- else if (data == kUserDataHint) {
- return NSLocalizedString(@"Delete shortcut", @"Tooltip for hint button near the non-empty shortcut");
- }
- return nil;
-}
-
-#pragma mark - Event monitoring
-
-- (void)activateEventMonitoring:(BOOL)shouldActivate
-{
- static BOOL isActive = NO;
- if (isActive == shouldActivate) return;
- isActive = shouldActivate;
-
- static id eventMonitor = nil;
- if (shouldActivate) {
- __weak MASShortcutView *weakSelf = self;
- NSEventMask eventMask = (NSKeyDownMask | NSFlagsChangedMask);
- eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^(NSEvent *event) {
-
- MASShortcut *shortcut = [MASShortcut shortcutWithEvent:event];
- if ((shortcut.keyCode == kVK_Delete) || (shortcut.keyCode == kVK_ForwardDelete)) {
- // Delete shortcut
- weakSelf.shortcutValue = nil;
- weakSelf.recording = NO;
- event = nil;
- }
- else if (shortcut.keyCode == kVK_Escape) {
- // Cancel recording
- weakSelf.recording = NO;
- event = nil;
- }
- else if (shortcut.shouldBypass) {
- // Command + W, Command + Q, ESC should deactivate recorder
- weakSelf.recording = NO;
- }
- else {
- // Verify possible shortcut
- if (shortcut.keyCodeString.length > 0) {
- if (shortcut.valid) {
- // Verify that shortcut is not used
- NSError *error = nil;
- if ([shortcut isTakenError:&error]) {
- // Prevent cancel of recording when Alert window is key
- [weakSelf activateResignObserver:NO];
- [weakSelf activateEventMonitoring:NO];
- NSString *format = NSLocalizedString(@"The key combination %@ cannot be used",
- @"Title for alert when shortcut is already used");
- NSRunCriticalAlertPanel([NSString stringWithFormat:format, shortcut], error.localizedDescription,
- NSLocalizedString(@"OK", @"Alert button when shortcut is already used"),
- nil, nil);
- weakSelf.shortcutPlaceholder = nil;
- [weakSelf activateResignObserver:YES];
- [weakSelf activateEventMonitoring:YES];
- }
- else {
- weakSelf.shortcutValue = shortcut;
- weakSelf.recording = NO;
- }
- }
- else {
- // Key press with or without SHIFT is not valid input
- NSBeep();
- }
- }
- else {
- // User is playing with modifier keys
- weakSelf.shortcutPlaceholder = shortcut.modifierFlagsString;
- }
- event = nil;
- }
- return event;
- }];
- }
- else {
- [NSEvent removeMonitor:eventMonitor];
- }
-}
-
-- (void)activateResignObserver:(BOOL)shouldActivate
-{
- static BOOL isActive = NO;
- if (isActive == shouldActivate) return;
- isActive = shouldActivate;
-
- static id observer = nil;
- NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
- if (shouldActivate) {
- __weak MASShortcutView *weakSelf = self;
- observer = [notificationCenter addObserverForName:NSWindowDidResignKeyNotification object:self.window
- queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) {
- weakSelf.recording = NO;
- }];
- }
- else {
- [notificationCenter removeObserver:observer];
- }
-}
-
-@end