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.

606 lines
14KB

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