Merge pull request #8910 from electron/touchbar-scrubber

Touchbar NSScrubber
This commit is contained in:
Kevin Sawicki 2017-03-16 09:10:59 -07:00 committed by GitHub
commit da0d0e7aac
7 changed files with 325 additions and 15 deletions

View file

@ -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_;

View file

@ -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

View file

@ -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

View 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

View 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.

View file

@ -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

View file

@ -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'