feat: allow monospaced font styles to be specified for macOS tray titles (#25059)

* feat: add optional font type to macOS tray title

* test: add tests for tray font type

* docs: update API reference for Tray setTitle

* review: change API to use an options object

* review: fix string enum in docs

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>

* review: return after throwing errors

* review: don't need thrower anymore now that we have args

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
This commit is contained in:
Alfred Xing 2020-08-23 14:39:29 -07:00 committed by GitHub
parent 13751c815e
commit a23c66e4e1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 106 additions and 13 deletions

View file

@ -217,9 +217,11 @@ Sets the `image` associated with this tray icon when pressed on macOS.
Sets the hover text for this tray icon.
#### `tray.setTitle(title)` _macOS_
#### `tray.setTitle(title[, options])` _macOS_
* `title` String
* `options` Object (optional)
* `fontType` String (optional) - The font family variant to display, can be `monospaced` or `monospacedDigit`. `monospaced` is available in macOS 10.15+ and `monospacedDigit` is available in macOS 10.11+. When left blank, the title uses the default system font.
Sets the title displayed next to the tray icon in the status bar (Support ANSI colors).

View file

@ -212,11 +212,33 @@ void Tray::SetToolTip(const std::string& tool_tip) {
tray_icon_->SetToolTip(tool_tip);
}
void Tray::SetTitle(const std::string& title) {
void Tray::SetTitle(const std::string& title,
const base::Optional<gin_helper::Dictionary>& options,
gin::Arguments* args) {
if (!CheckAlive())
return;
#if defined(OS_MAC)
tray_icon_->SetTitle(title);
TrayIcon::TitleOptions title_options;
if (options) {
if (options->Get("fontType", &title_options.font_type)) {
// Validate the font type if it's passed in
if (title_options.font_type != "monospaced" &&
title_options.font_type != "monospacedDigit") {
args->ThrowTypeError(
"fontType must be one of 'monospaced' or 'monospacedDigit'");
return;
}
} else if (options->Has("fontType")) {
args->ThrowTypeError(
"fontType must be one of 'monospaced' or 'monospacedDigit'");
return;
}
} else if (args->Length() >= 2) {
args->ThrowTypeError("setTitle options must be an object");
return;
}
tray_icon_->SetTitle(title, title_options);
#endif
}

View file

@ -86,7 +86,9 @@ class Tray : public gin::Wrappable<Tray>,
void SetImage(gin::Handle<NativeImage> image);
void SetPressedImage(gin::Handle<NativeImage> image);
void SetToolTip(const std::string& tool_tip);
void SetTitle(const std::string& title);
void SetTitle(const std::string& title,
const base::Optional<gin_helper::Dictionary>& options,
gin::Arguments* args);
std::string GetTitle();
void SetIgnoreDoubleClickEvents(bool ignore);
bool GetIgnoreDoubleClickEvents();

View file

@ -45,8 +45,13 @@ class TrayIcon {
virtual void SetIgnoreDoubleClickEvents(bool ignore) = 0;
virtual bool GetIgnoreDoubleClickEvents() = 0;
struct TitleOptions {
std::string font_type;
};
// Set/Get title displayed next to status icon in the status bar.
virtual void SetTitle(const std::string& title) = 0;
virtual void SetTitle(const std::string& title,
const TitleOptions& options) = 0;
virtual std::string GetTitle() = 0;
#endif

View file

@ -25,7 +25,7 @@ class TrayIconCocoa : public TrayIcon {
void SetImage(const gfx::Image& image) override;
void SetPressedImage(const gfx::Image& image) override;
void SetToolTip(const std::string& tool_tip) override;
void SetTitle(const std::string& title) override;
void SetTitle(const std::string& title, const TitleOptions& options) override;
std::string GetTitle() override;
void SetIgnoreDoubleClickEvents(bool ignore) override;
bool GetIgnoreDoubleClickEvents() override;

View file

@ -103,14 +103,43 @@
return ignoreDoubleClickEvents_;
}
- (void)setTitle:(NSString*)title {
- (void)setTitle:(NSString*)title font_type:(NSString*)font_type {
NSMutableAttributedString* attributed_title =
[[NSMutableAttributedString alloc] initWithString:title];
if ([title containsANSICodes]) {
[[statusItem_ button]
setAttributedTitle:[title attributedStringParsingANSICodes]];
} else {
[[statusItem_ button] setTitle:title];
attributed_title = [title attributedStringParsingANSICodes];
}
// Change font type, if specified
CGFloat existing_size = [[[statusItem_ button] font] pointSize];
if ([font_type isEqualToString:@"monospaced"]) {
if (@available(macOS 10.15, *)) {
NSDictionary* attributes = @{
NSFontAttributeName :
[NSFont monospacedSystemFontOfSize:existing_size
weight:NSFontWeightRegular]
};
[attributed_title
setAttributes:attributes
range:NSMakeRange(0, [attributed_title length])];
}
} else if ([font_type isEqualToString:@"monospacedDigit"]) {
if (@available(macOS 10.11, *)) {
NSDictionary* attributes = @{
NSFontAttributeName :
[NSFont monospacedDigitSystemFontOfSize:existing_size
weight:NSFontWeightRegular]
};
[attributed_title
setAttributes:attributes
range:NSMakeRange(0, [attributed_title length])];
}
}
// Set title
[[statusItem_ button] setAttributedTitle:attributed_title];
// Fix icon margins.
if (title.length > 0) {
[[statusItem_ button] setImagePosition:NSImageLeft];
@ -306,8 +335,10 @@ void TrayIconCocoa::SetToolTip(const std::string& tool_tip) {
[status_item_view_ setToolTip:base::SysUTF8ToNSString(tool_tip)];
}
void TrayIconCocoa::SetTitle(const std::string& title) {
[status_item_view_ setTitle:base::SysUTF8ToNSString(title)];
void TrayIconCocoa::SetTitle(const std::string& title,
const TitleOptions& options) {
[status_item_view_ setTitle:base::SysUTF8ToNSString(title)
font_type:base::SysUTF8ToNSString(options.font_type)];
}
std::string TrayIconCocoa::GetTitle() {

View file

@ -159,5 +159,36 @@ describe('tray module', () => {
expect(newTitle).to.equal(title);
});
it('can have an options object passed in', () => {
expect(() => {
tray.setTitle('Hello World!', {});
}).to.not.throw();
});
it('throws when the options parameter is not an object', () => {
expect(() => {
tray.setTitle('Hello World!', 'test' as any);
}).to.throw(/setTitle options must be an object/);
});
it('can have a font type option set', () => {
expect(() => {
tray.setTitle('Hello World!', { fontType: 'monospaced' });
tray.setTitle('Hello World!', { fontType: 'monospacedDigit' });
}).to.not.throw();
});
it('throws when the font type is specified but is not a string', () => {
expect(() => {
tray.setTitle('Hello World!', { fontType: 5.4 as any });
}).to.throw(/fontType must be one of 'monospaced' or 'monospacedDigit'/);
});
it('throws on invalid font types', () => {
expect(() => {
tray.setTitle('Hello World!', { fontType: 'blep' as any });
}).to.throw(/fontType must be one of 'monospaced' or 'monospacedDigit'/);
});
});
});