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.

1089 lines
25KB

  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/Fl_Scroll.H>
  20. #include "Fl_Canvas.h"
  21. #include "Fl_DeviceGUI.h"
  22. #include <iostream>
  23. #include "../../SpiralSound/SpiralInfo.h"
  24. // no of calls to handle when dragged, before the widget is redrawn
  25. // to allow the wire (connection currently being made) to be redrawn
  26. static const int UPDATE_TICKS = 5;
  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. m_UpdateTimer(0),
  35. m_Selecting(false)
  36. {
  37. m_IncompleteWire.OutputID=-1;
  38. m_IncompleteWire.OutputPort=-1;
  39. m_IncompleteWire.OutputTerminal=false;
  40. m_IncompleteWire.InputID=-1;
  41. m_IncompleteWire.InputPort=-1;
  42. m_IncompleteWire.InputTerminal=false;
  43. m_BG=NULL;
  44. m_BGData=NULL;
  45. m_Menu=NULL;
  46. m_CanPaste=false;
  47. }
  48. ////////////////////////////////////////////////////////////////////////
  49. Fl_Canvas::~Fl_Canvas()
  50. {
  51. if (m_Menu) delete m_Menu;
  52. }
  53. ////////////////////////////////////////////////////////////////////////
  54. void Fl_Canvas::draw()
  55. {
  56. Fl_Widget*const* a = array();
  57. if (damage() & ~FL_DAMAGE_CHILD) // redraw the entire thing:
  58. {
  59. if (m_BG)
  60. {
  61. int X=0,Y=0;
  62. while (Y<w())
  63. {
  64. while (X<h())
  65. {
  66. m_BG->draw(parent()->x()+X,parent()->y()+Y);
  67. #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 0
  68. X+=m_BG->w;
  69. #else
  70. X+=m_BG->w();
  71. #endif
  72. }
  73. #if FL_MAJOR_VERSION == 1 && FL_MINOR_VERSION == 0
  74. Y+=m_BG->h;
  75. #else
  76. Y+=m_BG->h();
  77. #endif
  78. X=0;
  79. }
  80. }
  81. else
  82. {
  83. draw_box();
  84. }
  85. // draw minimised modules first
  86. for (int i=children(); i--;)
  87. {
  88. Fl_Widget& o = **a++;
  89. if (((Fl_DeviceGUI*)&o)->IsMinimised())
  90. {
  91. draw_child(o);
  92. draw_outside_label(o);
  93. std::vector<int>::iterator sel = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), ((Fl_DeviceGUI*)&o)->GetID() );
  94. if (sel != m_Selection.m_DeviceIds.end())
  95. {
  96. fl_color(FL_YELLOW);
  97. fl_rect(o.x(), o.y(), o.w(), o.h());
  98. }
  99. }
  100. }
  101. DrawWires();
  102. // draw maximised modules on top of everything else
  103. Fl_Widget*const* a = array();
  104. for (int i=children(); i--;)
  105. {
  106. Fl_Widget& o = **a++;
  107. if (!((Fl_DeviceGUI*)&o)->IsMinimised())
  108. {
  109. draw_child(o);
  110. draw_outside_label(o);
  111. std::vector<int>::iterator sel = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), ((Fl_DeviceGUI*)&o)->GetID() );
  112. if (sel != m_Selection.m_DeviceIds.end())
  113. {
  114. fl_color(FL_YELLOW);
  115. fl_rect(o.x(), o.y(), o.w(), o.h());
  116. }
  117. }
  118. }
  119. }
  120. else // only redraw the children that need it:
  121. {
  122. for (int i=children(); i--;) update_child(**a++);
  123. }
  124. if (m_ToolMenu)
  125. {
  126. int Pos=0,X=0,Y=0,textw,texth;
  127. int DegreesPerItem=30;
  128. float conv=3.151/180.0f;
  129. bool selected=false;
  130. m_Selected=-1;
  131. fl_font(fl_font(),10);
  132. for (vector< pair<string,int> >::iterator i=m_PluginNameList.begin();
  133. i!=m_PluginNameList.end(); ++i)
  134. {
  135. textw=0;
  136. fl_font(fl_font(),10);
  137. fl_measure(i->first.c_str(), textw, texth);
  138. X=m_x-(textw/2);
  139. Y=m_y-(m_PluginNameList.size()*5)+Pos*10;
  140. if (Fl::event_y()>Y-10 && Fl::event_y()<Y &&
  141. Fl::event_x()>X && Fl::event_x()<X+textw)
  142. {
  143. fl_font(fl_font(),15);
  144. fl_measure(i->first.c_str(), textw, texth);
  145. X=m_x-(textw/2);
  146. m_Selected=i->second;
  147. selected=true;
  148. }
  149. else selected=false;
  150. fl_color(FL_GRAY);
  151. fl_color(FL_WHITE);
  152. fl_draw(i->first.c_str(),X-1,Y+1);
  153. if (selected) fl_color(FL_BLUE);
  154. else fl_color(FL_BLACK);
  155. fl_draw(i->first.c_str(),X,Y);
  156. Pos+=1;
  157. }
  158. }
  159. DrawSelection();
  160. }
  161. ////////////////////////////////////////////////////////////////////////
  162. void Fl_Canvas::Poll()
  163. {
  164. // bit of a workaround...
  165. if (UserMakingConnection()) m_UpdateTimer++;
  166. if (m_UpdateTimer>UPDATE_TICKS)
  167. {
  168. m_UpdateTimer=0;
  169. redraw();
  170. }
  171. }
  172. ////////////////////////////////////////////////////////////////////////
  173. void Fl_Canvas::DrawSelection()
  174. {
  175. if (m_Selecting)
  176. {
  177. int X, Y, W, H;
  178. fl_color(FL_YELLOW);
  179. X = min(m_StartSelectX, m_EndSelectX);
  180. Y = min(m_StartSelectY, m_EndSelectY);
  181. W = max(m_StartSelectX, m_EndSelectX) - X;
  182. H = max(m_StartSelectY, m_EndSelectY) - Y;
  183. fl_rect(X-1, Y-1, W+2, H+2);
  184. }
  185. }
  186. bool widget_intersects_rectangle (Fl_Widget* o, int X, int Y, int W, int H)
  187. {
  188. int src1_x1=o->x(), src1_y1=o->y();
  189. int src1_x2=o->x()+o->w(), src1_y2=o->y()+o->h();
  190. int src2_x1=X, src2_y1=Y;
  191. int src2_x2=X+W, src2_y2=Y+H;
  192. int width=0, height=0;
  193. if (X < o->x())
  194. {
  195. src1_x1=X;
  196. src1_y1=Y;
  197. src1_x2=X+W;
  198. src1_y2=Y+H;
  199. src2_x1=o->x();
  200. src2_y1=o->y();
  201. src2_x2=o->w();
  202. src2_y2=o->h();
  203. }
  204. if (src2_x1 < src1_x2)
  205. {
  206. if (src1_x2 < src2_x2)
  207. width = src1_x2 - src2_x1;
  208. else
  209. width = src2_x2 - src2_x1;
  210. if (width == 0)
  211. return false;
  212. if (src2_y1 < src1_y1)
  213. {
  214. int tmp;
  215. tmp = src2_x1;
  216. src2_x1=src1_x1;
  217. src1_x1=tmp;
  218. tmp = src2_y1;
  219. src2_y1=src1_y1;
  220. src1_y1=tmp;
  221. tmp = src2_x2;
  222. src2_x2=src1_x2;
  223. src1_x2=tmp;
  224. tmp = src2_y2;
  225. src2_y2=src1_y2;
  226. src1_y2=tmp;
  227. }
  228. if (src2_y1 < src1_y2)
  229. {
  230. if (src1_y2 < src2_y2)
  231. height = src1_y2 - src2_y1;
  232. else
  233. height = src2_y2 - src2_y1;
  234. if ((height == 0))
  235. return false;
  236. else
  237. return true;
  238. }
  239. }
  240. return false;
  241. }
  242. void Fl_Canvas::CalculateSelection()
  243. {
  244. Fl_Widget*const* a = array();
  245. int X, Y, W, H;
  246. X = min(m_StartSelectX, m_EndSelectX);
  247. Y = min(m_StartSelectY, m_EndSelectY);
  248. W = max(m_StartSelectX, m_EndSelectX) - X;
  249. H = max(m_StartSelectY, m_EndSelectY) - Y;
  250. m_HaveSelection = false;
  251. m_Selection.Clear();
  252. for (int i=0; i<children(); i++)
  253. {
  254. Fl_Widget& o = **a++;
  255. if (widget_intersects_rectangle(&o, X, Y, W, H))
  256. {
  257. m_HaveSelection = true;
  258. m_Selection.m_DeviceIds.push_back(((Fl_DeviceGUI*)&o)->GetID());
  259. ((Fl_DeviceGUI*)&o)->SetOnDragCallback(cb_OnDrag_s, this);
  260. }
  261. }
  262. }
  263. inline void Fl_Canvas::cb_OnDrag_i(Fl_Widget* widget, int xoffset,int yoffset)
  264. {
  265. if ((widget) && (widget->parent()))
  266. {
  267. int moved_device_id = ((Fl_DeviceGUI*)(widget->parent()))->GetID();
  268. if (m_HaveSelection)
  269. {
  270. if (m_Selection.m_DeviceIds.size() <= 0)
  271. m_HaveSelection = false;
  272. for (unsigned int i=0; i<m_Selection.m_DeviceIds.size(); i++)
  273. {
  274. int ID = Selection().m_DeviceIds[i];
  275. Fl_Widget *o = FindDevice(ID);
  276. if ((o) && (m_Selection.m_DeviceIds[i] != moved_device_id))
  277. {
  278. o->position(o->x() + xoffset, o->y() + yoffset);
  279. }
  280. }
  281. }
  282. }
  283. return;
  284. }
  285. inline void Fl_Canvas::cb_DeleteDeviceGroup_i()
  286. {
  287. if (! m_HaveSelection)
  288. return;
  289. //show some warning here
  290. for (unsigned int i=0; i<m_Selection.m_DeviceIds.size(); i++)
  291. {
  292. int ID = m_Selection.m_DeviceIds[i];
  293. Fl_DeviceGUI* o = FindDevice(ID);
  294. if (o)
  295. {
  296. Fl_DeviceGUI::Kill(o);
  297. }
  298. }
  299. m_HaveSelection=false;
  300. m_Selection.Clear();
  301. redraw();
  302. }
  303. void Fl_Canvas::PopupEditMenu(Fl_Group *group)
  304. {
  305. if (! (m_Menu))
  306. {
  307. m_Menu = new Fl_Menu_Button(Fl::event_x(),Fl::event_x(),4,4,"Edit");
  308. m_Menu->type(Fl_Menu_Button::POPUP123);
  309. m_Menu->textsize(10);
  310. m_Menu->add("Cut Currently Selected Devices", 0, (Fl_Callback*)cb_CutDeviceGroup,user_data());
  311. m_Menu->add("Copy Currently Selected Devices", 0, (Fl_Callback*)cb_CopyDeviceGroup,user_data());
  312. m_Menu->add("Paste Previously Copied Devices", 0, (Fl_Callback*)cb_PasteDeviceGroup,user_data(), FL_MENU_DIVIDER);
  313. m_Menu->add("Merge Existing Patch", 0, (Fl_Callback*)cb_MergePatch,user_data(), FL_MENU_DIVIDER);
  314. m_Menu->add("Delete Currently Selected Devices", 0, (Fl_Callback*)cb_DeleteDeviceGroup, this);
  315. }
  316. m_Menu->value(0);
  317. group->add(m_Menu);
  318. Fl_Menu_Item *cut=(Fl_Menu_Item*)&(m_Menu->menu()[0]);
  319. Fl_Menu_Item *copy=(Fl_Menu_Item*)&(m_Menu->menu()[1]);
  320. Fl_Menu_Item *paste=(Fl_Menu_Item*)&(m_Menu->menu()[2]);
  321. Fl_Menu_Item *merge=(Fl_Menu_Item*)&(m_Menu->menu()[3]);
  322. Fl_Menu_Item *deleteitems=(Fl_Menu_Item*)&(m_Menu->menu()[4]);
  323. if ((cb_CopyDeviceGroup) && (m_HaveSelection))
  324. copy->activate();
  325. else
  326. copy->deactivate();
  327. if ((cb_CutDeviceGroup) && (m_HaveSelection))
  328. cut->activate();
  329. else
  330. cut->deactivate();
  331. if ((cb_PasteDeviceGroup) && (m_CanPaste))
  332. paste->activate();
  333. else
  334. paste->deactivate();
  335. if (m_HaveSelection)
  336. deleteitems->activate();
  337. else
  338. deleteitems->deactivate();
  339. m_Menu->popup();
  340. group->remove(m_Menu);
  341. }
  342. void Fl_Canvas::StreamSelectionWiresIn(istream &s, std::map<int,int> NewDeviceIds, bool merge, bool paste)
  343. {
  344. MapNewDeviceIds = NewDeviceIds;
  345. StreamWiresIn(s, merge, paste);
  346. }
  347. void Fl_Canvas::StreamSelectionWiresOut(ostream &s)
  348. {
  349. int total_wires = 0, curpos=0;
  350. curpos = s.tellp();
  351. s<<-1<<endl;
  352. if (m_WireVec.size()>0)
  353. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  354. i!=m_WireVec.end(); i++)
  355. {
  356. std::vector<int>::iterator output = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), i->OutputID );
  357. std::vector<int>::iterator input = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), i->InputID );
  358. if ((input != m_Selection.m_DeviceIds.end()) && (output != m_Selection.m_DeviceIds.end()))
  359. {
  360. s<<i->OutputID<<" ";
  361. s<<0<<" ";
  362. s<<i->OutputPort<<" ";
  363. s<<i->OutputTerminal<<" ";
  364. s<<i->InputID<<" ";
  365. s<<0<<" ";
  366. s<<i->InputPort<<" ";
  367. s<<i->InputTerminal<<endl;
  368. total_wires += 1;
  369. }
  370. }
  371. if (total_wires >= 1)
  372. {
  373. s.seekp(curpos, ios::beg);
  374. s<<total_wires<<endl;
  375. s.seekp(0, ios::end);
  376. }
  377. }
  378. ////////////////////////////////////////////////////////////////////////
  379. void Fl_Canvas::DrawWires()
  380. {
  381. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  382. i!=m_WireVec.end(); i++)
  383. {
  384. Fl_DeviceGUI* SourceDevice = FindDevice(i->OutputID);
  385. Fl_DeviceGUI* DestDevice = FindDevice(i->InputID);
  386. if (!SourceDevice || !DestDevice)
  387. {
  388. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  389. return;
  390. }
  391. Fl_Color col = (Fl_Color) WIRE_COL0;
  392. switch (SourceDevice->GetPortType(i->OutputPort+SourceDevice->GetInfo()->NumInputs)) {
  393. case 0: col = (Fl_Color) WIRE_COL0; break;
  394. case 1: col = (Fl_Color) WIRE_COL1; break;
  395. case 2: col = (Fl_Color) WIRE_COL2; break;
  396. case 3: col = (Fl_Color) WIRE_COL3; break;
  397. case 4: col = (Fl_Color) WIRE_COL4; break;
  398. default: col = (Fl_Color) WIRE_COL0;
  399. }
  400. fl_color(col);
  401. fl_line(SourceDevice->GetPortX(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  402. SourceDevice->GetPortY(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  403. DestDevice->GetPortX(i->InputPort),
  404. DestDevice->GetPortY(i->InputPort));
  405. }
  406. DrawIncompleteWire();
  407. }
  408. ////////////////////////////////////////////////////////////////////////
  409. bool Fl_Canvas::UserMakingConnection()
  410. {
  411. return (m_IncompleteWire.InputID!=-1 || m_IncompleteWire.OutputID!=-1);
  412. }
  413. ////////////////////////////////////////////////////////////////////////
  414. void Fl_Canvas::DrawIncompleteWire()
  415. {
  416. // draw the wire we are currently connecting
  417. if(m_IncompleteWire.InputID!=-1)
  418. {
  419. Fl_DeviceGUI* Device = FindDevice(m_IncompleteWire.InputID);
  420. if (!Device)
  421. {
  422. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  423. return;
  424. }
  425. Fl_Color col = (Fl_Color) WIRE_COL0;
  426. switch (Device->GetPortType(m_IncompleteWire.InputPort)) {
  427. case 0: col = (Fl_Color) WIRE_COL0; break;
  428. case 1: col = (Fl_Color) WIRE_COL1; break;
  429. case 2: col = (Fl_Color) WIRE_COL2; break;
  430. case 3: col = (Fl_Color) WIRE_COL3; break;
  431. case 4: col = (Fl_Color) WIRE_COL4; break;
  432. default: col = (Fl_Color) WIRE_COL0;
  433. }
  434. fl_color(col);
  435. fl_line(Device->GetPortX(m_IncompleteWire.InputPort),
  436. Device->GetPortY(m_IncompleteWire.InputPort),
  437. Fl::event_x(),
  438. Fl::event_y());
  439. }
  440. if(m_IncompleteWire.OutputID!=-1)
  441. {
  442. Fl_DeviceGUI* Device = FindDevice(m_IncompleteWire.OutputID);
  443. if (!Device)
  444. {
  445. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  446. return;
  447. }
  448. Fl_Color col = (Fl_Color) WIRE_COL0;
  449. switch (Device->GetPortType(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs)) {
  450. case 0: col = (Fl_Color) WIRE_COL0; break;
  451. case 1: col = (Fl_Color) WIRE_COL1; break;
  452. case 2: col = (Fl_Color) WIRE_COL2; break;
  453. case 3: col = (Fl_Color) WIRE_COL3; break;
  454. case 4: col = (Fl_Color) WIRE_COL4; break;
  455. default: col = (Fl_Color) WIRE_COL0;
  456. }
  457. fl_color(col);
  458. fl_line(Device->GetPortX(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs),
  459. Device->GetPortY(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs),
  460. Fl::event_x(),
  461. Fl::event_y());
  462. }
  463. }
  464. ////////////////////////////////////////////////////////////////////////
  465. void Fl_Canvas::ClearIncompleteWire()
  466. {
  467. // Turn off both ports
  468. if (m_IncompleteWire.OutputID!=-1)
  469. {
  470. FindDevice(m_IncompleteWire.OutputID)->RemoveConnection(m_IncompleteWire.OutputPort+FindDevice(m_IncompleteWire.OutputID)->GetInfo()->NumInputs);
  471. }
  472. if (m_IncompleteWire.InputID!=-1)
  473. {
  474. FindDevice(m_IncompleteWire.InputID)->RemoveConnection(m_IncompleteWire.InputPort);
  475. }
  476. m_IncompleteWire.Clear();
  477. }
  478. ////////////////////////////////////////////////////////////////////////
  479. int Fl_Canvas::handle(int event)
  480. {
  481. if (Fl_Group::handle(event)) return 1;
  482. if (event==FL_PUSH)
  483. {
  484. ClearIncompleteWire();
  485. redraw();
  486. m_DragX=Fl::event_x();
  487. m_DragY=Fl::event_y();
  488. }
  489. if (Fl::event_button()==1)
  490. {
  491. if (event==FL_PUSH)
  492. {
  493. if (m_HaveSelection)
  494. {
  495. m_Selection.Clear();
  496. m_HaveSelection = false;
  497. }
  498. if ((Fl::event_state() & FL_CTRL) != 0)
  499. {
  500. m_Selecting = true;
  501. m_StartSelectX=Fl::event_x();
  502. m_StartSelectY=Fl::event_y();
  503. m_EndSelectX=Fl::event_x();
  504. m_EndSelectY=Fl::event_y();
  505. }
  506. ClearIncompleteWire();
  507. redraw();
  508. m_DragX=Fl::event_x();
  509. m_DragY=Fl::event_y();
  510. }
  511. if (event==FL_DRAG)
  512. {
  513. if (m_Selecting)
  514. {
  515. m_EndSelectX=Fl::event_x();
  516. m_EndSelectY=Fl::event_y();
  517. int newx=0, newy=0, xp=((Fl_Scroll *)parent())->xposition(), yp=((Fl_Scroll *)parent())->yposition();
  518. if ((m_EndSelectX < m_StartSelectX) && ((m_EndSelectX - x() - xp) <= 15))
  519. newx=10;
  520. if ((m_EndSelectY < m_StartSelectY) && ((m_EndSelectY - y() - yp) <= 15))
  521. newy=10;
  522. if ((m_EndSelectX > m_StartSelectX) && ((((Fl_Scroll *)parent())->x() + ((Fl_Scroll *)parent())->w() - m_EndSelectX - 15) <= 15))
  523. newx=-10;
  524. if ((m_EndSelectY > m_StartSelectY) && ((((Fl_Scroll *)parent())->y() + ((Fl_Scroll *)parent())->h() - m_EndSelectY - 15) <= 5))
  525. newy=-10;
  526. if ((newx!=0) || (newy!=0)) {
  527. position(x()+newx,y()+newy);
  528. m_StartSelectX += newx;
  529. m_StartSelectY += newy;
  530. }
  531. }
  532. else
  533. {
  534. position(x()+(Fl::event_x()-m_DragX),y()+(Fl::event_y()-m_DragY));
  535. }
  536. m_DragX=Fl::event_x();
  537. m_DragY=Fl::event_y();
  538. redraw();
  539. }
  540. if (event==FL_RELEASE)
  541. {
  542. if (m_Selecting)
  543. {
  544. m_Selecting = false;
  545. if ((m_EndSelectX != m_StartSelectX) && (m_EndSelectY != m_StartSelectY))
  546. CalculateSelection();
  547. redraw();
  548. }
  549. }
  550. }
  551. if (Fl::event_button()==2)
  552. {
  553. if (event==FL_PUSH)
  554. {
  555. m_ToolMenu=true;
  556. m_x=Fl::event_x();
  557. m_y=Fl::event_y();
  558. redraw();
  559. }
  560. if (event==FL_DRAG) redraw();
  561. if (event==FL_RELEASE)
  562. {
  563. m_ToolMenu=false;
  564. if (m_Selected!=-1 && cb_AddDevice)
  565. {
  566. int args[3];
  567. args[0]=m_Selected;
  568. args[1]=m_x;
  569. args[2]=m_y;
  570. cb_AddDevice(this,args);
  571. }
  572. redraw();
  573. }
  574. }
  575. if ((Fl::event_button()==3) && (event==FL_PUSH) && ((Fl::event_state() & FL_CTRL) != 0))
  576. {
  577. PopupEditMenu(this);
  578. }
  579. return 1;
  580. }
  581. ////////////////////////////////////////////////////////////////////////
  582. void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value)
  583. {
  584. if(Value) // Turned on the port
  585. {
  586. if(m_IncompleteWire.InputID==-1 || m_IncompleteWire.OutputID==-1)
  587. {
  588. if (Type==Fl_DeviceGUI::OUTPUT)
  589. {
  590. // make sure we don't make a output->output connection
  591. if (m_IncompleteWire.OutputID==-1)
  592. {
  593. m_IncompleteWire.OutputPort=Port;
  594. m_IncompleteWire.OutputID=Device->GetID();
  595. m_IncompleteWire.OutputTerminal=Device->IsTerminal();
  596. }
  597. else
  598. {
  599. ClearIncompleteWire();
  600. }
  601. }
  602. else
  603. {
  604. // make sure we don't make a input->input connection
  605. if (m_IncompleteWire.InputID==-1)
  606. {
  607. m_IncompleteWire.InputPort=Port;
  608. m_IncompleteWire.InputID=Device->GetID();
  609. m_IncompleteWire.InputTerminal=Device->IsTerminal();
  610. }
  611. else
  612. {
  613. ClearIncompleteWire();
  614. }
  615. }
  616. // if both have now been set...
  617. if (m_IncompleteWire.InputID!=-1 && m_IncompleteWire.OutputID!=-1)
  618. {
  619. m_WireVec.push_back(m_IncompleteWire);
  620. // send the connect callback
  621. cb_Connection(this,(void*)&m_IncompleteWire);
  622. m_Graph.AddConnection(m_IncompleteWire.OutputID,m_IncompleteWire.OutputTerminal,
  623. m_IncompleteWire.InputID,m_IncompleteWire.InputTerminal);
  624. // Turn on both ports
  625. Fl_DeviceGUI* ODGUI = FindDevice(m_IncompleteWire.OutputID);
  626. ODGUI->AddConnection(m_IncompleteWire.OutputPort+ODGUI->GetInfo()->NumInputs);
  627. Fl_DeviceGUI* IDGUI = FindDevice(m_IncompleteWire.InputID);
  628. IDGUI->AddConnection(m_IncompleteWire.InputPort);
  629. m_IncompleteWire.Clear();
  630. redraw();
  631. }
  632. }
  633. }
  634. else // Turned off the port
  635. {
  636. // Find connections using this port
  637. bool Found=true;
  638. while (Found)
  639. {
  640. Found=false;
  641. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  642. i!=m_WireVec.end(); i++)
  643. {
  644. if ((Type==Fl_DeviceGUI::OUTPUT && i->OutputID==Device->GetID() && i->OutputPort==Port) ||
  645. (Type==Fl_DeviceGUI::INPUT && i->InputID==Device->GetID() && i->InputPort==Port))
  646. {
  647. // Turn off both ports
  648. Fl_DeviceGUI* ODGUI = FindDevice(i->OutputID);
  649. ODGUI->RemoveConnection(i->OutputPort+ODGUI->GetInfo()->NumInputs);
  650. Fl_DeviceGUI* IDGUI = FindDevice(i->InputID);
  651. IDGUI->RemoveConnection(i->InputPort);
  652. // send the unconnect callback
  653. cb_Unconnect(this,(void*)&(*i));
  654. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  655. // Remove the wire
  656. m_WireVec.erase(i);
  657. Found=true;
  658. break;
  659. }
  660. }
  661. }
  662. redraw();
  663. // Clear the current m_Selection
  664. m_IncompleteWire.Clear();
  665. }
  666. }
  667. ////////////////////////////////////////////////////////////////////////
  668. void Fl_Canvas::ClearConnections(Fl_DeviceGUI* Device)
  669. {
  670. bool removedall=false;
  671. //make sure we don't leave a dangling incomplete wire this will cause errors/seg-faults
  672. if (UserMakingConnection() && Device && ((Device->GetID() == m_IncompleteWire.OutputID) ||
  673. (Device->GetID() == m_IncompleteWire.InputID)))
  674. {
  675. ClearIncompleteWire();
  676. }
  677. while (!removedall)
  678. {
  679. removedall=true;
  680. for (vector<CanvasWire>::iterator i=m_WireVec.begin();
  681. i!=m_WireVec.end(); i++)
  682. {
  683. if (i->OutputID==Device->GetID() ||
  684. i->InputID==Device->GetID())
  685. {
  686. // Turn off both ports
  687. FindDevice(i->OutputID)->RemoveConnection(i->OutputPort+FindDevice(i->OutputID)->GetInfo()->NumInputs);
  688. FindDevice(i->InputID)->RemoveConnection(i->InputPort);
  689. // send the unconnect callback
  690. cb_Unconnect(this,(void*)&(*i));
  691. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  692. m_WireVec.erase(i);
  693. removedall=false;
  694. break;
  695. }
  696. }
  697. }
  698. }
  699. ////////////////////////////////////////////////////////////////////////
  700. void Fl_Canvas::RemoveDevice(Fl_DeviceGUI* Device)
  701. {
  702. ClearConnections(Device);
  703. remove(Device);
  704. redraw();
  705. }
  706. ////////////////////////////////////////////////////////////////////////
  707. void Fl_Canvas::Clear()
  708. {
  709. m_Graph.Clear();
  710. int kids=children();
  711. for(int n=0; n<kids; n++)
  712. {
  713. remove(child(0));
  714. }
  715. m_WireVec.clear();
  716. redraw();
  717. }
  718. ////////////////////////////////////////////////////////////////////////
  719. void Fl_Canvas::Rename(Fl_DeviceGUI* Device)
  720. {
  721. if (cb_Rename) cb_Rename(this,Device);
  722. }
  723. ////////////////////////////////////////////////////////////////////////
  724. Fl_DeviceGUI *Fl_Canvas::FindDevice(int ID)
  725. {
  726. for(int n=0; n<children(); n++)
  727. {
  728. if(((Fl_DeviceGUI*)child(n))->GetID()==ID)
  729. {
  730. return (Fl_DeviceGUI*)child(n);
  731. }
  732. }
  733. return NULL;
  734. }
  735. /////////////////////////////////////////////////////////////////////////
  736. void Fl_Canvas::ToTop(Fl_DeviceGUI *o)
  737. {
  738. if (children()<2) return; //no need to do anything
  739. // cast away the const :P
  740. Fl_Widget** a=(Fl_Widget**)array();
  741. int p=find(o);
  742. if (p<0)
  743. {
  744. cerr<<"ToTop couldn't find widget!"<<endl;
  745. return;
  746. }
  747. Fl_Widget *temp=a[0];
  748. Fl_Widget *last=a[0];
  749. for(int n=1; n<children(); n++)
  750. {
  751. if (n>p) // after the widget in the list
  752. {
  753. // move the widgets up
  754. a[n-1]=a[n];
  755. }
  756. }
  757. a[children()-1]=o; // put the raised one at the top of the list
  758. }
  759. void Fl_Canvas::ToBot(Fl_DeviceGUI *o)
  760. {
  761. if (children()<2) return; //no need to do anything
  762. // cast away the const :P
  763. Fl_Widget** a=(Fl_Widget**)array();
  764. int p=find(o);
  765. if (p<0)
  766. {
  767. cerr<<"ToBot couldn't find widget!"<<endl;
  768. return;
  769. }
  770. Fl_Widget *temp=a[0];
  771. Fl_Widget *last=a[0];
  772. for(int n=1; n<children(); n++)
  773. {
  774. if (n<=p) // before the widget in the list
  775. {
  776. // move the widgets down
  777. temp=a[n];
  778. a[n]=last;
  779. last=temp;
  780. }
  781. }
  782. a[0]=o; // put the lowered one at the top of the list
  783. }
  784. /////////////////////////////////////////////////////////////////////////
  785. void Fl_Canvas::StreamWiresIn(istream &s, bool merge, bool paste)
  786. {
  787. int NumWires;
  788. s>>NumWires;
  789. // my bad, didn't version this stream - remove one day...
  790. if (paste || NumWires==-1)
  791. {
  792. int version;
  793. if (!paste)
  794. {
  795. s>>version;
  796. s>>NumWires;
  797. }
  798. for(int n=0; n<NumWires; n++)
  799. {
  800. CanvasWire NewWire;
  801. int dummy;
  802. s>>NewWire.OutputID;
  803. s>>dummy;
  804. s>>NewWire.OutputPort;
  805. s>>NewWire.OutputTerminal;
  806. s>>NewWire.InputID;
  807. s>>dummy;
  808. s>>NewWire.InputPort;
  809. s>>NewWire.InputTerminal;
  810. if (paste || merge)
  811. {
  812. std::map<int, int>::iterator inputID = MapNewDeviceIds.find( NewWire.InputID);
  813. std::map<int, int>::iterator outputID = MapNewDeviceIds.find(NewWire.OutputID);
  814. if ((inputID != MapNewDeviceIds.end()) && (outputID != MapNewDeviceIds.end()))
  815. {
  816. NewWire.InputID = inputID->second;
  817. NewWire.OutputID = outputID->second;
  818. }
  819. }
  820. // if we can turn on both ports
  821. if (FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
  822. FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
  823. FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
  824. {
  825. m_WireVec.push_back(NewWire);
  826. // Notify connection by callback
  827. cb_Connection(this,(void*)&NewWire);
  828. m_Graph.AddConnection(NewWire.OutputID,NewWire.OutputTerminal,NewWire.InputID,NewWire.InputTerminal);
  829. }
  830. }
  831. }
  832. else
  833. {
  834. for(int n=0; n<NumWires; n++)
  835. {
  836. CanvasWire NewWire;
  837. int dummy;
  838. s>>NewWire.OutputID;
  839. s>>dummy;
  840. s>>NewWire.OutputPort;
  841. s>>NewWire.InputID;
  842. s>>dummy;
  843. s>>NewWire.InputPort;
  844. if (paste || merge)
  845. {
  846. std::map<int, int>::iterator inputID = MapNewDeviceIds.find( NewWire.InputID);
  847. std::map<int, int>::iterator outputID = MapNewDeviceIds.find(NewWire.OutputID);
  848. if ((inputID != MapNewDeviceIds.end()) && (outputID != MapNewDeviceIds.end()))
  849. {
  850. NewWire.InputID = inputID->second;
  851. NewWire.OutputID = outputID->second;
  852. }
  853. }
  854. // if we can turn on both ports
  855. if (FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
  856. FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
  857. FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
  858. {
  859. m_WireVec.push_back(NewWire);
  860. // Notify connection by callback
  861. cb_Connection(this,(void*)&NewWire);
  862. m_Graph.AddConnection(NewWire.OutputID,false,NewWire.InputID,false);
  863. }
  864. }
  865. }
  866. }
  867. istream &operator>>(istream &s, Fl_Canvas &o)
  868. {
  869. o.StreamWiresIn(s, false, false);
  870. return s;
  871. }
  872. ////////////////////////////////////////////////////////////////////////
  873. ostream &operator<<(ostream &s, Fl_Canvas &o)
  874. {
  875. int version=0;
  876. s<<-1<<" "<<version<<" ";
  877. s<<o.m_WireVec.size()<<endl;
  878. for(vector<CanvasWire>::iterator i=o.m_WireVec.begin();
  879. i!=o.m_WireVec.end(); i++)
  880. {
  881. s<<i->OutputID<<" ";
  882. s<<0<<" ";
  883. s<<i->OutputPort<<" ";
  884. s<<i->OutputTerminal<<" ";
  885. s<<i->InputID<<" ";
  886. s<<0<<" ";
  887. s<<i->InputPort<<" ";
  888. s<<i->InputTerminal<<endl;
  889. }
  890. return s;
  891. }