aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPTextAndLinkCell.m
diff options
context:
space:
mode:
authorrowanbeentje <rowan@beent.je>2009-07-21 21:43:13 +0000
committerrowanbeentje <rowan@beent.je>2009-07-21 21:43:13 +0000
commitb6ce7c756f63de03ea2d87aaa733751610ee2dee (patch)
tree9cbd6ad21631ca4521a09da698e18ab0f61b3d49 /Source/SPTextAndLinkCell.m
parenteedd073ec6134a822ee8c51e388f6bcec5fb6687 (diff)
downloadsequelpro-b6ce7c756f63de03ea2d87aaa733751610ee2dee.tar.gz
sequelpro-b6ce7c756f63de03ea2d87aaa733751610ee2dee.tar.bz2
sequelpro-b6ce7c756f63de03ea2d87aaa733751610ee2dee.zip
- Improve the TextAndLinkCell (foreign key link arrows) to make the arrows behave like proper buttons, allowing clicking and dragging out to cancel the click, and highlight states
Diffstat (limited to 'Source/SPTextAndLinkCell.m')
-rw-r--r--Source/SPTextAndLinkCell.m71
1 files changed, 68 insertions, 3 deletions
diff --git a/Source/SPTextAndLinkCell.m b/Source/SPTextAndLinkCell.m
index 2a57c8b3..d1e8338e 100644
--- a/Source/SPTextAndLinkCell.m
+++ b/Source/SPTextAndLinkCell.m
@@ -28,6 +28,13 @@
@implementation SPTextAndLinkCell
+/**
+ * Provide a method to derive the link rect from a cell rect.
+ */
+static inline NSRect SPTextLinkRectFromCellRect(NSRect inRect) {
+ return NSMakeRect(inRect.origin.x + inRect.size.width - 15, inRect.origin.y - 1, 12, inRect.size.height);
+}
+
#pragma mark -
#pragma mark Setup and teardown
@@ -99,6 +106,7 @@
[linkButton setBordered:NO];
[linkButton setShowsBorderOnlyWhileMouseInside:YES];
[linkButton setImage:[NSImage imageNamed:@"link-arrow"]];
+ [linkButton setAlternateImage:[NSImage imageNamed:@"link-arrow-clicked"]];
}
}
@@ -120,7 +128,7 @@
// Set up new rects
NSRect textRect = NSMakeRect(aRect.origin.x, aRect.origin.y, aRect.size.width - 18, aRect.size.height);
- linkRect = NSMakeRect(aRect.origin.x + aRect.size.width - 15, aRect.origin.y - 1, 12, aRect.size.height);
+ NSRect linkRect = SPTextLinkRectFromCellRect(aRect);
// Draw the text
[super drawInteriorWithFrame:textRect inView:controlView];
@@ -138,12 +146,15 @@
switch (drawState) {
case SP_LINKDRAWSTATE_NORMAL:
[linkButton setImage:[NSImage imageNamed:@"link-arrow"]];
+ [linkButton setAlternateImage:[NSImage imageNamed:@"link-arrow-clicked"]];
break;
case SP_LINKDRAWSTATE_HIGHLIGHT:
[linkButton setImage:[NSImage imageNamed:@"link-arrow-highlighted"]];
+ [linkButton setAlternateImage:[NSImage imageNamed:@"link-arrow-highlighted-clicked"]];
break;
case SP_LINKDRAWSTATE_BACKGROUNDHIGHLIGHT:
[linkButton setImage:[NSImage imageNamed:@"link-arrow-clicked"]];
+ [linkButton setAlternateImage:[NSImage imageNamed:@"link-arrow"]];
break;
}
}
@@ -161,6 +172,7 @@
if (!hasLink) return NSCellHitContentArea | NSCellHitEditableTextArea;
NSPoint p = [[[NSApp mainWindow] contentView] convertPoint:[event locationInWindow] toView:controlView];
+ NSRect linkRect = SPTextLinkRectFromCellRect(cellFrame);
// Hit the link if it falls within the link rectangle for this cell, set when drawing
if (p.x > linkRect.origin.x && p.x < (linkRect.origin.x + linkRect.size.width)) {
@@ -171,8 +183,8 @@
lastLinkColumn = [tableView columnAtPoint:p];
lastLinkRow = [tableView rowAtPoint:p];
- [linkTarget performSelector:linkAction withObject:self];
- return NSCellHitContentArea;
+ // Return a trackable hit
+ return NSCellHitContentArea | NSCellHitTrackableArea;
// Otherwise return an editable hit - this allows the entire cell to be clicked to edit the contents.
} else {
@@ -180,6 +192,59 @@
}
}
+/**
+ * Allow mouse tracking within the button cell, to support expected click
+ * behaviour in the button cell.
+ */
+- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)untilMouseUp
+{
+
+ // Fast case for no link
+ if (!hasLink) return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
+
+ NSPoint p = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+ NSRect linkRect = SPTextLinkRectFromCellRect(cellFrame);
+
+ // Fast path for if not in button rect - just pass to super
+ if (!NSMouseInRect(p, linkRect, [controlView isFlipped]))
+ return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:untilMouseUp];
+
+ // Continue tracking the mouse while it's down, updating the state as it enters and leaves the cell,
+ // until it is released; if still within the cell, follow the link.
+ BOOL mouseInButton = YES;
+ while (1) {
+ if (mouseInButton) {
+
+ // Highlight the button
+ [linkButton highlight:YES withFrame:linkRect inView:controlView];
+
+ // Continue to track until mouse completes a click or exits the cell while still down
+ BOOL mouseClicked = [linkButton trackMouse:theEvent inRect:linkRect ofView:controlView untilMouseUp:NO];
+ if (mouseClicked) {
+
+ // Remove highlight, and follow the link
+ [linkButton highlight:NO withFrame:linkRect inView:controlView];
+ [linkTarget performSelector:linkAction withObject:self];
+ return YES;
+ }
+
+ // Mouse has exited the cell. Remove highlight.
+ mouseInButton = NO;
+ [linkButton highlight:NO withFrame:linkRect inView:controlView];
+ }
+
+ // Keep tracking the mouse outside the button, until the mouse button is released or it reenters the button
+ theEvent = [[controlView window] nextEventMatchingMask: NSLeftMouseUpMask | NSLeftMouseDraggedMask];
+ p = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+ mouseInButton = NSMouseInRect(p, linkRect, [controlView isFlipped]);
+
+ // If the event is a mouse release, break the loop.
+ if ([theEvent type] == NSLeftMouseUp) break;
+ }
+
+ return YES;
+}
+
#pragma mark -
#pragma mark Information getters