Browse Source

Add Copy, Paste, and Merge functionality to the Canvas.

This adds the ability to select multiple devices either by a ctrl-mouse drag
or by ctrl-click on individual devices title to do finer selection
and deselection, and then ctrl-right-click on the canvas to produce a menu
with the options to cut/copy/paste/delete selection or to merge an existing
patch entirely into the patch. Pasting or merging will auto-select new devices
so any old devices will lose selection.

To remove selection simply click anywhere on canvas.

Current problems -

Multiple Select drag is buggy and may select items not in the selection area.

Multiple OSS plugins are buggy so merging/pasting an OSS device can cause crashing.
master
aj_genius 21 years ago
parent
commit
0d1d13c3ed
12 changed files with 945 additions and 107 deletions
  1. +421
    -33
      GUI/Widgets/Fl_Canvas.C
  2. +123
    -0
      GUI/Widgets/Fl_Canvas.h
  3. +1
    -0
      GUI/Widgets/Fl_DeviceGUI.C
  4. +4
    -0
      GUI/Widgets/Fl_DeviceGUI.h
  5. +8
    -1
      GUI/Widgets/Fl_DragBar.H
  6. +30
    -1
      GUI/Widgets/Fl_DragBar.cxx
  7. +32
    -1
      GUI/Widgets/Fl_DragBar.fld
  8. +2
    -2
      SpiralSound/Plugins/PoshSamplerPlugin/PoshSamplerPlugin.C
  9. +1
    -1
      SpiralSound/Plugins/PoshSamplerPlugin/PoshSamplerPlugin.h
  10. +1
    -1
      SpiralSound/Plugins/SpiralPlugin.h
  11. +284
    -57
      SpiralSynthModular.C
  12. +38
    -10
      SpiralSynthModular.h

+ 421
- 33
GUI/Widgets/Fl_Canvas.C View File

@@ -17,6 +17,7 @@
*/

#include "FL/fl_draw.H"
#include <FL/Fl_Scroll.H>
#include "Fl_Canvas.h"
#include "Fl_DeviceGUI.h"
#include <iostream>
@@ -34,7 +35,8 @@ cb_Connection(NULL),
cb_Unconnect(NULL),
cb_AddDevice(NULL),
m_ToolMenu(false),
m_UpdateTimer(0)
m_UpdateTimer(0),
m_Selecting(false)
{
m_IncompleteWire.OutputID=-1;
m_IncompleteWire.OutputPort=-1;
@@ -45,12 +47,15 @@ m_UpdateTimer(0)
m_BG=NULL;
m_BGData=NULL;
m_Menu=NULL;
m_CanPaste=false;
}

////////////////////////////////////////////////////////////////////////

Fl_Canvas::~Fl_Canvas()
{
if (m_Menu) delete m_Menu;
}

////////////////////////////////////////////////////////////////////////
@@ -58,7 +63,7 @@ Fl_Canvas::~Fl_Canvas()
void Fl_Canvas::draw()
{
Fl_Widget*const* a = array();
if (damage() & ~FL_DAMAGE_CHILD) // redraw the entire thing:
{
if (m_BG)
@@ -96,6 +101,14 @@ void Fl_Canvas::draw()
{
draw_child(o);
draw_outside_label(o);

std::vector<int>::iterator sel = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), ((Fl_DeviceGUI*)&o)->GetID() );

if (sel != m_Selection.m_DeviceIds.end())
{
fl_color(FL_YELLOW);
fl_rect(o.x(), o.y(), o.w(), o.h());
}
}
}
@@ -110,6 +123,14 @@ void Fl_Canvas::draw()
{
draw_child(o);
draw_outside_label(o);

std::vector<int>::iterator sel = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), ((Fl_DeviceGUI*)&o)->GetID() );

if (sel != m_Selection.m_DeviceIds.end())
{
fl_color(FL_YELLOW);
fl_rect(o.x(), o.y(), o.w(), o.h());
}
}
}
}
@@ -161,6 +182,7 @@ void Fl_Canvas::draw()
Pos+=1;
}
}
DrawSelection();
}

////////////////////////////////////////////////////////////////////////
@@ -179,6 +201,264 @@ void Fl_Canvas::Poll()

////////////////////////////////////////////////////////////////////////

void Fl_Canvas::DrawSelection()
{
if (m_Selecting)
{
int X, Y, W, H;
fl_color(FL_YELLOW);

X = min(m_StartSelectX, m_EndSelectX);
Y = min(m_StartSelectY, m_EndSelectY);
W = max(m_StartSelectX, m_EndSelectX) - X;
H = max(m_StartSelectY, m_EndSelectY) - Y;

fl_rect(X-1, Y-1, W+2, H+2);
}
}

bool widget_intersects_rectangle (Fl_Widget* o, int X, int Y, int W, int H)
{
int src1_x1=o->x(), src1_y1=o->y();
int src1_x2=o->x()+o->w(), src1_y2=o->y()+o->h();

int src2_x1=X, src2_y1=Y;
int src2_x2=X+W, src2_y2=Y+H;

int width=0, height=0;
if (X < o->x())
{
src1_x1=X;
src1_y1=Y;
src1_x2=X+W;
src1_y2=Y+H;

src2_x1=o->x();
src2_y1=o->y();
src2_x2=o->w();
src2_y2=o->h();
}

if (src2_x1 < src1_x2)
{
if (src1_x2 < src2_x2)
width = src1_x2 - src2_x1;
else
width = src2_x2 - src2_x1;

if (width == 0)
return false;
if (src2_y1 < src1_y1)
{
int tmp;

tmp = src2_x1;
src2_x1=src1_x1;
src1_x1=tmp;
tmp = src2_y1;
src2_y1=src1_y1;
src1_y1=tmp;

tmp = src2_x2;
src2_x2=src1_x2;
src1_x2=tmp;
tmp = src2_y2;
src2_y2=src1_y2;
src1_y2=tmp;

}

if (src2_y1 < src1_y2)
{
if (src1_y2 < src2_y2)
height = src1_y2 - src2_y1;
else
height = src2_y2 - src2_y1;

if ((height == 0))
return false;
else
return true;
}
}

return false;
}

void Fl_Canvas::CalculateSelection()
{
Fl_Widget*const* a = array();
int X, Y, W, H;
X = min(m_StartSelectX, m_EndSelectX);
Y = min(m_StartSelectY, m_EndSelectY);
W = max(m_StartSelectX, m_EndSelectX) - X;
H = max(m_StartSelectY, m_EndSelectY) - Y;

m_HaveSelection = false;
m_Selection.Clear();
for (int i=0; i<children(); i++)
{
Fl_Widget& o = **a++;
if (widget_intersects_rectangle(&o, X, Y, W, H))
{
m_HaveSelection = true;
m_Selection.m_DeviceIds.push_back(((Fl_DeviceGUI*)&o)->GetID());
((Fl_DeviceGUI*)&o)->SetOnDragCallback(cb_OnDrag_s, this);
}
}
}

