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.

653 lines
16KB

  1. /* Canvas Widget
  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 "Fl/fl_draw.H"
  19. #include "Fl_Canvas.h"
  20. #include "Fl_DeviceGUI.h"
  21. #include <iostream>
  22. #include "../../SpiralSynthModularInfo.h"
  23. // no of calls to handle when dragged, before the widget is redrawn
  24. // to allow the wire (connection currently being made) to be redrawn
  25. static const int UPDATE_TICKS = 5;
  26. ////////////////////////////////////////////////////////////////////////
  27. Fl_Canvas::Fl_Canvas(int x, int y, int w, int h, char *name) :
  28. Fl_Group(x,y,w,h,name),
  29. cb_Connection(NULL),
  30. cb_Unconnect(NULL),
  31. cb_AddDevice(NULL),
  32. m_ToolMenu(false),
  33. m_UpdateTimer(0)
  34. {
  35. m_IncompleteWire.OutputChild=-1;
  36. m_IncompleteWire.OutputPort=-1;
  37. m_IncompleteWire.OutputTerminal=false;
  38. m_IncompleteWire.InputChild=-1;
  39. m_IncompleteWire.InputPort=-1;
  40. m_IncompleteWire.InputTerminal=false;
  41. m_BG=NULL;
  42. m_BGData=NULL;
  43. }
  44. ////////////////////////////////////////////////////////////////////////
  45. Fl_Canvas::~Fl_Canvas()
  46. {
  47. }
  48. ////////////////////////////////////////////////////////////////////////
  49. void Fl_Canvas::draw()
  50. {
  51. Fl_Widget*const* a = array();
  52. if (damage() & ~FL_DAMAGE_CHILD) // redraw the entire thing:
  53. {
  54. if (m_BG)
  55. {
  56. int X=0,Y=0;
  57. while (Y<w())
  58. {
  59. while (X<h())
  60. {
  61. m_BG->draw(parent()->x()+X,parent()->y()+Y);
  62. #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 0
  63. X+=m_BG->w;
  64. #else
  65. X+=m_BG->w();
  66. #endif
  67. }
  68. #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 0
  69. Y+=m_BG->h;
  70. #else
  71. Y+=m_BG->h();
  72. #endif
  73. X=0;
  74. }
  75. }
  76. else
  77. {
  78. draw_box();
  79. }
  80. for (int i=children(); i--;)
  81. {
  82. Fl_Widget& o = **a++;
  83. draw_child(o);
  84. draw_outside_label(o);
  85. }
  86. DrawWires();
  87. }
  88. else // only redraw the children that need it:
  89. {
  90. for (int i=children(); i--;) update_child(**a++);
  91. }
  92. if (m_ToolMenu)
  93. {
  94. int Pos=0,X=0,Y=0,textw,texth;
  95. int DegreesPerItem=30;
  96. float conv=3.151/180.0f;
  97. bool selected=false;
  98. m_Selected=-1;
  99. fl_font(fl_font(),10);
  100. for (vector< pair<string,int> >::iterator i=m_PluginNameList.begin();
  101. i!=m_PluginNameList.end(); ++i)
  102. {
  103. textw=0;
  104. fl_font(fl_font(),10);
  105. fl_measure(i->first.c_str(), textw, texth);
  106. X=m_x-(textw/2);
  107. Y=m_y-(m_PluginNameList.size()*5)+Pos*10;
  108. if (Fl::event_y()>Y-10 && Fl::event_y()<Y &&
  109. Fl::event_x()>X && Fl::event_x()<X+textw)
  110. {
  111. fl_font(fl_font(),15);
  112. fl_measure(i->first.c_str(), textw, texth);
  113. X=m_x-(textw/2);
  114. m_Selected=i->second;
  115. selected=true;
  116. }
  117. else selected=false;
  118. fl_color(FL_GRAY);
  119. fl_color(FL_WHITE);
  120. fl_draw(i->first.c_str(),X-1,Y+1);
  121. if (selected) fl_color(FL_BLUE);
  122. else fl_color(FL_BLACK);
  123. fl_draw(i->first.c_str(),X,Y);
  124. Pos+=1;
  125. }
  126. }
  127. }
  128. ////////////////////////////////////////////////////////////////////////
  129. void Fl_Canvas::Poll()
  130. {
  131. // bit of a workaround...
  132. if (UserMakingConnection()) m_UpdateTimer++;
  133. if (m_UpdateTimer>UPDATE_TICKS)
  134. {
  135. m_UpdateTimer=0;
  136. redraw();
  137. }
  138. }
  139. ////////////////////////////////////////////////////////////////////////
  140. void Fl_Canvas::DrawWires()
  141. {
  142. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  143. i!=m_WireVec.end(); i++)
  144. {
  145. if (i->OutputChild>children() || i->InputChild>children())
  146. {
  147. cerr<<"wire output child = "<<i->OutputChild<<endl;
  148. cerr<<"wire input child = "<<i->InputChild<<endl;
  149. SpiralInfo::Alert("Wire drawing mismatch!");
  150. return;
  151. }
  152. Fl_DeviceGUI* SourceDevice = (Fl_DeviceGUI*)(child(i->OutputChild));
  153. Fl_DeviceGUI* DestDevice = (Fl_DeviceGUI*)(child(i->InputChild));
  154. if (!SourceDevice || !DestDevice)
  155. {
  156. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  157. return;
  158. }
  159. Fl_Color col = (Fl_Color) WIRE_COL0;
  160. switch (SourceDevice->GetPortType(i->OutputPort+SourceDevice->GetInfo()->NumInputs)) {
  161. case 0: col = (Fl_Color) WIRE_COL0; break;
  162. case 1: col = (Fl_Color) WIRE_COL1; break;
  163. case 2: col = (Fl_Color) WIRE_COL2; break;
  164. case 3: col = (Fl_Color) WIRE_COL3; break;
  165. case 4: col = (Fl_Color) WIRE_COL4; break;
  166. default: col = (Fl_Color) WIRE_COL0;
  167. }
  168. fl_color(col);
  169. fl_line(SourceDevice->GetPortX(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  170. SourceDevice->GetPortY(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  171. DestDevice->GetPortX(i->InputPort),
  172. DestDevice->GetPortY(i->InputPort));
  173. }
  174. DrawIncompleteWire();
  175. }
  176. ////////////////////////////////////////////////////////////////////////
  177. bool Fl_Canvas::UserMakingConnection()
  178. {
  179. return (m_IncompleteWire.InputChild!=-1 || m_IncompleteWire.OutputChild!=-1);
  180. }
  181. ////////////////////////////////////////////////////////////////////////
  182. void Fl_Canvas::DrawIncompleteWire()
  183. {
  184. // draw the wire we are currently connecting
  185. if(m_IncompleteWire.InputChild!=-1)
  186. {
  187. Fl_DeviceGUI* Device = (Fl_DeviceGUI*)(child(m_IncompleteWire.InputChild));
  188. if (!Device)
  189. {
  190. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  191. return;
  192. }
  193. Fl_Color col = (Fl_Color) WIRE_COL0;
  194. switch (Device->GetPortType(m_IncompleteWire.InputPort)) {
  195. case 0: col = (Fl_Color) WIRE_COL0; break;
  196. case 1: col = (Fl_Color) WIRE_COL1; break;
  197. case 2: col = (Fl_Color) WIRE_COL2; break;
  198. case 3: col = (Fl_Color) WIRE_COL3; break;
  199. case 4: col = (Fl_Color) WIRE_COL4; break;
  200. default: col = (Fl_Color) WIRE_COL0;
  201. }
  202. fl_color(col);
  203. fl_line(Device->GetPortX(m_IncompleteWire.InputPort),
  204. Device->GetPortY(m_IncompleteWire.InputPort),
  205. Fl::event_x(),
  206. Fl::event_y());
  207. }
  208. if(m_IncompleteWire.OutputChild!=-1)
  209. {
  210. Fl_DeviceGUI* Device = (Fl_DeviceGUI*)(child(m_IncompleteWire.OutputChild));
  211. if (!Device)
  212. {
  213. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  214. return;
  215. }
  216. Fl_Color col = (Fl_Color) WIRE_COL0;
  217. switch (Device->GetPortType(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs)) {
  218. case 0: col = (Fl_Color) WIRE_COL0; break;
  219. case 1: col = (Fl_Color) WIRE_COL1; break;
  220. case 2: col = (Fl_Color) WIRE_COL2; break;
  221. case 3: col = (Fl_Color) WIRE_COL3; break;
  222. case 4: col = (Fl_Color) WIRE_COL4; break;
  223. default: col = (Fl_Color) WIRE_COL0;
  224. }
  225. fl_color(col);
  226. fl_line(Device->GetPortX(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs),
  227. Device->GetPortY(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs),
  228. Fl::event_x(),
  229. Fl::event_y());
  230. }
  231. }
  232. ////////////////////////////////////////////////////////////////////////
  233. void Fl_Canvas::ClearIncompleteWire()
  234. {
  235. // Turn off both ports
  236. if (m_IncompleteWire.OutputChild!=-1)
  237. {
  238. ((Fl_DeviceGUI*)(child(m_IncompleteWire.OutputChild)))->RemoveConnection(m_IncompleteWire.OutputPort+
  239. ((Fl_DeviceGUI*)(child(m_IncompleteWire.OutputChild)))->GetInfo()->NumInputs);
  240. }
  241. if (m_IncompleteWire.InputChild!=-1)
  242. {
  243. ((Fl_DeviceGUI*)(child(m_IncompleteWire.InputChild)))->RemoveConnection(m_IncompleteWire.InputPort);
  244. }
  245. m_IncompleteWire.Clear();
  246. }
  247. ////////////////////////////////////////////////////////////////////////
  248. int Fl_Canvas::handle(int event)
  249. {
  250. if (Fl_Group::handle(event)) return 1;
  251. if (event==FL_PUSH)
  252. {
  253. ClearIncompleteWire();
  254. redraw();
  255. }
  256. if (Fl::event_button()==3)
  257. {
  258. if (event==FL_PUSH)
  259. {
  260. m_ToolMenu=true;
  261. m_x=Fl::event_x();
  262. m_y=Fl::event_y();
  263. redraw();
  264. }
  265. if (event==FL_DRAG) redraw();
  266. if (event==FL_RELEASE && Fl::event_button()==3)
  267. {
  268. m_ToolMenu=false;
  269. if (m_Selected!=-1 && cb_AddDevice)
  270. {
  271. int args[3];
  272. args[0]=m_Selected;
  273. args[1]=m_x;
  274. args[2]=m_y;
  275. cb_AddDevice(this,args);
  276. }
  277. redraw();
  278. }
  279. }
  280. return 1;
  281. }
  282. ////////////////////////////////////////////////////////////////////////
  283. void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value)
  284. {
  285. // find out which child this comes from.
  286. int ChildNum=-1;
  287. for(int n=0; n<children(); n++)
  288. {
  289. if(child(n)==Device)
  290. {
  291. ChildNum=n;
  292. }
  293. }
  294. if (ChildNum==-1)
  295. {
  296. SpiralInfo::Alert("Port clicked callback can't find source child.");
  297. return;
  298. }
  299. if(Value) // Turned on the port
  300. {
  301. if(m_IncompleteWire.InputChild==-1 || m_IncompleteWire.OutputChild==-1)
  302. {
  303. if (Type==Fl_DeviceGUI::OUTPUT)
  304. {
  305. // make sure we don't make a output->output connection
  306. if (m_IncompleteWire.OutputChild==-1)
  307. {
  308. m_IncompleteWire.OutputChild=ChildNum;
  309. m_IncompleteWire.OutputPort=Port;
  310. m_IncompleteWire.OutputID=Device->GetID();
  311. m_IncompleteWire.OutputTerminal=Device->IsTerminal();
  312. }
  313. else
  314. {
  315. ClearIncompleteWire();
  316. }
  317. }
  318. else
  319. {
  320. // make sure we don't make a input->input connection
  321. if (m_IncompleteWire.InputChild==-1)
  322. {
  323. m_IncompleteWire.InputChild=ChildNum;
  324. m_IncompleteWire.InputPort=Port;
  325. m_IncompleteWire.InputID=Device->GetID();
  326. m_IncompleteWire.InputTerminal=Device->IsTerminal();
  327. }
  328. else
  329. {
  330. ClearIncompleteWire();
  331. }
  332. }
  333. // if both have now been set...
  334. if (m_IncompleteWire.InputChild!=-1 && m_IncompleteWire.OutputChild!=-1)
  335. {
  336. m_WireVec.push_back(m_IncompleteWire);
  337. // send the connect callback
  338. cb_Connection(this,(void*)&m_IncompleteWire);
  339. m_Graph.AddConnection(m_IncompleteWire.OutputID,m_IncompleteWire.OutputTerminal,
  340. m_IncompleteWire.InputID,m_IncompleteWire.InputTerminal);
  341. // Turn on both ports
  342. Fl_DeviceGUI* ODGUI = (Fl_DeviceGUI*)(child(m_IncompleteWire.OutputChild));
  343. ODGUI->AddConnection(m_IncompleteWire.OutputPort+ODGUI->GetInfo()->NumInputs);
  344. Fl_DeviceGUI* IDGUI = (Fl_DeviceGUI*)(child(m_IncompleteWire.InputChild));
  345. IDGUI->AddConnection(m_IncompleteWire.InputPort);
  346. m_IncompleteWire.Clear();
  347. redraw();
  348. }
  349. }
  350. }
  351. else // Turned off the port
  352. {
  353. // Find connections using this port
  354. bool Found=true;
  355. while (Found)
  356. {
  357. Found=false;
  358. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  359. i!=m_WireVec.end(); i++)
  360. {
  361. if ((Type==Fl_DeviceGUI::OUTPUT && i->OutputChild==ChildNum && i->OutputPort==Port) ||
  362. (Type==Fl_DeviceGUI::INPUT && i->InputChild==ChildNum && i->InputPort==Port))
  363. {
  364. // Turn off both ports
  365. Fl_DeviceGUI* ODGUI = (Fl_DeviceGUI*)(child(i->OutputChild));
  366. ODGUI->RemoveConnection(i->OutputPort+ODGUI->GetInfo()->NumInputs);
  367. Fl_DeviceGUI* IDGUI = (Fl_DeviceGUI*)(child(i->InputChild));
  368. IDGUI->RemoveConnection(i->InputPort);
  369. // send the unconnect callback
  370. cb_Unconnect(this,(void*)&(*i));
  371. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  372. // Remove the wire
  373. m_WireVec.erase(i);
  374. Found=true;
  375. break;
  376. }
  377. }
  378. }
  379. redraw();
  380. // Clear the current selection
  381. m_IncompleteWire.Clear();
  382. }
  383. }
  384. ////////////////////////////////////////////////////////////////////////
  385. void Fl_Canvas::ClearConnections(Fl_DeviceGUI* Device)
  386. {
  387. // find out which child this comes from.
  388. int ChildNum=-1;
  389. for(int n=0; n<children(); n++)
  390. {
  391. if(child(n)==Device)
  392. {
  393. ChildNum=n;
  394. }
  395. }
  396. if (ChildNum==-1)
  397. {
  398. SpiralInfo::Alert("Clear connections callback can't find source child.");
  399. return;
  400. }
  401. bool removedall=false;
  402. while (!removedall)
  403. {
  404. removedall=true;
  405. for (vector<CanvasWire>::iterator i=m_WireVec.begin();
  406. i!=m_WireVec.end(); i++)
  407. {
  408. if (i->OutputChild==ChildNum ||
  409. i->InputChild==ChildNum)
  410. {
  411. // Turn off both ports
  412. ((Fl_DeviceGUI*)(child(i->OutputChild)))->RemoveConnection(i->OutputPort+
  413. ((Fl_DeviceGUI*)(child(i->OutputChild)))->GetInfo()->NumInputs);
  414. ((Fl_DeviceGUI*)(child(i->InputChild)))->RemoveConnection(i->InputPort);
  415. // send the unconnect callback
  416. cb_Unconnect(this,(void*)&(*i));
  417. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  418. m_WireVec.erase(i);
  419. removedall=false;
  420. break;
  421. }
  422. }
  423. }
  424. }
  425. ////////////////////////////////////////////////////////////////////////
  426. void Fl_Canvas::RemoveDevice(Fl_DeviceGUI* Device)
  427. {
  428. // find out which child this comes from.
  429. int ChildNum=-1;
  430. for(int n=0; n<children(); n++)
  431. {
  432. if(child(n)==Device)
  433. {
  434. ChildNum=n;
  435. }
  436. }
  437. if (ChildNum==-1)
  438. {
  439. SpiralInfo::Alert("Remove device callback can't find source child.");
  440. return;
  441. }
  442. ClearConnections(Device);
  443. for (vector<CanvasWire>::iterator i=m_WireVec.begin();
  444. i!=m_WireVec.end(); i++)
  445. {
  446. if (i->OutputChild>ChildNum) i->OutputChild--;
  447. if (i->InputChild>ChildNum) i->InputChild--;
  448. }
  449. remove(child(ChildNum));
  450. redraw();
  451. }
  452. ////////////////////////////////////////////////////////////////////////
  453. void Fl_Canvas::Clear()
  454. {
  455. m_Graph.Clear();
  456. int kids=children();
  457. for(int n=0; n<kids; n++)
  458. {
  459. remove(child(0));
  460. }
  461. m_WireVec.clear();
  462. redraw();
  463. }
  464. ////////////////////////////////////////////////////////////////////////
  465. istream &operator>>(istream &s, Fl_Canvas &o)
  466. {
  467. int NumWires;
  468. s>>NumWires;
  469. // my bad, didn't version this stream - remove one day...
  470. if (NumWires==-1)
  471. {
  472. int version;
  473. s>>version;
  474. s>>NumWires;
  475. for(int n=0; n<NumWires; n++)
  476. {
  477. CanvasWire NewWire;
  478. s>>NewWire.OutputID;
  479. s>>NewWire.OutputChild;
  480. s>>NewWire.OutputPort;
  481. s>>NewWire.OutputTerminal;
  482. s>>NewWire.InputID;
  483. s>>NewWire.InputChild;
  484. s>>NewWire.InputPort;
  485. s>>NewWire.InputTerminal;
  486. // if we can turn on both ports
  487. if (((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->AddConnection(NewWire.OutputPort+
  488. ((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->GetInfo()->NumInputs) &&
  489. ((Fl_DeviceGUI*)(o.child(NewWire.InputChild)))->AddConnection(NewWire.InputPort))
  490. {
  491. o.m_WireVec.push_back(NewWire);
  492. // Notify connection by callback
  493. o.cb_Connection(&o,(void*)&NewWire);
  494. o.m_Graph.AddConnection(NewWire.OutputID,NewWire.OutputTerminal,NewWire.InputID,NewWire.InputTerminal);
  495. }
  496. }
  497. }
  498. else
  499. {
  500. for(int n=0; n<NumWires; n++)
  501. {
  502. CanvasWire NewWire;
  503. s>>NewWire.OutputID;
  504. s>>NewWire.OutputChild;
  505. s>>NewWire.OutputPort;
  506. s>>NewWire.InputID;
  507. s>>NewWire.InputChild;
  508. s>>NewWire.InputPort;
  509. // if we can turn on both ports
  510. if (((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->AddConnection(NewWire.OutputPort+
  511. ((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->GetInfo()->NumInputs) &&
  512. ((Fl_DeviceGUI*)(o.child(NewWire.InputChild)))->AddConnection(NewWire.InputPort))
  513. {
  514. o.m_WireVec.push_back(NewWire);
  515. // Notify connection by callback
  516. o.cb_Connection(&o,(void*)&NewWire);
  517. o.m_Graph.AddConnection(NewWire.OutputID,false,NewWire.InputID,false);
  518. }
  519. }
  520. }
  521. return s;
  522. }
  523. ////////////////////////////////////////////////////////////////////////
  524. ostream &operator<<(ostream &s, Fl_Canvas &o)
  525. {
  526. int version=0;
  527. s<<-1<<" "<<version<<" ";
  528. s<<o.m_WireVec.size()<<endl;
  529. for(vector<CanvasWire>::iterator i=o.m_WireVec.begin();
  530. i!=o.m_WireVec.end(); i++)
  531. {
  532. s<<i->OutputID<<" ";
  533. s<<i->OutputChild<<" ";
  534. s<<i->OutputPort<<" ";
  535. s<<i->OutputTerminal<<" ";
  536. s<<i->InputID<<" ";
  537. s<<i->InputChild<<" ";
  538. s<<i->InputPort<<" ";
  539. s<<i->InputTerminal<<endl;
  540. }
  541. return s;
  542. }