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.

1074 lines
29KB

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