inline void Fl_Canvas::cb_OnDrag_i(Fl_Widget* widget, int xoffset,int yoffset)
{
if ((widget) && (widget->parent()))
{
int moved_device_id = ((Fl_DeviceGUI*)(widget->parent()))->GetID();

if (m_HaveSelection)
{
if (m_Selection.m_DeviceIds.size() <= 0)
m_HaveSelection = false;

for (unsigned int i=0; i<m_Selection.m_DeviceIds.size(); i++)
{
int ID = Selection().m_DeviceIds[i];
Fl_Widget *o = FindDevice(ID);

if ((o) && (m_Selection.m_DeviceIds[i] != moved_device_id))
{
o->position(o->x() + xoffset, o->y() + yoffset);
}
}
}
}
return;
}

inline void Fl_Canvas::cb_DeleteDeviceGroup_i()
{
if (! m_HaveSelection)
return;

//show some warning here

for (unsigned int i=0; i<m_Selection.m_DeviceIds.size(); i++)
{
int ID = m_Selection.m_DeviceIds[i];
Fl_DeviceGUI* o = FindDevice(ID);
if (o)
{
Fl_DeviceGUI::Kill(o);
}

}

m_HaveSelection=false;
m_Selection.Clear();
redraw();
}


void Fl_Canvas::PopupEditMenu(Fl_Group *group)
{
if (! (m_Menu))
{
m_Menu = new Fl_Menu_Button(Fl::event_x(),Fl::event_x(),4,4,"Edit");
m_Menu->type(Fl_Menu_Button::POPUP123);
m_Menu->textsize(10);

m_Menu->add("Cut Currently Selected Devices", 0, (Fl_Callback*)cb_CutDeviceGroup,user_data());
m_Menu->add("Copy Currently Selected Devices", 0, (Fl_Callback*)cb_CopyDeviceGroup,user_data());
m_Menu->add("Paste Previously Copied Devices", 0, (Fl_Callback*)cb_PasteDeviceGroup,user_data(), FL_MENU_DIVIDER);
m_Menu->add("Merge Existing Patch", 0, (Fl_Callback*)cb_MergePatch,user_data(), FL_MENU_DIVIDER);
m_Menu->add("Delete Currently Selected Devices", 0, (Fl_Callback*)cb_DeleteDeviceGroup, this);
}

m_Menu->value(0);
group->add(m_Menu);
Fl_Menu_Item *cut=(Fl_Menu_Item*)&(m_Menu->menu()[0]);
Fl_Menu_Item *copy=(Fl_Menu_Item*)&(m_Menu->menu()[1]);
Fl_Menu_Item *paste=(Fl_Menu_Item*)&(m_Menu->menu()[2]);
Fl_Menu_Item *merge=(Fl_Menu_Item*)&(m_Menu->menu()[3]);
Fl_Menu_Item *deleteitems=(Fl_Menu_Item*)&(m_Menu->menu()[4]);
if ((cb_CopyDeviceGroup) && (m_HaveSelection))
copy->activate();
else
copy->deactivate();
if ((cb_CutDeviceGroup) && (m_HaveSelection))
cut->activate();
else
cut->deactivate();

if ((cb_PasteDeviceGroup) && (m_CanPaste))
paste->activate();
else
paste->deactivate();

if (m_HaveSelection)
deleteitems->activate();
else
deleteitems->deactivate();

m_Menu->popup();
group->remove(m_Menu);
}

void Fl_Canvas::StreamSelectionWiresIn(istream &s, std::map<int,int> NewDeviceIds, bool merge, bool paste)
{
MapNewDeviceIds = NewDeviceIds;
StreamWiresIn(s, merge, paste);
}
void Fl_Canvas::StreamSelectionWiresOut(ostream &s)
{
int total_wires = 0, curpos=0;

curpos = s.tellp();
s<<-1<<endl;

if (m_WireVec.size()>0)
for(vector<CanvasWire>::iterator i=m_WireVec.begin();
i!=m_WireVec.end(); i++)
{
std::vector<int>::iterator output = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), i->OutputID );
std::vector<int>::iterator input = std::find( m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), i->InputID );
if ((input != m_Selection.m_DeviceIds.end()) && (output != m_Selection.m_DeviceIds.end()))
{
s<<i->OutputID<<" ";
s<<0<<" ";
s<<i->OutputPort<<" ";
s<<i->OutputTerminal<<" ";
s<<i->InputID<<" ";
s<<0<<" ";
s<<i->InputPort<<" ";
s<<i->InputTerminal<<endl;
total_wires += 1;
}
}

if (total_wires >= 1)
{
s.seekp(curpos, ios::beg);
s<<total_wires<<endl;
s.seekp(0, ios::end);
}
}

////////////////////////////////////////////////////////////////////////

