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.

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