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.

1082 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. void Fl_Canvas::DeleteSelection (void) {
  286. if (! m_HaveSelection) return;
  287. // show some warning here
  288. for (unsigned int i=0; i<m_Selection.m_DeviceIds.size(); i++) {
  289. int ID = m_Selection.m_DeviceIds[i];
  290. Fl_DeviceGUI* o = FindDevice(ID);
  291. if (o) Fl_DeviceGUI::Kill(o);
  292. }
  293. m_HaveSelection = false;
  294. m_Selection.Clear();
  295. redraw();
  296. }
  297. inline void Fl_Canvas::cb_DeleteDeviceGroup_i() {
  298. DeleteSelection ();
  299. }
  300. void Fl_Canvas::PopupEditMenu(Fl_Group *group)
  301. {
  302. if (! (m_Menu))
  303. {
  304. m_Menu = new Fl_Menu_Button(Fl::event_x(),Fl::event_x(),4,4,"Edit");
  305. m_Menu->type(Fl_Menu_Button::POPUP123);
  306. m_Menu->textsize(10);
  307. m_Menu->add("Cut Currently Selected Devices", 0, (Fl_Callback*)cb_CutDeviceGroup,user_data());
  308. m_Menu->add("Copy Currently Selected Devices", 0, (Fl_Callback*)cb_CopyDeviceGroup,user_data());
  309. m_Menu->add("Paste Previously Copied Devices", 0, (Fl_Callback*)cb_PasteDeviceGroup,user_data(), FL_MENU_DIVIDER);
  310. m_Menu->add("Merge Existing Patch", 0, (Fl_Callback*)cb_MergePatch,user_data(), FL_MENU_DIVIDER);
  311. m_Menu->add("Delete Currently Selected Devices", 0, (Fl_Callback*)cb_DeleteDeviceGroup, this);
  312. }
  313. m_Menu->value(0);
  314. group->add(m_Menu);
  315. Fl_Menu_Item *cut=(Fl_Menu_Item*)&(m_Menu->menu()[0]);
  316. Fl_Menu_Item *copy=(Fl_Menu_Item*)&(m_Menu->menu()[1]);
  317. Fl_Menu_Item *paste=(Fl_Menu_Item*)&(m_Menu->menu()[2]);
  318. Fl_Menu_Item *merge=(Fl_Menu_Item*)&(m_Menu->menu()[3]);
  319. Fl_Menu_Item *deleteitems=(Fl_Menu_Item*)&(m_Menu->menu()[4]);
  320. if ((cb_CopyDeviceGroup) && (m_HaveSelection))
  321. copy->activate();
  322. else
  323. copy->deactivate();
  324. if ((cb_CutDeviceGroup) && (m_HaveSelection))
  325. cut->activate();
  326. else
  327. cut->deactivate();
  328. if ((cb_PasteDeviceGroup) && (m_CanPaste))
  329. paste->activate();
  330. else
  331. paste->deactivate();
  332. if (m_HaveSelection)
  333. deleteitems->activate();
  334. else
  335. deleteitems->deactivate();
  336. m_Menu->popup();
  337. group->remove(m_Menu);
  338. }
  339. void Fl_Canvas::StreamSelectionWiresIn(istream &s, std::map<int,int> NewDeviceIds, bool merge, bool paste)
  340. {
  341. MapNewDeviceIds = NewDeviceIds;
  342. StreamWiresIn(s, merge, paste);
  343. }
  344. void Fl_Canvas::StreamSelectionWiresOut(ostream &s)
  345. {
  346. int total_wires = 0, curpos=0;
  347. curpos = s.tellp();
  348. s<<-1<<endl;
  349. if (m_WireVec.size()>0)
  350. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  351. i!=m_WireVec.end(); i++)
  352. {
  353. std::vector<int>::iterator output = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), i->OutputID );
  354. std::vector<int>::iterator input = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), i->InputID );
  355. if ((input != m_Selection.m_DeviceIds.end()) && (output != m_Selection.m_DeviceIds.end()))
  356. {
  357. s<<i->OutputID<<" ";
  358. s<<0<<" ";
  359. s<<i->OutputPort<<" ";
  360. s<<i->OutputTerminal<<" ";
  361. s<<i->InputID<<" ";
  362. s<<0<<" ";
  363. s<<i->InputPort<<" ";
  364. s<<i->InputTerminal<<endl;
  365. total_wires += 1;
  366. }
  367. }
  368. if (total_wires >= 1)
  369. {
  370. s.seekp(curpos, ios::beg);
  371. s<<total_wires<<endl;
  372. s.seekp(0, ios::end);
  373. }
  374. }
  375. ////////////////////////////////////////////////////////////////////////
  376. void Fl_Canvas::DrawWires()
  377. {
  378. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  379. i!=m_WireVec.end(); i++)
  380. {
  381. Fl_DeviceGUI* SourceDevice = FindDevice(i->OutputID);
  382. Fl_DeviceGUI* DestDevice = FindDevice(i->InputID);
  383. if (!SourceDevice || !DestDevice)
  384. {
  385. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  386. return;
  387. }
  388. Fl_Color col = (Fl_Color) WIRE_COL0;
  389. switch (SourceDevice->GetPortType(i->OutputPort+SourceDevice->GetInfo()->NumInputs)) {
  390. case 0: col = (Fl_Color) WIRE_COL0; break;
  391. case 1: col = (Fl_Color) WIRE_COL1; break;
  392. case 2: col = (Fl_Color) WIRE_COL2; break;
  393. case 3: col = (Fl_Color) WIRE_COL3; break;
  394. case 4: col = (Fl_Color) WIRE_COL4; break;
  395. default: col = (Fl_Color) WIRE_COL0;
  396. }
  397. fl_color(col);
  398. fl_line(SourceDevice->GetPortX(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  399. SourceDevice->GetPortY(i->OutputPort+SourceDevice->GetInfo()->NumInputs),
  400. DestDevice->GetPortX(i->InputPort),
  401. DestDevice->GetPortY(i->InputPort));
  402. }
  403. DrawIncompleteWire();
  404. }
  405. ////////////////////////////////////////////////////////////////////////
  406. bool Fl_Canvas::UserMakingConnection()
  407. {
  408. return (m_IncompleteWire.InputID!=-1 || m_IncompleteWire.OutputID!=-1);
  409. }
  410. ////////////////////////////////////////////////////////////////////////
  411. void Fl_Canvas::DrawIncompleteWire()
  412. {
  413. // draw the wire we are currently connecting
  414. if(m_IncompleteWire.InputID!=-1)
  415. {
  416. Fl_DeviceGUI* Device = FindDevice(m_IncompleteWire.InputID);
  417. if (!Device)
  418. {
  419. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  420. return;
  421. }
  422. Fl_Color col = (Fl_Color) WIRE_COL0;
  423. switch (Device->GetPortType(m_IncompleteWire.InputPort)) {
  424. case 0: col = (Fl_Color) WIRE_COL0; break;
  425. case 1: col = (Fl_Color) WIRE_COL1; break;
  426. case 2: col = (Fl_Color) WIRE_COL2; break;
  427. case 3: col = (Fl_Color) WIRE_COL3; break;
  428. case 4: col = (Fl_Color) WIRE_COL4; break;
  429. default: col = (Fl_Color) WIRE_COL0;
  430. }
  431. fl_color(col);
  432. fl_line(Device->GetPortX(m_IncompleteWire.InputPort),
  433. Device->GetPortY(m_IncompleteWire.InputPort),
  434. Fl::event_x(),
  435. Fl::event_y());
  436. }
  437. if(m_IncompleteWire.OutputID!=-1)
  438. {
  439. Fl_DeviceGUI* Device = FindDevice(m_IncompleteWire.OutputID);
  440. if (!Device)
  441. {
  442. SpiralInfo::Alert("Cant find source or dest device while drawing wires");
  443. return;
  444. }
  445. Fl_Color col = (Fl_Color) WIRE_COL0;
  446. switch (Device->GetPortType(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs)) {
  447. case 0: col = (Fl_Color) WIRE_COL0; break;
  448. case 1: col = (Fl_Color) WIRE_COL1; break;
  449. case 2: col = (Fl_Color) WIRE_COL2; break;
  450. case 3: col = (Fl_Color) WIRE_COL3; break;
  451. case 4: col = (Fl_Color) WIRE_COL4; break;
  452. default: col = (Fl_Color) WIRE_COL0;
  453. }
  454. fl_color(col);
  455. fl_line(Device->GetPortX(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs),
  456. Device->GetPortY(m_IncompleteWire.OutputPort+Device->GetInfo()->NumInputs),
  457. Fl::event_x(),
  458. Fl::event_y());
  459. }
  460. }
  461. ////////////////////////////////////////////////////////////////////////
  462. void Fl_Canvas::ClearIncompleteWire()
  463. {
  464. // Turn off both ports
  465. if (m_IncompleteWire.OutputID!=-1)
  466. {
  467. FindDevice(m_IncompleteWire.OutputID)->RemoveConnection(m_IncompleteWire.OutputPort+FindDevice(m_IncompleteWire.OutputID)->GetInfo()->NumInputs);
  468. }
  469. if (m_IncompleteWire.InputID!=-1)
  470. {
  471. FindDevice(m_IncompleteWire.InputID)->RemoveConnection(m_IncompleteWire.InputPort);
  472. }
  473. m_IncompleteWire.Clear();
  474. }
  475. ////////////////////////////////////////////////////////////////////////
  476. int Fl_Canvas::handle(int event)
  477. {
  478. if (Fl_Group::handle(event)) return 1;
  479. if (event==FL_PUSH)
  480. {
  481. ClearIncompleteWire();
  482. redraw();
  483. m_DragX=Fl::event_x();
  484. m_DragY=Fl::event_y();
  485. }
  486. if (Fl::event_button()==1)
  487. {
  488. if (event==FL_PUSH)
  489. {
  490. if (m_HaveSelection)
  491. {
  492. m_Selection.Clear();
  493. m_HaveSelection = false;
  494. }
  495. if (((Fl::event_state() & FL_CTRL) != 0) || ((Fl::event_state() & FL_SHIFT) != 0))
  496. {
  497. m_Selecting = true;
  498. m_StartSelectX=Fl::event_x();
  499. m_StartSelectY=Fl::event_y();
  500. m_EndSelectX=Fl::event_x();
  501. m_EndSelectY=Fl::event_y();
  502. }
  503. ClearIncompleteWire();
  504. redraw();
  505. m_DragX=Fl::event_x();
  506. m_DragY=Fl::event_y();
  507. }
  508. if (event==FL_DRAG)
  509. {
  510. if (m_Selecting)
  511. {
  512. m_EndSelectX=Fl::event_x();
  513. m_EndSelectY=Fl::event_y();
  514. int newx=0, newy=0, xp=((Fl_Scroll *)parent())->xposition(), yp=((Fl_Scroll *)parent())->yposition();
  515. if ((m_EndSelectX < m_StartSelectX) && ((m_EndSelectX - x() - xp) <= 15))
  516. newx=10;
  517. if ((m_EndSelectY < m_StartSelectY) && ((m_EndSelectY - y() - yp) <= 15))
  518. newy=10;
  519. if ((m_EndSelectX > m_StartSelectX) && ((((Fl_Scroll *)parent())->x() + ((Fl_Scroll *)parent())->w() - m_EndSelectX - 15) <= 15))
  520. newx=-10;
  521. if ((m_EndSelectY > m_StartSelectY) && ((((Fl_Scroll *)parent())->y() + ((Fl_Scroll *)parent())->h() - m_EndSelectY - 15) <= 5))
  522. newy=-10;
  523. if ((newx!=0) || (newy!=0)) {
  524. position(x()+newx,y()+newy);
  525. m_StartSelectX += newx;
  526. m_StartSelectY += newy;
  527. }
  528. }
  529. else
  530. {
  531. position(x()+(Fl::event_x()-m_DragX),y()+(Fl::event_y()-m_DragY));
  532. }
  533. m_DragX=Fl::event_x();
  534. m_DragY=Fl::event_y();
  535. redraw();
  536. }
  537. if (event==FL_RELEASE)
  538. {
  539. if (m_Selecting)
  540. {
  541. m_Selecting = false;
  542. if ((m_EndSelectX != m_StartSelectX) && (m_EndSelectY != m_StartSelectY))
  543. CalculateSelection();
  544. redraw();
  545. }
  546. }
  547. }
  548. if (Fl::event_button()==2)
  549. {
  550. if (event==FL_PUSH)
  551. {
  552. m_ToolMenu=true;
  553. m_x=Fl::event_x();
  554. m_y=Fl::event_y();
  555. redraw();
  556. }
  557. if (event==FL_DRAG) redraw();
  558. if (event==FL_RELEASE)
  559. {
  560. m_ToolMenu=false;
  561. if (m_Selected!=-1 && cb_AddDevice)
  562. {
  563. int args[3];
  564. args[0]=m_Selected;
  565. args[1]=m_x;
  566. args[2]=m_y;
  567. cb_AddDevice(this,args);
  568. }
  569. redraw();
  570. }
  571. }
  572. if ((Fl::event_button()==3) && (event==FL_PUSH))
  573. {
  574. PopupEditMenu(this);
  575. }
  576. return 1;
  577. }
  578. ////////////////////////////////////////////////////////////////////////
  579. void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value)
  580. {
  581. if(Value) // Turned on the port
  582. {
  583. if(m_IncompleteWire.InputID==-1 || m_IncompleteWire.OutputID==-1)
  584. {
  585. if (Type==Fl_DeviceGUI::OUTPUT)
  586. {
  587. // make sure we don't make a output->output connection
  588. if (m_IncompleteWire.OutputID==-1)
  589. {
  590. m_IncompleteWire.OutputPort=Port;
  591. m_IncompleteWire.OutputID=Device->GetID();
  592. m_IncompleteWire.OutputTerminal=Device->IsTerminal();
  593. }
  594. else
  595. {
  596. ClearIncompleteWire();
  597. }
  598. }
  599. else
  600. {
  601. // make sure we don't make a input->input connection
  602. if (m_IncompleteWire.InputID==-1)
  603. {
  604. m_IncompleteWire.InputPort=Port;
  605. m_IncompleteWire.InputID=Device->GetID();
  606. m_IncompleteWire.InputTerminal=Device->IsTerminal();
  607. }
  608. else
  609. {
  610. ClearIncompleteWire();
  611. }
  612. }
  613. // if both have now been set...
  614. if (m_IncompleteWire.InputID!=-1 && m_IncompleteWire.OutputID!=-1)
  615. {
  616. m_WireVec.push_back(m_IncompleteWire);
  617. // send the connect callback
  618. cb_Connection(this,(void*)&m_IncompleteWire);
  619. m_Graph.AddConnection(m_IncompleteWire.OutputID,m_IncompleteWire.OutputTerminal,
  620. m_IncompleteWire.InputID,m_IncompleteWire.InputTerminal);
  621. // Turn on both ports
  622. Fl_DeviceGUI* ODGUI = FindDevice(m_IncompleteWire.OutputID);
  623. ODGUI->AddConnection(m_IncompleteWire.OutputPort+ODGUI->GetInfo()->NumInputs);
  624. Fl_DeviceGUI* IDGUI = FindDevice(m_IncompleteWire.InputID);
  625. IDGUI->AddConnection(m_IncompleteWire.InputPort);
  626. m_IncompleteWire.Clear();
  627. redraw();
  628. }
  629. }
  630. }
  631. else // Turned off the port
  632. {
  633. // Find connections using this port
  634. bool Found=true;
  635. while (Found)
  636. {
  637. Found=false;
  638. for(vector<CanvasWire>::iterator i=m_WireVec.begin();
  639. i!=m_WireVec.end(); i++)
  640. {
  641. if ((Type==Fl_DeviceGUI::OUTPUT && i->OutputID==Device->GetID() && i->OutputPort==Port) ||
  642. (Type==Fl_DeviceGUI::INPUT && i->InputID==Device->GetID() && i->InputPort==Port))
  643. {
  644. // Turn off both ports
  645. Fl_DeviceGUI* ODGUI = FindDevice(i->OutputID);
  646. ODGUI->RemoveConnection(i->OutputPort+ODGUI->GetInfo()->NumInputs);
  647. Fl_DeviceGUI* IDGUI = FindDevice(i->InputID);
  648. IDGUI->RemoveConnection(i->InputPort);
  649. // send the unconnect callback
  650. cb_Unconnect(this,(void*)&(*i));
  651. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  652. // Remove the wire
  653. m_WireVec.erase(i);
  654. Found=true;
  655. break;
  656. }
  657. }
  658. }
  659. redraw();
  660. // Clear the current m_Selection
  661. m_IncompleteWire.Clear();
  662. }
  663. }
  664. ////////////////////////////////////////////////////////////////////////
  665. void Fl_Canvas::ClearConnections(Fl_DeviceGUI* Device)
  666. {
  667. bool removedall=false;
  668. //make sure we don't leave a dangling incomplete wire this will cause errors/seg-faults
  669. if (UserMakingConnection() && Device && ((Device->GetID() == m_IncompleteWire.OutputID) ||
  670. (Device->GetID() == m_IncompleteWire.InputID)))
  671. {
  672. ClearIncompleteWire();
  673. }
  674. while (!removedall)
  675. {
  676. removedall=true;
  677. for (vector<CanvasWire>::iterator i=m_WireVec.begin();
  678. i!=m_WireVec.end(); i++)
  679. {
  680. if (i->OutputID==Device->GetID() ||
  681. i->InputID==Device->GetID())
  682. {
  683. // Turn off both ports
  684. FindDevice(i->OutputID)->RemoveConnection(i->OutputPort+FindDevice(i->OutputID)->GetInfo()->NumInputs);
  685. FindDevice(i->InputID)->RemoveConnection(i->InputPort);
  686. // send the unconnect callback
  687. cb_Unconnect(this,(void*)&(*i));
  688. m_Graph.RemoveConnection(i->OutputID,i->InputID);
  689. m_WireVec.erase(i);
  690. removedall=false;
  691. break;
  692. }
  693. }
  694. }
  695. }
  696. ////////////////////////////////////////////////////////////////////////
  697. void Fl_Canvas::RemoveDevice(Fl_DeviceGUI* Device)
  698. {
  699. ClearConnections(Device);
  700. remove(Device);
  701. redraw();
  702. }
  703. ////////////////////////////////////////////////////////////////////////
  704. void Fl_Canvas::Clear()
  705. {
  706. m_Graph.Clear();
  707. int kids=children();
  708. for(int n=0; n<kids; n++)
  709. {
  710. remove(child(0));
  711. }
  712. m_WireVec.clear();
  713. redraw();
  714. }
  715. ////////////////////////////////////////////////////////////////////////
  716. void Fl_Canvas::Rename(Fl_DeviceGUI* Device)
  717. {
  718. if (cb_Rename) cb_Rename(this,Device);
  719. }
  720. ////////////////////////////////////////////////////////////////////////
  721. Fl_DeviceGUI *Fl_Canvas::FindDevice(int ID)
  722. {
  723. for(int n=0; n<children(); n++)
  724. {
  725. if(((Fl_DeviceGUI*)child(n))->GetID()==ID)
  726. {
  727. return (Fl_DeviceGUI*)child(n);
  728. }
  729. }
  730. return NULL;
  731. }
  732. /////////////////////////////////////////////////////////////////////////
  733. void Fl_Canvas::ToTop(Fl_DeviceGUI *o)
  734. {
  735. if (children()<2) return; //no need to do anything
  736. // cast away the const :P
  737. Fl_Widget** a=(Fl_Widget**)array();
  738. int p=find(o);
  739. if (p<0)
  740. {
  741. cerr<<"ToTop couldn't find widget!"<<endl;
  742. return;
  743. }
  744. Fl_Widget *temp=a[0];
  745. Fl_Widget *last=a[0];
  746. for(int n=1; n<children(); n++)
  747. {
  748. if (n>p) // after the widget in the list
  749. {
  750. // move the widgets up
  751. a[n-1]=a[n];
  752. }
  753. }
  754. a[children()-1]=o; // put the raised one at the top of the list
  755. }
  756. void Fl_Canvas::ToBot(Fl_DeviceGUI *o)
  757. {
  758. if (children()<2) return; //no need to do anything
  759. // cast away the const :P
  760. Fl_Widget** a=(Fl_Widget**)array();
  761. int p=find(o);
  762. if (p<0)
  763. {
  764. cerr<<"ToBot couldn't find widget!"<<endl;
  765. return;
  766. }
  767. Fl_Widget *temp=a[0];
  768. Fl_Widget *last=a[0];
  769. for(int n=1; n<children(); n++)
  770. {
  771. if (n<=p) // before the widget in the list
  772. {
  773. // move the widgets down
  774. temp=a[n];
  775. a[n]=last;
  776. last=temp;
  777. }
  778. }
  779. a[0]=o; // put the lowered one at the top of the list
  780. }
  781. /////////////////////////////////////////////////////////////////////////
  782. void Fl_Canvas::StreamWiresIn(istream &s, bool merge, bool paste)
  783. {
  784. int NumWires;
  785. s>>NumWires;
  786. // my bad, didn't version this stream - remove one day...
  787. if (paste || NumWires==-1)
  788. {
  789. int version;
  790. if (!paste)
  791. {
  792. s>>version;
  793. s>>NumWires;
  794. }
  795. for(int n=0; n<NumWires; n++)
  796. {
  797. CanvasWire NewWire;
  798. int dummy;
  799. s>>NewWire.OutputID;
  800. s>>dummy;
  801. s>>NewWire.OutputPort;
  802. s>>NewWire.OutputTerminal;
  803. s>>NewWire.InputID;
  804. s>>dummy;
  805. s>>NewWire.InputPort;
  806. s>>NewWire.InputTerminal;
  807. if (paste || merge)
  808. {
  809. std::map<int, int>::iterator inputID = MapNewDeviceIds.find( NewWire.InputID);
  810. std::map<int, int>::iterator outputID = MapNewDeviceIds.find(NewWire.OutputID);
  811. if ((inputID != MapNewDeviceIds.end()) && (outputID != MapNewDeviceIds.end()))
  812. {
  813. NewWire.InputID = inputID->second;
  814. NewWire.OutputID = outputID->second;
  815. }
  816. }
  817. // if we can turn on both ports
  818. if (FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
  819. FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
  820. FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
  821. {
  822. m_WireVec.push_back(NewWire);
  823. // Notify connection by callback
  824. cb_Connection(this,(void*)&NewWire);
  825. m_Graph.AddConnection(NewWire.OutputID,NewWire.OutputTerminal,NewWire.InputID,NewWire.InputTerminal);
  826. }
  827. }
  828. }
  829. else
  830. {
  831. for(int n=0; n<NumWires; n++)
  832. {
  833. CanvasWire NewWire;
  834. int dummy;
  835. s>>NewWire.OutputID;
  836. s>>dummy;
  837. s>>NewWire.OutputPort;
  838. s>>NewWire.InputID;
  839. s>>dummy;
  840. s>>NewWire.InputPort;
  841. if (paste || merge)
  842. {
  843. std::map<int, int>::iterator inputID = MapNewDeviceIds.find( NewWire.InputID);
  844. std::map<int, int>::iterator outputID = MapNewDeviceIds.find(NewWire.OutputID);
  845. if ((inputID != MapNewDeviceIds.end()) && (outputID != MapNewDeviceIds.end()))
  846. {
  847. NewWire.InputID = inputID->second;
  848. NewWire.OutputID = outputID->second;
  849. }
  850. }
  851. // if we can turn on both ports
  852. if (FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
  853. FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
  854. FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
  855. {
  856. m_WireVec.push_back(NewWire);
  857. // Notify connection by callback
  858. cb_Connection(this,(void*)&NewWire);
  859. m_Graph.AddConnection(NewWire.OutputID,false,NewWire.InputID,false);
  860. }
  861. }
  862. }
  863. }
  864. istream &operator>>(istream &s, Fl_Canvas &o)
  865. {
  866. o.StreamWiresIn(s, false, false);
  867. return s;
  868. }
  869. ////////////////////////////////////////////////////////////////////////
  870. ostream &operator<<(ostream &s, Fl_Canvas &o)
  871. {
  872. int version=0;
  873. s<<-1<<" "<<version<<" ";
  874. s<<o.m_WireVec.size()<<endl;
  875. for(vector<CanvasWire>::iterator i=o.m_WireVec.begin();
  876. i!=o.m_WireVec.end(); i++)
  877. {
  878. s<<i->OutputID<<" ";
  879. s<<0<<" ";
  880. s<<i->OutputPort<<" ";
  881. s<<i->OutputTerminal<<" ";
  882. s<<i->InputID<<" ";
  883. s<<0<<" ";
  884. s<<i->InputPort<<" ";
  885. s<<i->InputTerminal<<endl;
  886. }
  887. return s;
  888. }