void Fl_Canvas::DrawWires()
{
for(vector<CanvasWire>::iterator i=m_WireVec.begin();
@@ -304,7 +584,7 @@ void Fl_Canvas::ClearIncompleteWire()
int Fl_Canvas::handle(int event)
{
if (Fl_Group::handle(event)) return 1;
if (event==FL_PUSH)
{
ClearIncompleteWire();
@@ -313,12 +593,84 @@ int Fl_Canvas::handle(int event)
m_DragY=Fl::event_y();
}
if (Fl::event_button()==1 && event==FL_DRAG)
if (Fl::event_button()==1)
{
position(x()+(Fl::event_x()-m_DragX),y()+(Fl::event_y()-m_DragY));
m_DragX=Fl::event_x();
m_DragY=Fl::event_y();
redraw();
if (event==FL_PUSH)
{
if (m_HaveSelection)
{
m_Selection.Clear();
m_HaveSelection = false;
}

if ((Fl::event_state() & FL_CTRL) != 0)
{
m_Selecting = true;
m_StartSelectX=Fl::event_x();
m_StartSelectY=Fl::event_y();
m_EndSelectX=Fl::event_x();
m_EndSelectY=Fl::event_y();
}

ClearIncompleteWire();
redraw();
m_DragX=Fl::event_x();
m_DragY=Fl::event_y();
}

if (event==FL_DRAG)
{
if (m_Selecting)
{
m_EndSelectX=Fl::event_x();
m_EndSelectY=Fl::event_y();

int newx=0, newy=0, xp=((Fl_Scroll *)parent())->xposition(), yp=((Fl_Scroll *)parent())->yposition();

if ((m_EndSelectX < m_StartSelectX) && ((m_EndSelectX - x() - xp) <= 15))
newx=10;
if ((m_EndSelectY < m_StartSelectY) && ((m_EndSelectY - y() - yp) <= 15))
newy=10;

if ((m_EndSelectX > m_StartSelectX) && ((((Fl_Scroll *)parent())->x() + ((Fl_Scroll *)parent())->w() - m_EndSelectX - 15) <= 15))
newx=-10;
if ((m_EndSelectY > m_StartSelectY) && ((((Fl_Scroll *)parent())->y() + ((Fl_Scroll *)parent())->h() - m_EndSelectY - 15) <= 5))
newy=-10;

if ((newx!=0) || (newy!=0)) {
position(x()+newx,y()+newy);

m_StartSelectX += newx;
m_StartSelectY += newy;
}
}
else
{
position(x()+(Fl::event_x()-m_DragX),y()+(Fl::event_y()-m_DragY));
}

m_DragX=Fl::event_x();
m_DragY=Fl::event_y();
redraw();
}

if (event==FL_RELEASE)
{
if (m_Selecting)
{
m_Selecting = false;

if ((m_EndSelectX != m_StartSelectX) && (m_EndSelectY != m_StartSelectY))
CalculateSelection();

redraw();
}

}
}
if (Fl::event_button()==2)
@@ -348,6 +700,11 @@ int Fl_Canvas::handle(int event)
}
}

if ((Fl::event_button()==3) && (event==FL_PUSH) && ((Fl::event_state() & FL_CTRL) != 0))
{
PopupEditMenu(this);
}
return 1;
}

@@ -448,7 +805,7 @@ void Fl_Canvas::PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value
redraw();
// Clear the current selection
// Clear the current m_Selection
m_IncompleteWire.Clear();
}
}
@@ -603,24 +960,29 @@ void Fl_Canvas::ToBot(Fl_DeviceGUI *o)
}

/////////////////////////////////////////////////////////////////////////
istream &operator>>(istream &s, Fl_Canvas &o)
void Fl_Canvas::StreamWiresIn(istream &s, bool merge, bool paste)
{
int NumWires;

s>>NumWires;
// my bad, didn't version this stream - remove one day...
if (NumWires==-1)
if (paste || NumWires==-1)
{
int version;
s>>version;
s>>NumWires;

if (!paste)
{
s>>version;
s>>NumWires;
}
for(int n=0; n<NumWires; n++)
{
CanvasWire NewWire;
int dummy;
s>>NewWire.OutputID;
s>>dummy;
s>>NewWire.OutputPort;
@@ -629,21 +991,30 @@ istream &operator>>(istream &s, Fl_Canvas &o)
s>>dummy;
s>>NewWire.InputPort;
s>>NewWire.InputTerminal;
// if we can turn on both ports
if (o.FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
o.FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
o.FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))

if (paste || merge)
{
o.m_WireVec.push_back(NewWire);
std::map<int, int>::iterator inputID = MapNewDeviceIds.find( NewWire.InputID);
std::map<int, int>::iterator outputID = MapNewDeviceIds.find(NewWire.OutputID);

// Notify connection by callback
o.cb_Connection(&o,(void*)&NewWire);
o.m_Graph.AddConnection(NewWire.OutputID,NewWire.OutputTerminal,NewWire.InputID,NewWire.InputTerminal);
if ((inputID != MapNewDeviceIds.end()) && (outputID != MapNewDeviceIds.end()))
{
NewWire.InputID = inputID->second;
NewWire.OutputID = outputID->second;
}
}
// if we can turn on both ports
if (FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
{
m_WireVec.push_back(NewWire);
// Notify connection by callback
cb_Connection(this,(void*)&NewWire);
m_Graph.AddConnection(NewWire.OutputID,NewWire.OutputTerminal,NewWire.InputID,NewWire.InputTerminal);
}
}
}
}
else
{
for(int n=0; n<NumWires; n++)
@@ -658,19 +1029,36 @@ istream &operator>>(istream &s, Fl_Canvas &o)
s>>dummy;
s>>NewWire.InputPort;
if (paste || merge)
{
std::map<int, int>::iterator inputID = MapNewDeviceIds.find( NewWire.InputID);
std::map<int, int>::iterator outputID = MapNewDeviceIds.find(NewWire.OutputID);

if ((inputID != MapNewDeviceIds.end()) && (outputID != MapNewDeviceIds.end()))
{
NewWire.InputID = inputID->second;
NewWire.OutputID = outputID->second;
}
}

// if we can turn on both ports
if (o.FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
o.FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
o.FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
if (FindDevice(NewWire.OutputID)->AddConnection(NewWire.OutputPort+
FindDevice(NewWire.OutputID)->GetInfo()->NumInputs) &&
FindDevice(NewWire.InputID)->AddConnection(NewWire.InputPort))
{
o.m_WireVec.push_back(NewWire);
m_WireVec.push_back(NewWire);

// Notify connection by callback
o.cb_Connection(&o,(void*)&NewWire);
o.m_Graph.AddConnection(NewWire.OutputID,false,NewWire.InputID,false);
cb_Connection(this,(void*)&NewWire);
m_Graph.AddConnection(NewWire.OutputID,false,NewWire.InputID,false);
}
}
}
}

istream &operator>>(istream &s, Fl_Canvas &o)
{
o.StreamWiresIn(s, false, false);
return s;
}



+ 123
- 0
GUI/Widgets/Fl_Canvas.h View File

@@ -19,9 +19,11 @@
#include <FL/Fl_Group.h>
#include <FL/Fl_Output.h>
#include <FL/Fl_Image.h>
#include <FL/Fl_Menu_Button.h>
#include <vector>
#include <string>
#include "../../GraphSort.h"
#include "Fl_DeviceGUI.h"

#ifndef CANVAS_WIDGET
#define CANVAS_WIDGET
@@ -55,14 +57,30 @@ public:
bool DelMe;
};

class CanvasGroup
{
public:
CanvasGroup() { Clear(); }
void Clear()
{
m_DeviceIds.clear();
}
vector<int> m_DeviceIds;
};

