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.
|
||||
|
||||
#### `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).
|
||||
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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'/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue