Add support for custom Dock icons while running

The emoji labeled buttons will convert and save their respective
state icon to the settings folder, and refresh the current icon
as necessary.

Signed-off-by: Christopher Snowhill <kode54@gmail.com>
This commit is contained in:
Christopher Snowhill 2024-11-24 19:47:55 -08:00
parent aa491fe0bb
commit f5be598311
18 changed files with 305 additions and 27 deletions

View file

@ -13,6 +13,13 @@
@interface DockIconController : NSObject { @interface DockIconController : NSObject {
NSImage *dockImage; NSImage *dockImage;
NSInteger lastDockCustom;
NSInteger lastDockCustomPlaque;
NSInteger dockCustomLoaded;
NSImage *dockCustomStop;
NSImage *dockCustomPlay;
NSImage *dockCustomPause;
IBOutlet PlaybackController *playbackController; IBOutlet PlaybackController *playbackController;
NSInteger lastPlaybackStatus; NSInteger lastPlaybackStatus;

View file

@ -14,16 +14,24 @@
static NSString *DockIconPlaybackStatusObservationContext = @"DockIconPlaybackStatusObservationContext"; static NSString *DockIconPlaybackStatusObservationContext = @"DockIconPlaybackStatusObservationContext";
static NSString *CogCustomDockIconsReloadNotification = @"CogCustomDockIconsReloadNotification";
- (void)startObserving { - (void)startObserving {
[playbackController addObserver:self forKeyPath:@"playbackStatus" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)]; [playbackController addObserver:self forKeyPath:@"playbackStatus" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial) context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[playbackController addObserver:self forKeyPath:@"progressOverall" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionOld) context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)]; [playbackController addObserver:self forKeyPath:@"progressOverall" options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionOld) context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.colorfulDockIcons" options:0 context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)]; [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.colorfulDockIcons" options:0 context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.customDockIcons" options:0 context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:@"values.customDockIconsPlaque" options:0 context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(refreshDockIcons:) name:CogCustomDockIconsReloadNotification object:nil];
} }
- (void)stopObserving { - (void)stopObserving {
[playbackController removeObserver:self forKeyPath:@"playbackStatus" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)]; [playbackController removeObserver:self forKeyPath:@"playbackStatus" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[playbackController removeObserver:self forKeyPath:@"progressOverall" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)]; [playbackController removeObserver:self forKeyPath:@"progressOverall" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.colorfulDockIcons" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)]; [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.colorfulDockIcons" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.customDockIcons" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:@"values.customDockIconsPlaque" context:(__bridge void *_Nullable)(DockIconPlaybackStatusObservationContext)];
[[NSNotificationCenter defaultCenter] removeObserver:self name:CogCustomDockIconsReloadNotification object:nil];
} }
- (void)startObservingProgress:(NSProgress *)progress { - (void)startObservingProgress:(NSProgress *)progress {
@ -42,6 +50,34 @@ static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons) {
} }
} }
static NSString *getCustomIconName(NSString *baseName) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *basePath = [[paths firstObject] stringByAppendingPathComponent:@"Cog"];
basePath = [basePath stringByAppendingPathComponent:@"Icons"];
basePath = [basePath stringByAppendingPathComponent:baseName];
return [basePath stringByAppendingPathExtension:@"png"];
}
- (BOOL)loadCustomDockIcons {
NSError *error = nil;
NSData *dataStopIcon = [NSData dataWithContentsOfFile:getCustomIconName(@"Stop") options:(NSDataReadingMappedIfSafe) error:&error];
if(!dataStopIcon || error) {
return NO;
}
NSData *dataPlayIcon = [NSData dataWithContentsOfFile:getCustomIconName(@"Play") options:(NSDataReadingMappedIfSafe) error:&error];
if(!dataPlayIcon || error) {
return NO;
}
NSData *dataPauseIcon = [NSData dataWithContentsOfFile:getCustomIconName(@"Pause") options:(NSDataReadingMappedIfSafe) error:&error];
if(!dataPauseIcon || error) {
return NO;
}
dockCustomStop = [[NSImage alloc] initWithData:dataStopIcon];
dockCustomPlay = [[NSImage alloc] initWithData:dataPlayIcon];
dockCustomPause = [[NSImage alloc] initWithData:dataPauseIcon];
return (dockCustomStop && dockCustomPlay && dockCustomPause);
}
- (void)refreshDockIcon:(NSInteger)playbackStatus withProgress:(double)progressStatus { - (void)refreshDockIcon:(NSInteger)playbackStatus withProgress:(double)progressStatus {
// Really weird crash user experienced because the plaque image didn't load? // Really weird crash user experienced because the plaque image didn't load?
if(!dockImage || dockImage.size.width == 0 || dockImage.size.height == 0) return; if(!dockImage || dockImage.size.width == 0 || dockImage.size.height == 0) return;
@ -50,6 +86,30 @@ static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons) {
BOOL drawIcon = NO; BOOL drawIcon = NO;
BOOL removeProgress = NO; BOOL removeProgress = NO;
BOOL useCustomDockIcons = [[NSUserDefaults standardUserDefaults] boolForKey:@"customDockIcons"];
BOOL useCustomDockIconsPlaque = [[NSUserDefaults standardUserDefaults] boolForKey:@"customDockIconsPlaque"];
if(useCustomDockIcons && !dockCustomLoaded) {
dockCustomLoaded = [self loadCustomDockIcons];
if(!dockCustomLoaded) {
useCustomDockIcons = NO;
}
}
if(useCustomDockIcons != lastDockCustom ||
useCustomDockIconsPlaque != lastDockCustomPlaque) {
lastDockCustom = useCustomDockIcons;
lastDockCustomPlaque = useCustomDockIconsPlaque;
drawIcon = YES;
if(!useCustomDockIcons) {
dockCustomLoaded = NO;
dockCustomStop = nil;
dockCustomPlay = nil;
dockCustomPause = nil;
}
}
if(playbackStatus < 0) if(playbackStatus < 0)
playbackStatus = lastPlaybackStatus; playbackStatus = lastPlaybackStatus;
else { else {
@ -82,20 +142,20 @@ static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons) {
if(drawIcon) { if(drawIcon) {
switch(playbackStatus) { switch(playbackStatus) {
case CogStatusPlaying: case CogStatusPlaying:
badgeImage = [NSImage imageNamed:getBadgeName(@"Play", colorfulIcons)]; badgeImage = useCustomDockIcons ? dockCustomPlay : [NSImage imageNamed:getBadgeName(@"Play", colorfulIcons)];
break; break;
case CogStatusPaused: case CogStatusPaused:
badgeImage = [NSImage imageNamed:getBadgeName(@"Pause", colorfulIcons)]; badgeImage = useCustomDockIcons ? dockCustomPause : [NSImage imageNamed:getBadgeName(@"Pause", colorfulIcons)];
break; break;
default: default:
badgeImage = [NSImage imageNamed:getBadgeName(@"Stop", colorfulIcons)]; badgeImage = useCustomDockIcons ? dockCustomStop : [NSImage imageNamed:getBadgeName(@"Stop", colorfulIcons)];
break; break;
} }
NSSize badgeSize = [badgeImage size]; NSSize badgeSize = [badgeImage size];
NSImage *newDockImage = [dockImage copy]; NSImage *newDockImage = (useCustomDockIcons && !useCustomDockIconsPlaque) ? [[NSImage alloc] initWithSize:NSMakeSize(1024, 1024)] : [dockImage copy];
[newDockImage lockFocus]; [newDockImage lockFocus];
[badgeImage drawInRect:NSMakeRect(0, 0, 1024, 1024) [badgeImage drawInRect:NSMakeRect(0, 0, 1024, 1024)
@ -186,7 +246,9 @@ static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons) {
} }
[self refreshDockIcon:-1 withProgress:progressStatus]; [self refreshDockIcon:-1 withProgress:progressStatus];
} else if([keyPath isEqualToString:@"values.colorfulDockIcons"]) { } else if([keyPath isEqualToString:@"values.colorfulDockIcons"] ||
[keyPath isEqualToString:@"values.customDockIcons"] ||
[keyPath isEqualToString:@"values.customDockIconsPlaque"]) {
[self refreshDockIcon:-1 withProgress:-10]; [self refreshDockIcon:-1 withProgress:-10];
} else if([keyPath isEqualToString:@"fractionCompleted"]) { } else if([keyPath isEqualToString:@"fractionCompleted"]) {
double progressStatus = [(NSProgress *)object fractionCompleted]; double progressStatus = [(NSProgress *)object fractionCompleted];
@ -197,6 +259,12 @@ static NSString *getBadgeName(NSString *baseName, BOOL colorfulIcons) {
} }
} }
- (void)refreshDockIcons:(NSNotification *)notification {
lastDockCustom = NO;
dockCustomLoaded = NO;
[self refreshDockIcon:-1 withProgress:-10];
}
- (void)awakeFromNib { - (void)awakeFromNib {
dockImage = [[NSImage imageNamed:@"Plaque"] copy]; dockImage = [[NSImage imageNamed:@"Plaque"] copy];
lastColorfulStatus = -1; lastColorfulStatus = -1;

View file

@ -0,0 +1,19 @@
//
// AppearancePane.h
// General
//
// Created by Christopher Snowhill on 11/24/24.
//
//
#import "GeneralPreferencePane.h"
#import <Cocoa/Cocoa.h>
@interface AppearancePane : GeneralPreferencePane {
}
- (IBAction)setDockIconStop:(id)sender;
- (IBAction)setDockIconPlay:(id)sender;
- (IBAction)setDockIconPause:(id)sender;
@end

View file

@ -0,0 +1,90 @@
//
// AppearancePane.m
// General
//
// Created by Christopher Snowhill on 11/24/24.
//
//
#import "AppearancePane.h"
static NSString *CogCustomDockIconsReloadNotification = @"CogCustomDockIconsReloadNotification";
@implementation AppearancePane
- (NSString *)title {
return NSLocalizedPrefString(@"Appearance");
}
- (NSImage *)icon {
if(@available(macOS 11.0, *))
return [NSImage imageWithSystemSymbolName:@"paintpalette.fill" accessibilityDescription:nil];
return [[NSImage alloc] initWithContentsOfFile:[[NSBundle bundleForClass:[self class]] pathForImageResource:@"appearance"]];
}
- (void)setDockIcon:(NSString *)baseName {
NSArray *fileTypes = @[@"jpg", @"jpeg", @"png", @"gif", @"webp", @"avif", @"heic"];
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setAllowsMultipleSelection:NO];
[panel setCanChooseDirectories:NO];
[panel setCanChooseFiles:YES];
[panel setFloatingPanel:YES];
[panel setAllowedFileTypes:fileTypes];
NSInteger result = [panel runModal];
if(result == NSModalResponseOK) {
NSError *error = nil;
NSData *iconData = [NSData dataWithContentsOfURL:[panel URL] options:NSDataReadingMappedIfSafe error:&error];
if(iconData && !error) {
NSImage *icon = [[NSImage alloc] initWithData:iconData];
if(icon) {
CGImageRef cgRef = [icon CGImageForProposedRect:NULL
context:nil
hints:nil];
if(cgRef) {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString *basePath = [[paths firstObject] stringByAppendingPathComponent:@"Cog"];
basePath = [basePath stringByAppendingPathComponent:@"Icons"];
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isDirectory = NO;
if(![fileManager fileExistsAtPath:basePath isDirectory:&isDirectory] || !isDirectory) {
if(!isDirectory) {
[fileManager removeItemAtPath:basePath error:&error];
}
[fileManager createDirectoryAtURL:[NSURL fileURLWithPath:basePath] withIntermediateDirectories:YES attributes:nil error:&error];
}
NSString *filePath = [basePath stringByAppendingPathComponent:baseName];
filePath = [filePath stringByAppendingPathExtension:@"png"];
NSBitmapImageRep *newRep =
[[NSBitmapImageRep alloc] initWithCGImage:cgRef];
NSData *pngData = [newRep
representationUsingType:NSBitmapImageFileTypePNG
properties:@{}];
[pngData writeToURL:[NSURL fileURLWithPath:filePath] atomically:YES];
// Now to refresh the icons by a little trickery, if enabled
BOOL enabled = [[NSUserDefaults standardUserDefaults] boolForKey:@"customDockIcons"];
if(enabled) {
[[NSNotificationCenter defaultCenter] postNotificationName:CogCustomDockIconsReloadNotification object:nil];
}
}
}
}
}
}
- (IBAction)setDockIconStop:(id)sender {
[self setDockIcon:@"Stop"];
}
- (IBAction)setDockIconPlay:(id)sender {
[self setDockIcon:@"Play"];
}
- (IBAction)setDockIconPause:(id)sender {
[self setDockIcon:@"Pause"];
}
@end

View file

@ -1,14 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="22154" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct"> <document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="23504" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
<dependencies> <dependencies>
<deployment identifier="macosx"/> <deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="22154"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="23504"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
<objects> <objects>
<customObject id="-2" userLabel="File's Owner" customClass="GeneralPreferencesPlugin"> <customObject id="-2" userLabel="File's Owner" customClass="GeneralPreferencesPlugin">
<connections> <connections>
<outlet property="appearanceView" destination="CgN-sy-RmM" id="wvB-aW-Gfx"/> <outlet property="appearancePane" destination="gKy-O9-bcf" id="Kdj-LI-JmX"/>
<outlet property="generalPane" destination="tm7-TU-wbV" id="jTO-w4-xwD"/> <outlet property="generalPane" destination="tm7-TU-wbV" id="jTO-w4-xwD"/>
<outlet property="hotKeyPane" destination="6" id="14"/> <outlet property="hotKeyPane" destination="6" id="14"/>
<outlet property="iTunesStyleCheck" destination="AIz-WH-Wqk" id="2n1-pY-cZR"/> <outlet property="iTunesStyleCheck" destination="AIz-WH-Wqk" id="2n1-pY-cZR"/>
@ -58,7 +58,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" selectedItem="250" id="248"> <popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" selectedItem="250" id="248">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="message"/>
<menu key="menu" title="OtherViews" id="249"> <menu key="menu" title="OtherViews" id="249">
<items> <items>
<menuItem title="Item 1" state="on" id="250"/> <menuItem title="Item 1" state="on" id="250"/>
@ -101,7 +101,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" inset="2" id="254"> <popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" inset="2" id="254">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="message"/>
<menu key="menu" title="OtherViews" id="255"> <menu key="menu" title="OtherViews" id="255">
<items> <items>
<menuItem title="Item 1" id="256"/> <menuItem title="Item 1" id="256"/>
@ -131,6 +131,11 @@
</subviews> </subviews>
<point key="canvasLocation" x="-151" y="-283.5"/> <point key="canvasLocation" x="-151" y="-283.5"/>
</customView> </customView>
<customObject id="gKy-O9-bcf" userLabel="AppearancePane" customClass="AppearancePane">
<connections>
<outlet property="view" destination="CgN-sy-RmM" id="eEi-cI-GKg"/>
</connections>
</customObject>
<customObject id="6" userLabel="HotKeyPane" customClass="HotKeyPane"> <customObject id="6" userLabel="HotKeyPane" customClass="HotKeyPane">
<connections> <connections>
<outlet property="fadeShortcutView" destination="vEd-Af-7tR" id="DMK-Z9-Sm5"/> <outlet property="fadeShortcutView" destination="vEd-Af-7tR" id="DMK-Z9-Sm5"/>
@ -293,7 +298,7 @@
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<popUpButtonCell key="cell" type="push" title="Item1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="62" id="210"> <popUpButtonCell key="cell" type="push" title="Item1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" inset="2" arrowPosition="arrowAtCenter" preferredEdge="maxY" selectedItem="62" id="210">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="message"/>
<menu key="menu" title="OtherViews" id="61"> <menu key="menu" title="OtherViews" id="61">
<items> <items>
<menuItem title="Item1" state="on" id="62"/> <menuItem title="Item1" state="on" id="62"/>
@ -323,7 +328,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="vmS-eb-zen"> <popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="vmS-eb-zen">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="message"/>
<menu key="menu" title="OtherViews" id="V8o-Xy-HUW"> <menu key="menu" title="OtherViews" id="V8o-Xy-HUW">
<items> <items>
<menuItem title="Item 1" id="oWh-lD-mFH"/> <menuItem title="Item 1" id="oWh-lD-mFH"/>
@ -568,11 +573,11 @@
<point key="canvasLocation" x="450" y="-52.5"/> <point key="canvasLocation" x="450" y="-52.5"/>
</customView> </customView>
<customView id="CgN-sy-RmM" userLabel="AppearanceView"> <customView id="CgN-sy-RmM" userLabel="AppearanceView">
<rect key="frame" x="0.0" y="0.0" width="640" height="193"/> <rect key="frame" x="0.0" y="0.0" width="640" height="245"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="haX-dq-OIe"> <button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="haX-dq-OIe">
<rect key="frame" x="18" y="156" width="602" height="18"/> <rect key="frame" x="18" y="208" width="602" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Colorful dock icons" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="GdX-5e-NeU"> <buttonCell key="cell" type="check" title="Colorful dock icons" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="GdX-5e-NeU">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/> <behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
@ -582,6 +587,28 @@
<binding destination="52" name="value" keyPath="values.colorfulDockIcons" id="NZt-v6-8iW"/> <binding destination="52" name="value" keyPath="values.colorfulDockIcons" id="NZt-v6-8iW"/>
</connections> </connections>
</button> </button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zv5-2j-Aoj" userLabel="Use custom dock icon set:">
<rect key="frame" x="18" y="182" width="477" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Use custom dock icon set:" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="RwB-Tk-ufd">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="52" name="value" keyPath="values.customDockIcons" id="Eps-hb-AfK"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AjL-Ho-0mM">
<rect key="frame" x="40" y="158" width="580" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="check" title="Render over background plaque" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="KZd-iR-dXL">
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<binding destination="52" name="value" keyPath="values.customDockIconsPlaque" id="PQe-kt-nXW"/>
</connections>
</button>
<button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AA7-fr-NOk"> <button fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AA7-fr-NOk">
<rect key="frame" x="18" y="130" width="602" height="18"/> <rect key="frame" x="18" y="130" width="602" height="18"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
@ -658,6 +685,39 @@
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell> </textFieldCell>
</textField> </textField>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="5fh-1K-0GQ" userLabel="Stopped">
<rect key="frame" x="496" y="174" width="45" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="⏹️" alternateTitle="Stopped" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="QYJ-kq-zao">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setDockIconStop:" target="gKy-O9-bcf" id="C7I-ab-aYn"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="paU-SV-utl" userLabel="Playing">
<rect key="frame" x="539" y="174" width="45" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="▶️" alternateTitle="Playing" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Z7K-Px-LDn">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setDockIconPlay:" target="gKy-O9-bcf" id="EgK-ze-Ymi"/>
</connections>
</button>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="NpP-Uh-srl" userLabel="Paused">
<rect key="frame" x="582" y="174" width="45" height="32"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="⏸️" alternateTitle="Paused" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="yJA-mn-Xjt">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="setDockIconPause:" target="gKy-O9-bcf" id="Pol-yc-d36"/>
</connections>
</button>
</subviews> </subviews>
<point key="canvasLocation" x="450" y="198.5"/> <point key="canvasLocation" x="450" y="198.5"/>
</customView> </customView>
@ -716,7 +776,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="vaQ-pZ-jXy" id="xcv-1b-kTI"> <popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="vaQ-pZ-jXy" id="xcv-1b-kTI">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="message"/>
<menu key="menu" id="pRc-b6-sMR"> <menu key="menu" id="pRc-b6-sMR">
<items> <items>
<menuItem title="Item 1" state="on" id="vaQ-pZ-jXy"/> <menuItem title="Item 1" state="on" id="vaQ-pZ-jXy"/>
@ -746,7 +806,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="3Gx-cs-3B0" id="5q7-83-7V6"> <popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="3Gx-cs-3B0" id="5q7-83-7V6">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="message"/>
<menu key="menu" title="OtherViews" id="HKM-FW-dhH"> <menu key="menu" title="OtherViews" id="HKM-FW-dhH">
<items> <items>
<menuItem title="Item 1" state="on" id="3Gx-cs-3B0"/> <menuItem title="Item 1" state="on" id="3Gx-cs-3B0"/>
@ -776,7 +836,7 @@
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" altersStateOfSelectedItem="NO" selectedItem="XzK-h2-vIT" id="qzt-Ox-taI"> <popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" autoenablesItems="NO" altersStateOfSelectedItem="NO" selectedItem="XzK-h2-vIT" id="qzt-Ox-taI">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/> <behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="menu"/> <font key="font" metaFont="message"/>
<menu key="menu" autoenablesItems="NO" id="q1g-E5-NwQ"> <menu key="menu" autoenablesItems="NO" id="q1g-E5-NwQ">
<items> <items>
<menuItem title="Item 1" id="XzK-h2-vIT"/> <menuItem title="Item 1" id="XzK-h2-vIT"/>

View file

@ -14,16 +14,17 @@
#import "HotKeyPane.h" #import "HotKeyPane.h"
#import "MIDIPane.h" #import "MIDIPane.h"
#import "OutputPane.h" #import "OutputPane.h"
#import "AppearancePane.h"
@interface GeneralPreferencesPlugin : NSObject <PreferencePanePlugin> { @interface GeneralPreferencesPlugin : NSObject <PreferencePanePlugin> {
IBOutlet HotKeyPane *hotKeyPane; IBOutlet HotKeyPane *hotKeyPane;
IBOutlet OutputPane *outputPane; IBOutlet OutputPane *outputPane;
IBOutlet MIDIPane *midiPane; IBOutlet MIDIPane *midiPane;
IBOutlet GeneralPane *generalPane; IBOutlet GeneralPane *generalPane;
IBOutlet AppearancePane *appearancePane;
IBOutlet NSView *playlistView; IBOutlet NSView *playlistView;
IBOutlet NSView *notificationsView; IBOutlet NSView *notificationsView;
IBOutlet NSView *appearanceView;
__weak IBOutlet NSButton *iTunesStyleCheck; __weak IBOutlet NSButton *iTunesStyleCheck;
} }

View file

@ -82,10 +82,7 @@
} }
- (GeneralPreferencePane *)appearancePane { - (GeneralPreferencePane *)appearancePane {
return [GeneralPreferencePane preferencePaneWithView:appearanceView return appearancePane;
title:NSLocalizedPrefString(@"Appearance")
systemIconName:@"paintpalette.fill"
orOldIconNamed:@"appearance"];
} }
@end @end

View file

@ -25,6 +25,7 @@
833A899F286FF3850022E036 /* TimeIntervalToStringTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 833A899E286FF3850022E036 /* TimeIntervalToStringTransformer.m */; }; 833A899F286FF3850022E036 /* TimeIntervalToStringTransformer.m in Sources */ = {isa = PBXBuildFile; fileRef = 833A899E286FF3850022E036 /* TimeIntervalToStringTransformer.m */; };
83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */; }; 83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 83651DA327322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m */; };
8372053718E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */; }; 8372053718E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */; };
83726F022CF41B3200F15FBF /* AppearancePane.m in Sources */ = {isa = PBXBuildFile; fileRef = 83726F012CF41B3200F15FBF /* AppearancePane.m */; };
837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */; }; 837C0D401C50954000CAE18F /* MIDIPluginBehaviorArrayController.m in Sources */ = {isa = PBXBuildFile; fileRef = 837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */; };
8384917718084D9F00E7332D /* appearance.png in Resources */ = {isa = PBXBuildFile; fileRef = 8384917518084D9F00E7332D /* appearance.png */; }; 8384917718084D9F00E7332D /* appearance.png in Resources */ = {isa = PBXBuildFile; fileRef = 8384917518084D9F00E7332D /* appearance.png */; };
8391EA06286F9D3200A37593 /* PathSuggester.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83DAD9F0286EDBCD000FAA9A /* PathSuggester.xib */; }; 8391EA06286F9D3200A37593 /* PathSuggester.xib in Resources */ = {isa = PBXBuildFile; fileRef = 83DAD9F0286EDBCD000FAA9A /* PathSuggester.xib */; };
@ -119,6 +120,8 @@
83651DA427322C8700A2C097 /* MIDIFlavorBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIFlavorBehaviorArrayController.h; sourceTree = "<group>"; }; 83651DA427322C8700A2C097 /* MIDIFlavorBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIFlavorBehaviorArrayController.h; sourceTree = "<group>"; };
8372053518E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResamplerBehaviorArrayController.h; sourceTree = "<group>"; }; 8372053518E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ResamplerBehaviorArrayController.h; sourceTree = "<group>"; };
8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ResamplerBehaviorArrayController.m; sourceTree = "<group>"; }; 8372053618E3DEAF007EFAD4 /* ResamplerBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ResamplerBehaviorArrayController.m; sourceTree = "<group>"; };
83726F002CF41B3200F15FBF /* AppearancePane.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppearancePane.h; sourceTree = "<group>"; };
83726F012CF41B3200F15FBF /* AppearancePane.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppearancePane.m; sourceTree = "<group>"; };
837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIPluginBehaviorArrayController.h; sourceTree = "<group>"; }; 837C0D3E1C50954000CAE18F /* MIDIPluginBehaviorArrayController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MIDIPluginBehaviorArrayController.h; sourceTree = "<group>"; };
837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIPluginBehaviorArrayController.m; sourceTree = "<group>"; }; 837C0D3F1C50954000CAE18F /* MIDIPluginBehaviorArrayController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIDIPluginBehaviorArrayController.m; sourceTree = "<group>"; };
8384913618081ECB00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; }; 8384913618081ECB00E7332D /* Logging.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Logging.h; path = ../../Utils/Logging.h; sourceTree = "<group>"; };
@ -258,6 +261,8 @@
17D5033F0ABDB1570022D1E8 /* Panes */ = { 17D5033F0ABDB1570022D1E8 /* Panes */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
83726F002CF41B3200F15FBF /* AppearancePane.h */,
83726F012CF41B3200F15FBF /* AppearancePane.m */,
8E07AA820AAC8EA200A4B32F /* GeneralPreferencePane.h */, 8E07AA820AAC8EA200A4B32F /* GeneralPreferencePane.h */,
8E07AA830AAC8EA200A4B32F /* GeneralPreferencePane.m */, 8E07AA830AAC8EA200A4B32F /* GeneralPreferencePane.m */,
8E07AA800AAC8EA200A4B32F /* HotKeyPane.h */, 8E07AA800AAC8EA200A4B32F /* HotKeyPane.h */,
@ -494,6 +499,7 @@
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
83AC573A2861A54D009D6F50 /* PathSuggester.m in Sources */, 83AC573A2861A54D009D6F50 /* PathSuggester.m in Sources */,
83726F022CF41B3200F15FBF /* AppearancePane.m in Sources */,
83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */, 83651DA527322C8700A2C097 /* MIDIFlavorBehaviorArrayController.m in Sources */,
83B06729180D85B8008E3612 /* MIDIPane.m in Sources */, 83B06729180D85B8008E3612 /* MIDIPane.m in Sources */,
8E07AA880AAC8EA200A4B32F /* HotKeyPane.m in Sources */, 8E07AA880AAC8EA200A4B32F /* HotKeyPane.m in Sources */,

View file

@ -244,3 +244,9 @@
/* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */ /* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */
"Phw-hj-6tI.title" = "Reduce DSD volume level by 6 dB"; "Phw-hj-6tI.title" = "Reduce DSD volume level by 6 dB";
/* Class = "NSButtonCell"; title = "Use custom dock icon set:"; ObjectID = "RwB-Tk-ufd"; */
"RwB-Tk-ufd.title" = "Use custom dock icon set:";
/* Class = "NSButtonCell"; title = "Render over background plaque"; ObjectID = "KZd-iR-dXL"; */
"KZd-iR-dXL.title" = "Render over background plaque";

View file

@ -243,3 +243,9 @@
/* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */ /* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */
"Phw-hj-6tI.title" = "Reducir volumen de DSD en 6 dB"; "Phw-hj-6tI.title" = "Reducir volumen de DSD en 6 dB";
/* Class = "NSButtonCell"; title = "Use custom dock icon set:"; ObjectID = "RwB-Tk-ufd"; */
"RwB-Tk-ufd.title" = "Usar conjunto de iconos del dock personalizados:";
/* Class = "NSButtonCell"; title = "Render over background plaque"; ObjectID = "KZd-iR-dXL"; */
"KZd-iR-dXL.title" = "Mostrar fondo del icono";

View file

@ -109,3 +109,9 @@
/* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */ /* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */
"Phw-hj-6tI.title" = "Reduce DSD volume level by 6 dB"; "Phw-hj-6tI.title" = "Reduce DSD volume level by 6 dB";
/* Class = "NSButtonCell"; title = "Use custom dock icon set:"; ObjectID = "RwB-Tk-ufd"; */
"RwB-Tk-ufd.title" = "własny zestaw ikon:";
/* Class = "NSButtonCell"; title = "Render over background plaque"; ObjectID = "KZd-iR-dXL"; */
"KZd-iR-dXL.title" = "tarcza za ikoną";

View file

@ -205,3 +205,9 @@
/* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */ /* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */
"Phw-hj-6tI.title" = "Reduce DSD volume level by 6 dB"; "Phw-hj-6tI.title" = "Reduce DSD volume level by 6 dB";
/* Class = "NSButtonCell"; title = "Use custom dock icon set:"; ObjectID = "RwB-Tk-ufd"; */
"RwB-Tk-ufd.title" = "Используйте свой собственный набор икон:";
/* Class = "NSButtonCell"; title = "Render over background plaque"; ObjectID = "KZd-iR-dXL"; */
"KZd-iR-dXL.title" = "Отображать икону над щитом";

View file

@ -244,3 +244,9 @@
/* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */ /* Class = "NSButtonCell"; title = "Reduce DSD volume level by 6 dB"; ObjectID = "Phw-hj-6tI"; */
"Phw-hj-6tI.title" = "Reduce DSD volume level by 6 dB"; "Phw-hj-6tI.title" = "Reduce DSD volume level by 6 dB";
/* Class = "NSButtonCell"; title = "Use custom dock icon set:"; ObjectID = "RwB-Tk-ufd"; */
"RwB-Tk-ufd.title" = "Sahip olduğunuz kendi ikon setini kullanın:";
/* Class = "NSButtonCell"; title = "Render over background plaque"; ObjectID = "KZd-iR-dXL"; */
"KZd-iR-dXL.title" = "İkonun şaltırın üzerinde gösterilmesi";

View file

@ -31,7 +31,7 @@
<div> <div>
Now with 92% more future!<br><br> Thanks to my patrons: Now with 92% more future!<br><br> Thanks to my patrons:
<br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz <br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz
<br><br> Additional code contributions by <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a> and <a href="https://kddlb.com">Kevin López Brante</a>. <br><br> Additional code contributions by <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a>, <a href="https://kddlb.com">Kevin López Brante</a> and mpan.
<br><br> <br><br>
<em>This program has been made possible through contributions from users like you.</em> <em>This program has been made possible through contributions from users like you.</em>
<br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses. <br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses.

View file

@ -31,7 +31,7 @@
<div> <div>
¡Ahora con 92% más de futuro!<br><br> Gracias a mis patrocinadores: ¡Ahora con 92% más de futuro!<br><br> Gracias a mis patrocinadores:
<br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz <br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz
<br><br> Desarrollo adicional por <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a> and <a href="https://kddlb.com">Kevin López Brante</a>. <br><br> Desarrollo adicional por <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a>, <a href="https://kddlb.com">Kevin López Brante</a> y mpan.
<br>Traducido al español por Kevin López Brante. <br>Traducido al español por Kevin López Brante.
<br><br> <br><br>
<em>Este programa ha sido posible gracias a las contribuciones de usuarios y usuarias como tú.</em> <em>Este programa ha sido posible gracias a las contribuciones de usuarios y usuarias como tú.</em>

View file

@ -31,7 +31,7 @@
<div> <div>
Now with 92% more future!<br><br> Thanks to my patrons: Now with 92% more future!<br><br> Thanks to my patrons:
<br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz <br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz
<br><br> Additional code contributions by <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a> and <a href="https://kddlb.com">Kevin López Brante</a>. <br><br> Additional code contributions by <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a>, <a href="https://kddlb.com">Kevin López Brante</a> and mpan.
<br><br> <br><br>
<em>This program has been made possible through contributions from users like you.</em> <em>This program has been made possible through contributions from users like you.</em>
<br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses. <br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses.

View file

@ -31,7 +31,7 @@
<div> <div>
Теперь на 92% больше функий!<br><br> Спасибо моим патронам: Теперь на 92% больше функий!<br><br> Спасибо моим патронам:
<br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz <br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz
<br><br> Дополнительный вклад в разработку от <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a> и <a href="https://kddlb.com">Kevin López Brante</a>. <br><br> Дополнительный вклад в разработку от <a href="https://twitter.com/nevack_d">Dzmitry Neviadomski</a>, <a href="https://kddlb.com">Kevin López Brante</a> и mpan.
<br><br> <br><br>
<em>Создние этой программы стало возможным благодаря вкладу таких пользователей, как вы.</em> <em>Создние этой программы стало возможным благодаря вкладу таких пользователей, как вы.</em>
<br><br> Весь код Cog защищен моим авторским правом и распространяется под лицензией <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog содержит фрагменты другого кода от третьих сторон, который находятся под их собственными лицензиями. <br><br> Весь код Cog защищен моим авторским правом и распространяется под лицензией <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog содержит фрагменты другого кода от третьих сторон, который находятся под их собственными лицензиями.

View file

@ -31,7 +31,7 @@
<div> <div>
Now with 92% more future!<br><br> Thanks to my patrons: Now with 92% more future!<br><br> Thanks to my patrons:
<br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz <br> Alexander Pecheny, Electric Keet, Antti Aro, Fj&ouml;lnir &Aacute;sgeirsson, Giampaolo Bellavite, Louis Martinez V, deef.xyz
<br><br> Additional code contributions by <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a> and <a href="https://kddlb.com">Kevin López Brante</a>. <br><br> Additional code contributions by <a href="https://twitter.com/nevack_d"> Dzmitry Neviadomski</a>, <a href="https://kddlb.com">Kevin López Brante</a> and mpan.
<br><br> <br><br>
<em>This program has been made possible through contributions from users like you.</em> <em>This program has been made possible through contributions from users like you.</em>
<br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses. <br><br> All Cog code is copyrighted by me, and is licensed under the <a href="http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt">GPL</a>. Cog contains bits of other code from third parties that are under their own licenses.