class Fl_Canvas : public Fl_Group
{
public:
Fl_Canvas(int x, int y, int w, int h, char *name);
~Fl_Canvas();
Fl_Menu_Button *m_Menu;
virtual void draw();
virtual int handle(int event);
int globalhandle(int event);

void PortClicked(Fl_DeviceGUI* Device, int Type, int Port, bool Value);
void Rename(Fl_DeviceGUI* Device);

@@ -71,6 +89,12 @@ public:
void SetAddDeviceCallback(Fl_Callback* s) { cb_AddDevice=s; }
void SetRenameCallback(Fl_Callback* s) { cb_Rename=s; }
void SetCutDeviceGroupCallback(Fl_Callback* s) { cb_CutDeviceGroup=s; }
void SetCopyDeviceGroupCallback(Fl_Callback* s) { cb_CopyDeviceGroup=s; }
void SetPasteDeviceGroupCallback(Fl_Callback* s) { cb_PasteDeviceGroup=s; }

void SetMergePatchCallback(Fl_Callback* s) { cb_MergePatch=s; }

void ClearConnections(Fl_DeviceGUI* Device);
void RemoveDevice(Fl_DeviceGUI* Device);
void Clear();
@@ -83,7 +107,48 @@ public:
void ToTop(Fl_DeviceGUI *o);
void ToBot(Fl_DeviceGUI *o);

void StreamSelectionWiresIn(istream &s, map<int,int> NewDeviceIds, bool merge, bool paste);
void StreamSelectionWiresOut(ostream &s);

void StreamWiresIn(istream &s, bool merge, bool paste);

static void AppendSelection(int DeviceId, Fl_Canvas *data)
{
Fl_DeviceGUI *o = data->FindDevice(DeviceId);
if (o)
{
data->m_HaveSelection = true;
data->m_Selection.m_DeviceIds.push_back(DeviceId);
o->SetOnDragCallback(Fl_Canvas::cb_OnDrag_s, data);
data->redraw();
}
}


static void ClearSelection(Fl_Canvas *data)
{
data->m_HaveSelection=false;
data->m_Selection.Clear();
data->redraw();
}

static void EnablePaste(Fl_Canvas *data)
{
data->m_CanPaste=true;
}
bool HaveSelection() {return m_HaveSelection; }
CanvasGroup Selection() { return m_Selection; }

static void SetDeviceCallbacks(Fl_DeviceGUI *device, Fl_Canvas *data)
{
device->SetOnDragCallback(Fl_Canvas::cb_OnDrag_s, data);
device->SetOnClickCallback(Fl_Canvas::cb_OnDragClick_s, data);
}

private:
void DrawSelection();
void CalculateSelection();

void DrawWires();
void ClearIncompleteWire();
@@ -99,6 +164,13 @@ private:
void (*cb_AddDevice)(Fl_Widget*, void*);
void (*cb_Rename)(Fl_Widget*, void*);
void (*cb_CutDeviceGroup)(Fl_Widget*, void*);
void (*cb_CopyDeviceGroup)(Fl_Widget*, void*);
void (*cb_PasteDeviceGroup)(Fl_Widget*, void*);
void (*cb_MergePatch)(Fl_Widget*, void*);

map<int,int> MapNewDeviceIds;
vector<CanvasWire> m_WireVec;
CanvasWire m_IncompleteWire;
@@ -109,9 +181,60 @@ private:
GraphSort m_Graph;
int m_UpdateTimer;
int m_DragX,m_DragY;
bool m_HaveSelection, m_Selecting;
int m_StartSelectX,m_StartSelectY;
int m_EndSelectX,m_EndSelectY;

CanvasGroup m_Selection;
bool m_CanPaste;

friend istream &operator>>(istream &s, Fl_Canvas &o);
friend ostream &operator<<(ostream &s, Fl_Canvas &o);

void PopupEditMenu(Fl_Group *group);

///Inline Callbacks///
inline void cb_OnDrag_i(Fl_Widget* widget, int x,int y);
inline void cb_OnDragClick_i(Fl_Widget* widget, int button,int shift_state)
{
if ((button==3) && ((shift_state & FL_CTRL) != 0))
{
PopupEditMenu(widget->parent());
}
if ((widget) && (button==1) && ((shift_state & FL_CTRL) != 0))
{
int ID = ((Fl_DeviceGUI*)(widget->parent()))->GetID();
std::vector<int>::iterator device_iter = std::find(m_Selection.m_DeviceIds.begin(), m_Selection.m_DeviceIds.end(), ID);

if (m_HaveSelection)
{
if (device_iter != m_Selection.m_DeviceIds.end())
m_Selection.m_DeviceIds.erase(device_iter);
else
m_Selection.m_DeviceIds.push_back(ID);
}
else
{
m_Selection.Clear();
m_HaveSelection = true;
m_Selection.m_DeviceIds.push_back(ID);
}
redraw();
}
}

inline void cb_DeleteDeviceGroup_i();

///Static Callbacks///
static void cb_OnDrag_s(Fl_Widget* widget, int x,int y, void* data) { ((Fl_Canvas *)data)->cb_OnDrag_i(widget, x, y); }
static void cb_OnDragClick_s(Fl_Widget* widget, int button,int shift_state, void* data) { ((Fl_Canvas *)data)->cb_OnDragClick_i(widget, button, shift_state); }

static void cb_DeleteDeviceGroup(Fl_Widget* widget, void* data) { ((Fl_Canvas *)data)->cb_DeleteDeviceGroup_i(); }

};

istream &operator>>(istream &s, Fl_Canvas &o);


+ 1
- 0
GUI/Widgets/Fl_DeviceGUI.C View File

@@ -141,6 +141,7 @@ int Fl_DeviceGUI::handle (int event) {
Minimise();
if (m_IconButton) m_IconButton->show();
}

return 1;
}



+ 4
- 0
GUI/Widgets/Fl_DeviceGUI.h View File

