1#import "Parameter.h"
2#import "Utils.h"
3
4@implementation Parameter
5- (id)init
6{
7  self = [super init];
8  if(self) {
9    label = [[UILabel alloc] init];
10    // set font size at 90% of default size
11    label.font = [label.font fontWithSize:(0.9 * label.font.pointSize)];
12    [label setBackgroundColor:[UIColor clearColor]];
13  }
14  return self;
15}
16
17- (void)refresh
18{
19  return;
20}
21
22- (NSString *)getName
23{
24  return name;
25}
26
27- (UILabel *)getLabel
28{
29  return label;
30}
31
32- (void)setFrame:(CGRect)frame
33{
34  return;
35}
36
37- (void)setLabelFrame:(CGRect)frame
38{
39  [label setFrame:frame];
40}
41
42- (void)editValue
43{
44  if(onelab_cb("check") > 0) {
45    [[NSNotificationCenter defaultCenter] postNotificationName:@"requestRender"
46                                                        object:nil];
47    [[NSNotificationCenter defaultCenter]
48      postNotificationName:@"refreshParameters"
49                    object:nil];
50  }
51}
52
53+ (double)getHeight
54{
55  return 65.0f;
56}
57@end
58
59@implementation ParameterStringList
60- (id)initWithString:(onelab::string)string
61{
62  self = [super init];
63  if(self) {
64    [label setText:[Utils getStringFromCString:string.getShortName().c_str()]];
65    name = [Utils getStringFromCString:string.getName().c_str()];
66    button = [UIButton buttonWithType:UIButtonTypeSystem];
67    [button addTarget:self
68                action:@selector(selectValue)
69      forControlEvents:UIControlEventTouchDown];
70    [button setTitle:[Utils getStringFromCString:string.getValue().c_str()]
71            forState:UIControlStateNormal];
72    [button setEnabled:(string.getReadOnly() ? FALSE : TRUE)];
73    [label setEnabled:(string.getReadOnly() ? FALSE : TRUE)];
74  }
75  return self;
76}
77
78- (void)selectValue
79{
80  std::vector<onelab::string> string;
81  onelab::server::instance()->get(string, [name UTF8String]);
82  if(string.size() < 1) return;
83  UIAlertController *alertController = [UIAlertController
84    alertControllerWithTitle:nil
85                     message:nil
86              preferredStyle:UIAlertControllerStyleActionSheet];
87  [alertController
88    addAction:[UIAlertAction actionWithTitle:@"Cancel"
89                                       style:UIAlertActionStyleCancel
90                                     handler:^(UIAlertAction *action){}]];
91  std::vector<std::string> choices = string[0].getChoices();
92  for(unsigned int i = 0; i < choices.size(); i++) {
93    NSString *t = [Utils getStringFromCString:choices[i].c_str()];
94    [alertController
95      addAction:[UIAlertAction
96                  actionWithTitle:t
97                            style:UIAlertActionStyleDefault
98                          handler:^(UIAlertAction *action) {
99                            [self updateString:string[0] withValue:choices[i]];
100                            [self->button
101                              setTitle:[Utils getStringFromCString:choices[i]
102                                                                     .c_str()]
103                              forState:UIControlStateNormal];
104                          }]];
105  }
106  [alertController setModalPresentationStyle:UIModalPresentationPopover];
107  UIPopoverPresentationController *popPresenter =
108    [alertController popoverPresentationController];
109  popPresenter.sourceView = button;
110  popPresenter.sourceRect = button.bounds;
111  // FIXME: is traverseResponderChainForUIViewController a good idea?
112  [[Utils traverseResponderChainForUIViewController:button]
113    presentViewController:alertController
114                 animated:YES
115               completion:nil];
116}
117
118- (void)updateString:(onelab::string)s withValue:(std::string)v
119{
120  s.setValue(v);
121  onelab::server::instance()->set(s);
122  [super editValue];
123}
124
125- (void)refresh
126{
127  std::vector<onelab::string> string;
128  onelab::server::instance()->get(string, [name UTF8String]);
129  if(string.size() < 1) return;
130  [button setTitle:[Utils getStringFromCString:string[0].getValue().c_str()]
131          forState:UIControlStateNormal];
132  [button setEnabled:(string[0].getReadOnly() ? FALSE : TRUE)];
133  [label setEnabled:(string[0].getReadOnly() ? FALSE : TRUE)];
134}
135
136- (void)setFrame:(CGRect)frame
137{
138  [button setFrame:frame];
139}
140
141- (UIButton *)getUIView
142{
143  return button;
144}
145
146@end
147
148@implementation ParameterNumberList
149- (id)initWithNumber:(onelab::number)number
150{
151  self = [super init];
152  if(self) {
153    [label setText:[Utils getStringFromCString:number.getShortName().c_str()]];
154    name = [Utils getStringFromCString:number.getName().c_str()];
155    button = [UIButton buttonWithType:UIButtonTypeSystem];
156    [button addTarget:self
157                action:@selector(selectValue)
158      forControlEvents:UIControlEventTouchDown];
159    [button
160      setTitle:[Utils
161                 getStringFromCString:number.getValueLabel(number.getValue())
162                                        .c_str()]
163      forState:UIControlStateNormal];
164    [button setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
165    [label setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
166  }
167  return self;
168}
169
170- (void)selectValue
171{
172  std::vector<onelab::number> numbers;
173  onelab::server::instance()->get(numbers, [name UTF8String]);
174  if(numbers.size() < 1) return;
175  UIAlertController *alertController = [UIAlertController
176    alertControllerWithTitle:nil
177                     message:nil
178              preferredStyle:UIAlertControllerStyleActionSheet];
179  [alertController
180    addAction:[UIAlertAction actionWithTitle:@"Cancel"
181                                       style:UIAlertActionStyleCancel
182                                     handler:^(UIAlertAction *action){}]];
183  std::vector<double> choices = numbers[0].getChoices();
184  for(unsigned int i = 0; i < choices.size(); i++) {
185    NSString *t =
186      [Utils getStringFromCString:numbers[0].getValueLabel(choices[i]).c_str()];
187    [alertController
188      addAction:[UIAlertAction
189                  actionWithTitle:t
190                            style:UIAlertActionStyleDefault
191                          handler:^(UIAlertAction *action) {
192                            [self updateNumber:numbers[0] withValue:choices[i]];
193                            [self->button
194                              setTitle:[Utils
195                                         getStringFromCString:numbers[0]
196                                                                .getValueLabel(
197                                                                  i)
198                                                                .c_str()]
199                              forState:UIControlStateNormal];
200                          }]];
201  }
202  [alertController setModalPresentationStyle:UIModalPresentationPopover];
203  UIPopoverPresentationController *popPresenter =
204    [alertController popoverPresentationController];
205  popPresenter.sourceView = button;
206  popPresenter.sourceRect = button.bounds;
207  // FIXME: is traverseResponderChainForUIViewController a good idea?
208  [[Utils traverseResponderChainForUIViewController:button]
209    presentViewController:alertController
210                 animated:YES
211               completion:nil];
212}
213
214- (void)updateNumber:(onelab::number)n withValue:(double)v
215{
216  n.setValue(v);
217  onelab::server::instance()->set(n);
218  [super editValue];
219}
220
221- (void)refresh
222{
223  std::vector<onelab::number> number;
224  onelab::server::instance()->get(number, [name UTF8String]);
225  if(number.size() < 1) return;
226  [button
227    setTitle:[Utils getStringFromCString:number[0]
228                                           .getValueLabel(number[0].getValue())
229                                           .c_str()]
230    forState:UIControlStateNormal];
231  [button setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
232  [label setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
233}
234
235- (void)setFrame:(CGRect)frame
236{
237  [button setFrame:frame];
238}
239
240- (UIButton *)getUIView
241{
242  return button;
243}
244
245@end
246
247@implementation ParameterNumberCheckbox
248- (id)initWithNumber:(onelab::number)number
249{
250  self = [super init];
251  if(self) {
252    [label setText:[Utils getStringFromCString:number.getShortName().c_str()]];
253    name = [Utils getStringFromCString:number.getName().c_str()];
254    checkbox = [[UISwitch alloc] init];
255    [checkbox setOn:(number.getValue() == 1)];
256    [checkbox addTarget:self
257                 action:@selector(valueChange:)
258       forControlEvents:UIControlEventValueChanged];
259    [checkbox setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
260    [label setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
261  }
262  return self;
263}
264
265- (void)refresh
266{
267  std::vector<onelab::number> number;
268  onelab::server::instance()->get(number, [name UTF8String]);
269  if(number.size() < 1) return;
270  [checkbox setSelected:(number[0].getValue() == 1)];
271  [checkbox setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
272  [label setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
273}
274
275- (void)valueChange:(UISwitch *)sender
276{
277  std::vector<onelab::number> number;
278  onelab::server::instance()->get(number, [name UTF8String]);
279  if(number.size() < 1) return;
280  number[0].setValue(([sender isOn]) ? 1 : 0);
281  onelab::server::instance()->set(number[0]);
282  [super editValue];
283}
284
285- (void)setFrame:(CGRect)frame
286{
287  [checkbox setFrame:frame];
288}
289
290- (UISwitch *)getCheckbox
291{
292  return checkbox;
293}
294
295+ (double)getHeight
296{
297  return 45.0f;
298}
299@end
300
301@implementation ParameterNumberStepper
302- (id)initWithNumber:(onelab::number)number
303{
304  self = [super init];
305  if(self) {
306    name = [Utils getStringFromCString:number.getName().c_str()];
307    stepper = [[UIStepper alloc] init];
308    // make the stepper a bit smaller
309    stepper.transform = CGAffineTransformMakeScale(0.8, 0.8);
310    [stepper setValue:number.getValue()];
311    [stepper setStepValue:1];
312    [stepper setMaximumValue:number.getMax()];
313    [stepper setMinimumValue:number.getMin()];
314    [stepper addTarget:self
315                action:@selector(stepperValueChanged:)
316      forControlEvents:UIControlEventValueChanged];
317    [label
318      setText:[NSString
319                stringWithFormat:@"%@ %d",
320                                 [Utils
321                                   getStringFromCString:number.getShortName()
322                                                          .c_str()],
323                                 (int)number.getValue()]];
324    [stepper setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
325    [label setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
326  }
327  return self;
328}
329
330- (void)stepperValueChanged:(UIStepper *)sender
331{
332  std::vector<onelab::number> number;
333  onelab::server::instance()->get(number, [name UTF8String]);
334  if(number.size() < 1) return;
335  number[0].setValue(sender.value);
336  onelab::server::instance()->set(number[0]);
337  [label
338    setText:[NSString
339              stringWithFormat:@"%@ %d",
340                               [Utils getStringFromCString:number[0]
341                                                             .getShortName()
342                                                             .c_str()],
343                               (int)number[0].getValue()]];
344  [super editValue];
345}
346
347- (void)refresh
348{
349  std::vector<onelab::number> number;
350  onelab::server::instance()->get(number, [name UTF8String]);
351  if(number.size() < 1) return;
352  [stepper setValue:number[0].getValue()];
353  [label
354    setText:[NSString
355              stringWithFormat:@"%@ %d",
356                               [Utils getStringFromCString:number[0]
357                                                             .getShortName()
358                                                             .c_str()],
359                               (int)number[0].getValue()]];
360  [stepper setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
361  [label setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
362}
363
364- (void)setFrame:(CGRect)frame
365{
366  [stepper setFrame:frame];
367}
368
369- (UIStepper *)getStepper
370{
371  return stepper;
372}
373
374@end
375
376@implementation ParameterNumberRange
377- (id)initWithNumber:(onelab::number)number
378{
379  self = [super init];
380  if(self) {
381    name = [Utils getStringFromCString:number.getName().c_str()];
382    slider = [[UISlider alloc] init];
383    [slider setMaximumValue:number.getMax()];
384    [slider setMinimumValue:number.getMin()];
385    [slider setValue:number.getValue()];
386    // TODO add step ?
387    [slider addTarget:self
388                action:@selector(sliderValueChanged:)
389      forControlEvents:UIControlEventTouchUpOutside];
390    [slider addTarget:self
391                action:@selector(sliderValueChanged:)
392      forControlEvents:UIControlEventTouchUpInside];
393    [label
394      setText:[NSString
395                stringWithFormat:@"%@ %g",
396                                 [Utils
397                                   getStringFromCString:number.getShortName()
398                                                          .c_str()],
399                                 number.getValue()]];
400    [slider setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
401    [label setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
402  }
403  return self;
404}
405
406- (void)refresh
407{
408  std::vector<onelab::number> number;
409  onelab::server::instance()->get(number, [name UTF8String]);
410  if(number.size() < 1) return;
411  [slider setMaximumValue:number[0].getMax()];
412  [slider setMinimumValue:number[0].getMin()];
413  [slider setValue:number[0].getValue()];
414  [label
415    setText:[NSString
416              stringWithFormat:@"%@ %g",
417                               [Utils getStringFromCString:number[0]
418                                                             .getShortName()
419                                                             .c_str()],
420                               number[0].getValue()]];
421  [slider setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
422  [label setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
423}
424
425- (void)sliderValueChanged:(UISlider *)sender
426{
427  std::vector<onelab::number> number;
428  onelab::server::instance()->get(number, [name UTF8String]);
429  if(number.size() < 1) return;
430  number[0].setValue(sender.value);
431  onelab::server::instance()->set(number[0]);
432  [label
433    setText:[NSString
434              stringWithFormat:@"%@ %g",
435                               [Utils getStringFromCString:number[0]
436                                                             .getShortName()
437                                                             .c_str()],
438                               number[0].getValue()]];
439  [super editValue];
440}
441
442- (void)setFrame:(CGRect)frame
443{
444  [slider setFrame:frame];
445}
446
447- (UISlider *)getSlider
448{
449  return slider;
450}
451
452@end
453
454@implementation ParameterNumberTextbox
455- (id)initWithNumber:(onelab::number)number
456{
457  self = [super init];
458  if(self) {
459    [label setText:[Utils getStringFromCString:number.getShortName().c_str()]];
460    name = [Utils getStringFromCString:number.getName().c_str()];
461    textbox = [[UITextField alloc] init];
462    [textbox setBorderStyle:UITextBorderStyleRoundedRect];
463    [textbox setText:[NSString stringWithFormat:@"%g", number.getValue()]];
464    [textbox setDelegate:self];
465    UIToolbar *numberToolbar =
466      [[UIToolbar alloc] initWithFrame:CGRectMake(0, 0, 320, 50)];
467    numberToolbar.items = [NSArray
468      arrayWithObjects:
469        [[UIBarButtonItem alloc]
470          initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace
471                               target:nil
472                               action:nil],
473        [[UIBarButtonItem alloc] initWithTitle:@"Apply"
474                                         style:UIBarButtonItemStyleDone
475                                        target:self
476                                        action:@selector(doneWithNumberPad)],
477        nil];
478    [numberToolbar sizeToFit];
479    textbox.inputAccessoryView = numberToolbar;
480    [textbox setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
481    [label setEnabled:(number.getReadOnly() ? FALSE : TRUE)];
482  }
483  return self;
484}
485
486- (void)refresh
487{
488  std::vector<onelab::number> number;
489  onelab::server::instance()->get(number, [name UTF8String]);
490  if(number.size() < 1) return;
491  [textbox setText:[NSString stringWithFormat:@"%g", number[0].getValue()]];
492  [textbox setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
493  [label setEnabled:(number[0].getReadOnly() ? FALSE : TRUE)];
494  [textbox reloadInputViews];
495}
496
497- (BOOL)textFieldShouldEndEditing:(UITextField *)textField
498{
499  std::vector<onelab::number> number;
500  onelab::server::instance()->get(number, [name UTF8String]);
501  if(number.size() < 1) return YES;
502  number[0].setValue([textField.text doubleValue]);
503  onelab::server::instance()->set(number[0]);
504  [textField setText:[NSString stringWithFormat:@"%g", number[0].getValue()]];
505  [super editValue];
506  return YES;
507}
508
509- (BOOL)textFieldShouldReturn:(UITextField *)textField
510{
511  return [textField endEditing:YES];
512}
513
514- (void)doneWithNumberPad
515{
516  [textbox endEditing:YES];
517}
518
519- (void)setFrame:(CGRect)frame
520{
521  [textbox setFrame:frame];
522}
523
524- (UITextField *)getTextbox
525{
526  return textbox;
527}
528
529@end
530