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.

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