@@ -104,6 +104,10 @@ class Fl_DeviceGUI : public Fl_Group {
int GetPortType (int n) { return m_Info.PortTypes[n]; }
// do we belong to a plugin that is an output?
bool IsTerminal() { return m_IsTerminal; }
void SetOnDragCallback(void (*cb)(Fl_Widget*, int x,int y, void*), void* data) { m_DragBar->cb_OnDrag = cb; m_DragBar->cb_OnDrag_Data = data; }
void SetOnClickCallback(void (*cb)(Fl_Widget*, int button, int shift_state, void*), void* data) { m_DragBar->cb_OnClick = cb; m_DragBar->cb_OnClick_Data = data; }
static void Kill(Fl_DeviceGUI *device) { if (device) device->m_DelMe = true; }
protected:
DeviceGUIInfo m_Info;
Fl_DragBar* m_DragBar;


+ 8
- 1
GUI/Widgets/Fl_DragBar.H View File

@@ -11,9 +11,16 @@ class Fl_DragBar : public Fl_Widget {
int old_rx,old_ry;
int _type;
public:
enum DragType {WINDRAG=0,NICEWINDRAG,FLDRAG,NICEFLDRAG};
Fl_DragBar(int x,int y,int w,int h,const char *l=0);
~Fl_DragBar();

enum DragType {WINDRAG=0,NICEWINDRAG,FLDRAG,NICEFLDRAG};

void (*cb_OnClick)(Fl_Widget*, int button, int shift_state, void*);
void *cb_OnClick_Data;

void (*cb_OnDrag)(Fl_Widget*, int xoffset,int yoffset, void*);
void *cb_OnDrag_Data;
private:
void draw();
int handle(int event);


+ 30
- 1
GUI/Widgets/Fl_DragBar.cxx View File

@@ -3,7 +3,11 @@
#include "Fl_DragBar.H"
#include <string.h>

Fl_DragBar::Fl_DragBar(int x,int y,int w,int h,const char *l): Fl_Widget(x,y,w,h,l) {
Fl_DragBar::Fl_DragBar(int x,int y,int w,int h,const char *l):
Fl_Widget(x,y,w,h,l),
cb_OnDrag(NULL),
cb_OnDrag_Data(NULL)
{
_type = Fl_DragBar::NICEFLDRAG;
}

@@ -119,6 +123,12 @@ int mx,my;
{
fl_cursor(FL_CURSOR_DEFAULT);
do_callback();

if ((Fl::event_is_click()) && (cb_OnClick))
{
cb_OnClick(this, Fl::event_button(), Fl::event_state(), cb_OnClick_Data);
}

return 1;
}
case FL_DRAG:
@@ -129,11 +139,30 @@ int mx,my;
yy = ry - old_ry;
if (_type < (int)Fl_DragBar::FLDRAG)
{
if (cb_OnDrag) {
int xoffset, yoffset;
xoffset = (rx - window()->x()) - old_rx;
yoffset = (ry - window()->y()) - old_ry;
cb_OnDrag(this, xoffset, yoffset, cb_OnDrag_Data);
}

window()->position(xx,yy);
}
else
{
if (cb_OnDrag) {
int xoffset, yoffset;
xoffset = (rx - parent()->x()) - old_rx;
yoffset = (ry - parent()->y()) - old_ry;
cb_OnDrag(this, xoffset, yoffset, cb_OnDrag_Data);
}

parent()->position(xx,yy);

if (parent()->parent())
parent()->parent()->redraw();
else


+ 32
- 1
GUI/Widgets/Fl_DragBar.fld View File

@@ -18,9 +18,16 @@ class Fl_DragBar {open : {public Fl_Widget}
} {
decl {int old_rx,old_ry;} {}
decl {int _type;} {}
decl {void (*cb_OnDrag)(Fl_Widget*, int xoffset,int yoffset, void*);} {public}
decl {void *cb_OnDrag_Data;} {public}
decl {void (*cb_OnClick)(Fl_Widget*, int button, int shift_state, void*);} {public}
decl {void *cb_OnClick_Data;} {public}
decl {enum DragType {WINDRAG=0,NICEWINDRAG,FLDRAG,NICEFLDRAG};} {public
}
Function {Fl_DragBar(int x,int y,int w,int h,const char *l=0): Fl_Widget(x,y,w,h,l)} {open
Function {Fl_DragBar(int x,int y,int w,int h,const char *l=0): Fl_Widget(x,y,w,h,l),
cb_OnDrag(NULL),
cb_OnDrag_Data(NULL)
} {open
} {
code {_type = Fl_DragBar::NICEFLDRAG;} {}
}
@@ -133,6 +140,10 @@ int mx,my;
{
fl_cursor(FL_CURSOR_DEFAULT);
do_callback();
if (((Fl::event_is_click()) && (cb_OnClick))
{
cb_OnClick(this, cb_OnClick_Data);
}
return 1;
}
case FL_DRAG:
@@ -141,13 +152,33 @@ int mx,my;
{
xx = rx - old_rx;
yy = ry - old_ry;
if (_type < (int)Fl_DragBar::FLDRAG)
{
if (cb_OnDrag) {
int xoffset, yoffset;
xoffset = (rx - window()->x()) - old_rx;
yoffset = (ry - window()->y()) - old_ry;
cb_OnDrag(this, xoffset, yoffset, cb_OnDrag_Data);
}

window()->position(xx,yy);
}
else
{
if (cb_OnDrag) {
int xoffset, yoffset;
xoffset = (rx - parent()->x()) - old_rx;
yoffset = (ry - parent()->y()) - old_ry;
cb_OnDrag(this, xoffset, yoffset, cb_OnDrag_Data);
}

parent()->position(xx,yy);

if (parent()->parent())
parent()->parent()->redraw();
else


+ 2
- 2
SpiralSound/Plugins/PoshSamplerPlugin/PoshSamplerPlugin.C View File

@@ -491,14 +491,14 @@ bool PoshSamplerPlugin::SaveExternalFiles(const string &Dir)
return true;
}

void PoshSamplerPlugin::LoadExternalFiles(const string &Dir)
void PoshSamplerPlugin::LoadExternalFiles(const string &Dir, int withID)
{
for (int n=0; n<NUM_SAMPLES; n++)
{
char temp[256];
// Andy's fix for bug 766594
// sprintf (temp, "PoshSampler%d_%d.wav", SpiralPlugin_GetID(), n);
sprintf (temp, "PoshSampler%d_%d.wav", GetID(), n);
sprintf (temp, "PoshSampler%d_%d.wav", ((withID==-1)?GetID():withID), n);
m_SampleDescVec[n]->Pathname = temp;
}



+ 1
- 1
SpiralSound/Plugins/PoshSamplerPlugin/PoshSamplerPlugin.h View File

@@ -59,7 +59,7 @@ public:
virtual void StreamIn(std::istream &s);
virtual bool SaveExternalFiles(const std::string &Dir);
virtual void LoadExternalFiles(const std::string &Dir);
virtual void LoadExternalFiles(const std::string &Dir, int withID=-1);
enum GUICommands{NONE,LOAD,SAVE,SETVOL,SETPITCH,SETLOOP,SETPING,SETNOTE,SETOCT,
SETPLAYPOINTS,SETREC,CUT,COPY,PASTE,CROP,MIX,REV,AMP,SETCURRENT,


+ 1
- 1
SpiralSound/Plugins/SpiralPlugin.h View File

@@ -91,7 +91,7 @@ public:
// stuff here gets saved in filename_files directory
// you must return true if this feature is used.
virtual bool SaveExternalFiles(const std::string &Dir) { return false; }
virtual void LoadExternalFiles(const std::string &Dir) {}
virtual void LoadExternalFiles(const std::string &Dir, int withID=-1) {}

const HostInfo* GetHostInfo() { return m_HostInfo; }
bool GetOutput(unsigned int n, Sample **s);


+ 284
- 57
SpiralSynthModular.C View File

@@ -104,6 +104,7 @@ SynthModular::~SynthModular()
{
ClearUp();
PluginManager::Get()->PackUpAndGoHome();
system("rm -f ___temp.ssmcopytmp");
}

//////////////////////////////////////////////////////////
@@ -371,6 +372,13 @@ SpiralWindowType *SynthModular::CreateWindow()
m_Canvas->SetConnectionCallback((Fl_Callback*)cb_Connection);
m_Canvas->SetUnconnectCallback((Fl_Callback*)cb_Unconnect);
m_Canvas->SetAddDeviceCallback((Fl_Callback*)cb_NewDeviceFromMenu);

m_Canvas->SetCutDeviceGroupCallback((Fl_Callback*)cb_CutDeviceGroup);
m_Canvas->SetCopyDeviceGroupCallback((Fl_Callback*)cb_CopyDeviceGroup);
m_Canvas->SetPasteDeviceGroupCallback((Fl_Callback*)cb_PasteDeviceGroup);

m_Canvas->SetMergePatchCallback((Fl_Callback*)cb_MergePatch);

m_CanvasScroll->add(m_Canvas);

m_SettingsWindow = new SettingsWindow;
@@ -629,6 +637,7 @@ DeviceWin* SynthModular::NewDeviceWin(int n, int x, int y)
Info.YPos = y; //rand()%400;

nlw->m_DeviceGUI = new Fl_DeviceGUI(Info, temp, Pix, nlw->m_Device->IsTerminal());
Fl_Canvas::SetDeviceCallbacks(nlw->m_DeviceGUI, m_Canvas);
m_Canvas->add(nlw->m_DeviceGUI);
m_Canvas->redraw();

@@ -685,6 +694,7 @@ DeviceWin* SynthModular::NewComment(int n, int x=-1, int y=-1)

nlw->m_DeviceGUI = new Fl_CommentGUI(Info, NULL, NULL);

Fl_Canvas::SetDeviceCallbacks(nlw->m_DeviceGUI, m_Canvas);
m_Canvas->add(nlw->m_DeviceGUI);
m_Canvas->redraw();

@@ -755,35 +765,201 @@ void SynthModular::cb_Blocking(void* o, bool mode)

//////////////////////////////////////////////////////////

istream &operator>>(istream &s, SynthModular &o)
inline void SynthModular::cb_CutDeviceGroup_i()
{
o.PauseAudio();
if (! m_Canvas->HaveSelection())
return;

string dummy,dummy2;
int ver;
s>>dummy>>dummy>>dummy>>ver;
//show some warning here

if (ver>FILE_VERSION)
cb_CopyDeviceGroup_i();

for (unsigned int i=0; i<m_Canvas->Selection().m_DeviceIds.size(); i++)
{
SpiralInfo::Alert("Bad file, or more recent version.");
return s;
int ID = m_Canvas->Selection().m_DeviceIds[i];
Fl_DeviceGUI::Kill(m_DeviceWinMap[ID]->m_DeviceGUI);

}
Fl_Canvas::ClearSelection(m_Canvas);
}

//////////////////////////////////////////////////////////

inline void SynthModular::cb_MergePatch_i()
{
char *fn=fl_file_chooser("Merge a patch", "*.ssm", NULL);

if (fn && fn!='\0')
{
ifstream in(fn);

if (in)
{
fstream inf;

inf.open(fn,ios::in);

m_MergeFilePath=fn;

StreamPatchIn(inf, false, true);
m_Canvas->StreamSelectionWiresIn(inf, m_Copied.m_DeviceIds, true, false);
inf.close();
}
}
}

//////////////////////////////////////////////////////////

inline void SynthModular::cb_CopyDeviceGroup_i()
{
if (! m_Canvas->HaveSelection())
return;

m_Copied.devices.open("___temp.ssmcopytmp",ios::out);

if (ver>2)
m_Copied.devicecount = 0;
m_Copied.m_DeviceIds.clear();
if (m_FilePath != "")
{
int MainWinX,MainWinY,MainWinW,MainWinH;
int EditWinX,EditWinY,EditWinW,EditWinH;
m_Copied.devices<<true<<" ";
m_Copied.devices<<m_FilePath<<endl;
}
else
m_Copied.devices<<false<<endl;

s>>MainWinX>>MainWinY>>MainWinW>>MainWinH;
s>>EditWinX>>EditWinY>>EditWinW>>EditWinH;
for (unsigned int i=0; i<m_Canvas->Selection().m_DeviceIds.size(); i++)
{
int ID = m_Canvas->Selection().m_DeviceIds[i];
std::map<int,DeviceWin*>::iterator i = m_DeviceWinMap.find(ID);

m_Copied.m_DeviceIds[ID] = ID;

m_Copied.devicecount += 1;
m_Copied.devices<<"Device ";
m_Copied.devices<<i->first<<" "; // save the id
m_Copied.devices<<"Plugin ";
m_Copied.devices<<i->second->m_PluginID<<endl;
m_Copied.devices<<i->second->m_DeviceGUI->x()<<" ";
m_Copied.devices<<i->second->m_DeviceGUI->y()<<" ";
m_Copied.devices<<i->second->m_DeviceGUI->GetName().size()<<" ";
m_Copied.devices<<i->second->m_DeviceGUI->GetName()<<" ";
if (i->second->m_DeviceGUI->GetPluginWindow())
{
m_Copied.devices<<i->second->m_DeviceGUI->GetPluginWindow()->visible()<<" ";
m_Copied.devices<<i->second->m_DeviceGUI->GetPluginWindow()->x()<<" ";
m_Copied.devices<<i->second->m_DeviceGUI->GetPluginWindow()->y()<<" ";
}
else
{
m_Copied.devices<<0<<" "<<0<<" "<<0;
}
m_Copied.devices<<endl;

//o.m_MainWindow->resize(MainWinX,MainWinY,MainWinW,MainWinH);
//o.m_EditorWindow->resize(EditWinX,EditWinY,EditWinW,EditWinH);
if (i->second->m_PluginID==COMMENT_ID)
{
// save the comment gui
((Fl_CommentGUI*)(i->second->m_DeviceGUI))->StreamOut(m_Copied.devices);
}
else
{
// save the plugin
i->second->m_Device->StreamOut(m_Copied.devices);
}
m_Copied.devices<<endl;
}
m_Canvas->StreamSelectionWiresOut(m_Copied.devices);
m_Copied.devices.close();

int Num, ID, PluginID, x,y,ps,px,py;
s>>dummy>>Num;
Fl_Canvas::EnablePaste(m_Canvas);
};

//////////////////////////////////////////////////////////

inline void SynthModular::cb_PasteDeviceGroup_i()
{
if (m_Copied.devicecount <= 0)
return;

m_Copied.devices.open("___temp.ssmcopytmp",ios::in);

StreamPatchIn(m_Copied.devices, true, false);

m_Canvas->StreamSelectionWiresIn(m_Copied.devices, m_Copied.m_DeviceIds, false, true);

m_Copied.devices.close();
};

//////////////////////////////////////////////////////////

iostream &SynthModular::StreamPatchIn(iostream &s, bool paste, bool merge)
{
//if we are merging as opposed to loading a new patch
//we have no need to pause audio
if (!merge && !paste)
PauseAudio();

//if we are pasting we don't have any of the file version
//or saving information. since its internal we didn't
//need it, but we do have other things we might need to load

bool has_file_path;
string m_FromFilePath;
string dummy,dummy2;
int ver;

if (paste)
{
m_Copied.devices>>has_file_path;

if (has_file_path)
m_Copied.devices>>m_FromFilePath;
}
else
{
s>>dummy>>dummy>>dummy>>ver;

if (ver>FILE_VERSION)
{
SpiralInfo::Alert("Bad file, or more recent version.");
return s;
}
if (ver>2)
{
int MainWinX,MainWinY,MainWinW,MainWinH;
int EditWinX,EditWinY,EditWinW,EditWinH;

s>>MainWinX>>MainWinY>>MainWinW>>MainWinH;
s>>EditWinX>>EditWinY>>EditWinW>>EditWinH;

//o.m_MainWindow->resize(MainWinX,MainWinY,MainWinW,MainWinH);
//o.m_EditorWindow->resize(EditWinX,EditWinY,EditWinW,EditWinH);
}
if (merge)
m_FromFilePath = m_MergeFilePath;
}

//wether pasting or merging we need to clear the current
//selection so we can replace it with the new devices
if (paste || merge)
Fl_Canvas::ClearSelection(m_Canvas);
int Num, ID, PluginID, x,y,ps,px,py;
if (paste)
{
Num = m_Copied.devicecount;
}
else
{
s>>dummy>>Num;
}
for(int n=0; n<Num; n++)
{
#ifdef DEBUG_STREAM
@@ -798,7 +974,7 @@ istream &operator>>(istream &s, SynthModular &o)

string Name;

if (ver>3)
if (paste || ver>3)
{
// load the device name
int size;
@@ -811,75 +987,107 @@ istream &operator>>(istream &s, SynthModular &o)
} else {
Name = "";
}
}
}

#ifdef DEBUG_STREAM
cerr<<dummy<<" "<<ID<<" "<<dummy2<<" "<<PluginID<<" "<<x<<" "<<y<<endl;
#endif

if (ver>1) s>>ps>>px>>py;
// Check we're not duplicating an ID
if (o.m_DeviceWinMap.find(ID)!=o.m_DeviceWinMap.end())
if (paste || ver>1) s>>ps>>px>>py;
//if we are merging a patch or pasting we will change duplicate ID's
if (!paste && !merge)
{
SpiralInfo::Alert("Duplicate device ID found in file - aborting load");
return s;
// Check we're not duplicating an ID
if (m_DeviceWinMap.find(ID)!=m_DeviceWinMap.end())
{
SpiralInfo::Alert("Duplicate device ID found in file - aborting load");
return s;
}
}

if (PluginID==COMMENT_ID)
{
DeviceWin* temp = o.NewComment(PluginID, x, y);
DeviceWin* temp = NewComment(PluginID, x, y);
if (temp)
{
if (paste || merge)
{
m_Copied.m_DeviceIds[ID] = m_NextID++;
ID = m_Copied.m_DeviceIds[ID];
}

temp->m_DeviceGUI->SetID(ID);
o.m_DeviceWinMap[ID]=temp;
((Fl_CommentGUI*)(o.m_DeviceWinMap[ID]->m_DeviceGUI))->StreamIn(s); // load the plugin
if (o.m_NextID<=ID) o.m_NextID=ID+1;
m_DeviceWinMap[ID]=temp;
((Fl_CommentGUI*)(m_DeviceWinMap[ID]->m_DeviceGUI))->StreamIn(s); // load the plugin

if (paste || merge)
Fl_Canvas::AppendSelection(ID, m_Canvas);
else
if (m_NextID<=ID) m_NextID=ID+1;

}
}
else
{
DeviceWin* temp = o.NewDeviceWin(PluginID, x, y);
DeviceWin* temp = NewDeviceWin(PluginID, x, y);
if (temp)
{
int oldID=ID;
if (paste || merge)
{
m_Copied.m_DeviceIds[ID] = m_NextID++;
ID = m_Copied.m_DeviceIds[ID];
}
temp->m_DeviceGUI->SetID(ID);
if (ver>3)
if (paste || ver>3)
{
// set the titlebars
temp->m_DeviceGUI->SetName(Name);
}

temp->m_Device->SetUpdateInfoCallback(ID,o.cb_UpdatePluginInfo);
o.m_DeviceWinMap[ID]=temp;
o.m_DeviceWinMap[ID]->m_Device->StreamIn(s); // load the plugin
temp->m_Device->SetUpdateInfoCallback(ID,cb_UpdatePluginInfo);
m_DeviceWinMap[ID]=temp;
m_DeviceWinMap[ID]->m_Device->StreamIn(s); // load the plugin

// load external files
o.m_DeviceWinMap[ID]->m_Device->LoadExternalFiles(o.m_FilePath+"_files/");
if (paste || merge)
m_DeviceWinMap[ID]->m_Device->LoadExternalFiles(m_FromFilePath+"_files/", oldID);
else
m_DeviceWinMap[ID]->m_Device->LoadExternalFiles(m_FilePath+"_files/");

if (ver>1 && o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow())
if ((paste || ver>1) && m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow())
{
// set the GUI up with the loaded values
// looks messy, but if we do it here, the plugin and it's gui can remain
// totally seperated.
((SpiralPluginGUI*)(o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()))->
UpdateValues(o.m_DeviceWinMap[ID]->m_Device);
((SpiralPluginGUI*)(m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()))->
UpdateValues(m_DeviceWinMap[ID]->m_Device);

// updates the data in the channel buffers, so the values don't
// get overwritten in the next tick. (should maybe be somewhere else)
o.m_DeviceWinMap[ID]->m_Device->GetChannelHandler()->FlushChannels();
m_DeviceWinMap[ID]->m_Device->GetChannelHandler()->FlushChannels();

// position the plugin window in the main window
//o.m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->position(px,py);
//m_DeviceWinMap[ID]->m_DeviceGUI->GetPluginWindow()->position(px,py);

if (ps)
{
o.m_DeviceWinMap[ID]->m_DeviceGUI->Maximise();
m_DeviceWinMap[ID]->m_DeviceGUI->Maximise();
// reposition after maximise
o.m_DeviceWinMap[ID]->m_DeviceGUI->position(x,y);
m_DeviceWinMap[ID]->m_DeviceGUI->position(x,y);
}
else o.m_DeviceWinMap[ID]->m_DeviceGUI->Minimise();
else m_DeviceWinMap[ID]->m_DeviceGUI->Minimise();
if (paste || merge)
Fl_Canvas::AppendSelection(ID, m_Canvas);
}

if (o.m_NextID<=ID) o.m_NextID=ID+1;
if (!paste && !merge)
if (m_NextID<=ID) m_NextID=ID+1;
}
else
{
@@ -891,12 +1099,21 @@ istream &operator>>(istream &s, SynthModular &o)
}
}

s>>*o.m_Canvas;

o.ResumeAudio();
if (!paste && !merge)
{
s>>*m_Canvas;
ResumeAudio();
}
return s;
}

iostream &operator>>(iostream &s, SynthModular &o)
{
return o.StreamPatchIn(s, false, false);
}

//////////////////////////////////////////////////////////

ostream &operator<<(ostream &s, SynthModular &o)
@@ -1013,15 +1230,20 @@ inline void SynthModular::cb_Load_i(Fl_Button* o, void* v)

if (fn && fn!='\0')
{
ifstream inf(fn);
ifstream in(fn);

if (inf)
if (in)
{
fstream inf;

inf.open(fn,ios::in);
m_FilePath=fn;

ClearUp();
inf>>*this;

inf.close();

TITLEBAR=LABEL+" "+fn;
m_TopWindow->label(TITLEBAR.c_str());
}
@@ -1232,18 +1454,23 @@ void SynthModular::cb_UpdatePluginInfo(int ID, void *PInfo)

void SynthModular::LoadPatch(const char *fn)
{
ifstream inf(fn);
ifstream in(fn);

if (inf)
if (in)
{
m_FilePath=fn;
fstream inf;
inf.open(fn);
m_FilePath=fn;

ClearUp();
inf>>*this;
inf>>*this;

TITLEBAR=LABEL+" "+fn;
m_TopWindow->label(TITLEBAR.c_str());
}
inf.close();
TITLEBAR=LABEL+" "+fn;
m_TopWindow->label(TITLEBAR.c_str());
}
}

//////////////////////////////////////////////////////////

+ 38
- 10
SpiralSynthModular.h View File

@@ -32,6 +32,7 @@
#include <FL/Fl_Tabs.H>
#include <sstream>
#include <iostream>
#include <fstream>
#include <map>
#include "GUI/Widgets/Fl_DeviceGUI.h"
#include "GUI/Widgets/Fl_CommentGUI.h"
@@ -66,6 +67,16 @@ public:
virtual void draw() { draw_label(); }
};

class DeviceGroup
{
public:
DeviceGroup() { devicecount = 0; }
int devicecount;
fstream devices;
map<int,int> m_DeviceIds;//old ID, new ID
};

class SynthModular
{
public:
@@ -98,6 +109,8 @@ public:
// only for audio thread
bool IsPaused() { return m_PauseAudio; }


iostream &StreamPatchIn(iostream &s, bool paste, bool merge);
private:

vector<string> BuildPluginList(const string &Path);
@@ -118,7 +131,8 @@ private:
static bool m_CallbackUpdateMode;
static bool m_BlockingOutputPluginIsReady;
string m_FilePath;

string m_MergeFilePath;
// Main GUI stuff
void CreateGUI(int xoff=0, int yoff=0, char *name="");

@@ -146,17 +160,22 @@ private:
bool m_PauseAudio;

inline void cb_NewDevice_i(Fl_Button* o, void* v);
static void cb_NewDevice(Fl_Button* o, void* v);
static void cb_NewDevice(Fl_Button* o, void* v);
inline void cb_NewDeviceFromMenu_i(Fl_Canvas* o, void* v);
static void cb_NewDeviceFromMenu(Fl_Canvas* o, void* v);
inline void cb_NewComment_i(Fl_Button* o, void* v);
static void cb_NewComment(Fl_Button* o, void* v);
static void cb_NewComment(Fl_Button* o, void* v);
inline void cb_Load_i(Fl_Button* o, void* v);
static void cb_Load(Fl_Button* o, void* v);
static void cb_Load(Fl_Button* o, void* v);
inline void cb_Save_i(Fl_Button* o, void* v);
static void cb_Save(Fl_Button* o, void* v);
static void cb_Save(Fl_Button* o, void* v);
inline void cb_New_i(Fl_Button* o, void* v);
static void cb_New(Fl_Button* o, void* v);
static void cb_New(Fl_Button* o, void* v);

inline void cb_MergePatch_i();
static void cb_MergePatch(Fl_Canvas* o, SynthModular*v) { v->cb_MergePatch_i(); };

inline void cb_Connection_i(Fl_Canvas* o, void* v);
static void cb_Connection(Fl_Canvas* o, void* v);
inline void cb_Unconnect_i(Fl_Canvas* o, void* v);
@@ -168,18 +187,27 @@ private:
static void cb_GroupTab(Fl_Tabs* o, void* v);

inline void cb_Rload_i(Fl_Button* o, void* v);
static void cb_Rload(Fl_Button* o, void* v);
static void cb_Rload(Fl_Button* o, void* v);

static void cb_Update(void* o, bool Mode);
static void cb_Blocking(void* o, bool Mode);
static void cb_Update(void* o, bool Mode);
static void cb_Blocking(void* o, bool Mode);
static void cb_UpdatePluginInfo(int ID, void *PluginInfo);

DeviceGroup m_Copied;

inline void cb_CutDeviceGroup_i();
inline void cb_CopyDeviceGroup_i();
inline void cb_PasteDeviceGroup_i();

static void cb_CutDeviceGroup(Fl_Canvas* o, SynthModular*v) { v->cb_CutDeviceGroup_i(); };
static void cb_CopyDeviceGroup(Fl_Canvas* o, SynthModular*v) { v->cb_CopyDeviceGroup_i(); };
static void cb_PasteDeviceGroup(Fl_Canvas* o, SynthModular*v) { v->cb_PasteDeviceGroup_i(); };

friend istream &operator>>(istream &s, SynthModular &o);
friend ostream &operator<<(ostream &s, SynthModular &o);
};

istream &operator>>(istream &s, SynthModular &o);
iostream &operator>>(iostream &s, SynthModular &o);
ostream &operator<<(ostream &s, SynthModular &o);

#endif

Loading…
Cancel
Save