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.

694 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.OutputID=-1;
  36. m_IncompleteWire.OutputPort=-1;
  37. m_IncompleteWire.OutputTerminal=false;
  38. m_IncompleteWire.InputID=-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. // draw minimised modules first
  81. for (int i=children(); i--;)
  82. {
  83. Fl_Widget& o = **a++;
  84. if (((Fl_DeviceGUI*)&o)->IsMinimised())
  85. {
  86. draw_child(o);
  87. draw_outside_label(o);
  88. }
  89. }
  90. DrawWires();
  91. // draw maximised modules on top of everything else
  92. Fl_Widget*const* a = array();
  93. for (int i=children(); i--;)
  94. {
  95. Fl_Widget& o = **a++;
  96. if (!((Fl_DeviceGUI*)&o)->IsMinimised())
  97. {
  98. draw_child(o);
  99. draw_outside_label(o);
  100. }
  101. }
  102. }
  103. else // only redraw the children that need it:
  104. {
  105. for (int i=children(); i--;) update_child(**a++);
  106. }
  107. if (m_ToolMenu)
  108. {
  109. int Pos=0,X=0,Y=0,textw,texth;
  110. int DegreesPerItem=30;
  111. float conv=3.151/180.0f;
  112. bool selected=false;
  113. m_Selected=-1;
  114. fl_font(fl_font(),10);
  115. for (vector< pair<string,int> >::iterator i=m_PluginNameList.begin();
  116. i!=m_PluginNameList.end(); ++i)
  117. {
  118. textw=0;
  119. fl_font(fl_font(),10);
  120. fl_measure(i->first.c_str(), textw, texth);
  121. X=m_x-(textw/2);
  122. Y=m_y-(m_PluginNameList.size()*5)+Pos*10;
  123. if (Fl::event_y()>Y-10 && Fl::event_y()<Y &&
  124. Fl::event_x()>X && Fl::event_x()<X+textw)
  125. {
  126. fl_font(fl_font(),15);
  127. fl_measure(i->first.c_str(), textw, texth);
  128. X=m_x-(textw/2);
  129. m_Selected=i->second;
  130. selected=true;
  131. }
  132. else selected=false;
  133. fl_color(FL_GRAY);
  134. fl_color(FL_WHITE);
  135. fl_draw(i->first.c_str(),X-1,Y+1);
  136. if (selected) fl_color(FL_BLUE);
  137. else fl_color(FL_BLACK);
  138. fl_draw(i->first.c_str(),X,Y);
  139. Pos+=1;
  140. }
  141. }
  142. }
  143. ////////////////////////////////////////////////////////////////////////
  144. void Fl_Canvas::Poll()
  145. {
  146. // bit of a workaround...
  147. if (UserMakingConnection()) m_UpdateTimer++;
  148. if (m_UpdateTimer>UPDATE_TICKS)
  149. {
  150. m_UpdateTimer=0;
  151. redraw();
  152. }
  153. }
  154. ////////////////////////////////////////////////////////////////////////
  155. void Fl_Canvas::DrawWires()
  156. {
  157. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  158. i!=m_WireVec.end(); i++)
  159. {
  160. Fl_DeviceGUI* SourceDevice = FindDevice(i->OutputID);
  161. Fl_DeviceGUI* DestDevice = FindDevice(i->InputID);
  162. if (!SourceDevice || !DestDevice)
  163. {
  164. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  165. return;
  166. }
  167. Fl_Color col = (Fl_Color) WIRE_COL0;
  168. switch (SourceDevice->GetPortType(i->OutputPort+SourceDevice->GetInfo()->NumInputs)) {
  169. case 0: col = (Fl_Color) WIRE_COL0; break;
  170. case 1: col = (Fl_Color) WIRE_COL1; break;
  171. case 2: col = (Fl_Color) WIRE_COL2; break;
  172. case 3: col = (Fl_Color) WIRE_COL3; break;
  173. case 4: col = (Fl_Color) WIRE_COL4; break;
  174. default: col = (Fl_Color) WIRE_COL0;
  175. }
  176. fl_color(col);
  177. fl_line(SourceDevice->GetPortX(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  178. SourceDevice->GetPortY(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  179. DestDevice->GetPortX(i->InputPort),
  180. DestDevice->GetPortY(i->InputPort));
  181. }
  182. DrawIncompleteWire();
  183. }
  184. ////////////////////////////////////////////////////////////////////////
  185. bool Fl_Canvas::UserMakingConnection()
  186. {
  187. return (m_IncompleteWire.InputID!=-1 || m_IncompleteWire.OutputID!=-1);
  188. }
  189. ////////////////////////////////////////////////////////////////////////
  190. void Fl_Canvas::DrawIncompleteWire()
  191. {
  192. // draw the wire we are currently connecting
  193. if(m_IncompleteWire.InputID!=-1)
  194. {
  195. Fl_DeviceGUI* Device = FindDevice(m_IncompleteWire.InputID);
  196. if (!Device)
  197. {
  198. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  199. return;
  200. }
  201. Fl_Color col = (Fl_Color) WIRE_COL0;
  202. switch (Device->GetPortType(m_IncompleteWire.InputPort)) {
  203. case 0: col = (Fl_Color) WIRE_COL0; break;
  204. case 1: col = (Fl_Color) WIRE_COL1; break;
  205. case 2: col = (Fl_Color) WIRE_COL2; break;
  206. case 3: col = (Fl_Color) WIRE_COL3; break;
  207. case 4: col = (Fl_Color) WIRE_COL4; break;
  208. default: col = (Fl_Color) WIRE_COL0;
  209. }
  210. fl_color(col);
  211. fl_line(Device->GetPortX(m_IncompleteWire.InputPort),
  212. Device->GetPortY(m_IncompleteWire.InputPort),
  213. Fl::event_x(),
  214. Fl::event_y());
  215. }
  216. if(m_IncompleteWire.OutputID!=-1)
  217. {
  218. Fl_DeviceGUI* Device = FindDevice(m_IncompleteWire.OutputID);
  219. if (!Device)
  220. {
  221. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  222. return;
  223. }
  224. Fl_Color col = (Fl_Color) WIRE_COL0;
  225. switch (Device->GetPortType(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs)) {
  226. case 0: col = (Fl_Color) WIRE_COL0; break;
  227. case 1: col = (Fl_Color) WIRE_COL1; break;
  228. case 2: col = (Fl_Color) WIRE_COL2; break;
  229. case 3: col = (Fl_Color) WIRE_COL3; break;
  230. case 4: col = (Fl_Color) WIRE_COL4; break;
  231. default: col = (Fl_Color) WIRE_COL0;
  232. }
  233. fl_color(col);
  234. fl_line(Device->GetPortX(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs),
  235. Device->GetPortY(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs),
  236. Fl::event_x(),
  237. Fl::event_y());
  238. }
  239. }
  240. ////////////////////////////////////////////////////////////////////////
  241. void Fl_Canvas::ClearIncompleteWire()
  242. {
  243. // Turn off both ports
  244. if (m_IncompleteWire.OutputID!=-1)
  245. {
  246. FindDevice(m_IncompleteWire.OutputID)->RemoveConnection(m_IncompleteWire.OutputPort+FindDevice(m_IncompleteWire.OutputID)->GetInfo()->NumInputs);
  247. }
  248. if (m_IncompleteWire.InputID!=-1)
  249. {
  250. FindDevice(m_IncompleteWire.InputID)->RemoveConnection(m_IncompleteWire.InputPort);
  251. }
  252. m_IncompleteWire.Clear();
  253. }
  254. ////////////////////////////////////////////////////////////////////////
  255. int Fl_Canvas::handle(int event)
  256. {
  257. if (Fl_Group::handle(event)) return 1;
  258. if (event==FL_PUSH)
  259. {
  260. ClearIncompleteWire();
  261. redraw();
  262. m_DragX=Fl::event_x();
  263. m_DragY=Fl::event_y();
  264. }
  265. if (Fl::event_button()==1 && event==FL_DRAG)
  266. {
  267. position(x()+(Fl::event_x()-m_DragX),y()+(Fl::event_y()-m_DragY));
  268. m_DragX=Fl::event_x();
  269. m_DragY=Fl::event_y();
  270. redraw();
  271. }
  272. if (Fl::event_button()==3)
  273. {
  274. if (event==FL_PUSH)
  275. {
  276. m_ToolMenu=true;
  277. m_x=Fl::event_x();
  278. m_y=Fl::event_y();
  279. redraw();
  280. }
  281. if (event==FL_DRAG) redraw();
  282. if (event==FL_RELEASE && Fl::event_button()==3)
  283. {
  284. m_ToolMenu=false;
  285. if (m_Selected!=-1 && cb_AddDevice)
  286. {
  287. int args[3];
  288. args[0]=m_Selected;
  289. args[1]=m_x;
  290. args[2]=m_y;
  291. cb_AddDevice(this,args);
  292. }
  293. redraw();
  294. }
  295. }
  296. return 1;
  297. }
  298. ////////////////////////////////////////////////////////////////////////
  299. void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value)
  300. {
  301. if(Value) // Turned on the port
  302. {
  303. if(m_IncompleteWire.InputID==-1 || m_IncompleteWire.OutputID==-1)
  304. {
  305. if (Type==Fl_DeviceGUI::OUTPUT)
  306. {
  307. // make sure we don't make a output->output connection
  308. if (m_IncompleteWire.OutputID==-1)
  309. {
  310. m_IncompleteWire.OutputPort=Port;
  311. m_IncompleteWire.OutputID=Device->GetID();
  312. m_IncompleteWire.OutputTerminal=Device->IsTerminal();
  313. }
  314. else
  315. {
  316. ClearIncompleteWire();
  317. }
  318. }
  319. else
  320. {
  321. // make sure we don't make a input->input connection
  322. if (m_IncompleteWire.InputID==-1)
  323. {
  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.InputID!=-1 && m_IncompleteWire.OutputID!=-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 = FindDevice(m_IncompleteWire.OutputID);
  343. ODGUI->AddConnection(m_IncompleteWire.OutputPort+ODGUI->GetInfo()->NumInputs);
  344. Fl_DeviceGUI* IDGUI = FindDevice(m_IncompleteWire.InputID);
  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->OutputID==Device->GetID() && i->OutputPort==Port) ||
  362. (Type==Fl_DeviceGUI::INPUT && i->InputID==Device->GetID() && i->InputPort==Port))
  363. {
  364. // Turn off both ports
  365. Fl_DeviceGUI* ODGUI = FindDevice(i->OutputID);
  366. ODGUI->RemoveConnection(i->OutputPort+ODGUI->GetInfo()->NumInputs);
  367. Fl_DeviceGUI* IDGUI = FindDevice(i->InputID);
  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. bool removedall=false;
  388. while (!removedall)
  389. {
  390. removedall=true;
  391. for (vector<CanvasWire>::iterator i=m_WireVec.begin();
  392. i!=m_WireVec.end(); i++)
  393. {
  394. if (i->OutputID==Device->GetID() ||
  395. i->InputID==Device->GetID())
  396. {
  397. // Turn off both ports
  398. FindDevice(i->OutputID)->RemoveConnection(i->OutputPort+FindDevice(i->OutputID)->GetInfo()->NumInputs);
  399. FindDevice(i->InputID)->RemoveConnection(i->InputPort);
  400. // send the unconnect callback
  401. cb_Unconnect(this,(void*)&(*i));
  402. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  403. m_WireVec.erase(i);
  404. removedall=false;
  405. break;
  406. }
  407. }
  408. }
  409. }
  410. ////////////////////////////////////////////////////////////////////////
  411. void Fl_Canvas::RemoveDevice(Fl_DeviceGUI* Device)
  412. {
  413. ClearConnections(Device);
  414. remove(Device);
  415. redraw();
  416. }
  417. ////////////////////////////////////////////////////////////////////////
  418. void Fl_Canvas::Clear()
  419. {
  420. m_Graph.Clear();
  421. int kids=children();
  422. for(int n=0; n<kids; n++)
  423. {
  424. remove(child(0));
  425. }
  426. m_WireVec.clear();
  427. redraw();
  428. }
  429. ////////////////////////////////////////////////////////////////////////
  430. void Fl_Canvas::Rename(Fl_DeviceGUI* Device)
  431. {
  432. if (cb_Rename) cb_Rename(this,Device);
  433. }
  434. ////////////////////////////////////////////////////////////////////////
  435. Fl_DeviceGUI *Fl_Canvas::FindDevice(int ID)
  436. {
  437. for(int n=0; n<children(); n++)
  438. {
  439. if(((Fl_DeviceGUI*)child(n))->GetID()==ID)
  440. {
  441. return (Fl_DeviceGUI*)child(n);
  442. }
  443. }
  444. return NULL;
  445. }
  446. /////////////////////////////////////////////////////////////////////////
  447. void Fl_Canvas::ToTop(Fl_DeviceGUI *o)
  448. {
  449. if (children()<2) return; //no need to do anything
  450. // cast away the const :P
  451. Fl_Widget** a=(Fl_Widget**)array();
  452. int p=find(o);
  453. if (p<0)
  454. {
  455. cerr<<"ToTop couldn't find widget!"<<endl;
  456. return;
  457. }
  458. Fl_Widget *temp=a[0];
  459. Fl_Widget *last=a[0];
  460. for(int n=1; n<children(); n++)
  461. {
  462. if (n>p) // after the widget in the list
  463. {
  464. // move the widgets up
  465. a[n-1]=a[n];
  466. }
  467. }
  468. a[children()-1]=o; // put the raised one at the top of the list
  469. }
  470. void Fl_Canvas::ToBot(Fl_DeviceGUI *o)
  471. {
  472. if (children()<2) return; //no need to do anything
  473. // cast away the const :P
  474. Fl_Widget** a=(Fl_Widget**)array();
  475. int p=find(o);
  476. if (p<0)
  477. {
  478. cerr<<"ToBot couldn't find widget!"<<endl;
  479. return;
  480. }
  481. Fl_Widget *temp=a[0];
  482. Fl_Widget *last=a[0];
  483. for(int n=1; n<children(); n++)
  484. {
  485. if (n<=p) // before the widget in the list
  486. {
  487. // move the widgets down
  488. temp=a[n];
  489. a[n]=last;
  490. last=temp;
  491. }
  492. }
  493. a[0]=o; // put the lowered one at the top of the list
  494. }
  495. /////////////////////////////////////////////////////////////////////////
  496. istream &operator>>(istream &s, Fl_Canvas &o)
  497. {
  498. int NumWires;
  499. s>>NumWires;
  500. // my bad, didn't version this stream - remove one day...
  501. if (NumWires==-1)
  502. {
  503. int version;
  504. s>>version;
  505. s>>NumWires;
  506. for(int n=0; n<NumWires; n++)
  507. {
  508. CanvasWire NewWire;
  509. int dummy;
  510. s>>NewWire.OutputID;
  511. s>>dummy;
  512. s>>NewWire.OutputPort;
  513. s>>NewWire.OutputTerminal;
  514. s>>NewWire.InputID;
  515. s>>dummy;
  516. s>>NewWire.InputPort;
  517. s>>NewWire.InputTerminal;
  518. // if we can turn on both ports
  519. if (o.FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
  520. o.FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
  521. o.FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
  522. {
  523. o.m_WireVec.push_back(NewWire);
  524. // Notify connection by callback
  525. o.cb_Connection(&o,(void*)&NewWire);
  526. o.m_Graph.AddConnection(NewWire.OutputID,NewWire.OutputTerminal,NewWire.InputID,NewWire.InputTerminal);
  527. }
  528. }
  529. }
  530. else
  531. {
  532. for(int n=0; n<NumWires; n++)
  533. {
  534. CanvasWire NewWire;
  535. int dummy;
  536. s>>NewWire.OutputID;
  537. s>>dummy;
  538. s>>NewWire.OutputPort;
  539. s>>NewWire.InputID;
  540. s>>dummy;
  541. s>>NewWire.InputPort;
  542. // if we can turn on both ports
  543. if (o.FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
  544. o.FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
  545. o.FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
  546. {
  547. o.m_WireVec.push_back(NewWire);
  548. // Notify connection by callback
  549. o.cb_Connection(&o,(void*)&NewWire);
  550. o.m_Graph.AddConnection(NewWire.OutputID,false,NewWire.InputID,false);
  551. }
  552. }
  553. }
  554. return s;
  555. }
  556. ////////////////////////////////////////////////////////////////////////
  557. ostream &operator<<(ostream &s, Fl_Canvas &o)
  558. {
  559. int version=0;
  560. s<<-1<<" "<<version<<" ";
  561. s<<o.m_WireVec.size()<<endl;
  562. for(vector<CanvasWire>::iterator i=o.m_WireVec.begin();
  563. i!=o.m_WireVec.end(); i++)
  564. {
  565. s<<i->OutputID<<" ";
  566. s<<0<<" ";
  567. s<<i->OutputPort<<" ";
  568. s<<i->OutputTerminal<<" ";
  569. s<<i->InputID<<" ";
  570. s<<0<<" ";
  571. s<<i->InputPort<<" ";
  572. s<<i->InputTerminal<<endl;
  573. }
  574. return s;
  575. }