RSS icon drawing

This commit is contained in:
relikd
2018-08-05 23:55:07 +02:00
parent 9507f1d412
commit 3a79faaa65
6 changed files with 204 additions and 30 deletions

View File

@@ -8,6 +8,7 @@
/* Begin PBXBuildFile section */
1968E0AE14B8E8A90E194980 /* PyHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 1968EF7567E06D2A5BB3481A /* PyHandler.m */; };
54209E942117325100F3B5EF /* DrawImage.m in Sources */ = {isa = PBXBuildFile; fileRef = 54209E932117325100F3B5EF /* DrawImage.m */; };
544B011A2114B41200386E5C /* ModalSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = 544B01192114B41200386E5C /* ModalSheet.m */; };
544B011D2114EE9100386E5C /* AppHook.m in Sources */ = {isa = PBXBuildFile; fileRef = 544B011C2114EE9100386E5C /* AppHook.m */; };
544FBD4521064AEB008A260C /* Python.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 544FBD4421064AEB008A260C /* Python.framework */; };
@@ -25,6 +26,8 @@
/* Begin PBXFileReference section */
1968E7919BAA36F042FCB717 /* PyHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PyHandler.h; sourceTree = "<group>"; };
1968EF7567E06D2A5BB3481A /* PyHandler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PyHandler.m; sourceTree = "<group>"; };
54209E922117325100F3B5EF /* DrawImage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DrawImage.h; sourceTree = "<group>"; };
54209E932117325100F3B5EF /* DrawImage.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = DrawImage.m; sourceTree = "<group>"; };
544B01182114B41200386E5C /* ModalSheet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ModalSheet.h; sourceTree = "<group>"; };
544B01192114B41200386E5C /* ModalSheet.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ModalSheet.m; sourceTree = "<group>"; };
544B011B2114EE9100386E5C /* AppHook.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppHook.h; sourceTree = "<group>"; };
@@ -108,6 +111,8 @@
54ACC29721061FBA0020715F /* Preferences.m */,
544B01182114B41200386E5C /* ModalSheet.h */,
544B01192114B41200386E5C /* ModalSheet.m */,
54209E922117325100F3B5EF /* DrawImage.h */,
54209E932117325100F3B5EF /* DrawImage.m */,
54ACC28521061B3C0020715F /* Assets.xcassets */,
54ACC28721061B3C0020715F /* Main.xib */,
54ACC28A21061B3C0020715F /* Info.plist */,
@@ -205,6 +210,7 @@
544B011A2114B41200386E5C /* ModalSheet.m in Sources */,
54ACC29821061FBA0020715F /* Preferences.m in Sources */,
1968E0AE14B8E8A90E194980 /* PyHandler.m in Sources */,
54209E942117325100F3B5EF /* DrawImage.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};

View File

@@ -22,6 +22,7 @@
#import "AppDelegate.h"
#import "PyHandler.h"
#import "DrawImage.h"
@interface AppDelegate ()
@property (strong) NSStatusItem *statusItem;
@@ -34,9 +35,11 @@
self.statusItem = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength];
self.statusItem.title = @"me";
self.statusItem.menu = self.statusMenu;
printf("will init\n");
self.statusItem.highlightMode = YES;
self.statusItem.image = [[RSSIcon templateIcon:16 tint:nil] image];
self.statusItem.image.template = YES;
[PyHandler prepare];
printf("done\n");
printf("up and running\n");
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {

View File

@@ -308,21 +308,21 @@
<rect key="frame" x="0.0" y="0.0" width="320" height="327"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="19" horizontalPageScroll="10" verticalLineScroll="19" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jUM-kR-Dxs">
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="20" horizontalPageScroll="10" verticalLineScroll="20" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jUM-kR-Dxs">
<rect key="frame" x="0.0" y="20" width="320" height="307"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<clipView key="contentView" ambiguous="YES" id="nZO-rz-NyQ">
<rect key="frame" x="1" y="0.0" width="318" height="306"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" autosaveName="" rowSizeStyle="automatic" headerView="ne2-ld-l1b" viewBased="YES" indentationPerLevel="15" outlineTableColumn="Lb1-9n-wlc" id="hKk-G1-1po">
<outlineView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="firstColumnOnly" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" typeSelect="NO" autosaveName="" rowHeight="18" headerView="ne2-ld-l1b" viewBased="YES" indentationPerLevel="15" outlineTableColumn="Lb1-9n-wlc" id="hKk-G1-1po">
<rect key="frame" x="0.0" y="0.0" width="318" height="283"/>
<autoresizingMask key="autoresizingMask"/>
<size key="intercellSpacing" width="3" height="2"/>
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
<tableColumns>
<tableColumn identifier="NameColumn" editable="NO" width="262" minWidth="40" maxWidth="42000" id="Lb1-9n-wlc">
<tableColumn identifier="NameColumn" editable="NO" width="262" minWidth="40" maxWidth="10000" id="Lb1-9n-wlc">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Name">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
@@ -336,16 +336,16 @@
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/>
<prototypeCellViews>
<tableCellView identifier="cellFeed" id="xPj-mA-zCd" userLabel="Feed">
<rect key="frame" x="1" y="1" width="262" height="17"/>
<rect key="frame" x="1" y="1" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="ZkQ-CQ-77k" userLabel="img">
<rect key="frame" x="3" y="0.0" width="17" height="17"/>
<rect key="frame" x="1" y="1" width="16" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSActionTemplate" id="6xE-Sq-YVt"/>
</imageView>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="v0D-kY-dKT" userLabel="str">
<rect key="frame" x="25" y="0.0" width="237" height="17"/>
<rect key="frame" x="23" y="0.0" width="241" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="AQH-6L-dw6">
<font key="font" metaFont="system"/>
@@ -360,11 +360,11 @@
</connections>
</tableCellView>
<tableCellView identifier="cellSeparator" id="IkM-wJ-Az7" userLabel="Separator">
<rect key="frame" x="1" y="20" width="262" height="17"/>
<rect key="frame" x="1" y="21" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<customView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mlO-VE-655" userLabel="img" customClass="DrawSeparator">
<rect key="frame" x="3" y="0.0" width="256" height="17"/>
<rect key="frame" x="0.0" y="0.0" width="262" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</customView>
</subviews>
@@ -379,7 +379,7 @@
</binding>
</connections>
</tableColumn>
<tableColumn identifier="RefreshColumn" editable="NO" width="50" minWidth="40" maxWidth="1000" id="8st-OH-BXG">
<tableColumn identifier="RefreshColumn" editable="NO" width="50" minWidth="40" maxWidth="100" id="8st-OH-BXG">
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" title="Refresh">
<font key="font" metaFont="smallSystem"/>
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
@@ -392,11 +392,11 @@
</textFieldCell>
<prototypeCellViews>
<tableCellView identifier="cellRefresh" id="tSf-op-fUB" userLabel="cellView">
<rect key="frame" x="266" y="1" width="50" height="17"/>
<rect key="frame" x="266" y="1" width="50" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsExpansionToolTips="YES" translatesAutoresizingMaskIntoConstraints="NO" id="RZ4-Kn-HYa" userLabel="str">
<rect key="frame" x="0.0" y="0.0" width="50" height="17"/>
<rect key="frame" x="-2" y="0.0" width="54" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" alignment="right" title="21042s" id="pIo-Xo-bMN">
<font key="font" metaFont="system"/>

45
baRSS/DrawImage.h Normal file
View File

@@ -0,0 +1,45 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import <Cocoa/Cocoa.h>
@interface RSSIcon : NSObject
@property (strong) NSColor *barsColor;
@property (strong) NSColor *squareColor;
@property (strong) NSColor *squareGradientColor;
@property (assign) NSSize size;
@property (assign) bool isTemplate;
+ (instancetype)iconWithSize:(NSSize)size;
+ (instancetype)templateIcon:(CGFloat)size tint:(nullable NSColor*)color;
- (instancetype)autoGradient;
+ (NSColor*)rssOrange;
- (NSImage*)image;
@end
IB_DESIGNABLE
@interface DrawSeparator : NSView
@end

122
baRSS/DrawImage.m Normal file
View File

@@ -0,0 +1,122 @@
//
// The MIT License (MIT)
// Copyright (c) 2018 Oleg Geier
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#import "DrawImage.h"
@implementation RSSIcon
+ (NSColor*)rssOrange {
return [NSColor colorWithCalibratedRed:0.984 green:0.639 blue:0.227 alpha:1.0];
}
+ (instancetype)iconWithSize:(NSSize)size {
RSSIcon *icon = [[super alloc] init];
icon.size = size;
icon.barsColor = [NSColor whiteColor];
icon.squareColor = [RSSIcon rssOrange];
return icon;
}
+ (instancetype)templateIcon:(CGFloat)s tint:(NSColor*)color {
RSSIcon *icon = [[super alloc] init];
icon.size = NSMakeSize(s, s);
icon.squareColor = (color ? color : [NSColor blackColor]);
icon.isTemplate = YES;
return icon;
}
- (instancetype)autoGradient {
const CGFloat h = self.squareColor.hueComponent;
const CGFloat s = self.squareColor.saturationComponent;
const CGFloat b = self.squareColor.brightnessComponent;
const CGFloat a = self.squareColor.alphaComponent;
static const CGFloat impact = 0.3;
self.squareGradientColor = [NSColor colorWithHue:h saturation:(s - impact < 0 ? 0 : s - impact) brightness:b alpha:a];
self.squareColor = [NSColor colorWithHue:h saturation:(s + impact > 1 ? 1 : s + impact) brightness:b alpha:a];
return self;
}
- (NSImage*)image {
return [NSImage imageWithSize:self.size flipped:NO drawingHandler:^BOOL(NSRect rect) {
CGFloat s = (self.size.height < self.size.width ? self.size.height : self.size.width);
CGFloat corner = s * 0.2;
CGMutablePathRef square = CGPathCreateMutable(); // the brackground
CGPathAddRoundedRect(square, NULL, rect, corner, corner);
CGMutablePathRef bars = CGPathCreateMutable(); // the rss bars
CGAffineTransform at = CGAffineTransformMake(0.75, 0, 0, 0.75, s * 0.15, s * 0.15); // scale 0.75, translate 0.15
// circle
CGPathAddEllipseInRect(bars, &at, CGRectMake(0, 0, s * 0.25, s * 0.25));
// 1st bar
CGPathMoveToPoint(bars, &at, 0, s * 0.65);
CGPathAddArc(bars, &at, 0, 0, s * 0.65, M_PI_2, 0, YES);
CGPathAddLineToPoint(bars, &at, s * 0.45, 0);
CGPathAddArc(bars, &at, 0, 0, s * 0.45, 0, M_PI_2, NO);
CGPathCloseSubpath(bars);
// 2nd bar
CGPathMoveToPoint(bars, &at, 0, s);
CGPathAddArc(bars, &at, 0, 0, s, M_PI_2, 0, YES);
CGPathAddLineToPoint(bars, &at, s * 0.8, 0);
CGPathAddArc(bars, &at, 0, 0, s * 0.8, 0, M_PI_2, NO);
CGPathCloseSubpath(bars);
CGContextRef c = [[NSGraphicsContext currentContext] CGContext];
CGContextSetFillColorWithColor(c, [self.squareColor CGColor]);
CGContextAddPath(c, square);
if (!self.isTemplate) {
if (self.squareGradientColor) {
CGContextClip(c);
const void* cgColors[] = {
[self.squareColor CGColor],
[self.squareGradientColor CGColor],
[self.squareColor CGColor]
};
CFArrayRef colors = CFArrayCreate(NULL, cgColors, 3, NULL);
CGGradientRef gradient = CGGradientCreateWithColors(NULL, colors, NULL);
CGContextDrawLinearGradient(c, gradient, CGPointMake(0, s), CGPointMake(s, 0), 0);
CGGradientRelease(gradient);
CFRelease(colors);
}
CGContextFillPath(c);
CGContextSetFillColorWithColor(c, [self.barsColor CGColor]);
}
CGContextAddPath(c, bars);
CGContextEOFillPath(c);
CGPathRelease(square);
CGPathRelease(bars);
return YES;
}];
}
@end
@implementation DrawSeparator
- (void)drawRect:(NSRect)dirtyRect {
NSGradient *grdnt = [[NSGradient alloc] initWithStartingColor:[NSColor darkGrayColor] endingColor:[[NSColor darkGrayColor] colorWithAlphaComponent:0.0]];
NSBezierPath *rounded = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(1, self.bounds.size.height/2.0-1, self.bounds.size.width-2, 2) xRadius:1 yRadius:1];
[grdnt drawInBezierPath:rounded angle:0];
}
@end

View File

@@ -25,6 +25,7 @@
#import "Preferences.h"
#import "DBv1+CoreDataModel.h"
#import "ModalSheet.h"
#import "DrawImage.h"
@interface NewsController ()
@property (weak) IBOutlet Preferences *preferencesWindow;
@@ -49,6 +50,7 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
- (NSView *)outlineView:(NSOutlineView *)outlineView viewForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
FeedConfig *f = [(NSTreeNode*)item representedObject];
bool isFeed = (f.type == 1);
bool isSeperator = (f.type == 2);
bool isRefreshColumn = [tableColumn.identifier isEqualToString:@"RefreshColumn"];
@@ -57,14 +59,23 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
NSTableCellView *cellView = [self.outlineView makeViewWithIdentifier:cellIdent owner:nil];
if (isRefreshColumn) {
cellView.textField.stringValue = (f.type != 1 ? @"" : [ModalFeedEdit stringForRefreshNum:f.refreshNum unit:f.refreshUnit]);
cellView.textField.stringValue = (!isFeed ? @"" : [ModalFeedEdit stringForRefreshNum:f.refreshNum unit:f.refreshUnit]);
} else if (isSeperator) {
return cellView; // the refresh cell is already skipped with the above if condition
} else {
cellView.textField.objectValue = f.name;
cellView.imageView.image = (f.type == 0 ? [NSImage imageNamed:NSImageNameFolder] : nil);
// TODO: load icon or show default rss icon
if (f.type == 0) {
cellView.imageView.image = [NSImage imageNamed:NSImageNameFolder];
} else {
// TODO: load icon
static NSImage *defaultRSSIcon;
if (!defaultRSSIcon)
defaultRSSIcon = [[[RSSIcon iconWithSize:cellView.imageView.frame.size] autoGradient] image];
cellView.imageView.image = defaultRSSIcon;
}
}
if (isFeed) // also for refresh column
cellView.textField.textColor = (f.refreshNum == 0 ? [NSColor disabledControlTextColor] : [NSColor controlTextColor]);
return cellView;
}
@@ -322,16 +333,3 @@ static NSString *dragNodeType = @"baRSS-feed-drag";
}
@end
#pragma mark - Drawings on Screen
@interface DrawSeparator : NSView @end
@implementation DrawSeparator
- (void)drawRect:(NSRect)dirtyRect {
[super drawRect:dirtyRect];
NSGradient *grdnt = [[NSGradient alloc] initWithStartingColor:[NSColor darkGrayColor] endingColor:[[NSColor darkGrayColor] colorWithAlphaComponent:0.0]];
NSBezierPath *rounded = [NSBezierPath bezierPathWithRoundedRect:NSMakeRect(1, self.bounds.size.height/2.0-1, self.bounds.size.width-2, 2) xRadius:1 yRadius:1];
[grdnt drawInBezierPath:rounded angle:0];
}
@end