diff --git a/baRSS/AppHook.m b/baRSS/AppHook.m
index 2cd8cdf..7b7168c 100644
--- a/baRSS/AppHook.m
+++ b/baRSS/AppHook.m
@@ -24,6 +24,7 @@
#import "BarStatusItem.h"
#import "FeedDownload.h"
#import "Preferences.h"
+#import "DrawImage.h"
@interface AppHook()
@property (strong) NSWindowController *prefWindow;
@@ -45,6 +46,7 @@
}
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
+ RegisterImageViewNames();
// feed://https://feeds.feedburner.com/simpledesktops
[FeedDownload registerNetworkChangeNotification]; // will call update scheduler
}
diff --git a/baRSS/Core Data/Feed+Ext.m b/baRSS/Core Data/Feed+Ext.m
index 5577de3..be6ba67 100644
--- a/baRSS/Core Data/Feed+Ext.m
+++ b/baRSS/Core Data/Feed+Ext.m
@@ -228,7 +228,7 @@
} else if (self.icon.icon) {
img = [[NSImage alloc] initWithData:self.icon.icon];
} else {
- return [RSSIcon iconWithSize:16]; // TODO: setup imageNamed: for default rss icon?
+ img = [NSImage imageNamed:RSSImageDefaultRSSIcon];
}
[img setSize:NSMakeSize(16, 16)];
return img;
diff --git a/baRSS/Helper/DrawImage.h b/baRSS/Helper/DrawImage.h
index 75e9987..83351e1 100644
--- a/baRSS/Helper/DrawImage.h
+++ b/baRSS/Helper/DrawImage.h
@@ -29,67 +29,18 @@
+ (NSColor*)rssOrange;
@end
-// ---------------------------------------------------------------
-// |
-// | DrawImage
-// |
-// ---------------------------------------------------------------
-
-IB_DESIGNABLE
-@interface DrawImage : NSView
-@property (strong) IBInspectable NSColor *color;
-@property (assign) IBInspectable BOOL showBackground;
-/** percentage value between 0 - 100 */
-@property (assign, nonatomic) IBInspectable CGFloat roundness;
-@property (assign, nonatomic) IBInspectable CGFloat contentScale;
-@property (strong, readonly) NSImageView *imageView;
-
-- (NSImage*)drawnImage;
-@end
-
-// ---------------------------------------------------------------
-// |
-// | RSSIcon
-// |
-// ---------------------------------------------------------------
-
-IB_DESIGNABLE
-@interface RSSIcon : DrawImage
-@property (strong) IBInspectable NSColor *barsColor;
-@property (strong) IBInspectable NSColor *gradientColor;
-@property (assign) IBInspectable BOOL noConnection;
-
-+ (NSImage*)iconWithSize:(CGFloat)size;
-+ (NSImage*)systemBarIcon:(CGFloat)size tint:(NSColor*)color noConnection:(BOOL)conn;
-@end
-
-// ---------------------------------------------------------------
-// |
-// | SettingsIconGlobal
-// |
-// ---------------------------------------------------------------
-
-IB_DESIGNABLE
-@interface SettingsIconGlobal : DrawImage
-@end
-
-// ---------------------------------------------------------------
-// |
-// | SettingsIconGroup
-// |
-// ---------------------------------------------------------------
-
-IB_DESIGNABLE
-@interface SettingsIconGroup : DrawImage
-@end
-
-// ---------------------------------------------------------------
-// |
-// | DrawSeparator
-// |
-// ---------------------------------------------------------------
+/// Draw separator line in @c NSOutlineView
IB_DESIGNABLE
@interface DrawSeparator : NSView
@end
+
+static NSImageName const RSSImageSettingsGlobal = @"RSSImageSettingsGlobal";
+static NSImageName const RSSImageSettingsGroup = @"RSSImageSettingsGroup";
+static NSImageName const RSSImageSettingsFeed = @"RSSImageSettingsFeed";
+static NSImageName const RSSImageDefaultRSSIcon = @"RSSImageDefaultRSSIcon";
+static NSImageName const RSSImageMenuBarIconActive = @"RSSImageMenuBarIconActive";
+static NSImageName const RSSImageMenuBarIconPaused = @"RSSImageMenuBarIconPaused";
+
+void RegisterImageViewNames(void);
diff --git a/baRSS/Helper/DrawImage.m b/baRSS/Helper/DrawImage.m
index 4052092..b22b9c9 100644
--- a/baRSS/Helper/DrawImage.m
+++ b/baRSS/Helper/DrawImage.m
@@ -32,209 +32,169 @@
}
/// @return Orange color that is typically used for RSS
+ (NSColor*)rssOrange {
- return [NSColor colorWithCalibratedRed:0.984 green:0.639 blue:0.227 alpha:1.0];
+ return [NSColor colorWithCalibratedRed:251/255.0 green:163/255.0 blue:58/255.0 alpha:1.0];
}
@end
-// ################################################################
-// #
-// # DrawImage
-// #
-// ################################################################
-
-@implementation DrawImage
-@synthesize roundness = _roundness, contentScale = _contentScale;
-
--(id)init{self=[super init];if(self)[self initialize];return self;}
--(id)initWithFrame:(CGRect)f{self=[super initWithFrame:f];if(self)[self initialize];return self;}
--(id)initWithCoder:(NSCoder*)c{self=[super initWithCoder:c];if(self)[self initialize];return self;}
-
-//#if !TARGET_INTERFACE_BUILDER #endif
-/// Prepare view content to autoresize when rescaling
-- (void)initialize {
- _contentScale = 1.0;
- _imageView = [NSImageView imageViewWithImage:[self drawnImage]];
- [_imageView setFrameSize:self.frame.size];
- _imageView.autoresizingMask = NSViewWidthSizable | NSViewHeightSizable;
- [self addSubview:_imageView];
-}
-
-/**
- Designated initializer. Will add rounded corners and background color.
-
- @param w Square size of icon.
- @param s Scaling factor of the content image.
- */
-- (instancetype)initWithSize:(CGFloat)w scale:(CGFloat)s {
- self = [super initWithFrame:NSMakeRect(0, 0, w, w)];
- self.roundness = 40;
- self.contentScale = s;
- self.showBackground = YES;
- return self;
-}
-
-/**
- @return New image with drawn content. Will call @c drawImageInRect:
- */
-- (NSImage*)drawnImage {
- return [NSImage imageWithSize:self.frame.size flipped:NO drawingHandler:^BOOL(NSRect rect) {
- [self drawImageInRect:rect];
- return YES;
- }];
-}
-
-/// Set roundness factor for rounded corners (background). This setter ensures a percent value between 0 and 1.
-- (void)setRoundness:(CGFloat)r {
- _roundness = 0.5 * (r < 0 ? 0 : r > 100 ? 100 : r);
-}
-
-/// @return MIN( width, height )
-- (CGFloat)shorterSide {
- if (self.frame.size.width < self.frame.size.height)
- return self.frame.size.width;
- return self.frame.size.height;
-}
-
-/**
- Draw background image, rounded corners and scaled image content
- */
-- (void)drawImageInRect:(NSRect)r {
- const CGFloat s = [self shorterSide];
- CGContextRef c = [[NSGraphicsContext currentContext] CGContext];
-
- if (_showBackground) {
- CGMutablePathRef pth = CGPathCreateMutable();
- const CGFloat corner = s * (_roundness / 100.0);
- if (corner > 0) {
- CGPathAddRoundedRect(pth, NULL, r, corner, corner);
- } else {
- CGPathAddRect(pth, NULL, r);
- }
- CGContextSetFillColorWithColor(c, [_color CGColor]);
- CGContextAddPath(c, pth);
- CGPathRelease(pth);
- if ([self isMemberOfClass:[DrawImage class]])
- CGContextFillPath(c); // fill only if not a subclass
- }
- if (_contentScale != 1.0) {
- CGFloat offset = s * (1 - _contentScale) / 2;
- CGContextTranslateCTM(c, offset, offset);
- CGContextScaleCTM(c, _contentScale, _contentScale);
- }
+@implementation DrawSeparator
+- (void)drawRect:(NSRect)r {
+ NSColor *color = [NSColor darkGrayColor];
+ NSGradient *grdnt = [[NSGradient alloc] initWithStartingColor:color endingColor:[color colorWithAlphaComponent:0.0]];
+ NSRect separatorRect = NSMakeRect(1, NSMidY(self.frame) - 1, NSWidth(self.frame) - 2, 2);
+ NSBezierPath *rounded = [NSBezierPath bezierPathWithRoundedRect:separatorRect xRadius:1 yRadius:1];
+ [grdnt drawInBezierPath:rounded angle:0];
}
@end
-// ################################################################
-// #
-// # RSSIcon
-// #
-// ################################################################
+#pragma mark - Helper Methods
-@implementation RSSIcon // content scale 0.75 works fine
-/**
- @return Default RSS icon for feeds that are missing an icon. (Not used in system bar).
- */
-+ (NSImage*)iconWithSize:(CGFloat)s {
- RSSIcon *icon = [[RSSIcon alloc] initWithSize:s scale:0.7];
- icon.barsColor = [NSColor whiteColor];
- icon.gradientColor = [NSColor rssOrange];
- return [icon drawnImage];
+/// @return @c MIN(s.width,s.height)
+NS_INLINE const CGFloat ShorterSide(NSSize s) {
+ return (s.width < s.height ? s.width : s.height);
}
-/**
- Returns new @c NSImage with background (tinted or not) and connection error (if set).
+/// Perform @c CGAffineTransform with custom rotation point
+// CGAffineTransform RotateAroundPoint(CGAffineTransform at, CGFloat angle, CGFloat x, CGFloat y) {
+// at = CGAffineTransformTranslate(at, x, y);
+// at = CGAffineTransformRotate(at, angle);
+// return CGAffineTransformTranslate(at, -x, -y);
+//}
- @param s Square image size
- @param color Tint color of icon. Either untintend (white) or highlighted (rss orange).
- @param conn If @c YES show small pause icon in right upper corner.
- */
-+ (NSImage*)systemBarIcon:(CGFloat)s tint:(NSColor*)color noConnection:(BOOL)conn {
- RSSIcon *icon = [[RSSIcon alloc] initWithSize:s scale:0.7];
- icon.color = (color ? color : [NSColor blackColor]);
- icon.noConnection = conn;
-// icon.showBackground = !conn;
-// icon.contentScale = (conn ? 0.9 : 0.7);
- return [icon drawnImage];
+
+#pragma mark - CGPath Component Generators
+
+
+/// Add circle with @c radius
+NS_INLINE void PathAddCircle(CGMutablePathRef path, CGFloat radius) {
+ CGPathAddArc(path, NULL, radius, radius, radius, 0, M_PI * 2, YES);
}
+/// Add a single RSS icon radio wave
+NS_INLINE void PathAddRSSArc(CGMutablePathRef path, CGFloat radius, CGFloat thickness) {
+ CGPathMoveToPoint(path, NULL, 0, radius + thickness);
+ CGPathAddArc(path, NULL, 0, 0, radius + thickness, M_PI_2, 0, YES);
+ CGPathAddLineToPoint(path, NULL, radius, 0);
+ CGPathAddArc(path, NULL, 0, 0, radius, 0, M_PI_2, NO);
+ CGPathCloseSubpath(path);
+}
+
+/// Add two vertical bars representing a pause icon
+NS_INLINE void PathAddPauseIcon(CGMutablePathRef path, CGAffineTransform at, CGFloat size, CGFloat thickness) {
+ const CGFloat off = (size - 2 * thickness) / 4;
+ CGPathAddRect(path, &at, CGRectMake(off, 0, thickness, size));
+ CGPathAddRect(path, &at, CGRectMake(size/2 + off, 0, thickness, size));
+}
+
+/// Add X icon by applying a rotational affine transform and drawing a plus sign
+// void PathAddXIcon(CGMutablePathRef path, CGAffineTransform at, CGFloat size, CGFloat thickness) {
+// at = RotateAroundPoint(at, M_PI_4, size/2, size/2);
+// const CGFloat p = size * 0.5 - thickness / 2;
+// CGPathAddRect(path, &at, CGRectMake(0, p, size, thickness));
+// CGPathAddRect(path, &at, CGRectMake(p, 0, thickness, p));
+// CGPathAddRect(path, &at, CGRectMake(p, p + thickness, thickness, p));
+//}
+
+
+#pragma mark - Full Icon Path Generators
+
+
+/// Create @c CGPath for global icon; a menu bar and an open menu below
+NS_INLINE void AddGlobalIconPath(CGContextRef c, CGFloat size) {
+ CGMutablePathRef menu = CGPathCreateMutable();
+ CGPathAddRect(menu, NULL, CGRectMake(0, 0.8 * size, size, 0.2 * size));
+ CGPathAddRect(menu, NULL, CGRectMake(0.3 * size, 0, 0.55 * size, 0.75 * size));
+ CGPathAddRect(menu, NULL, CGRectMake(0.35 * size, 0.05 * size, 0.45 * size, 0.75 * size));
+
+ CGFloat entryHeight = 0.1 * size; // 0.075
+ for (int i = 0; i < 3; i++) { // 4
+ //CGPathAddRect(menu, NULL, CGRectMake(0.37 * size, (2 * i + 1) * entryHeight, 0.42 * size, entryHeight)); // uncomment path above
+ CGPathAddRect(menu, NULL, CGRectMake(0.35 * size, (2 * i + 1.5) * entryHeight, 0.4 * size, entryHeight * 0.8));
+ }
+ CGContextAddPath(c, menu);
+ CGPathRelease(menu);
+}
+
+/// Create @c CGPath for group icon; a folder symbol
+NS_INLINE void AddGroupIconPath(CGContextRef c, CGFloat size, BOOL showBackground) {
+ const CGFloat r1 = size * 0.05; // corners
+ const CGFloat r2 = size * 0.08; // upper part, name tag
+ const CGFloat r3 = size * 0.15; // lower part, corners inside
+ const CGFloat posTop = 0.85 * size;
+ const CGFloat posMiddle = 0.6 * size - r3;
+ const CGFloat posBottom = 0.15 * size + r1;
+ const CGFloat posNameTag = 0.3 * size;
+
+ CGMutablePathRef upper = CGPathCreateMutable();
+ CGPathMoveToPoint(upper, NULL, 0, 0.5 * size);
+ CGPathAddLineToPoint(upper, NULL, 0, posTop - r1);
+ CGPathAddArc(upper, NULL, r1, posTop - r1, r1, M_PI, M_PI_2, YES);
+ CGPathAddArc(upper, NULL, posNameTag, posTop - r2, r2, M_PI_2, M_PI_4, YES);
+ CGPathAddArc(upper, NULL, posNameTag + 1.85 * r2, posTop, r2, M_PI + M_PI_4, -M_PI_2, NO);
+ CGPathAddArc(upper, NULL, size - r1, posTop - r1 - r2, r1, M_PI_2, 0, YES);
+ CGPathAddArc(upper, NULL, size - r1, posBottom, r1, 0, -M_PI_2, YES);
+ CGPathAddArc(upper, NULL, r1, posBottom, r1, -M_PI_2, M_PI, YES);
+ CGPathCloseSubpath(upper);
+
+ CGMutablePathRef lower = CGPathCreateMutable();
+ CGPathAddArc(lower, NULL, r3, posMiddle, r3, M_PI, M_PI_2, YES);
+ CGPathAddArc(lower, NULL, size - r3, posMiddle, r3, M_PI_2, 0, YES);
+ CGPathAddArc(lower, NULL, size - r1, posBottom, r1, 0, -M_PI_2, YES);
+ CGPathAddArc(lower, NULL, r1, posBottom, r1, -M_PI_2, M_PI, YES);
+ CGPathCloseSubpath(lower);
+
+ CGContextAddPath(c, upper);
+ if (showBackground)
+ CGContextEOFillPath(c);
+ CGContextAddPath(c, lower);
+ CGPathRelease(upper);
+ CGPathRelease(lower);
+}
+
+
/**
- Draw two rss bars (or paused icon) and tint color or gradient color.
- */
-- (void)drawImageInRect:(NSRect)r {
- [super drawImageInRect:r];
-
- const CGFloat s = [self shorterSide];
- CGContextRef c = [[NSGraphicsContext currentContext] CGContext];
- CGContextSetFillColorWithColor(c, [self.color CGColor]);
-
+NS_INLINE Create @c CGPath for RSS icon; a circle in the lower left bottom and two radio waves going outwards.
+NS_INLINE @param connection If @c NO, draw only one radio wave and a pause icon in the upper right
+NS_INLINE */
+NS_INLINE void AddRSSIconPath(CGContextRef c, CGFloat size, BOOL connection) {
CGMutablePathRef bars = CGPathCreateMutable(); // the rss bars
- // circle
- const CGFloat r1 = s * 0.125; // circle radius
- CGPathAddArc(bars, NULL, r1, r1, r1, 0, M_PI * 2, YES);
- // 1st bar
- CGPathMoveToPoint(bars, NULL, 0, s * 0.65);
- CGPathAddArc(bars, NULL, 0, 0, s * 0.65, M_PI_2, 0, YES);
- CGPathAddLineToPoint(bars, NULL, s * 0.45, 0);
- CGPathAddArc(bars, NULL, 0, 0, s * 0.45, 0, M_PI_2, NO);
- CGPathCloseSubpath(bars);
- // 2nd bar
- if (_noConnection) {
- CGAffineTransform at = CGAffineTransformMake(0.5, 0, 0, 0.5, s * 0.5, s * 0.5);
- // X icon
-// CGPathMoveToPoint(bars, &at, 0, s * 0.2);
-// CGPathAddLineToPoint(bars, &at, s * 0.3, s * 0.5);
-// CGPathAddLineToPoint(bars, &at, 0, s * 0.8);
-// CGPathAddLineToPoint(bars, &at, s * 0.2, s);
-// CGPathAddLineToPoint(bars, &at, s * 0.5, s * 0.7);
-// CGPathAddLineToPoint(bars, &at, s * 0.8, s);
-// CGPathAddLineToPoint(bars, &at, s, s * 0.8);
-// CGPathAddLineToPoint(bars, &at, s * 0.7, s * 0.5);
-// CGPathAddLineToPoint(bars, &at, s, s * 0.2);
-// CGPathAddLineToPoint(bars, &at, s * 0.8, 0);
-// CGPathAddLineToPoint(bars, &at, s * 0.5, s * 0.3);
-// CGPathAddLineToPoint(bars, &at, s * 0.2, 0);
-// CGPathCloseSubpath(bars);
- // Pause icon
-// CGPathMoveToPoint(bars, &at, s * 0.2, s * 0.2);
- CGPathAddRect(bars, &at, CGRectMake(s*0.1, 0, s*0.3, s));
- CGPathAddRect(bars, &at, CGRectMake(s*0.6, 0, s*0.3, s));
+ PathAddCircle(bars, size * 0.125);
+ PathAddRSSArc(bars, size * 0.45, size * 0.2);
+ if (connection) {
+ PathAddRSSArc(bars, size * 0.8, size * 0.2);
} else {
- CGPathMoveToPoint(bars, NULL, 0, s);
- CGPathAddArc(bars, NULL, 0, 0, s, M_PI_2, 0, YES);
- CGPathAddLineToPoint(bars, NULL, s * 0.8, 0);
- CGPathAddArc(bars, NULL, 0, 0, s * 0.8, 0, M_PI_2, NO);
- CGPathCloseSubpath(bars);
+ CGAffineTransform at = CGAffineTransformMake(0.5, 0, 0, 0.5, size/2, size/2);
+ PathAddPauseIcon(bars, at, size, size * 0.3);
+ //PathAddXIcon(bars, at, size, size * 0.3);
}
-
CGContextAddPath(c, bars);
-
- if (_gradientColor) {
- CGContextSaveGState(c);
- CGContextClip(c);
- [self drawGradient:c side:s / self.contentScale];
- CGContextRestoreGState(c);
- } else {
- CGContextEOFillPath(c);
- }
-
- if (_barsColor) {
- CGContextSetFillColorWithColor(c, [_barsColor CGColor]);
- CGContextAddPath(c, bars);
- CGContextEOFillPath(c);
- }
CGPathRelease(bars);
}
-/**
- Apply gradient to current context clipping.
- */
-- (void)drawGradient:(CGContextRef)c side:(CGFloat)w {
+
+#pragma mark - Icon Background Generators
+
+
+/// Create @c CGPath with rounded corners (optional). @param roundness Value between @c 0.0 and @c 1.0
+NS_INLINE void AddRoundedBackgroundPath(CGContextRef c, CGRect r, CGFloat roundness) {
+ const CGFloat corner = ShorterSide(r.size) * (roundness / 2.0);
+ if (corner > 0) {
+ CGMutablePathRef pth = CGPathCreateMutable();
+ CGPathAddRoundedRect(pth, NULL, r, corner, corner);
+ CGContextAddPath(c, pth);
+ CGPathRelease(pth);
+ } else {
+ CGContextAddRect(c, r);
+ }
+}
+
+/// Insert and draw linear gradient with @c color saturation @c ±0.3
+NS_INLINE void DrawGradient(CGContextRef c, CGFloat size, NSColor *color) {
CGFloat h = 0, s = 1, b = 1, a = 1;
@try {
- NSColor *rgbColor = [_gradientColor colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
+ NSColor *rgbColor = [color colorUsingColorSpace:[NSColorSpace deviceRGBColorSpace]];
[rgbColor getHue:&h saturation:&s brightness:&b alpha:&a];
} @catch (NSException *e) {}
@@ -249,128 +209,100 @@
CFArrayRef colors = CFArrayCreate(NULL, cgColors, 3, NULL);
CGGradientRef gradient = CGGradientCreateWithColors(NULL, colors, NULL);
- CGContextDrawLinearGradient(c, gradient, CGPointMake(0, w), CGPointMake(w, 0), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
+ CGContextDrawLinearGradient(c, gradient, CGPointMake(0, size), CGPointMake(size, 0), kCGGradientDrawsBeforeStartLocation | kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient);
CFRelease(colors);
}
-@end
-// ################################################################
-// #
-// # SettingsIconGlobal
-// #
-// ################################################################
+#pragma mark - CGContext Drawing & Manipulation
-@implementation SettingsIconGlobal // content scale 0.7 works fine
-/**
- Draw icon for preferences; showing the status bar and an open menu. (single colors contour)
- */
-- (void)drawImageInRect:(NSRect)r {
- [super drawImageInRect:r]; // add path of rounded rect
-
- const CGFloat w = r.size.width;
- const CGFloat h = r.size.height;
-
- CGMutablePathRef menu = CGPathCreateMutable();
- CGPathAddRect(menu, NULL, CGRectMake(0, 0.8 * h, w, 0.2 * h));
- CGPathAddRect(menu, NULL, CGRectMake(0.3 * w, 0, 0.55 * w, 0.75 * h));
- CGPathAddRect(menu, NULL, CGRectMake(0.35 * w, 0.05 * h, 0.45 * w, 0.75 * h));
-
- CGFloat entryHeight = 0.1 * h; // 0.075
- for (int i = 0; i < 3; i++) { // 4
- //CGPathAddRect(menu, NULL, CGRectMake(0.37 * w, (2 * i + 1) * entryHeight, 0.42 * w, entryHeight)); // uncomment path above
- CGPathAddRect(menu, NULL, CGRectMake(0.35 * w, (2 * i + 1.5) * entryHeight, 0.4 * w, entryHeight * 0.8));
+
+/// Scale and translate context to the center with respect to the new scale. If @c width @c != @c length align top left.
+NS_INLINE void SetContentScale(CGContextRef c, CGSize size, CGFloat scale) {
+ const CGFloat s = ShorterSide(size);
+ CGFloat offset = s * (1 - scale) / 2;
+ CGContextTranslateCTM(c, offset, size.height - s + offset); // top left alignment
+ CGContextScaleCTM(c, scale, scale);
+}
+
+/// Helper method; set drawing color, add rounded background and prepare content scale
+NS_INLINE void DrawRoundedFrame(CGContextRef c, CGRect r, CGColorRef color, BOOL background, CGFloat corner, CGFloat defaultScale, CGFloat scaling) {
+ CGContextSetFillColorWithColor(c, color);
+ CGContextSetStrokeColorWithColor(c, color);
+ CGFloat contentScale = defaultScale;
+ if (background) {
+ AddRoundedBackgroundPath(c, r, corner);
+ if (scaling != 0.0)
+ contentScale *= scaling;
}
-
- CGContextRef c = [[NSGraphicsContext currentContext] CGContext];
- CGContextSetFillColorWithColor(c, [self.color CGColor]);
-
- CGContextAddPath(c, menu);
+ SetContentScale(c, r.size, contentScale);
+}
+
+
+#pragma mark - Easy Icon Drawing Methods
+
+
+/// Draw global icon (menu bar)
+NS_INLINE void DrawGlobalIcon(CGRect r, CGColorRef color, BOOL background) {
+ CGContextRef c = NSGraphicsContext.currentContext.CGContext;
+ DrawRoundedFrame(c, r, color, background, 0.4, 1.0, 0.7);
+ AddGlobalIconPath(c, ShorterSide(r.size));
CGContextEOFillPath(c);
- CGPathRelease(menu);
}
-@end
-
-// ################################################################
-// #
-// # SettingsIconGroup
-// #
-// ################################################################
-
-@implementation SettingsIconGroup // content scale 0.8 works fine
-/**
- Draw icon for preferences; showing the mac typcial folder icon. (single colors contour)
- */
-- (void)drawImageInRect:(NSRect)r {
- [super drawImageInRect:r];
-
- const CGFloat w = r.size.width;
- const CGFloat h = r.size.height;
- const CGFloat s = (w < h ? w : h); // shorter side
- const CGFloat l = s * 0.04; // line width (half size)
- const CGFloat r1 = s * 0.05; // corners
- const CGFloat r2 = s * 0.08; // upper part, name tag
- const CGFloat r3 = s * 0.15; // lower part, corners inside
- const CGFloat posTop = 0.85 * h - l;
- const CGFloat posMiddle = 0.6 * h - l - r3;
- const CGFloat posBottom = 0.15 * h + l + r1;
- const CGFloat posNameTag = 0.3 * w - l;
-
- CGMutablePathRef upper = CGPathCreateMutable();
- CGPathMoveToPoint(upper, NULL, l, 0.5 * h);
- CGPathAddLineToPoint(upper, NULL, l, posTop - r1);
- CGPathAddArc(upper, NULL, l + r1, posTop - r1, r1, M_PI, M_PI_2, YES);
- CGPathAddArc(upper, NULL, posNameTag, posTop - r2, r2, M_PI_2, M_PI_4, YES);
- CGPathAddArc(upper, NULL, posNameTag + 2 * r2, posTop, r2, M_PI + M_PI_4, -M_PI_2, NO);
- CGPathAddArc(upper, NULL, w - l - r1, posTop - r1 - r2, r1, M_PI_2, 0, YES);
- CGPathAddArc(upper, NULL, w - l - r1, posBottom, r1, 0, -M_PI_2, YES);
- CGPathAddArc(upper, NULL, l + r1, posBottom, r1, -M_PI_2, M_PI, YES);
- CGPathCloseSubpath(upper);
-
- CGMutablePathRef lower = CGPathCreateMutable();
- CGPathMoveToPoint(lower, NULL, l, 0.5 * h);
- CGPathAddArc(lower, NULL, l + r3, posMiddle, r3, M_PI, M_PI_2, YES);
- CGPathAddArc(lower, NULL, w - l - r3, posMiddle, r3, M_PI_2, 0, YES);
- CGPathAddArc(lower, NULL, w - l - r1, posBottom, r1, 0, -M_PI_2, YES);
- CGPathAddArc(lower, NULL, l + r1, posBottom, r1, -M_PI_2, M_PI, YES);
- CGPathCloseSubpath(lower);
-
- CGContextRef c = [[NSGraphicsContext currentContext] CGContext];
- CGContextSetFillColorWithColor(c, [self.color CGColor]);
- CGContextSetStrokeColorWithColor(c, [self.color CGColor]);
- CGContextSetLineWidth(c, l * 2);
-
- CGContextAddPath(c, upper);
- CGContextAddPath(c, lower);
- if (self.showBackground) {
- CGContextAddPath(c, lower);
- CGContextEOFillPath(c);
- CGContextSetLineWidth(c, l); // thinner line
- CGContextAddPath(c, lower);
- }
+/// Draw group icon (folder)
+NS_INLINE void DrawGroupIcon(CGRect r, CGColorRef color, BOOL background) {
+ CGContextRef c = NSGraphicsContext.currentContext.CGContext;
+ const CGFloat s = ShorterSide(r.size);
+ const CGFloat l = s * 0.08; // line width
+ DrawRoundedFrame(c, r, color, background, 0.4, 1.0 - (l / s), 0.85);
+ CGContextSetLineWidth(c, l * (background ? 0.5 : 1.0));
+ AddGroupIconPath(c, s, background);
CGContextStrokePath(c);
- CGPathRelease(upper);
- CGPathRelease(lower);
}
-@end
-
-// ################################################################
-// #
-// # DrawSeparator
-// #
-// ################################################################
-
-@implementation DrawSeparator
-/**
- Draw separator line in @c NSOutlineView
- */
-- (void)drawRect:(NSRect)dirtyRect {
- NSGradient *grdnt = [[NSGradient alloc] initWithStartingColor:[NSColor darkGrayColor] endingColor:[[NSColor darkGrayColor] colorWithAlphaComponent:0.0]];
- NSRect separatorRect = NSMakeRect(1, self.frame.size.height / 2.0 - 1, self.frame.size.width - 2, 2);
- NSBezierPath *rounded = [NSBezierPath bezierPathWithRoundedRect:separatorRect xRadius:1 yRadius:1];
- [grdnt drawInBezierPath:rounded angle:0];
+/// Draw RSS icon (flat without gradient)
+NS_INLINE void DrawRSSIcon(CGRect r, CGColorRef color, BOOL background, BOOL connection) {
+ CGContextRef c = NSGraphicsContext.currentContext.CGContext;
+ DrawRoundedFrame(c, r, color, background, 0.4, 1.0, 0.7);
+ AddRSSIconPath(c, ShorterSide(r.size), connection);
+ CGContextEOFillPath(c);
+}
+
+/// Draw RSS icon (with orange gradient, corner @c 0.4, white radio waves)
+NS_INLINE void DrawRSSGradientIcon(CGRect r) {
+ const CGFloat size = ShorterSide(r.size);
+ CGContextRef c = NSGraphicsContext.currentContext.CGContext;
+ DrawRoundedFrame(c, r, NSColor.whiteColor.CGColor, YES, 0.4, 1.0, 0.7);
+ // Gradient
+ CGContextSaveGState(c);
+ CGContextClip(c);
+ DrawGradient(c, size, [NSColor rssOrange]);
+ CGContextRestoreGState(c);
+ // Bars
+ AddRSSIconPath(c, size, YES);
+ CGContextEOFillPath(c);
+}
+
+
+#pragma mark - NSImage Name Registration
+
+
+/// Add single image to @c ImageNamed cache and set accessibility description
+NS_INLINE void Register(CGFloat size, NSImageName name, NSString *description, BOOL (^draw)(NSRect r)) {
+ NSImage *img = [NSImage imageWithSize: NSMakeSize(size, size) flipped:NO drawingHandler:draw];
+ img.accessibilityDescription = description;
+ img.name = name;
+}
+
+/// Register all icons that require custom drawing in @c ImageNamed cache
+void RegisterImageViewNames(void) {
+ const CGColorRef black = [NSColor controlTextColor].CGColor;
+ Register(16, RSSImageSettingsGlobal, NSLocalizedString(@"Global settings", nil), ^(NSRect r) { DrawGlobalIcon(r, black, NO); return YES; });
+ Register(16, RSSImageSettingsGroup, NSLocalizedString(@"Group settings", nil), ^(NSRect r) { DrawGroupIcon(r, black, NO); return YES; });
+ Register(16, RSSImageSettingsFeed, NSLocalizedString(@"Feed settings", nil), ^(NSRect r) { DrawRSSIcon(r, black, NO, YES); return YES; });
+ Register(16, RSSImageDefaultRSSIcon, NSLocalizedString(@"RSS icon", nil), ^(NSRect r) { DrawRSSGradientIcon(r); return YES; });
+ Register(16, RSSImageMenuBarIconActive, NSLocalizedString(@"RSS menu bar icon", nil), ^(NSRect r) { DrawRSSIcon(r, [NSColor rssOrange].CGColor, YES, YES); return YES; });
+ Register(16, RSSImageMenuBarIconPaused, NSLocalizedString(@"RSS menu bar icon, paused", nil), ^(NSRect r) { DrawRSSIcon(r, [NSColor rssOrange].CGColor, YES, NO); return YES; });
}
-@end
diff --git a/baRSS/Info.plist b/baRSS/Info.plist
index bf2575a..9b2584d 100644
--- a/baRSS/Info.plist
+++ b/baRSS/Info.plist
@@ -32,7 +32,7 @@
CFBundleVersion
- 7288
+ 7539
LSMinimumSystemVersion
$(MACOSX_DEPLOYMENT_TARGET)
LSUIElement
diff --git a/baRSS/Preferences/Appearance Tab/SettingsAppearanceView.m b/baRSS/Preferences/Appearance Tab/SettingsAppearanceView.m
index ee775b8..c0acd5e 100644
--- a/baRSS/Preferences/Appearance Tab/SettingsAppearanceView.m
+++ b/baRSS/Preferences/Appearance Tab/SettingsAppearanceView.m
@@ -40,9 +40,9 @@
self = [super initWithFrame: NSZeroRect];
self.row = 0;
// Insert matrix header (the three icons)
- [self head:0 tooltip:NSLocalizedString(@"Show in menu bar", nil) class:[SettingsIconGlobal class]];
- [self head:1 tooltip:NSLocalizedString(@"Show in group menu", nil) class:[SettingsIconGroup class]];
- [self head:2 tooltip:NSLocalizedString(@"Show in feed menu", nil) class:[RSSIcon class]];
+ [self head:0 img:RSSImageSettingsGlobal tooltip:NSLocalizedString(@"Show in menu bar", nil)];
+ [self head:1 img:RSSImageSettingsGroup tooltip:NSLocalizedString(@"Show in group menu", nil)];
+ [self head:2 img:RSSImageSettingsFeed tooltip:NSLocalizedString(@"Show in feed menu", nil)];
// Generate checkbox matrix (checkbox state, X: default ON, O: default OFF, blank: hidden)
[self entry:"X " label:NSLocalizedString(@"Tint menu bar icon on unread", nil)];
[self entry:"X " label:NSLocalizedString(@"Update all feeds", nil)];
@@ -57,8 +57,8 @@
}
/// Helper method for matrix table header icons
-- (void)head:(int)x tooltip:(NSString*)ttip class:(Class)cls {
- [[[[cls alloc] initWithFrame:NSMakeRect(0, 0, IconSize, IconSize)] tooltip:ttip] placeIn:self x:PAD_WIN + x * colWidth yTop:PAD_WIN];
+- (void)head:(int)x img:(NSImageName)img tooltip:(NSString*)ttip {
+ [[[NSView imageView:img size:IconSize] tooltip:ttip] placeIn:self x:PAD_WIN + x * colWidth yTop:PAD_WIN];
}
/// Create new entry with 1-3 checkboxes and a descriptive label
diff --git a/baRSS/Preferences/Feeds Tab/SettingsFeedsView.m b/baRSS/Preferences/Feeds Tab/SettingsFeedsView.m
index 8755b9a..a88bdae 100644
--- a/baRSS/Preferences/Feeds Tab/SettingsFeedsView.m
+++ b/baRSS/Preferences/Feeds Tab/SettingsFeedsView.m
@@ -199,7 +199,9 @@ NSUserInterfaceItemIdentifier const CustomCellName = @"NameColumnCell";
self = [super initWithFrame:frameRect];
self.identifier = CustomCellName;
self.imageView = [[NSView imageView:nil size:16] placeIn:self x:1 yTop:1];
+ self.imageView.accessibilityLabel = NSLocalizedString(@"Feed icon", nil);
self.textField = [[[NSView label:@""] placeIn:self x:25 yTop:0] sizeToRight:0];
+ self.textField.accessibilityLabel = NSLocalizedString(@"Feed title", nil);
return self;
}
@@ -222,6 +224,7 @@ NSUserInterfaceItemIdentifier const CustomCellRefresh = @"RefreshColumnCell";
self = [super initWithFrame:frameRect];
self.identifier = CustomCellRefresh;
self.textField = [[[[NSView label:@""] textRight] placeIn:self x:0 yTop:0] sizeToRight:0];
+ self.textField.accessibilityLabel = NSLocalizedString(@"Refresh interval", nil);
return self;
}
diff --git a/baRSS/Status Bar Menu/BarStatusItem.m b/baRSS/Status Bar Menu/BarStatusItem.m
index 579bdef..3636111 100644
--- a/baRSS/Status Bar Menu/BarStatusItem.m
+++ b/baRSS/Status Bar Menu/BarStatusItem.m
@@ -117,18 +117,13 @@
/// Update menu bar icon and text according to unread count and user preferences.
- (void)updateBarIcon {
dispatch_async(dispatch_get_main_queue(), ^{
- if (self.unreadCountTotal > 0 && [UserPrefs defaultYES:@"globalUnreadCount"]) {
- self.statusItem.title = [NSString stringWithFormat:@"%ld", self.unreadCountTotal];
- } else {
- self.statusItem.title = @"";
- }
BOOL hasNet = [FeedDownload allowNetworkConnection];
- if (self.unreadCountTotal > 0 && hasNet && [UserPrefs defaultYES:@"globalTintMenuBarIcon"]) {
- self.statusItem.image = [RSSIcon systemBarIcon:16 tint:[NSColor rssOrange] noConnection:!hasNet];
- } else {
- self.statusItem.image = [RSSIcon systemBarIcon:16 tint:nil noConnection:!hasNet];
- self.statusItem.image.template = YES;
- }
+ BOOL tint = (self.unreadCountTotal > 0 && hasNet && [UserPrefs defaultYES:@"globalTintMenuBarIcon"]);
+ self.statusItem.image = [NSImage imageNamed:(hasNet ? RSSImageMenuBarIconActive : RSSImageMenuBarIconPaused)];
+ self.statusItem.image.template = !tint;
+
+ BOOL showCount = (self.unreadCountTotal > 0 && [UserPrefs defaultYES:@"globalUnreadCount"]);
+ self.statusItem.title = (showCount ? [NSString stringWithFormat:@"%ld", self.unreadCountTotal] : @"");
});
}