1function [handles] = InteractiveHopperSettings(handles,saveOrLoad,varargin)
2% INTERACTIVEHOPPERSETTINGS
3%   Save or load GUI settings from the InteractiveHopper example
4
5%-----------------------------------------------------------------------%
6% The OpenSim API is a toolkit for musculoskeletal modeling and         %
7% simulation. See http://opensim.stanford.edu and the NOTICE file       %
8% for more information. OpenSim is developed at Stanford University     %
9% and supported by the US National Institutes of Health (U54 GM072970,  %
10% R24 HD065690) and by DARPA through the Warrior Web program.           %
11%                                                                       %
12% Copyright (c) 2017 Stanford University and the Authors                %
13% Author(s): Nick Bianco                                                %
14%                                                                       %
15% Licensed under the Apache License, Version 2.0 (the "License");       %
16% you may not use this file except in compliance with the License.      %
17% You may obtain a copy of the License at                               %
18% http://www.apache.org/licenses/LICENSE-2.0.                           %
19%                                                                       %
20% Unless required by applicable law or agreed to in writing, software   %
21% distributed under the License is distributed on an "AS IS" BASIS,     %
22% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or       %
23% implied. See the License for the specific language governing          %
24% permissions and limitations under the License.                        %
25%-----------------------------------------------------------------------%
26
27% Parse inputs
28p = inputParser();
29
30defaultFilename = 'file';
31defaultSetDefaults = false;
32
33addOptional(p,'filename',defaultFilename)
34addOptional(p,'setDefaults',defaultSetDefaults)
35
36parse(p,varargin{:})
37
38filename = p.Results.filename;
39setDefaults = p.Results.setDefaults;
40
41% Prescibe relevant subfields from GUI handles
42subfields = {'Value','Enable','String','Min','Max'};
43
44% Save or load current GUI settings
45switch saveOrLoad
46    case 'save'
47        saveHandles(handles,filename,subfields);
48    case 'load'
49        if setDefaults
50            settings = getDefaults(subfields);
51        else
52            settings = load(filename);
53        end
54
55        handles = loadHandles(handles,settings,subfields);
56end
57
58% LOADHANDLES
59%   Given a MAT file containing settings for the InteractiveHopper GUI,
60%   update the GUI handles to reflect the settings in the relevant setting
61%   subfields.
62function [handles] = loadHandles(handles,settings,subfields)
63
64handleNames = fieldnames(settings);
65
66for i = 1:length(handleNames)
67    for j = 1:length(subfields)
68        if isfield(settings.(handleNames{i}),subfields{j})
69            handles.(handleNames{i}).(subfields{j}) = settings.(handleNames{i}).(subfields{j});
70        end
71    end
72end
73
74% SAVEHANDLES
75%   Given the current set of handles from the InteractiveHopper GUI, save
76%   the settings from each handle's relevant subfields. Settings are saved
77%   to a MAT file in the current working directory.
78function saveHandles(handles,filename,subfields)
79
80settings = struct();
81handleNames = fieldnames(handles);
82
83for i = 1:length(handleNames)
84    for j = 1:length(subfields)
85        if isstruct(handles.(handleNames{i}))
86            if isfield(handles.(handleNames{i}),subfields{j})
87                settings.(handleNames{i}).(subfields{j}) = handles.(handleNames{i}).(subfields{j});
88            end
89        else
90            if isprop(handles.(handleNames{i}),subfields{j})
91                settings.(handleNames{i}).(subfields{j}) = handles.(handleNames{i}).(subfields{j});
92            end
93        end
94    end
95end
96
97save(filename,'-struct','settings')
98
99% SETSUBFIELDS
100%   Set values of settings subfields based on optional inputs.
101function S = setSubfields(S,subfields,field,varargin)
102
103p = inputParser;
104
105for i = 1:length(subfields)
106   addOptional(p,subfields{i},NaN)
107end
108
109parse(p,varargin{:});
110
111for i = 1:length(subfields)
112    if ~isnan(p.Results.(subfields{i}))
113        fieldnames = {field subfields{i}};
114        S = setfield(S,fieldnames{:},p.Results.(subfields{i}));
115    end
116end
117
118% GETDEFAULTS
119%   These settings reflect the default settings that are called by the
120%   InteractiveHopper example upon start up.
121function S = getDefaults(subfields)
122
123muscle = InteractiveHopperParameters('defaultMuscle');
124
125muscleFunc = InteractiveHopperParameters(muscle);
126[max_isometric_force,optimal_fiber_length,tendon_slack_length,muscle_mass] = muscleFunc();
127
128controls = InteractiveHopperParameters('controls');
129[muscleExcitation,muscleExcitationColor,deviceControl,deviceControlColor] = controls();
130
131passiveSlider = InteractiveHopperParameters('passiveSlider');
132[passive_slider,passive_min,passive_max] = passiveSlider();
133
134activeSlider = InteractiveHopperParameters('activeSlider');
135[active_slider,active_min,active_max] = activeSlider();
136
137S = struct();
138
139S = setSubfields(S,subfields,'active_as_prop_myo'        ,'Value',0,'Enable','off');
140S = setSubfields(S,subfields,'active_mass'               ,'Value',0,'Enable','off','String',' ');
141S = setSubfields(S,subfields,'active_mass_text'          ,'Value',0,'Enable','off');
142S = setSubfields(S,subfields,'active_mass_units'         ,'Value',0,'Enable','off');
143S = setSubfields(S,subfields,'active_patella_wrap'       ,'Value',0,'Enable','off');
144S = setSubfields(S,subfields,'active_slider'             ,'Value',active_slider,'Enable','off' ...
145                                                         ,'Min',active_min,'Max',active_max);
146S = setSubfields(S,subfields,'arnold'                    ,'Value',0,'Enable','on');
147S = setSubfields(S,subfields,'average_joe'               ,'Value',1,'Enable','on');
148S = setSubfields(S,subfields,'clear'                     ,'Value',0,'Enable','on');
149S = setSubfields(S,subfields,'deviceControl'             ,'Value',deviceControl);
150S = setSubfields(S,subfields,'deviceControlColor'        ,'Value',deviceControlColor);
151S = setSubfields(S,subfields,'enable_active'             ,'Value',0,'Enable','off');
152S = setSubfields(S,subfields,'enable_passive'            ,'Value',0,'Enable','off');
153S = setSubfields(S,subfields,'katie_ledecky'             ,'Value',0,'Enable','on');
154S = setSubfields(S,subfields,'load_setup'                ,'Value',0,'Enable','on');
155S = setSubfields(S,subfields,'max_isometric_force'       ,'Value',max_isometric_force,'Enable','off' ...
156                                                         ,'String',num2str(max_isometric_force));
157S = setSubfields(S,subfields,'max_isometric_force_text'  ,'Value',0,'Enable','on');
158S = setSubfields(S,subfields,'max_isometric_force_units' ,'Value',0,'Enable','on');
159S = setSubfields(S,subfields,'max_jump_best'             ,'Value',0,'Enable','off');
160S = setSubfields(S,subfields,'max_jump_best_text'        ,'Value',0,'Enable','on');
161S = setSubfields(S,subfields,'max_jump_recent'           ,'Value',0,'Enable','off');
162S = setSubfields(S,subfields,'max_jump_recent_text'      ,'Value',0,'Enable','on');
163S = setSubfields(S,subfields,'muscle'                    ,'Value',muscle);
164S = setSubfields(S,subfields,'muscleExcitation'          ,'Value',muscleExcitation);
165S = setSubfields(S,subfields,'muscleExcitationColor'     ,'Value',muscleExcitationColor);
166S = setSubfields(S,subfields,'muscle_mass'               ,'Value',muscle_mass,'Enable','off' ...
167                                                         ,'String',num2str(muscle_mass));
168S = setSubfields(S,subfields,'muscle_mass_text'          ,'Value',0,'Enable','on');
169S = setSubfields(S,subfields,'muscle_mass_units'         ,'Value',0,'Enable','on');
170S = setSubfields(S,subfields,'new_device_control'        ,'Value',0,'Enable','off');
171S = setSubfields(S,subfields,'new_musc_excitation'       ,'Value',0,'Enable','on');
172S = setSubfields(S,subfields,'passive_mass'              ,'Enable','off','String',' ');
173S = setSubfields(S,subfields,'passive_mass_text'         ,'Value',0,'Enable','off');
174S = setSubfields(S,subfields,'passive_mass_units'        ,'Value',0,'Enable','off');
175S = setSubfields(S,subfields,'passive_patella_wrap'      ,'Value',0,'Enable','off');
176S = setSubfields(S,subfields,'passive_slider'            ,'Value',passive_slider,'Enable','off' ...
177                                                         ,'Min',passive_min,'Max',passive_max);
178S = setSubfields(S,subfields,'reset'                     ,'Value',0,'Enable','on');
179S = setSubfields(S,subfields,'save_setup'                ,'Value',0,'Enable','on');
180S = setSubfields(S,subfields,'setup'                     ,'Value',0,'Enable','on');
181S = setSubfields(S,subfields,'simulate'                  ,'Value',0,'Enable','on');
182S = setSubfields(S,subfields,'stiffness'                 ,'Enable','off','String',' ');
183S = setSubfields(S,subfields,'stiffness_text'            ,'Value',0,'Enable','off');
184S = setSubfields(S,subfields,'stiffness_units'           ,'Value',0,'Enable','off');
185S = setSubfields(S,subfields,'tendon_slack_length'       ,'Value',tendon_slack_length,'Enable','off' ...
186                                                         ,'String',num2str(tendon_slack_length));
187S = setSubfields(S,subfields,'tendon_slack_length_text'  ,'Value',0,'Enable','on');
188S = setSubfields(S,subfields,'tendon_slack_length_units' ,'Value',0,'Enable','on');
189S = setSubfields(S,subfields,'optimal_fiber_length'      ,'Value',optimal_fiber_length,'Enable','off' ...
190                                                         ,'String',num2str(optimal_fiber_length));
191S = setSubfields(S,subfields,'optimal_fiber_length_text' ,'Value',0,'Enable','on');
192S = setSubfields(S,subfields,'optimal_fiber_length_units','Value',0,'Enable','on');
193S = setSubfields(S,subfields,'tension_or_gain'           ,'Enable','off','String',' ');
194S = setSubfields(S,subfields,'tension_or_gain_text'      ,'Value',0,'Enable','off','String','Max Tension');
195S = setSubfields(S,subfields,'tension_or_gain_units'     ,'Value',0,'Enable','off','String','N');
196S = setSubfields(S,subfields,'visualize'                 ,'Value',0,'Enable','on');
197S = setSubfields(S,subfields,'with_device'               ,'Value',0,'Enable','on');
198S = setSubfields(S,subfields,'without_device'            ,'Value',1,'Enable','on');
199