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 "CPasteChannelsDialog.h"
22 
23 #include <algorithm>
24 
25 #include <istring>
26 
27 #include "settings.h"
28 
29 #include "../backend/AAction.h"
30 #include "../backend/CActionSound.h"
31 #include "../backend/CActionParameters.h"
32 #include "../backend/ASoundClipboard.h"
33 
34 #include "../backend/ActionParamMappers.h"
35 
36 CPasteChannelsDialog *gPasteChannelsDialog=NULL;
37 
38 
39 FXDEFMAP(CPasteChannelsDialog) CPasteChannelsDialogMap[]=
40 {
41 //	Message_Type			ID						Message_Handler
42 	FXMAPFUNC(SEL_COMMAND,		CPasteChannelsDialog::ID_DEFAULT_BUTTON,	CPasteChannelsDialog::onDefaultButton),
43 	FXMAPFUNC(SEL_COMMAND,		CPasteChannelsDialog::ID_CLEAR_BUTTON,		CPasteChannelsDialog::onClearButton),
44 
45 	FXMAPFUNC(SEL_COMMAND,		CPasteChannelsDialog::ID_REPEAT_TYPE_COMBOBOX,	CPasteChannelsDialog::onRepeatTypeChange),
46 };
47 
48 
FXIMPLEMENT(CPasteChannelsDialog,FXModalDialogBox,CPasteChannelsDialogMap,ARRAYNUMBER (CPasteChannelsDialogMap))49 FXIMPLEMENT(CPasteChannelsDialog,FXModalDialogBox,CPasteChannelsDialogMap,ARRAYNUMBER(CPasteChannelsDialogMap))
50 
51 
52 
53 // ----------------------------------------
54 
55 // ??? derive this from CActionDialog if I can so that it can have presets, maybe not possible as it is
56 
57 #include "FXConstantParamValue.h"
58 
59 CPasteChannelsDialog::CPasteChannelsDialog(FXWindow *mainWindow) :
60 	FXModalDialogBox(mainWindow,N_("Paste Channels"),100,100,FXModalDialogBox::ftVertical,FXModalDialogBox::stShrinkWrap),
61 
62 	label(new FXLabel(getFrame(),_("Pasting Parameters:"),NULL,LAYOUT_CENTER_X)),
63 	horzSeparator(new FXHorizontalSeparator(getFrame())),
64 	topFrame(new FXHorizontalFrame(getFrame())),
65 		routingContents(new FXMatrix(topFrame,2,MATRIX_BY_COLUMNS | LAYOUT_FILL_X|LAYOUT_FILL_Y)),
66 		vertSeparator(new FXVerticalSeparator(topFrame)),
67 		repeatFrame(new FXVerticalFrame(topFrame,LAYOUT_CENTER_X))
68 {
69 	// setup the repeat type controls
70 
71 	repeatTypeSwitcher=new FXSwitcher(repeatFrame,LAYOUT_CENTER_X);
72 
73 		repeatCountSlider=new FXConstantParamValue(
74 			new CActionParamMapper_linear_bipolar(1.0,4,100),
75 			false,
76 			repeatTypeSwitcher,
77 			LAYOUT_CENTER_X,_("Repeat Count")
78 		);
79 		repeatCountSlider->setUnits("x");
80 
81 		repeatTimeSlider=new FXConstantParamValue(
82 			new CActionParamMapper_linear_bipolar(10.0,60,3600),
83 			false,
84 			repeatTypeSwitcher,
85 			LAYOUT_CENTER_X,_("Repeat Time")
86 		);
87 		repeatTimeSlider->setUnits("s");
88 
89 		repeatTypeSwitcher->setCurrent(0);
90 
91 	repeatTypeComboBox=new FXComboBox(repeatFrame,0,this,ID_REPEAT_TYPE_COMBOBOX,COMBOBOX_NORMAL|COMBOBOX_STATIC | FRAME_SUNKEN|FRAME_THICK | LAYOUT_CENTER_X);
92 		repeatTypeComboBox->setNumVisible(2);
93 		repeatTypeComboBox->appendItem(_("Repeat X Times"));
94 		repeatTypeComboBox->appendItem(_("Repeat for X Seconds"));
95 		repeatTypeComboBox->setCurrentItem(0);
96 
97 
98 
99 	getFrame()->setVSpacing(1);
100 	getFrame()->setHSpacing(1);
101 
102 	// add clear and default buffers, and the dropdown list for choosing the mix type
103 	FXPacker *buttonPacker=new FXHorizontalFrame((/*this cast might cause a problem in the future*/FXComposite *)(getFrame()->getParent()),LAYOUT_FILL_X | FRAME_RAISED|FRAME_THICK);
104 		new FXButton(buttonPacker,_("Default"),NULL,this,ID_DEFAULT_BUTTON,BUTTON_NORMAL|LAYOUT_CENTER_Y);
105 		new FXButton(buttonPacker,_("Clear"),NULL,this,ID_CLEAR_BUTTON,BUTTON_NORMAL|LAYOUT_CENTER_Y);
106 		mixTypeFrame=new FXHorizontalFrame(buttonPacker,LAYOUT_CENTER_X|LAYOUT_CENTER_Y);
107 			new FXLabel(mixTypeFrame,_("Mix Type:"),NULL,LAYOUT_CENTER_Y);
108 			mixTypeComboBox=new FXComboBox(mixTypeFrame,16,NULL,0, COMBOBOX_NORMAL|FRAME_SUNKEN|FRAME_THICK | COMBOBOX_STATIC | LAYOUT_CENTER_Y);
109 			mixTypeComboBox->setNumVisible(4);
110 			mixTypeComboBox->appendItem(_("Add"),(void *)mmAdd);
111 			mixTypeComboBox->appendItem(_("Subtract"),(void *)mmSubtract);
112 			mixTypeComboBox->appendItem(_("Multiply"),(void *)mmMultiply);
113 			mixTypeComboBox->appendItem(_("Average"),(void *)mmAverage);
114 
115 
116 	new FXLabel(routingContents,"");
117 	sourceLabel=new FXLabel(routingContents,_("Clipboard"),NULL,LAYOUT_CENTER_X);
118 	destinationLabel=new FXLabel(routingContents,_("Destination"),NULL,LAYOUT_CENTER_Y);
119 	checkBoxMatrix=new FXMatrix(routingContents,MAX_CHANNELS+1,MATRIX_BY_COLUMNS | LAYOUT_FILL_X|LAYOUT_FILL_Y, 0,0,0,0, 0,0,0,0, 0,0);
120 
121 	// put top source labels
122 	new FXLabel(checkBoxMatrix,"");
123 	for(unsigned t=0;t<MAX_CHANNELS;t++)
124 		new FXLabel(checkBoxMatrix,(_("Channel ")+istring(t)).c_str());
125 
126 	for(unsigned t=0;t<MAX_CHANNELS;t++)
127 	{
128 		// put side destination label
129 		new FXLabel(checkBoxMatrix,(_("Channel ")+istring(t)).c_str(),NULL,LAYOUT_RIGHT);
130 
131 		// built a row of check boxes
132 		for(unsigned col=0;col<MAX_CHANNELS;col++)
133 			new FXCheckButton(checkBoxMatrix,"",NULL,0,CHECKBUTTON_NORMAL | LAYOUT_CENTER_X);
134 	}
135 
136 }
137 
~CPasteChannelsDialog()138 CPasteChannelsDialog::~CPasteChannelsDialog()
139 {
140 }
141 
show(CActionSound * _actionSound,CActionParameters * actionParameters)142 bool CPasteChannelsDialog::show(CActionSound *_actionSound,CActionParameters *actionParameters)
143 {
144 	actionSound=_actionSound; // save for use in the reset and default handler buttons
145 
146 	const ASoundClipboard *clipboard=AAction::clipboards[gWhichClipboard];
147 	if(clipboard->isEmpty())
148 		return false;
149 
150 	// only show the checkboxes that matter
151 	for(unsigned row=0;row<MAX_CHANNELS;row++)
152 	for(unsigned col=0;col<MAX_CHANNELS;col++)
153 	{
154 		FXCheckButton *cb=(FXCheckButton *)checkBoxMatrix->childAtRowCol(row+1,col+1);
155 
156 		cb->enable();
157 
158 		if(row<actionSound->sound->getChannelCount() && col<clipboard->getChannelCount())
159 			cb->show();
160 		else
161 			cb->hide();
162 
163 		// let it show, but disabled since there is no data for that channel in the clipboard
164 		if(!clipboard->getWhichChannels()[col])
165 			cb->disable();
166 	}
167 
168 	// show/hide labels across the top that matter
169 	for(unsigned col=0;col<MAX_CHANNELS;col++)
170 	{
171 		if(col<clipboard->getChannelCount())
172 			checkBoxMatrix->childAtRowCol(0,col+1)->show();
173 		else
174 			checkBoxMatrix->childAtRowCol(0,col+1)->hide();
175 	}
176 
177 	// show/hide labels on the left that matter
178 	for(unsigned row=0;row<MAX_CHANNELS;row++)
179 	{
180 		if(row<actionSound->sound->getChannelCount())
181 			checkBoxMatrix->childAtRowCol(row+1,0)->show();
182 		else
183 			checkBoxMatrix->childAtRowCol(row+1,0)->hide();
184 	}
185 
186 	// by default check a 1:1 paste mapping
187 	onDefaultButton(NULL,0,NULL);
188 
189 	// if there is only one checkbox, then make it checked and hide it and the labels
190 	if(actionSound->sound->getChannelCount()==1 && clipboard->getChannelCount()==1)
191 	{
192 		((FXCheckButton *)(checkBoxMatrix->childAtRowCol(1,1)))->setCheck(true);
193 		routingContents->hide();
194 		vertSeparator->hide();
195 	}
196 	else
197 	{
198 		routingContents->show();
199 		vertSeparator->show();
200 	}
201 
202 	// when the number of hidden and shown widgets change, the matrix needs to be told to recalc
203 	checkBoxMatrix->recalc();
204 
205 	if(execute(PLACEMENT_CURSOR))
206 	{
207 		pasteChannels.clear();
208 
209 		actionParameters->setValue<unsigned>(_("MixMethod"),(uintptr_t)(mixTypeComboBox->getItemData(mixTypeComboBox->getCurrentItem())));
210 
211 		if(repeatTypeComboBox->getCurrentItem()==0)
212 		{ // repeating it a given number of times
213 			actionParameters->setValue<double>(_("Repeat Count"),repeatCountSlider->getValue());
214 		}
215 		else
216 		{ // repeating it for a given number of seconds
217 			actionParameters->setValue<double>(_("Repeat Count"),
218 				(double)( (sample_fpos_t)repeatTimeSlider->getValue() * actionSound->sound->getSampleRate() / clipboard->getLength(actionSound->sound->getSampleRate()) )
219 			);
220 		}
221 
222 		bool ret=false; // or all the checks together, if they're all false, it's like hitting cancel
223 		for(unsigned row=0;row<MAX_CHANNELS;row++)
224 		{
225 			pasteChannels.push_back(vector<bool>());
226 			actionSound->doChannel[row]=false; // set doChannel for backend's crossfading's sake
227 			for(unsigned col=0;col<MAX_CHANNELS;col++)
228 			{
229 				FXCheckButton *cb=(FXCheckButton *)checkBoxMatrix->childAtRowCol(row+1,col+1);
230 				pasteChannels[row].push_back(cb->shown() ? cb->getCheck() : false);
231 				ret|=pasteChannels[row][col];
232 				actionSound->doChannel[row]|=pasteChannels[row][col]; // set doChannel for backend's crossfading's sake
233 			}
234 		}
235 
236 		return ret;
237 	}
238 	return false;
239 
240 }
241 
hide()242 void CPasteChannelsDialog::hide()
243 {
244 	FXModalDialogBox::hide();
245 }
246 
getUserData()247 void *CPasteChannelsDialog::getUserData()
248 {
249 	return(&pasteChannels);
250 }
251 
252 
onDefaultButton(FXObject * sender,FXSelector sel,void * ptr)253 long CPasteChannelsDialog::onDefaultButton(FXObject *sender,FXSelector sel,void *ptr)
254 {
255 	for(unsigned row=0;row<MAX_CHANNELS;row++)
256 	for(unsigned col=0;col<MAX_CHANNELS;col++)
257 	{
258 		FXCheckButton *cb=(FXCheckButton *)checkBoxMatrix->childAtRowCol(row+1,col+1);
259 		cb->setCheck(FALSE);
260 	}
261 
262 	for(unsigned t=0;t<actionSound->sound->getChannelCount();t++)
263 	{
264 		FXCheckButton *cb=(FXCheckButton *)checkBoxMatrix->childAtRowCol(t+1,t+1);
265 		if(cb->shown() && cb->isEnabled())
266 			cb->setCheck(TRUE);
267 	}
268 
269 	return 1;
270 }
271 
onClearButton(FXObject * sender,FXSelector sel,void * ptr)272 long CPasteChannelsDialog::onClearButton(FXObject *sender,FXSelector sel,void *ptr)
273 {
274 	for(unsigned row=0;row<MAX_CHANNELS;row++)
275 	for(unsigned col=0;col<MAX_CHANNELS;col++)
276 	{
277 		FXCheckButton *cb=(FXCheckButton *)checkBoxMatrix->childAtRowCol(row+1,col+1);
278 		cb->setCheck(FALSE);
279 	}
280 
281 	return 1;
282 }
283 
onRepeatTypeChange(FXObject * sender,FXSelector sel,void * ptr)284 long CPasteChannelsDialog::onRepeatTypeChange(FXObject *sender,FXSelector sel,void *ptr)
285 {
286 	repeatTypeSwitcher->setCurrent(repeatTypeComboBox->getCurrentItem());
287 	return 1;
288 }
289