You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1219 lines
33KB

  1. /* SpiralSynthModular
  2. * Copyleft (C) 2002 David Griffiths <dave@pawfal.org>
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  17. */
  18. #include <string>
  19. #include <iostream>
  20. #include <fstream>
  21. #include <sstream>
  22. #include <FL/Fl.H>
  23. #include <FL/Enumerations.H>
  24. #include <FL/fl_file_chooser.h>
  25. #include <FL/Fl_Box.h>
  26. #include <FL/Fl_Tooltip.h>
  27. #include "SpiralSynthModular.h"
  28. #include "SpiralSound/PluginManager.h"
  29. #include "SpiralSound/Plugins/SpiralPluginGUI.h"
  30. #include "GUI/SSM.xpm"
  31. #include "GUI/load.xpm"
  32. #include "GUI/save.xpm"
  33. #include "GUI/new.xpm"
  34. #include "GUI/options.xpm"
  35. #include "GUI/edit.xpm"
  36. #include "GUI/comment.xpm"
  37. #include "GUI/Widgets/PawfalYesNo.h"
  38. //#define DEBUG_PLUGINS
  39. //#define DEBUG_STREAM
  40. const static string LABEL = "SpiralSynthModular "+VER_STRING;
  41. static string TITLEBAR;
  42. static const int FILE_VERSION = 3;
  43. static int Numbers[512];
  44. static const int MAIN_WIDTH = 700;
  45. static const int MAIN_HEIGHT = 300;
  46. static const int SLIDER_WIDTH = 15;
  47. static const int TOOLBOX_HEIGHT = MAIN_HEIGHT-40;
  48. static const int TOOLBOX_WIDTH = 132+SLIDER_WIDTH;
  49. static const int ICON_DEPTH = 3;
  50. static const int COMMENT_ID = -1;
  51. using namespace std;
  52. map<int,DeviceWin*> SynthModular::m_DeviceWinMap;
  53. bool SynthModular::m_CallbackUpdateMode = false;
  54. bool SynthModular::m_BlockingOutputPluginIsReady = false;
  55. //////////////////////////////////////////////////////////
  56. DeviceWin::~DeviceWin()
  57. {
  58. }
  59. //////////////////////////////////////////////////////////
  60. SynthModular::SynthModular():
  61. m_NextID(0),
  62. m_NextPluginButton(1),
  63. m_NextPluginButtonXPos(5),
  64. m_NextPluginButtonYPos(20),
  65. m_PauseAudio(false)
  66. {
  67. m_Info.BUFSIZE = SpiralInfo::BUFSIZE;
  68. m_Info.FRAGSIZE = SpiralInfo::FRAGSIZE;
  69. m_Info.FRAGCOUNT = SpiralInfo::FRAGCOUNT;
  70. m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE;
  71. m_Info.OUTPUTFILE = SpiralInfo::OUTPUTFILE;
  72. m_Info.MIDIFILE = SpiralInfo::MIDIFILE;
  73. m_Info.POLY = SpiralInfo::POLY;
  74. //m_Info.GUI_COLOUR = SpiralInfo::GUI_COLOUR;
  75. for (int n=0; n<512; n++) Numbers[n]=n;
  76. m_CH.Register("PauseAudio",&m_PauseAudio);
  77. }
  78. //////////////////////////////////////////////////////////
  79. SynthModular::~SynthModular()
  80. {
  81. ClearUp();
  82. PluginManager::Get()->PackUpAndGoHome();
  83. }
  84. //////////////////////////////////////////////////////////
  85. void SynthModular::ClearUp()
  86. {
  87. PauseAudio();
  88. for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  89. i!=m_DeviceWinMap.end(); i++)
  90. {
  91. if (i->second->m_DeviceGUI->GetPluginWindow())
  92. {
  93. i->second->m_DeviceGUI->GetPluginWindow()->hide();
  94. m_MainWindow->remove(i->second->m_DeviceGUI->GetPluginWindow());
  95. }
  96. // deleted by Canvas::Remove()? seems to cause random crashes
  97. //delete i->second->m_DeviceGUI;
  98. delete i->second->m_Device;
  99. i->second->m_Device=NULL;
  100. }
  101. m_Canvas->Clear();
  102. m_DeviceWinMap.clear();
  103. m_NextID=0;
  104. ResumeAudio();
  105. }
  106. //////////////////////////////////////////////////////////
  107. void SynthModular::Update()
  108. {
  109. m_CH.UpdateDataNow();
  110. if (m_PauseAudio) return;
  111. // for all the plugins
  112. for(map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  113. i!=m_DeviceWinMap.end(); i++)
  114. {
  115. if (i->second->m_Device) // if it's not a comment
  116. {
  117. #ifdef DEBUG_PLUGINS
  118. cerr<<"Updating channelhandler of plugin "<<i->second->m_PluginID<<endl;
  119. #endif
  120. // updates the data from the gui thread, if it's not blocking
  121. i->second->m_Device->UpdateChannelHandler();
  122. #ifdef DEBUG_PLUGINS
  123. cerr<<"Finished updating"<<endl;
  124. #endif
  125. // run any commands we've received from the GUI's
  126. i->second->m_Device->ExecuteCommands();
  127. }
  128. }
  129. // run the plugins (only ones connected to anything)
  130. list<int> ExecutionOrder = m_Canvas->GetGraph()->GetSortedList();
  131. for (list<int>::reverse_iterator i=ExecutionOrder.rbegin();
  132. i!=ExecutionOrder.rend(); i++)
  133. {
  134. // use the graphsort order to remove internal latency
  135. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(*i);
  136. if (di!=m_DeviceWinMap.end() && di->second->m_Device)
  137. {
  138. #ifdef DEBUG_PLUGINS
  139. cerr<<"Executing plugin "<<di->second->m_PluginID<<endl;
  140. #endif
  141. di->second->m_Device->Execute();
  142. #ifdef DEBUG_PLUGINS
  143. cerr<<"Finished executing"<<endl;
  144. #endif
  145. }
  146. }
  147. }
  148. //////////////////////////////////////////////////////////
  149. void SynthModular::UpdatePluginGUIs()
  150. {
  151. // see if any need deleting
  152. for (map<int,DeviceWin*>::iterator i=m_DeviceWinMap.begin();
  153. i!=m_DeviceWinMap.end(); i++)
  154. {
  155. if (i->second->m_DeviceGUI->GetPluginWindow())
  156. {
  157. SpiralPluginGUI *GUI=(SpiralPluginGUI *)i->second->m_DeviceGUI->GetPluginWindow();
  158. GUI->Update();
  159. }
  160. if (i->second->m_DeviceGUI->Killed())
  161. {
  162. PauseAudio();
  163. if (i->second->m_Device)
  164. {
  165. delete i->second->m_Device;
  166. i->second->m_Device=NULL;
  167. }
  168. if (i->second->m_DeviceGUI->GetPluginWindow())
  169. {
  170. i->second->m_DeviceGUI->GetPluginWindow()->hide();
  171. m_MainWindow->remove(i->second->m_DeviceGUI->GetPluginWindow());
  172. }
  173. i->second->m_DeviceGUI->Clear();
  174. m_Canvas->RemoveDevice(i->second->m_DeviceGUI);
  175. // deleted by Canvas::Remove()? seems to cause random crashes
  176. //delete i->second->m_DeviceGUI;
  177. m_DeviceWinMap.erase(i);
  178. ResumeAudio();
  179. break;
  180. }
  181. }
  182. m_Canvas->Poll();
  183. }
  184. //////////////////////////////////////////////////////////
  185. SpiralWindowType *SynthModular::CreateWindow()
  186. {
  187. int xoff=0, yoff=10, but=64, gap=MAIN_HEIGHT/4, n=0;
  188. m_TopWindow = new SpiralWindowType(MAIN_WIDTH, MAIN_HEIGHT*2, LABEL.c_str());
  189. m_TopWindow->resizable(m_TopWindow);
  190. m_TopTile = new Fl_Tile(0,0,MAIN_WIDTH, MAIN_HEIGHT*2, "");
  191. m_TopWindow->add(m_TopTile);
  192. m_MainWindow = new Fl_Tile(0,0,MAIN_WIDTH, MAIN_HEIGHT, "");
  193. m_MainWindow->color(SpiralSynthModularInfo::GUICOL_Canvas);
  194. //m_MainWindow->callback((Fl_Callback*)cb_Close);
  195. m_MainWindow->user_data((void*)(this));
  196. m_TopTile->add(m_MainWindow);
  197. m_MainButtons = new Fl_Group(0, 0, but, MAIN_HEIGHT, "");
  198. m_MainButtons->type(1);
  199. m_MainButtons->color(SpiralSynthModularInfo::GUICOL_Tool);
  200. m_MainButtons->box(FL_FLAT_BOX);
  201. m_MainButtons->user_data((void*)(this));
  202. m_MainWindow->add(m_MainButtons);
  203. m_AppScroll = new Fl_Scroll(but, 0, MAIN_WIDTH-but, MAIN_HEIGHT, "");
  204. m_AppScroll->scrollbar.align(FL_ALIGN_RIGHT);
  205. m_MainWindow->add(m_AppScroll);
  206. //m_MainWindow->resizable(m_AppScroll);
  207. m_AppGroup = new Fl_Group(-5000, -5000, 10000, 10000, "");
  208. m_AppGroup->type(1);
  209. m_AppGroup->box(FL_FLAT_BOX);
  210. m_AppGroup->labeltype(FL_ENGRAVED_LABEL);
  211. m_AppGroup->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  212. m_AppGroup->color(SpiralSynthModularInfo::GUICOL_Canvas);
  213. m_AppScroll->add(m_AppGroup);
  214. m_Load = new Fl_Button(xoff, 5+yoff, but, but, "");
  215. m_Load->box(FL_NO_BOX);
  216. Fl_Pixmap *tPix = new Fl_Pixmap(load_xpm);
  217. m_Load->image(tPix->copy(tPix->w(),tPix->h()));
  218. m_Load->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  219. m_Load->tooltip("Load a patch file");
  220. m_Load->callback((Fl_Callback*)cb_Load);
  221. m_MainButtons->add(m_Load);
  222. n++;
  223. m_Save = new Fl_Button(xoff, n*gap+yoff, but, but, "");
  224. m_Save->box(FL_NO_BOX);
  225. tPix = new Fl_Pixmap(save_xpm);
  226. m_Save->image(tPix->copy(tPix->w(),tPix->h()));
  227. delete tPix;
  228. m_Save->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  229. m_Save->tooltip("Save a patch file");
  230. m_Save->callback((Fl_Callback*)cb_Save);
  231. m_MainButtons->add(m_Save);
  232. n++;
  233. m_New = new Fl_Button(xoff, n*gap+yoff, but, but, "");
  234. m_New->box(FL_NO_BOX);
  235. tPix = new Fl_Pixmap(new_xpm);
  236. m_New->image(tPix->copy(tPix->w(),tPix->h()));
  237. delete tPix;
  238. m_New->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  239. m_New->tooltip("New patch");
  240. m_New->callback((Fl_Callback*)cb_New);
  241. m_MainButtons->add(m_New);
  242. n++;
  243. m_Options = new Fl_Button(xoff, n*gap+yoff, but, but, "");
  244. m_Options->box(FL_NO_BOX);
  245. tPix = new Fl_Pixmap(options_xpm);
  246. m_Options->image(tPix->copy(tPix->w(),tPix->h()));
  247. delete tPix;
  248. m_Options->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  249. m_Options->tooltip("Options");
  250. m_Options->callback((Fl_Callback*)cb_Rload);
  251. m_MainButtons->add(m_Options);
  252. n++;
  253. /////////////////
  254. m_EditorWindow = new Fl_Tile(0,MAIN_HEIGHT,MAIN_WIDTH, MAIN_HEIGHT, "");
  255. m_EditorWindow->color(SpiralSynthModularInfo::GUICOL_Tool);
  256. m_TopTile->add(m_EditorWindow);
  257. int edy = MAIN_HEIGHT;
  258. Fl_Group *Left = new Fl_Group(0,MAIN_HEIGHT,TOOLBOX_WIDTH,MAIN_HEIGHT);
  259. Left->box(FL_FLAT_BOX);
  260. Left->color(SpiralSynthModularInfo::GUICOL_Tool);
  261. Left->user_data((void*)(this));
  262. m_EditorWindow->add(Left);
  263. m_EditorWindow->resizable(Left);
  264. m_GroupName = new Fl_Box(0,MAIN_HEIGHT,TOOLBOX_WIDTH,16,"");
  265. m_GroupName->labelsize(12);
  266. m_GroupName->color(SpiralSynthModularInfo::GUICOL_Canvas);
  267. m_GroupName->align(FL_ALIGN_CENTER|FL_ALIGN_INSIDE);
  268. m_GroupName->box(FL_BORDER_BOX);
  269. Left->add(m_GroupName);
  270. m_PluginGroupLeft = new Fl_Button(0, MAIN_HEIGHT, 16, 16, "@<");
  271. m_PluginGroupLeft->callback((Fl_Callback*)cb_PluginGroupLeft);
  272. Left->add(m_PluginGroupLeft);
  273. m_PluginGroupRight = new Fl_Button(TOOLBOX_WIDTH-16, MAIN_HEIGHT, 16, 16, "@>");
  274. m_PluginGroupRight->callback((Fl_Callback*)cb_PluginGroupRight);
  275. Left->add(m_PluginGroupRight);
  276. m_ToolBox = new Fl_Scroll(0,0+edy+16,TOOLBOX_WIDTH, TOOLBOX_HEIGHT-16, "");
  277. m_ToolBox->type(Fl_Scroll::VERTICAL_ALWAYS);
  278. m_ToolBox->box(FL_FLAT_BOX);
  279. m_ToolBox->labeltype(FL_ENGRAVED_LABEL);
  280. m_ToolBox->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  281. m_ToolBox->scrollbar.align(FL_ALIGN_LEFT);
  282. m_ToolBox->color(SpiralSynthModularInfo::GUICOL_Tool);
  283. m_ToolBox->user_data((void*)(this));
  284. Left->add(m_ToolBox);
  285. xoff=0; yoff=MAIN_HEIGHT+TOOLBOX_HEIGHT;
  286. m_Buttons = new Fl_Group(xoff, yoff, TOOLBOX_WIDTH, MAIN_HEIGHT*2-TOOLBOX_HEIGHT, "");
  287. m_Buttons->type(1);
  288. m_Buttons->color(SpiralSynthModularInfo::GUICOL_Tool);
  289. m_Buttons->box(FL_FLAT_BOX);
  290. m_Buttons->user_data((void*)(this));
  291. Left->add(m_Buttons);
  292. m_CanvasScroll = new Fl_Scroll(TOOLBOX_WIDTH, 0+edy, MAIN_WIDTH-TOOLBOX_WIDTH, MAIN_HEIGHT, "");
  293. m_EditorWindow->add(m_CanvasScroll);
  294. m_EditorWindow->resizable(m_CanvasScroll);
  295. m_Canvas = new Fl_Canvas(-5000, -5000, 10000, 10000, "");
  296. m_Canvas->type(1);
  297. m_Canvas->box(FL_FLAT_BOX);
  298. m_Canvas->labeltype(FL_ENGRAVED_LABEL);
  299. m_Canvas->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  300. m_Canvas->color(SpiralSynthModularInfo::GUICOL_Canvas);
  301. m_Canvas->user_data((void*)(this));
  302. m_Canvas->SetConnectionCallback((Fl_Callback*)cb_Connection);
  303. m_Canvas->SetUnconnectCallback((Fl_Callback*)cb_Unconnect);
  304. m_Canvas->SetAddDeviceCallback((Fl_Callback*)cb_NewDeviceFromMenu);
  305. m_CanvasScroll->add(m_Canvas);
  306. m_NewComment = new Fl_Button(TOOLBOX_WIDTH/2-16, MAIN_HEIGHT*2-25, 40, 40, "");
  307. m_NewComment->box(FL_NO_BOX);
  308. m_Canvas->align(FL_ALIGN_TOP_LEFT|FL_ALIGN_INSIDE);
  309. tPix = new Fl_Pixmap(comment_xpm);
  310. m_NewComment->image(tPix->copy(tPix->w(),tPix->h()));
  311. delete tPix;
  312. m_NewComment->color(SpiralSynthModularInfo::GUICOL_Button);
  313. m_NewComment->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  314. m_NewComment->type(0);
  315. m_NewComment->shortcut(FL_F + 10);
  316. m_NewComment->tooltip("New comment in editor");
  317. m_NewComment->user_data((void*)(this));
  318. m_NewComment->callback((Fl_Callback*)cb_NewComment);
  319. m_Buttons->add(m_NewComment);
  320. m_SettingsWindow = new SettingsWindow;
  321. m_SettingsWindow->RegisterApp(this);
  322. return m_TopWindow;
  323. }
  324. //////////////////////////////////////////////////////////
  325. SynthModular::ToolBox::ToolBox(Fl_Scroll *parent, void* user)
  326. {
  327. int Width = 40;
  328. int Height = 40;
  329. m_Icon=0;
  330. m_ToolPack = new Fl_Pack(SLIDER_WIDTH+5,25+MAIN_HEIGHT,TOOLBOX_WIDTH-10, TOOLBOX_HEIGHT-60,"");
  331. m_ToolPack->type(FL_VERTICAL);
  332. m_ToolPack->box(FL_NO_BOX);
  333. m_ToolPack->color(SpiralSynthModularInfo::GUICOL_Tool);
  334. m_ToolPack->user_data(user);
  335. parent->add(m_ToolPack);
  336. m_IconPack = new Fl_Pack(0,0,TOOLBOX_WIDTH-SLIDER_WIDTH,Height,"");
  337. m_IconPack->type(FL_HORIZONTAL);
  338. m_IconPack->color(SpiralSynthModularInfo::GUICOL_Tool);
  339. m_IconPack->user_data(m_ToolPack->user_data());
  340. m_ToolPack->add(m_IconPack);
  341. }
  342. void SynthModular::ToolBox::AddIcon(Fl_Button *Icon)
  343. {
  344. int Width = 40;
  345. int Height = 40;
  346. if (m_Icon>=ICON_DEPTH)
  347. {
  348. m_Icon=0;
  349. m_IconPack = new Fl_Pack(0,0,TOOLBOX_WIDTH-SLIDER_WIDTH,Height,"");
  350. m_IconPack->type(FL_HORIZONTAL);
  351. m_IconPack->color(SpiralSynthModularInfo::GUICOL_Tool);
  352. m_IconPack->user_data(m_ToolPack->user_data());
  353. m_ToolPack->add(m_IconPack);
  354. }
  355. m_IconPack->add(Icon);
  356. m_Icon++;
  357. }
  358. void SynthModular::LoadPlugins(string pluginPath)
  359. {
  360. int Width = 40;
  361. int Height = 40;
  362. int SWidth = 256;
  363. int SHeight = 256;
  364. Fl_Pixmap pic(SSM_xpm);
  365. Fl_Double_Window* Splash = new Fl_Double_Window((Fl::w()/2)-(SWidth/2),
  366. (Fl::h()/2)-(SHeight/2),
  367. SWidth,SHeight,"SSM");
  368. Splash->border(0);
  369. Fl_Box* pbut = new Fl_Box(0,8,SWidth,SHeight,"");
  370. pbut->box(FL_NO_BOX);
  371. pic.label(pbut);
  372. Fl_Box *splashtext = new Fl_Box(5,SHeight-20,200,20,"Loading...");
  373. splashtext->labelsize(10);
  374. splashtext->box(FL_NO_BOX);
  375. splashtext->align(FL_ALIGN_INSIDE|FL_ALIGN_LEFT);
  376. Splash->add(pbut);
  377. Splash->add(splashtext);
  378. Splash->show();
  379. int ID=-1;
  380. for (vector<string>::iterator i=SpiralSynthModularInfo::PLUGINVEC.begin();
  381. i!=SpiralSynthModularInfo::PLUGINVEC.end(); i++)
  382. {
  383. string Fullpath;
  384. if (pluginPath=="")
  385. {
  386. Fullpath=SpiralSynthModularInfo::PLUGIN_PATH+*i;
  387. }
  388. else
  389. {
  390. Fullpath=pluginPath+*"/"+*i;
  391. }
  392. ID=PluginManager::Get()->LoadPlugin(Fullpath.c_str());
  393. if (ID!=PluginError)
  394. {
  395. #ifdef DEBUG_PLUGINS
  396. cerr<<"Plugin ["<<*i<<"] = "<<ID<<endl;
  397. #endif
  398. Fl_Button *NewButton = new Fl_Button(0,0,Width,Height,"");
  399. NewButton->labelsize(10);
  400. Fl_Pixmap *tPix = new Fl_Pixmap(PluginManager::Get()->GetPlugin(ID)->GetIcon());
  401. NewButton->image(tPix->copy(tPix->w(),tPix->h()));
  402. delete tPix;
  403. string GroupName = PluginManager::Get()->GetPlugin(ID)->GetGroupName();
  404. ToolBox* Tool=NULL;
  405. map<string,ToolBox*>::iterator ti=m_PluginGroupMap.find(GroupName);
  406. if (ti==m_PluginGroupMap.end())
  407. {
  408. if (Tool) Tool->GetToolPack()->hide();
  409. Tool = new ToolBox(m_ToolBox,(void*)(this));
  410. m_PluginGroupMap[GroupName]=Tool;
  411. Tool->GetToolPack()->hide();
  412. }
  413. else
  414. {
  415. Tool=ti->second;
  416. }
  417. Tool->AddIcon(NewButton);
  418. NewButton->type(0);
  419. NewButton->box(FL_PLASTIC_UP_BOX);
  420. NewButton->align(FL_ALIGN_INSIDE|FL_ALIGN_TOP);
  421. NewButton->color(SpiralSynthModularInfo::GUICOL_Button);
  422. NewButton->selection_color(SpiralSynthModularInfo::GUICOL_Tool);
  423. string tooltip=*i;
  424. // find the first / if there is one, and get rid of everything before and including it
  425. unsigned int p = tooltip.find ('/');
  426. if (p < tooltip.length()) tooltip.erase (0, p);
  427. // find last . and get rid of everything after and including it
  428. p = tooltip.rfind ('.');
  429. unsigned int l = tooltip.length ();
  430. if (p < l) tooltip.erase (p, l);
  431. m_Canvas->AddPluginName (tooltip, PluginManager::Get()->GetPlugin(ID)->ID);
  432. splashtext->label (tooltip.c_str());
  433. Splash->redraw();
  434. NewButton->tooltip (tooltip.c_str());
  435. NewButton->callback((Fl_Callback*)cb_NewDevice,&Numbers[ID]);
  436. NewButton->show();
  437. m_DeviceVec.push_back(NewButton);
  438. m_ToolBox->redraw();
  439. m_NextPluginButton++;
  440. Fl::check();
  441. }
  442. }
  443. // try to show the SpiralSound group
  444. m_CurrentGroup=m_PluginGroupMap.find("SpiralSound");
  445. if (m_CurrentGroup==m_PluginGroupMap.end())
  446. {
  447. // can't find it - show the first plugin group
  448. m_CurrentGroup=m_PluginGroupMap.begin();
  449. m_CurrentGroup->second->GetToolPack()->show();
  450. m_GroupName->label(m_CurrentGroup->first.c_str());
  451. }
  452. m_CurrentGroup->second->GetToolPack()->show();
  453. m_GroupName->label(m_CurrentGroup->first.c_str());
  454. Splash->hide();
  455. delete Splash;
  456. }
  457. //////////////////////////////////////////////////////////
  458. DeviceGUIInfo SynthModular::BuildDeviceGUIInfo(PluginInfo &PInfo)
  459. {
  460. DeviceGUIInfo Info;
  461. int Height=50;
  462. // tweak the size if we have too many ins/outs
  463. if (PInfo.NumInputs>4 || PInfo.NumOutputs>4)
  464. {
  465. if (PInfo.NumInputs<PInfo.NumOutputs)
  466. {
  467. Height=PInfo.NumOutputs*10+5;
  468. }
  469. else
  470. {
  471. Height=PInfo.NumInputs*10+5;
  472. }
  473. }
  474. // Make the guiinfo struct
  475. Info.XPos = 0;
  476. Info.YPos = 0;
  477. Info.Width = 40;
  478. Info.Height = Height;
  479. Info.NumInputs = PInfo.NumInputs;
  480. Info.NumOutputs = PInfo.NumOutputs;
  481. Info.Name = PInfo.Name;
  482. Info.PortTips = PInfo.PortTips;
  483. Info.PortTypes = PInfo.PortTypes;
  484. return Info;
  485. }
  486. //////////////////////////////////////////////////////////
  487. DeviceWin* SynthModular::NewDeviceWin(int n, int x, int y)
  488. {
  489. DeviceWin *nlw = new DeviceWin;
  490. const HostsideInfo* Plugin=PluginManager::Get()->GetPlugin(n);
  491. if (!Plugin) return NULL;
  492. nlw->m_Device=Plugin->CreateInstance();
  493. if (!nlw->m_Device)
  494. {
  495. return NULL;
  496. }
  497. nlw->m_Device->SetBlockingCallback(cb_Blocking);
  498. nlw->m_Device->SetUpdateCallback(cb_Update);
  499. nlw->m_Device->SetParent((void*)this);
  500. PluginInfo PInfo = nlw->m_Device->Initialise(&m_Info);
  501. SpiralGUIType *temp = nlw->m_Device->CreateGUI();
  502. Fl_Pixmap *Pix = new Fl_Pixmap(Plugin->GetIcon());
  503. nlw->m_PluginID = n;
  504. if (temp)
  505. {
  506. temp->hide();
  507. temp->position(200,50);
  508. m_AppGroup->add(temp);
  509. m_MainWindow->redraw();
  510. }
  511. DeviceGUIInfo Info=BuildDeviceGUIInfo(PInfo);
  512. Info.XPos = x; //TOOLBOX_WIDTH+(rand()%400);
  513. Info.YPos = y; //rand()%400;
  514. nlw->m_DeviceGUI = new Fl_DeviceGUI(Info, temp, Pix, nlw->m_Device->IsTerminal());
  515. m_Canvas->add(nlw->m_DeviceGUI);
  516. m_Canvas->redraw();
  517. return nlw;
  518. }
  519. //////////////////////////////////////////////////////////
  520. void SynthModular::AddDevice(int n, int x=-1, int y=-1)
  521. {
  522. //cerr<<"Adding "<<m_NextID<<endl;
  523. if (x==-1)
  524. {
  525. x = m_CanvasScroll->x()+50;
  526. y = m_CanvasScroll->y()+50;
  527. }
  528. DeviceWin* temp = NewDeviceWin(n,x,y);
  529. if (temp)
  530. {
  531. int ID=m_NextID++;
  532. //cerr<<"adding device "<<ID<<endl;
  533. temp->m_DeviceGUI->SetID(ID);
  534. temp->m_Device->SetUpdateInfoCallback(ID,cb_UpdatePluginInfo);
  535. m_DeviceWinMap[ID]=temp;
  536. }
  537. }
  538. //////////////////////////////////////////////////////////
  539. DeviceWin* SynthModular::NewComment(int n, int x=-1, int y=-1)
  540. {
  541. DeviceWin *nlw = new DeviceWin;
  542. if (x==-1)
  543. {
  544. x = m_CanvasScroll->x()+50;
  545. y = m_CanvasScroll->y()+50;
  546. }
  547. nlw->m_Device=NULL;
  548. nlw->m_PluginID = COMMENT_ID;
  549. DeviceGUIInfo Info;
  550. Info.XPos = x;
  551. Info.YPos = y;
  552. Info.Width = 50;
  553. Info.Height = 20;
  554. Info.NumInputs = 0;
  555. Info.NumOutputs = 0;
  556. Info.Name = "";
  557. nlw->m_DeviceGUI = new Fl_CommentGUI(Info, NULL, NULL);
  558. m_Canvas->add(nlw->m_DeviceGUI);
  559. m_Canvas->redraw();
  560. return nlw;
  561. }
  562. //////////////////////////////////////////////////////////
  563. void SynthModular::AddComment(int n)
  564. {
  565. //cerr<<"Adding "<<m_NextID<<endl;
  566. DeviceWin* temp = NewComment(n);
  567. if (temp)
  568. {
  569. int ID=m_NextID++;
  570. //cerr<<"adding comment "<<ID<<endl;
  571. temp->m_DeviceGUI->SetID(ID);
  572. m_DeviceWinMap[ID]=temp;
  573. }
  574. }
  575. //////////////////////////////////////////////////////////
  576. void SynthModular::UpdateHostInfo()
  577. {
  578. // used to use string streams, but this seems to cause a compiler bug
  579. // at the moment, so fall back to using a temporary file
  580. //std::stringstream str;
  581. fstream ofs("___temp.ssmtmp",ios::out);
  582. //str<<*this;
  583. ofs<<*this;
  584. ClearUp();
  585. // update the settings
  586. m_Info.BUFSIZE = SpiralInfo::BUFSIZE;
  587. m_Info.FRAGSIZE = SpiralInfo::FRAGSIZE;
  588. m_Info.FRAGCOUNT = SpiralInfo::FRAGCOUNT;
  589. m_Info.SAMPLERATE = SpiralInfo::SAMPLERATE;
  590. m_Info.OUTPUTFILE = SpiralInfo::OUTPUTFILE;
  591. m_Info.MIDIFILE = SpiralInfo::MIDIFILE;
  592. m_Info.POLY = SpiralInfo::POLY;
  593. fstream ifs("___temp.ssmtmp",ios::in);
  594. //str>>*this;
  595. ifs>>*this;
  596. system("rm -f ___temp.ssmtmp");
  597. }
  598. //////////////////////////////////////////////////////////
  599. // called when a callback output plugin wants to run the audio thread
  600. void SynthModular::cb_Update(void* o, bool mode)
  601. {
  602. m_CallbackUpdateMode=mode;
  603. ((SynthModular*)o)->Update();
  604. }
  605. // called by a blocking output plugin to notify the engine its ready to
  606. // take control of the update timing (so take the brakes off)
  607. void SynthModular::cb_Blocking(void* o, bool mode)
  608. {
  609. m_BlockingOutputPluginIsReady=mode;
  610. }
  611. //////////////////////////////////////////////////////////
  612. istream &operator>>(istream &s, SynthModular &o)
  613. {
  614. o.PauseAudio();
  615. string dummy,dummy2;
  616. int ver;
  617. s>>dummy>>dummy>>dummy>>ver;
  618. if (ver>FILE_VERSION)
  619. {
  620. SpiralInfo::Alert("Bad file, or more recent version.");
  621. return s;
  622. }
  623. if (ver>2)
  624. {
  625. int MainWinX,MainWinY,MainWinW,MainWinH;
  626. int EditWinX,EditWinY,EditWinW,EditWinH;
  627. s>>MainWinX>>MainWinY>>MainWinW>>MainWinH;
  628. s>>EditWinX>>EditWinY>>EditWinW>>EditWinH;
  629. //o.m_MainWindow->resize(MainWinX,MainWinY,MainWinW,MainWinH);
  630. //o.m_EditorWindow->resize(EditWinX,EditWinY,EditWinW,EditWinH);
  631. }
  632. int Num, ID, PluginID, x,y,ps,px,py;
  633. s>>dummy>>Num;
  634. for(int n=0; n<Num; n++)
  635. {
  636. #ifdef DEBUG_STREAM
  637. cerr<<"Loading Device "<<n<<endl;
  638. #endif
  639. s>>dummy;
  640. s>>ID;
  641. s>>dummy2;
  642. s>>PluginID;
  643. s>>x>>y;
  644. #ifdef DEBUG_STREAM
  645. cerr<<dummy<<" "<<ID<<" "<<dummy2<<" "<<PluginID<<" "<<x<<" "<<y<<endl;
  646. #endif
  647. if (ver>1) s>>ps>>px>>py;
  648. // Check we're not duplicating an ID
  649. if (o.m_DeviceWinMap.find(ID)!=o.m_DeviceWinMap.end())
  650. {
  651. SpiralInfo::Alert("Duplicate device ID found in file - aborting load");
  652. return s;
  653. }
  654. if (PluginID==COMMENT_ID)
  655. {
  656. DeviceWin* temp = o.NewComment(PluginID, x, y);
  657. if (temp)
  658. {
  659. temp->m_DeviceGUI->SetID(ID);
  660. o.m_DeviceWinMap[ID]=temp;
  661. ((Fl_CommentGUI*)(o.m_DeviceWinMap[ID]->m_DeviceGUI))->StreamIn(s); // load the plugin
  662. if (o.m_NextID<=ID) o.m_NextID=ID+1;
  663. }
  664. }
  665. else
  666. {
  667. DeviceWin* temp = o.NewDeviceWin(PluginID, x, y);
  668. if (temp)
  669. {
  670. temp->m_DeviceGUI->SetID(ID);
  671. temp->m_Device->SetUpdateInfoCallback(ID,o.cb_UpdatePluginInfo);
  672. o.m_DeviceWinMap[ID]=temp;
  673. o.m_DeviceWinMap[ID]->m_Device->StreamIn(s); // load the plugin
  674. if (ver>1 && o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow())
  675. {
  676. // set the GUI up with the loaded values
  677. // looks messy, but if we do it here, the plugin and it's gui can remain
  678. // totally seperated.
  679. ((SpiralPluginGUI*)(o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()))->
  680. UpdateValues(o.m_DeviceWinMap[ID]->m_Device);
  681. // updates the data in the channel buffers, so the values don't
  682. // get overwritten in the next tick. (should maybe be somewhere else)
  683. o.m_DeviceWinMap[ID]->m_Device->GetChannelHandler()->FlushChannels();
  684. // position the plugin window in the main window
  685. o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->position(px,py);
  686. if (ps) o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->show();
  687. else o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->hide();
  688. // load external files
  689. o.m_DeviceWinMap[ID]->m_Device->LoadExternalFiles(o.m_FilePath+"_files/");
  690. }
  691. if (o.m_NextID<=ID) o.m_NextID=ID+1;
  692. }
  693. else
  694. {
  695. // can't really recover if the plugin ID doesn't match a plugin, as
  696. // we have no idea how much data in the stream belongs to this plugin
  697. SpiralInfo::Alert("Error in stream, can't really recover data from here on.");
  698. return s;
  699. }
  700. }
  701. }
  702. s>>*o.m_Canvas;
  703. o.ResumeAudio();
  704. return s;
  705. }
  706. //////////////////////////////////////////////////////////
  707. ostream &operator<<(ostream &s, SynthModular &o)
  708. {
  709. o.PauseAudio();
  710. s<<"SpiralSynthModular File Ver "<<FILE_VERSION<<endl;
  711. // make external files dir
  712. bool ExternalDirUsed=false;
  713. string command("mkdir "+o.m_FilePath+"_files");
  714. system(command.c_str());
  715. if (FILE_VERSION>2)
  716. {
  717. s<<o.m_MainWindow->x()<<" "<<o.m_MainWindow->y()<<" ";
  718. s<<o.m_MainWindow->w()<<" "<<o.m_MainWindow->h()<<" ";
  719. s<<o.m_EditorWindow->x()<<" "<<o.m_EditorWindow->y()<<" ";
  720. s<<o.m_EditorWindow->w()<<" "<<o.m_EditorWindow->h()<<endl;
  721. }
  722. // save out the SynthModular
  723. s<<"SectionList"<<endl;
  724. s<<o.m_DeviceWinMap.size()<<endl;
  725. for(map<int,DeviceWin*>::iterator i=o.m_DeviceWinMap.begin();
  726. i!=o.m_DeviceWinMap.end(); i++)
  727. {
  728. s<<endl;
  729. s<<"Device ";
  730. s<<i->first<<" "; // save the id
  731. s<<"Plugin ";
  732. s<<i->second->m_PluginID<<endl;
  733. s<<i->second->m_DeviceGUI->x()<<" ";
  734. s<<i->second->m_DeviceGUI->y()<<" ";
  735. if (i->second->m_DeviceGUI->GetPluginWindow())
  736. {
  737. s<<i->second->m_DeviceGUI->GetPluginWindow()->visible()<<" ";
  738. s<<i->second->m_DeviceGUI->GetPluginWindow()->x()<<" ";
  739. s<<i->second->m_DeviceGUI->GetPluginWindow()->y()<<" ";
  740. }
  741. else
  742. {
  743. s<<0<<" "<<0<<" "<<0;
  744. }
  745. s<<endl;
  746. if (i->second->m_PluginID==COMMENT_ID)
  747. {
  748. // save the comment gui
  749. ((Fl_CommentGUI*)(i->second->m_DeviceGUI))->StreamOut(s);
  750. }
  751. else
  752. {
  753. // save the plugin
  754. i->second->m_Device->StreamOut(s);
  755. }
  756. s<<endl;
  757. // save external files
  758. if (i->second->m_Device && i->second->m_Device->SaveExternalFiles(o.m_FilePath+"_files/"))
  759. {
  760. ExternalDirUsed=true;
  761. }
  762. }
  763. s<<endl<<*o.m_Canvas<<endl;
  764. // remove it if it wasn't used
  765. if (!ExternalDirUsed)
  766. {
  767. // i guess rmdir won't work if there is something in the dir
  768. // anyway, but best to be on the safe side. (could do rm -rf) :)
  769. string command("rmdir "+o.m_FilePath+"_files");
  770. system(command.c_str());
  771. }
  772. o.ResumeAudio();
  773. return s;
  774. }
  775. //////////////////////////////////////////////////////////
  776. inline void SynthModular::cb_Close_i(Fl_Window* o, void* v)
  777. {
  778. m_SettingsWindow->hide();
  779. delete m_SettingsWindow;
  780. m_EditorWindow->hide();
  781. delete m_EditorWindow;
  782. o->hide();
  783. }
  784. void SynthModular::cb_Close(Fl_Window* o, void* v)
  785. {((SynthModular*)(o->user_data()))->cb_Close_i(o,v);}
  786. //////////////////////////////////////////////////////////
  787. inline void SynthModular::cb_Load_i(Fl_Button* o, void* v)
  788. {
  789. if (m_DeviceWinMap.size()>0 && !Pawfal_YesNo("Load - Lose changes to current patch?"))
  790. {
  791. return;
  792. }
  793. char *fn=fl_file_chooser("Load a patch", "*.ssm", NULL);
  794. if (fn && fn!='\0')
  795. {
  796. ifstream inf(fn);
  797. if (inf)
  798. {
  799. m_FilePath=fn;
  800. ClearUp();
  801. inf>>*this;
  802. TITLEBAR=LABEL+" "+fn;
  803. m_TopWindow->label(TITLEBAR.c_str());
  804. }
  805. }
  806. }
  807. void SynthModular::cb_Load(Fl_Button* o, void* v)
  808. {((SynthModular*)(o->parent()->user_data()))->cb_Load_i(o,v);}
  809. //////////////////////////////////////////////////////////
  810. inline void SynthModular::cb_Save_i(Fl_Button* o, void* v)
  811. {
  812. char *fn=fl_file_chooser("Save a patch", "*.ssm", NULL);
  813. if (fn && fn!='\0')
  814. {
  815. ifstream ifl(fn);
  816. if (ifl)
  817. {
  818. if (!Pawfal_YesNo("File [%s] exists, overwrite?",fn))
  819. {
  820. return;
  821. }
  822. }
  823. ofstream of(fn);
  824. if (of)
  825. {
  826. m_FilePath=fn;
  827. of<<*this;
  828. TITLEBAR=LABEL+" "+fn;
  829. m_TopWindow->label(TITLEBAR.c_str());
  830. }
  831. }
  832. }
  833. void SynthModular::cb_Save(Fl_Button* o, void* v)
  834. {((SynthModular*)(o->parent()->user_data()))->cb_Save_i(o,v);}
  835. //////////////////////////////////////////////////////////
  836. inline void SynthModular::cb_New_i(Fl_Button* o, void* v)
  837. {
  838. if (m_DeviceWinMap.size()>0 && !Pawfal_YesNo("New - Lose changes to current patch?"))
  839. {
  840. return;
  841. }
  842. m_TopWindow->label(TITLEBAR.c_str());
  843. ClearUp();
  844. }
  845. void SynthModular::cb_New(Fl_Button* o, void* v)
  846. {((SynthModular*)(o->parent()->user_data()))->cb_New_i(o,v);}
  847. //////////////////////////////////////////////////////////
  848. inline void SynthModular::cb_NewDevice_i(Fl_Button* o, void* v)
  849. {
  850. AddDevice(*((int*)v));
  851. }
  852. void SynthModular::cb_NewDevice(Fl_Button* o, void* v)
  853. {((SynthModular*)(o->parent()->user_data()))->cb_NewDevice_i(o,v);}
  854. //////////////////////////////////////////////////////////
  855. inline void SynthModular::cb_NewDeviceFromMenu_i(Fl_Canvas* o, void* v)
  856. {
  857. AddDevice(*((int*)v),*((int*)v+1),*((int*)v+2));
  858. }
  859. void SynthModular::cb_NewDeviceFromMenu(Fl_Canvas* o, void* v)
  860. {((SynthModular*)(o->user_data()))->cb_NewDeviceFromMenu_i(o,v);}
  861. //////////////////////////////////////////////////////////
  862. inline void SynthModular::cb_NewComment_i(Fl_Button* o, void* v)
  863. {
  864. AddComment(-1);
  865. }
  866. void SynthModular::cb_NewComment(Fl_Button* o, void* v)
  867. {((SynthModular*)(o->user_data()))->cb_NewComment_i(o,v);}
  868. //////////////////////////////////////////////////////////
  869. inline void SynthModular::cb_PluginGroupLeft_i(Fl_Button* o, void* v)
  870. {
  871. m_CurrentGroup->second->GetToolPack()->hide();
  872. m_CurrentGroup++;
  873. if (m_CurrentGroup==m_PluginGroupMap.end()) m_CurrentGroup=m_PluginGroupMap.begin();
  874. m_CurrentGroup->second->GetToolPack()->show();
  875. m_GroupName->label(m_CurrentGroup->first.c_str());
  876. }
  877. void SynthModular::cb_PluginGroupLeft(Fl_Button* o, void* v)
  878. {((SynthModular*)(o->parent()->user_data()))->cb_PluginGroupLeft_i(o,v);}
  879. //////////////////////////////////////////////////////////
  880. inline void SynthModular::cb_PluginGroupRight_i(Fl_Button* o, void* v)
  881. {
  882. m_CurrentGroup->second->GetToolPack()->hide();
  883. m_CurrentGroup++;
  884. if (m_CurrentGroup==m_PluginGroupMap.end()) m_CurrentGroup=m_PluginGroupMap.begin();
  885. m_CurrentGroup->second->GetToolPack()->show();
  886. m_GroupName->label(m_CurrentGroup->first.c_str());
  887. }
  888. void SynthModular::cb_PluginGroupRight(Fl_Button* o, void* v)
  889. {((SynthModular*)(o->parent()->user_data()))->cb_PluginGroupRight_i(o,v);}
  890. //////////////////////////////////////////////////////////
  891. inline void SynthModular::cb_Rload_i(Fl_Button* o, void* v)
  892. {
  893. m_SettingsWindow->show();
  894. /*PluginManager::Get()->UnloadAll();
  895. m_ToolBox->remove(m_ToolPack);
  896. delete m_ToolPack;
  897. m_ToolPack = new Fl_Pack(5,20,TOOLBOX_WIDTH-10, TOOLBOX_HEIGHT-40,"");
  898. m_ToolPack->type(FL_VERTICAL);
  899. m_ToolPack->box(FL_NO_BOX);
  900. m_ToolPack->color(SpiralSynthModularInfo::GUICOL_Tool);
  901. m_ToolPack->user_data((void*)(this));
  902. m_ToolBox->add(m_ToolPack);
  903. m_ToolBox->redraw();
  904. LoadPlugins();*/
  905. }
  906. void SynthModular::cb_Rload(Fl_Button* o, void* v)
  907. {((SynthModular*)(o->parent()->user_data()))->cb_Rload_i(o,v);}
  908. //////////////////////////////////////////////////////////
  909. inline void SynthModular::cb_Connection_i(Fl_Canvas* o, void* v)
  910. {
  911. CanvasWire *Wire;
  912. Wire=(CanvasWire*)v;
  913. map<int,DeviceWin*>::iterator si=m_DeviceWinMap.find(Wire->OutputID);
  914. if (si==m_DeviceWinMap.end())
  915. {
  916. char num[32];
  917. sprintf(num,"%d",Wire->OutputID);
  918. SpiralInfo::Alert("Warning: Connection problem - can't find source "+string(num));
  919. return;
  920. }
  921. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(Wire->InputID);
  922. if (di==m_DeviceWinMap.end())
  923. {
  924. char num[32];
  925. sprintf(num,"%d",Wire->InputID);
  926. SpiralInfo::Alert("Warning: Connection problem - can't find destination "+string(num));
  927. return;
  928. }
  929. Sample *sample=NULL;
  930. if (!si->second->m_Device->GetOutput(Wire->OutputPort,&sample))
  931. {
  932. char num[32];
  933. sprintf(num,"%d,%d",Wire->OutputID,Wire->OutputPort);
  934. SpiralInfo::Alert("Warning: Connection problem - can't find source output "+string(num));
  935. return;
  936. }
  937. if (!di->second->m_Device->SetInput(Wire->InputPort,(const Sample*)sample))
  938. {
  939. char num[32];
  940. sprintf(num,"%d,%d",Wire->InputID,Wire->InputPort);
  941. SpiralInfo::Alert("Warning: Connection problem - can't find source input "+string(num));
  942. return;
  943. }
  944. }
  945. void SynthModular::cb_Connection(Fl_Canvas* o, void* v)
  946. {((SynthModular*)(o->user_data()))->cb_Connection_i(o,v);}
  947. //////////////////////////////////////////////////////////
  948. inline void SynthModular::cb_Unconnect_i(Fl_Canvas* o, void* v)
  949. {
  950. CanvasWire *Wire;
  951. Wire=(CanvasWire*)v;
  952. //cerr<<Wire->InputID<<" "<<Wire->InputPort<<endl;
  953. map<int,DeviceWin*>::iterator di=m_DeviceWinMap.find(Wire->InputID);
  954. if (di==m_DeviceWinMap.end())
  955. {
  956. //cerr<<"Can't find destination device "<<Wire->InputID<<endl;
  957. return;
  958. }
  959. SpiralPlugin *Plugin=di->second->m_Device;
  960. if (Plugin && !Plugin->SetInput(Wire->InputPort,NULL))
  961. { cerr<<"Can't find destination device's Input"<<endl; return; }
  962. }
  963. void SynthModular::cb_Unconnect(Fl_Canvas* o, void* v)
  964. {((SynthModular*)(o->user_data()))->cb_Unconnect_i(o,v);}
  965. //////////////////////////////////////////////////////////
  966. void SynthModular::cb_UpdatePluginInfo(int ID, void *PInfo)
  967. {
  968. map<int,DeviceWin*>::iterator i=m_DeviceWinMap.find(ID);
  969. if (i!=m_DeviceWinMap.end())
  970. {
  971. DeviceGUIInfo Info=BuildDeviceGUIInfo(*((PluginInfo*)PInfo));
  972. (*i).second->m_DeviceGUI->Setup(Info);
  973. (*i).second->m_DeviceGUI->redraw();
  974. }
  975. }
  976. //////////////////////////////////////////////////////////
  977. void SynthModular::LoadPatch(const char *fn)
  978. {
  979. ifstream inf(fn);
  980. if (inf)
  981. {
  982. m_FilePath=fn;
  983. ClearUp();
  984. inf>>*this;
  985. TITLEBAR=LABEL+" "+fn;
  986. m_TopWindow->label(TITLEBAR.c_str());
  987. }
  988. }
  989. //////////////////////////////////////////////////////////