зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1563349 - Part 5 - Support NSScrollView in the Touch Bar. r=spohl
Differential Revision: https://phabricator.services.mozilla.com/D47622 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
525bd39f48
Коммит
fc5596715d
|
@ -103,6 +103,13 @@ using namespace mozilla::dom;
|
||||||
*/
|
*/
|
||||||
@property(strong) NSMutableDictionary<NSTouchBarItemIdentifier, TouchBarInput*>* mappedLayoutItems;
|
@property(strong) NSMutableDictionary<NSTouchBarItemIdentifier, TouchBarInput*>* mappedLayoutItems;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores buttons displayed in a NSScrollView. They must be stored separately
|
||||||
|
* because they are generic NSButtons and not NSTouchBarItems. As such, they
|
||||||
|
* cannot be retrieved with [NSTouchBar itemForIdentifier].
|
||||||
|
*/
|
||||||
|
@property(strong) NSMutableDictionary<NSTouchBarItemIdentifier, NSButton*>* scrollViewButtons;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns an instance of nsTouchBar based on implementation details
|
* Returns an instance of nsTouchBar based on implementation details
|
||||||
* fetched from the frontend through nsTouchBarHelper.
|
* fetched from the frontend through nsTouchBarHelper.
|
||||||
|
@ -140,6 +147,12 @@ using namespace mozilla::dom;
|
||||||
*/
|
*/
|
||||||
- (bool)maybeUpdatePopoverChild:(TouchBarInput*)aInput;
|
- (bool)maybeUpdatePopoverChild:(TouchBarInput*)aInput;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Helper function for updateItem. Checks to see if a given input exists within
|
||||||
|
* any of this Touch Bar's scroll views and updates it if it exists.
|
||||||
|
*/
|
||||||
|
- (bool)maybeUpdateScrollViewChild:(TouchBarInput*)aInput;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function for updateItem. Replaces an item in the
|
* Helper function for updateItem. Replaces an item in the
|
||||||
* self.mappedLayoutItems dictionary.
|
* self.mappedLayoutItems dictionary.
|
||||||
|
@ -152,6 +165,7 @@ using namespace mozilla::dom;
|
||||||
- (void)updateButton:(NSButton*)aButton input:(TouchBarInput*)aInput;
|
- (void)updateButton:(NSButton*)aButton input:(TouchBarInput*)aInput;
|
||||||
- (void)updateMainButton:(NSButton*)aMainButton input:(TouchBarInput*)aInput;
|
- (void)updateMainButton:(NSButton*)aMainButton input:(TouchBarInput*)aInput;
|
||||||
- (void)updatePopover:(NSPopoverTouchBarItem*)aPopoverItem input:(TouchBarInput*)aInput;
|
- (void)updatePopover:(NSPopoverTouchBarItem*)aPopoverItem input:(TouchBarInput*)aInput;
|
||||||
|
- (void)updateScrollView:(NSCustomTouchBarItem*)aScrollViewItem input:(TouchBarInput*)aInput;
|
||||||
- (NSTouchBarItem*)makeShareScrubberForIdentifier:(NSTouchBarItemIdentifier)aIdentifier;
|
- (NSTouchBarItem*)makeShareScrubberForIdentifier:(NSTouchBarItemIdentifier)aIdentifier;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -27,8 +27,16 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
||||||
@"mainButton",
|
@"mainButton",
|
||||||
@"scrubber",
|
@"scrubber",
|
||||||
@"popover",
|
@"popover",
|
||||||
|
@"scrollView",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// The default space between inputs, used where layout is not automatic.
|
||||||
|
static const uint32_t kInputSpacing = 8;
|
||||||
|
// The width of buttons in Apple's Share ScrollView. We use this in our
|
||||||
|
// ScrollViews to give them a native appearance.
|
||||||
|
static const uint32_t kScrollViewButtonWidth = 144;
|
||||||
|
static const uint32_t kInputIconSize = 16;
|
||||||
|
|
||||||
// The system default width for Touch Bar inputs is 128px. This is double.
|
// The system default width for Touch Bar inputs is 128px. This is double.
|
||||||
#define MAIN_BUTTON_WIDTH 256
|
#define MAIN_BUTTON_WIDTH 256
|
||||||
|
|
||||||
|
@ -114,6 +122,9 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
||||||
[(NSPopoverTouchBarItem*)item setCollapsedRepresentation:nil];
|
[(NSPopoverTouchBarItem*)item setCollapsedRepresentation:nil];
|
||||||
[(NSPopoverTouchBarItem*)item setCollapsedRepresentationImage:nil];
|
[(NSPopoverTouchBarItem*)item setCollapsedRepresentationImage:nil];
|
||||||
[(nsTouchBar*)[(NSPopoverTouchBarItem*)item popoverTouchBar] release];
|
[(nsTouchBar*)[(NSPopoverTouchBarItem*)item popoverTouchBar] release];
|
||||||
|
} else if ([[item view] isKindOfClass:[NSScrollView class]]) {
|
||||||
|
[[(NSScrollView*)[item view] documentView] release];
|
||||||
|
[(NSScrollView*)[item view] release];
|
||||||
}
|
}
|
||||||
|
|
||||||
[item release];
|
[item release];
|
||||||
|
@ -121,6 +132,8 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
||||||
|
|
||||||
[self.defaultItemIdentifiers release];
|
[self.defaultItemIdentifiers release];
|
||||||
[self.customizationAllowedItemIdentifiers release];
|
[self.customizationAllowedItemIdentifiers release];
|
||||||
|
[self.scrollViewButtons removeAllObjects];
|
||||||
|
[self.scrollViewButtons release];
|
||||||
[self.mappedLayoutItems removeAllObjects];
|
[self.mappedLayoutItems removeAllObjects];
|
||||||
[self.mappedLayoutItems release];
|
[self.mappedLayoutItems release];
|
||||||
[super dealloc];
|
[super dealloc];
|
||||||
|
@ -163,21 +176,35 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
||||||
// Our new item, which will be initialized depending on aIdentifier.
|
// Our new item, which will be initialized depending on aIdentifier.
|
||||||
NSCustomTouchBarItem* newItem = [[NSCustomTouchBarItem alloc] initWithIdentifier:aIdentifier];
|
NSCustomTouchBarItem* newItem = [[NSCustomTouchBarItem alloc] initWithIdentifier:aIdentifier];
|
||||||
|
|
||||||
|
if ([[input type] hasSuffix:@"scrollView"]) {
|
||||||
|
[self updateScrollView:newItem input:input];
|
||||||
|
return newItem;
|
||||||
|
}
|
||||||
|
|
||||||
// The cases of a button or main button require the same setup.
|
// The cases of a button or main button require the same setup.
|
||||||
NSButton* button = [NSButton buttonWithTitle:@"" target:self action:@selector(touchBarAction:)];
|
NSButton* button = [NSButton buttonWithTitle:@"" target:self action:@selector(touchBarAction:)];
|
||||||
newItem.view = button;
|
newItem.view = button;
|
||||||
|
|
||||||
if ([[input type] hasSuffix:@"mainButton"]) {
|
if ([[input type] hasSuffix:@"button"] && ![[input type] hasPrefix:@"scrollView"]) {
|
||||||
|
[self updateButton:button input:input];
|
||||||
|
} else if ([[input type] hasSuffix:@"mainButton"]) {
|
||||||
[self updateMainButton:button input:input];
|
[self updateMainButton:button input:input];
|
||||||
return newItem;
|
|
||||||
}
|
}
|
||||||
[self updateButton:button input:input];
|
|
||||||
return newItem;
|
return newItem;
|
||||||
}
|
}
|
||||||
|
|
||||||
- (bool)updateItem:(TouchBarInput*)aInput {
|
- (bool)updateItem:(TouchBarInput*)aInput {
|
||||||
NSTouchBarItem* item = [self itemForIdentifier:[aInput nativeIdentifier]];
|
NSTouchBarItem* item = [self itemForIdentifier:[aInput nativeIdentifier]];
|
||||||
|
// If we can't immediately find item, there are three possibilities:
|
||||||
|
// * It is a button in a ScrollView, which can't be found with itemForIdentifier; or
|
||||||
|
// * It is contained within a popover; or
|
||||||
|
// * It simply does not exist.
|
||||||
|
// We check for each possibility here.
|
||||||
if (!item) {
|
if (!item) {
|
||||||
|
if ([self maybeUpdateScrollViewChild:aInput]) {
|
||||||
|
[self replaceMappedLayoutItem:aInput];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
if ([self maybeUpdatePopoverChild:aInput]) {
|
if ([self maybeUpdatePopoverChild:aInput]) {
|
||||||
[self replaceMappedLayoutItem:aInput];
|
[self replaceMappedLayoutItem:aInput];
|
||||||
return true;
|
return true;
|
||||||
|
@ -191,6 +218,9 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
||||||
} else if ([[aInput type] hasSuffix:@"mainButton"]) {
|
} else if ([[aInput type] hasSuffix:@"mainButton"]) {
|
||||||
[(NSCustomTouchBarItem*)item setCustomizationLabel:[aInput title]];
|
[(NSCustomTouchBarItem*)item setCustomizationLabel:[aInput title]];
|
||||||
[self updateMainButton:(NSButton*)item.view input:aInput];
|
[self updateMainButton:(NSButton*)item.view input:aInput];
|
||||||
|
} else if ([[aInput type] hasSuffix:@"scrollView"]) {
|
||||||
|
[(NSCustomTouchBarItem*)item setCustomizationLabel:[aInput title]];
|
||||||
|
[self updateScrollView:(NSCustomTouchBarItem*)item input:aInput];
|
||||||
} else if ([[aInput type] hasSuffix:@"popover"]) {
|
} else if ([[aInput type] hasSuffix:@"popover"]) {
|
||||||
[(NSPopoverTouchBarItem*)item setCustomizationLabel:[aInput title]];
|
[(NSPopoverTouchBarItem*)item setCustomizationLabel:[aInput title]];
|
||||||
[self updatePopover:(NSPopoverTouchBarItem*)item input:aInput];
|
[self updatePopover:(NSPopoverTouchBarItem*)item input:aInput];
|
||||||
|
@ -216,6 +246,35 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (bool)maybeUpdateScrollViewChild:(TouchBarInput*)aInput {
|
||||||
|
NSButton* scrollViewButton = self.scrollViewButtons[[aInput nativeIdentifier]];
|
||||||
|
if (scrollViewButton) {
|
||||||
|
// ScrollView buttons are similar to mainButtons except for their width.
|
||||||
|
[self updateMainButton:scrollViewButton input:aInput];
|
||||||
|
uint32_t buttonSize =
|
||||||
|
MAX(scrollViewButton.attributedTitle.size.width + kInputIconSize + kInputSpacing,
|
||||||
|
kScrollViewButtonWidth);
|
||||||
|
[[scrollViewButton widthAnchor] constraintGreaterThanOrEqualToConstant:buttonSize].active = YES;
|
||||||
|
}
|
||||||
|
// Updating the TouchBarInput* in the ScrollView's mChildren array.
|
||||||
|
for (NSTouchBarItemIdentifier identifier in self.mappedLayoutItems) {
|
||||||
|
TouchBarInput* potentialScrollView = self.mappedLayoutItems[identifier];
|
||||||
|
if (![[potentialScrollView type] hasSuffix:@"scrollView"]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
for (uint32_t i = 0; i < [[potentialScrollView children] count]; ++i) {
|
||||||
|
TouchBarInput* child = [potentialScrollView children][i];
|
||||||
|
if (![[child nativeIdentifier] isEqualToString:[aInput nativeIdentifier]]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
[[potentialScrollView children] replaceObjectAtIndex:i withObject:aInput];
|
||||||
|
[child release];
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
- (void)replaceMappedLayoutItem:(TouchBarInput*)aItem {
|
- (void)replaceMappedLayoutItem:(TouchBarInput*)aItem {
|
||||||
[self.mappedLayoutItems[[aItem nativeIdentifier]] release];
|
[self.mappedLayoutItems[[aItem nativeIdentifier]] release];
|
||||||
self.mappedLayoutItems[[aItem nativeIdentifier]] = aItem;
|
self.mappedLayoutItems[[aItem nativeIdentifier]] = aItem;
|
||||||
|
@ -288,6 +347,59 @@ static const NSArray<NSString*>* kAllowedInputTypes = @[
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)updateScrollView:(NSCustomTouchBarItem*)aScrollViewItem input:(TouchBarInput*)aInput {
|
||||||
|
if (!aScrollViewItem || ![aInput children]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
NSMutableDictionary* constraintViews = [NSMutableDictionary dictionary];
|
||||||
|
NSView* documentView = [[NSView alloc] initWithFrame:NSZeroRect];
|
||||||
|
NSString* layoutFormat = @"H:|-8-";
|
||||||
|
NSSize size = NSMakeSize(kInputSpacing, 30);
|
||||||
|
// Layout strings allow only alphanumeric characters. We will use this
|
||||||
|
// NSCharacterSet to strip illegal characters.
|
||||||
|
NSCharacterSet* charactersToRemove = [[NSCharacterSet alphanumericCharacterSet] invertedSet];
|
||||||
|
|
||||||
|
for (TouchBarInput* childInput in [aInput children]) {
|
||||||
|
if (![[childInput type] hasSuffix:@"button"]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
NSButton* button = [NSButton buttonWithTitle:[childInput title]
|
||||||
|
target:self
|
||||||
|
action:@selector(touchBarAction:)];
|
||||||
|
// ScrollView buttons are similar to mainButtons except for their width.
|
||||||
|
[self updateMainButton:button input:childInput];
|
||||||
|
uint32_t buttonSize = MAX(button.attributedTitle.size.width + kInputIconSize + kInputSpacing,
|
||||||
|
kScrollViewButtonWidth);
|
||||||
|
[[button widthAnchor] constraintGreaterThanOrEqualToConstant:buttonSize].active = YES;
|
||||||
|
|
||||||
|
self.scrollViewButtons[[childInput nativeIdentifier]] = button;
|
||||||
|
|
||||||
|
button.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
|
[documentView addSubview:button];
|
||||||
|
NSString* layoutKey = [[[childInput nativeIdentifier]
|
||||||
|
componentsSeparatedByCharactersInSet:charactersToRemove] componentsJoinedByString:@""];
|
||||||
|
|
||||||
|
// Iteratively create our layout string.
|
||||||
|
layoutFormat =
|
||||||
|
[layoutFormat stringByAppendingString:[NSString stringWithFormat:@"[%@]-8-", layoutKey]];
|
||||||
|
[constraintViews setObject:button forKey:layoutKey];
|
||||||
|
size.width += kInputSpacing + buttonSize;
|
||||||
|
}
|
||||||
|
layoutFormat = [layoutFormat stringByAppendingString:[NSString stringWithFormat:@"|"]];
|
||||||
|
NSArray* hConstraints =
|
||||||
|
[NSLayoutConstraint constraintsWithVisualFormat:layoutFormat
|
||||||
|
options:NSLayoutFormatAlignAllCenterY
|
||||||
|
metrics:nil
|
||||||
|
views:constraintViews];
|
||||||
|
NSScrollView* scrollView =
|
||||||
|
[[NSScrollView alloc] initWithFrame:CGRectMake(0, 0, size.width, size.height)];
|
||||||
|
[documentView setFrame:NSMakeRect(0, 0, size.width, size.height)];
|
||||||
|
[NSLayoutConstraint activateConstraints:hConstraints];
|
||||||
|
scrollView.documentView = documentView;
|
||||||
|
|
||||||
|
aScrollViewItem.view = scrollView;
|
||||||
|
}
|
||||||
|
|
||||||
- (NSTouchBarItem*)makeShareScrubberForIdentifier:(NSTouchBarItemIdentifier)aIdentifier {
|
- (NSTouchBarItem*)makeShareScrubberForIdentifier:(NSTouchBarItemIdentifier)aIdentifier {
|
||||||
TouchBarInput* input = self.mappedLayoutItems[aIdentifier];
|
TouchBarInput* input = self.mappedLayoutItems[aIdentifier];
|
||||||
// System-default share menu
|
// System-default share menu
|
||||||
|
|
Загрузка…
Ссылка в новой задаче