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.

511 lines
12KB

  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::DrawWires()
  164. {
  165. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  166. i!=m_WireVec.end(); i++)
  167. {
  168. if (i->OutputChild>children() || i->InputChild>children())
  169. {
  170. cerr<<"wire output child = "<<i->OutputChild<<endl;
  171. cerr<<"wire input child = "<<i->InputChild<<endl;
  172. SpiralInfo::Alert("Wire drawing mismatch!");
  173. return;
  174. }
  175. Fl_DeviceGUI* SourceDevice = (Fl_DeviceGUI*)(child(i->OutputChild));
  176. Fl_DeviceGUI* DestDevice = (Fl_DeviceGUI*)(child(i->InputChild));
  177. if (!SourceDevice || !DestDevice)
  178. {
  179. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  180. return;
  181. }
  182. //=============================
  183. // wire colour stuff - dan b.
  184. //=============================
  185. Fl_Color col = (Fl_Color) WIRE_COL0;
  186. switch (SourceDevice->GetPortType(i->OutputPort+SourceDevice->GetInfo()->NumInputs)) {
  187. case 0: col = (Fl_Color) WIRE_COL0;
  188. break;
  189. case 1: col = (Fl_Color) WIRE_COL1;
  190. break;
  191. case 2: col = (Fl_Color) WIRE_COL2;
  192. break;
  193. case 3: col = (Fl_Color) WIRE_COL3;
  194. break;
  195. case 4: col = (Fl_Color) WIRE_COL4;
  196. break;
  197. default: col = (Fl_Color) WIRE_COL0;
  198. }
  199. fl_color(col);
  200. //=============================
  201. fl_line(SourceDevice->GetPortX(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  202. SourceDevice->GetPortY(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  203. DestDevice->GetPortX(i->InputPort),
  204. DestDevice->GetPortY(i->InputPort));
  205. }
  206. }
  207. int Fl_Canvas::handle(int event)
  208. {
  209. if (Fl_Group::handle(event)) return 1;
  210. if (Fl::event_button()==3)
  211. {
  212. if (event==FL_PUSH)
  213. {
  214. m_ToolMenu=true;
  215. m_x=Fl::event_x();
  216. m_y=Fl::event_y();
  217. redraw();
  218. }
  219. if (event==FL_DRAG) redraw();
  220. if (event==FL_RELEASE && Fl::event_button()==3)
  221. {
  222. m_ToolMenu=false;
  223. if (m_Selected!=-1 && cb_AddDevice)
  224. {
  225. int args[3];
  226. args[0]=m_Selected;
  227. args[1]=m_x;
  228. args[2]=m_y;
  229. cb_AddDevice(this,args);
  230. }
  231. redraw();
  232. }
  233. }
  234. return 1;
  235. }
  236. void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value)
  237. {
  238. // find out which child this comes from.
  239. int ChildNum=-1;
  240. for(int n=0; n<children(); n++)
  241. {
  242. if(child(n)==Device)
  243. {
  244. ChildNum=n;
  245. }
  246. }
  247. if (ChildNum==-1)
  248. {
  249. SpiralInfo::Alert("Port clicked callback can't find source child.");
  250. return;
  251. }
  252. if(Value) // Turned on the port
  253. {
  254. if(m_IncompleteWire.InputChild==-1 || m_IncompleteWire.OutputChild==-1)
  255. {
  256. if (Type==Fl_DeviceGUI::OUTPUT)
  257. {
  258. // make sure we don't make a output->output connection
  259. if (m_IncompleteWire.OutputChild==-1)
  260. {
  261. m_IncompleteWire.OutputChild=ChildNum;
  262. m_IncompleteWire.OutputPort=Port;
  263. m_IncompleteWire.OutputID=Device->GetID();
  264. }
  265. else
  266. {
  267. m_IncompleteWire.Clear();
  268. }
  269. }
  270. else
  271. {
  272. // make sure we don't make a input->input connection
  273. if (m_IncompleteWire.InputChild==-1)
  274. {
  275. m_IncompleteWire.InputChild=ChildNum;
  276. m_IncompleteWire.InputPort=Port;
  277. m_IncompleteWire.InputID=Device->GetID();
  278. }
  279. else
  280. {
  281. m_IncompleteWire.Clear();
  282. }
  283. }
  284. // if both have now been set...
  285. if (m_IncompleteWire.InputChild!=-1 && m_IncompleteWire.OutputChild!=-1)
  286. {
  287. m_WireVec.push_back(m_IncompleteWire);
  288. // send the connect callback
  289. cb_Connection(this,(void*)&m_IncompleteWire);
  290. m_Graph.AddConnection(m_IncompleteWire.OutputID,m_IncompleteWire.InputID);
  291. m_IncompleteWire.Clear();
  292. redraw();
  293. }
  294. }
  295. }
  296. else // Turned off the port
  297. {
  298. // Find the connection
  299. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  300. i!=m_WireVec.end(); i++)
  301. {
  302. if ((Type==Fl_DeviceGUI::OUTPUT && i->OutputChild==ChildNum && i->OutputPort==Port) ||
  303. (Type==Fl_DeviceGUI::INPUT && i->InputChild==ChildNum && i->InputPort==Port))
  304. {
  305. // Turn off both ports
  306. ((Fl_DeviceGUI*)(child(i->OutputChild)))->ForcePortValue(i->OutputPort+
  307. ((Fl_DeviceGUI*)(child(i->OutputChild)))->GetInfo()->NumInputs,false);
  308. ((Fl_DeviceGUI*)(child(i->InputChild)))->ForcePortValue(i->InputPort,false);
  309. // send the unconnect callback
  310. cb_Unconnect(this,(void*)&(*i));
  311. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  312. // Remove the wire
  313. m_WireVec.erase(i);
  314. redraw();
  315. break;
  316. }
  317. }
  318. // Clear the current selection
  319. m_IncompleteWire.Clear();
  320. }
  321. }
  322. void Fl_Canvas::ClearConnections(Fl_DeviceGUI* Device)
  323. {
  324. // find out which child this comes from.
  325. int ChildNum=-1;
  326. for(int n=0; n<children(); n++)
  327. {
  328. if(child(n)==Device)
  329. {
  330. ChildNum=n;
  331. }
  332. }
  333. if (ChildNum==-1)
  334. {
  335. SpiralInfo::Alert("Clear connections callback can't find source child.");
  336. return;
  337. }
  338. bool removedall=false;
  339. while (!removedall)
  340. {
  341. removedall=true;
  342. for (vector<CanvasWire>::iterator i=m_WireVec.begin();
  343. i!=m_WireVec.end(); i++)
  344. {
  345. if (i->OutputChild==ChildNum ||
  346. i->InputChild==ChildNum)
  347. {
  348. // Turn off both ports
  349. ((Fl_DeviceGUI*)(child(i->OutputChild)))->ForcePortValue(i->OutputPort+
  350. ((Fl_DeviceGUI*)(child(i->OutputChild)))->GetInfo()->NumInputs,false);
  351. ((Fl_DeviceGUI*)(child(i->InputChild)))->ForcePortValue(i->InputPort,false);
  352. // send the unconnect callback
  353. cb_Unconnect(this,(void*)&(*i));
  354. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  355. m_WireVec.erase(i);
  356. removedall=false;
  357. break;
  358. }
  359. }
  360. }
  361. }
  362. void Fl_Canvas::RemoveDevice(Fl_DeviceGUI* Device)
  363. {
  364. // find out which child this comes from.
  365. int ChildNum=-1;
  366. for(int n=0; n<children(); n++)
  367. {
  368. if(child(n)==Device)
  369. {
  370. ChildNum=n;
  371. }
  372. }
  373. if (ChildNum==-1)
  374. {
  375. SpiralInfo::Alert("Remove device callback can't find source child.");
  376. return;
  377. }
  378. ClearConnections(Device);
  379. for (vector<CanvasWire>::iterator i=m_WireVec.begin();
  380. i!=m_WireVec.end(); i++)
  381. {
  382. if (i->OutputChild>ChildNum) i->OutputChild--;
  383. if (i->InputChild>ChildNum) i->InputChild--;
  384. }
  385. remove(child(ChildNum));
  386. redraw();
  387. }
  388. void Fl_Canvas::Clear()
  389. {
  390. m_Graph.Clear();
  391. int kids=children();
  392. for(int n=0; n<kids; n++)
  393. {
  394. remove(child(0));
  395. }
  396. m_WireVec.clear();
  397. redraw();
  398. }
  399. istream &operator>>(istream &s, Fl_Canvas &o)
  400. {
  401. int NumWires;
  402. s>>NumWires;
  403. for(int n=0; n<NumWires; n++)
  404. {
  405. CanvasWire NewWire;
  406. s>>NewWire.OutputID;
  407. s>>NewWire.OutputChild;
  408. s>>NewWire.OutputPort;
  409. s>>NewWire.InputID;
  410. s>>NewWire.InputChild;
  411. s>>NewWire.InputPort;
  412. o.m_WireVec.push_back(NewWire);
  413. // Notify connection by callback
  414. o.cb_Connection(&o,(void*)&NewWire);
  415. o.m_Graph.AddConnection(NewWire.OutputID,NewWire.InputID);
  416. // Turn on both ports
  417. ((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->ForcePortValue(NewWire.OutputPort+
  418. ((Fl_DeviceGUI*)(o.child(NewWire.OutputChild)))->GetInfo()->NumInputs,true);
  419. ((Fl_DeviceGUI*)(o.child(NewWire.InputChild)))->ForcePortValue(NewWire.InputPort,true);
  420. }
  421. return s;
  422. }
  423. ostream &operator<<(ostream &s, Fl_Canvas &o)
  424. {
  425. s<<o.m_WireVec.size()<<endl;
  426. for(vector<CanvasWire>::iterator i=o.m_WireVec.begin();
  427. i!=o.m_WireVec.end(); i++)
  428. {
  429. s<<i->OutputID<<" ";
  430. s<<i->OutputChild<<" ";
  431. s<<i->OutputPort<<" ";
  432. s<<i->InputID<<" ";
  433. s<<i->InputChild<<" ";
  434. s<<i->InputPort<<endl;
  435. }
  436. return s;
  437. }