1 /*
2  * Copyright (C) 2002 - David W. Durham
3  *
4  * This file is part of ReZound, an audio editing application.
5  *
6  * ReZound is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published
8  * by the Free Software Foundation; either version 2 of the License,
9  * or (at your option) any later version.
10  *
11  * ReZound is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA
19  */
20 
21 #include "CActionParamDialog.h"
22 
23 #include <stdexcept>
24 
25 #include <istring>
26 
27 #include <CNestedDataFile/CNestedDataFile.h>
28 
29 #include "CStatusComm.h"
30 #include "settings.h"
31 
32 #include "../backend/CActionParameters.h"
33 #include "../backend/CActionSound.h"
34 #include "../backend/AAction.h" // for EUserMessage
35 
36 #include "CFOXIcons.h"
37 
38 FXDEFMAP(CActionParamDialog) CActionParamDialogMap[]=
39 {
40 //	Message_Type			ID							Message_Handler
41 
42 	FXMAPFUNC(SEL_COMMAND,		CActionParamDialog::ID_NATIVE_PRESET_BUTTON,	CActionParamDialog::onPresetUseButton),
43 	FXMAPFUNC(SEL_DOUBLECLICKED,	CActionParamDialog::ID_NATIVE_PRESET_LIST,	CActionParamDialog::onPresetUseButton),
44 
45 	FXMAPFUNC(SEL_COMMAND,		CActionParamDialog::ID_USER_PRESET_USE_BUTTON,	CActionParamDialog::onPresetUseButton),
46 	FXMAPFUNC(SEL_COMMAND,		CActionParamDialog::ID_USER_PRESET_SAVE_BUTTON,	CActionParamDialog::onPresetSaveButton),
47 	FXMAPFUNC(SEL_COMMAND,		CActionParamDialog::ID_USER_PRESET_REMOVE_BUTTON,CActionParamDialog::onPresetRemoveButton),
48 	FXMAPFUNC(SEL_DOUBLECLICKED,	CActionParamDialog::ID_USER_PRESET_LIST,	CActionParamDialog::onPresetUseButton),
49 
50 	FXMAPFUNC(SEL_COMMAND,		CActionParamDialog::ID_EXPLAIN_BUTTON,		CActionParamDialog::onExplainButton),
51 };
52 
53 
FXIMPLEMENT(CActionParamDialog,FXModalDialogBox,CActionParamDialogMap,ARRAYNUMBER (CActionParamDialogMap))54 FXIMPLEMENT(CActionParamDialog,FXModalDialogBox,CActionParamDialogMap,ARRAYNUMBER(CActionParamDialogMap))
55 
56 
57 // ----------------------------------------
58 
59 // ??? TODO Well, I got it to not need the width, it's determined by the
60 // widgets' needed widths.. I don't quite know tho, what the height won't
61 // work the same what.. I'll work on figuring that out and then both
62 // parameters should be unnecessary
63 
64 CActionParamDialog::CActionParamDialog(FXWindow *mainWindow,bool _showPresetPanel,const string _presetPrefix,FXModalDialogBox::ShowTypes showType) :
65 	FXModalDialogBox(mainWindow,"",0,0,FXModalDialogBox::ftVertical,showType),
66 
67 	showPresetPanel(_showPresetPanel),
68 
69 	explanationButtonCreated(false),
70 
71 	splitter(new FXSplitter(getFrame(),SPLITTER_VERTICAL|SPLITTER_REVERSED | LAYOUT_FILL_X|LAYOUT_FILL_Y)),
72 		topPanel(new FXHorizontalFrame(splitter,FRAME_RAISED|FRAME_THICK, 0,0,0,0, 0,0,0,0, 0,0)),
73 			leftMargin(new FXFrame(topPanel,FRAME_NONE|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH,0,0,0,0, 0,0,0,0)),
74 			controlsFrame(new FXPacker(topPanel,FRAME_NONE | LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0, 0,0)),
75 			rightMargin(new FXFrame(topPanel,FRAME_NONE|LAYOUT_FILL_Y|LAYOUT_FIX_WIDTH,0,0,0,0, 0,0,0,0)),
76 		presetsFrame(NULL),
77 			nativePresetList(NULL),
78 			userPresetList(NULL),
79 
80 	presetPrefix(_presetPrefix=="" ? "" : _presetPrefix DOT ""),
81 	firstShowing(true)
82 {
83 	disableFrameDecor();
84 
85 	setHeight(getHeight()+100); // since we're adding this presets section, make the dialog taller
86 
87 	// make sure the dialog has at least a minimum height and width
88 	//ASSURE_HEIGHT(this,10);
89 	//ASSURE_WIDTH(this,200);
90 }
91 
~CActionParamDialog()92 CActionParamDialog::~CActionParamDialog()
93 {
94 }
95 
create()96 void CActionParamDialog::create()
97 {
98 	if(!explanationButtonCreated && getExplanation()!="")
99 		new FXButton(getButtonFrame(),_("Explain"),FOXIcons->explain,this,ID_EXPLAIN_BUTTON,FRAME_RAISED|FRAME_THICK | JUSTIFY_NORMAL | ICON_ABOVE_TEXT | LAYOUT_FIX_WIDTH, 0,0,60,0, 2,2,2,2);
100 	explanationButtonCreated=true;
101 
102 	FXModalDialogBox::create();
103 }
104 
onExplainButton(FXObject * sender,FXSelector sel,void * ptr)105 long CActionParamDialog::onExplainButton(FXObject *sender,FXSelector sel,void *ptr)
106 {
107 	Message(getExplanation());
108 	return 1;
109 }
110 
newHorzPanel(void * parent,bool createMargin,bool createFrame)111 FXPacker *CActionParamDialog::newHorzPanel(void *parent,bool createMargin,bool createFrame)
112 {
113 	if(parent==NULL)
114 	{
115 		if(controlsFrame->numChildren()>0)
116 			throw runtime_error(string(__func__)+" -- this method has already been called with a NULL parameter");
117 		parent=controlsFrame;
118 	}
119 	if(createMargin)
120 		return new FXHorizontalFrame((FXPacker *)parent,(createFrame ? FRAME_RAISED : FRAME_NONE) | LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 2,2,2,2, 0,0);
121 	else
122 		return new FXHorizontalFrame((FXPacker *)parent,(createFrame ? FRAME_RAISED : FRAME_NONE) | LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0, 0,0);
123 }
124 
newVertPanel(void * parent,bool createMargin,bool createFrame)125 FXPacker *CActionParamDialog::newVertPanel(void *parent,bool createMargin,bool createFrame)
126 {
127 	if(parent==NULL)
128 	{
129 		if(controlsFrame->numChildren()>0)
130 			throw runtime_error(string(__func__)+" -- this method has already been called with a NULL parameter");
131 		parent=controlsFrame;
132 	}
133 	if(createMargin)
134 		return new FXVerticalFrame((FXPacker *)parent,(createFrame ? FRAME_RAISED : FRAME_NONE) | LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 2,2,2,2, 0,0);
135 	else
136 		return new FXVerticalFrame((FXPacker *)parent,(createFrame ? FRAME_RAISED : FRAME_NONE) | LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0, 0,0);
137 }
138 
addSlider(void * parent,const string name,const string units,AActionParamMapper * valueMapper,f_at_x optRetValueConv,bool showInverseButton)139 FXConstantParamValue *CActionParamDialog::addSlider(void *parent,const string name,const string units,AActionParamMapper *valueMapper,f_at_x optRetValueConv,bool showInverseButton)
140 {
141 	if(parent==NULL)
142 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
143 	FXConstantParamValue *slider=new FXConstantParamValue(valueMapper,showInverseButton,(FXPacker *)parent,0,name.c_str());
144 	slider->setUnits(units.c_str());
145 	slider->setValue(valueMapper->getDefaultValue());
146 	parameters.push_back(make_pair(ptConstant,slider));
147 	retValueConvs.push_back(optRetValueConv);
148 
149 	return slider;
150 }
151 
getSliderParam(const string name)152 FXConstantParamValue *CActionParamDialog::getSliderParam(const string name)
153 {
154 	const unsigned index=findParamByName(name);
155 	if(parameters[index].first==ptConstant);
156 		return (FXConstantParamValue *)parameters[index].second;
157 	throw runtime_error(string(__func__)+" -- widget with name, "+name+", is not a slider");
158 }
159 
addNumericTextEntry(void * parent,const string name,const string units,const double initialValue,const double minValue,const double maxValue,const string unitsTipText)160 FXTextParamValue *CActionParamDialog::addNumericTextEntry(void *parent,const string name,const string units,const double initialValue,const double minValue,const double maxValue,const string unitsTipText)
161 {
162 	if(parent==NULL)
163 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
164 	FXTextParamValue *textEntry=new FXTextParamValue((FXPacker *)parent,0,name.c_str(),initialValue,minValue,maxValue);
165 	textEntry->setUnits(units.c_str(),unitsTipText.c_str());
166 	parameters.push_back(make_pair(ptNumericText,textEntry));
167 	retValueConvs.push_back(NULL);
168 
169 	return textEntry;
170 }
171 
addStringTextEntry(void * parent,const string name,const string initialValue,const string tipText)172 FXTextParamValue *CActionParamDialog::addStringTextEntry(void *parent,const string name,const string initialValue,const string tipText)
173 {
174 	if(parent==NULL)
175 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
176 	FXTextParamValue *textEntry=new FXTextParamValue((FXPacker *)parent,0,name.c_str(),initialValue);
177 	textEntry->setTipText(tipText.c_str());
178 	parameters.push_back(make_pair(ptStringText,textEntry));
179 	retValueConvs.push_back(NULL);
180 
181 	return textEntry;
182 }
183 
getTextParam(const string name)184 FXTextParamValue *CActionParamDialog::getTextParam(const string name)
185 {
186 	for(size_t t=0;t<parameters.size();t++)
187 	{
188 		if((parameters[t].first==ptStringText || parameters[t].first==ptNumericText) && ((FXTextParamValue *)parameters[t].second)->getName()==name)
189 			return (FXTextParamValue *)parameters[t].second;
190 	}
191 	throw runtime_error(string(__func__)+" -- no text param found named "+name);
192 }
193 
addDiskEntityEntry(void * parent,const string name,const string initialEntityName,FXDiskEntityParamValue::DiskEntityTypes entityType,const string tipText)194 FXDiskEntityParamValue *CActionParamDialog::addDiskEntityEntry(void *parent,const string name,const string initialEntityName,FXDiskEntityParamValue::DiskEntityTypes entityType,const string tipText)
195 {
196 	if(parent==NULL)
197 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
198 	FXDiskEntityParamValue *diskEntityEntry=new FXDiskEntityParamValue((FXPacker *)parent,0,name.c_str(),initialEntityName,entityType);
199 	diskEntityEntry->setTipText(tipText.c_str());
200 	parameters.push_back(make_pair(ptDiskEntity,diskEntityEntry));
201 	retValueConvs.push_back(NULL);
202 
203 	return diskEntityEntry;
204 }
205 
getDiskEntityParam(const string name)206 FXDiskEntityParamValue *CActionParamDialog::getDiskEntityParam(const string name)
207 {
208 	const unsigned index=findParamByName(name);
209 	if(parameters[index].first==ptDiskEntity)
210 		return (FXDiskEntityParamValue *)parameters[index].second;
211 	throw runtime_error(string(__func__)+" -- widget with name, "+name+", is not a disk entity");
212 }
213 
addComboTextEntry(void * parent,const string name,const vector<string> & items,ComboParamValueTypes type,const string tipText,bool isEditable)214 FXComboTextParamValue *CActionParamDialog::addComboTextEntry(void *parent,const string name,const vector<string> &items,ComboParamValueTypes type,const string tipText,bool isEditable)
215 {
216 	if(parent==NULL)
217 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
218 	FXComboTextParamValue *comboTextEntry=new FXComboTextParamValue((FXPacker *)parent,0,name.c_str(),items,isEditable);
219 	if(type==cpvtAsString)
220 		comboTextEntry->asString=true;
221 	else
222 		comboTextEntry->asString=false;
223 	comboTextEntry->setTipText(tipText.c_str());
224 	parameters.push_back(make_pair(ptComboText,comboTextEntry));
225 	retValueConvs.push_back(NULL);
226 
227 	return comboTextEntry;
228 }
229 
getComboText(const string name)230 FXComboTextParamValue *CActionParamDialog::getComboText(const string name)
231 {
232 	const unsigned index=findParamByName(name);
233 	if(parameters[index].first==ptComboText);
234 		return (FXComboTextParamValue *)parameters[index].second;
235 	throw runtime_error(string(__func__)+" -- widget with name, "+name+", is not a combobox");
236 }
237 
238 
addCheckBoxEntry(void * parent,const string name,const bool checked,const string tipText)239 FXCheckBoxParamValue *CActionParamDialog::addCheckBoxEntry(void *parent,const string name,const bool checked,const string tipText)
240 {
241 	if(parent==NULL)
242 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
243 	FXCheckBoxParamValue *checkBoxEntry=new FXCheckBoxParamValue((FXPacker *)parent,0,name.c_str(),checked);
244 	checkBoxEntry->setTipText(tipText.c_str());
245 	parameters.push_back(make_pair(ptCheckBox,checkBoxEntry));
246 	retValueConvs.push_back(NULL);
247 
248 	return checkBoxEntry;
249 }
250 
getCheckBoxParam(const string name)251 FXCheckBoxParamValue *CActionParamDialog::getCheckBoxParam(const string name)
252 {
253 	const unsigned index=findParamByName(name);
254 	if(parameters[index].first==ptCheckBox)
255 		return (FXCheckBoxParamValue *)parameters[index].second;
256 	throw runtime_error(string(__func__)+" -- widget with name, "+name+", is not a checkbox");
257 }
258 
addGraph(void * parent,const string name,const string horzAxisLabel,const string horzUnits,AActionParamMapper * horzValueMapper,const string vertAxisLabel,const string vertUnits,AActionParamMapper * vertValueMapper,f_at_x optRetValueConv)259 FXGraphParamValue *CActionParamDialog::addGraph(void *parent,const string name,const string horzAxisLabel,const string horzUnits,AActionParamMapper *horzValueMapper,const string vertAxisLabel,const string vertUnits,AActionParamMapper *vertValueMapper,f_at_x optRetValueConv)
260 {
261 	if(parent==NULL)
262 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
263 	FXGraphParamValue *graph=new FXGraphParamValue(name.c_str(),(FXPacker *)parent,LAYOUT_FILL_X|LAYOUT_FILL_Y);
264 	graph->setHorzParameters(horzAxisLabel,horzUnits,horzValueMapper);
265 	graph->setVertParameters(vertAxisLabel,vertUnits,vertValueMapper);
266 	parameters.push_back(make_pair(ptGraph,graph));
267 	retValueConvs.push_back(optRetValueConv);
268 
269 	return graph;
270 }
271 
addGraphWithWaveform(void * parent,const string name,const string vertAxisLabel,const string vertUnits,AActionParamMapper * vertValueMapper,f_at_x optRetValueConv)272 FXGraphParamValue *CActionParamDialog::addGraphWithWaveform(void *parent,const string name,const string vertAxisLabel,const string vertUnits,AActionParamMapper *vertValueMapper,f_at_x optRetValueConv)
273 {
274 	if(parent==NULL)
275 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
276 	FXGraphParamValue *graph=new FXGraphParamValue(name.c_str(),(FXPacker *)parent,LAYOUT_FILL_X|LAYOUT_FILL_Y);
277 	graph->setVertParameters(vertAxisLabel,vertUnits,vertValueMapper);
278 	parameters.push_back(make_pair(ptGraphWithWaveform,graph));
279 	retValueConvs.push_back(optRetValueConv);
280 
281 	return graph;
282 }
283 
getGraphParam(const string name)284 FXGraphParamValue *CActionParamDialog::getGraphParam(const string name)
285 {
286 	for(size_t t=0;t<parameters.size();t++)
287 	{
288 		if((parameters[t].first==ptGraph || parameters[t].first==ptGraphWithWaveform) && ((FXGraphParamValue *)parameters[t].second)->getName()==name)
289 			return (FXGraphParamValue *)parameters[t].second;
290 	}
291 	throw runtime_error(string(__func__)+" -- no graph param found named "+name);
292 }
293 
addLFO(void * parent,const string name,const string ampUnits,const string ampTitle,const double maxAmp,const string freqUnits,const double maxFreq,const bool hideBipolarLFOs)294 FXLFOParamValue *CActionParamDialog::addLFO(void *parent,const string name,const string ampUnits,const string ampTitle,const double maxAmp,const string freqUnits,const double maxFreq,const bool hideBipolarLFOs)
295 {
296 	if(parent==NULL)
297 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
298 	FXLFOParamValue *LFOEntry=new FXLFOParamValue((FXPacker *)parent,0,name.c_str(),ampUnits,ampTitle,maxAmp,freqUnits,maxFreq,hideBipolarLFOs);
299 	//LFOEntry->setTipText(tipText.c_str());
300 	parameters.push_back(make_pair(ptLFO,LFOEntry));
301 	retValueConvs.push_back(NULL);
302 
303 	return LFOEntry;
304 }
305 
getLFOParam(const string name)306 FXLFOParamValue *CActionParamDialog::getLFOParam(const string name)
307 {
308 	const unsigned index=findParamByName(name);
309 	if(parameters[index].first==ptLFO);
310 		return (FXLFOParamValue *)parameters[index].second;
311 	throw runtime_error(string(__func__)+" -- widget with name, "+name+", is not an LFO");
312 }
313 
addPluginRoutingParam(void * parent,const string name,const LADSPA_Descriptor * desc)314 FXPluginRoutingParamValue *CActionParamDialog::addPluginRoutingParam(void *parent,const string name,const LADSPA_Descriptor *desc)
315 {
316 	if(parent==NULL)
317 		throw runtime_error(string(__func__)+" -- parent was passed NULL -- use CActionParameValue::newHorzPanel() or newVertPanel() to obtain a parent parameter to pass");
318 	FXPluginRoutingParamValue *pluginRoutingEntry=new FXPluginRoutingParamValue((FXPacker *)parent,0,name.c_str(),desc);
319 	parameters.push_back(make_pair(ptPluginRouting,pluginRoutingEntry));
320 	retValueConvs.push_back(NULL);
321 
322 	return pluginRoutingEntry;
323 }
324 
getPluginRoutingParam(const string name)325 FXPluginRoutingParamValue *CActionParamDialog::getPluginRoutingParam(const string name)
326 {
327 	const unsigned index=findParamByName(name);
328 	if(parameters[index].first==ptPluginRouting);
329 		return (FXPluginRoutingParamValue *)parameters[index].second;
330 	throw runtime_error(string(__func__)+" -- widget with name, "+name+", is not a Plugin Routing");
331 }
332 
setMargin(FXint margin)333 void CActionParamDialog::setMargin(FXint margin)
334 {
335 	leftMargin->setWidth(margin);
336 	rightMargin->setWidth(margin);
337 }
338 
setValue(size_t index,const double value)339 void CActionParamDialog::setValue(size_t index,const double value)
340 {
341 	switch(parameters[index].first)
342 	{
343 	case ptConstant:
344 		((FXConstantParamValue *)parameters[index].second)->setValue(value);
345 		break;
346 
347 	case ptNumericText:
348 		((FXTextParamValue *)parameters[index].second)->setValue(value);
349 		break;
350 
351 	case ptStringText:
352 		((FXTextParamValue *)parameters[index].second)->setText(istring(value));
353 		break;
354 
355 	case ptComboText:
356 		((FXComboTextParamValue *)parameters[index].second)->setIntegerValue((FXint)value);
357 		break;
358 
359 	case ptCheckBox:
360 		((FXCheckBoxParamValue *)parameters[index].second)->setValue((bool)value);
361 		break;
362 
363 	case ptGraph:
364 	case ptGraphWithWaveform:
365 		/*
366 		((FXGraphParamValue *)parameters[index].second)->setValue(value);
367 		break;
368 		*/
369 
370 	case ptLFO:
371 		/*
372 		((FXGraphParamValue *)parameters[index].second)->setValue(value);
373 		break;
374 		*/
375 
376 	case ptPluginRouting:
377 		/*
378 		((FXGraphParamValue *)parameters[index].second)->setValue(value);
379 		 break;
380 		 */
381 
382 	default:
383 		throw runtime_error(string(__func__)+" -- unhandled or unimplemented parameter type: "+istring(parameters[index].first));
384 	}
385 }
386 
setTipText(const string name,const string tipText)387 void CActionParamDialog::setTipText(const string name,const string tipText)
388 {
389 	const unsigned index=findParamByName(name);
390 
391 	switch(parameters[index].first)
392 	{
393 	case ptConstant:
394 		((FXConstantParamValue *)parameters[index].second)->setTipText(tipText.c_str());
395 		break;
396 
397 	case ptNumericText:
398 	case ptStringText:
399 		((FXTextParamValue *)parameters[index].second)->setTipText(tipText.c_str());
400 		break;
401 
402 	case ptDiskEntity:
403 		((FXDiskEntityParamValue *)parameters[index].second)->setTipText(tipText.c_str());
404 		break;
405 
406 	case ptComboText:
407 		((FXComboTextParamValue *)parameters[index].second)->setTipText(tipText.c_str());
408 		break;
409 
410 	case ptCheckBox:
411 		((FXCheckBoxParamValue *)parameters[index].second)->setTipText(tipText.c_str());
412 		break;
413 
414 	case ptGraph:
415 	case ptGraphWithWaveform:
416 /*
417 		((FXGraphParamValue *)parameters[index].second)->setTipText(tipText.c_str());
418 		break;
419 */
420 
421 	case ptLFO:
422 /*
423 		((FXLFOParamValue *)parameters[index].second)->setTipText(tipText.c_str());
424 		break;
425 */
426 
427 	case ptPluginRouting:
428 /*
429 		((FXPluginRoutingParamValue *)parameters[index].second)->setTipText(tipText.c_str());
430 		break;
431 */
432 
433 	default:
434 		throw runtime_error(string(__func__)+" -- unhandled or unimplemented parameter type: "+istring(parameters[index].first));
435 	}
436 }
437 
showControl(const string name,bool show)438 void CActionParamDialog::showControl(const string name,bool show)
439 {
440 	const unsigned index=findParamByName(name);
441 
442 	switch(parameters[index].first)
443 	{
444 	case ptConstant:
445 		if(show)
446 			((FXConstantParamValue *)parameters[index].second)->show();
447 		else
448 			((FXConstantParamValue *)parameters[index].second)->hide();
449 		break;
450 
451 	case ptNumericText:
452 	case ptStringText:
453 		if(show)
454 			((FXTextParamValue *)parameters[index].second)->show();
455 		else
456 			((FXTextParamValue *)parameters[index].second)->hide();
457 		break;
458 
459 	case ptDiskEntity:
460 		if(show)
461 			((FXDiskEntityParamValue *)parameters[index].second)->show();
462 		else
463 			((FXDiskEntityParamValue *)parameters[index].second)->hide();
464 		break;
465 
466 	case ptComboText:
467 		if(show)
468 			((FXComboTextParamValue *)parameters[index].second)->show();
469 		else
470 			((FXComboTextParamValue *)parameters[index].second)->hide();
471 		break;
472 
473 	case ptCheckBox:
474 		if(show)
475 			((FXCheckBoxParamValue *)parameters[index].second)->show();
476 		else
477 			((FXCheckBoxParamValue *)parameters[index].second)->hide();
478 		break;
479 
480 	case ptGraph:
481 	case ptGraphWithWaveform:
482 		if(show)
483 			((FXGraphParamValue *)parameters[index].second)->show();
484 		else
485 			((FXGraphParamValue *)parameters[index].second)->hide();
486 		break;
487 
488 	case ptLFO:
489 		if(show)
490 			((FXLFOParamValue *)parameters[index].second)->show();
491 		else
492 			((FXLFOParamValue *)parameters[index].second)->hide();
493 		break;
494 
495 	case ptPluginRouting:
496 		if(show)
497 			((FXPluginRoutingParamValue *)parameters[index].second)->show();
498 		else
499 			((FXPluginRoutingParamValue *)parameters[index].second)->hide();
500 		break;
501 
502 	default:
503 		throw runtime_error(string(__func__)+" -- unhandled or unimplemented parameter type: "+istring(parameters[index].first));
504 	}
505 
506 	// tell it to recalc if the number of shown or hidden children changes
507 	parameters[index].second->getParent()->recalc();
508 }
509 
show(CActionSound * actionSound,CActionParameters * actionParameters)510 bool CActionParamDialog::show(CActionSound *actionSound,CActionParameters *actionParameters)
511 {
512 	bool retval=false;
513 
514 	if(getOrigTitle()=="")
515 		throw runtime_error(string(__func__)+" -- title was never set");
516 
517 	buildPresetLists();
518 
519 	// restore the splitter's position
520 	const FXint h=gSettingsRegistry->getValue<int>("FOX" DOT "SplitterPositions" DOT presetPrefix+getOrigTitle());
521 	if(presetsFrame!=NULL)
522 		presetsFrame->setHeight(h);
523 
524 
525 	// initialize all the graphs to this sound
526 	for(size_t t=0;t<parameters.size();t++)
527 	{
528 		if(parameters[t].first==ptGraphWithWaveform)
529 		{
530 			((FXGraphParamValue *)parameters[t].second)->setSound(actionSound->sound,actionSound->start,actionSound->stop);
531 			if(firstShowing)
532 				((FXGraphParamValue *)parameters[t].second)->clearNodes();
533 		}
534 		else if(parameters[t].first==ptPluginRouting)
535 			((FXPluginRoutingParamValue *)parameters[t].second)->setSound(actionSound->sound);
536 	}
537 
538 	firstShowing=false;
539 
540 reshow:
541 
542 	if(execute(PLACEMENT_CURSOR))
543 	{
544 		vector<string> addedParameters;
545 		try
546 		{
547 			for(unsigned t=0;t<parameters.size();t++)
548 			{
549 				switch(parameters[t].first)
550 				{
551 				case ptConstant:
552 					{
553 						FXConstantParamValue *slider=(FXConstantParamValue *)parameters[t].second;
554 						double ret=slider->getValue();
555 
556 						if(retValueConvs[t]!=NULL)
557 							ret=retValueConvs[t](ret);
558 
559 						actionParameters->setValue<double>(slider->getName(),ret);
560 						addedParameters.push_back(slider->getName());
561 					}
562 					break;
563 
564 				case ptNumericText:
565 					{
566 						FXTextParamValue *textEntry=(FXTextParamValue *)parameters[t].second;
567 						double ret=textEntry->getValue();
568 
569 						if(retValueConvs[t]!=NULL)
570 							ret=retValueConvs[t](ret);
571 
572 						actionParameters->setValue<double>(textEntry->getName(),ret);
573 						addedParameters.push_back(textEntry->getName());
574 					}
575 					break;
576 
577 				case ptStringText:
578 					{
579 						FXTextParamValue *textEntry=(FXTextParamValue *)parameters[t].second;
580 						const string ret=textEntry->getText();
581 						actionParameters->setValue<string>(textEntry->getName(),ret);
582 						addedParameters.push_back(textEntry->getName());
583 					}
584 					break;
585 
586 				case ptDiskEntity:
587 					{
588 						FXDiskEntityParamValue *diskEntityEntry=(FXDiskEntityParamValue *)parameters[t].second;
589 						const string ret=diskEntityEntry->getEntityName();
590 
591 						actionParameters->setValue<string>(diskEntityEntry->getName(),ret);
592 
593 						if(diskEntityEntry->getEntityType()==FXDiskEntityParamValue::detAudioFilename)
594 							actionParameters->setValue<bool>(diskEntityEntry->getName()+" OpenAsRaw",diskEntityEntry->getOpenAsRaw());
595 						addedParameters.push_back(diskEntityEntry->getName());
596 					}
597 					break;
598 
599 				case ptComboText:
600 					{
601 						FXComboTextParamValue *comboTextEntry=(FXComboTextParamValue *)parameters[t].second;
602 						if(comboTextEntry->asString)
603 						{ // return the text of the item selected
604 							actionParameters->setValue<string>(comboTextEntry->getName(),comboTextEntry->getStringValue());
605 						}
606 						else
607 						{ // return values as integer of the index that was selected
608 							FXint ret=comboTextEntry->getIntegerValue();
609 							actionParameters->setValue<unsigned>(comboTextEntry->getName(),(unsigned)ret);
610 						}
611 						addedParameters.push_back(comboTextEntry->getName());
612 					}
613 					break;
614 
615 				case ptCheckBox:
616 					{
617 						FXCheckBoxParamValue *checkBoxEntry=(FXCheckBoxParamValue *)parameters[t].second;
618 						bool ret=checkBoxEntry->getValue();
619 
620 						actionParameters->setValue<bool>(checkBoxEntry->getName(),ret);
621 						addedParameters.push_back(checkBoxEntry->getName());
622 					}
623 					break;
624 
625 				case ptGraph:
626 				case ptGraphWithWaveform:
627 					{
628 						FXGraphParamValue *graph=(FXGraphParamValue *)parameters[t].second;
629 						CGraphParamValueNodeList nodes=graph->getNodes();
630 
631 						if(retValueConvs[t]!=NULL)
632 						{
633 							for(size_t i=0;i<nodes.size();i++)
634 								nodes[i].y=retValueConvs[t](nodes[i].y);
635 						}
636 
637 						actionParameters->setValue<CGraphParamValueNodeList>(graph->getName(),nodes);
638 						addedParameters.push_back(graph->getName());
639 					}
640 					break;
641 
642 				case ptLFO:
643 					{
644 						FXLFOParamValue *LFOEntry=(FXLFOParamValue *)parameters[t].second;
645 						actionParameters->setValue<CLFODescription>(LFOEntry->getName(),LFOEntry->getValue());
646 						addedParameters.push_back(LFOEntry->getName());
647 					}
648 					break;
649 
650 				case ptPluginRouting:
651 					{
652 						FXPluginRoutingParamValue *pluginRoutingEntry=(FXPluginRoutingParamValue *)parameters[t].second;
653 						actionParameters->setValue<CPluginMapping>(pluginRoutingEntry->getName(),pluginRoutingEntry->getValue());
654 						addedParameters.push_back(pluginRoutingEntry->getName());
655 					}
656 					break;
657 
658 				default:
659 					throw runtime_error(string(__func__)+" -- unhandled parameter type: "+istring(parameters[t].first));
660 				}
661 			}
662 			retval=true;
663 		}
664 		catch(EUserMessage &e)
665 		{
666 			if(e.what()[0])
667 			{
668 				Message(e.what());
669 				for(size_t t=0;t<addedParameters.size();t++)
670 					actionParameters->removeKey(addedParameters[t]);
671 				goto reshow;
672 			}
673 			else
674 				retval=false;;
675 		}
676 	}
677 
678 	// save the splitter's position
679 	if(presetsFrame!=NULL)
680 	{
681 		FXint h2=presetsFrame->getHeight();
682 		gSettingsRegistry->setValue<string>("FOX" DOT "SplitterPositions" DOT presetPrefix+getOrigTitle(),istring(h2));
683 	}
684 
685 	hide(); // hide now and ...
686 #if FOX_MAJOR>0 // stupid debian's old crap
687 	getApp()->repaint(); // force redraws from disappearing dialogs now
688 #endif
689 
690 	return retval;
691 }
692 
hide()693 void CActionParamDialog::hide()
694 {
695 	FXModalDialogBox::hide();
696 }
697 
onPresetUseButton(FXObject * sender,FXSelector sel,void * ptr)698 long CActionParamDialog::onPresetUseButton(FXObject *sender,FXSelector sel,void *ptr)
699 {
700 	CNestedDataFile *presetsFile;
701 	FXList *listBox;
702 	if(FXSELID(sel)==ID_NATIVE_PRESET_BUTTON || FXSELID(sel)==ID_NATIVE_PRESET_LIST)
703 	{
704 		presetsFile=gSysPresetsFile;
705 		listBox=nativePresetList;
706 	}
707 	else //if(FXSELID(sel)==ID_USER_PRESET_BUTTON || FXSELID(sel)==ID_USER_PRESET_LIST)
708 	{
709 		presetsFile=gUserPresetsFile;
710 		listBox=userPresetList;
711 	}
712 
713 	try
714 	{
715 		if(listBox->getCurrentItem()<0)
716 		{
717 			gStatusComm->beep();
718 			return 1;
719 		}
720 
721 		const string name=string(listBox->getItemText(listBox->getCurrentItem()).text()).substr(4);
722 		const string title=presetPrefix+getOrigTitle() DOT name;
723 
724 		for(unsigned t=0;t<parameters.size();t++)
725 		{
726 			switch(parameters[t].first)
727 			{
728 			case ptConstant:
729 				((FXConstantParamValue *)parameters[t].second)->readFromFile(title,presetsFile);
730 				break;
731 
732 			case ptNumericText:
733 			case ptStringText:
734 				((FXTextParamValue *)parameters[t].second)->readFromFile(title,presetsFile);
735 				break;
736 
737 			case ptDiskEntity:
738 				((FXDiskEntityParamValue *)parameters[t].second)->readFromFile(title,presetsFile);
739 				break;
740 
741 			case ptComboText:
742 				((FXComboTextParamValue *)parameters[t].second)->readFromFile(title,presetsFile);
743 				break;
744 
745 			case ptCheckBox:
746 				((FXCheckBoxParamValue *)parameters[t].second)->readFromFile(title,presetsFile);
747 				break;
748 
749 			case ptGraph:
750 			case ptGraphWithWaveform:
751 				((FXGraphParamValue *)parameters[t].second)->readFromFile(title,presetsFile);
752 				break;
753 
754 			case ptLFO:
755 				((FXLFOParamValue *)parameters[t].second)->readFromFile(title,presetsFile);
756 				break;
757 
758 			case ptPluginRouting:
759 				((FXPluginRoutingParamValue *)parameters[t].second)->readFromFile(title,presetsFile);
760 				break;
761 
762 			default:
763 				throw runtime_error(string(__func__)+" -- unhandled parameter type: "+istring(parameters[t].first));
764 			}
765 		}
766 	}
767 	catch(exception &e)
768 	{
769 		Error(e.what());
770 	}
771 
772 	return 1;
773 }
774 
onPresetSaveButton(FXObject * sender,FXSelector sel,void * ptr)775 long CActionParamDialog::onPresetSaveButton(FXObject *sender,FXSelector sel,void *ptr)
776 {
777 	FXString _name=userPresetList->getCurrentItem()>=0 ? (userPresetList->getItemText(userPresetList->getCurrentItem())).mid(4,255) : "";
778 
779 	askAgain:
780 	if(FXInputDialog::getString(_name,this,_("Preset Name"),_("Preset Name")))
781 	{
782 		if(_name.trim()=="")
783 		{
784 			Error(_("Invalid Preset Name"));
785 			goto askAgain;
786 		}
787 
788 		string name=_name.text();
789 
790 		// make sure it doesn't contain DOT
791 		if(name.find(CNestedDataFile::delim)!=string::npos)
792 		{
793 			Error(_("Preset Name cannot contain")+string(" '")+string(CNestedDataFile::delim)+"'");
794 			goto askAgain;
795 		}
796 
797 		try
798 		{
799 			CNestedDataFile *presetsFile=gUserPresetsFile;
800 
801 
802 			const string title=presetPrefix+getOrigTitle() DOT name;
803 
804 			bool alreadyExists=false;
805 			if(presetsFile->keyExists(title))
806 			{
807 				alreadyExists=true;
808 				if(Question(_("Overwrite Existing Preset")+string(" '")+name+"'",yesnoQues)!=yesAns)
809 					return 1;
810 			}
811 
812 			for(unsigned t=0;t<parameters.size();t++)
813 			{
814 				switch(parameters[t].first)
815 				{
816 				case ptConstant:
817 					((FXConstantParamValue *)parameters[t].second)->writeToFile(title,presetsFile);
818 					break;
819 
820 				case ptNumericText:
821 				case ptStringText:
822 					((FXTextParamValue *)parameters[t].second)->writeToFile(title,presetsFile);
823 					break;
824 
825 				case ptDiskEntity:
826 					((FXDiskEntityParamValue *)parameters[t].second)->writeToFile(title,presetsFile);
827 					break;
828 
829 				case ptComboText:
830 					((FXComboTextParamValue *)parameters[t].second)->writeToFile(title,presetsFile);
831 					break;
832 
833 				case ptCheckBox:
834 					((FXCheckBoxParamValue *)parameters[t].second)->writeToFile(title,presetsFile);
835 					break;
836 
837 				case ptGraph:
838 				case ptGraphWithWaveform:
839 					((FXGraphParamValue *)parameters[t].second)->writeToFile(title,presetsFile);
840 					break;
841 
842 				case ptLFO:
843 					((FXLFOParamValue *)parameters[t].second)->writeToFile(title,presetsFile);
844 					break;
845 
846 				case ptPluginRouting:
847 					((FXPluginRoutingParamValue *)parameters[t].second)->writeToFile(title,presetsFile);
848 					break;
849 
850 				default:
851 					throw runtime_error(string(__func__)+" -- unhandled parameter type: "+istring(parameters[t].first));
852 				}
853 			}
854 
855 			if(!alreadyExists)
856 			{
857 				const string key=presetPrefix+getOrigTitle() DOT "names";
858 				vector<string> names=presetsFile->getValue<vector<string> >(key);
859 				names.push_back(name);
860 				presetsFile->setValue<vector<string> >(key,names);
861 				buildPresetList(presetsFile,userPresetList);
862 			}
863 
864 			presetsFile->save();
865 		}
866 		catch(exception &e)
867 		{
868 			Error(e.what());
869 		}
870 	}
871 
872 	return 1;
873 }
874 
onPresetRemoveButton(FXObject * sender,FXSelector sel,void * ptr)875 long CActionParamDialog::onPresetRemoveButton(FXObject *sender,FXSelector sel,void *ptr)
876 {
877 	if(userPresetList->getCurrentItem()>=0)
878 	{
879 		string name=(userPresetList->getItemText(userPresetList->getCurrentItem())).mid(4,255).text();
880 		if(Question(_("Remove Preset")+string(" '")+name+"'",yesnoQues)==yesAns)
881 		{
882 			CNestedDataFile *presetsFile=gUserPresetsFile;
883 
884 			const string key=presetPrefix+getOrigTitle() DOT name;
885 
886 			// remove preset's values
887 			presetsFile->removeKey(key);
888 
889 			// remove preset's name from the names array
890 			vector<string> names=presetsFile->getValue<vector<string> >(presetPrefix+getOrigTitle() DOT "names");
891 			names.erase(names.begin()+userPresetList->getCurrentItem());
892 			presetsFile->setValue<vector<string> >(presetPrefix+getOrigTitle() DOT "names",names);
893 
894 			buildPresetList(presetsFile,userPresetList);
895 			presetsFile->save();
896 		}
897 	}
898 	else
899 		gStatusComm->beep();
900 
901 	return 1;
902 }
903 
buildPresetLists()904 void CActionParamDialog::buildPresetLists()
905 {
906 	if(showPresetPanel)
907 	{
908 		bool firstTime=presetsFrame==NULL;
909 
910 		FXint currentNativePresetItem=nativePresetList ? nativePresetList->getCurrentItem() : 0;
911 		FXint currentUserPresetItem=userPresetList ? userPresetList->getCurrentItem() : 0;
912 
913 		// delete previous stuff
914 		delete presetsFrame;
915 			nativePresetList=NULL;
916 			userPresetList=NULL;
917 
918 		// (re)create GUI widgets
919 		presetsFrame=new FXHorizontalFrame(splitter,FRAME_RAISED|FRAME_THICK | LAYOUT_FILL_X, 0,0,0,0, 2,2,2,2);
920 		try
921 		{
922 			if(gSysPresetsFile->getValue<vector<string> >(presetPrefix+getOrigTitle() DOT "names").size()>0)
923 			{
924 				// native preset stuff
925 				FXPacker *listFrame=new FXPacker(presetsFrame,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FIX_WIDTH | LAYOUT_FILL_Y, 0,0,210,0, 0,0,0,0, 0,0); // had to do this because FXList won't take that frame style
926 					nativePresetList=new FXList(listFrame,this,ID_NATIVE_PRESET_LIST,LIST_BROWSESELECT | LAYOUT_FILL_X|LAYOUT_FILL_Y);
927 					nativePresetList->setNumVisible(4);
928 				new FXButton(presetsFrame,_("&Use\tOr Double-Click an Item in the List"),NULL,this,ID_NATIVE_PRESET_BUTTON);
929 			}
930 		}
931 		catch(exception &e)
932 		{
933 			nativePresetList=NULL;
934 			Error(e.what());
935 		}
936 
937 		// user preset stuff
938 		FXPacker *listFrame=new FXPacker(presetsFrame,FRAME_SUNKEN|FRAME_THICK|LAYOUT_FIX_WIDTH | LAYOUT_FILL_Y, 0,0,210,0, 0,0,0,0, 0,0); // had to do this because FXList won't take that frame style
939 			userPresetList=new FXList(listFrame,this,ID_USER_PRESET_LIST,LIST_BROWSESELECT | LAYOUT_FILL_X|LAYOUT_FILL_Y);
940 			userPresetList->setNumVisible(4);
941 		FXPacker *buttonGroup=new FXVerticalFrame(presetsFrame);
942 			new FXButton(buttonGroup,_("&Use\tOr Double-Click an Item in the List"),NULL,this,ID_USER_PRESET_USE_BUTTON,BUTTON_NORMAL|LAYOUT_FILL_X);
943 			new FXButton(buttonGroup,_("&Save"),NULL,this,ID_USER_PRESET_SAVE_BUTTON,BUTTON_NORMAL|LAYOUT_FILL_X);
944 			new FXButton(buttonGroup,_("&Remove"),NULL,this,ID_USER_PRESET_REMOVE_BUTTON,BUTTON_NORMAL|LAYOUT_FILL_X);
945 
946 
947 
948 
949 		// load presets from file
950 
951 		if(nativePresetList!=NULL)
952 		{
953 			try
954 			{
955 				buildPresetList(gSysPresetsFile,nativePresetList);
956 				if(currentNativePresetItem<nativePresetList->getNumItems())
957 					nativePresetList->setCurrentItem(currentNativePresetItem);
958 			}
959 			catch(exception &e)
960 			{
961 				Error(e.what());
962 				nativePresetList->clearItems();
963 			}
964 		}
965 
966 		try
967 		{
968 			buildPresetList(gUserPresetsFile,userPresetList);
969 			if(currentUserPresetItem<userPresetList->getNumItems())
970 				userPresetList->setCurrentItem(currentUserPresetItem);
971 		}
972 		catch(exception &e)
973 		{
974 			Error(e.what());
975 			userPresetList->clearItems();
976 		}
977 
978 		// have to do this after the first showing, otherwise the presets won't show up until you resize the dialog
979 		if(!firstTime)
980 			presetsFrame->create();
981 	}
982 }
983 
buildPresetList(CNestedDataFile * f,FXList * list)984 void CActionParamDialog::buildPresetList(CNestedDataFile *f,FXList *list)
985 {
986 	const vector<string> names=f->getValue<vector<string> >(presetPrefix+getOrigTitle() DOT "names");
987 	list->clearItems();
988 	for(size_t t=0;t<names.size();t++)
989 		list->appendItem((istring(t,3,true)+" "+names[t]).c_str());
990 }
991 
992 
findParamByName(const string name) const993 unsigned CActionParamDialog::findParamByName(const string name) const
994 {
995 	for(unsigned t=0;t<parameters.size();t++)
996 	{
997 		switch(parameters[t].first)
998 		{
999 		case ptConstant:
1000 			if(((FXConstantParamValue *)parameters[t].second)->getName()==name)
1001 				return t;
1002 			break;
1003 
1004 		case ptNumericText:
1005 		case ptStringText:
1006 			if(((FXTextParamValue *)parameters[t].second)->getName()==name)
1007 				return t;
1008 			break;
1009 
1010 		case ptDiskEntity:
1011 			if(((FXDiskEntityParamValue *)parameters[t].second)->getName()==name)
1012 				return t;
1013 			break;
1014 
1015 		case ptComboText:
1016 			if(((FXComboTextParamValue *)parameters[t].second)->getName()==name)
1017 				return t;
1018 			break;
1019 
1020 		case ptCheckBox:
1021 			if(((FXCheckBoxParamValue *)parameters[t].second)->getName()==name)
1022 				return t;
1023 			break;
1024 
1025 		case ptGraph:
1026 		case ptGraphWithWaveform:
1027 			if(((FXGraphParamValue *)parameters[t].second)->getName()==name)
1028 				return t;
1029 			break;
1030 
1031 		case ptLFO:
1032 			if(((FXLFOParamValue *)parameters[t].second)->getName()==name)
1033 				return t;
1034 			break;
1035 
1036 		case ptPluginRouting:
1037 			if(((FXPluginRoutingParamValue *)parameters[t].second)->getName()==name)
1038 				return t;
1039 			break;
1040 
1041 		default:
1042 			throw runtime_error(string(__func__)+" -- unhandled parameter type: "+istring(parameters[t].first));
1043 		}
1044 	}
1045 
1046 	throw runtime_error(string(__func__)+" -- no param found named "+name);
1047 }
1048 
1049