atom_touch_bar.mm 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813
  1. // Copyright (c) 2017 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #import "atom/browser/ui/cocoa/atom_touch_bar.h"
  5. #include "atom/common/color_util.h"
  6. #include "atom/common/native_mate_converters/image_converter.h"
  7. #include "base/strings/sys_string_conversions.h"
  8. #include "skia/ext/skia_utils_mac.h"
  9. #include "ui/gfx/image/image.h"
  10. @implementation AtomTouchBar
  11. static NSTouchBarItemIdentifier ButtonIdentifier =
  12. @"com.electron.touchbar.button.";
  13. static NSTouchBarItemIdentifier ColorPickerIdentifier =
  14. @"com.electron.touchbar.colorpicker.";
  15. static NSTouchBarItemIdentifier GroupIdentifier =
  16. @"com.electron.touchbar.group.";
  17. static NSTouchBarItemIdentifier LabelIdentifier =
  18. @"com.electron.touchbar.label.";
  19. static NSTouchBarItemIdentifier PopoverIdentifier =
  20. @"com.electron.touchbar.popover.";
  21. static NSTouchBarItemIdentifier SliderIdentifier =
  22. @"com.electron.touchbar.slider.";
  23. static NSTouchBarItemIdentifier SegmentedControlIdentifier =
  24. @"com.electron.touchbar.segmentedcontrol.";
  25. static NSTouchBarItemIdentifier ScrubberIdentifier =
  26. @"com.electron.touchbar.scrubber.";
  27. static NSString* const TextScrubberItemIdentifier = @"scrubber.text.item";
  28. static NSString* const ImageScrubberItemIdentifier = @"scrubber.image.item";
  29. - (id)initWithDelegate:(id<NSTouchBarDelegate>)delegate
  30. window:(atom::NativeWindow*)window
  31. settings:
  32. (const std::vector<mate::PersistentDictionary>&)settings {
  33. if ((self = [super init])) {
  34. delegate_ = delegate;
  35. window_ = window;
  36. ordered_settings_ = settings;
  37. }
  38. return self;
  39. }
  40. - (NSTouchBar*)makeTouchBar {
  41. NSMutableArray* identifiers =
  42. [self identifiersFromSettings:ordered_settings_];
  43. return [self touchBarFromItemIdentifiers:identifiers];
  44. }
  45. - (NSTouchBar*)touchBarFromItemIdentifiers:(NSMutableArray*)items {
  46. base::scoped_nsobject<NSTouchBar> bar(
  47. [[NSClassFromString(@"NSTouchBar") alloc] init]);
  48. [bar setDelegate:delegate_];
  49. [bar setDefaultItemIdentifiers:items];
  50. return bar.autorelease();
  51. }
  52. - (NSMutableArray*)identifiersFromSettings:
  53. (const std::vector<mate::PersistentDictionary>&)dicts {
  54. NSMutableArray* identifiers = [NSMutableArray array];
  55. if (@available(macOS 10.12.2, *)) {
  56. for (const auto& item : dicts) {
  57. std::string type;
  58. std::string item_id;
  59. if (item.Get("type", &type) && item.Get("id", &item_id)) {
  60. NSTouchBarItemIdentifier identifier = nil;
  61. if (type == "spacer") {
  62. std::string size;
  63. item.Get("size", &size);
  64. if (size == "large") {
  65. identifier = NSTouchBarItemIdentifierFixedSpaceLarge;
  66. } else if (size == "flexible") {
  67. identifier = NSTouchBarItemIdentifierFlexibleSpace;
  68. } else {
  69. identifier = NSTouchBarItemIdentifierFixedSpaceSmall;
  70. }
  71. } else {
  72. identifier = [self identifierFromID:item_id type:type];
  73. }
  74. if (identifier) {
  75. settings_[item_id] = item;
  76. [identifiers addObject:identifier];
  77. }
  78. }
  79. }
  80. [identifiers addObject:NSTouchBarItemIdentifierOtherItemsProxy];
  81. }
  82. return identifiers;
  83. }
  84. - (NSTouchBarItem*)makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier {
  85. NSString* item_id = nil;
  86. if ([identifier hasPrefix:ButtonIdentifier]) {
  87. item_id = [self idFromIdentifier:identifier withPrefix:ButtonIdentifier];
  88. return [self makeButtonForID:item_id withIdentifier:identifier];
  89. } else if ([identifier hasPrefix:LabelIdentifier]) {
  90. item_id = [self idFromIdentifier:identifier withPrefix:LabelIdentifier];
  91. return [self makeLabelForID:item_id withIdentifier:identifier];
  92. } else if ([identifier hasPrefix:ColorPickerIdentifier]) {
  93. item_id =
  94. [self idFromIdentifier:identifier withPrefix:ColorPickerIdentifier];
  95. return [self makeColorPickerForID:item_id withIdentifier:identifier];
  96. } else if ([identifier hasPrefix:SliderIdentifier]) {
  97. item_id = [self idFromIdentifier:identifier withPrefix:SliderIdentifier];
  98. return [self makeSliderForID:item_id withIdentifier:identifier];
  99. } else if ([identifier hasPrefix:PopoverIdentifier]) {
  100. item_id = [self idFromIdentifier:identifier withPrefix:PopoverIdentifier];
  101. return [self makePopoverForID:item_id withIdentifier:identifier];
  102. } else if ([identifier hasPrefix:GroupIdentifier]) {
  103. item_id = [self idFromIdentifier:identifier withPrefix:GroupIdentifier];
  104. return [self makeGroupForID:item_id withIdentifier:identifier];
  105. } else if ([identifier hasPrefix:SegmentedControlIdentifier]) {
  106. item_id = [self idFromIdentifier:identifier
  107. withPrefix:SegmentedControlIdentifier];
  108. return [self makeSegmentedControlForID:item_id withIdentifier:identifier];
  109. } else if ([identifier hasPrefix:ScrubberIdentifier]) {
  110. item_id = [self idFromIdentifier:identifier withPrefix:ScrubberIdentifier];
  111. return [self makeScrubberForID:item_id withIdentifier:identifier];
  112. }
  113. return nil;
  114. }
  115. - (void)refreshTouchBarItem:(NSTouchBar*)touchBar
  116. id:(NSTouchBarItemIdentifier)identifier
  117. withType:(const std::string&)item_type
  118. withSettings:(const mate::PersistentDictionary&)settings
  119. API_AVAILABLE(macosx(10.12.2)) {
  120. NSTouchBarItem* item = [touchBar itemForIdentifier:identifier];
  121. if (!item)
  122. return;
  123. if (item_type == "button") {
  124. [self updateButton:(NSCustomTouchBarItem*)item withSettings:settings];
  125. } else if (item_type == "label") {
  126. [self updateLabel:(NSCustomTouchBarItem*)item withSettings:settings];
  127. } else if (item_type == "colorpicker") {
  128. [self updateColorPicker:(NSColorPickerTouchBarItem*)item
  129. withSettings:settings];
  130. } else if (item_type == "slider") {
  131. [self updateSlider:(NSSliderTouchBarItem*)item withSettings:settings];
  132. } else if (item_type == "popover") {
  133. [self updatePopover:(NSPopoverTouchBarItem*)item withSettings:settings];
  134. } else if (item_type == "segmented_control") {
  135. [self updateSegmentedControl:(NSCustomTouchBarItem*)item
  136. withSettings:settings];
  137. } else if (item_type == "scrubber") {
  138. [self updateScrubber:(NSCustomTouchBarItem*)item withSettings:settings];
  139. } else if (item_type == "group") {
  140. [self updateGroup:(NSGroupTouchBarItem*)item withSettings:settings];
  141. }
  142. }
  143. - (void)addNonDefaultTouchBarItems:
  144. (const std::vector<mate::PersistentDictionary>&)items {
  145. [self identifiersFromSettings:items];
  146. }
  147. - (void)setEscapeTouchBarItem:(const mate::PersistentDictionary&)item
  148. forTouchBar:(NSTouchBar*)touchBar {
  149. if (![touchBar
  150. respondsToSelector:@selector(escapeKeyReplacementItemIdentifier)])
  151. return;
  152. std::string type;
  153. std::string item_id;
  154. NSTouchBarItemIdentifier identifier = nil;
  155. if (item.Get("type", &type) && item.Get("id", &item_id)) {
  156. identifier = [self identifierFromID:item_id type:type];
  157. }
  158. if (identifier) {
  159. [self addNonDefaultTouchBarItems:{item}];
  160. touchBar.escapeKeyReplacementItemIdentifier = identifier;
  161. } else {
  162. touchBar.escapeKeyReplacementItemIdentifier = nil;
  163. }
  164. }
  165. - (void)refreshTouchBarItem:(NSTouchBar*)touchBar
  166. id:(const std::string&)item_id {
  167. if (![self hasItemWithID:item_id])
  168. return;
  169. mate::PersistentDictionary settings = settings_[item_id];
  170. std::string item_type;
  171. settings.Get("type", &item_type);
  172. auto identifier = [self identifierFromID:item_id type:item_type];
  173. if (!identifier)
  174. return;
  175. std::vector<mate::Dictionary> parents;
  176. settings.Get("_parents", &parents);
  177. for (auto& parent : parents) {
  178. std::string parent_type;
  179. std::string parent_id;
  180. if (!parent.Get("type", &parent_type) || !parent.Get("id", &parent_id))
  181. continue;
  182. auto parentIdentifier = [self identifierFromID:parent_id type:parent_type];
  183. if (!parentIdentifier)
  184. continue;
  185. if (parent_type == "popover") {
  186. NSPopoverTouchBarItem* popoverItem =
  187. [touchBar itemForIdentifier:parentIdentifier];
  188. [self refreshTouchBarItem:popoverItem.popoverTouchBar
  189. id:identifier
  190. withType:item_type
  191. withSettings:settings];
  192. } else if (parent_type == "group") {
  193. NSGroupTouchBarItem* groupItem =
  194. [touchBar itemForIdentifier:parentIdentifier];
  195. [self refreshTouchBarItem:groupItem.groupTouchBar
  196. id:identifier
  197. withType:item_type
  198. withSettings:settings];
  199. }
  200. }
  201. [self refreshTouchBarItem:touchBar
  202. id:identifier
  203. withType:item_type
  204. withSettings:settings];
  205. }
  206. - (void)buttonAction:(id)sender {
  207. NSString* item_id =
  208. [NSString stringWithFormat:@"%ld", ((NSButton*)sender).tag];
  209. window_->NotifyTouchBarItemInteraction([item_id UTF8String],
  210. base::DictionaryValue());
  211. }
  212. - (void)colorPickerAction:(id)sender {
  213. NSString* identifier = ((NSColorPickerTouchBarItem*)sender).identifier;
  214. NSString* item_id =
  215. [self idFromIdentifier:identifier withPrefix:ColorPickerIdentifier];
  216. NSColor* color = ((NSColorPickerTouchBarItem*)sender).color;
  217. std::string hex_color = atom::ToRGBHex(skia::NSDeviceColorToSkColor(color));
  218. base::DictionaryValue details;
  219. details.SetString("color", hex_color);
  220. window_->NotifyTouchBarItemInteraction([item_id UTF8String], details);
  221. }
  222. - (void)sliderAction:(id)sender {
  223. NSString* identifier = ((NSSliderTouchBarItem*)sender).identifier;
  224. NSString* item_id =
  225. [self idFromIdentifier:identifier withPrefix:SliderIdentifier];
  226. base::DictionaryValue details;
  227. details.SetInteger("value",
  228. [((NSSliderTouchBarItem*)sender).slider intValue]);
  229. window_->NotifyTouchBarItemInteraction([item_id UTF8String], details);
  230. }
  231. - (NSString*)idFromIdentifier:(NSString*)identifier
  232. withPrefix:(NSString*)prefix {
  233. return [identifier substringFromIndex:[prefix length]];
  234. }
  235. - (void)segmentedControlAction:(id)sender {
  236. NSString* item_id =
  237. [NSString stringWithFormat:@"%ld", ((NSSegmentedControl*)sender).tag];
  238. base::DictionaryValue details;
  239. details.SetInteger("selectedIndex",
  240. ((NSSegmentedControl*)sender).selectedSegment);
  241. details.SetBoolean(
  242. "isSelected",
  243. [((NSSegmentedControl*)sender)
  244. isSelectedForSegment:((NSSegmentedControl*)sender).selectedSegment]);
  245. window_->NotifyTouchBarItemInteraction([item_id UTF8String], details);
  246. }
  247. - (void)scrubber:(NSScrubber*)scrubber
  248. didSelectItemAtIndex:(NSInteger)selectedIndex
  249. API_AVAILABLE(macosx(10.12.2)) {
  250. base::DictionaryValue details;
  251. details.SetInteger("selectedIndex", selectedIndex);
  252. details.SetString("type", "select");
  253. window_->NotifyTouchBarItemInteraction([scrubber.identifier UTF8String],
  254. details);
  255. }
  256. - (void)scrubber:(NSScrubber*)scrubber
  257. didHighlightItemAtIndex:(NSInteger)highlightedIndex
  258. API_AVAILABLE(macosx(10.12.2)) {
  259. base::DictionaryValue details;
  260. details.SetInteger("highlightedIndex", highlightedIndex);
  261. details.SetString("type", "highlight");
  262. window_->NotifyTouchBarItemInteraction([scrubber.identifier UTF8String],
  263. details);
  264. }
  265. - (NSTouchBarItemIdentifier)identifierFromID:(const std::string&)item_id
  266. type:(const std::string&)type {
  267. NSTouchBarItemIdentifier base_identifier = nil;
  268. if (type == "button")
  269. base_identifier = ButtonIdentifier;
  270. else if (type == "label")
  271. base_identifier = LabelIdentifier;
  272. else if (type == "colorpicker")
  273. base_identifier = ColorPickerIdentifier;
  274. else if (type == "slider")
  275. base_identifier = SliderIdentifier;
  276. else if (type == "popover")
  277. base_identifier = PopoverIdentifier;
  278. else if (type == "group")
  279. base_identifier = GroupIdentifier;
  280. else if (type == "segmented_control")
  281. base_identifier = SegmentedControlIdentifier;
  282. else if (type == "scrubber")
  283. base_identifier = ScrubberIdentifier;
  284. if (base_identifier)
  285. return [NSString stringWithFormat:@"%@%s", base_identifier, item_id.data()];
  286. else
  287. return nil;
  288. }
  289. - (bool)hasItemWithID:(const std::string&)item_id {
  290. return settings_.find(item_id) != settings_.end();
  291. }
  292. - (NSColor*)colorFromHexColorString:(const std::string&)colorString {
  293. SkColor color = atom::ParseHexColor(colorString);
  294. return skia::SkColorToDeviceNSColor(color);
  295. }
  296. - (NSTouchBarItem*)makeButtonForID:(NSString*)id
  297. withIdentifier:(NSString*)identifier {
  298. std::string s_id([id UTF8String]);
  299. if (![self hasItemWithID:s_id])
  300. return nil;
  301. mate::PersistentDictionary settings = settings_[s_id];
  302. base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
  303. @"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
  304. NSButton* button = [NSButton buttonWithTitle:@""
  305. target:self
  306. action:@selector(buttonAction:)];
  307. button.tag = [id floatValue];
  308. [item setView:button];
  309. [self updateButton:item withSettings:settings];
  310. return item.autorelease();
  311. }
  312. - (void)updateButton:(NSCustomTouchBarItem*)item
  313. withSettings:(const mate::PersistentDictionary&)settings {
  314. NSButton* button = (NSButton*)item.view;
  315. std::string backgroundColor;
  316. if (settings.Get("backgroundColor", &backgroundColor)) {
  317. button.bezelColor = [self colorFromHexColorString:backgroundColor];
  318. }
  319. std::string label;
  320. settings.Get("label", &label);
  321. button.title = base::SysUTF8ToNSString(label);
  322. gfx::Image image;
  323. if (settings.Get("icon", &image)) {
  324. button.image = image.AsNSImage();
  325. std::string iconPosition;
  326. settings.Get("iconPosition", &iconPosition);
  327. if (iconPosition == "left") {
  328. button.imagePosition = NSImageLeft;
  329. } else if (iconPosition == "right") {
  330. button.imagePosition = NSImageRight;
  331. } else {
  332. button.imagePosition = NSImageOverlaps;
  333. }
  334. }
  335. }
  336. - (NSTouchBarItem*)makeLabelForID:(NSString*)id
  337. withIdentifier:(NSString*)identifier {
  338. std::string s_id([id UTF8String]);
  339. if (![self hasItemWithID:s_id])
  340. return nil;
  341. mate::PersistentDictionary settings = settings_[s_id];
  342. base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
  343. @"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
  344. [item setView:[NSTextField labelWithString:@""]];
  345. [self updateLabel:item withSettings:settings];
  346. return item.autorelease();
  347. }
  348. - (void)updateLabel:(NSCustomTouchBarItem*)item
  349. withSettings:(const mate::PersistentDictionary&)settings {
  350. NSTextField* text_field = (NSTextField*)item.view;
  351. std::string label;
  352. settings.Get("label", &label);
  353. text_field.stringValue = base::SysUTF8ToNSString(label);
  354. std::string textColor;
  355. if (settings.Get("textColor", &textColor) && !textColor.empty()) {
  356. text_field.textColor = [self colorFromHexColorString:textColor];
  357. } else {
  358. text_field.textColor = nil;
  359. }
  360. }
  361. - (NSTouchBarItem*)makeColorPickerForID:(NSString*)id
  362. withIdentifier:(NSString*)identifier {
  363. std::string s_id([id UTF8String]);
  364. if (![self hasItemWithID:s_id])
  365. return nil;
  366. mate::PersistentDictionary settings = settings_[s_id];
  367. base::scoped_nsobject<NSColorPickerTouchBarItem> item([[NSClassFromString(
  368. @"NSColorPickerTouchBarItem") alloc] initWithIdentifier:identifier]);
  369. [item setTarget:self];
  370. [item setAction:@selector(colorPickerAction:)];
  371. [self updateColorPicker:item withSettings:settings];
  372. return item.autorelease();
  373. }
  374. - (void)updateColorPicker:(NSColorPickerTouchBarItem*)item
  375. withSettings:(const mate::PersistentDictionary&)settings {
  376. std::vector<std::string> colors;
  377. if (settings.Get("availableColors", &colors) && !colors.empty()) {
  378. NSColorList* color_list =
  379. [[[NSColorList alloc] initWithName:@""] autorelease];
  380. for (size_t i = 0; i < colors.size(); ++i) {
  381. [color_list insertColor:[self colorFromHexColorString:colors[i]]
  382. key:base::SysUTF8ToNSString(colors[i])
  383. atIndex:i];
  384. }
  385. item.colorList = color_list;
  386. }
  387. std::string selectedColor;
  388. if (settings.Get("selectedColor", &selectedColor)) {
  389. item.color = [self colorFromHexColorString:selectedColor];
  390. }
  391. }
  392. - (NSTouchBarItem*)makeSliderForID:(NSString*)id
  393. withIdentifier:(NSString*)identifier {
  394. std::string s_id([id UTF8String]);
  395. if (![self hasItemWithID:s_id])
  396. return nil;
  397. mate::PersistentDictionary settings = settings_[s_id];
  398. base::scoped_nsobject<NSSliderTouchBarItem> item([[NSClassFromString(
  399. @"NSSliderTouchBarItem") alloc] initWithIdentifier:identifier]);
  400. [item setTarget:self];
  401. [item setAction:@selector(sliderAction:)];
  402. [self updateSlider:item withSettings:settings];
  403. return item.autorelease();
  404. }
  405. - (void)updateSlider:(NSSliderTouchBarItem*)item
  406. withSettings:(const mate::PersistentDictionary&)settings {
  407. std::string label;
  408. settings.Get("label", &label);
  409. item.label = base::SysUTF8ToNSString(label);
  410. int maxValue = 100;
  411. int minValue = 0;
  412. int value = 50;
  413. settings.Get("minValue", &minValue);
  414. settings.Get("maxValue", &maxValue);
  415. settings.Get("value", &value);
  416. item.slider.minValue = minValue;
  417. item.slider.maxValue = maxValue;
  418. item.slider.doubleValue = value;
  419. }
  420. - (NSTouchBarItem*)makePopoverForID:(NSString*)id
  421. withIdentifier:(NSString*)identifier {
  422. std::string s_id([id UTF8String]);
  423. if (![self hasItemWithID:s_id])
  424. return nil;
  425. mate::PersistentDictionary settings = settings_[s_id];
  426. base::scoped_nsobject<NSPopoverTouchBarItem> item([[NSClassFromString(
  427. @"NSPopoverTouchBarItem") alloc] initWithIdentifier:identifier]);
  428. [self updatePopover:item withSettings:settings];
  429. return item.autorelease();
  430. }
  431. - (void)updatePopover:(NSPopoverTouchBarItem*)item
  432. withSettings:(const mate::PersistentDictionary&)settings {
  433. std::string label;
  434. settings.Get("label", &label);
  435. item.collapsedRepresentationLabel = base::SysUTF8ToNSString(label);
  436. gfx::Image image;
  437. if (settings.Get("icon", &image)) {
  438. item.collapsedRepresentationImage = image.AsNSImage();
  439. }
  440. bool showCloseButton = true;
  441. settings.Get("showCloseButton", &showCloseButton);
  442. item.showsCloseButton = showCloseButton;
  443. mate::PersistentDictionary child;
  444. std::vector<mate::PersistentDictionary> items;
  445. if (settings.Get("child", &child) && child.Get("ordereredItems", &items)) {
  446. item.popoverTouchBar =
  447. [self touchBarFromItemIdentifiers:[self identifiersFromSettings:items]];
  448. }
  449. }
  450. - (NSTouchBarItem*)makeGroupForID:(NSString*)id
  451. withIdentifier:(NSString*)identifier {
  452. std::string s_id([id UTF8String]);
  453. if (![self hasItemWithID:s_id])
  454. return nil;
  455. mate::PersistentDictionary settings = settings_[s_id];
  456. mate::PersistentDictionary child;
  457. if (!settings.Get("child", &child))
  458. return nil;
  459. std::vector<mate::PersistentDictionary> items;
  460. if (!child.Get("ordereredItems", &items))
  461. return nil;
  462. NSMutableArray* generatedItems = [NSMutableArray array];
  463. NSMutableArray* identifiers = [self identifiersFromSettings:items];
  464. for (NSUInteger i = 0; i < [identifiers count]; ++i) {
  465. if ([identifiers objectAtIndex:i] !=
  466. NSTouchBarItemIdentifierOtherItemsProxy) {
  467. NSTouchBarItem* generatedItem =
  468. [self makeItemForIdentifier:[identifiers objectAtIndex:i]];
  469. if (generatedItem) {
  470. [generatedItems addObject:generatedItem];
  471. }
  472. }
  473. }
  474. return [NSClassFromString(@"NSGroupTouchBarItem")
  475. groupItemWithIdentifier:identifier
  476. items:generatedItems];
  477. }
  478. - (void)updateGroup:(NSGroupTouchBarItem*)item
  479. withSettings:(const mate::PersistentDictionary&)settings
  480. API_AVAILABLE(macosx(10.12.2)) {
  481. mate::PersistentDictionary child;
  482. if (!settings.Get("child", &child))
  483. return;
  484. std::vector<mate::PersistentDictionary> items;
  485. if (!child.Get("ordereredItems", &items))
  486. return;
  487. item.groupTouchBar =
  488. [self touchBarFromItemIdentifiers:[self identifiersFromSettings:items]];
  489. }
  490. - (NSTouchBarItem*)makeSegmentedControlForID:(NSString*)id
  491. withIdentifier:(NSString*)identifier
  492. API_AVAILABLE(macosx(10.12.2)) {
  493. std::string s_id([id UTF8String]);
  494. if (![self hasItemWithID:s_id])
  495. return nil;
  496. mate::PersistentDictionary settings = settings_[s_id];
  497. base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
  498. @"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
  499. NSSegmentedControl* control = [NSSegmentedControl
  500. segmentedControlWithLabels:[NSMutableArray array]
  501. trackingMode:NSSegmentSwitchTrackingSelectOne
  502. target:self
  503. action:@selector(segmentedControlAction:)];
  504. control.tag = [id floatValue];
  505. [item setView:control];
  506. [self updateSegmentedControl:item withSettings:settings];
  507. return item.autorelease();
  508. }
  509. - (void)updateSegmentedControl:(NSCustomTouchBarItem*)item
  510. withSettings:(const mate::PersistentDictionary&)settings
  511. API_AVAILABLE(macosx(10.12.2)) {
  512. NSSegmentedControl* control = item.view;
  513. std::string segmentStyle;
  514. settings.Get("segmentStyle", &segmentStyle);
  515. if (segmentStyle == "rounded")
  516. control.segmentStyle = NSSegmentStyleRounded;
  517. else if (segmentStyle == "textured-rounded")
  518. control.segmentStyle = NSSegmentStyleTexturedRounded;
  519. else if (segmentStyle == "round-rect")
  520. control.segmentStyle = NSSegmentStyleRoundRect;
  521. else if (segmentStyle == "textured-square")
  522. control.segmentStyle = NSSegmentStyleTexturedSquare;
  523. else if (segmentStyle == "capsule")
  524. control.segmentStyle = NSSegmentStyleCapsule;
  525. else if (segmentStyle == "small-square")
  526. control.segmentStyle = NSSegmentStyleSmallSquare;
  527. else if (segmentStyle == "separated")
  528. control.segmentStyle = NSSegmentStyleSeparated;
  529. else
  530. control.segmentStyle = NSSegmentStyleAutomatic;
  531. std::string segmentMode;
  532. settings.Get("mode", &segmentMode);
  533. if (segmentMode == "multiple")
  534. control.trackingMode = NSSegmentSwitchTrackingSelectAny;
  535. else if (segmentMode == "buttons")
  536. control.trackingMode = NSSegmentSwitchTrackingMomentary;
  537. else
  538. control.trackingMode = NSSegmentSwitchTrackingSelectOne;
  539. std::vector<mate::Dictionary> segments;
  540. settings.Get("segments", &segments);
  541. control.segmentCount = segments.size();
  542. for (size_t i = 0; i < segments.size(); ++i) {
  543. std::string label;
  544. gfx::Image image;
  545. bool enabled = true;
  546. segments[i].Get("enabled", &enabled);
  547. if (segments[i].Get("label", &label)) {
  548. [control setLabel:base::SysUTF8ToNSString(label) forSegment:i];
  549. } else if (segments[i].Get("icon", &image)) {
  550. [control setImage:image.AsNSImage() forSegment:i];
  551. [control setImageScaling:NSImageScaleProportionallyUpOrDown forSegment:i];
  552. }
  553. [control setEnabled:enabled forSegment:i];
  554. }
  555. int selectedIndex = 0;
  556. settings.Get("selectedIndex", &selectedIndex);
  557. if (selectedIndex >= 0 && selectedIndex < control.segmentCount)
  558. control.selectedSegment = selectedIndex;
  559. }
  560. - (NSTouchBarItem*)makeScrubberForID:(NSString*)id
  561. withIdentifier:(NSString*)identifier
  562. API_AVAILABLE(macosx(10.12.2)) {
  563. std::string s_id([id UTF8String]);
  564. if (![self hasItemWithID:s_id])
  565. return nil;
  566. mate::PersistentDictionary settings = settings_[s_id];
  567. base::scoped_nsobject<NSCustomTouchBarItem> item([[NSClassFromString(
  568. @"NSCustomTouchBarItem") alloc] initWithIdentifier:identifier]);
  569. NSScrubber* scrubber = [[[NSClassFromString(@"NSScrubber") alloc]
  570. initWithFrame:NSZeroRect] autorelease];
  571. [scrubber registerClass:NSClassFromString(@"NSScrubberTextItemView")
  572. forItemIdentifier:TextScrubberItemIdentifier];
  573. [scrubber registerClass:NSClassFromString(@"NSScrubberImageItemView")
  574. forItemIdentifier:ImageScrubberItemIdentifier];
  575. scrubber.delegate = self;
  576. scrubber.dataSource = self;
  577. scrubber.identifier = id;
  578. [item setView:scrubber];
  579. [self updateScrubber:item withSettings:settings];
  580. return item.autorelease();
  581. }
  582. - (void)updateScrubber:(NSCustomTouchBarItem*)item
  583. withSettings:(const mate::PersistentDictionary&)settings
  584. API_AVAILABLE(macosx(10.12.2)) {
  585. NSScrubber* scrubber = item.view;
  586. bool showsArrowButtons = false;
  587. settings.Get("showArrowButtons", &showsArrowButtons);
  588. scrubber.showsArrowButtons = showsArrowButtons;
  589. std::string selectedStyle;
  590. std::string overlayStyle;
  591. settings.Get("selectedStyle", &selectedStyle);
  592. settings.Get("overlayStyle", &overlayStyle);
  593. if (selectedStyle == "outline") {
  594. scrubber.selectionBackgroundStyle =
  595. [NSClassFromString(@"NSScrubberSelectionStyle") outlineOverlayStyle];
  596. } else if (selectedStyle == "background") {
  597. scrubber.selectionBackgroundStyle =
  598. [NSClassFromString(@"NSScrubberSelectionStyle") roundedBackgroundStyle];
  599. } else {
  600. scrubber.selectionBackgroundStyle = nil;
  601. }
  602. if (overlayStyle == "outline") {
  603. scrubber.selectionOverlayStyle =
  604. [NSClassFromString(@"NSScrubberSelectionStyle") outlineOverlayStyle];
  605. } else if (overlayStyle == "background") {
  606. scrubber.selectionOverlayStyle =
  607. [NSClassFromString(@"NSScrubberSelectionStyle") roundedBackgroundStyle];
  608. } else {
  609. scrubber.selectionOverlayStyle = nil;
  610. }
  611. std::string mode;
  612. settings.Get("mode", &mode);
  613. if (mode == "fixed") {
  614. scrubber.mode = NSScrubberModeFixed;
  615. } else {
  616. scrubber.mode = NSScrubberModeFree;
  617. }
  618. bool continuous = true;
  619. settings.Get("continuous", &continuous);
  620. scrubber.continuous = continuous;
  621. [scrubber reloadData];
  622. }
  623. - (NSInteger)numberOfItemsForScrubber:(NSScrubber*)scrubber
  624. API_AVAILABLE(macosx(10.12.2)) {
  625. std::string s_id([[scrubber identifier] UTF8String]);
  626. if (![self hasItemWithID:s_id])
  627. return 0;
  628. mate::PersistentDictionary settings = settings_[s_id];
  629. std::vector<mate::PersistentDictionary> items;
  630. settings.Get("items", &items);
  631. return items.size();
  632. }
  633. - (NSScrubberItemView*)scrubber:(NSScrubber*)scrubber
  634. viewForItemAtIndex:(NSInteger)index
  635. API_AVAILABLE(macosx(10.12.2)) {
  636. std::string s_id([[scrubber identifier] UTF8String]);
  637. if (![self hasItemWithID:s_id])
  638. return nil;
  639. mate::PersistentDictionary settings = settings_[s_id];
  640. std::vector<mate::PersistentDictionary> items;
  641. if (!settings.Get("items", &items))
  642. return nil;
  643. if (index >= static_cast<NSInteger>(items.size()))
  644. return nil;
  645. mate::PersistentDictionary item = items[index];
  646. NSScrubberItemView* itemView;
  647. std::string title;
  648. if (item.Get("label", &title)) {
  649. NSScrubberTextItemView* view =
  650. [scrubber makeItemWithIdentifier:TextScrubberItemIdentifier owner:self];
  651. view.title = base::SysUTF8ToNSString(title);
  652. itemView = view;
  653. } else {
  654. NSScrubberImageItemView* view =
  655. [scrubber makeItemWithIdentifier:ImageScrubberItemIdentifier
  656. owner:self];
  657. gfx::Image image;
  658. if (item.Get("icon", &image)) {
  659. view.image = image.AsNSImage();
  660. }
  661. itemView = view;
  662. }
  663. return itemView;
  664. }
  665. - (NSSize)scrubber:(NSScrubber*)scrubber
  666. layout:(NSScrubberFlowLayout*)layout
  667. sizeForItemAtIndex:(NSInteger)itemIndex API_AVAILABLE(macosx(10.12.2)) {
  668. NSInteger width = 50;
  669. NSInteger height = 30;
  670. NSInteger margin = 15;
  671. NSSize defaultSize = NSMakeSize(width, height);
  672. std::string s_id([[scrubber identifier] UTF8String]);
  673. if (![self hasItemWithID:s_id])
  674. return defaultSize;
  675. mate::PersistentDictionary settings = settings_[s_id];
  676. std::vector<mate::PersistentDictionary> items;
  677. if (!settings.Get("items", &items))
  678. return defaultSize;
  679. if (itemIndex >= static_cast<NSInteger>(items.size()))
  680. return defaultSize;
  681. mate::PersistentDictionary item = items[itemIndex];
  682. std::string title;
  683. if (item.Get("label", &title)) {
  684. NSSize size = NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX);
  685. NSRect textRect = [base::SysUTF8ToNSString(title)
  686. boundingRectWithSize:size
  687. options:NSStringDrawingUsesLineFragmentOrigin |
  688. NSStringDrawingUsesFontLeading
  689. attributes:@{
  690. NSFontAttributeName : [NSFont systemFontOfSize:0]
  691. }];
  692. width = textRect.size.width + margin;
  693. } else {
  694. gfx::Image image;
  695. if (item.Get("icon", &image)) {
  696. width = image.AsNSImage().size.width;
  697. }
  698. }
  699. return NSMakeSize(width, height);
  700. }
  701. @end