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.

1034 lines
28KB

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