From 80b7627b5cc4f9ed5bfd1e03e367d420b5a1428b Mon Sep 17 00:00:00 2001 From: Eric Petit Date: Fri, 20 Jan 2006 01:51:07 +0000 Subject: [PATCH] This adds badging --- macosx/Badger.h | 31 +++ macosx/Badger.m | 190 ++++++++++++++++++ macosx/Controller.h | 4 +- macosx/Controller.m | 25 ++- macosx/Images/Badge.png | Bin 0 -> 1227 bytes macosx/Transmission.xcodeproj/project.pbxproj | 10 + 6 files changed, 256 insertions(+), 4 deletions(-) create mode 100644 macosx/Badger.h create mode 100644 macosx/Badger.m create mode 100644 macosx/Images/Badge.png diff --git a/macosx/Badger.h b/macosx/Badger.h new file mode 100644 index 000000000..d06d9b2f1 --- /dev/null +++ b/macosx/Badger.h @@ -0,0 +1,31 @@ +// +// Badger.h +// Transmission +// +// Created by Mitchell Livingston on 12/21/05. +// + +#ifndef BADGER_H +#define BADGER_H + +#import + +@interface Badger : NSObject { + + NSImage * fBadge, * fDockIcon, * fBadgedDockIcon; + + NSDictionary * fBadgeAttributes, * fStringAttributes; + + NSColor * fUploadingColor, * fDownloadingColor; + + int fCompleted; +} + +- (void) updateBadgeWithCompleted: (int) completed + uploadRate: (NSString *) uploadRate + downloadRate: (NSString *) downloadRate; +- (void) clearBadge; + +@end + +#endif diff --git a/macosx/Badger.m b/macosx/Badger.m new file mode 100644 index 000000000..14926def3 --- /dev/null +++ b/macosx/Badger.m @@ -0,0 +1,190 @@ +// +// Badger.m +// Transmission +// +// Created by Mitchell Livingston on 12/21/05. +// + +#import "Badger.h" + +@interface Badger (Private) + +- (NSImage *) badgeWithNum: (int) num; + +@end + +@implementation Badger + +- (id) init +{ + if ((self = [super init])) + { + fBadge = [NSImage imageNamed: @"Badge"]; + fDockIcon = [[NSApp applicationIconImage] copy]; + fBadgedDockIcon = [fDockIcon copy]; + + fBadgeAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: + [NSColor whiteColor], NSForegroundColorAttributeName, + [NSFont fontWithName: @"Helvetica-Bold" size: 24], NSFontAttributeName, + nil] retain]; + + fStringAttributes = [[NSDictionary dictionaryWithObjectsAndKeys: + [NSColor whiteColor], NSForegroundColorAttributeName, + [NSFont fontWithName: @"Helvetica-Bold" size: 20], NSFontAttributeName, + nil] retain]; + + fUploadingColor = [[[NSColor greenColor] colorWithAlphaComponent: 0.65] retain]; + fDownloadingColor = [[[NSColor blueColor] colorWithAlphaComponent: 0.65] retain]; + + fCompleted = 0; + } + + return self; +} + +- (void) dealloc +{ + [fDockIcon release]; + [fBadgedDockIcon release]; + + [fBadgeAttributes release]; + [fStringAttributes release]; + + [fUploadingColor release]; + [fDownloadingColor release]; + + [super dealloc]; +} + +- (void) updateBadgeWithCompleted: (int) completed + uploadRate: (NSString *) uploadRate + downloadRate: (NSString *) downloadRate +{ + NSImage * dockIcon; + NSSize iconSize = [fDockIcon size]; + + //set seeding and downloading badges if there was a change + if (completed != fCompleted) + { + fCompleted = completed; + + dockIcon = [fDockIcon copy]; + [dockIcon lockFocus]; + + //set completed badge to top right + if (completed > 0) + { + NSSize badgeSize = [fBadge size]; + [[self badgeWithNum: completed] + compositeToPoint: NSMakePoint(iconSize.width - badgeSize.width, + iconSize.height - badgeSize.height) + operation: NSCompositeSourceOver]; + } + + [dockIcon unlockFocus]; + + [fBadgedDockIcon release]; + fBadgedDockIcon = [dockIcon copy]; + } + else + dockIcon = [fBadgedDockIcon copy]; + + if (uploadRate || downloadRate) + { + //upload rate at bottom + float mainY = 5, + mainHeight = 25; + NSRect shapeRect = NSMakeRect(12.5, mainY, iconSize.width - 25, mainHeight); + + NSRect leftRect, rightRect; + leftRect.origin.x = 0; + leftRect.origin.y = mainY; + leftRect.size.width = shapeRect.origin.x * 2.0; + leftRect.size.height = mainHeight; + + rightRect = leftRect; + rightRect.origin.x = iconSize.width - rightRect.size.width; + + NSRect textRect; + textRect.origin.y = mainY; + textRect.size.height = mainHeight; + + [dockIcon lockFocus]; + + if (uploadRate) + { + float width = [uploadRate sizeWithAttributes: fStringAttributes].width; + textRect.origin.x = (iconSize.width - width) * 0.5; + textRect.size.width = width; + + NSBezierPath * uploadOval = [NSBezierPath bezierPathWithRect: shapeRect]; + [uploadOval appendBezierPathWithOvalInRect: leftRect]; + [uploadOval appendBezierPathWithOvalInRect: rightRect]; + + [fUploadingColor set]; + [uploadOval fill]; + [uploadRate drawInRect: textRect withAttributes: fStringAttributes]; + + //shift up for download rate if there is an upload rate + float heightDiff = 27; + shapeRect.origin.y += heightDiff; + leftRect.origin.y += heightDiff; + rightRect.origin.y += heightDiff; + textRect.origin.y += heightDiff; + } + + //download rate above upload rate + if (downloadRate) + { + float width = [downloadRate sizeWithAttributes: fStringAttributes].width; + textRect.origin.x = (iconSize.width - width) * 0.5; + textRect.size.width = width; + + NSBezierPath * downloadOval = [NSBezierPath bezierPathWithRect: shapeRect]; + [downloadOval appendBezierPathWithOvalInRect: leftRect]; + [downloadOval appendBezierPathWithOvalInRect: rightRect]; + + [fDownloadingColor set]; + [downloadOval fill]; + [downloadRate drawInRect: textRect withAttributes: fStringAttributes]; + } + + [dockIcon unlockFocus]; + } + + [NSApp setApplicationIconImage: dockIcon]; + [dockIcon release]; +} + +- (void) clearBadge +{ + [fBadgedDockIcon release]; + fBadgedDockIcon = [fDockIcon copy]; + + [NSApp setApplicationIconImage: fDockIcon]; +} + +@end + +@implementation Badger (Private) + +- (NSImage *) badgeWithNum: (int) num +{ + NSImage * badge = [[fBadge copy] autorelease]; + NSString * numString = [NSString stringWithFormat: @"%d", num]; + + //number is in center of image + NSRect badgeRect; + NSSize numSize = [numString sizeWithAttributes: fBadgeAttributes]; + badgeRect.size = [badge size]; + badgeRect.origin.x = (badgeRect.size.width - numSize.width) * 0.5; + badgeRect.origin.y = badgeRect.size.height * 0.5 - numSize.height * 1.2; + + [badge lockFocus]; + [numString drawInRect: badgeRect withAttributes: fBadgeAttributes]; + [badge unlockFocus]; + + return badge; +} + +@end diff --git a/macosx/Controller.h b/macosx/Controller.h index dcd56a30c..3a153e8e4 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -26,13 +26,14 @@ #import #import #import "PrefsController.h" +#import "Badger.h" @class TorrentTableView; @interface Controller : NSObject { tr_handle_t * fHandle; - int fCount; + int fCount, fCompleted; tr_stat_t * fStat; int fResumeOnWake[TR_MAX_TORRENT_COUNT]; @@ -74,6 +75,7 @@ NSUserDefaults * fDefaults; BOOL fHasGrowl; + Badger * fBadger; } - (void) advancedChanged: (id) sender; diff --git a/macosx/Controller.m b/macosx/Controller.m index c4231ac00..b152a0991 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -133,6 +133,10 @@ static void sleepCallBack( void * controller, io_service_t y, || [manager fileExistsAtPath: [[NSString stringWithFormat: @"~%@", GROWL_PATH] stringByExpandingTildeInPath]]; [self growlRegister: self]; + + //initialize badging + fBadger = [[Badger alloc] init]; + fCompleted = 0; //update the interface every 500 ms fCount = 0; @@ -143,6 +147,12 @@ static void sleepCallBack( void * controller, io_service_t y, forMode: NSEventTrackingRunLoopMode]; } +- (void) windowDidBecomeKey: (NSNotification *) n +{ + /* Reset the number of recently completed downloads */ + fCompleted = 0; +} + - (void) windowDidResize: (NSNotification *) n { [fTableView sizeToFit]; @@ -557,8 +567,10 @@ static void sleepCallBack( void * controller, io_service_t y, //Update the global DL/UL rates tr_torrentRates( fHandle, &dl, &ul ); - [fTotalDLField setStringValue: [NSString stringForSpeed: dl]]; - [fTotalULField setStringValue: [NSString stringForSpeed: ul]]; + NSString * downloadRate = [NSString stringForSpeed: dl]; + NSString * uploadRate = [NSString stringForSpeed: ul]; + [fTotalDLField setStringValue: downloadRate]; + [fTotalULField setStringValue: uploadRate]; //Update DL/UL totals in the Info panel row = [fTableView selectedRow]; @@ -575,11 +587,18 @@ static void sleepCallBack( void * controller, io_service_t y, { if( !tr_getFinished( fHandle, i ) ) continue; - + + fCompleted++; [self notifyGrowl: [NSString stringWithUTF8String: fStat[i].info.name]]; tr_setFinished( fHandle, i, 0 ); } + + //badge dock + NSUserDefaults * defaults = [NSUserDefaults standardUserDefaults]; + [fBadger updateBadgeWithCompleted: [defaults boolForKey: @"BadgeCompleted"] ? fCompleted : 0 + uploadRate: ul >= 0.1 && [defaults boolForKey: @"BadgeUploadRate"] ? uploadRate : nil + downloadRate: dl >= 0.1 && [defaults boolForKey: @"BadgeDownloadRate"] ? downloadRate : nil]; } - (int) numberOfRowsInTableView: (NSTableView *) t diff --git a/macosx/Images/Badge.png b/macosx/Images/Badge.png new file mode 100644 index 0000000000000000000000000000000000000000..03ead6e84cde66141864614c16fa4b8107e65588 GIT binary patch literal 1227 zcmV;+1T_1JP)QfZk|=LO=8QRw+RNH=j=MRY zqn=~1b-jGE_g>%r)>;3(F5mx~DwUURsq2nPE>>O1m;WD<_TCB0NCv{A+zfZI1Qs$q zU+)Q?gB47M7x^5%{)DrjIZ+`$xB#6%d+ zAQ%_V@8Q)Gu`6>3Rh6LA4Q}LISi??O#WEPh1o(lUUDfi3d&-bznxTW;aF9P? z1Y<)b4f;`%IfS~(a@BBMAh02HwuYx3VGR5g%EyaHTK-904~|%>k8ug_#G?T)g2S+m zKjQwO{}`VoDHua9FdxP<4ccgf{!woZSJ<$`(|e=N)zJ%9vJj>+^H}pTBVEN%4J>8@ zj14fF0-3*0kzvUfa89hdhXb&P_3@}WrFzuO%t&VpT}p3wg$2-uksx zv_(Q~VF&DE4NQs{Z)P7EM5r@{w$Tdn_z{-zFu6*et{0V(^cRo>NU!)pdPFxqhnJz5 z{rURYMdl_M4wY($dMvrg4EtX5(hMxBwOeThnDZE`yYcOrg5>EQ?@ij(eygg9vqY z3Qq?6GK-g>j=q#XhDt@G(ES8~j>vY4c^u{i$B{XNI7-jC~A*upiif=%SI-YTAgWqe1D z?@Rtq;nQGeCUY&!W@#AG0ar&@9pWqaHph&Xavq#Lgi89=DM=Dj-x%9r7{g&A_raW~ z8#ANhs0!!J56)sX55UUM+sejxUs7L^o#=6Gmd_w`45^E;XN;}Thx7B5_VH`{nRNHb pp