summaryrefslogtreecommitdiff
path: root/frontends/cocoa/URLFieldCell.m
diff options
context:
space:
mode:
Diffstat (limited to 'frontends/cocoa/URLFieldCell.m')
-rw-r--r--frontends/cocoa/URLFieldCell.m254
1 files changed, 254 insertions, 0 deletions
diff --git a/frontends/cocoa/URLFieldCell.m b/frontends/cocoa/URLFieldCell.m
new file mode 100644
index 000000000..54b240d02
--- /dev/null
+++ b/frontends/cocoa/URLFieldCell.m
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2011 Sven Weidauer <sven.weidauer@gmail.com>
+ *
+ * This file is part of NetSurf, http://www.netsurf-browser.org/
+ *
+ * NetSurf is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * NetSurf is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#import "cocoa/URLFieldCell.h"
+
+#import "utils/nsurl.h"
+#import "netsurf/url_db.h"
+
+@interface URLFieldCell () <
+ NSPasteboardWriting,
+ NSDraggingSource
+>
+
+@property (nonatomic) NSButtonCell *refreshCell;
+
+- (NSRect)buttonFrame:(NSRect)cellFrame;
+- (NSRect)urlFrame:(NSRect)cellFrame;
+- (NSRect)iconFrame:(NSRect)cellFrame;
+
+@end
+
+@implementation URLFieldCell
+
+@synthesize refreshCell = _refreshCell;
+
+- (void)setFavicon:(NSImage *)newIcon
+{
+ if (_favicon != newIcon) {
+ _favicon = newIcon;
+ [self.controlView setNeedsDisplay:YES];
+ }
+}
+
+#define BUTTON_SIZE 32
+#define PADDING 2
+
+- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
+{
+ [self.favicon drawInRect:[self iconFrame:cellFrame]
+ fromRect:NSZeroRect
+ operation:NSCompositingOperationSourceOver
+ fraction:1.0];
+
+ [super drawInteriorWithFrame:[self urlFrame:cellFrame] inView:controlView];
+
+ [[self refreshCell] drawInteriorWithFrame:[self buttonFrame:cellFrame]
+ inView:controlView];
+}
+
+- (void)selectWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj
+ delegate:(id)anObject
+ start:(NSInteger)selStart
+ length:(NSInteger)selLength
+{
+ const NSRect textFrame = [self urlFrame:aRect];
+ [super selectWithFrame:textFrame
+ inView:controlView
+ editor:textObj
+ delegate:anObject
+ start:selStart
+ length:selLength];
+}
+
+- (void)editWithFrame:(NSRect)aRect inView:(NSView *)controlView editor:(NSText *)textObj
+ delegate:(id)anObject
+ event:(NSEvent *)theEvent
+{
+ const NSRect textFrame = [self urlFrame:aRect];
+ [super editWithFrame:textFrame
+ inView:controlView
+ editor:textObj
+ delegate:anObject
+ event:theEvent];
+}
+
+- (void)startDragURLAt:(NSPoint)point inView:(NSView *)view
+{
+ NSString *url = [self stringValue];
+ NSString *title = url;
+ nsurl *nsurl;
+
+ if (nsurl_create([url UTF8String], &nsurl) != NSERROR_OK)
+ return;
+
+ const struct url_data *data = urldb_get_url_data(nsurl);
+
+ nsurl_unref(nsurl);
+
+ if (data && data->title)
+ title = [NSString stringWithUTF8String:data->title];
+
+ NSPasteboard *pb = [NSPasteboard pasteboardWithName:NSDragPboard];
+ [pb declareTypes:[NSArray arrayWithObjects:NSStringPboardType, NSURLPboardType,
+ @"public.url", @"public.url-name", nil]
+ owner:nil];
+ [pb setString:url forType:NSStringPboardType];
+ [pb setString:url forType:@"public.url"];
+ [pb setString:title forType:@"public.url-name"];
+ [[NSURL URLWithString:url] writeToPasteboard:pb];
+
+ NSRect urlBounds = NSZeroRect;
+ urlBounds.size = [title sizeWithAttributes:nil];
+ urlBounds.size.width += urlBounds.size.height + 2;
+
+ NSImage *image = [[NSImage alloc] initWithSize:urlBounds.size];
+
+ [image lockFocus];
+ [self.favicon drawInRect:NSMakeRect(urlBounds.origin.x, urlBounds.origin.y, urlBounds.size.height, urlBounds.size.height)
+ fromRect:NSZeroRect
+ operation:NSCompositingOperationCopy
+ fraction:1.0];
+ urlBounds.origin.x += urlBounds.size.height + 2;
+ [title drawInRect:urlBounds withAttributes:nil];
+ [image unlockFocus];
+
+ point.x -= urlBounds.size.height / 2;
+ point.y += urlBounds.size.height / 2;
+
+ NSDraggingItem *item = [[NSDraggingItem alloc] initWithPasteboardWriter: self];
+ item.imageComponentsProvider = ^NSArray<NSDraggingImageComponent *> * _Nonnull{
+ NSDraggingImageComponent *component = [NSDraggingImageComponent draggingImageComponentWithKey: NSDraggingImageComponentIconKey];
+ component.contents = image;
+ return @[component];
+ };
+
+ [view beginDraggingSessionWithItems:@[item] event:NSApp.currentEvent source:self];
+}
+
+- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal
+{
+ return NSDragOperationCopy | NSDragOperationGeneric;
+}
+
+- (BOOL)trackMouse:(NSEvent *)theEvent inRect:(NSRect)cellFrame ofView:(NSView *)controlView untilMouseUp:(BOOL)flag
+{
+ const NSPoint point = [controlView convertPoint:[theEvent locationInWindow] fromView:nil];
+ const NSRect buttonRect = [self buttonFrame:cellFrame];
+ if (NSPointInRect(point, [self iconFrame:cellFrame])) {
+ [self startDragURLAt:point inView:controlView];
+ return NO;
+ } else if (NSPointInRect(point, buttonRect)) {
+ return [[self refreshCell] trackMouse:theEvent
+ inRect:buttonRect
+ ofView:controlView
+ untilMouseUp:flag];
+ } else {
+ cellFrame.size.width -= BUTTON_SIZE + PADDING;
+ return [super trackMouse:theEvent inRect:cellFrame ofView:controlView untilMouseUp:YES];
+ }
+}
+
+- (NSRect)buttonFrame:(NSRect)cellFrame
+{
+ NSRect buttonRect = cellFrame;
+ buttonRect.origin.x = NSMaxX(cellFrame) - BUTTON_SIZE;
+ buttonRect.size.width = BUTTON_SIZE;
+ return buttonRect;
+}
+
+- (NSRect)urlFrame:(NSRect)cellFrame
+{
+ NSRect textFrame = cellFrame;
+ textFrame.origin.x += cellFrame.size.height;
+ textFrame.size.width -= cellFrame.size.height + BUTTON_SIZE + PADDING;
+ return textFrame;
+}
+
+- (NSRect)iconFrame:(NSRect)cellFrame
+{
+ NSRect iconFrame = {
+ .origin = {
+ .x = cellFrame.origin.x + PADDING,
+ .y = cellFrame.origin.y,
+ },
+ .size = NSMakeSize(NSHeight(cellFrame), NSHeight(cellFrame))
+ };
+ return NSInsetRect(iconFrame, 2 * PADDING, 2 * PADDING);
+}
+
+- (NSButtonCell *)refreshCell
+{
+ if (nil == _refreshCell) {
+ _refreshCell = [[NSButtonCell alloc] initImageCell:[NSImage imageNamed:NSImageNameRefreshTemplate]];
+ _refreshCell.buttonType = NSMomentaryPushInButton;
+ _refreshCell.bordered = NO;
+ }
+
+ return _refreshCell;
+}
+
+- (void)setRefreshTarget:(id)newTarget
+{
+ self.refreshCell.target = newTarget;
+}
+
+- (id)refreshTarget
+{
+ return self.refreshCell.target;
+}
+
+- (void)setRefreshAction:(SEL)newAction
+{
+ self.refreshCell.action = newAction;
+}
+
+- (SEL)refreshAction
+{
+ return self.refreshCell.action;
+}
+
+- (nullable id) pasteboardPropertyListForType:(nonnull NSPasteboardType)type {
+ if ([type isEqualToString: NSPasteboardTypeString] || [type isEqualToString: @"public.url"]) {
+ return self.stringValue;
+ } else if ([type isEqualToString: @"public.url-name"]) {
+ nsurl *nsurl;
+
+ if (nsurl_create(self.stringValue.UTF8String, &nsurl) == NSERROR_OK) {
+
+ const struct url_data *data = urldb_get_url_data(nsurl);
+ nsurl_unref(nsurl);
+
+ if (data && data->title) {
+ return @(data->title);
+ }
+ }
+ }
+
+ return nil;
+}
+
+- (nonnull NSArray<NSPasteboardType> *) writableTypesForPasteboard:(nonnull NSPasteboard *)pasteboard {
+ return @[NSPasteboardTypeString, @"public.url", @"public.url-name"];
+}
+
+- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context {
+ return NSDragOperationCopy;
+}
+
+@end