aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Resources/Images/link-arrow-highlighted-clicked.pngbin0 -> 249 bytes
-rw-r--r--Resources/Images/link-arrow-highlighted.pngbin249 -> 271 bytes
-rw-r--r--Source/SPTextAndLinkCell.h1
-rw-r--r--Source/SPTextAndLinkCell.m71
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj16
5 files changed, 78 insertions, 10 deletions
diff --git a/Resources/Images/link-arrow-highlighted-clicked.png b/Resources/Images/link-arrow-highlighted-clicked.png
new file mode 100644
index 00000000..5ce39b58
--- /dev/null
+++ b/Resources/Images/link-arrow-highlighted-clicked.png
Binary files differ
diff --git a/Resources/Images/link-arrow-highlighted.png b/Resources/Images/link-arrow-highlighted.png
index 5ce39b58..ce1d6b14 100644
--- a/Resources/Images/link-arrow-highlighted.png
+++ b/Resources/Images/link-arrow-highlighted.png
Binary files differ
diff --git a/Source/SPTextAndLinkCell.h b/Source/SPTextAndLinkCell.h
index 48d6bb18..7cd34c3f 100644
--- a/Source/SPTextAndLinkCell.h
+++ b/Source/SPTextAndLinkCell.h
@@ -39,7 +39,6 @@ enum sptextandlinkcell_drawstates
id linkTarget;
SEL linkAction;
- NSRect linkRect;
int lastLinkColumn;
int lastLinkRow;
int drawState;
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
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index 4b1e79c2..729133f9 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -127,6 +127,7 @@
4DECC3370EC2A170008D359E /* Growl.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DECC3340EC2A170008D359E /* Growl.framework */; };
4DECC48F0EC2B436008D359E /* Sparkle.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4DECC3320EC2A170008D359E /* Sparkle.framework */; };
4DECC4910EC2B436008D359E /* Growl.framework in CopyFiles */ = {isa = PBXBuildFile; fileRef = 4DECC3340EC2A170008D359E /* Growl.framework */; };
+ 581068B61015411B0068C6E2 /* link-arrow-highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = 581068B51015411B0068C6E2 /* link-arrow-highlighted.png */; };
58186D210F4CB38900851FE9 /* ConnectionErrorDialog.xib in Resources */ = {isa = PBXBuildFile; fileRef = 58186D1F0F4CB38900851FE9 /* ConnectionErrorDialog.xib */; };
5822C9B51000DB2400DCC3D6 /* SPConnectionController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5822C9B41000DB2400DCC3D6 /* SPConnectionController.m */; };
5822CAE110011C8000DCC3D6 /* ConnectionView.xib in Resources */ = {isa = PBXBuildFile; fileRef = 5822CADF10011C8000DCC3D6 /* ConnectionView.xib */; };
@@ -146,7 +147,7 @@
58CDB3420FCE142500F8ACA3 /* KeyChain.m in Sources */ = {isa = PBXBuildFile; fileRef = 17E641740EF01F80001BC333 /* KeyChain.m */; };
58D2E229101222670063EF1D /* SPTextAndLinkCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 58D2E227101222670063EF1D /* SPTextAndLinkCell.m */; };
58D2E22E101222870063EF1D /* link-arrow-clicked.png in Resources */ = {isa = PBXBuildFile; fileRef = 58D2E22B101222870063EF1D /* link-arrow-clicked.png */; };
- 58D2E22F101222870063EF1D /* link-arrow-highlighted.png in Resources */ = {isa = PBXBuildFile; fileRef = 58D2E22C101222870063EF1D /* link-arrow-highlighted.png */; };
+ 58D2E22F101222870063EF1D /* link-arrow-highlighted-clicked.png in Resources */ = {isa = PBXBuildFile; fileRef = 58D2E22C101222870063EF1D /* link-arrow-highlighted-clicked.png */; };
58D2E230101222870063EF1D /* link-arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = 58D2E22D101222870063EF1D /* link-arrow.png */; };
58FEF16D0F23D66600518E8E /* SPSQLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FEF16C0F23D66600518E8E /* SPSQLParser.m */; };
58FEF57E0F3B4E9700518E8E /* SPTableData.m in Sources */ = {isa = PBXBuildFile; fileRef = 58FEF57D0F3B4E9700518E8E /* SPTableData.m */; };
@@ -220,7 +221,7 @@
isa = PBXContainerItemProxy;
containerPortal = 2A37F4A9FDCFA73011CA2CEA /* Project object */;
proxyType = 1;
- remoteGlobalIDString = 17B7B5611016012700F057DE /* MCPKit */;
+ remoteGlobalIDString = 17B7B5611016012700F057DE;
remoteInfo = MCPKit;
};
380F4EDF0FC0B51D00B0BFD7 /* PBXContainerItemProxy */ = {
@@ -471,6 +472,7 @@
387BBBA70FBCB6CB00B31746 /* SPTableRelations.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTableRelations.m; sourceTree = "<group>"; };
4DECC3320EC2A170008D359E /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Sparkle.framework; path = Frameworks/Sparkle.framework; sourceTree = "<group>"; };
4DECC3340EC2A170008D359E /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = Frameworks/Growl.framework; sourceTree = "<group>"; };
+ 581068B51015411B0068C6E2 /* link-arrow-highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "link-arrow-highlighted.png"; sourceTree = "<group>"; };
58186D200F4CB38900851FE9 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Interfaces/English.lproj/ConnectionErrorDialog.xib; sourceTree = "<group>"; };
5822C9B31000DB2400DCC3D6 /* SPConnectionController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPConnectionController.h; sourceTree = "<group>"; };
5822C9B41000DB2400DCC3D6 /* SPConnectionController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPConnectionController.m; sourceTree = "<group>"; };
@@ -494,7 +496,7 @@
58D2E227101222670063EF1D /* SPTextAndLinkCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTextAndLinkCell.m; sourceTree = "<group>"; };
58D2E228101222670063EF1D /* SPTextAndLinkCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTextAndLinkCell.h; sourceTree = "<group>"; };
58D2E22B101222870063EF1D /* link-arrow-clicked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "link-arrow-clicked.png"; sourceTree = "<group>"; };
- 58D2E22C101222870063EF1D /* link-arrow-highlighted.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "link-arrow-highlighted.png"; sourceTree = "<group>"; };
+ 58D2E22C101222870063EF1D /* link-arrow-highlighted-clicked.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "link-arrow-highlighted-clicked.png"; sourceTree = "<group>"; };
58D2E22D101222870063EF1D /* link-arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "link-arrow.png"; sourceTree = "<group>"; };
58FEF16B0F23D66600518E8E /* SPSQLParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPSQLParser.h; sourceTree = "<group>"; };
58FEF16C0F23D66600518E8E /* SPSQLParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPSQLParser.m; sourceTree = "<group>"; };
@@ -967,8 +969,8 @@
5841423E0F97E11000A34B47 /* NoodleLineNumberView.m */,
BC1847E80FE6EC8400094BFB /* SPEditSheetTextView.h */,
BC1847E90FE6EC8400094BFB /* SPEditSheetTextView.m */,
- 58D2E227101222670063EF1D /* SPTextAndLinkCell.m */,
58D2E228101222670063EF1D /* SPTextAndLinkCell.h */,
+ 58D2E227101222670063EF1D /* SPTextAndLinkCell.m */,
);
name = GUI;
sourceTree = "<group>";
@@ -1018,7 +1020,8 @@
17E6419F0EF02036001BC333 /* hideconsole.tiff */,
58D2E22D101222870063EF1D /* link-arrow.png */,
58D2E22B101222870063EF1D /* link-arrow-clicked.png */,
- 58D2E22C101222870063EF1D /* link-arrow-highlighted.png */,
+ 581068B51015411B0068C6E2 /* link-arrow-highlighted.png */,
+ 58D2E22C101222870063EF1D /* link-arrow-highlighted-clicked.png */,
17E641A20EF02036001BC333 /* logo-48.png */,
17E641AE0EF02036001BC333 /* selectall.tiff */,
17E641AF0EF02036001BC333 /* selectnone.tiff */,
@@ -1440,9 +1443,10 @@
BC1E55C4100DC92200AAE9F0 /* table-view-small-square.tiff in Resources */,
BCA6F631100FA7D700E80253 /* FieldEditorSheet.xib in Resources */,
58D2E22E101222870063EF1D /* link-arrow-clicked.png in Resources */,
- 58D2E22F101222870063EF1D /* link-arrow-highlighted.png in Resources */,
+ 58D2E22F101222870063EF1D /* link-arrow-highlighted-clicked.png in Resources */,
58D2E230101222870063EF1D /* link-arrow.png in Resources */,
BC688D811012462600D35128 /* borderlessbackground.png in Resources */,
+ 581068B61015411B0068C6E2 /* link-arrow-highlighted.png in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};