1// Gmsh - Copyright (C) 1997-2021 C. Geuzaine, J.-F. Remacle
2//
3// See the LICENSE.txt file in the Gmsh root directory for license information.
4// Please report all issues on https://gitlab.onelab.info/gmsh/gmsh/issues.
5//
6// Contributors: Anthony Royer
7
8#define GL_SILENCE_DEPRECATION
9
10#include <Foundation/Foundation.h>
11#include <AppKit/AppKit.h>
12
13#include "touchBar.h"
14#include "graphicWindow.h"
15#include "drawContext.h"
16#include "Options.h"
17#include "PView.h"
18#include "FlGui.h"
19
20static NSString *touchBarCustomizationId = @"com.something.customization_id";
21
22static NSString *touchBarItemRunMesh = @"com.something.item_runmesh";
23
24static NSString *touchBarItemGeoMenu = @"com.something.item_geoMenu";
25static NSString *touchBarItemGeoButtons = @"com.something.item_geoButtons";
26static NSString *touchBarItemGeoButtonNormalTangent = @"com.something.item_geoButtonNormalTangent";
27static NSString *touchBarItemGeoSliderNormalTangent = @"com.something.item_geoSliderNormalTangent";
28static NSString *touchBarItemGeoHoldButtons = @"com.something.item_geoHoldButtons";
29
30static NSString *touchBarItemMeshMenu = @"com.something.item_meshMenu";
31static NSString *touchBarItemMeshButtons = @"com.something.item_meshButtons";
32static NSString *touchBarItemMeshButtonNormalTangent = @"com.something.item_meshButtonNormalTangent";
33static NSString *touchBarItemMeshSliderNormalTangent = @"com.something.item_meshSliderNormalTangent";
34static NSString *touchBarItemMeshHoldButtons = @"com.something.item_meshHoldButtons";
35
36static NSString *touchBarItemViewMenu = @"com.something.item_viewMenu";
37static NSString *touchBarItemViewButtons = @"com.something.item_viewButtons";
38static NSString *touchBarItemViewSlider = @"com.something.item_viewSlider";
39
40@interface TouchBarDelegate : NSObject <NSTouchBarDelegate>
41
42@property (strong) NSSegmentedControl *geoButtons;
43@property (strong) NSSegmentedControl *geoButtonsNormalTangent;
44@property (strong) NSSliderTouchBarItem *geoSliderNormalTangent;
45@property (strong) NSSegmentedControl *meshButtons;
46@property (strong) NSSegmentedControl *meshButtonsNormalTangent;
47@property (strong) NSSliderTouchBarItem *meshSliderNormalTangent;
48@property (strong) NSButton *viewMenuButton;
49@property (strong) NSSegmentedControl *viewButtons;
50@property (strong) NSSlider *viewSlider;
51
52- (NSTouchBar *)makeTouchBar;
53- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar
54       makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier;
55- (void)buttonRunMesh:(id)sender;
56- (void)buttonGeo:(id)sender;
57- (void)buttonGeoNormalTangent:(id)sender;
58- (void)sliderGeoNormalTangent:(id)sender;
59- (void)buttonHoldGeo:(id)sender;
60- (void)buttonMesh:(id)sender;
61- (void)buttonMeshNormalTangent:(id)sender;
62- (void)sliderMeshNormalTangent:(id)sender;
63- (void)buttonHoldMesh:(id)sender;
64- (void)buttonView:(id)sender;
65- (void)sliderView:(id)sender;
66- (void)updateGeo;
67- (void)updateGeoSliderNormalTangent;
68- (void)updateMesh;
69- (void)updateMeshSliderNormalTangent;
70- (void)updateViewMenu;
71- (void)updateViewButtons;
72- (void)updateViewSlider;
73- (void)update;
74@end
75
76@implementation TouchBarDelegate
77- (NSTouchBar *)makeTouchBar
78{
79  NSTouchBar *touchBar = [[NSTouchBar alloc] init];
80  touchBar.delegate = self;
81  touchBar.customizationIdentifier = touchBarCustomizationId;
82
83  touchBar.defaultItemIdentifiers = @[
84    touchBarItemRunMesh, touchBarItemGeoMenu, touchBarItemMeshMenu,
85    touchBarItemViewMenu
86  ];
87  touchBar.customizationAllowedItemIdentifiers = @[
88    touchBarItemRunMesh, touchBarItemGeoMenu, touchBarItemMeshMenu,
89    touchBarItemViewMenu
90  ];
91
92  return touchBar;
93}
94
95- (NSTouchBarItem *)touchBar:(NSTouchBar *)touchBar
96       makeItemForIdentifier:(NSTouchBarItemIdentifier)identifier
97{
98  if([identifier isEqualToString:touchBarItemRunMesh]) {
99    NSSegmentedControl *segmentedControl = [NSSegmentedControl
100      segmentedControlWithLabels:@[ @"1D", @"2D", @"3D" ]
101                    trackingMode:NSSegmentSwitchTrackingMomentary
102                          target:self
103                          action:@selector(buttonRunMesh:)];
104
105    NSCustomTouchBarItem *touchBarItem =
106      [[NSCustomTouchBarItem alloc] initWithIdentifier:touchBarItemRunMesh];
107    touchBarItem.view = segmentedControl;
108    touchBarItem.customizationLabel = @"Meshing commands";
109
110    return touchBarItem;
111  }
112  else if([identifier isEqualToString:touchBarItemGeoMenu]) {
113    NSPopoverTouchBarItem *popoverTouchBarItem =
114      [[NSPopoverTouchBarItem alloc] initWithIdentifier:touchBarItemGeoMenu];
115
116    popoverTouchBarItem.customizationLabel = @"Geometry";
117    popoverTouchBarItem.showsCloseButton = YES;
118    popoverTouchBarItem.collapsedRepresentationLabel = @"Geometry";
119
120    NSTouchBar *secondTouchBar = [[NSTouchBar alloc] init];
121    secondTouchBar.delegate = self;
122    secondTouchBar.defaultItemIdentifiers = @[ touchBarItemGeoButtons, touchBarItemGeoButtonNormalTangent, touchBarItemGeoSliderNormalTangent ];
123
124    NSTouchBar *thirdTouchBar = [[NSTouchBar alloc] init];
125    thirdTouchBar.delegate = self;
126    thirdTouchBar.defaultItemIdentifiers = @[ touchBarItemGeoHoldButtons ];
127
128    popoverTouchBarItem.popoverTouchBar = secondTouchBar;
129    popoverTouchBarItem.pressAndHoldTouchBar = thirdTouchBar;
130
131    return popoverTouchBarItem;
132  }
133  else if([identifier isEqualToString:touchBarItemGeoButtons]) {
134    NSSegmentedControl *segmentedControl = [NSSegmentedControl
135      segmentedControlWithLabels:@[
136        @"Points", @"Curves", @"Surfaces", @"Volumes"
137      ]
138                    trackingMode:NSSegmentSwitchTrackingSelectAny
139                          target:self
140                          action:@selector(buttonGeo:)];
141
142    segmentedControl.segmentStyle = NSSegmentStyleSeparated;
143
144    NSCustomTouchBarItem *touchBarItem =
145      [[NSCustomTouchBarItem alloc] initWithIdentifier:touchBarItemGeoButtons];
146    touchBarItem.view = segmentedControl;
147
148    _geoButtons = segmentedControl;
149    [self updateGeo];
150
151    return touchBarItem;
152  }
153  else if([identifier isEqualToString:touchBarItemGeoButtonNormalTangent]) {
154    NSSegmentedControl *segmentedControl = [NSSegmentedControl
155      segmentedControlWithLabels:@[@"N", @"T"]
156                    trackingMode:NSSegmentSwitchTrackingSelectOne
157                          target:self
158                          action:@selector(buttonGeoNormalTangent:)];
159
160    [segmentedControl setWidth:30 forSegment:0];
161    [segmentedControl setWidth:30 forSegment:1];
162
163    NSCustomTouchBarItem *touchBarItem =
164      [[NSCustomTouchBarItem alloc] initWithIdentifier:touchBarItemGeoButtonNormalTangent];
165    touchBarItem.view = segmentedControl;
166
167    segmentedControl.selectedSegment = 0; //Normal
168    _geoButtonsNormalTangent = segmentedControl;
169
170    return touchBarItem;
171  }
172  else if([identifier isEqualToString:touchBarItemGeoSliderNormalTangent]) {
173    NSSliderTouchBarItem *slider = [[NSSliderTouchBarItem alloc]
174            initWithIdentifier:touchBarItemGeoSliderNormalTangent];
175
176    slider.target = self;
177    slider.action = @selector(sliderGeoNormalTangent:);
178    slider.slider.minValue = 0;
179    slider.slider.maxValue = 500;
180    slider.slider.doubleValue = 0;
181
182    _geoSliderNormalTangent = slider;
183    [self updateGeoSliderNormalTangent];
184
185    return slider;
186  }
187  else if([identifier isEqualToString:touchBarItemGeoHoldButtons]) {
188    NSSegmentedControl *segmentedControl = [NSSegmentedControl
189      segmentedControlWithLabels:@[ @"Show all", @"Hide all" ]
190                    trackingMode:NSSegmentSwitchTrackingSelectOne
191                          target:self
192                          action:@selector(buttonHoldGeo:)];
193
194    NSCustomTouchBarItem *touchBarItem = [[NSCustomTouchBarItem alloc]
195      initWithIdentifier:touchBarItemGeoHoldButtons];
196    touchBarItem.view = segmentedControl;
197
198    return touchBarItem;
199  }
200  else if([identifier isEqualToString:touchBarItemMeshMenu]) {
201    NSPopoverTouchBarItem *popoverTouchBarItem =
202      [[NSPopoverTouchBarItem alloc] initWithIdentifier:touchBarItemMeshMenu];
203
204    popoverTouchBarItem.customizationLabel = @"Mesh";
205    popoverTouchBarItem.showsCloseButton = YES;
206    popoverTouchBarItem.collapsedRepresentationLabel = @"Mesh";
207
208    NSTouchBar *secondTouchBar = [[NSTouchBar alloc] init];
209    secondTouchBar.delegate = self;
210    secondTouchBar.defaultItemIdentifiers = @[ touchBarItemMeshButtons, touchBarItemMeshButtonNormalTangent, touchBarItemMeshSliderNormalTangent ];
211
212    NSTouchBar *thirdTouchBar = [[NSTouchBar alloc] init];
213    thirdTouchBar.delegate = self;
214    thirdTouchBar.defaultItemIdentifiers = @[ touchBarItemMeshHoldButtons ];
215
216    popoverTouchBarItem.popoverTouchBar = secondTouchBar;
217    popoverTouchBarItem.pressAndHoldTouchBar = thirdTouchBar;
218
219    return popoverTouchBarItem;
220  }
221  else if([identifier isEqualToString:touchBarItemMeshButtons]) {
222    NSSegmentedControl *segmentedControl = [NSSegmentedControl
223      segmentedControlWithLabels:@[
224        @"Nodes", @"Lines", @"2D edges", @"2D faces", @"3D edges", @"3D faces"
225      ]
226                    trackingMode:NSSegmentSwitchTrackingSelectAny
227                          target:self
228                          action:@selector(buttonMesh:)];
229
230    segmentedControl.segmentStyle = NSSegmentStyleSeparated;
231
232    NSCustomTouchBarItem *touchBarItem =
233      [[NSCustomTouchBarItem alloc] initWithIdentifier:touchBarItemMeshButtons];
234    touchBarItem.view = segmentedControl;
235
236    _meshButtons = segmentedControl;
237    [self updateMesh];
238
239    return touchBarItem;
240  }
241  else if([identifier isEqualToString:touchBarItemMeshButtonNormalTangent]) {
242    NSSegmentedControl *segmentedControl = [NSSegmentedControl
243      segmentedControlWithLabels:@[@"N", @"T"]
244                    trackingMode:NSSegmentSwitchTrackingSelectOne
245                          target:self
246                          action:@selector(buttonMeshNormalTangent:)];
247
248    [segmentedControl setWidth:30 forSegment:0];
249    [segmentedControl setWidth:30 forSegment:1];
250
251    NSCustomTouchBarItem *touchBarItem =
252      [[NSCustomTouchBarItem alloc] initWithIdentifier:touchBarItemMeshButtonNormalTangent];
253    touchBarItem.view = segmentedControl;
254
255    segmentedControl.selectedSegment = 0; //Normal
256    _meshButtonsNormalTangent = segmentedControl;
257
258    return touchBarItem;
259  }
260  else if([identifier isEqualToString:touchBarItemMeshSliderNormalTangent]) {
261    NSSliderTouchBarItem *slider = [[NSSliderTouchBarItem alloc]
262            initWithIdentifier:touchBarItemMeshSliderNormalTangent];
263
264    slider.target = self;
265    slider.action = @selector(sliderMeshNormalTangent:);
266    slider.slider.minValue = 0;
267    slider.slider.maxValue = 500;
268    slider.slider.doubleValue = 0;
269
270    _meshSliderNormalTangent = slider;
271    [self updateMeshSliderNormalTangent];
272
273    return slider;
274  }
275  else if([identifier isEqualToString:touchBarItemMeshHoldButtons]) {
276    NSSegmentedControl *segmentedControl = [NSSegmentedControl
277      segmentedControlWithLabels:@[ @"Show all", @"Hide all" ]
278                    trackingMode:NSSegmentSwitchTrackingSelectOne
279                          target:self
280                          action:@selector(buttonHoldMesh:)];
281
282    NSCustomTouchBarItem *touchBarItem = [[NSCustomTouchBarItem alloc]
283      initWithIdentifier:touchBarItemMeshHoldButtons];
284    touchBarItem.view = segmentedControl;
285
286    return touchBarItem;
287  }
288  else if([identifier isEqualToString:touchBarItemViewMenu]) {
289    NSPopoverTouchBarItem *popoverTouchBarItem =
290      [[NSPopoverTouchBarItem alloc] initWithIdentifier:touchBarItemViewMenu];
291
292    popoverTouchBarItem.customizationLabel = @"View";
293    popoverTouchBarItem.showsCloseButton = YES;
294    popoverTouchBarItem.collapsedRepresentationLabel = @"View";
295
296    NSTouchBar *secondTouchBar = [[NSTouchBar alloc] init];
297    secondTouchBar.delegate = self;
298
299    _viewMenuButton = (NSButton *)popoverTouchBarItem.view;
300    [self updateViewMenu];
301
302    secondTouchBar.defaultItemIdentifiers =
303      @[ touchBarItemViewButtons, touchBarItemViewSlider ];
304    popoverTouchBarItem.popoverTouchBar = secondTouchBar;
305
306    return popoverTouchBarItem;
307  }
308  else if([identifier isEqualToString:touchBarItemViewButtons]) {
309    NSSegmentedControl *segmentedControl = [NSSegmentedControl
310      segmentedControlWithLabels:@[
311        @"Iso-values", @"Continuous map", @"Filled iso-values",
312        @"Numeric values"
313      ]
314                    trackingMode:NSSegmentSwitchTrackingSelectOne
315                          target:self
316                          action:@selector(buttonView:)];
317
318    NSCustomTouchBarItem *touchBarItem =
319      [[NSCustomTouchBarItem alloc] initWithIdentifier:touchBarItemViewButtons];
320    touchBarItem.view = segmentedControl;
321
322    _viewButtons = segmentedControl;
323    [self updateViewButtons];
324
325    return touchBarItem;
326  }
327  else if([identifier isEqualToString:touchBarItemViewSlider]) {
328    NSSliderTouchBarItem *slider = [[NSSliderTouchBarItem alloc]
329            initWithIdentifier:touchBarItemViewSlider];
330
331    slider.target = self;
332    slider.action = @selector(sliderView:);
333    slider.slider.minValue = 1;
334    slider.slider.maxValue = 100;
335    slider.slider.doubleValue = 10;
336    _viewSlider = slider.slider;
337    [self updateViewSlider];
338
339    return slider;
340  }
341
342  return nil;
343}
344
345- (void)buttonRunMesh:(id)sender
346{
347  NSInteger segment = ((NSSegmentedControl *)sender).selectedSegment;
348  switch(segment) {
349  case 0: mesh_1d_cb(0, 0); break;
350  case 1: mesh_2d_cb(0, 0); break;
351  case 2: mesh_3d_cb(0, 0); break;
352  default: break;
353  }
354  FlGui::check(); // to see meshing messages in the fltk gui
355}
356
357- (void)buttonGeo:(id)sender
358{
359  NSInteger segment = ((NSSegmentedControl *)sender).selectedSegment;
360  switch(segment) {
361  case 0: quick_access_cb(0, (void *)"geometry_points"); break;
362  case 1: quick_access_cb(0, (void *)"geometry_curves"); break;
363  case 2: quick_access_cb(0, (void *)"geometry_surfaces"); break;
364  case 3: quick_access_cb(0, (void *)"geometry_volumes"); break;
365  default: break;
366  }
367  drawContext::global()->draw();
368}
369
370- (void)buttonGeoNormalTangent:(id)sender
371{
372  [self updateGeoSliderNormalTangent];
373  drawContext::global()->draw();
374}
375
376- (void)sliderGeoNormalTangent:(id)sender
377{
378  NSInteger segment = _geoButtonsNormalTangent.selectedSegment;
379  if(segment == 0) { // Normal
380    opt_geometry_normals(0, GMSH_SET | GMSH_GUI, _geoSliderNormalTangent.slider.doubleValue);
381  }
382  else { // Tangent
383    opt_geometry_tangents(0, GMSH_SET | GMSH_GUI, _geoSliderNormalTangent.slider.doubleValue);
384  }
385  drawContext::global()->draw();
386}
387
388- (void)buttonHoldGeo:(id)sender
389{
390  NSInteger segment = ((NSSegmentedControl *)sender).selectedSegment;
391  switch(segment) {
392  case 0: // show all
393    if(!opt_geometry_points(0, GMSH_GET, 0)) {
394      quick_access_cb(0, (void *)"geometry_points");
395    }
396    if(!opt_geometry_curves(0, GMSH_GET, 0)) {
397      quick_access_cb(0, (void *)"geometry_curves");
398    }
399    if(!opt_geometry_surfaces(0, GMSH_GET, 0)) {
400      quick_access_cb(0, (void *)"geometry_surfaces");
401    }
402    if(!opt_geometry_volumes(0, GMSH_GET, 0)) {
403      quick_access_cb(0, (void *)"geometry_volumes");
404    }
405    break;
406  case 1: // hide all
407    if(opt_geometry_points(0, GMSH_GET, 0)) {
408      quick_access_cb(0, (void *)"geometry_points");
409    }
410    if(opt_geometry_curves(0, GMSH_GET, 0)) {
411      quick_access_cb(0, (void *)"geometry_curves");
412    }
413    if(opt_geometry_surfaces(0, GMSH_GET, 0)) {
414      quick_access_cb(0, (void *)"geometry_surfaces");
415    }
416    if(opt_geometry_volumes(0, GMSH_GET, 0)) {
417      quick_access_cb(0, (void *)"geometry_volumes");
418    }
419    break;
420  default: break;
421  }
422  [self updateGeo];
423  drawContext::global()->draw();
424  ((NSSegmentedControl *)sender).selectedSegment = -1;
425}
426
427- (void)buttonMesh:(id)sender
428{
429  NSInteger segment = ((NSSegmentedControl *)sender).selectedSegment;
430  switch(segment) {
431  case 0: quick_access_cb(0, (void *)"mesh_nodes"); break;
432  case 1: quick_access_cb(0, (void *)"mesh_lines"); break;
433  case 2: quick_access_cb(0, (void *)"mesh_surface_edges"); break;
434  case 3: quick_access_cb(0, (void *)"mesh_surface_faces"); break;
435  case 4: quick_access_cb(0, (void *)"mesh_volume_edges"); break;
436  case 5: quick_access_cb(0, (void *)"mesh_volume_faces"); break;
437  default: break;
438  }
439  drawContext::global()->draw();
440}
441
442- (void)buttonMeshNormalTangent:(id)sender
443{
444  [self updateMeshSliderNormalTangent];
445  drawContext::global()->draw();
446}
447
448- (void)sliderMeshNormalTangent:(id)sender
449{
450  NSInteger segment = _meshButtonsNormalTangent.selectedSegment;
451  if(segment == 0) { // Normal
452    opt_mesh_normals(0, GMSH_SET | GMSH_GUI, _meshSliderNormalTangent.slider.doubleValue);
453  }
454  else { // Tangent
455    opt_mesh_tangents(0, GMSH_SET | GMSH_GUI, _meshSliderNormalTangent.slider.doubleValue);
456  }
457  drawContext::global()->draw();
458}
459
460- (void)buttonHoldMesh:(id)sender
461{
462  NSInteger segment = ((NSSegmentedControl *)sender).selectedSegment;
463  switch(segment) {
464  case 0: // show all
465    if(!opt_mesh_nodes(0, GMSH_GET, 0)) {
466      quick_access_cb(0, (void *)"mesh_nodes");
467    }
468    if(!opt_mesh_lines(0, GMSH_GET, 0)) {
469      quick_access_cb(0, (void *)"mesh_lines");
470    }
471    if(!opt_mesh_surface_edges(0, GMSH_GET, 0)) {
472      quick_access_cb(0, (void *)"mesh_surface_edges");
473    }
474    if(!opt_mesh_surface_faces(0, GMSH_GET, 0)) {
475      quick_access_cb(0, (void *)"mesh_surface_faces");
476    }
477    if(!opt_mesh_volume_edges(0, GMSH_GET, 0)) {
478      quick_access_cb(0, (void *)"mesh_volume_edges");
479    }
480    if(!opt_mesh_volume_faces(0, GMSH_GET, 0)) {
481      quick_access_cb(0, (void *)"mesh_volume_faces");
482    }
483    break;
484  case 1: // hide all
485    if(opt_mesh_nodes(0, GMSH_GET, 0)) {
486      quick_access_cb(0, (void *)"mesh_nodes");
487    }
488    if(opt_mesh_lines(0, GMSH_GET, 0)) {
489      quick_access_cb(0, (void *)"mesh_lines");
490    }
491    if(opt_mesh_surface_edges(0, GMSH_GET, 0)) {
492      quick_access_cb(0, (void *)"mesh_surface_edges");
493    }
494    if(opt_mesh_surface_faces(0, GMSH_GET, 0)) {
495      quick_access_cb(0, (void *)"mesh_surface_faces");
496    }
497    if(opt_mesh_volume_edges(0, GMSH_GET, 0)) {
498      quick_access_cb(0, (void *)"mesh_volume_edges");
499    }
500    if(opt_mesh_volume_faces(0, GMSH_GET, 0)) {
501      quick_access_cb(0, (void *)"mesh_volume_faces");
502    }
503    break;
504  default: break;
505  }
506  [self updateMesh];
507  drawContext::global()->draw();
508  ((NSSegmentedControl *)sender).selectedSegment = -1;
509}
510
511- (void)buttonView:(id)sender
512{
513  NSInteger segment = ((NSSegmentedControl *)sender).selectedSegment;
514  for(std::size_t i = 0; i < PView::list.size(); i++) {
515    if(opt_view_visible(i, GMSH_GET, 0)) {
516      opt_view_intervals_type(i, GMSH_SET | GMSH_GUI, segment + 1);
517    }
518  }
519  if(segment + 1 == 1 ||
520     segment + 1 == 3) { // For iso-values and filled iso-values
521    _viewSlider.hidden = NO;
522  }
523  else {
524    _viewSlider.hidden = YES;
525  }
526  drawContext::global()->draw();
527}
528
529- (void)sliderView:(id)sender
530{
531  NSSlider *slider = ((NSSliderTouchBarItem *)sender).slider;
532  if(!slider.hidden) {
533    double value = slider.doubleValue;
534    for(std::size_t i = 0; i < PView::list.size(); i++) {
535      if(opt_view_visible(i, GMSH_GET, 0)) {
536        opt_view_nb_iso(i, GMSH_SET | GMSH_GUI, value);
537      }
538    }
539    drawContext::global()->draw();
540  }
541}
542
543- (void)updateGeo
544{
545  if(opt_geometry_points(0, GMSH_GET, 0)) {
546    [_geoButtons setSelected:YES forSegment:0];
547  }
548  else {
549    [_geoButtons setSelected:NO forSegment:0];
550  }
551
552  if(opt_geometry_curves(0, GMSH_GET, 0)) {
553    [_geoButtons setSelected:YES forSegment:1];
554  }
555  else {
556    [_geoButtons setSelected:NO forSegment:1];
557  }
558
559  if(opt_geometry_surfaces(0, GMSH_GET, 0)) {
560    [_geoButtons setSelected:YES forSegment:2];
561  }
562  else {
563    [_geoButtons setSelected:NO forSegment:2];
564  }
565
566  if(opt_geometry_volumes(0, GMSH_GET, 0)) {
567    [_geoButtons setSelected:YES forSegment:3];
568  }
569  else {
570    [_geoButtons setSelected:NO forSegment:3];
571  }
572}
573
574- (void)updateGeoSliderNormalTangent
575{
576  NSInteger segment = _geoButtonsNormalTangent.selectedSegment;
577  if(segment == 0) { // Normal
578    _geoSliderNormalTangent.slider.doubleValue = opt_geometry_normals(0, GMSH_GET, 0);
579  }
580  else { // Tangent
581    _geoSliderNormalTangent.slider.doubleValue = opt_geometry_tangents(0, GMSH_GET, 0);
582  }
583}
584
585- (void)updateMesh
586{
587  if(opt_mesh_nodes(0, GMSH_GET, 0)) {
588    [_meshButtons setSelected:YES forSegment:0];
589  }
590  else {
591    [_meshButtons setSelected:NO forSegment:0];
592  }
593
594  if(opt_mesh_lines(0, GMSH_GET, 0)) {
595    [_meshButtons setSelected:YES forSegment:1];
596  }
597  else {
598    [_meshButtons setSelected:NO forSegment:1];
599  }
600
601  if(opt_mesh_surface_edges(0, GMSH_GET, 0)) {
602    [_meshButtons setSelected:YES forSegment:2];
603  }
604  else {
605    [_meshButtons setSelected:NO forSegment:2];
606  }
607
608  if(opt_mesh_surface_faces(0, GMSH_GET, 0)) {
609    [_meshButtons setSelected:YES forSegment:3];
610  }
611  else {
612    [_meshButtons setSelected:NO forSegment:3];
613  }
614
615  if(opt_mesh_volume_edges(0, GMSH_GET, 0)) {
616    [_meshButtons setSelected:YES forSegment:4];
617  }
618  else {
619    [_meshButtons setSelected:NO forSegment:4];
620  }
621
622  if(opt_mesh_volume_faces(0, GMSH_GET, 0)) {
623    [_meshButtons setSelected:YES forSegment:5];
624  }
625  else {
626    [_meshButtons setSelected:NO forSegment:5];
627  }
628}
629
630- (void)updateMeshSliderNormalTangent
631{
632  NSInteger segment = _meshButtonsNormalTangent.selectedSegment;
633  if(segment == 0) { // Normal
634    _meshSliderNormalTangent.slider.doubleValue = opt_mesh_normals(0, GMSH_GET, 0);
635  }
636  else { // Tangent
637    _meshSliderNormalTangent.slider.doubleValue = opt_mesh_tangents(0, GMSH_GET, 0);
638  }
639}
640
641
642- (void)updateViewMenu
643{
644  if(PView::list.empty()) { _viewMenuButton.hidden = YES; }
645  else {
646    _viewMenuButton.hidden = NO;
647  }
648}
649
650- (void)updateViewButtons
651{
652  for(std::size_t i = 0; i < PView::list.size(); i++) {
653    if(opt_view_visible(i, GMSH_GET, 0)) {
654      NSInteger opt = opt_view_intervals_type(i, GMSH_GET, 0);
655      [_viewButtons setSelected:YES forSegment:opt - 1];
656    }
657  }
658}
659
660- (void)updateViewSlider
661{
662  for(std::size_t i = 0; i < PView::list.size(); i++) {
663    if(opt_view_visible(i, GMSH_GET, 0)) {
664      NSInteger opt = opt_view_intervals_type(i, GMSH_GET, 0);
665      if(opt - 1 == 1 || opt - 1 == 3) { // For iso-values and filled iso-values
666        _viewSlider.hidden = YES;
667      }
668      else {
669        _viewSlider.hidden = NO;
670        _viewSlider.doubleValue = opt_view_nb_iso(i, GMSH_GET, 0);
671      }
672    }
673  }
674}
675
676- (void)update
677{
678  [self updateGeo];
679  [self updateGeoSliderNormalTangent];
680  [self updateMesh];
681  [self updateMeshSliderNormalTangent];
682  [self updateViewMenu];
683  [self updateViewButtons];
684  [self updateViewSlider];
685}
686@end
687
688TouchBarDelegate *touchBarDelegate = nullptr;
689void showTouchBar()
690{
691  if(!touchBarDelegate) {
692    touchBarDelegate = [[TouchBarDelegate alloc] init];
693    [NSApplication sharedApplication]
694      .automaticCustomizeTouchBarMenuItemEnabled = YES;
695  }
696
697  NSTouchBar *touchBar = [touchBarDelegate makeTouchBar];
698
699  NSArray<NSWindow *> *windows = [NSApplication sharedApplication].windows;
700  for(int i = 0; i < windows.count; ++i) {
701    NSWindow *wnd = windows[i];
702    wnd.touchBar = touchBar;
703  }
704}
705
706void updateTouchBar() { [touchBarDelegate update]; }
707