Add a brewfile
[opengl.git] / ui.mm
1 #import "ui.hpp"
2 #import <Cocoa/Cocoa.h>
3
4 @interface Controller : NSObject
5 - (instancetype)initWithBlendshapeNames:(NSArray<NSString *> *)names
6                                                            delegate:(ControlWindowDelegate *)delegate;
7 - (void)sliderMoved:(id)sender;
8 @property(readonly) NSView *view;
9 @end
10
11 @implementation Controller {
12         size_t numBlendshapes;
13         ControlWindowDelegate *delegate;
14         NSMutableArray<NSControl *> *sliders;
15 }
16
17 - (instancetype)initWithBlendshapeNames:(NSArray<NSString *> *)names
18                                                            delegate:(ControlWindowDelegate *)d {
19         if (self = [super init]) {
20                 self->numBlendshapes = [names count];
21                 self->delegate = d;
22         }
23
24         sliders = [NSMutableArray arrayWithCapacity:numBlendshapes];
25         NSStackView *stackView = [NSStackView stackViewWithViews:sliders];
26
27         for (int i = 0; i < numBlendshapes; i++) {
28                 NSSlider *slider = [NSSlider sliderWithTarget:self
29                                                                                            action:@selector(sliderMoved:)];
30                 [slider setTag:i];
31                 sliders[i] = slider;
32
33                 NSTextField *label = [NSTextField labelWithString:names[i]];
34                 NSStackView *rowStackView =
35                         [NSStackView stackViewWithViews:@[ label, slider ]];
36                 [stackView addView:rowStackView inGravity:NSStackViewGravityTop];
37         }
38
39         NSButton *solveButton = [NSButton buttonWithTitle:@"Solve weights"
40                                                                                            target:self
41                                                                                            action:@selector(solveWeights:)];
42         NSButton *resetButton = [NSButton buttonWithTitle:@"Reset weights"
43                                                                                            target:self
44                                                                                            action:@selector(resetWeights:)];
45         NSStackView *buttonStack =
46                 [NSStackView stackViewWithViews:@[ solveButton, resetButton ]];
47         [stackView addView:buttonStack inGravity:NSStackViewGravityTop];
48
49         NSButton *manipsButton =
50                 [NSButton buttonWithTitle:@"Reset Manipulators"
51                                                    target:self
52                                                    action:@selector(resetManipulators:)];
53         [stackView addView:manipsButton inGravity:NSStackViewGravityTop];
54
55         NSButton *animCheckbox =
56                 [NSButton checkboxWithTitle:@"Play animation"
57                                                          target:self
58                                                          action:@selector(animationPlayback:)];
59         [stackView addView:animCheckbox inGravity:NSStackViewGravityTop];
60
61         [stackView setOrientation:NSUserInterfaceLayoutOrientationVertical];
62         [stackView setEdgeInsets:NSEdgeInsetsMake(16, 16, 16, 16)];
63         _view = stackView;
64
65         return self;
66 }
67
68 - (void)sliderMoved:(id)sender {
69         NSSlider *slider = (NSSlider *)sender;
70         delegate->weightChanged([slider tag], [slider floatValue]);
71 }
72
73 - (void)solveWeights:(id)sender {
74         std::vector<float> newWeights(numBlendshapes);
75         delegate->solveWeights(newWeights);
76         for (int i = 0; i < numBlendshapes; i++)
77                 [sliders[i] setFloatValue:newWeights[i]];
78 }
79
80 - (void)resetWeights:(id)sender {
81         for (int i = 0; i < numBlendshapes; i++) {
82                 [sliders[i] setFloatValue:0];
83                 delegate->weightChanged(i, 0);
84         }
85 }
86
87 - (void)resetManipulators:(id)sender {
88         delegate->resetManipulators();
89 }
90
91 - (void)animationPlayback:(id)sender {
92         bool play = [(NSButton *)sender state] == NSControlStateValueOn;
93         for (int i = 0; i < [sliders count]; i++)
94                 [sliders[i] setEnabled: !play];
95         delegate->playbackChanged(play);
96 }
97
98 - (void)updateWeights:(NSArray<NSNumber *> *)newWeights {
99         for (int i = 0; i < [newWeights count]; i++)
100                 [sliders[i] setFloatValue:[newWeights[i] floatValue]];
101 }
102
103 @end
104
105 ControlWindow createControlWindow(std::vector<std::string> names,
106                                                                   ControlWindowDelegate *delegate) {
107         NSMutableArray<NSString *> *nsNames =
108                 [NSMutableArray arrayWithCapacity:names.size()];
109         for (auto &n : names)
110                 [nsNames addObject:[NSString stringWithUTF8String:n.c_str()]];
111         Controller *controller =
112                 [[Controller alloc] initWithBlendshapeNames:(NSArray *)nsNames
113                                                                                    delegate:delegate];
114
115         NSWindowStyleMask mask = NSWindowStyleMaskTitled |
116                                                          NSWindowStyleMaskClosable |
117                                                          NSWindowStyleMaskUtilityWindow;
118         NSWindow *window =
119                 [[NSPanel alloc] initWithContentRect:NSMakeRect(20, 20, 340, 420)
120                                                                    styleMask:mask
121                                                                          backing:NSBackingStoreBuffered
122                                                                            defer:NO];
123         [window makeKeyAndOrderFront:nil];
124         [window setTitle:@"Blendshapes"];
125         [window setContentView:[controller view]];
126
127         return {window, controller};
128 }
129
130 bool isPanelFocused(ControlWindow cw) {
131         NSWindow *win = (NSWindow *)cw.window;
132         return [win isKeyWindow];
133 }
134
135 void updateWeights(ControlWindow *cw, std::vector<float> weights) {
136         Controller *c = (Controller *)cw->controller;
137         NSMutableArray<NSNumber *> *nsWeights =
138                 [NSMutableArray arrayWithCapacity:weights.size()];
139         for (int i = 0; i < weights.size(); i++)
140                 nsWeights[i] = [NSNumber numberWithFloat:weights[i]];
141         [c updateWeights:(NSArray *)nsWeights];
142 }