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:
parent
13751c815e
commit
a23c66e4e1
7 changed files with 106 additions and 13 deletions
|
@ -217,9 +217,11 @@ Sets the `image` associated with this tray icon when pressed on macOS.
|
||||||
|
|
||||||
Sets the hover text for this tray icon.
|
Sets the hover text for this tray icon.
|
||||||
|
|
||||||
#### `tray.setTitle(title)` _macOS_
|
#### `tray.setTitle(title[, options])` _macOS_
|
||||||
|
|
||||||
* `title` String
|
* `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).
|
Sets the title displayed next to the tray icon in the status bar (Support ANSI colors).
|
||||||
|
|
||||||
|
|
|
@ -212,11 +212,33 @@ void Tray::SetToolTip(const std::string& tool_tip) {
|
||||||
tray_icon_->SetToolTip(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())
|
if (!CheckAlive())
|
||||||
return;
|
return;
|
||||||
#if defined(OS_MAC)
|
#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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,9 @@ class Tray : public gin::Wrappable<Tray>,
|
||||||
void SetImage(gin::Handle<NativeImage> image);
|
void SetImage(gin::Handle<NativeImage> image);
|
||||||
void SetPressedImage(gin::Handle<NativeImage> image);
|
void SetPressedImage(gin::Handle<NativeImage> image);
|
||||||
void SetToolTip(const std::string& tool_tip);
|
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();
|
std::string GetTitle();
|
||||||
void SetIgnoreDoubleClickEvents(bool ignore);
|
void SetIgnoreDoubleClickEvents(bool ignore);
|
||||||
bool GetIgnoreDoubleClickEvents();
|
bool GetIgnoreDoubleClickEvents();
|
||||||
|
|
|
@ -45,8 +45,13 @@ class TrayIcon {
|
||||||
virtual void SetIgnoreDoubleClickEvents(bool ignore) = 0;
|
virtual void SetIgnoreDoubleClickEvents(bool ignore) = 0;
|
||||||
virtual bool GetIgnoreDoubleClickEvents() = 0;
|
virtual bool GetIgnoreDoubleClickEvents() = 0;
|
||||||
|
|
||||||
|
struct TitleOptions {
|
||||||
|
std::string font_type;
|
||||||
|
};
|
||||||
|
|
||||||
// Set/Get title displayed next to status icon in the status bar.
|
// 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;
|
virtual std::string GetTitle() = 0;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ class TrayIconCocoa : public TrayIcon {
|
||||||
void SetImage(const gfx::Image& image) override;
|
void SetImage(const gfx::Image& image) override;
|
||||||
void SetPressedImage(const gfx::Image& image) override;
|
void SetPressedImage(const gfx::Image& image) override;
|
||||||
void SetToolTip(const std::string& tool_tip) 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;
|
std::string GetTitle() override;
|
||||||
void SetIgnoreDoubleClickEvents(bool ignore) override;
|
void SetIgnoreDoubleClickEvents(bool ignore) override;
|
||||||
bool GetIgnoreDoubleClickEvents() override;
|
bool GetIgnoreDoubleClickEvents() override;
|
||||||
|
|
|
@ -103,14 +103,43 @@
|
||||||
return ignoreDoubleClickEvents_;
|
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]) {
|
if ([title containsANSICodes]) {
|
||||||
[[statusItem_ button]
|
attributed_title = [title attributedStringParsingANSICodes];
|
||||||
setAttributedTitle:[title attributedStringParsingANSICodes]];
|
|
||||||
} else {
|
|
||||||
[[statusItem_ button] setTitle:title];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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.
|
// Fix icon margins.
|
||||||
if (title.length > 0) {
|
if (title.length > 0) {
|
||||||
[[statusItem_ button] setImagePosition:NSImageLeft];
|
[[statusItem_ button] setImagePosition:NSImageLeft];
|
||||||
|
@ -306,8 +335,10 @@ void TrayIconCocoa::SetToolTip(const std::string& tool_tip) {
|
||||||
[status_item_view_ setToolTip:base::SysUTF8ToNSString(tool_tip)];
|
[status_item_view_ setToolTip:base::SysUTF8ToNSString(tool_tip)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void TrayIconCocoa::SetTitle(const std::string& title) {
|
void TrayIconCocoa::SetTitle(const std::string& title,
|
||||||
[status_item_view_ setTitle:base::SysUTF8ToNSString(title)];
|
const TitleOptions& options) {
|
||||||
|
[status_item_view_ setTitle:base::SysUTF8ToNSString(title)
|
||||||
|
font_type:base::SysUTF8ToNSString(options.font_type)];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TrayIconCocoa::GetTitle() {
|
std::string TrayIconCocoa::GetTitle() {
|
||||||
|
|
|
@ -159,5 +159,36 @@ describe('tray module', () => {
|
||||||
|
|
||||||
expect(newTitle).to.equal(title);
|
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'/);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue