Merge pull request #8910 from electron/touchbar-scrubber
Touchbar NSScrubber
This commit is contained in:
commit
da0d0e7aac
7 changed files with 325 additions and 15 deletions
|
@ -17,7 +17,7 @@
|
|||
#include "native_mate/constructor.h"
|
||||
#include "native_mate/persistent_dictionary.h"
|
||||
|
||||
@interface AtomTouchBar : NSObject {
|
||||
@interface AtomTouchBar : NSObject<NSScrubberDelegate, NSScrubberDataSource> {
|
||||
@protected
|
||||
std::vector<mate::PersistentDictionary> ordered_settings_;
|
||||
std::map<std::string, mate::PersistentDictionary> settings_;
|
||||
|
|
|
@ -19,6 +19,10 @@ static NSTouchBarItemIdentifier LabelIdentifier = @"com.electron.touchbar.label.
|
|||
static NSTouchBarItemIdentifier PopoverIdentifier = @"com.electron.touchbar.popover.";
|
||||
static NSTouchBarItemIdentifier SliderIdentifier = @"com.electron.touchbar.slider.";
|
||||
static NSTouchBarItemIdentifier SegmentedControlIdentifier = @"com.electron.touchbar.segmentedcontrol.";
|
||||
static NSTouchBarItemIdentifier ScrubberIdentifier = @"com.electron.touchbar.scrubber.";
|
||||
|
||||
static NSString* const TextScrubberItemIdentifier = @"scrubber.text.item";
|
||||
static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item";
|
||||
|
||||
- (id)initWithDelegate:(id<NSTouchBarDelegate>)delegate
|
||||
window:(atom::NativeWindow*)window
|
||||
|
@ -101,6 +105,9 @@ static NSTouchBarItemIdentifier SegmentedControlIdentifier = @"com.electron.touc
|
|||
} else if ([identifier hasPrefix:SegmentedControlIdentifier]) {
|
||||
item_id = [self idFromIdentifier:identifier withPrefix:SegmentedControlIdentifier];
|
||||
return [self makeSegmentedControlForID:item_id withIdentifier:identifier];
|
||||
} else if ([identifier hasPrefix:ScrubberIdentifier]) {
|
||||
item_id = [self idFromIdentifier:identifier withPrefix:ScrubberIdentifier];
|
||||
return [self makeScrubberForID:item_id withIdentifier:identifier];
|
||||
}
|
||||
|
||||
return nil;
|
||||
|
@ -133,8 +140,12 @@ static NSTouchBarItemIdentifier SegmentedControlIdentifier = @"com.electron.touc
|
|||
[self updateSlider:(NSSliderTouchBarItem*)item withSettings:settings];
|
||||
} else if (item_type == "popover") {
|
||||
[self updatePopover:(NSPopoverTouchBarItem*)item withSettings:settings];
|
||||
} else if (item_type == "segmented_control")
|
||||
} else if (item_type == "segmented_control") {
|
||||
[self updateSegmentedControl:(NSCustomTouchBarItem*)item withSettings:settings];
|
||||
} else if (item_type == "scrubber") {
|
||||
[self updateScrubber:(NSCustomTouchBarItem*)item withSettings:settings];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (void)buttonAction:(id)sender {
|
||||
|
@ -177,6 +188,20 @@ static NSTouchBarItemIdentifier SegmentedControlIdentifier = @"com.electron.touc
|
|||
details);
|
||||
}
|
||||
|
||||
- (void)scrubber:(NSScrubber*)scrubber didSelectItemAtIndex:(NSInteger)selectedIndex {
|
||||
base::DictionaryValue details;
|
||||
details.SetInteger("selectedIndex", selectedIndex);
|
||||
details.SetString("type", "select");
|
||||
window_->NotifyTouchBarItemInteraction([scrubber.identifier UTF8String], details);
|
||||
}
|
||||
|
||||
- (void)scrubber:(NSScrubber*)scrubber didHighlightItemAtIndex:(NSInteger)highlightedIndex {
|
||||
base::DictionaryValue details;
|
||||
details.SetInteger("highlightedIndex", highlightedIndex);
|
||||
details.SetString("type", "highlight");
|
||||
window_->NotifyTouchBarItemInteraction([scrubber.identifier UTF8String], details);
|
||||
}
|
||||
|
||||
- (NSTouchBarItemIdentifier)identifierFromID:(const std::string&)item_id
|
||||
type:(const std::string&)type {
|
||||
NSTouchBarItemIdentifier base_identifier = nil;
|
||||
|
@ -194,6 +219,8 @@ static NSTouchBarItemIdentifier SegmentedControlIdentifier = @"com.electron.touc
|
|||
base_identifier = GroupIdentifier;
|
||||
else if (type == "segmented_control")
|
||||
base_identifier = SegmentedControlIdentifier;
|
||||
else if (type == "scrubber")
|
||||
base_identifier = ScrubberIdentifier;
|
||||
|
||||
if (base_identifier)
|
||||
return [NSString stringWithFormat:@"%@%s", base_identifier, item_id.data()];
|
||||
|
@ -467,4 +494,116 @@ static NSTouchBarItemIdentifier SegmentedControlIdentifier = @"com.electron.touc
|
|||
control.selectedSegment = selectedIndex;
|
||||
}
|
||||
|
||||
- (NSTouchBarItem*)makeScrubberForID:(NSString*)id
|
||||
withIdentifier:(NSString*)identifier {
|
||||
std::string s_id([id UTF8String]);
|
||||
if (![self hasItemWithID:s_id]) return nil;
|
||||
|
||||
mate::PersistentDictionary settings = settings_[s_id];
|
||||
base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
|
||||
@"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
|
||||
|
||||
NSScrubber* scrubber = [[[NSClassFromString(@"NSScrubber") alloc] initWithFrame:NSZeroRect] autorelease];
|
||||
|
||||
[scrubber registerClass:NSClassFromString(@"NSScrubberTextItemView") forItemIdentifier:TextScrubberItemIdentifier];
|
||||
[scrubber registerClass:NSClassFromString(@"NSScrubberImageItemView") forItemIdentifier:ImageScrubberItemIdentifier];
|
||||
|
||||
scrubber.delegate = self;
|
||||
scrubber.dataSource = self;
|
||||
scrubber.identifier = id;
|
||||
|
||||
[item setView:scrubber];
|
||||
[self updateScrubber:item withSettings:settings];
|
||||
|
||||
return item.autorelease();
|
||||
}
|
||||
|
||||
- (void)updateScrubber:(NSCustomTouchBarItem*)item
|
||||
withSettings:(const mate::PersistentDictionary&)settings {
|
||||
NSScrubber* scrubber = item.view;
|
||||
|
||||
bool showsArrowButtons = false;
|
||||
settings.Get("showArrowButtons", &showsArrowButtons);
|
||||
scrubber.showsArrowButtons = showsArrowButtons;
|
||||
|
||||
std::string selectedStyle;
|
||||
std::string overlayStyle;
|
||||
settings.Get("selectedStyle", &selectedStyle);
|
||||
settings.Get("overlayStyle", &overlayStyle);
|
||||
|
||||
if (selectedStyle == "outline") {
|
||||
scrubber.selectionBackgroundStyle = [NSClassFromString(@"NSScrubberSelectionStyle") outlineOverlayStyle];
|
||||
} else if (selectedStyle == "background") {
|
||||
scrubber.selectionBackgroundStyle = [NSClassFromString(@"NSScrubberSelectionStyle") roundedBackgroundStyle];
|
||||
} else {
|
||||
scrubber.selectionBackgroundStyle = nil;
|
||||
}
|
||||
|
||||
if (overlayStyle == "outline") {
|
||||
scrubber.selectionOverlayStyle = [NSClassFromString(@"NSScrubberSelectionStyle") outlineOverlayStyle];
|
||||
} else if (overlayStyle == "background") {
|
||||
scrubber.selectionOverlayStyle = [NSClassFromString(@"NSScrubberSelectionStyle") roundedBackgroundStyle];
|
||||
} else {
|
||||
scrubber.selectionOverlayStyle = nil;
|
||||
}
|
||||
|
||||
std::string mode;
|
||||
settings.Get("mode", &mode);
|
||||
if (mode == "fixed") {
|
||||
scrubber.mode = NSScrubberModeFixed;
|
||||
} else {
|
||||
scrubber.mode = NSScrubberModeFree;
|
||||
}
|
||||
|
||||
bool continuous = true;
|
||||
settings.Get("continuous", &continuous);
|
||||
scrubber.continuous = continuous;
|
||||
|
||||
[scrubber reloadData];
|
||||
}
|
||||
|
||||
- (NSInteger)numberOfItemsForScrubber:(NSScrubber*)scrubber {
|
||||
std::string s_id([[scrubber identifier] UTF8String]);
|
||||
if (![self hasItemWithID:s_id]) return 0;
|
||||
|
||||
mate::PersistentDictionary settings = settings_[s_id];
|
||||
std::vector<mate::PersistentDictionary> items;
|
||||
settings.Get("items", &items);
|
||||
return items.size();
|
||||
}
|
||||
|
||||
- (NSScrubberItemView*)scrubber:(NSScrubber*)scrubber
|
||||
viewForItemAtIndex:(NSInteger)index {
|
||||
std::string s_id([[scrubber identifier] UTF8String]);
|
||||
if (![self hasItemWithID:s_id]) return nil;
|
||||
|
||||
mate::PersistentDictionary settings = settings_[s_id];
|
||||
std::vector<mate::PersistentDictionary> items;
|
||||
if (!settings.Get("items", &items)) return nil;
|
||||
|
||||
if (index >= (long)items.size()) return nil;
|
||||
|
||||
mate::PersistentDictionary item = items[index];
|
||||
|
||||
NSScrubberItemView* itemView;
|
||||
std::string title;
|
||||
|
||||
if (item.Get("label", &title)) {
|
||||
NSScrubberTextItemView* view = [scrubber makeItemWithIdentifier:TextScrubberItemIdentifier
|
||||
owner:self];
|
||||
view.title = base::SysUTF8ToNSString(title);
|
||||
itemView = view;
|
||||
} else {
|
||||
NSScrubberImageItemView* view = [scrubber makeItemWithIdentifier:ImageScrubberItemIdentifier
|
||||
owner:self];
|
||||
gfx::Image image;
|
||||
if (item.Get("icon", &image)) {
|
||||
view.image = image.AsNSImage();
|
||||
}
|
||||
itemView = view;
|
||||
}
|
||||
|
||||
return itemView;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -14,13 +14,19 @@
|
|||
#pragma clang assume_nonnull begin
|
||||
|
||||
@class NSTouchBar, NSTouchBarItem;
|
||||
@protocol NSTouchBarDelegate;
|
||||
@class NSScrubber, NSScrubberItemView, NSScrubberArrangedView, NSScrubberTextItemView, NSScrubberImageItemView, NSScrubberSelectionStyle;
|
||||
@protocol NSTouchBarDelegate, NSScrubberDelegate, NSScrubberDataSource;
|
||||
|
||||
typedef float NSTouchBarItemPriority;
|
||||
static const NSTouchBarItemPriority NSTouchBarItemPriorityHigh = 1000;
|
||||
static const NSTouchBarItemPriority NSTouchBarItemPriorityNormal = 0;
|
||||
static const NSTouchBarItemPriority NSTouchBarItemPriorityLow = -1000;
|
||||
|
||||
enum NSScrubberMode {
|
||||
NSScrubberModeFixed = 0,
|
||||
NSScrubberModeFree
|
||||
};
|
||||
|
||||
typedef NSString* NSTouchBarItemIdentifier;
|
||||
typedef NSString* NSTouchBarCustomizationIdentifier;
|
||||
|
||||
|
@ -100,17 +106,17 @@ static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierOtherItemsProxy =
|
|||
|
||||
@property SEL action;
|
||||
@property(weak) id target;
|
||||
@property(copy) NSColor *color;
|
||||
@property(strong) NSColorList *colorList;
|
||||
@property(copy) NSColor* color;
|
||||
@property(strong) NSColorList* colorList;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSPopoverTouchBarItem : NSTouchBarItem
|
||||
|
||||
@property BOOL showsCloseButton;
|
||||
@property(strong) NSImage *collapsedRepresentationImage;
|
||||
@property(strong) NSString *collapsedRepresentationLabel;
|
||||
@property(strong) NSTouchBar *popoverTouchBar;
|
||||
@property(strong) NSImage* collapsedRepresentationImage;
|
||||
@property(strong) NSString* collapsedRepresentationLabel;
|
||||
@property(strong) NSTouchBar* popoverTouchBar;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -118,8 +124,54 @@ static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierOtherItemsProxy =
|
|||
|
||||
@property SEL action;
|
||||
@property(weak) id target;
|
||||
@property(copy) NSString *label;
|
||||
@property(strong) NSSlider *slider;
|
||||
@property(copy) NSString* label;
|
||||
@property(strong) NSSlider* slider;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSScrubber : NSView
|
||||
|
||||
@property(weak) id<NSScrubberDelegate> delegate;
|
||||
@property(weak) id<NSScrubberDataSource> dataSource;
|
||||
@property NSScrubberMode mode;
|
||||
@property BOOL showsArrowButtons;
|
||||
@property(getter=isContinuous) BOOL continuous;
|
||||
@property(strong, nullable) NSScrubberSelectionStyle* selectionBackgroundStyle;
|
||||
@property(strong, nullable) NSScrubberSelectionStyle* selectionOverlayStyle;
|
||||
|
||||
- (void)registerClass:(Class)itemViewClass
|
||||
forItemIdentifier:(NSString*)itemIdentifier;
|
||||
|
||||
- (__kindof NSScrubberItemView*)makeItemWithIdentifier:(NSString*)itemIdentifier
|
||||
owner:(id)owner;
|
||||
- (void)reloadData;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSScrubberSelectionStyle : NSObject<NSCoding>
|
||||
|
||||
@property(class, strong, readonly) NSScrubberSelectionStyle* outlineOverlayStyle;
|
||||
@property(class, strong, readonly) NSScrubberSelectionStyle* roundedBackgroundStyle;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSScrubberArrangedView : NSView
|
||||
|
||||
@end
|
||||
|
||||
@interface NSScrubberItemView : NSScrubberArrangedView
|
||||
|
||||
@end
|
||||
|
||||
@interface NSScrubberTextItemView : NSScrubberItemView
|
||||
|
||||
@property(copy) NSString* title;
|
||||
|
||||
@end
|
||||
|
||||
@interface NSScrubberImageItemView : NSScrubberItemView
|
||||
|
||||
@property(copy) NSImage* image;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -131,8 +183,8 @@ static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierOtherItemsProxy =
|
|||
|
||||
@interface NSButton (TouchBarSDK)
|
||||
|
||||
@property(copy) NSColor *bezelColor;
|
||||
+ (instancetype)buttonWithTitle:(NSString *)title
|
||||
@property(copy) NSColor* bezelColor;
|
||||
+ (instancetype)buttonWithTitle:(NSString*)title
|
||||
target:(id)target
|
||||
action:(SEL)action;
|
||||
|
||||
|
@ -140,7 +192,7 @@ static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierOtherItemsProxy =
|
|||
|
||||
@interface NSTextField (TouchBarSDK)
|
||||
|
||||
+ (instancetype)labelWithString:(NSString *)stringValue;
|
||||
+ (instancetype)labelWithString:(NSString*)stringValue;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -158,6 +210,22 @@ static const NSTouchBarItemIdentifier NSTouchBarItemIdentifierOtherItemsProxy =
|
|||
@optional
|
||||
- (nullable NSTouchBarItem*)touchBar:(NSTouchBar*)touchBar
|
||||
makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier;
|
||||
|
||||
@end
|
||||
|
||||
@protocol NSScrubberDelegate<NSObject>
|
||||
|
||||
- (void)scrubber:(NSScrubber*)scrubber didHighlightItemAtIndex:(NSInteger)highlightedIndex;
|
||||
- (void)scrubber:(NSScrubber*)scrubber didSelectItemAtIndex:(NSInteger)selectedIndex;
|
||||
|
||||
@end
|
||||
|
||||
@protocol NSScrubberDataSource<NSObject>
|
||||
|
||||
- (NSInteger)numberOfItemsForScrubber:(NSScrubber*)scrubber;
|
||||
- (__kindof NSScrubberItemView*)scrubber:(NSScrubber*)scrubber
|
||||
viewForItemAtIndex:(NSInteger)index;
|
||||
|
||||
@end
|
||||
|
||||
#pragma clang assume_nonnull end
|
||||
|
|
4
docs/api/structures/scrubber-item.md
Normal file
4
docs/api/structures/scrubber-item.md
Normal file
|
@ -0,0 +1,4 @@
|
|||
# ScrubberItem Object
|
||||
|
||||
* `label` String - (Optional) The text to appear in this item
|
||||
* `icon` NativeImage - (Optional) The image to appear in this item
|
65
docs/api/touch-bar-scrubber.md
Normal file
65
docs/api/touch-bar-scrubber.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
## Class: TouchBarScrubber
|
||||
|
||||
> Create a scrubber (a scrollable selector)
|
||||
|
||||
Process: [Main](../tutorial/quick-start.md#main-process)
|
||||
|
||||
### `new TouchBarScrubber(options)`
|
||||
|
||||
* `options` Object
|
||||
* `items` [ScrubberItem[]](structures/scrubber-item.md) - An array of items to place in this scrubber
|
||||
* `select` Function - Called when the user taps an item that was not the last tapped item
|
||||
* `selectedIndex` - The index of the item the user selected
|
||||
* `highlight` Function - Called when the user taps any item
|
||||
* `highlightedIndex` - The index of the item the user touched
|
||||
* `selectedStyle` String - Selected item style. Defaults to `null`.
|
||||
* `overlayStyle` String - Selected overlay item style. Defaults to `null`.
|
||||
* `showArrowButtons` Boolean - Defaults to `false`.
|
||||
* `mode` String - Defaults to `free`.
|
||||
* `continuous` Boolean - Defaults to `true`.
|
||||
|
||||
### Instance Properties
|
||||
|
||||
The following properties are available on instances of `TouchBarScrubber`:
|
||||
|
||||
#### `touchBarSegmentedControl.items`
|
||||
|
||||
A `ScrubberItem[]` array representing the items in this scrubber. Updating this value immediately
|
||||
updates the control in the touch bar. Updating deep properties inside this array **does not update the touch bar**.
|
||||
|
||||
#### `touchBarSegmentedControl.selectedStyle`
|
||||
|
||||
A `String` representing the style that selected items in the scrubber should have. Updating this value immediately
|
||||
updates the control in the touch bar. Possible values:
|
||||
|
||||
* `background` - Maps to `[NSScrubberSelectionStyle roundedBackgroundStyle]`
|
||||
* `outline` - Maps to `[NSScrubberSelectionStyle outlineOverlayStyle]`
|
||||
* `null` - Actually null, not a string, removes all styles
|
||||
|
||||
#### `touchBarSegmentedControl.overlayStyle`
|
||||
|
||||
A `String` representing the style that selected items in the scrubber should have. This style is overlayed on top
|
||||
of the scrubber item instead of being placed behind it. Updating this value immediately updates the control in the
|
||||
touch bar. Possible values:
|
||||
|
||||
* `background` - Maps to `[NSScrubberSelectionStyle roundedBackgroundStyle]`
|
||||
* `outline` - Maps to `[NSScrubberSelectionStyle outlineOverlayStyle]`
|
||||
* `null` - Actually null, not a string, removes all styles
|
||||
|
||||
#### `touchBarSegmentedControl.showArrowButtons`
|
||||
|
||||
A `Boolean` representing whether to show the left / right selection arrows in this scrubber. Updating this value
|
||||
immediately updates the control in the touch bar.
|
||||
|
||||
#### `touchBarSegmentedControl.mode`
|
||||
|
||||
A `String` representing the mode of this scrubber. Updating this value immediately
|
||||
updates the control in the touch bar. Possible values:
|
||||
|
||||
* `fixed` - Maps to `NSScrubberModeFixed`
|
||||
* `free` - Maps to `NSScrubberModeFree`
|
||||
|
||||
#### `touchBarSegmentedControl.continuous`
|
||||
|
||||
A `Boolean` representing whether this scrubber is continuous or not. Updating this value immediately
|
||||
updates the control in the touch bar.
|
|
@ -231,4 +231,32 @@ TouchBar.TouchBarSegmentedControl = class TouchBarSegmentedControl extends Touch
|
|||
}
|
||||
}
|
||||
|
||||
TouchBar.TouchBarScrubber = class TouchBarScrubber extends TouchBarItem {
|
||||
constructor (config) {
|
||||
super()
|
||||
if (config == null) config = {}
|
||||
const {items, selectedStyle, overlayStyle, showArrowButtons, continuous, mode} = config
|
||||
let {select, highlight} = config
|
||||
this.type = 'scrubber'
|
||||
this._addLiveProperty('items', items)
|
||||
this._addLiveProperty('selectedStyle', selectedStyle || null)
|
||||
this._addLiveProperty('overlayStyle', overlayStyle || null)
|
||||
this._addLiveProperty('showArrowButtons', showArrowButtons || false)
|
||||
this._addLiveProperty('mode', mode || 'free')
|
||||
this._addLiveProperty('continuous', continuous || true)
|
||||
|
||||
if (typeof select === 'function' || typeof highlight === 'function') {
|
||||
if (select == null) select = () => {}
|
||||
if (highlight == null) highlight = () => {}
|
||||
this.onInteraction = (details) => {
|
||||
if (details.type === 'select') {
|
||||
select(details.selectedIndex)
|
||||
} else if (details.type === 'highlight') {
|
||||
highlight(details.highlightedIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = TouchBar
|
||||
|
|
|
@ -3,7 +3,7 @@ const {BrowserWindow, TouchBar} = require('electron').remote
|
|||
const {closeWindow} = require('./window-helpers')
|
||||
|
||||
const {TouchBarButton, TouchBarColorPicker, TouchBarGroup} = TouchBar
|
||||
const {TouchBarLabel, TouchBarPopover, TouchBarSegmentedControl, TouchBarSlider, TouchBarSpacer} = TouchBar
|
||||
const {TouchBarLabel, TouchBarPopover, TouchBarScrubber, TouchBarSegmentedControl, TouchBarSlider, TouchBarSpacer} = TouchBar
|
||||
|
||||
describe('TouchBar module', function () {
|
||||
it('throws an error when created without an items array', function () {
|
||||
|
@ -47,7 +47,13 @@ describe('TouchBar module', function () {
|
|||
segments: [{label: 'baz', enabled: false}],
|
||||
selectedIndex: 5
|
||||
}),
|
||||
new TouchBarSegmentedControl({segments: []})
|
||||
new TouchBarSegmentedControl({segments: []}),
|
||||
new TouchBarScrubber({
|
||||
items: [{label: 'foo'}, {label: 'bar'}, {label: 'baz'}],
|
||||
selectedStyle: 'outline',
|
||||
mode: 'fixed',
|
||||
showArrowButtons: true
|
||||
})
|
||||
])
|
||||
window.setTouchBar(touchBar)
|
||||
label.label = 'baz'
|
||||
|
|
Loading…
Reference in a new issue