diff options
Diffstat (limited to 'frontends/cocoa/URLFieldCell.m')
-rw-r--r-- | frontends/cocoa/URLFieldCell.m | 254 |
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 |