@@ -1,26 +1,26 @@ | |||
/* ========================================================================================= | |||
This is an auto-generated file: Any edits you make may be overwritten! | |||
*/ | |||
#ifndef BINARYDATA_INCLUDED | |||
#define BINARYDATA_INCLUDED | |||
namespace BinaryData | |||
{ | |||
extern const char* cabbageLogoHBlueText_png; | |||
const int cabbageLogoHBlueText_pngSize = 7732; | |||
extern const char* logo_cabbage_Black_png; | |||
const int logo_cabbage_Black_pngSize = 32229; | |||
extern const char* logo_cabbage_black_no_text_png; | |||
const int logo_cabbage_black_no_text_pngSize = 7710; | |||
// If you provide the name of one of the binary resource variables above, this function will | |||
// return the corresponding data and its size (or a null pointer if the name isn't found). | |||
const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes) throw(); | |||
} | |||
#endif | |||
/* ========================================================================================= | |||
This is an auto-generated file: Any edits you make may be overwritten! | |||
*/ | |||
#ifndef BINARYDATA_INCLUDED | |||
#define BINARYDATA_INCLUDED | |||
namespace BinaryData | |||
{ | |||
extern const char* cabbageLogoHBlueText_png; | |||
const int cabbageLogoHBlueText_pngSize = 7732; | |||
extern const char* logo_cabbage_Black_png; | |||
const int logo_cabbage_Black_pngSize = 32229; | |||
extern const char* logo_cabbage_black_no_text_png; | |||
const int logo_cabbage_black_no_text_pngSize = 7710; | |||
// If you provide the name of one of the binary resource variables above, this function will | |||
// return the corresponding data and its size (or a null pointer if the name isn't found). | |||
const char* getNamedResource (const char* resourceNameUTF8, int& dataSizeInBytes) throw(); | |||
} | |||
#endif |
@@ -18,7 +18,7 @@ CabbageCallOutBox::CabbageCallOutBox (Component& c, const Rectangle<int>& area, | |||
{ | |||
setAlwaysOnTop (true); | |||
updatePosition (area, Desktop::getInstance().getDisplays() | |||
.getDisplayContaining (area.getCentre()).userArea); | |||
.getDisplayContaining (area.getCentre()).userArea); | |||
addToDesktop (ComponentPeer::windowIsTemporary); | |||
} | |||
@@ -48,8 +48,8 @@ public: | |||
}; | |||
CabbageCallOutBox& CabbageCallOutBox::launchAsynchronously (Component* content, | |||
const Rectangle<int>& area, | |||
Component* parent) | |||
const Rectangle<int>& area, | |||
Component* parent) | |||
{ | |||
jassert (content != nullptr); // must be a valid content component! | |||
@@ -60,7 +60,7 @@ CabbageCallOutBox& CabbageCallOutBox::launchAsynchronously (Component* content, | |||
void CabbageCallOutBox::paint (Graphics& g) | |||
{ | |||
g.fillAll(Colours::black); | |||
g.fillAll(Colours::black); | |||
// getLookAndFeel().drawCallOutBoxBackground (*this, g, outline, background); | |||
} | |||
@@ -144,12 +144,14 @@ void CabbageCallOutBox::updatePosition (const Rectangle<int>& newAreaToPointTo, | |||
Point<float> targets[4] = { Point<float> ((float) targetArea.getCentreX(), (float) targetArea.getBottom()), | |||
Point<float> ((float) targetArea.getRight(), (float) targetArea.getCentreY()), | |||
Point<float> ((float) targetArea.getX(), (float) targetArea.getCentreY()), | |||
Point<float> ((float) targetArea.getCentreX(), (float) targetArea.getY()) }; | |||
Point<float> ((float) targetArea.getCentreX(), (float) targetArea.getY()) | |||
}; | |||
Line<float> lines[4] = { Line<float> (targets[0].translated (-hwReduced, hh - arrowIndent), targets[0].translated (hwReduced, hh - arrowIndent)), | |||
Line<float> (targets[1].translated (hw - arrowIndent, -hhReduced), targets[1].translated (hw - arrowIndent, hhReduced)), | |||
Line<float> (targets[2].translated (-(hw - arrowIndent), -hhReduced), targets[2].translated (-(hw - arrowIndent), hhReduced)), | |||
Line<float> (targets[3].translated (-hwReduced, -(hh - arrowIndent)), targets[3].translated (hwReduced, -(hh - arrowIndent))) }; | |||
Line<float> (targets[3].translated (-hwReduced, -(hh - arrowIndent)), targets[3].translated (hwReduced, -(hh - arrowIndent))) | |||
}; | |||
const Rectangle<float> centrePointArea (newAreaToFitIn.reduced (hw, hh).toFloat()); | |||
const Point<float> targetCentre (targetArea.getCentre().toFloat()); | |||
@@ -186,12 +188,12 @@ void CabbageCallOutBox::refreshPath() | |||
background = Image::null; | |||
outline.clear(); | |||
outline.addRectangle(1, 1, getWidth()-2, getHeight()-2); | |||
/* | |||
const float gap = 4.5f; | |||
outline.addRectangle(1, 1, getWidth()-2, getHeight()-2); | |||
/* | |||
const float gap = 4.5f; | |||
outline.addBubble (content.getBounds().toFloat().expanded (gap, gap), | |||
getLocalBounds().toFloat(), | |||
targetPoint - getPosition().toFloat(), | |||
9.0*/ | |||
outline.addBubble (content.getBounds().toFloat().expanded (gap, gap), | |||
getLocalBounds().toFloat(), | |||
targetPoint - getPosition().toFloat(), | |||
9.0*/ | |||
} |
@@ -27,15 +27,15 @@ class CabbageCallOutBox : public Component | |||
public: | |||
//============================================================================== | |||
CabbageCallOutBox (Component& contentComponent, | |||
const Rectangle<int>& areaToPointTo, | |||
Component* parentComponent); | |||
const juce::Rectangle<int>& areaToPointTo, | |||
Component* parentComponent); | |||
~CabbageCallOutBox(); | |||
void updatePosition (const Rectangle<int>& newAreaToPointTo, | |||
const Rectangle<int>& newAreaToFitIn); | |||
void updatePosition (const juce::Rectangle<int>& newAreaToPointTo, | |||
const juce::Rectangle<int>& newAreaToFitIn); | |||
static CabbageCallOutBox& launchAsynchronously (Component* contentComponent, | |||
const Rectangle<int>& areaToPointTo, | |||
Component* parentComponent); | |||
const juce::Rectangle<int>& areaToPointTo, | |||
Component* parentComponent); | |||
//============================================================================== | |||
void paint (Graphics& g); | |||
@@ -54,7 +54,7 @@ private: | |||
Component& content; | |||
Path outline; | |||
Point<float> targetPoint; | |||
Rectangle<int> availableArea, targetArea; | |||
juce::Rectangle<int> availableArea, targetArea; | |||
Image background; | |||
void refreshPath(); | |||
@@ -15,7 +15,7 @@ | |||
License along with Csound; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |||
02111-1307 USA | |||
*/ | |||
#ifndef CABBPARSE_H | |||
#define CABBPARSE_H | |||
@@ -32,273 +32,323 @@ | |||
#include "CabbageUtils.h" | |||
//creating this as a singleton as I don't wish to create | |||
//this array over and oer again when dealing with the CabbageGUIClass | |||
//objects. | |||
class IdentArray : public StringArray | |||
{ | |||
public: | |||
IdentArray() : StringArray("tablecolour") | |||
{ | |||
add("tablecolours"); | |||
add("bounds"); | |||
add("fontcolour"); | |||
add("size"); | |||
add("items"); | |||
add("pos"); | |||
add("min"); | |||
add("max"); | |||
add("value"); | |||
add("tabpage"); | |||
add("guirefresh"); | |||
add("midictrl"); | |||
add("stack"); | |||
add("line"); | |||
add("populate"); | |||
add("range"); | |||
add("amprange"); | |||
add("rangex"); | |||
add("rangey"); | |||
add("plant"); | |||
add("channeltype"); | |||
add("channels"); | |||
add("channel"); | |||
add("channelarray"); | |||
add("identchannelarray"); | |||
add("name"); | |||
add("textbox"); | |||
add("caption"); | |||
add("kind"); | |||
add("config"); | |||
add("align"); | |||
add("beveltype"); | |||
add("wrap"); | |||
//add(" mode("); | |||
//add(",mode("); | |||
add("mode"); | |||
add("tablenumber"); | |||
add("tablenum"); | |||
add("tablenumbers"); | |||
add("tablenums"); | |||
add("fill"); | |||
add("logger"); | |||
add("file"); | |||
add("outlinecolour"); | |||
add("master"); | |||
add("shape"); | |||
add("textcolour"); | |||
add("scale"); | |||
add("key("); | |||
add("pluginid"); | |||
add("trackercolour"); | |||
add("preset"); | |||
add("popup"); | |||
add("include"); | |||
add("show"); | |||
add("author"); | |||
add("drawmode"); | |||
add("resizemode"); | |||
add("readonly"); | |||
add("latched"); | |||
add("identchannel"); | |||
add("visible"); | |||
add("scrubberposition"); | |||
add("scroll"); | |||
add("zoom"); | |||
add("samplerange"); | |||
add("scrollbars"); | |||
add("socket"); | |||
//colour and text must go at end to prevent fall through | |||
add("colour"); | |||
add("text"); | |||
} | |||
~IdentArray() | |||
{ | |||
// this ensures that no dangling pointers are left when the | |||
// singleton is deleted. | |||
clearSingletonInstance(); | |||
} | |||
juce_DeclareSingleton (IdentArray, false) | |||
}; | |||
namespace CabbageIDs | |||
{ | |||
static const Identifier top = "top"; | |||
static const Identifier left = "left"; | |||
static const Identifier width = "width"; | |||
static const Identifier height = "height"; | |||
static const Identifier min = "min"; | |||
static const Identifier max = "max"; | |||
static const Identifier value = "value"; | |||
static const Identifier channel = "channel"; | |||
static const Identifier colour = "colour"; | |||
static const Identifier tablecolour = "tablecolour"; | |||
static const Identifier fontcolour= "fontcolour"; | |||
static const Identifier items = "items"; | |||
static const Identifier text = "text"; | |||
static const Identifier range = "range"; | |||
static const Identifier sliderrange = "sliderrange"; | |||
static const Identifier amprange = "amprange"; | |||
static const Identifier caption = "caption"; | |||
static const Identifier basetype = "basetype"; | |||
static const Identifier textbox = "textbox"; | |||
static const Identifier name = "name"; | |||
static const Identifier type = "type"; | |||
static const Identifier trackercolour = "trackercolour"; | |||
static const Identifier sliderskew = "sliderskew"; | |||
static const Identifier sliderincr = "sliderince"; | |||
static const Identifier midichan = "midichan"; | |||
static const Identifier midictrl = "midictrl"; | |||
static const Identifier kind = "kind"; | |||
static const Identifier decimalplaces = "decimalplaces"; | |||
static const Identifier mode = "mode"; | |||
static const Identifier shape = "shape"; | |||
static const Identifier channeltype = "channeltype"; | |||
static const Identifier comborange = "comborange"; | |||
static const Identifier populate = "populate"; | |||
static const Identifier outline = "outline"; | |||
static const Identifier popup = "popup"; | |||
static const Identifier plant = "plant"; | |||
static const Identifier line = "line"; | |||
static const Identifier tablenumber = "tablenumber"; | |||
static const Identifier resizemode = "resizemode"; | |||
static const Identifier drawmode = "drawmode"; | |||
static const Identifier readonly = "readonly"; | |||
static const Identifier xyautoindex = "xyautoindex"; | |||
static const Identifier file = "file"; | |||
static const Identifier latched = "latched"; | |||
static const Identifier xchannel = "xchannel"; | |||
static const Identifier ychannel = "ychannel"; | |||
static const Identifier minx = "minx"; | |||
static const Identifier miny = "miny"; | |||
static const Identifier maxx = "maxx"; | |||
static const Identifier maxy = "maxy"; | |||
static const Identifier valuex = "valuex"; | |||
static const Identifier fill = "fill"; | |||
static const Identifier valuey = "valuey"; | |||
static const Identifier textcolour = "textcolour"; | |||
static const Identifier pluginid = "pluginid"; | |||
static const Identifier tabs = "tabs"; | |||
static const Identifier tabbed = "tabbed"; | |||
static const Identifier rangey = "rangey"; | |||
static const Identifier rangex = "rangex"; | |||
static const Identifier tabpage = "tabpage"; | |||
static const Identifier filetype = "filetype"; | |||
static const Identifier workingdir = "workingdir"; | |||
static const Identifier author = "author"; | |||
static const Identifier xychannel = "xychannel"; | |||
static const Identifier guirefresh = "guirefresh"; | |||
//type of widgets/controls/messages | |||
static const String combobox = "combobox"; | |||
static const String rslider = "rslider"; | |||
static const String hslider = "hslider"; | |||
static const String vslider = "vslider"; | |||
static const String checkbox = "checkbox"; | |||
static const String button = "button"; | |||
static const String filebutton = "filebutton"; | |||
static const String table = "table"; | |||
static const String groupbox = "groupbox"; | |||
static const String image = "image"; | |||
static const String form = "form"; | |||
static const String xypad = "xypad"; | |||
static const String stringchannel = "string"; | |||
static const String hostbpm = "HOST_BPM"; | |||
static const String timeinseconds = "TIME_IN_SECONDS"; | |||
static const String isplaying = "IS_PLAYING"; | |||
static const String isrecording = "IS_RECORDING"; | |||
static const String hostppqpos = "HOST_PPQ_POS"; | |||
static const String csoundoutput = "csoundoutput"; | |||
//identifiers | |||
static const Identifier top = "top"; | |||
static const Identifier left = "left"; | |||
static const Identifier width = "width"; | |||
static const Identifier height = "height"; | |||
static const Identifier min = "min"; | |||
static const Identifier max = "max"; | |||
static const Identifier value = "value"; | |||
static const Identifier channel = "channel"; | |||
static const Identifier channelarray = "channelarray"; | |||
static const Identifier identchannelarray = "identchannelarray"; | |||
static const Identifier outlinecolour = "outlinecolour"; | |||
static const Identifier fillcolour = "fillcolour"; | |||
static const Identifier textcolour = "textcolour"; | |||
static const Identifier trackercolour = "trackercolour"; | |||
static const Identifier tablecolour = "tablecolour"; | |||
static const Identifier fontcolour= "fontcolour"; | |||
static const Identifier colour = "colour"; | |||
static const Identifier items = "items"; | |||
static const Identifier text = "text"; | |||
static const Identifier range = "range"; | |||
static const Identifier sliderrange = "sliderrange"; | |||
static const Identifier amprange = "amprange"; | |||
static const Identifier caption = "caption"; | |||
static const Identifier basetype = "basetype"; | |||
static const Identifier textbox = "textbox"; | |||
static const Identifier name = "name"; | |||
static const Identifier type = "type"; | |||
static const Identifier sliderskew = "sliderskew"; | |||
static const Identifier sliderincr = "sliderincr"; | |||
static const Identifier midichan = "midichan"; | |||
static const Identifier midictrl = "midictrl"; | |||
static const Identifier kind = "kind"; | |||
static const Identifier decimalplaces = "decimalplaces"; | |||
static const Identifier mode = "mode"; | |||
static const Identifier shape = "shape"; | |||
static const Identifier channeltype = "channeltype"; | |||
static const Identifier comborange = "comborange"; | |||
static const Identifier populate = "populate"; | |||
static const Identifier popup = "popup"; | |||
static const Identifier plant = "plant"; | |||
static const Identifier line = "line"; | |||
static const Identifier tablenumber = "tablenumber"; | |||
static const Identifier tableconfig = "tableconfig"; | |||
static const Identifier resizemode = "resizemode"; | |||
static const Identifier drawmode = "drawmode"; | |||
static const Identifier readonly = "readonly"; | |||
static const Identifier xyautoindex = "xyautoindex"; | |||
static const Identifier file = "file"; | |||
static const Identifier latched = "latched"; | |||
static const Identifier xchannel = "xchannel"; | |||
static const Identifier ychannel = "ychannel"; | |||
static const Identifier minx = "minx"; | |||
static const Identifier miny = "miny"; | |||
static const Identifier maxx = "maxx"; | |||
static const Identifier maxy = "maxy"; | |||
static const Identifier logger = "logger"; | |||
static const Identifier stack = "stack"; | |||
static const Identifier valuex = "valuex"; | |||
static const Identifier valuey = "valuey"; | |||
static const Identifier pluginid = "pluginid"; | |||
static const Identifier tabs = "tabs"; | |||
static const Identifier wrap = "wrap"; | |||
static const Identifier align = "align"; | |||
static const Identifier tabbed = "tabbed"; | |||
static const Identifier rangey = "rangey"; | |||
static const Identifier rangex = "rangex"; | |||
static const Identifier include = "include"; | |||
static const Identifier tabpage = "tabpage"; | |||
static const Identifier filetype = "filetype"; | |||
static const Identifier workingdir = "workingdir"; | |||
static const Identifier author = "author"; | |||
static const Identifier xychannel = "xychannel"; | |||
static const Identifier guirefresh = "guirefresh"; | |||
static const Identifier identchannel = "identchannel"; | |||
static const Identifier identchannelmessage = "identchannelmessage"; | |||
static const Identifier visible = "visible"; | |||
static const Identifier lineNumber = "linenumber"; | |||
static const Identifier scrubberposition = "scrubberposition"; | |||
static const Identifier startpoint = "startpoint"; | |||
static const Identifier endpoint = "endpoint"; | |||
static const Identifier zoom = "zoom"; | |||
static const Identifier visiblelength = "visiblelength"; | |||
static const Identifier samplerange = "samplerange"; | |||
static const Identifier startpos = "startpos"; | |||
static const Identifier endpos = "endpos"; | |||
static const Identifier show = "show"; | |||
static const Identifier child = "child"; | |||
static const Identifier scrollbars = "scrollbars"; | |||
static const Identifier oscport = "oscport"; | |||
static const Identifier oscaddress = "oscaddress"; | |||
//type of widgets/controls/messages | |||
static const String combobox = "combobox"; | |||
static const String numberbox = "numberbox"; | |||
static const String rslider = "rslider"; | |||
static const String hslider = "hslider"; | |||
static const String vslider = "vslider"; | |||
static const String checkbox = "checkbox"; | |||
static const String soundfiler = "sounfiler"; | |||
static const String button = "button"; | |||
static const String infobutton = "infobutton"; | |||
static const String filebutton = "filebutton"; | |||
static const String texteditor = "texteditor"; | |||
static const String table = "table"; | |||
static const String gentable = "gentable"; | |||
static const String groupbox = "groupbox"; | |||
static const String image = "image"; | |||
static const String popupmenu = "popupmenu"; | |||
static const String label = "label"; | |||
static const String keyboard = "keyboard"; | |||
static const String oscserver = "oscserver"; | |||
static const String form = "form"; | |||
static const String directorylist = "directorylist"; | |||
static const String index = "index"; | |||
static const String xypad = "xypad"; | |||
static const String stringchannel = "string"; | |||
static const String hostbpm = "HOST_BPM"; | |||
static const String timeinseconds = "TIME_IN_SECONDS"; | |||
static const String isplaying = "IS_PLAYING"; | |||
static const String isrecording = "IS_RECORDING"; | |||
static const String hostppqpos = "HOST_PPQ_POS"; | |||
static const String mousex = "MOUSE_X"; | |||
static const String mousey = "MOUSE_Y"; | |||
static const String mousedownleft = "MOUSE_DOWN_LEFT"; | |||
static const String mousedownright = "MOUSE_DOWN_RIGHT"; | |||
static const String mousedownlmiddle = "MOUSE_DOWN_MIDDLE"; | |||
static const String csoundoutput = "csoundoutput"; | |||
}; | |||
class CabbageGUIClass : public CabbageUtils | |||
{ | |||
double width, height, top, left, isRect, min, max, minX, minY, maxX, tabbed, maxY, comboRange, fftSize, overlapSize, frameSize, | |||
noOfMenus, onoff, midiChan, midiCtrl, sliderRange, xypadRangeY, xypadRangeX, noSteps, noPatterns, pvsChannel, alpha, | |||
line, anchor, linkTo, scaleX, scaleY, value, valueX, valueY, maxItems, sliderIncr, sliderSkew, decimalPlaces, rCtrls, lineIsVertical; | |||
StringArray items, onoffcaptions, key, channels, snapshotData, colours; | |||
String channel, name, sizeText, posText, boundsText, text, type, plant, reltoplant, bounds, range, fileType, workingDir, | |||
shape, beveltype, caption, kind, topitem, yChannel, xChannel, author, native, basetype, | |||
exit, csstdout, cssetup, file, debugMessage, xyChannel, pluginID, tabpage, preset; | |||
Colour outline, fill, fontcolour, textcolour, colour, trackerFill; | |||
int tableNum, textBox, numPresets, masterSnap, plantButton, xyAutoIndex, paramIndex, numTables, soundfilerIndex; | |||
Array<int> vuConfig; | |||
Array<int> tableNumbers; | |||
Array<float> tableChannelValues; | |||
//JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageGUIClass); | |||
double width, height, top, left; | |||
/*, isRect, min, max, minX, minY, maxX, tabbed, maxY, comboRange, fftSize, overlapSize, frameSize, | |||
noOfMenus, onoff, midiChan, midiCtrl, sliderRange, xypadRangeY, xypadRangeX, noSteps, noPatterns, pvsChannel, alpha, | |||
line, anchor, linkTo, scaleX, scaleY, value, valueX, valueY, maxItems, sliderIncr, sliderSkew, decimalPlaces, rCtrls, lineIsVertical; | |||
StringArray items, onoffcaptions, key, channels, snapshotData, colours;*/ | |||
Array<int> vuConfig; | |||
Array<int> tableNumbers; | |||
Array<float> tableChannelValues; | |||
//JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageGUIClass); | |||
public: | |||
//constructor | |||
NamedValueSet cabbageIdentifiers; | |||
CabbageGUIClass(String str, int ID); | |||
CabbageGUIClass(){}; | |||
//constructor | |||
NamedValueSet cabbageIdentifiers; | |||
CabbageGUIClass(String str, int ID); | |||
CabbageGUIClass() {}; | |||
~CabbageGUIClass(); | |||
int parse(String str); | |||
float getNumProp(Identifier prop); | |||
float getNumProp(Identifier prop, int index); | |||
void setNumProp(Identifier prop, float val); | |||
void setTableChannelValues(int index, float val); | |||
float getTableChannelValues(int index); | |||
void addTableChannelValues(); | |||
void setStringProp(Identifier prop, String val); | |||
void setStringProp(Identifier prop, int index, String value); | |||
String getStringProp(Identifier prop); | |||
String getStringProp(Identifier prop, int index); | |||
String getPropsString(); | |||
String getColourProp(Identifier prop); | |||
float getNumPropVal(Identifier prop); | |||
void setNumPropVal(Identifier prop, float val); | |||
static String getCabbageCodeFromIdentifiers(NamedValueSet props); | |||
static String getStringForIdentifier(var props, String identifier, String type); | |||
Rectangle<int> getBounds(){ | |||
Rectangle<int> bounds(left, top, width, height); | |||
return bounds; | |||
} | |||
void setBounds(Rectangle<int> bounds){ | |||
left = bounds.getX(); | |||
top = bounds.getY(); | |||
width = bounds.getWidth(); | |||
height = bounds.getHeight(); | |||
} | |||
static StringArray getIdentifiers(){ | |||
StringArray test; | |||
return test; | |||
} | |||
Rectangle<int> getComponentBounds(); | |||
StringArray getStringArrayProp(Identifier prop); | |||
String getStringArrayPropValue(Identifier prop, int index); | |||
int getIntArrayPropValue(Identifier prop, int index); | |||
Array<int> getIntArrayProp(Identifier prop); | |||
float getFloatArrayPropValue(Identifier prop, int index); | |||
Array<float> getFloatArrayProp(Identifier prop); | |||
StringArray getChannels(){ | |||
return channels; | |||
} | |||
inline int getNumPresets(){ | |||
return snapshotData.size(); | |||
} | |||
inline void clearPresets(){ | |||
snapshotData.clear(); | |||
} | |||
inline String setOnOffcaptions(int index, String str){ | |||
if(index<=onoffcaptions.size()) | |||
onoffcaptions.getReference(index)=str; | |||
} | |||
inline String getOnOffcaptions(int index){ | |||
if(index<=onoffcaptions.size()) | |||
return onoffcaptions.getReference(index); | |||
else return ""; | |||
} | |||
inline String setItems(int index, String str){ | |||
if(index<=items.size()) | |||
items.getReference(index)=str; | |||
else | |||
return ""; | |||
} | |||
inline String getItems(int index){ | |||
if(isPositiveAndBelow (index, items.size())) | |||
return items.getReference(index); | |||
else return ""; | |||
} | |||
inline String getColours(int index){ | |||
if(colours.size()) | |||
return colours.getReference(index); | |||
else return ""; | |||
} | |||
inline int getNumberOfColours(){ | |||
return colours.size(); | |||
} | |||
inline StringArray getItemArray(){ | |||
if(items.size()) | |||
return items; | |||
else return StringArray(); | |||
} | |||
inline int getItemsSize(){ | |||
return items.size(); | |||
} | |||
inline Array<int> getVUConfig(){ | |||
return vuConfig; | |||
} | |||
// inline String getChannel(int index){ | |||
// return channels[index]; | |||
// } | |||
inline void addDummyChannel(String dummyChan){ | |||
return channels.add(dummyChan); | |||
} | |||
// inline String getTableChannel(int index){ | |||
// return channels[index]; | |||
// } | |||
// inline int getNumberOfTableChannels(){ | |||
// return channels.size(); | |||
// } | |||
inline int getKeySize(){ | |||
return key.size(); | |||
} | |||
inline String getkey(int index){ | |||
return key.getReference(index); | |||
} | |||
// inline int getNumberOfTables(){ | |||
// return numTables; | |||
// } | |||
// int getTableNumbers(int index) | |||
// { | |||
// if(index<tableNumbers.size()) | |||
// return tableNumbers[index]; | |||
// } | |||
// inline Array<int> getTableNumbersArray() | |||
// { | |||
// return tableNumbers; | |||
// } | |||
int parse(String str, String identifier); | |||
float getNumProp(Identifier prop); | |||
float getNumProp(Identifier prop, int index); | |||
void setNumProp(Identifier prop, float val); | |||
void setTableChannelValues(int index, float val); | |||
float getTableChannelValues(int index); | |||
void addTableChannelValues(); | |||
void setStringProp(Identifier prop, String val); | |||
void setStringProp(Identifier prop, int index, String value); | |||
String getStringProp(Identifier prop); | |||
String getStringProp(Identifier prop, int index); | |||
String getPropsString(); | |||
String getColourProp(Identifier prop); | |||
float getNumPropVal(Identifier prop); | |||
void setNumPropVal(Identifier prop, float val); | |||
static String getCabbageCodeFromIdentifiers(NamedValueSet props); | |||
static String getStringForIdentifier(var props, String identifier, String type); | |||
Rectangle<int> getBounds() | |||
{ | |||
Rectangle<int> bounds(left, top, width, height); | |||
return bounds; | |||
} | |||
//static methods used for updating look and pos of GUI controls | |||
static Rectangle<int> getBoundsFromText(String text); | |||
static Colour getColourFromText(String text); | |||
static String getTextFromText(String text); | |||
static Point<int> getSizeFromText(String text); | |||
static Point<int> getPosFromText(String text); | |||
static float getSkewFromText(String text); | |||
static var getVarArrayFromText(String text); | |||
void setBounds(Rectangle<int> bounds) | |||
{ | |||
left = bounds.getX(); | |||
top = bounds.getY(); | |||
width = bounds.getWidth(); | |||
height = bounds.getHeight(); | |||
} | |||
static StringArray getIdentifiers() | |||
{ | |||
StringArray test; | |||
return test; | |||
} | |||
Rectangle<int> getComponentBounds(); | |||
StringArray getStringArrayProp(Identifier prop); | |||
String getStringArrayPropValue(Identifier prop, int index); | |||
int getIntArrayPropValue(Identifier prop, int index); | |||
Array<int> getIntArrayProp(Identifier prop); | |||
var getVarArrayProp(Identifier prop); | |||
float getFloatArrayPropValue(Identifier prop, int index); | |||
Array<float> getFloatArrayProp(Identifier prop); | |||
void setStringArrayPropValue(Identifier prop, int index, String value); | |||
void setStringArrayProp(Identifier prop, var value); | |||
}; | |||
#endif | |||
#endif | |||
@@ -16,97 +16,101 @@ | |||
class CabbageLookAndFeel : public LookAndFeel_V2 | |||
{ | |||
public: | |||
CabbageLookAndFeel(); | |||
~CabbageLookAndFeel(); | |||
Image drawRotaryImage(int diameter, const Colour circleFill, const Colour trackerCol, float sliderPosProportional, float zeroPosProportional, | |||
bool useTrackerFill, | |||
float markerOpacity); | |||
Image drawLinearBgImage (float width, float height, float sliderPosProportional, float zeroPosProportional, | |||
bool useTrackerFill, | |||
bool isVertical, | |||
const Colour trackerCol); | |||
void drawTableHeaderColumn (Graphics& g, const String& columnName, int /*columnId*/, | |||
int width, int height, | |||
bool isMouseOver, bool isMouseDown, | |||
int columnFlags); | |||
void drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header); | |||
Image drawLinearThumbImage (float width, float height, const Colour thumbFill, bool isVertical); | |||
static Image drawToggleImage (float width, float height, bool isToggleOn, Colour colour, bool isRect); | |||
Image drawTextButtonImage (float width, float height, bool isButtonDown, Colour colour); | |||
virtual void drawRotarySlider (Graphics &g, int x, int y, int width, int height, float sliderPosProportional, | |||
float rotaryStartAngle, | |||
float rotaryEndAngle, | |||
Slider &slider); | |||
virtual void drawLinearSliderBackground (Graphics &g, int x, int y, int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider &slider); | |||
virtual void drawLinearSliderThumb (Graphics &g, int x, int y, int width, int height, float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider &slider); | |||
virtual void drawButtonBackground (Graphics&, Button&, const Colour&, bool, bool); | |||
virtual void drawButtonText (Graphics &g, TextButton &button, bool isMouseOverButton, bool isButtonDown); | |||
virtual void drawLabel (Graphics &g, Label &label); | |||
virtual void drawComboBox (Graphics&, int, int, bool, int, int, int, int, ComboBox&); | |||
virtual void drawToggleButton (Graphics &g, ToggleButton &button, bool isMouseOverButton, bool isButtonDown); | |||
virtual void drawTextEditorOutline (Graphics &g, int width, int height, TextEditor &textEditor); | |||
virtual void fillTextEditorBackground (Graphics &g, int width, int height, TextEditor &textEditor); | |||
virtual void drawGroupComponentOutline (Graphics &g, int w, int h, const String &text, const Justification &position, | |||
GroupComponent &group); | |||
virtual int getDefaultScrollbarWidth(); | |||
virtual void drawScrollbar (Graphics &g, ScrollBar &scrollbar, int x, int y, int width, int height, | |||
bool isScrollbarVertical, | |||
int thumbStartPosition, | |||
int thumbSize, | |||
bool isMouseOver, | |||
bool isMouseDown); | |||
virtual void drawScrollbarButton (Graphics &g, ScrollBar &scrollbar, int width, int height, int buttonDirection, | |||
bool isScrollbarVertical, | |||
bool isMouseOverButton, | |||
bool isButtonDown); | |||
void setDefaultSansSerifTypefaceName (const String &newName); | |||
virtual void drawMenuBarBackground(Graphics &g, int width, int height, bool isMouseOverBar, MenuBarComponent &menuBar); | |||
CabbageLookAndFeel(); | |||
~CabbageLookAndFeel(); | |||
Image getSVGImageFor(String type); | |||
Image drawRotaryImage(int diameter, const Colour circleFill, const Colour trackerCol, float sliderPosProportional, float zeroPosProportional, | |||
bool useTrackerFill, | |||
float markerOpacity); | |||
Image drawLinearBgImage (float width, float height, float sliderPosProportional, float zeroPosProportional, | |||
bool useTrackerFill, | |||
bool isVertical, | |||
const Colour trackerCol); | |||
void drawTableHeaderColumn (Graphics& g, const String& columnName, int /*columnId*/, | |||
int width, int height, | |||
bool isMouseOver, bool isMouseDown, | |||
int columnFlags); | |||
void drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header); | |||
Image drawLinearThumbImage (float width, float height, const Colour thumbFill, bool isVertical); | |||
static Image drawToggleImage (float width, float height, bool isToggleOn, Colour colour, bool isRect); | |||
Image drawTextButtonImage (float width, float height, bool isButtonDown, Colour colour); | |||
virtual void drawRotarySlider (Graphics &g, int x, int y, int width, int height, float sliderPosProportional, | |||
float rotaryStartAngle, | |||
float rotaryEndAngle, | |||
Slider &slider); | |||
virtual void drawLinearSliderBackground (Graphics &g, int x, int y, int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider &slider); | |||
virtual void drawLinearSliderThumb (Graphics &g, int x, int y, int width, int height, float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider &slider); | |||
virtual void drawButtonBackground (Graphics&, Button&, const Colour&, bool, bool); | |||
virtual void drawButtonText (Graphics &g, TextButton &button, bool isMouseOverButton, bool isButtonDown); | |||
virtual void drawLabel (Graphics &g, Label &label); | |||
virtual void drawComboBox (Graphics&, int, int, bool, int, int, int, int, ComboBox&); | |||
virtual Font getComboBoxFont (ComboBox& box); | |||
virtual Label* createComboBoxTextBox (ComboBox&); | |||
void positionComboBoxText (ComboBox& box, Label& label); | |||
virtual void drawToggleButton (Graphics &g, ToggleButton &button, bool isMouseOverButton, bool isButtonDown); | |||
virtual void drawTextEditorOutline (Graphics &g, int width, int height, TextEditor &textEditor); | |||
virtual void fillTextEditorBackground (Graphics &g, int width, int height, TextEditor &textEditor); | |||
virtual void drawGroupComponentOutline (Graphics &g, int w, int h, const String &text, const Justification &position, | |||
GroupComponent &group); | |||
virtual int getDefaultScrollbarWidth(); | |||
int getMinimumScrollbarThumbSize(){return 15;} | |||
virtual void drawScrollbar (Graphics &g, ScrollBar &scrollbar, int x, int y, int width, int height, | |||
bool isScrollbarVertical, | |||
int thumbStartPosition, | |||
int thumbSize, | |||
bool isMouseOver, | |||
bool isMouseDown); | |||
virtual void drawScrollbarButton (Graphics &g, ScrollBar &scrollbar, int width, int height, int buttonDirection, | |||
bool isScrollbarVertical, | |||
bool isMouseOverButton, | |||
bool isButtonDown); | |||
void setDefaultSansSerifTypefaceName (const String &newName); | |||
virtual void drawMenuBarBackground(Graphics &g, int width, int height, bool isMouseOverBar, MenuBarComponent &menuBar); | |||
virtual void drawMenuBarItem(Graphics & g, int width, int height, int itemIndex, | |||
const String &itemText, bool isMouseOverItem, | |||
bool isMenuOpen, bool isMouseOverBar, | |||
MenuBarComponent &menuBar); | |||
void drawPopupMenuBackground(Graphics &g, int width, int height); | |||
Image drawCheckMark(); | |||
virtual void drawPopupMenuItem (Graphics &g, int width, int height, bool isSeparator, bool isActive, bool isHighlighted, | |||
bool isTicked, | |||
bool hasSubMenu, | |||
const String &text, | |||
const String &shortcutKeyText, | |||
Image *image, | |||
const Colour *const textColour); | |||
virtual void drawDocumentWindowTitleBar (DocumentWindow &window, Graphics &g, int w, int h, int titleSpaceX, int titleSpaceW, | |||
const Image *icon, | |||
bool drawTitleTextOnLeft); | |||
Image drawWindowButtonNormal(int buttonType); | |||
Image drawWindowButtonIsOver(int buttonType); | |||
virtual Button* createDocumentWindowButton (int buttonType); | |||
int getAlertBoxWindowFlags(); | |||
int getAlertWindowButtonHeight(); | |||
Font getAlertWindowMessageFont(); | |||
Font getAlertWindowFont(); | |||
void drawAlertBox (Graphics& g, AlertWindow& alert, const Rectangle<int>& textArea, TextLayout& textLayout); | |||
AlertWindow* createAlertWindow (const String& title, const String& message, const String& button1, const String& button2, | |||
const String& button3, AlertWindow::AlertIconType iconType, int numButtons, | |||
Component* associatedComponent); | |||
int getTabButtonSpaceAroundImage(); | |||
const String &itemText, bool isMouseOverItem, | |||
bool isMenuOpen, bool isMouseOverBar, | |||
MenuBarComponent &menuBar); | |||
void drawPopupMenuBackground(Graphics &g, int width, int height); | |||
Image drawCheckMark(); | |||
virtual void drawPopupMenuItem (Graphics& g, const Rectangle<int>& area, | |||
const bool isSeparator, const bool isActive, | |||
const bool isHighlighted, const bool isTicked, | |||
const bool hasSubMenu, const String& text, | |||
const String& shortcutKeyText, | |||
const Drawable* icon, const Colour* const textColourToUse); | |||
virtual void drawDocumentWindowTitleBar (DocumentWindow &window, Graphics &g, int w, int h, int titleSpaceX, int titleSpaceW, | |||
const Image *icon, | |||
bool drawTitleTextOnLeft); | |||
Image drawWindowButtonNormal(int buttonType); | |||
Image drawWindowButtonIsOver(int buttonType); | |||
virtual Button* createDocumentWindowButton (int buttonType); | |||
int getAlertBoxWindowFlags(); | |||
int getAlertWindowButtonHeight(); | |||
Font getAlertWindowMessageFont(); | |||
Font getAlertWindowFont(); | |||
void drawAlertBox (Graphics& g, AlertWindow& alert, const Rectangle<int>& textArea, TextLayout& textLayout); | |||
AlertWindow* createAlertWindow (const String& title, const String& message, const String& button1, const String& button2, | |||
const String& button3, AlertWindow::AlertIconType iconType, int numButtons, | |||
Component* associatedComponent); | |||
int getTabButtonSpaceAroundImage(); | |||
int getTabButtonOverlap (int tabDepth); | |||
int getTabButtonBestWidth (TabBarButton&, int tabDepth); | |||
Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp); | |||
@@ -119,26 +123,39 @@ public: | |||
void fillTabButtonShape (TabBarButton&, Graphics& g, const Path& path, bool isMouseOver, bool isMouseDown); | |||
void drawFileBrowserRow (Graphics& g, int width, int height, | |||
const String& filename, Image* icon, | |||
const String& fileSizeDescription, | |||
const String& fileTimeDescription, | |||
bool isDirectory, | |||
bool isItemSelected, | |||
int itemIndex, | |||
DirectoryContentsDisplayComponent& component); | |||
const String& filename, Image* icon, | |||
const String& fileSizeDescription, | |||
const String& fileTimeDescription, | |||
bool isDirectory, | |||
bool isItemSelected, | |||
int itemIndex, | |||
DirectoryContentsDisplayComponent& component); | |||
void drawTreeviewPlusMinusBox (Graphics& g, int x, int y, int w, int h, bool isPlus, bool /*isMouseOver*/); | |||
void drawTreeviewPlusMinusBox (Graphics& g, int x, int y, int w, int h, bool isPlus, bool /*isMouseOver*/); | |||
void drawLevelMeter(Graphics &g, int width, int height, float level); | |||
Button* createTabBarExtrasButton(); | |||
juce_UseDebuggingNewOperator | |||
Button* createTabBarExtrasButton(); | |||
void drawLinearSlider (Graphics&, int x, int y, int width, int height, | |||
float sliderPos, float minSliderPos, float maxSliderPos, | |||
const Slider::SliderStyle, Slider&); | |||
void drawStretchableLayoutResizerBar (Graphics& g, int w, int h, | |||
bool /*isVerticalBar*/, | |||
bool isMouseOver, | |||
bool isMouseDragging); | |||
int getDefaultMenuBarHeight(){ | |||
return 18; | |||
} | |||
juce_UseDebuggingNewOperator | |||
private: | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageLookAndFeel); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageLookAndFeel); | |||
}; | |||
@@ -152,64 +169,64 @@ private: | |||
class CabbageLookAndFeelBasic : public LookAndFeel_V2 | |||
{ | |||
public: | |||
CabbageLookAndFeelBasic(); | |||
~CabbageLookAndFeelBasic(); | |||
void drawLabel(Graphics&, Label&); | |||
virtual void drawLinearSliderBackground (Graphics &g, int x, int y, int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider &slider); | |||
virtual void drawLinearSliderThumb (Graphics &g, int x, int y, int width, int height, float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider &slider); | |||
CabbageLookAndFeelBasic(); | |||
~CabbageLookAndFeelBasic(); | |||
void drawLabel(Graphics&, Label&); | |||
virtual void drawLinearSliderBackground (Graphics &g, int x, int y, int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider &slider); | |||
virtual void drawLinearSliderThumb (Graphics &g, int x, int y, int width, int height, float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider &slider); | |||
void drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour, bool isMouseOverButton, bool isButtonDown); | |||
virtual void drawScrollbar (Graphics &g, ScrollBar &scrollbar, int x, int y, int width, int height, | |||
bool isScrollbarVertical, | |||
int thumbStartPosition, | |||
int thumbSize, | |||
bool isMouseOver, | |||
bool isMouseDown); | |||
void drawDocumentWindowTitleBar (DocumentWindow &window, Graphics &g, int w, int h, | |||
int /*titleSpaceX*/, | |||
int titleSpaceW, | |||
const Image */*icon*/, | |||
bool /*drawTitleTextOnLeft*/); | |||
void drawResizableWindowBorder (Graphics &g, int w, int h, const BorderSize< int > &border, ResizableWindow &window); | |||
void drawPopupMenuBackground(Graphics &g, int width, int height); | |||
void drawMenuBarBackground(Graphics &g, int width, int height, bool isMouseOverBar, MenuBarComponent &menuBar); | |||
Image drawCheckMark(); | |||
void drawMenuBarItem(Graphics & g, int width, int height, int itemIndex, | |||
const String &itemText, | |||
bool isMouseOverItem, | |||
bool isMenuOpen, | |||
bool isMouseOverBar, | |||
MenuBarComponent &menuBar); | |||
void drawPopupMenuItem (Graphics &g, int width, int height, bool isSeparator, bool /*isActive*/, | |||
bool isHighlighted, | |||
bool isTicked, | |||
bool hasSubMenu, | |||
const String &text, | |||
const String &shortcutKeyText, | |||
Image */*image*/, | |||
const Colour */*const textColour*/); | |||
juce_UseDebuggingNewOperator | |||
virtual void drawScrollbar (Graphics &g, ScrollBar &scrollbar, int x, int y, int width, int height, | |||
bool isScrollbarVertical, | |||
int thumbStartPosition, | |||
int thumbSize, | |||
bool isMouseOver, | |||
bool isMouseDown); | |||
void drawDocumentWindowTitleBar (DocumentWindow &window, Graphics &g, int w, int h, | |||
int /*titleSpaceX*/, | |||
int titleSpaceW, | |||
const Image */*icon*/, | |||
bool /*drawTitleTextOnLeft*/); | |||
void drawResizableWindowBorder (Graphics &g, int w, int h, const BorderSize< int > &border, ResizableWindow &window); | |||
void drawPopupMenuBackground(Graphics &g, int width, int height); | |||
void drawMenuBarBackground(Graphics &g, int width, int height, bool isMouseOverBar, MenuBarComponent &menuBar); | |||
Image drawCheckMark(); | |||
void drawMenuBarItem(Graphics & g, int width, int height, int itemIndex, | |||
const String &itemText, | |||
bool isMouseOverItem, | |||
bool isMenuOpen, | |||
bool isMouseOverBar, | |||
MenuBarComponent &menuBar); | |||
void drawPopupMenuItem (Graphics &g, int width, int height, bool isSeparator, bool /*isActive*/, | |||
bool isHighlighted, | |||
bool isTicked, | |||
bool hasSubMenu, | |||
const String &text, | |||
const String &shortcutKeyText, | |||
Image */*image*/, | |||
const Colour */*const textColour*/); | |||
juce_UseDebuggingNewOperator | |||
private: | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageLookAndFeelBasic); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageLookAndFeelBasic); | |||
}; | |||
@@ -1,43 +1,43 @@ | |||
/* | |||
Copyright (C) 2007 Rory Walsh | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with Csound; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |||
02111-1307 USA | |||
*/ | |||
#include "CabbageMainPanel.h" | |||
#include "ComponentLayoutEditor.h" | |||
/* | |||
Copyright (C) 2007 Rory Walsh | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with Csound; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |||
02111-1307 USA | |||
*/ | |||
#include "CabbageMainPanel.h" | |||
#include "ComponentLayoutEditor.h" | |||
// This is the main panel/component onto which all other components are drawn. | |||
// When users drop components onto this panel, ComponentLayoutEditor will | |||
// When users drop components onto this panel, ComponentLayoutEditor will | |||
// create aliases of each so that they can be moved around and resized. | |||
// When a user disables the ComponentLayoutEditor this panel is again brought | |||
// to front so that components can no longer be edited. The idea is that | |||
// by toggling these two classes toFront() we can swap between edit and lock mode | |||
CabbageMainPanel::CabbageMainPanel() : width(-99), top(-99), height(-99), left(-99) | |||
{ | |||
setName("CabbageMainPanel"); | |||
setVisible(true); | |||
setSize(0,0); | |||
LOCKED=true; | |||
panelColour = CabbageUtils::getBackgroundSkin(); | |||
setName("CabbageMainPanel"); | |||
setVisible(true); | |||
setSize(0,0); | |||
LOCKED=true; | |||
panelColour = CabbageUtils::getBackgroundSkin(); | |||
} | |||
CabbageMainPanel::~CabbageMainPanel() | |||
{ | |||
@@ -46,23 +46,23 @@ CabbageMainPanel::~CabbageMainPanel() | |||
void CabbageMainPanel::paint(Graphics &g) | |||
{ | |||
} | |||
ComponentLayoutEditor* CabbageMainPanel::getLayoutEditor() | |||
{ | |||
return layoutEditor; | |||
return layoutEditor; | |||
} | |||
void CabbageMainPanel::setLayoutEditor(ComponentLayoutEditor* ed) | |||
{ | |||
jassert (ed); | |||
if (layoutEditor) | |||
{ | |||
// deleteAndZero (layoutEditor); | |||
} | |||
layoutEditor = ed; | |||
jassert (ed); | |||
if (layoutEditor) | |||
{ | |||
// deleteAndZero (layoutEditor); | |||
} | |||
layoutEditor = ed; | |||
} |
@@ -32,112 +32,125 @@ class ComponentLayoutEditor; | |||
//----------------------------------------------------------------------------- | |||
class CabbageMainPanel : public Component, | |||
public CabbageUtils, | |||
public ActionBroadcaster | |||
public CabbageUtils, | |||
public ActionBroadcaster | |||
{ | |||
private: | |||
ScopedPointer<ComponentLayoutEditor> layoutEditor; | |||
OwnedArray<Component > comps; | |||
OwnedArray<Component > clipBoard; | |||
Colour panelColour; | |||
int currentIndex; | |||
bool LOCKED; | |||
String mouseState; | |||
String colour; | |||
bool doubleClick; | |||
private: | |||
ScopedPointer<ComponentLayoutEditor> layoutEditor; | |||
OwnedArray<Component > comps; | |||
OwnedArray<Component > clipBoard; | |||
Colour panelColour; | |||
int currentIndex; | |||
bool LOCKED; | |||
String mouseState; | |||
String colour; | |||
bool doubleClick; | |||
public: | |||
Rectangle<int> currentBounds; | |||
Array<Rectangle<int> > childBounds; | |||
Array<Rectangle<int> > origChildBounds; | |||
Array<Point<int> > origSelectedCompBounds; | |||
Array<Point<int> > newSelectedCompBounds; | |||
int width, height, top, left; | |||
inline void setCompColour(String col){ | |||
colour = col; | |||
} | |||
inline String getColour(){ | |||
return colour; | |||
} | |||
inline String getMouseState(){ | |||
return mouseState; | |||
} | |||
inline void setMouseState(String state){ | |||
mouseState = state; | |||
} | |||
inline void setDoubleClick(bool dblClick){ | |||
doubleClick = dblClick; | |||
} | |||
bool isDoubleClick(){ | |||
return doubleClick; | |||
} | |||
//String getCurrentBounds(){ | |||
// return "bounds(" + String(currentBounds.getX()) + String(", ") + String(currentBounds.getY()) + String(", ") + String(currentBounds.getWidth()) + String(", ") | |||
// + String(currentBounds.getHeight()) + String(")"); | |||
//} | |||
//String getCurrentChildBounds(int i){ | |||
// return "bounds(" + String(childBounds[i].getX()) + String(", ") + String(childBounds[i].getY()) + String(", ") + String(childBounds[i].getWidth()) + String(", ") | |||
// + String(childBounds[i].getHeight()) + String(")"); | |||
//} | |||
//String getCurrentOrigChildBounds(int i){ | |||
// return "bounds(" + String(origChildBounds[i].getX()) + String(", ") + String(origChildBounds[i].getY()) + String(", ") + String(origChildBounds[i].getWidth()) + String(", ") | |||
// + String(origChildBounds[i].getHeight()) + String(")"); | |||
//} | |||
// | |||
//String getCurrentPos(){ | |||
//return String("pos(") + String(left) + String(", ") + String(top) + String(")"); | |||
//} | |||
String getCurrentSize(){ | |||
return String("size(") + String(width) + String(", ") + String(height) + String(")"); | |||
} | |||
CabbageMainPanel(); | |||
~CabbageMainPanel(); | |||
void paint(Graphics &g); | |||
ComponentLayoutEditor* getLayoutEditor(); | |||
void setLayoutEditor(ComponentLayoutEditor* ed); | |||
inline int getIndex(){ | |||
return currentIndex; | |||
} | |||
int getCurrentWidth(){ | |||
return width; | |||
} | |||
int getCurrentHeight(){ | |||
return height; | |||
} | |||
int getCurrentTop(){ | |||
return top; | |||
} | |||
int getCurrentLeft(){ | |||
return left; | |||
} | |||
inline void setIndex(int index){ | |||
currentIndex = index; | |||
} | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageMainPanel); | |||
juce::Rectangle<int> currentBounds; | |||
Array<juce::Rectangle<int> > childBounds; | |||
Array<juce::Rectangle<int> > origChildBounds; | |||
Array<Point<int> > origSelectedCompBounds; | |||
Array<Point<int> > newSelectedCompBounds; | |||
int width, height, top, left; | |||
inline void setCompColour(String col) | |||
{ | |||
colour = col; | |||
} | |||
inline String getColour() | |||
{ | |||
return colour; | |||
} | |||
inline String getMouseState() | |||
{ | |||
return mouseState; | |||
} | |||
inline void setMouseState(String state) | |||
{ | |||
mouseState = state; | |||
} | |||
inline void setDoubleClick(bool dblClick) | |||
{ | |||
doubleClick = dblClick; | |||
} | |||
bool isDoubleClick() | |||
{ | |||
return doubleClick; | |||
} | |||
//String getCurrentBounds(){ | |||
// return "bounds(" + String(currentBounds.getX()) + String(", ") + String(currentBounds.getY()) + String(", ") + String(currentBounds.getWidth()) + String(", ") | |||
// + String(currentBounds.getHeight()) + String(")"); | |||
//} | |||
//String getCurrentChildBounds(int i){ | |||
// return "bounds(" + String(childBounds[i].getX()) + String(", ") + String(childBounds[i].getY()) + String(", ") + String(childBounds[i].getWidth()) + String(", ") | |||
// + String(childBounds[i].getHeight()) + String(")"); | |||
//} | |||
//String getCurrentOrigChildBounds(int i){ | |||
// return "bounds(" + String(origChildBounds[i].getX()) + String(", ") + String(origChildBounds[i].getY()) + String(", ") + String(origChildBounds[i].getWidth()) + String(", ") | |||
// + String(origChildBounds[i].getHeight()) + String(")"); | |||
//} | |||
// | |||
//String getCurrentPos(){ | |||
//return String("pos(") + String(left) + String(", ") + String(top) + String(")"); | |||
//} | |||
String getCurrentSize() | |||
{ | |||
return String("size(") + String(width) + String(", ") + String(height) + String(")"); | |||
} | |||
CabbageMainPanel(); | |||
~CabbageMainPanel(); | |||
void paint(Graphics &g); | |||
ComponentLayoutEditor* getLayoutEditor(); | |||
void setLayoutEditor(ComponentLayoutEditor* ed); | |||
inline int getIndex() | |||
{ | |||
return currentIndex; | |||
} | |||
int getCurrentWidth() | |||
{ | |||
return width; | |||
} | |||
int getCurrentHeight() | |||
{ | |||
return height; | |||
} | |||
int getCurrentTop() | |||
{ | |||
return top; | |||
} | |||
int getCurrentLeft() | |||
{ | |||
return left; | |||
} | |||
inline void setIndex(int index) | |||
{ | |||
currentIndex = index; | |||
} | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageMainPanel); | |||
}; | |||
@@ -16,89 +16,103 @@ | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |||
02111-1307 USA | |||
*/ | |||
*/ | |||
#ifndef CABBMESS_H | |||
#define CABBMESS_H | |||
#define CABBMESS_H | |||
#include "CabbageUtils.h" | |||
#ifndef Cabbage_No_Csound | |||
#include "csound.hpp" | |||
#endif | |||
#ifdef AndroidBuild | |||
#include "AndroidCsound.hpp" | |||
#else | |||
#include <csound.hpp> | |||
#endif | |||
#endif | |||
using namespace std; | |||
//simple channel message classe | |||
class CabbageChannelMessage : public CabbageUtils | |||
{ | |||
public: | |||
String channelName; | |||
String channelName; | |||
#ifndef Cabbage_No_Csound | |||
MYFLT value; | |||
MYFLT value; | |||
#else | |||
float value; | |||
float value; | |||
#endif | |||
String type; | |||
String fStatement; | |||
String stringVal; | |||
CabbageChannelMessage(String chan, double val, String _type) | |||
{ | |||
channelName = chan; | |||
value = val; | |||
type = _type; | |||
} | |||
CabbageChannelMessage(String chan, String val, String _type) | |||
{ | |||
channelName = chan; | |||
stringVal = val; | |||
type = _type; | |||
} | |||
~CabbageChannelMessage() | |||
{} | |||
}; | |||
//message queue class | |||
String type; | |||
String fStatement; | |||
int tableNumber; | |||
String stringVal; | |||
CabbageChannelMessage(String chan, double val, String _type) | |||
{ | |||
channelName = chan; | |||
value = val; | |||
type = _type; | |||
} | |||
CabbageChannelMessage(String chan, String val, String _type) | |||
{ | |||
channelName = chan; | |||
stringVal = val; | |||
type = _type; | |||
} | |||
~CabbageChannelMessage() | |||
{} | |||
}; | |||
//message queue class | |||
class CabbageMessageQueue : public CabbageUtils | |||
{ | |||
Array<CabbageChannelMessage> outgoingChannelMessages; | |||
Array<CabbageChannelMessage, CriticalSection> outgoingChannelMessages; | |||
public: | |||
CabbageMessageQueue(){} | |||
~CabbageMessageQueue(){} | |||
void addOutgoingChannelMessageToQueue(String _chan, double _val, String _type){ | |||
outgoingChannelMessages.add(CabbageChannelMessage(_chan, _val, _type)); | |||
} | |||
void addOutgoingChannelMessageToQueue(String _chan, String _val, String _type){ | |||
outgoingChannelMessages.add(CabbageChannelMessage(_chan, _val, _type)); | |||
} | |||
void addOutgoingTableUpdateMessageToQueue(String fStatement){ | |||
CabbageChannelMessage tableMessage("", 0.f, "updateTable"); | |||
tableMessage.fStatement = fStatement; | |||
outgoingChannelMessages.add(tableMessage); | |||
} | |||
CabbageChannelMessage getOutgoingChannelMessageFromQueue(int index){ | |||
return outgoingChannelMessages.getReference(index); | |||
} | |||
int getNumberOfOutgoingChannelMessagesInQueue(){ | |||
return outgoingChannelMessages.size(); | |||
} | |||
void flushOutgoingChannelMessages(){ | |||
outgoingChannelMessages.clear(); | |||
} | |||
}; | |||
CabbageMessageQueue() {} | |||
~CabbageMessageQueue() {} | |||
void addOutgoingChannelMessageToQueue(String _chan, double _val, String _type) | |||
{ | |||
outgoingChannelMessages.add(CabbageChannelMessage(_chan, _val, _type)); | |||
} | |||
void addOutgoingChannelMessageToQueue(String _chan, String _val, String _type) | |||
{ | |||
outgoingChannelMessages.add(CabbageChannelMessage(_chan, _val, _type)); | |||
} | |||
void addOutgoingTableUpdateMessageToQueue(String fStatement, int tableNumber) | |||
{ | |||
CabbageChannelMessage tableMessage("", 0.f, "updateTable"); | |||
tableMessage.fStatement = fStatement; | |||
tableMessage.tableNumber = tableNumber; | |||
outgoingChannelMessages.add(tableMessage); | |||
} | |||
CabbageChannelMessage getOutgoingChannelMessageFromQueue(int index) | |||
{ | |||
return outgoingChannelMessages.getReference(index); | |||
} | |||
int getNumberOfOutgoingChannelMessagesInQueue() | |||
{ | |||
return outgoingChannelMessages.size(); | |||
} | |||
void flushOutgoingChannelMessages() | |||
{ | |||
//const MessageManagerLock mmLock; | |||
outgoingChannelMessages.clear(); | |||
} | |||
}; | |||
#endif |
@@ -15,43 +15,47 @@ | |||
License along with Csound; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |||
02111-1307 USA | |||
*/ | |||
#include "CabbagePropertiesDialog.h" | |||
ControlProperty::ControlProperty(String name, var _value): | |||
PropertyComponent(name), | |||
name(name), | |||
value(_value) | |||
ControlProperty::ControlProperty(String name, var _value): | |||
PropertyComponent(name), | |||
name(name), | |||
value(_value) | |||
{ | |||
if((name=="text" || name=="channel" || name=="items" | |||
|| name=="drawmode" || name=="tablenumber") | |||
|| name=="tablecolour" || name=="amprange" | |||
|| name=="resizemode"){ | |||
addAndMakeVisible(textComboField = new TextComboField(name, value)); | |||
//textComboField->setLookAndFeel(lookAndFeel); | |||
textComboField->addActionListener(this); | |||
} | |||
else if(name.contains("colour")){ | |||
addAndMakeVisible(colourField = new ColourField(name, value.toString())); | |||
colourField->addActionListener(this); | |||
colourField->repaint(); | |||
} | |||
else if(name.contains("file") || name.contains("workingdir")){ | |||
addAndMakeVisible(fileBrowserField = new FileBrowserField(name, value.toString())); | |||
fileBrowserField->addActionListener(this); | |||
} | |||
else{ | |||
addAndMakeVisible(textField = new TextField(name)); | |||
textField->addActionListener(this); | |||
if(value.size()>0) | |||
textField->setText(value[0]); | |||
else | |||
textField->setText(value); | |||
setName(name); | |||
} | |||
if((name=="text" || name=="channel" || name=="items" | |||
|| name=="drawmode" || name=="tablenumber") | |||
|| name=="tablecolour" || name=="amprange" | |||
|| name=="resizemode") | |||
{ | |||
addAndMakeVisible(textComboField = new TextComboField(name, value)); | |||
//textComboField->setLookAndFeel(lookAndFeel); | |||
textComboField->addActionListener(this); | |||
} | |||
else if(name.contains("colour")) | |||
{ | |||
addAndMakeVisible(colourField = new ColourField(name, value.toString())); | |||
colourField->addActionListener(this); | |||
colourField->repaint(); | |||
} | |||
else if(name=="file" || name=="workingdir") | |||
{ | |||
addAndMakeVisible(fileBrowserField = new FileBrowserField(name, value.toString())); | |||
fileBrowserField->addActionListener(this); | |||
} | |||
else | |||
{ | |||
addAndMakeVisible(textField = new TextField(name)); | |||
textField->addActionListener(this); | |||
if(value.size()>0) | |||
textField->setText(value[0]); | |||
else | |||
textField->setText(value); | |||
setName(name); | |||
} | |||
} | |||
@@ -59,43 +63,44 @@ void ControlProperty::actionListenerCallback (const String& message) | |||
{ | |||
//when a user clicks escape from a propery component this method is called. | |||
//everytime this method is called we update the parameters | |||
if(message=="ColourField") | |||
value = colourField->value; | |||
else if(message=="TextField") | |||
value = textField->value; | |||
else if(message=="TextComboField") | |||
value = textComboField->value; | |||
else if(message=="FileBrowserField") | |||
value = fileBrowserField->value; | |||
else if(message=="UpdateAll") | |||
{ | |||
CabbagePropertiesDialog* parentWindow = findParentComponentOfClass <CabbagePropertiesDialog>(); | |||
if(parentWindow) | |||
parentWindow->updateIdentifiers(); | |||
} | |||
if(message=="ColourField") | |||
value = colourField->value; | |||
else if(message=="TextField") | |||
value = textField->value; | |||
else if(message=="TextComboField") | |||
value = textComboField->value; | |||
else if(message=="FileBrowserField") | |||
value = fileBrowserField->value; | |||
else if(message=="UpdateAll") | |||
{ | |||
CabbagePropertiesDialog* parentWindow = findParentComponentOfClass <CabbagePropertiesDialog>(); | |||
if(parentWindow) | |||
parentWindow->updateIdentifiers(); | |||
} | |||
} | |||
void ControlProperty::resized() | |||
{ | |||
if(textField)textField->setBounds(getWidth()/2, 2.5, getWidth()/2-5, getHeight()-5); | |||
if(textComboField)textComboField->setBounds(getWidth()/2, 2.5, getWidth()/2-5, getHeight()-5); | |||
if(colourField)colourField->setBounds(getWidth()/2, 2.5, getWidth()/2-5, getHeight()-5); | |||
if(fileBrowserField)fileBrowserField->setBounds(getWidth()/2, 2.5, getWidth()/2-5, getHeight()-5); | |||
if(textField)textField->setBounds(getWidth()/2, 2.5, getWidth()/2-5, getHeight()-5); | |||
if(textComboField)textComboField->setBounds(getWidth()/2, 2.5, getWidth()/2-5, getHeight()-5); | |||
if(colourField)colourField->setBounds(getWidth()/2, 2.5, getWidth()/2-5, getHeight()-5); | |||
if(fileBrowserField)fileBrowserField->setBounds(getWidth()/2, 2.5, getWidth()/2-5, getHeight()-5); | |||
} | |||
void ControlProperty::paint(Graphics &g){ | |||
g.setColour (Colour(10, 10, 10)); | |||
g.fillAll(); | |||
void ControlProperty::paint(Graphics &g) | |||
{ | |||
g.setColour (Colour(10, 10, 10)); | |||
g.fillAll(); | |||
g.setColour (Colours::orange); | |||
g.setFont (CabbageUtils::getComponentFont()); | |||
g.setColour (Colours::orange); | |||
g.setFont (CabbageUtils::getComponentFont()); | |||
const Rectangle<int> r (5, 0, getWidth()/2, getHeight()-2); | |||
const Rectangle<int> r (5, 0, getWidth()/2, getHeight()-2); | |||
g.drawFittedText(name, | |||
r, | |||
Justification::centred, 2); | |||
g.setColour (Colours::black); | |||
g.drawRect(0, 0, getWidth(), getHeight(), 1); | |||
g.drawFittedText(name, | |||
r, | |||
Justification::centred, 2); | |||
g.setColour (Colours::black); | |||
g.drawRect(0, 0, getWidth(), getHeight(), 1); | |||
} |
@@ -3,6 +3,7 @@ | |||
#include "JuceHeader.h" | |||
#include "CabbageUtils.h" | |||
#include "./Plugin/CabbagePluginProcessor.h" | |||
#define HANDLESIZE 8 | |||
#define LINEAR 0 | |||
@@ -18,35 +19,35 @@ | |||
==================================================================================== | |||
*/ | |||
class CabbageEnvelopeHandleComponent : public Component, | |||
public ChangeBroadcaster | |||
public ChangeBroadcaster | |||
{ | |||
public: | |||
CabbageEnvelopeHandleComponent(int index, Colour colour, bool fixed); | |||
~CabbageEnvelopeHandleComponent(); | |||
CabbageEnvelopeHandleComponent(int index, Colour colour, bool fixed); | |||
~CabbageEnvelopeHandleComponent(); | |||
class Table* getParentComponent(); | |||
void paint (Graphics& g); | |||
void removeThisHandle(); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
int index; | |||
int height, width; | |||
int x,y; | |||
class Table* getParentComponent(); | |||
void paint (Graphics& g); | |||
void removeThisHandle(); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
int index; | |||
int height, width; | |||
int x,y; | |||
CabbageEnvelopeHandleComponent* getPreviousHandle(); | |||
CabbageEnvelopeHandleComponent* getNextHandle(); | |||
CabbageEnvelopeHandleComponent* getPreviousHandle(); | |||
CabbageEnvelopeHandleComponent* getNextHandle(); | |||
String changeMessage; | |||
String changeMessage; | |||
private: | |||
Colour colour; | |||
bool fixed; | |||
ComponentDragger dragger; | |||
int lastX, lastY; | |||
int offsetX, offsetY; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageEnvelopeHandleComponent); | |||
Colour colour; | |||
bool fixed; | |||
ComponentDragger dragger; | |||
int lastX, lastY; | |||
int offsetX, offsetY; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageEnvelopeHandleComponent); | |||
}; | |||
@@ -60,13 +61,13 @@ private: | |||
class TableData | |||
{ | |||
public: | |||
Array<double, CriticalSection> amps, x, y; | |||
Array<float, CriticalSection> amps, x, y; | |||
}; | |||
class OverviewData | |||
{ | |||
public: | |||
Array<double> minAmps, maxAmps, minY, maxY; | |||
Array<double> minAmps, maxAmps, minY, maxY; | |||
}; | |||
/* | |||
@@ -77,78 +78,79 @@ public: | |||
==================================================================================== | |||
*/ | |||
class Table : public Component, | |||
public ChangeBroadcaster, | |||
public ChangeListener | |||
public ChangeBroadcaster, | |||
public ChangeListener | |||
{ | |||
public: | |||
Table (String chan, int tblNumber, int tableSize, bool fixedEnv, bool drawHorizontal, bool drawOriginal, Colour colour); | |||
~Table(); | |||
void resized(); | |||
void setOriginalWidth(int w); | |||
void setGlobalAmpRange (float globalMax, float globalMin, float globalRange); | |||
void createAmpOverviews (Array<double, CriticalSection> csndInputData); | |||
void setDataSource (int zoomValue); | |||
float convertAmpToPixel (float ampValue); | |||
float convertPixelToAmp(float pixelYValue); | |||
void cacheBackgroundImage(); | |||
void paint (Graphics& g); | |||
void mouseDown (const MouseEvent& e); | |||
void applyZoom(int newZoom); | |||
void setToEnabled(bool isEnabled); | |||
void setViewWidth(float width); | |||
void setViewStart(float x); | |||
CabbageEnvelopeHandleComponent* addHandle(int x, int y, bool fixedPos, int width, Colour col); | |||
CabbageEnvelopeHandleComponent* getPreviousHandle(CabbageEnvelopeHandleComponent* thisHandle); | |||
CabbageEnvelopeHandleComponent* getNextHandle(CabbageEnvelopeHandleComponent* thisHandle); | |||
int getHandleIndex(CabbageEnvelopeHandleComponent* thisHandle); | |||
void removeHandle (CabbageEnvelopeHandleComponent* thisHandle); | |||
void modifyHandlePos (float j); | |||
void makeTableEditable(); | |||
void createHandlesFromTable(int points); | |||
void changeListenerCallback(juce::ChangeBroadcaster *source); | |||
TableData tableData; | |||
float scrubberPosition; | |||
String channel; | |||
int tableNumber, tableSize; | |||
Path envPath; | |||
bool drawOriginalTableData, isCurrentlyOnTop, drawFill, | |||
drawHorizontalSegments, fixedEnvelope, toggleMaxMin; | |||
OwnedArray<CabbageEnvelopeHandleComponent, CriticalSection> handles; | |||
void setYValueOfHandle(int x, int y); | |||
void toggleMinMaxAmp(int x); | |||
float minAmp, maxAmp; | |||
String changeMessage; | |||
String currentfStatement; | |||
float ampRange, zeroAmpPosition; | |||
Colour currColour; | |||
bool isResizing; | |||
bool useAmpRanges; | |||
Point<float> minMaxAmps; | |||
bool editMode; | |||
Table (String chan, int tblNumber, int tableSize, bool fixedEnv, bool drawHorizontal, bool drawOriginal, Colour colour); | |||
~Table(); | |||
void resized(); | |||
void setOriginalWidth(int w); | |||
void setGlobalAmpRange (float globalMax, float globalMin, float globalRange); | |||
void createAmpOverviews (Array<float, CriticalSection> csndInputData); | |||
void setDataSource (int zoomValue); | |||
float convertAmpToPixel (float ampValue); | |||
float convertPixelToAmp(float pixelYValue); | |||
void cacheBackgroundImage(); | |||
void paint (Graphics& g); | |||
void mouseDown (const MouseEvent& e); | |||
void applyZoom(int newZoom); | |||
void setToEnabled(bool isEnabled); | |||
void setViewWidth(float width); | |||
void setViewStart(float x); | |||
CabbageEnvelopeHandleComponent* addHandle(int x, int y, bool fixedPos, int width, Colour col); | |||
CabbageEnvelopeHandleComponent* getPreviousHandle(CabbageEnvelopeHandleComponent* thisHandle); | |||
CabbageEnvelopeHandleComponent* getNextHandle(CabbageEnvelopeHandleComponent* thisHandle); | |||
int getHandleIndex(CabbageEnvelopeHandleComponent* thisHandle); | |||
void removeHandle (CabbageEnvelopeHandleComponent* thisHandle); | |||
void modifyHandlePos (float j); | |||
void makeTableEditable(); | |||
void createHandlesFromTable(int points); | |||
void changeListenerCallback(juce::ChangeBroadcaster *source); | |||
TableData tableData; | |||
float scrubberPosition; | |||
String channel; | |||
int tableNumber, tableSize; | |||
Path envPath; | |||
bool drawOriginalTableData, isCurrentlyOnTop, drawFill, | |||
drawHorizontalSegments, fixedEnvelope, toggleMaxMin; | |||
OwnedArray<CabbageEnvelopeHandleComponent, CriticalSection> handles; | |||
void setYValueOfHandle(int x, int y); | |||
void toggleMinMaxAmp(int x); | |||
float minAmp, maxAmp; | |||
String changeMessage; | |||
String currentfStatement; | |||
float ampRange, zeroAmpPosition; | |||
Colour currColour; | |||
bool isResizing; | |||
bool useAmpRanges; | |||
Point<float> minMaxAmps; | |||
bool editMode; | |||
int gen; | |||
StringArray fStatement; | |||
private: | |||
Viewport* viewport; | |||
Viewport* viewport; | |||
Image img; | |||
int gen; | |||
int handleWidth; | |||
float tableTop, tableBottom, tableLeft, tableHeight; | |||
float zoom; | |||
float viewX, viewWidth; | |||
Image img; | |||
int handleWidth; | |||
float tableTop, tableBottom, tableLeft, tableHeight; | |||
float zoom; | |||
float viewX, viewWidth; | |||
OverviewData overview; | |||
Colour activeColour; | |||
int origWidth; | |||
bool useOverview; | |||
float maxZoomForOverview, numPixelsPerIndex; | |||
float minWaveHeight; | |||
OverviewData overview; | |||
Colour activeColour; | |||
int origWidth; | |||
bool useOverview; | |||
float maxZoomForOverview, numPixelsPerIndex; | |||
float minWaveHeight; | |||
CabbageEnvelopeHandleComponent* draggingHandle; | |||
CabbageEnvelopeHandleComponent* draggingHandle; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Table); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Table); | |||
}; | |||
/* | |||
@@ -164,47 +166,53 @@ private: | |||
class CabbageTableManager : public Component | |||
{ | |||
public: | |||
CabbageTableManager(int tableSize); | |||
~CabbageTableManager(); | |||
void resized(); | |||
void setOriginalWidth(float width); | |||
void paint(Graphics& g); | |||
float convertAmpToPixel (float ampValue); | |||
void addTable (String name, String channel, int tableNumber, | |||
int tableSize, | |||
bool fixedEnv, | |||
bool drawHoriz, | |||
bool drawOrig, | |||
bool toggleMaxMin, | |||
bool drawFill, | |||
int resizeMode, | |||
Point<float> maxMin, | |||
Colour colour, | |||
bool readOnly, | |||
ChangeListener* listener); | |||
void fillTable (int tableID, Array<double, CriticalSection> csndInputData); | |||
void tableToTop (int tableOnTop); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag(const MouseEvent& e); | |||
Table* getTable(int index); | |||
int getNumberOfTables(){ | |||
return tables.size(); | |||
} | |||
CabbageTableManager(int tableSize); | |||
~CabbageTableManager(); | |||
void resized(); | |||
void setOriginalWidth(float width); | |||
void paint(Graphics& g); | |||
float convertAmpToPixel (float ampValue); | |||
void addTable (String name, String channel, int tableNumber, | |||
int tableSize, | |||
bool fixedEnv, | |||
bool drawHoriz, | |||
bool drawOrig, | |||
bool toggleMaxMin, | |||
bool drawFill, | |||
int resizeMode, | |||
Point<float> maxMin, | |||
Colour colour, | |||
bool readOnly, | |||
bool stackMode, | |||
int numberOfTables, | |||
ChangeListener* listener); | |||
void fillTable (int tableID, Array<float, CriticalSection> csndInputData); | |||
void setEvtCode(int ID, StringArray fdata); | |||
void tableToTop (int tableOnTop); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseMove (const MouseEvent& e); | |||
void mouseDrag(const MouseEvent& e); | |||
Table* getTable(int index); | |||
int getNumberOfTables() | |||
{ | |||
return tables.size(); | |||
} | |||
private: | |||
OwnedArray<Table, CriticalSection> tables; | |||
float originalWidth; | |||
float alpha; | |||
bool readOnly; | |||
int zoom, maxZoom; | |||
float globalMaxAmp, globalMinAmp, globalAmpRange; | |||
float maxNumPixelsPerIndex; | |||
int currentTableIndex; | |||
int tableSize; | |||
float tableTop, tableBottom, tableHeight; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageTableManager); | |||
OwnedArray<Table, CriticalSection> tables; | |||
float originalWidth; | |||
float alpha; | |||
bool toggleMode; | |||
bool readOnly; | |||
int zoom, maxZoom; | |||
float globalMaxAmp, globalMinAmp, globalAmpRange; | |||
float maxNumPixelsPerIndex; | |||
int currentTableIndex; | |||
int tableSize; | |||
float tableTop, tableBottom, tableHeight; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageTableManager); | |||
}; | |||
@@ -219,23 +227,23 @@ private: | |||
==================================================================================== | |||
*/ | |||
class CabbageTableViewer : public Viewport | |||
//public Component | |||
//public Component | |||
{ | |||
public: | |||
CabbageTableViewer(); | |||
~CabbageTableViewer(); | |||
void resized(); | |||
void addTable (String name, int tableSize, Colour colour, float alpha); | |||
void fillTable (int tableIndex, Array<float> csndInputData); | |||
void tableToTop (int tableIndex); | |||
void setScrubberPosition(int tableIndex, float position); | |||
CabbageTableViewer(); | |||
~CabbageTableViewer(); | |||
void resized(); | |||
void addTable (String name, int tableSize, Colour colour, float alpha); | |||
void fillTable (int tableIndex, Array<float> csndInputData); | |||
void tableToTop (int tableIndex); | |||
void setScrubberPosition(int tableIndex, float position); | |||
private: | |||
ScopedPointer<CabbageTableManager> tableManager; | |||
//OwnedArray<Table> tables; | |||
//float tableOpacity; | |||
ScopedPointer<CabbageTableManager> tableManager; | |||
//OwnedArray<Table> tables; | |||
//float tableOpacity; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageTableViewer); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbageTableViewer); | |||
}; | |||
@@ -1,6 +1,6 @@ | |||
/* | |||
* ComponentLayoutEditor.h | |||
* | |||
* | |||
* Original written by Haydxn | |||
* Modified by Jordan Hochenbaum on 10/25/10. | |||
* http://www.rawmaterialsoftware.com/viewtopic.php?f=6&t=2635 | |||
@@ -23,125 +23,128 @@ extern ApplicationProperties* appProperties; | |||
class SelectedComponents : public SelectedItemSet<ChildAlias*> | |||
{ | |||
public: | |||
void itemSelected (ChildAlias* item); | |||
void itemDeselected (ChildAlias* item); | |||
void itemSelected (ChildAlias* item); | |||
void itemDeselected (ChildAlias* item); | |||
}; | |||
//============================================================================= | |||
class ComponentLayoutEditor : public Component, | |||
public LassoSource <ChildAlias*>, | |||
public ChangeBroadcaster | |||
public LassoSource <ChildAlias*>, | |||
public ChangeBroadcaster | |||
{ | |||
public: | |||
enum ColourIds | |||
{ | |||
aliasIdleColour, | |||
aliasHoverColour | |||
}; | |||
ComponentLayoutEditor (); | |||
~ComponentLayoutEditor (); | |||
void findLassoItemsInArea (Array <ChildAlias*>& results, const Rectangle<int>& area); | |||
Rectangle<int> getLassoRect(SelectedItemSet <ChildAlias*>); | |||
public: | |||
SelectedItemSet <ChildAlias*>& getLassoSelection(); | |||
void resized (); | |||
void paint (Graphics& g); | |||
void setTargetComponent (Component* target); | |||
void bindWithTarget (); | |||
void updateFrames (); | |||
void selectDuplicatedComponents(Array<Rectangle <int> > controls); | |||
Point<int> currentMouseCoors; | |||
String currentEvent; | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp(const MouseEvent& e); | |||
LassoComponent <ChildAlias*> lassoComp; | |||
SelectedComponents selectedFilters; | |||
Array<Rectangle < int > > selectedCompsOrigCoordinates; | |||
Array<Rectangle < int > > selectedCompsNewCoordinates; | |||
void enablementChanged (); | |||
const Component* getTarget (); | |||
void resetAllBorders(); | |||
private: | |||
virtual ChildAlias* createAlias (Component* child, String type, int index); | |||
SafePointer<Component> target; | |||
OwnedArray<ChildAlias> frames; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentLayoutEditor); | |||
enum ColourIds | |||
{ | |||
aliasIdleColour, | |||
aliasHoverColour | |||
}; | |||
ComponentLayoutEditor (); | |||
~ComponentLayoutEditor (); | |||
void findLassoItemsInArea (Array <ChildAlias*>& results, const juce::Rectangle<int>& area); | |||
juce::Rectangle<int> getLassoRect(SelectedItemSet <ChildAlias*>); | |||
SelectedItemSet <ChildAlias*>& getLassoSelection(); | |||
void resized (); | |||
void paint (Graphics& g); | |||
void setTargetComponent (Component* target); | |||
void bindWithTarget (); | |||
void updateFrames (); | |||
void selectDuplicatedComponents(Array<juce::Rectangle <int> > controls); | |||
Point<int> currentMouseCoors; | |||
String currentEvent; | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp(const MouseEvent& e); | |||
LassoComponent <ChildAlias*> lassoComp; | |||
SelectedComponents selectedFilters; | |||
Array<int> selectedLineNumbers; | |||
Array<juce::Rectangle < int > > selectedCompsOrigCoordinates; | |||
Array<juce::Rectangle < int > > selectedCompsNewCoordinates; | |||
void enablementChanged (); | |||
const Component* getTarget (); | |||
void resetAllBorders(); | |||
Array<juce::Rectangle <int> > boundsForDuplicatedCtrls; | |||
private: | |||
virtual ChildAlias* createAlias (Component* child, String type, int index); | |||
SafePointer<Component> target; | |||
OwnedArray<ChildAlias> frames; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentLayoutEditor); | |||
}; | |||
//============================================================================= | |||
class ChildAlias : public Component, | |||
public CabbageUtils, | |||
public KeyListener | |||
public CabbageUtils, | |||
public KeyListener | |||
{ | |||
public: | |||
ChildAlias (Component* targetChild, String type, int index); | |||
~ChildAlias (); | |||
void resized (); | |||
void paint (Graphics& g); | |||
const Component* getTargetChild (); | |||
const Component* getTarget(); | |||
CabbageMainPanel* getMainPanel(); | |||
ComponentLayoutEditor* getLayoutEditor() | |||
{ | |||
public: | |||
ChildAlias (Component* targetChild, String type, int index); | |||
~ChildAlias (); | |||
void resized (); | |||
void paint (Graphics& g); | |||
const Component* getTargetChild (); | |||
const Component* getTarget(); | |||
CabbageMainPanel* getMainPanel(); | |||
ComponentLayoutEditor* getLayoutEditor(){ | |||
ComponentLayoutEditor* c = dynamic_cast <ComponentLayoutEditor*> (getParentComponent()); | |||
if(c) | |||
return c; | |||
else | |||
return nullptr; | |||
} | |||
bool keyPressed(const juce::KeyPress &key ,Component *); | |||
void updateFromTarget (); | |||
void applyToTarget (String triggeredFrom); | |||
virtual void userChangedBounds (); | |||
virtual void userStartedChangingBounds (); | |||
virtual void userStoppedChangingBounds (); | |||
bool boundsChangedSinceStart (); | |||
void restrictBounds(int &x, int &y); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseExit (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseDoubleClick(const MouseEvent &event); | |||
bool interest, lockMovement; | |||
private: | |||
int index; | |||
Array<Rectangle<int> > origBounds; | |||
int dragX, dragY; | |||
String type; | |||
CriticalSection bounds; | |||
ScopedPointer<ComponentBoundsConstrainer> constrainer; | |||
ComponentDragger dragger; | |||
SafePointer<Component> target; | |||
bool userAdjusting; | |||
Rectangle<int> startBounds; | |||
ScopedPointer<ComponentBoundsConstrainer> resizeContainer; //added resizeContainer to limit resizing sizes | |||
ScopedPointer<ResizableBorderComponent> resizer; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildAlias); | |||
}; | |||
ComponentLayoutEditor* c = dynamic_cast <ComponentLayoutEditor*> (getParentComponent()); | |||
if(c) | |||
return c; | |||
else | |||
return nullptr; | |||
} | |||
bool keyPressed(const juce::KeyPress &key ,Component *); | |||
void updateFromTarget (); | |||
void applyToTarget (String triggeredFrom); | |||
virtual void userChangedBounds (); | |||
virtual void userStartedChangingBounds (); | |||
virtual void userStoppedChangingBounds (); | |||
bool boundsChangedSinceStart (); | |||
void restrictBounds(int &x, int &y); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseExit (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseDoubleClick(const MouseEvent &event); | |||
bool interest, lockMovement; | |||
private: | |||
int index; | |||
Array<juce::Rectangle<int> > origBounds; | |||
int dragX, dragY; | |||
String type; | |||
CriticalSection bounds; | |||
ScopedPointer<ComponentBoundsConstrainer> constrainer; | |||
ComponentDragger dragger; | |||
SafePointer<Component> target; | |||
bool userAdjusting; | |||
juce::Rectangle<int> startBounds; | |||
ScopedPointer<ComponentBoundsConstrainer> resizeContainer; //added resizeContainer to limit resizing sizes | |||
ScopedPointer<ResizableBorderComponent> resizer; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChildAlias); | |||
}; | |||
#endif//_COMPONENTLAYOUTEDITOR_H_ |
@@ -4,7 +4,7 @@ | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
@@ -21,215 +21,227 @@ | |||
//============================================================================== | |||
DirectoryContentsComponent::DirectoryContentsComponent(String dir, String files): | |||
fileTypes(files), | |||
rootDir(dir), | |||
thread ("audio file preview"), | |||
fileTreeComp (0), | |||
editor(0), | |||
ftableCounter(1), | |||
lookAndFeel(0), | |||
fileTypes(files), | |||
rootDir(dir), | |||
thread ("audio file preview"), | |||
fileTreeComp (0), | |||
editor(0), | |||
ftableCounter(1), | |||
lookAndFeel(0), | |||
//filter("*.wav;*.ogg;*.aiff", "*.*", "Audio Files"), | |||
filter(files, "*.*", ""), | |||
directoryList(&filter, thread) | |||
filter(files, "*.*", ""), | |||
directoryList(&filter, thread) | |||
{ | |||
; | |||
//directoryList.addChangeListener() | |||
//create and set Cabbage look and feel | |||
//directoryList.addChangeListener() | |||
//create and set Cabbage look and feel | |||
lookAndFeel=new CabbageLookAndFeel(); | |||
basicLookAndFeel = new CabbageLookAndFeelBasic(); | |||
setLookAndFeel(lookAndFeel); | |||
//directory list | |||
fileTreeComp = new FileTreeComponent(directoryList); | |||
fileTreeComp->addListener(this); | |||
//if file dir is valid set it, otherwise root is base | |||
//custom FunctionTable class | |||
tablesList.add(new FunctionTableList()); | |||
tablesList[0]->addActionListener(this); | |||
//table list class, uses above object as it's model | |||
tables.add(new TableListBox("list", tablesList[0])); | |||
tables[0]->setLookAndFeel(lookAndFeel); | |||
tables[0]->setMultipleSelectionEnabled(true); | |||
tables[0]->setColour(TableListBox::backgroundColourId, Colours::black); | |||
tables[0]->setColour(TableListBox::outlineColourId, Colours::black); | |||
tables[0]->setOutlineThickness (1); | |||
//addAndMakeVisible(tables[0]); | |||
functionRowData.add(new StringArray()); | |||
tabComp = new TabbedComponent(TabbedButtonBar::TabsAtTop); | |||
tabComp->setLookAndFeel(basicLookAndFeel); | |||
tabComp->setTabBarDepth(25); | |||
//tabComp->setColour(TabbedButtonBar::tabTextColourId, Colours::white); | |||
tabComp->setColour(TabbedButtonBar::tabOutlineColourId, Colours::black); | |||
tabComp->addTab("Bank 1", Colours::white, tables[0], false); | |||
tabComp->setOutline(0); | |||
tabComp->repaint(); | |||
addAndMakeVisible(tabComp); | |||
tables[0]->getHeader().addColumn ("Function Tables", 1, 400, 35, 400, TableHeaderComponent::defaultFlags); | |||
tables[0]->getHeader().setSize(tables[0]->getWidth(), 25); | |||
//file directory setups.... | |||
if(File(rootDir).isDirectory()) | |||
directoryList.setDirectory(File(rootDir), true, true); | |||
else | |||
directoryList.setDirectory (File::getSpecialLocation (File::userHomeDirectory), true, true); | |||
thread.startThread (3); | |||
basicLookAndFeel = new CabbageLookAndFeelBasic(); | |||
setLookAndFeel(lookAndFeel); | |||
//directory list | |||
fileTreeComp = new FileTreeComponent(directoryList); | |||
fileTreeComp->addListener(this); | |||
//if file dir is valid set it, otherwise root is base | |||
//custom FunctionTable class | |||
tablesList.add(new FunctionTableList()); | |||
tablesList[0]->addActionListener(this); | |||
//table list class, uses above object as it's model | |||
tables.add(new TableListBox("list", tablesList[0])); | |||
tables[0]->setLookAndFeel(lookAndFeel); | |||
tables[0]->setMultipleSelectionEnabled(true); | |||
tables[0]->setColour(TableListBox::backgroundColourId, Colours::black); | |||
tables[0]->setColour(TableListBox::outlineColourId, Colours::black); | |||
tables[0]->setOutlineThickness (1); | |||
//addAndMakeVisible(tables[0]); | |||
functionRowData.add(new StringArray()); | |||
tabComp = new TabbedComponent(TabbedButtonBar::TabsAtTop); | |||
tabComp->setLookAndFeel(basicLookAndFeel); | |||
tabComp->setTabBarDepth(25); | |||
//tabComp->setColour(TabbedButtonBar::tabTextColourId, Colours::white); | |||
tabComp->setColour(TabbedButtonBar::tabOutlineColourId, Colours::black); | |||
tabComp->addTab("Bank 1", Colours::white, tables[0], false); | |||
tabComp->setOutline(0); | |||
tabComp->repaint(); | |||
addAndMakeVisible(tabComp); | |||
tables[0]->getHeader().addColumn ("Function Tables", 1, 400, 35, 400, TableHeaderComponent::defaultFlags); | |||
tables[0]->getHeader().setSize(tables[0]->getWidth(), 25); | |||
//file directory setups.... | |||
if(File(rootDir).isDirectory()) | |||
directoryList.setDirectory(File(rootDir), true, true); | |||
else | |||
directoryList.setDirectory (File::getSpecialLocation (File::userHomeDirectory), true, true); | |||
thread.startThread (3); | |||
fileTreeComp->setColour(0x1000501, Colours::green);//linesColourId | |||
fileTreeComp->setColour(DirectoryContentsDisplayComponent::textColourId, Colours::white); | |||
fileTreeComp->setColour(ListBox::outlineColourId, Colours::red); | |||
fileTreeComp->addListener (this); | |||
addBankButton = new TextButton("Add Bank"); | |||
addBankButton->addListener(this); | |||
addBankButton->setLookAndFeel(basicLookAndFeel); | |||
addBankButton->setColour(TextButton::buttonColourId, Colours::cornflowerblue.withAlpha(.4f)); | |||
addBankButton->setColour(TextButton::textColourOffId, Colours::white); | |||
addBankButton->setColour(TextButton::textColourOnId, Colours::white); | |||
updateTablesButton = new TextButton("Update Tables"); | |||
updateTablesButton->addListener(this); | |||
updateTablesButton->setLookAndFeel(basicLookAndFeel); | |||
updateTablesButton->setColour(TextButton::buttonColourId, Colours::cornflowerblue.withAlpha(.4f)); | |||
updateTablesButton->setColour(TextButton::textColourOffId, Colours::white); | |||
updateTablesButton->setColour(TextButton::textColourOnId, Colours::white); | |||
autoUpdate = new ToggleButton("Auto-update"); | |||
autoUpdate->getProperties().set("isRect", true); | |||
autoUpdate->getProperties().set("colour", Colours::lime.toString()); | |||
autoUpdate->getProperties().set("fontcolour", Colours::white.toString()); | |||
//add everything to screen | |||
addAndMakeVisible(autoUpdate); | |||
addAndMakeVisible (fileTreeComp); | |||
addAndMakeVisible(updateTablesButton); | |||
addAndMakeVisible(addBankButton); | |||
setSize (600, 500); | |||
fileTreeComp->setColour(ListBox::outlineColourId, Colours::red); | |||
fileTreeComp->addListener (this); | |||
addBankButton = new TextButton("Add Bank"); | |||
addBankButton->addListener(this); | |||
addBankButton->setLookAndFeel(basicLookAndFeel); | |||
addBankButton->setColour(TextButton::buttonColourId, Colours::cornflowerblue.withAlpha(.4f)); | |||
addBankButton->setColour(TextButton::textColourOffId, Colours::white); | |||
addBankButton->setColour(TextButton::textColourOnId, Colours::white); | |||
updateTablesButton = new TextButton("Update Tables"); | |||
updateTablesButton->addListener(this); | |||
updateTablesButton->setLookAndFeel(basicLookAndFeel); | |||
updateTablesButton->setColour(TextButton::buttonColourId, Colours::cornflowerblue.withAlpha(.4f)); | |||
updateTablesButton->setColour(TextButton::textColourOffId, Colours::white); | |||
updateTablesButton->setColour(TextButton::textColourOnId, Colours::white); | |||
autoUpdate = new ToggleButton("Auto-update"); | |||
autoUpdate->getProperties().set("isRect", true); | |||
autoUpdate->getProperties().set("colour", Colours::lime.toString()); | |||
autoUpdate->getProperties().set("fontcolour", Colours::white.toString()); | |||
//add everything to screen | |||
addAndMakeVisible(autoUpdate); | |||
addAndMakeVisible (fileTreeComp); | |||
addAndMakeVisible(updateTablesButton); | |||
addAndMakeVisible(addBankButton); | |||
setSize (600, 500); | |||
} | |||
//==================================================================================== | |||
DirectoryContentsComponent::~DirectoryContentsComponent() | |||
{ | |||
thread.stopThread(10); | |||
thread.stopThread(10); | |||
} | |||
//==================================================================================== | |||
void DirectoryContentsComponent::paint (Graphics& g) | |||
{ | |||
g.setColour(CabbageUtils::getBackgroundSkin()); | |||
g.fillRoundedRectangle(0, 0, getWidth(), getHeight(), 7); | |||
g.setColour(CabbageUtils::getBackgroundSkin()); | |||
g.fillRoundedRectangle(0, 0, getWidth(), getHeight(), 7); | |||
} | |||
//==================================================================================== | |||
void DirectoryContentsComponent::resized() | |||
{ | |||
//resize evcerything | |||
fileTreeComp->setBounds (5, 5, (getWidth()/2)-5, getHeight()-45); | |||
tabComp->setBounds (getWidth()/2+5, 5, (getWidth()/2)-10, getHeight()-45); | |||
addBankButton->setBounds(5, getHeight()-35, 90, 25); | |||
updateTablesButton->setBounds(100, getHeight()-35, 110, 25); | |||
autoUpdate->setBounds(220, getHeight()-35, 150, 25); | |||
//resize evcerything | |||
fileTreeComp->setBounds (5, 5, (getWidth()/2)-5, getHeight()-45); | |||
tabComp->setBounds (getWidth()/2+5, 5, (getWidth()/2)-10, getHeight()-45); | |||
addBankButton->setBounds(5, getHeight()-35, 90, 25); | |||
updateTablesButton->setBounds(100, getHeight()-35, 110, 25); | |||
autoUpdate->setBounds(220, getHeight()-35, 150, 25); | |||
} | |||
//==================================================================================== | |||
//populate table rows with new strings and add new items to listable | |||
void DirectoryContentsComponent::fileClicked (const File& file, const MouseEvent& e) | |||
{ | |||
} | |||
//==================================================================================== | |||
//this will listen for messages from our FunctionTableList object, and behave accordingly. | |||
void DirectoryContentsComponent::actionListenerCallback(const juce::String& string){ | |||
if(string=="delete selected"){ | |||
if(tables[tabComp->getCurrentTabIndex()]->getNumSelectedRows()>0){ | |||
SparseSet<int> sparseSet = tables[tabComp->getCurrentTabIndex()]->getSelectedRows(); | |||
for(int i=sparseSet.size();i>=0;i--){ | |||
functionRowData[tabComp->getCurrentTabIndex()]->remove(sparseSet[i]); | |||
} | |||
tables[tabComp->getCurrentTabIndex()]->deselectAllRows(); | |||
tablesList[tabComp->getCurrentTabIndex()]->addOrModifyRows(tabComp->getCurrentTabIndex(), *functionRowData[tabComp->getCurrentTabIndex()]); | |||
tables[tabComp->getCurrentTabIndex()]->updateContent(); | |||
tables[tabComp->getCurrentTabIndex()]->repaint(); | |||
} | |||
} | |||
else if(string=="deselect") | |||
tables[tabComp->getCurrentTabIndex()]->deselectAllRows(); | |||
//this will listen for messages from our FunctionTableList object, and behave accordingly. | |||
void DirectoryContentsComponent::actionListenerCallback(const juce::String& string) | |||
{ | |||
if(string=="delete selected") | |||
{ | |||
if(tables[tabComp->getCurrentTabIndex()]->getNumSelectedRows()>0) | |||
{ | |||
SparseSet<int> sparseSet = tables[tabComp->getCurrentTabIndex()]->getSelectedRows(); | |||
for(int i=sparseSet.size(); i>=0; i--) | |||
{ | |||
functionRowData[tabComp->getCurrentTabIndex()]->remove(sparseSet[i]); | |||
} | |||
tables[tabComp->getCurrentTabIndex()]->deselectAllRows(); | |||
tablesList[tabComp->getCurrentTabIndex()]->addOrModifyRows(tabComp->getCurrentTabIndex(), *functionRowData[tabComp->getCurrentTabIndex()]); | |||
tables[tabComp->getCurrentTabIndex()]->updateContent(); | |||
tables[tabComp->getCurrentTabIndex()]->repaint(); | |||
} | |||
} | |||
else if(string=="deselect") | |||
tables[tabComp->getCurrentTabIndex()]->deselectAllRows(); | |||
} | |||
//==================================================================================== | |||
//button clicks | |||
void DirectoryContentsComponent::buttonClicked(Button* button) | |||
{ | |||
//each time the add bank button is clicked add a new object to tablesList, and tables arrays, then show them on the | |||
//tabbed component.. | |||
if(button->getName()=="Add Bank"){ | |||
functionRowData.add(new StringArray()); | |||
tablesList.add(new FunctionTableList()); | |||
tablesList[tablesList.size()-1]->addActionListener(this); | |||
tables.add(new TableListBox("list", tablesList[tablesList.size()-1])); | |||
tables[tables.size()-1]->setLookAndFeel(lookAndFeel); | |||
tables[tables.size()-1]->setMultipleSelectionEnabled(true); | |||
tables[tables.size()-1]->setColour(TableListBox::textColourId, Colours::white); | |||
tables[tables.size()-1]->setColour(TableListBox::backgroundColourId, Colours::black); | |||
tables[tables.size()-1]->getHeader().addColumn ("Function Tables", 1, 400, 50, 400, TableHeaderComponent::defaultFlags); | |||
tabComp->addTab("Bank "+String(tabComp->getNumTabs()+1), Colours::white, tables[tables.size()-1], false); | |||
tabComp->setCurrentTabIndex(tables.size()-1); | |||
} | |||
if(button->getName()=="Update Tables"){ | |||
sendActionMessage("updatingDirectoryTables"); | |||
} | |||
//each time the add bank button is clicked add a new object to tablesList, and tables arrays, then show them on the | |||
//tabbed component.. | |||
if(button->getName()=="Add Bank") | |||
{ | |||
functionRowData.add(new StringArray()); | |||
tablesList.add(new FunctionTableList()); | |||
tablesList[tablesList.size()-1]->addActionListener(this); | |||
tables.add(new TableListBox("list", tablesList[tablesList.size()-1])); | |||
tables[tables.size()-1]->setLookAndFeel(lookAndFeel); | |||
tables[tables.size()-1]->setMultipleSelectionEnabled(true); | |||
tables[tables.size()-1]->setColour(TableListBox::textColourId, Colours::white); | |||
tables[tables.size()-1]->setColour(TableListBox::backgroundColourId, Colours::black); | |||
tables[tables.size()-1]->getHeader().addColumn ("Function Tables", 1, 400, 50, 400, TableHeaderComponent::defaultFlags); | |||
tabComp->addTab("Bank "+String(tabComp->getNumTabs()+1), Colours::white, tables[tables.size()-1], false); | |||
tabComp->setCurrentTabIndex(tables.size()-1); | |||
} | |||
if(button->getName()=="Update Tables") | |||
{ | |||
sendActionMessage("updatingDirectoryTables"); | |||
} | |||
} | |||
//==================================================================================== | |||
void DirectoryContentsComponent::selectionChanged() | |||
{ | |||
if(fileTreeComp->getSelectedFile().existsAsFile()){ | |||
updateSelection(fileTreeComp->getSelectedFile()); | |||
if(autoUpdate->getToggleState()) | |||
sendActionMessage("updatingTables"); | |||
} | |||
{ | |||
if(fileTreeComp->getSelectedFile().existsAsFile()) | |||
{ | |||
updateSelection(fileTreeComp->getSelectedFile()); | |||
if(autoUpdate->getToggleState()) | |||
sendActionMessage("updatingTables"); | |||
} | |||
} | |||
//==================================================================================== | |||
const StringArray DirectoryContentsComponent::getFunctionTables() | |||
{ | |||
StringArray tables; | |||
StringArray tables; | |||
//only retrieve the current selected bank | |||
for(int y=0;y<functionRowData[tabComp->getCurrentTabIndex()]->size();y++){ | |||
tables.add("f "+String((tabComp->getCurrentTabIndex()+1)*50+y)+" 0 0 1 \""+functionRowData[tabComp->getCurrentTabIndex()]->getReference(y)+"\" 0 4 1"); | |||
} | |||
for(int y=0; y<functionRowData[tabComp->getCurrentTabIndex()]->size(); y++) | |||
{ | |||
tables.add("f "+String((tabComp->getCurrentTabIndex()+1)*50+y)+" 0 0 1 \""+functionRowData[tabComp->getCurrentTabIndex()]->getReference(y)+"\" 0 4 1"); | |||
} | |||
return tables; | |||
return tables; | |||
} | |||
//==================================================================================== | |||
void DirectoryContentsComponent::updateSelection(const File& file){ | |||
//update the number of rows in our listbox passing | |||
if(tables[tabComp->getCurrentTabIndex()]->getNumSelectedRows()>0){ | |||
SparseSet<int> sparseSet = tables[tabComp->getCurrentTabIndex()]->getSelectedRows(); | |||
for(int i=0;i<sparseSet.size();i++){ | |||
functionRowData[tabComp->getCurrentTabIndex()]->getReference(sparseSet[i])= file.getFullPathName(); | |||
tablesList[tabComp->getCurrentTabIndex()]->addOrModifyRows(tabComp->getCurrentTabIndex(), *functionRowData[tabComp->getCurrentTabIndex()]); | |||
tables[tabComp->getCurrentTabIndex()]->repaintRow(sparseSet[i]); | |||
tables[tabComp->getCurrentTabIndex()]->updateContent(); | |||
tables[tabComp->getCurrentTabIndex()]->repaint(); | |||
} | |||
} | |||
else{ | |||
functionRowData[tabComp->getCurrentTabIndex()]->add(file.getFullPathName()); | |||
tablesList[tabComp->getCurrentTabIndex()]->addOrModifyRows(tabComp->getCurrentTabIndex(), *functionRowData[tabComp->getCurrentTabIndex()]); | |||
tables[tabComp->getCurrentTabIndex()]->updateContent(); | |||
} | |||
void DirectoryContentsComponent::updateSelection(const File& file) | |||
{ | |||
//update the number of rows in our listbox passing | |||
if(tables[tabComp->getCurrentTabIndex()]->getNumSelectedRows()>0) | |||
{ | |||
SparseSet<int> sparseSet = tables[tabComp->getCurrentTabIndex()]->getSelectedRows(); | |||
for(int i=0; i<sparseSet.size(); i++) | |||
{ | |||
functionRowData[tabComp->getCurrentTabIndex()]->getReference(sparseSet[i])= file.getFullPathName(); | |||
tablesList[tabComp->getCurrentTabIndex()]->addOrModifyRows(tabComp->getCurrentTabIndex(), *functionRowData[tabComp->getCurrentTabIndex()]); | |||
tables[tabComp->getCurrentTabIndex()]->repaintRow(sparseSet[i]); | |||
tables[tabComp->getCurrentTabIndex()]->updateContent(); | |||
tables[tabComp->getCurrentTabIndex()]->repaint(); | |||
} | |||
} | |||
else | |||
{ | |||
functionRowData[tabComp->getCurrentTabIndex()]->add(file.getFullPathName()); | |||
tablesList[tabComp->getCurrentTabIndex()]->addOrModifyRows(tabComp->getCurrentTabIndex(), *functionRowData[tabComp->getCurrentTabIndex()]); | |||
tables[tabComp->getCurrentTabIndex()]->updateContent(); | |||
} | |||
} | |||
//==================================================================================== |
@@ -4,7 +4,7 @@ | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
@@ -27,152 +27,166 @@ | |||
//============================================================================== | |||
/* one of these is fitted inside each cell of the table. It contains a text editor | |||
* for the functoin tables number, and a string displaying the file name */ | |||
//============================================================================== | |||
//============================================================================== | |||
class listBoxItem : public Component | |||
{ | |||
String text; | |||
Colour highlightColour; | |||
int ftableNumber; | |||
ScopedPointer<LookAndFeel_V1> oldSchool; | |||
ScopedPointer<TextEditor> textEditor; | |||
String text; | |||
Colour highlightColour; | |||
int ftableNumber; | |||
ScopedPointer<LookAndFeel_V1> oldSchool; | |||
ScopedPointer<TextEditor> textEditor; | |||
public: | |||
listBoxItem():highlightColour(Colours::white), isHighlighted(false){ | |||
oldSchool = new LookAndFeel_V1(); | |||
textEditor = new TextEditor(); | |||
setInterceptsMouseClicks(false, true); | |||
textEditor->setLookAndFeel(oldSchool); | |||
addAndMakeVisible(textEditor); | |||
setSize(getWidth(), 50); | |||
} | |||
~listBoxItem(){ } | |||
//paint out | |||
void paint(Graphics &g){ | |||
g.fillAll(Colours::black.withAlpha(.5f)); | |||
g.setColour(highlightColour); | |||
g.drawRect(1, 1, getWidth()-1, getHeight()-1, 2); | |||
g.setColour(Colours::whitesmoke); | |||
g.drawText (text, 55, 0, getWidth() - 4, getHeight(), Justification::centredLeft, true); | |||
} | |||
void resized(){ | |||
textEditor->setBounds(3, 3, 40, getHeight()-5); | |||
} | |||
void setText(int _ftableNumber, String _text){ | |||
text = _text; | |||
textEditor->setText(String(_ftableNumber)); | |||
} | |||
bool isHighlighted; | |||
listBoxItem():highlightColour(Colours::white), isHighlighted(false) | |||
{ | |||
oldSchool = new LookAndFeel_V1(); | |||
textEditor = new TextEditor(); | |||
setInterceptsMouseClicks(false, true); | |||
textEditor->setLookAndFeel(oldSchool); | |||
addAndMakeVisible(textEditor); | |||
setSize(getWidth(), 50); | |||
} | |||
~listBoxItem() { } | |||
//paint out | |||
void paint(Graphics &g) | |||
{ | |||
g.fillAll(Colours::black.withAlpha(.5f)); | |||
g.setColour(highlightColour); | |||
g.drawRect(1, 1, getWidth()-1, getHeight()-1, 2); | |||
g.setColour(Colours::whitesmoke); | |||
g.drawText (text, 55, 0, getWidth() - 4, getHeight(), Justification::centredLeft, true); | |||
} | |||
void resized() | |||
{ | |||
textEditor->setBounds(3, 3, 40, getHeight()-5); | |||
} | |||
void setText(int _ftableNumber, String _text) | |||
{ | |||
text = _text; | |||
textEditor->setText(String(_ftableNumber)); | |||
} | |||
bool isHighlighted; | |||
}; | |||
//============================================================================== | |||
/* this is the table list box model, it' gets passed to our TableListBox object | |||
/* this is the table list box model, it' gets passed to our TableListBox object | |||
this class can send action messages to MainContentComponent whenever something | |||
happens to one of its cells...*/ | |||
//============================================================================== | |||
//============================================================================== | |||
class FunctionTableList : public TableListBoxModel, | |||
public ActionBroadcaster | |||
public ActionBroadcaster | |||
{ | |||
public: | |||
FunctionTableList():font(14.f), rowData(), numHighlighted(0){ | |||
numRows=0; | |||
ftableCounter=0; | |||
} | |||
~FunctionTableList(){ | |||
listBoxItems.clear(); | |||
} | |||
void paintRowBackground (Graphics& g, int rowNumber, int width, int height, bool rowIsSelected) | |||
{ | |||
g.fillAll (CabbageUtils::getBackgroundSkin()); | |||
g.setFont (font); | |||
g.setColour(Colours::white); | |||
//g.drawText (rowData[rowNumber], 2, 0, width - 4, height, Justification::centredLeft, true); | |||
FunctionTableList():font(14.f), rowData(), numHighlighted(0) | |||
{ | |||
numRows=0; | |||
ftableCounter=0; | |||
} | |||
~FunctionTableList() | |||
{ | |||
listBoxItems.clear(); | |||
} | |||
void paintRowBackground (Graphics& g, int rowNumber, int width, int height, bool rowIsSelected) | |||
{ | |||
g.fillAll (CabbageUtils::getBackgroundSkin()); | |||
g.setFont (font); | |||
g.setColour(Colours::white); | |||
//g.drawText (rowData[rowNumber], 2, 0, width - 4, height, Justification::centredLeft, true); | |||
if (rowIsSelected) | |||
g.fillAll (Colours::cornflowerblue); | |||
} | |||
//add or modify exiting funcoitn table entries | |||
void addOrModifyRows(int _bankNumber, StringArray functionRows){ | |||
rowData.clear(); | |||
rowData = functionRows; | |||
bankNumber = _bankNumber+1; | |||
ftableCounter = 0; | |||
numRows = rowData.size(); | |||
} | |||
// This is overloaded from TableListBoxModel, and must update any custom components that we're using | |||
Component* refreshComponentForCell (int rowNumber, int columnId, bool /*isRowSelected*/, | |||
Component* existingComponentToUpdate) | |||
{ | |||
if (columnId == 1) // If it's the main column, we'll return our custom component.. | |||
{ | |||
listBoxItem* boxItem = (listBoxItem*) existingComponentToUpdate; | |||
// If an existing component is being passed-in for updating, we'll re-use it, but | |||
// if not, we'll have to create one. | |||
if (boxItem == 0){ | |||
boxItem = new listBoxItem(); | |||
} | |||
boxItem->setText(rowNumber+(bankNumber*50), rowData[rowNumber]); | |||
return boxItem; | |||
} | |||
else | |||
{ | |||
// for any other column, just return 0, as we'll be painting these columns directly. | |||
jassert (existingComponentToUpdate == 0); | |||
return 0; | |||
} | |||
} | |||
//determine actions to take place when users click on a cell... | |||
void cellClicked (int rowNumber, int columnId, const MouseEvent &e){ | |||
if(e.mods.isRightButtonDown()){ | |||
PopupMenu m; | |||
CabbageLookAndFeel cLAK; | |||
m.setLookAndFeel(&cLAK); | |||
m.addItem(1, "Delete selected"); | |||
int choice = m.show(); | |||
if(choice==1) | |||
sendActionMessage("delete selected"); | |||
} | |||
} | |||
void backgroundClicked(){ | |||
sendActionMessage("deselect"); | |||
} | |||
int getNumRows(){ | |||
return numRows; | |||
} | |||
void setNumRows(int _numRows){ | |||
//add or modify exiting funcoitn table entries | |||
void addOrModifyRows(int _bankNumber, StringArray functionRows) | |||
{ | |||
rowData.clear(); | |||
rowData = functionRows; | |||
bankNumber = _bankNumber+1; | |||
ftableCounter = 0; | |||
numRows = rowData.size(); | |||
} | |||
// This is overloaded from TableListBoxModel, and must update any custom components that we're using | |||
Component* refreshComponentForCell (int rowNumber, int columnId, bool /*isRowSelected*/, | |||
Component* existingComponentToUpdate) | |||
{ | |||
if (columnId == 1) // If it's the main column, we'll return our custom component.. | |||
{ | |||
listBoxItem* boxItem = (listBoxItem*) existingComponentToUpdate; | |||
// If an existing component is being passed-in for updating, we'll re-use it, but | |||
// if not, we'll have to create one. | |||
if (boxItem == 0) | |||
{ | |||
boxItem = new listBoxItem(); | |||
} | |||
boxItem->setText(rowNumber+(bankNumber*50), rowData[rowNumber]); | |||
return boxItem; | |||
} | |||
else | |||
{ | |||
// for any other column, just return 0, as we'll be painting these columns directly. | |||
jassert (existingComponentToUpdate == 0); | |||
return 0; | |||
} | |||
} | |||
//determine actions to take place when users click on a cell... | |||
void cellClicked (int rowNumber, int columnId, const MouseEvent &e) | |||
{ | |||
if(e.mods.isRightButtonDown()) | |||
{ | |||
PopupMenu m; | |||
CabbageLookAndFeel cLAK; | |||
m.setLookAndFeel(&cLAK); | |||
m.addItem(1, "Delete selected"); | |||
int choice = 0;//m.show(); | |||
if(choice==1) | |||
sendActionMessage("delete selected"); | |||
} | |||
} | |||
void backgroundClicked() | |||
{ | |||
sendActionMessage("deselect"); | |||
} | |||
int getNumRows() | |||
{ | |||
return numRows; | |||
} | |||
void setNumRows(int _numRows) | |||
{ | |||
numRows = _numRows; | |||
} | |||
void paintCell(juce::Graphics& g, int, int, int, int, bool){ | |||
g.fillAll(Colours::pink); | |||
} | |||
void paintCell(juce::Graphics& g, int, int, int, int, bool) | |||
{ | |||
g.fillAll(Colours::pink); | |||
} | |||
private: | |||
Font font; | |||
StringArray highlightedItems; | |||
int numRows; | |||
int ftableCounter; | |||
int bankNumber; | |||
int numHighlighted; | |||
StringArray rowData; | |||
OwnedArray<listBoxItem> listBoxItems; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FunctionTableList) | |||
StringArray highlightedItems; | |||
int numRows; | |||
int ftableCounter; | |||
int bankNumber; | |||
int numHighlighted; | |||
StringArray rowData; | |||
OwnedArray<listBoxItem> listBoxItems; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FunctionTableList) | |||
}; | |||
//============================================================================== | |||
@@ -183,34 +197,34 @@ private: | |||
//============================================================================== | |||
class DirectoryContentsComponent : public Component, | |||
public FileBrowserListener, | |||
public ButtonListener, | |||
public ActionListener, | |||
public ActionBroadcaster | |||
public FileBrowserListener, | |||
public ButtonListener, | |||
public ActionListener, | |||
public ActionBroadcaster | |||
{ | |||
OwnedArray<FunctionTableList> tablesList; | |||
OwnedArray<TableListBox> tables; | |||
OwnedArray<FunctionTableList> tablesList; | |||
OwnedArray<TableListBox> tables; | |||
ScopedPointer<CabbageLookAndFeel> lookAndFeel; | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
StretchableLayoutManager horizontalLayout; | |||
ScopedPointer<Viewport> viewPort; | |||
StretchableLayoutManager horizontalLayout; | |||
ScopedPointer<Viewport> viewPort; | |||
ScopedPointer<StretchableLayoutResizerBar> horizontalDividerBar; | |||
ScopedPointer<TabbedComponent> tabComp; | |||
ScopedPointer<TextEditor> editor; | |||
ScopedPointer<TextButton> updateTablesButton; | |||
ScopedPointer<ToggleButton> autoUpdate; | |||
ScopedPointer<TextButton> addBankButton; | |||
StringArray functionTableStrings; | |||
DirectoryContentsList directoryList; | |||
TimeSliceThread thread; | |||
int ftableCounter; | |||
ScopedPointer<FileTreeComponent> fileTreeComp; | |||
WildcardFileFilter filter; | |||
//Array of stireng arrays.... | |||
OwnedArray<StringArray> functionRowData; | |||
String fileTypes, rootDir; | |||
StringArray previousScoreEvents; | |||
ScopedPointer<TabbedComponent> tabComp; | |||
ScopedPointer<TextEditor> editor; | |||
ScopedPointer<TextButton> updateTablesButton; | |||
ScopedPointer<ToggleButton> autoUpdate; | |||
ScopedPointer<TextButton> addBankButton; | |||
StringArray functionTableStrings; | |||
DirectoryContentsList directoryList; | |||
TimeSliceThread thread; | |||
int ftableCounter; | |||
ScopedPointer<FileTreeComponent> fileTreeComp; | |||
WildcardFileFilter filter; | |||
//Array of stireng arrays.... | |||
OwnedArray<StringArray> functionRowData; | |||
String fileTypes, rootDir; | |||
StringArray previousScoreEvents; | |||
public: | |||
//============================================================================== | |||
DirectoryContentsComponent(String dir, String files); | |||
@@ -218,32 +232,34 @@ public: | |||
bool isFileSuitable(const juce::File&) const | |||
{ | |||
return true; | |||
} | |||
{ | |||
return true; | |||
} | |||
bool isDirectorySuitable(const juce::File&) const | |||
{ | |||
return true; | |||
} | |||
void fileDoubleClicked (const File& file){ | |||
Logger::writeToLog("file double clicked"); | |||
} | |||
void browserRootChanged (const File&) { | |||
Logger::writeToLog("root changed"); | |||
} | |||
void updateSelection(const File& file); | |||
void showFile (const File& file){} | |||
{ | |||
return true; | |||
} | |||
void fileDoubleClicked (const File& file) | |||
{ | |||
Logger::writeToLog("file double clicked"); | |||
} | |||
void browserRootChanged (const File&) | |||
{ | |||
Logger::writeToLog("root changed"); | |||
} | |||
void updateSelection(const File& file); | |||
void showFile (const File& file) {} | |||
void paint (Graphics&); | |||
void resized(); | |||
void buttonClicked(Button* button); | |||
void fileClicked(const File& file, const MouseEvent& e); | |||
void actionListenerCallback(const juce::String& string); | |||
void selectionChanged(); | |||
const StringArray getFunctionTables(); | |||
void resized(); | |||
void buttonClicked(Button* button); | |||
void fileClicked(const File& file, const MouseEvent& e); | |||
void actionListenerCallback(const juce::String& string); | |||
void selectionChanged(); | |||
const StringArray getFunctionTables(); | |||
//============================================================================== | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryContentsComponent) | |||
@@ -30,68 +30,399 @@ | |||
extern ApplicationProperties* appProperties; | |||
extern CabbageTimer* cabbageTimer; | |||
class CsoundCodeEditor : public CodeEditorComponent, | |||
public ActionBroadcaster, | |||
public CodeDocument::Listener | |||
{ | |||
public: | |||
CodeDocument::Position positionInCode; | |||
CsoundCodeEditor(String type, CodeDocument &document, CodeTokeniser *codeTokeniser); | |||
class FlatButton; | |||
class HelpComp; | |||
class SearchReplaceComp; | |||
~CsoundCodeEditor(); | |||
class CsoundCodeEditorComponenet : public CodeEditorComponent, | |||
public ActionBroadcaster, | |||
public ChangeBroadcaster, | |||
public CodeDocument::Listener | |||
{ | |||
public: | |||
CodeDocument::Position positionInCode; | |||
CsoundCodeEditorComponenet(String type, CodeDocument &document, CodeTokeniser *codeTokeniser); | |||
~CsoundCodeEditorComponenet(); | |||
bool keyPressed (const KeyPress& key); | |||
void handleTabKey(String direction); | |||
void toggleComments(); | |||
void handleDirectionKey() {} | |||
void handleEscapeKey() | |||
{ | |||
if(type=="python") | |||
sendActionMessage("make python invisible"); | |||
if(type=="csound") | |||
sendActionMessage("make popup invisible"); | |||
} | |||
bool keyPressed (const KeyPress& key); | |||
void handleTabKey(String direction); | |||
void toggleComments(); | |||
enum DragType | |||
{ | |||
notDragging, | |||
draggingSelectionStart, | |||
draggingSelectionEnd | |||
}; | |||
DragType dragType; | |||
void handleDirectionKey(){} | |||
void editorHasScrolled(); | |||
bool skipBackwardsToPreviousTab(); | |||
bool moveCaretLeft (const bool moveInWholeWordSteps, const bool selecting); | |||
bool moveCaretRight (const bool moveInWholeWordSteps, const bool selecting); | |||
bool deleteBackwards (const bool moveInWholeWordSteps); | |||
bool deleteForwards (const bool moveInWholeWordSteps); | |||
void handleReturnKey (); | |||
void addPopupMenuItems (PopupMenu &menuToAddTo, const MouseEvent *mouseClickEvent); | |||
void performPopupMenuAction (int menuItemID); | |||
void modifyInstrumentBreakpoint(bool remove); | |||
String getLineText(); | |||
String getTempChannelInstr(); | |||
String getSelectedText(); | |||
String getInstrumentText(); | |||
Rectangle<int> getCaretPoisition(); | |||
StringArray getSelectedTextArray(); | |||
void addRepoToSettings(); | |||
void insertText(String text); | |||
void addToRepository(); | |||
StringArray repoEntries; | |||
String getAllText(); | |||
void setAllText(String text); | |||
void highlightLine(String line); | |||
void highlightLines(int firstLine, int lastLine); | |||
void codeDocumentTextDeleted(int,int); | |||
void codeDocumentTextInserted(const juce::String &,int); | |||
bool pasteFromClipboard(); | |||
void insertNewLine(String text); | |||
void changeListenerCallback(juce::ChangeBroadcaster* source); | |||
void enableColumnEditMode(bool enable); | |||
void setOpcodeStrings(String opcodes) | |||
{ | |||
opcodeStrings.addLines(opcodes); | |||
} | |||
void handleEscapeKey(){ | |||
if(type=="python") | |||
sendActionMessage("make python invisible"); | |||
if(type=="csound") | |||
sendActionMessage("make popup invisible"); | |||
} | |||
void handleReturnKey (); | |||
void addPopupMenuItems (PopupMenu &menuToAddTo, const MouseEvent *mouseClickEvent); | |||
void performPopupMenuAction (int menuItemID); | |||
String getLineText(); | |||
String getTempChannelInstr(); | |||
String getSelectedText(); | |||
String getInstrumentText(); | |||
Rectangle<int> getCaretPoisition(); | |||
StringArray getSelectedTextArray(); | |||
void addRepoToSettings(); | |||
void insertText(String text); | |||
void addToRepository(); | |||
StringArray repoEntries; | |||
String getAllText(); | |||
void setAllText(String text); | |||
void highlightLine(String line); | |||
void codeDocumentTextDeleted(int,int); | |||
void codeDocumentTextInserted(const juce::String &,int); | |||
bool textChanged; | |||
void insertNewLine(String text); | |||
void setOpcodeStrings(String opcodes){ | |||
opcodeStrings.addLines(opcodes); | |||
} | |||
void insertTextAtCaret (const String &textToInsert); | |||
void updateCaretPosition(); | |||
void insertMultiLineTextAtCaret(String text); | |||
String getOpcodeToken(int index) | |||
{ | |||
return opcodeTokens[index]; | |||
} | |||
bool columnEditMode; | |||
void mouseWheelMove (const MouseEvent&, const MouseWheelDetails&); | |||
void updateCaretPosition(); | |||
void insertMultiTextAtCaret(String text); | |||
String getOpcodeToken(int index){ | |||
return opcodeTokens[index]; | |||
} | |||
private: | |||
int xPos, yPos, prevXpos; | |||
CodeDocument::Position pos1, pos2; | |||
Colour selectedColour; | |||
String type; | |||
StringArray opcodeStrings; | |||
StringArray opcodeTokens; | |||
}; | |||
private: | |||
int xPos, yPos, prevXpos; | |||
CodeDocument::Position pos1, pos2; | |||
Colour selectedColour; | |||
int fontSize; | |||
String font; | |||
String type; | |||
StringArray opcodeStrings; | |||
StringArray opcodeTokens; | |||
}; | |||
//================================================================= | |||
class CsoundCodeEditor : public Component, | |||
public ChangeListener, | |||
public ActionListener, | |||
public ActionBroadcaster | |||
{ | |||
bool showTabButtons; | |||
bool showInstrumentButtons; | |||
int instrWidth; | |||
int searchStartIndex; | |||
bool highlightedWord; | |||
Array<int> breakpointLines; | |||
public: | |||
CsoundCodeEditor(CodeDocument &document, CodeTokeniser *codeTokeniser); | |||
~CsoundCodeEditor(); | |||
int saveAllFiles(); | |||
void setSavePoint(); | |||
void changeListenerCallback(juce::ChangeBroadcaster* source); | |||
String getAllText(); | |||
void setAllText(String text); | |||
void highlightLine(String line); | |||
void showTab(String name); | |||
void showInstrs(bool show); | |||
int findText(String text); | |||
String getCurrentSelectedText(); | |||
int replaceText(String text, String replaceWith); | |||
void actionListenerCallback(const juce::String&); | |||
void closeCurrentFile(); | |||
void setActiveTab(int index); | |||
void saveAuxFile(); | |||
OwnedArray<FlatButton> tabButtons; | |||
OwnedArray<FlatButton> instrButtons; | |||
ScopedPointer<HelpComp> helpComp; | |||
ScopedPointer<SearchReplaceComp> searchReplaceComp; | |||
bool textChanged; | |||
OwnedArray<CsoundCodeEditorComponenet> editor; | |||
int currentEditor; | |||
void addNewFile(File newFile); | |||
void paint(Graphics& g); | |||
void resized(); | |||
Range<int> getCabbageSectionRange(); | |||
OwnedArray<CodeDocument> codeDocuments; | |||
CsoundTokeniser codeToker; | |||
StringArray openFiles; | |||
int documentIndex; | |||
void enableColumnEdit(bool enable); | |||
}; | |||
class FlatButton : public Component, | |||
public ChangeBroadcaster | |||
{ | |||
public: | |||
FlatButton(String name, int currentTab, String type): name(name), | |||
type(type), | |||
currentTab(currentTab), | |||
isMouseDown(false), | |||
genericColour(Colours::brown) | |||
{ | |||
setName(name); | |||
if(name=="Csound code") | |||
active = true; | |||
else | |||
active=false; | |||
} | |||
~FlatButton() {} | |||
void mouseDown(const MouseEvent& event) | |||
{ | |||
sendChangeMessage(); | |||
Logger::writeToLog("mouseDown"); | |||
isMouseDown = true; | |||
repaint(); | |||
} | |||
void mouseUp(const MouseEvent& event) | |||
{ | |||
Logger::writeToLog("mouseUp"); | |||
isMouseDown = false; | |||
repaint(); | |||
} | |||
void isActive(bool isActive) | |||
{ | |||
active = isActive; | |||
repaint(); | |||
} | |||
void paint(Graphics &g) | |||
{ | |||
g.fillAll(Colour(20, 20, 20)); | |||
if(type=="Native") | |||
{ | |||
if(name.contains("code")) | |||
{ | |||
if(active) | |||
g.setColour(Colours::cornflowerblue.darker(.4f)); | |||
else | |||
g.setColour(Colours::cornflowerblue.darker(.9f)); | |||
g.fillRoundedRectangle(getLocalBounds().toFloat(), 5.f); | |||
if(active) | |||
g.setColour(Colours::white); | |||
else | |||
g.setColour(Colours::white.darker(.9f)); | |||
g.drawRoundedRectangle(getLocalBounds().toFloat(), 5.f, 2); | |||
g.drawFittedText(name, getLocalBounds(), Justification::centred, 1, 1.f); | |||
} | |||
} | |||
else if(type=="Aux") | |||
{ | |||
if(!active) | |||
g.setColour(genericColour.darker(.9f)); | |||
else | |||
g.setColour(genericColour.darker(.2f)); | |||
g.fillRoundedRectangle(0, 0, getWidth(), getHeight(), 5.f); | |||
if(!active) | |||
g.setColour(Colours::white.darker(.9f)); | |||
else | |||
g.setColour(Colours::white); | |||
g.drawRoundedRectangle(0, 0, getWidth(), getHeight(), 5.f, 2); | |||
g.drawFittedText(name, 0, 0, getWidth(), getHeight(), Justification::centred, 1, 1.f); | |||
} | |||
else | |||
{ | |||
float number = name.substring(6, 5).getDoubleValue(); | |||
if(isMouseDown) | |||
g.setColour(genericColour.darker(.2f)); | |||
else | |||
g.setColour(genericColour.darker(.6f)); | |||
g.fillRoundedRectangle(getLocalBounds().toFloat(), 5.f); | |||
g.setColour(Colours::white); | |||
g.drawRoundedRectangle(getLocalBounds().toFloat(), 5.f, 2); | |||
g.drawFittedText(name, getLocalBounds(), Justification::centred, 1, 1.f); | |||
} | |||
} | |||
String name; | |||
int currentTab; | |||
bool active; | |||
bool isMouseDown; | |||
String type; | |||
Colour genericColour; | |||
}; | |||
//============================================================ | |||
// class for displaying popup text | |||
//============================================================ | |||
class HelpComp : public Component | |||
{ | |||
public: | |||
HelpComp():firstTime(true) | |||
{ | |||
this->setInterceptsMouseClicks(false, false); | |||
setSize(10, 50); | |||
} | |||
~HelpComp() {}; | |||
void setText(String _info, String _syntax) | |||
{ | |||
syntax=_syntax; | |||
info=_info; | |||
repaint(); | |||
} | |||
void paint(Graphics& g) | |||
{ | |||
g.fillAll(Colour::fromRGB(10, 10, 10)); | |||
g.setColour(Colours::yellow); | |||
g.drawRect(0, 0, getWidth()-1, getHeight()-1, 1); | |||
g.setFont(14); | |||
g.setColour(Colours::cornflowerblue); | |||
g.drawFittedText(syntax, 10, 5, getWidth(), getHeight(), Justification::topLeft, 100, 1); | |||
int width = Font(14).getStringWidth(syntax); | |||
g.setColour(Colours::white); | |||
g.drawFittedText(info, width+30, 4, getWidth(), getHeight(), Justification::topLeft, 100, 1); | |||
} | |||
void resized() | |||
{ | |||
setSize(getWidth(), getHeight()); | |||
} | |||
bool firstTime; | |||
private: | |||
String syntax, info; | |||
}; | |||
//============================================================ | |||
// class for displaying popup text | |||
//============================================================ | |||
class SearchReplaceComp : public Component, | |||
public TextEditor::Listener, | |||
public ChangeBroadcaster | |||
{ | |||
public: | |||
ScopedPointer<FlatButton> searchButton, replaceAllButton, replaceOnceButton; | |||
SearchReplaceComp() | |||
{ | |||
addAndMakeVisible(searchEditor = new TextEditor("SearchEditor")); | |||
searchEditor->addListener(this); | |||
addAndMakeVisible(replaceEditor = new TextEditor("ReplaceWithEditor")); | |||
replaceEditor->addListener(this); | |||
addAndMakeVisible(searchButton = new FlatButton("Search", 0, "")); | |||
searchButton->setName("SearchButton"); | |||
addAndMakeVisible(replaceOnceButton = new FlatButton("Replace Once", 0, "")); | |||
replaceOnceButton->setName("ReplaceOnceButton"); | |||
replaceOnceButton->genericColour = Colours::cornflowerblue; | |||
addAndMakeVisible(replaceAllButton = new FlatButton("Replace All", 0, "")); | |||
replaceAllButton->genericColour = Colours::cornflowerblue; | |||
replaceAllButton->setName("ReplaceAllButton"); | |||
addAndMakeVisible(findLabel = new Label("FindLabel")); | |||
addAndMakeVisible(replaceLabel = new Label("ReplaceLabel")); | |||
replaceLabel->setText("Replace with:", dontSendNotification); | |||
replaceLabel->setColour(Label::textColourId, Colours::whitesmoke); | |||
findLabel->setText("Find:", dontSendNotification); | |||
findLabel->setColour(Label::textColourId, Colours::whitesmoke); | |||
replaceEditor->setColour(TextEditor::backgroundColourId, Colours::whitesmoke); | |||
replaceEditor->setColour(TextEditor::textColourId, Colours::black); | |||
replaceEditor->setColour(CaretComponent::caretColourId, Colours::black); | |||
searchEditor->setColour(TextEditor::backgroundColourId, Colours::whitesmoke); | |||
searchEditor->setColour(TextEditor::textColourId, Colours::black); | |||
searchEditor->setColour(CaretComponent::caretColourId, Colours::black); | |||
} | |||
~SearchReplaceComp() {}; | |||
void paint(Graphics& g) | |||
{ | |||
g.fillAll(CabbageUtils::getDarkerBackgroundSkin()); | |||
} | |||
void resized() | |||
{ | |||
findLabel->setBounds(0, 4, 30, 20); | |||
searchEditor->setBounds(35, 4, 150, 20); | |||
searchButton->setBounds(190, 4, 100, 20); | |||
replaceLabel->setBounds(295, 4, 50, 20); | |||
replaceEditor->setBounds(350, 4, 150, 20); | |||
replaceOnceButton->setBounds(505, 4, 100, 20); | |||
replaceAllButton->setBounds(610 , 4, 100, 20); | |||
} | |||
String getSearchText() | |||
{ | |||
return searchEditor->getText(); | |||
} | |||
void setSearchText(String text) | |||
{ | |||
if(! text.containsAnyOf ("\r\n")) | |||
searchEditor->setText(text); | |||
else | |||
searchEditor->setText(""); | |||
} | |||
String getReplaceText() | |||
{ | |||
return replaceEditor->getText(); | |||
} | |||
void textEditorReturnKeyPressed (TextEditor &editor) | |||
{ | |||
currentEditorName = editor.getName(); | |||
sendChangeMessage(); | |||
} | |||
String getCurrentTextEditor() | |||
{ | |||
return currentEditorName; | |||
} | |||
private: | |||
String currentEditorName; | |||
ScopedPointer<TextEditor> searchEditor, replaceEditor; | |||
ScopedPointer<Label> findLabel, replaceLabel; | |||
String syntax, info; | |||
}; | |||
#endif |
@@ -22,523 +22,227 @@ | |||
#include "CodeEditor.h" | |||
#include "KeyboardShortcuts.h" | |||
#include "SplitComponent.h" | |||
#include "../Plugin/CabbagePluginProcessor.h" | |||
//class LiveCsound; | |||
class PythonEditor; | |||
class PopupDisplay; | |||
//============================================================================== | |||
//Main window. This window holds a 2 textEditors. One for the code, and the other for | |||
//displaying Csound output messages | |||
//============================================================================== | |||
class CodeWindow : public DocumentWindow, | |||
public ApplicationCommandTarget, | |||
public MenuBarModel, | |||
public ActionListener, | |||
public ActionBroadcaster, | |||
public CodeDocument::Listener, | |||
public Timer | |||
//========== csound output console class ================= | |||
class CsoundOutputComponent : public Component | |||
{ | |||
ScopedPointer<TextEditor> textEditor; | |||
public: | |||
CodeWindow(String name); | |||
~CodeWindow(); | |||
CodeDocument csoundDoc; | |||
//============================================================================== | |||
StringArray getMenuBarNames() | |||
{ | |||
const char* const names[] = { "File", "Edit", "Help", 0 }; | |||
return StringArray (names); | |||
} | |||
//============================================================================== | |||
void getAllCommands (Array <CommandID>& commands) | |||
{ | |||
const CommandID ids[] = { | |||
CommandIDs::fileNew, | |||
CommandIDs::fileOpen, | |||
CommandIDs::fileSave, | |||
CommandIDs::fileSaveAs, | |||
CommandIDs::fileQuit, | |||
CommandIDs::fileKeyboardShorts, | |||
CommandIDs::editUndo, | |||
CommandIDs::editCopy, | |||
CommandIDs::editCut, | |||
CommandIDs::editPaste, | |||
CommandIDs::editRedo, | |||
CommandIDs::editToggleComments, | |||
CommandIDs::editZoomIn, | |||
CommandIDs::editZoomOut, | |||
CommandIDs::whiteBackground, | |||
CommandIDs::blackBackground, | |||
CommandIDs::startSession, | |||
CommandIDs::insertFromRepo, | |||
CommandIDs::AudioSettings, | |||
CommandIDs::addFromRepo, | |||
CommandIDs::insertRecentEvent, | |||
CommandIDs::openPythonEditor, | |||
CommandIDs::commOrchUpdateInstrument, | |||
CommandIDs::commOrchUpdateMultiLine, | |||
CommandIDs::commOrchUpdateSingleLine, | |||
CommandIDs::commScoUpdateMultiLine, | |||
CommandIDs::commScoUpdateSingleLine, | |||
CommandIDs::commOrcUpdateChannel, | |||
CommandIDs::viewCsoundHelp, | |||
CommandIDs::viewCabbageHelp | |||
}; | |||
commands.addArray (ids, sizeof (ids) / sizeof (ids [0])); | |||
} | |||
//============================================================================== | |||
void menuItemSelected (int menuItemID, int topLevelMenuIndex){ | |||
if (menuItemID >= 100 && menuItemID < 200) | |||
{ | |||
RecentlyOpenedFilesList recentFiles; | |||
recentFiles.restoreFromString (appProperties->getUserSettings() | |||
->getValue ("recentlyOpenedFiles")); | |||
csdFile = recentFiles.getFile (menuItemID - 100); | |||
textEditor->getDocument().replaceAllContent(csdFile.loadFileAsString()); | |||
setName(csdFile.getFullPathName()); | |||
} | |||
} | |||
//============================================================================== | |||
void setFontSize(String zoom) | |||
{ | |||
if(zoom==String("in")) | |||
textEditor->setFont(Font(String("Courier New"), ++fontSize, 1)); | |||
else | |||
textEditor->setFont(Font(String("Courier New"), --fontSize, 1)); | |||
} | |||
//================= command methods ==================== | |||
ApplicationCommandTarget* getNextCommandTarget(){ | |||
return findFirstTargetParentComponent(); | |||
} | |||
void getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result); | |||
PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName); | |||
bool perform (const InvocationInfo& info); | |||
void toggleManuals(String manual); | |||
void setEditorColourScheme(String theme); | |||
void actionListenerCallback(const String &message); | |||
void timerCallback(); | |||
void toggleTextWindows(); | |||
Rectangle<int> getCaretScreenPosition(){ | |||
Rectangle<int> rect(textEditor->getCaretPoisition()); | |||
rect.setLeft(rect.getX()+this->getTopLevelComponent()->getX()+100); | |||
rect.setTop(rect.getY()+this->getTopLevelComponent()->getY()+45); | |||
return rect; | |||
} | |||
void closeButtonPressed(){ | |||
//JUCEApplication::getInstance()->systemRequestedQuit(); | |||
this->setVisible(false); | |||
} | |||
void codeDocumentTextDeleted(int,int){} | |||
void codeDocumentTextInserted(const juce::String &,int){} | |||
void codeDocumentChanged (const CodeDocument::Position &affectedTextStart, const CodeDocument::Position &affectedTextEnd); | |||
void insertFromRepo(); | |||
void setText(String file){ | |||
csoundDoc.replaceAllContent(file); | |||
} | |||
String getText(){ | |||
return csoundDoc.getAllContent(); | |||
} | |||
void setColourScheme(String theme){ | |||
if(theme=="white"){ | |||
textEditor->setColourScheme(csoundToker.getDefaultColourScheme()); | |||
textEditor->setColour(CodeEditorComponent::backgroundColourId, Colours::white); | |||
textEditor->setColour(CaretComponent::caretColourId, Colours::black); | |||
textEditor->setColour(CodeEditorComponent::highlightColourId, Colours::cornflowerblue); | |||
appProperties->getUserSettings()->setValue("EditorColourScheme", 0); | |||
} | |||
else if(theme=="dark"){ | |||
textEditor->setColourScheme(csoundToker.getDarkColourScheme()); | |||
textEditor->setColour(CaretComponent::caretColourId, Colours::white); | |||
textEditor->setColour(CodeEditorComponent::backgroundColourId, Colour::fromRGB(20, 20, 20)); | |||
textEditor->setColour(CodeEditorComponent::highlightColourId, Colours::green.withAlpha(.6f)); | |||
appProperties->getUserSettings()->setValue("EditorColourScheme", 1); | |||
} | |||
} | |||
void newFile(String type); | |||
bool unSaved; | |||
StringArray recentEvents; | |||
//ScopedPointer<CabbageLookAndFeel> lookAndFeel; | |||
String csoundOutputText; | |||
bool firstTime; | |||
String debugMessage; | |||
bool showOutput; | |||
CommandManager commandManager; | |||
File csdFile; | |||
int fontSize; | |||
String ASCIICabbage; | |||
StringArray opcodeStrings; | |||
ScopedPointer<PopupDisplay> popupDisplay; | |||
CsoundCodeEditor* textEditor; | |||
CsoundTokeniser csoundToker; | |||
Font font; | |||
ScopedPointer<WebBrowserComponent> htmlHelp; | |||
bool showingHelp; | |||
}; | |||
CsoundOutputComponent(String title): Component() | |||
{ | |||
textEditor = new TextEditor(); | |||
textEditor->setColour(Label::outlineColourId, Colours::white); | |||
textEditor->setColour(TextEditor::backgroundColourId, CabbageUtils::getDarkerBackgroundSkin()); | |||
textEditor->setColour(TextEditor::textColourId, Colours::cornflowerblue); | |||
textEditor->setMultiLine(true); | |||
textEditor->setFont(Font("Arial", 14, 0)); | |||
addAndMakeVisible(textEditor, true); | |||
setText("hewe;roiuew asdfhsa ldkjfhsd lfauskdhf lsadiufh dslifuhsadlifu hdsaflisaud hflidsau hflidsa uf"); | |||
}; | |||
~CsoundOutputComponent() {}; | |||
void setText(String text) | |||
{ | |||
textEditor->setColour(TextEditor::textColourId, Colours::cornflowerblue); | |||
textEditor->setText(text); | |||
textEditor->setCaretPosition(textEditor->getText().length()); | |||
} | |||
String getText() | |||
{ | |||
return textEditor->getText(); | |||
} | |||
void resized() | |||
{ | |||
textEditor->setBounds(20, 21, getWidth()-25, getHeight()-30); | |||
} | |||
void paint(Graphics& g) | |||
{ | |||
g.fillAll(CabbageUtils::getDarkerBackgroundSkin()); | |||
g.setColour(Colours::white); | |||
g.drawRoundedRectangle(getLocalBounds().toFloat(), 2, 2); | |||
g.drawFittedText("Csound output", getLocalBounds().withHeight(18), Justification::centred, 1, 1.f); | |||
} | |||
//============================================================ | |||
// window for Python editor | |||
//============================================================ | |||
class PythonEditor: public DocumentWindow, | |||
public ActionListener, | |||
public ActionBroadcaster | |||
{ | |||
public: | |||
PythonEditor(String name):DocumentWindow (name, Colours::black, | |||
DocumentWindow::closeButton) | |||
{ | |||
textEditor = new CsoundCodeEditor("python", csoundDocu, &csoundToker); | |||
textEditor->setColour(TextEditor::textColourId, Colours::white); | |||
textEditor->setFont(Font(String("Courier New"), 15, 1)); | |||
textEditor->addActionListener(this); | |||
textEditor->setSize(600, 400); | |||
if(!appProperties->getUserSettings()->getValue("EditorColourScheme", var(0)).getIntValue()) | |||
setEditorColourScheme("white"); | |||
else if(appProperties->getUserSettings()->getValue("EditorColourScheme", var(0)).getIntValue()) | |||
setEditorColourScheme("dark"); | |||
centreWithSize(600, 400); | |||
setContentNonOwned(textEditor, true); | |||
setResizable(true, false); | |||
} | |||
~PythonEditor() | |||
{ | |||
delete textEditor; | |||
} | |||
void codeDocumentChanged (const CodeDocument::Position &affectedTextStart, const CodeDocument::Position &affectedTextEnd) | |||
{ | |||
} | |||
void actionListenerCallback(const String &message) | |||
{ | |||
if(message=="make invisible"){ | |||
//this->setVisible(false); | |||
sendActionMessage("sendPythonEvent"); | |||
//if(textEditor->getm) | |||
} | |||
} | |||
void closeButtonPressed(){ | |||
setVisible(false); | |||
} | |||
void setEditorColourScheme(String theme){ | |||
if(theme=="white"){ | |||
textEditor->setColourScheme(csoundToker.getDefaultColourScheme()); | |||
textEditor->setColour(CodeEditorComponent::backgroundColourId, Colours::white); | |||
textEditor->setColour(CaretComponent::caretColourId, Colours::black); | |||
textEditor->setColour(CodeEditorComponent::highlightColourId, Colours::cornflowerblue); | |||
appProperties->getUserSettings()->setValue("EditorColourScheme", 0); | |||
} | |||
else if(theme=="dark"){ | |||
textEditor->setColourScheme(csoundToker.getDarkColourScheme()); | |||
textEditor->setColour(CaretComponent::caretColourId, Colours::white); | |||
textEditor->setColour(CodeEditorComponent::backgroundColourId, Colour::fromRGB(20, 20, 20)); | |||
textEditor->setColour(CodeEditorComponent::highlightColourId, Colours::green.withAlpha(.6f)); | |||
appProperties->getUserSettings()->setValue("EditorColourScheme", 1); | |||
} | |||
} | |||
void codeDocumentTextDeleted(int,int){} | |||
void codeDocumentTextInserted(const juce::String &,int){} | |||
CsoundCodeEditor* textEditor; | |||
CodeDocument csoundDocu; | |||
PythonTokeniser csoundToker; | |||
}; | |||
//============================================================ | |||
// audio settings class (not currently used...) | |||
//============================================================ | |||
class AudioSettings: public Component, | |||
public ActionListener, | |||
public ActionBroadcaster | |||
//========== csound debugger output console class ================= | |||
class CsoundDebuggerComponent : public Component | |||
{ | |||
ScopedPointer<TextEditor> textEditor; | |||
public: | |||
AudioSettings(StringArray deviceStrings) | |||
{ | |||
addAndMakeVisible (label = new Label ("new label", | |||
"Sampling Rate")); | |||
label->setFont (Font (15.00f, Font::bold)); | |||
label->setJustificationType (Justification::centredLeft); | |||
label->setEditable (false, false, false); | |||
label->setColour (TextEditor::textColourId, Colours::lime); | |||
label->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (samplingRate = new ComboBox ("new combo box")); | |||
samplingRate->addItem("44100", 1); | |||
samplingRate->addItem("48000", 2); | |||
samplingRate->setSelectedId(1, dontSendNotification ); | |||
samplingRate->setEditableText (false); | |||
samplingRate->setJustificationType (Justification::centredLeft); | |||
samplingRate->setTextWhenNothingSelected (String::empty); | |||
samplingRate->setTextWhenNoChoicesAvailable ("(no choices)"); | |||
//samplingRate->addListener (this); | |||
addAndMakeVisible (label2 = new Label ("new label", | |||
"Ksmps")); | |||
label2->setFont (Font (20.00f, Font::bold)); | |||
label2->setJustificationType (Justification::centredLeft); | |||
label2->setEditable (false, false, false); | |||
label2->setColour (TextEditor::textColourId, Colours::lime); | |||
label2->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (ksmps = new ComboBox ("new combo box")); | |||
ksmps->addItem("32", 1); | |||
ksmps->addItem("64", 2); | |||
ksmps->addItem("128", 3); | |||
ksmps->addItem("512", 4); | |||
ksmps->addItem("1024", 5); | |||
ksmps->addItem("2048", 6); | |||
ksmps->addItem("4096", 7); | |||
ksmps->setSelectedId(2, dontSendNotification ); | |||
ksmps->setEditableText (false); | |||
ksmps->setJustificationType (Justification::centredLeft); | |||
ksmps->setTextWhenNothingSelected (String::empty); | |||
ksmps->setTextWhenNoChoicesAvailable ("(no choices)"); | |||
// ksmps->addListener (this); | |||
addAndMakeVisible (label3 = new Label ("new label", | |||
"Audio Device")); | |||
label3->setFont (Font (15.00f, Font::bold)); | |||
label3->setJustificationType (Justification::centredLeft); | |||
label3->setEditable (false, false, false); | |||
label3->setColour (TextEditor::textColourId, Colours::lime); | |||
label3->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (audioDevice = new ComboBox ("new combo box")); | |||
audioDevice->setEditableText (false); | |||
for(int i=0;i<deviceStrings.size();i++) | |||
audioDevice->addItem(deviceStrings[i], i+1); | |||
audioDevice->setSelectedId(deviceStrings.size(), dontSendNotification ); | |||
audioDevice->setJustificationType (Justification::centredLeft); | |||
audioDevice->setTextWhenNothingSelected (String::empty); | |||
audioDevice->setTextWhenNoChoicesAvailable ("(no choices)"); | |||
//audioDevice->addListener (this); | |||
addAndMakeVisible (label4 = new Label ("new label", | |||
"MIDI Device")); | |||
label4->setFont (Font (15.00f, Font::bold)); | |||
label4->setJustificationType (Justification::centredLeft); | |||
label4->setEditable (false, false, false); | |||
label4->setColour (TextEditor::textColourId, Colours::lime); | |||
label4->setColour (TextEditor::backgroundColourId, Colour (0x00000000)); | |||
addAndMakeVisible (midiDevice = new ComboBox ("new combo box")); | |||
midiDevice->setEditableText (false); | |||
midiDevice->setJustificationType (Justification::centredLeft); | |||
midiDevice->setTextWhenNothingSelected (String::empty); | |||
midiDevice->setTextWhenNoChoicesAvailable ("(no choices)"); | |||
//midiDevice->addListener (this); | |||
setSize(300, 200); | |||
} | |||
void actionListenerCallback(const String &message) | |||
{ | |||
if(message=="make invisible"){ | |||
//this->setVisible(false); | |||
sendActionMessage("sendPythonEvent"); | |||
} | |||
} | |||
void resized(){ | |||
label->setBounds (28, 16, 96, 24); | |||
samplingRate->setBounds (130, 16, 118, 24); | |||
label2->setBounds (58, 52, 80, 24); | |||
ksmps->setBounds (130, 52, 117, 24); | |||
label3->setBounds (41, 87, 80, 24); | |||
audioDevice->setBounds (130, 88, 117, 24); | |||
label4->setBounds (42, 122, 80, 24); | |||
midiDevice->setBounds (130, 121, 118, 24); | |||
} | |||
void paint(Graphics& g){ | |||
g.fillAll(Colours::black); | |||
} | |||
~AudioSettings(){ | |||
label = nullptr; | |||
samplingRate = nullptr; | |||
label2 = nullptr; | |||
ksmps = nullptr; | |||
label3 = nullptr; | |||
audioDevice = nullptr; | |||
label4 = nullptr; | |||
midiDevice = nullptr; | |||
} | |||
private: | |||
ScopedPointer<Label> label; | |||
ScopedPointer<ComboBox> samplingRate; | |||
ScopedPointer<Label> label2; | |||
ScopedPointer<ComboBox> ksmps; | |||
ScopedPointer<Label> label3; | |||
ScopedPointer<ComboBox> audioDevice; | |||
ScopedPointer<Label> label4; | |||
ScopedPointer<ComboBox> midiDevice; | |||
}; | |||
CsoundDebuggerComponent(String title): Component() | |||
{ | |||
textEditor = new TextEditor(); | |||
textEditor->setColour(Label::outlineColourId, Colours::white); | |||
textEditor->setColour(TextEditor::backgroundColourId, CabbageUtils::getDarkerBackgroundSkin()); | |||
textEditor->setColour(TextEditor::textColourId, Colours::white); | |||
textEditor->setMultiLine(true); | |||
#if defined(WIN32) | |||
textEditor->setFont(Font(String("Consolas"), 13, 1)); | |||
#elif defined(MACOSX) | |||
textEditor->setFont(Font(String("Courier New"), 13, 1)); | |||
#else | |||
textEditor->setFont(Font(String("Droid Sans Mono"), 13, 1)); | |||
#endif | |||
addAndMakeVisible(textEditor, true); | |||
}; | |||
~CsoundDebuggerComponent() {}; | |||
void setText(String text) | |||
{ | |||
StringArray textArray; | |||
textArray.addLines(text); | |||
textArray.removeEmptyStrings(true); | |||
for(int i=2; i<textArray.size(); i++) | |||
{ | |||
StringArray tempArray; | |||
String formattedLine=""; | |||
tempArray.addTokens(textArray[i], " "); | |||
tempArray.removeDuplicates(true); | |||
tempArray.removeEmptyStrings(); | |||
for(int j=0; j<tempArray.size(); j++) | |||
{ | |||
formattedLine+=tempArray[j].removeCharacters(" ").paddedRight(' ', 20); | |||
textArray.set(i, formattedLine); | |||
} | |||
} | |||
textEditor->setColour(TextEditor::textColourId, Colours::lime); | |||
textEditor->setText(textArray.joinIntoString("\n")); | |||
} | |||
String getText() | |||
{ | |||
return textEditor->getText(); | |||
} | |||
void resized() | |||
{ | |||
textEditor->setBounds(20, 21, getWidth()-25, getHeight()-30); | |||
} | |||
void paint(Graphics& g) | |||
{ | |||
g.fillAll(CabbageUtils::getDarkerBackgroundSkin()); | |||
g.setColour(Colours::white); | |||
g.drawRoundedRectangle(getLocalBounds().toFloat(), 2, 2); | |||
g.drawFittedText("Debugger output", getLocalBounds().withHeight(18), Justification::centred, 1, 1.f); | |||
} | |||
//============================================================ | |||
// class for displaying popup text | |||
//============================================================ | |||
class PopupDisplay : public DialogWindow, | |||
public Timer, | |||
public ActionBroadcaster | |||
}; | |||
//============================================================================== | |||
//Main window. This window holds a 2 textEditors. One for the code, and the other for | |||
//displaying Csound output messages | |||
//============================================================================== | |||
class CodeWindow : public DocumentWindow, | |||
public ApplicationCommandTarget, | |||
public MenuBarModel, | |||
public ActionListener, | |||
public ActionBroadcaster, | |||
public CodeDocument::Listener, | |||
public Timer | |||
{ | |||
class Box : public Component | |||
{ | |||
public: | |||
Box():firstTime(true) | |||
{ | |||
this->setInterceptsMouseClicks(false, false); | |||
setSize(10, 50); | |||
} | |||
~Box(){}; | |||
void setText(String _info, String _syntax){ | |||
syntax=_syntax; | |||
info=_info; | |||
repaint(); | |||
} | |||
void paint(Graphics& g) | |||
{ | |||
#ifdef LINUX | |||
g.fillAll(Colour::fromRGB(40,40,40)); | |||
g.setColour(Colours::yellow); | |||
g.drawRect(0, 0, getWidth()-1, getHeight()-1, 1); | |||
g.setFont(Font(String("Arial"), 16, 0)); | |||
g.setColour(Colours::whitesmoke); | |||
g.drawFittedText(syntax, 10, 10, getWidth(), getHeight(), Justification::topLeft, 100, 1); | |||
g.setFont(Font(String("Arial"), 15, 0)); | |||
g.setColour(Colours::cornflowerblue); | |||
g.drawFittedText(info, 10, 25, getWidth(), getHeight(), Justification::topLeft, 100, 1); | |||
#else | |||
g.fillAll(Colour::fromRGB(20, 20, 20)); | |||
g.setColour(Colours::whitesmoke); | |||
g.drawRect(0, 0, getWidth()-1, getHeight()-1, 1); | |||
g.setFont(Font(String("Arial"), 16, 0)); | |||
g.setColour(Colours::yellow); | |||
g.drawFittedText(syntax, 10, 10, getWidth(), getHeight(), Justification::topLeft, 100, 1); | |||
g.setFont(Font(String("Arial"), 15, 0)); | |||
g.setColour(Colours::lime); | |||
g.drawFittedText(info, 10, 25, getWidth(), getHeight(), Justification::topLeft, 100, 1); | |||
#endif | |||
} | |||
void resized(){ | |||
setSize(getWidth(), getHeight()); | |||
} | |||
bool firstTime; | |||
private: | |||
String syntax, info; | |||
}; | |||
public: | |||
PopupDisplay(String name): DialogWindow(name, Colours::black, true, true), | |||
time(0), seconds(0) | |||
{ | |||
box = new Box(); | |||
this->setContentNonOwned(box, true); | |||
#ifndef LINUX | |||
this->setAlpha(.9f); | |||
#endif | |||
} | |||
~PopupDisplay(){} | |||
void resized(){ | |||
setSize(getWidth(), 50); | |||
// box->repaint(); | |||
} | |||
void setText(String opcodeName, String opcodeDescrptor){ | |||
box->setText(opcodeName, opcodeDescrptor); | |||
} | |||
int getDesktopWindowStyleFlags() const{ | |||
int styleFlags = ComponentPeer::windowAppearsOnTaskbar; | |||
//if (useDropShadow) styleFlags |= ComponentPeer::windowHasDropShadow; | |||
//if (useNativeTitleBar) styleFlags |= ComponentPeer::windowHasTitleBar; | |||
return 0; | |||
} | |||
void timerCallback(){ | |||
if(time<seconds){ | |||
time++; | |||
stopTimer(); | |||
setVisible(true); | |||
sendActionMessage(""); | |||
} | |||
} | |||
void killSplash(){ | |||
box->firstTime=false; | |||
box->repaint(); | |||
} | |||
bool triggerToAppear(int _seconds) | |||
{ | |||
time=0; | |||
seconds = _seconds; | |||
startTimer(1000); | |||
} | |||
void closeButtonPressed(){ | |||
setVisible(false); | |||
} | |||
ScopedPointer<Box> box; | |||
int time; | |||
int seconds; | |||
CodeWindow(String name); | |||
~CodeWindow(); | |||
CodeDocument csoundDoc; | |||
StringArray getMenuBarNames(); | |||
void getAllCommands (Array <CommandID>& commands); | |||
void menuItemSelected (int menuItemID, int topLevelMenuIndex); | |||
void setFontSize(String zoom); | |||
//================= command methods ==================== | |||
ApplicationCommandTarget* getNextCommandTarget() | |||
{ | |||
return findFirstTargetParentComponent(); | |||
} | |||
void getCommandInfo (const CommandID commandID, ApplicationCommandInfo& result); | |||
PopupMenu getMenuForIndex (int topLevelMenuIndex, const String& menuName); | |||
bool perform (const InvocationInfo& info); | |||
void toggleManuals(String manual); | |||
void setEditorColourScheme(String theme); | |||
void actionListenerCallback(const String &message); | |||
void timerCallback(); | |||
void toggleTextWindows(); | |||
juce::Rectangle<int> getCaretScreenPosition() | |||
{ | |||
juce::Rectangle<int> rect(textEditor->editor[textEditor->currentEditor]->getCaretPoisition()); | |||
rect.setLeft(rect.getX()+this->getTopLevelComponent()->getX()+100); | |||
rect.setTop(rect.getY()+this->getTopLevelComponent()->getY()+45); | |||
return rect; | |||
} | |||
void closeButtonPressed() | |||
{ | |||
//JUCEApplication::getInstance()->systemRequestedQuit(); | |||
this->setVisible(false); | |||
} | |||
void codeDocumentTextDeleted(int,int) {} | |||
void showCabbageHelp(); | |||
void codeDocumentTextInserted(const juce::String &,int) {} | |||
void codeDocumentChanged (const CodeDocument::Position &affectedTextStart, const CodeDocument::Position &affectedTextEnd); | |||
void insertFromRepo(); | |||
void setText(String text, String file) | |||
{ | |||
textEditor->setAllText(text); | |||
textEditor->openFiles.getReference(0) = file; | |||
} | |||
String getText() | |||
{ | |||
return textEditor->getAllText(); | |||
} | |||
void setColourScheme(String theme); | |||
void newFile(String type); | |||
bool unSaved; | |||
StringArray recentEvents; | |||
String csoundOutputText; | |||
bool firstTime; | |||
String debugMessage; | |||
bool showOutput; | |||
CommandManager commandManager; | |||
File csdFile; | |||
int fontSize; | |||
String ASCIICabbage; | |||
ScopedPointer<SplitComponent> splitWindow; | |||
ScopedPointer<SplitComponent> splitBottomWindow; | |||
ScopedPointer<CsoundOutputComponent> csoundOutputComponent; | |||
ScopedPointer<CsoundDebuggerComponent> csoundDebuggerComponent; | |||
StringArray opcodeStrings; | |||
CsoundCodeEditor* textEditor; | |||
CsoundTokeniser csoundToker; | |||
Font font; | |||
bool isColumnModeEnabled; | |||
bool isInstrTabEnabled; | |||
bool isCsoundOutputEnabled; | |||
}; | |||
#endif // __MAINCOMPONENT_H_615ECE56__ |
@@ -2,7 +2,7 @@ | |||
//============================================================================== | |||
CommandManager::CommandManager () : | |||
ApplicationCommandManager () | |||
ApplicationCommandManager () | |||
{ | |||
} | |||
@@ -24,55 +24,58 @@ | |||
//============================================================================== | |||
namespace CommandIDs | |||
{ | |||
static const int fileNew = 1000; | |||
static const int fileOpen = 1001; | |||
static const int fileSave = 1002; | |||
static const int fileSaveAs = 1003; | |||
static const int fileSaveAll = 1004; | |||
static const int fileExportSynth = 1005; | |||
static const int fileExportEffect = 1006; | |||
static const int fileUpdateGUI = 1007; | |||
static const int fileQuit = 1008; | |||
static const int fileKeyboardShorts = 1009; | |||
static const int editUndo = 2011; | |||
static const int editRedo = 2012; | |||
static const int editCut = 2013; | |||
static const int editCopy = 2014; | |||
static const int editPaste = 2015; | |||
static const int editZoomIn = 2016; | |||
static const int editZoomOut = 2017; | |||
static const int whiteBackground = 2018; | |||
static const int blackBackground = 2019; | |||
static const int editToggleComments = 2020; | |||
static const int insertFromRepo = 2021; | |||
static const int addFromRepo = 2022; | |||
static const int insertRecentEvent = 2023; | |||
static const int openPythonEditor = 2024; | |||
static const int viewCsoundHelp = 4025; | |||
static const int viewCabbageHelp = 4026; | |||
static const int viewSource = 4027; | |||
static const int AudioSettings = 4028; | |||
static const int startSession = 3023; | |||
static const int commOrchUpdateInstrument = 3024; | |||
static const int commOrchUpdateSingleLine = 3025; | |||
static const int commOrchUpdateMultiLine = 3026; | |||
static const int commScoUpdateMultiLine = 3027; | |||
static const int commScoUpdateSingleLine = 3028; | |||
static const int commOrcUpdateChannel = 3029; | |||
static const int fileNew = 1000; | |||
static const int fileOpen = 1001; | |||
static const int fileSave = 1002; | |||
static const int fileSaveAs = 1003; | |||
static const int fileSaveAll = 1004; | |||
static const int fileExportSynth = 1005; | |||
static const int fileExportEffect = 1006; | |||
static const int fileUpdateGUI = 1007; | |||
static const int fileQuit = 1008; | |||
static const int fileCloseAux = 2081; | |||
static const int fileKeyboardShorts = 1009; | |||
static const int editUndo = 2011; | |||
static const int editRedo = 2012; | |||
static const int editCut = 2013; | |||
static const int editCopy = 2014; | |||
static const int editPaste = 2015; | |||
static const int editSearchReplace = 2080; | |||
static const int editColumnEdit = 2082; | |||
static const int editZoomIn = 2016; | |||
static const int editZoomOut = 2017; | |||
static const int whiteBackground = 2018; | |||
static const int blackBackground = 2019; | |||
static const int editToggleComments = 2020; | |||
static const int insertFromRepo = 2021; | |||
static const int addFromRepo = 2022; | |||
static const int insertRecentEvent = 2023; | |||
static const int openPythonEditor = 2024; | |||
static const int setBreakpoint = 3000; | |||
static const int removeBreakpoint = 3001; | |||
static const int continueDebug = 3002; | |||
static const int nextDebug = 3003; | |||
static const int viewCsoundHelp = 4025; | |||
static const int viewCabbageHelp = 4026; | |||
static const int viewCsoundOutput = 4032; | |||
static const int viewSource = 4027; | |||
static const int viewOpcodeHelp = 4028; | |||
static const int viewLinesNumbers = 4029; | |||
static const int viewInstrumentsTabs = 4030; | |||
}; | |||
//============================================================================== | |||
namespace CommandCategories | |||
{ | |||
static const char* const file = "File"; | |||
static const char* const edit = "Edit"; | |||
static const char* const command = "Command"; | |||
static const char* const help = "View"; | |||
static const char* const file = "File"; | |||
static const char* const edit = "Edit"; | |||
static const char* const view = "View"; | |||
static const char* const debug = "Debug"; | |||
static const char* const help = "Help"; | |||
} | |||
//============================================================================== | |||
@@ -81,10 +84,10 @@ class CommandManager : public ApplicationCommandManager | |||
{ | |||
public: | |||
CommandManager (); | |||
CommandManager (); | |||
~CommandManager (); | |||
juce_DeclareSingleton (CommandManager, true) | |||
juce_DeclareSingleton (CommandManager, true) | |||
}; | |||
@@ -11,45 +11,47 @@ | |||
class ShortcutsPanel : public PropertyPanel | |||
{ | |||
public: | |||
ShortcutsPanel() : PropertyPanel() | |||
{ | |||
setSize(200, 300); | |||
Array <PropertyComponent*> props; | |||
keyboardShortcutsXml = appProperties->getUserSettings()->getXmlValue("KeyboardShortcutXmlData"); | |||
for(int i=0;i<keyboardShortcutsXml->getNumAttributes();i++) | |||
{ | |||
textFields.add(Value(keyboardShortcutsXml->getAttributeValue(i))); | |||
attributeNames.add(keyboardShortcutsXml->getAttributeName(i)); | |||
props.add(new TextPropertyComponent(textFields[i], | |||
keyboardShortcutsXml->getAttributeName(i), | |||
100, false)); | |||
props[i]->setPreferredHeight(20); | |||
props[i]->setColour(TextPropertyComponent::backgroundColourId, Colours::red); | |||
} | |||
setSize(200, jmin(300, props.size()*props[0]->getPreferredHeight())); | |||
addProperties(props); | |||
} | |||
void paint(Graphics &g){ | |||
g.fillAll(Colours::lightgrey); | |||
} | |||
~ShortcutsPanel(){ | |||
for(int i=0;i<keyboardShortcutsXml->getNumAttributes();i++) | |||
keyboardShortcutsXml->setAttribute(attributeNames[i], textFields[i].toString()); | |||
appProperties->getUserSettings()->setValue("KeyboardShortcutXmlData", keyboardShortcutsXml); | |||
Logger::writeToLog("update all variables before closing"); | |||
keyboardShortcutsXml = nullptr; | |||
} | |||
Array<Value> textFields; | |||
ScopedPointer<XmlElement> keyboardShortcutsXml; | |||
StringArray attributeNames; | |||
ShortcutsPanel() : PropertyPanel() | |||
{ | |||
setSize(200, 300); | |||
Array <PropertyComponent*> props; | |||
keyboardShortcutsXml = appProperties->getUserSettings()->getXmlValue("KeyboardShortcutXmlData"); | |||
for(int i=0; i<keyboardShortcutsXml->getNumAttributes(); i++) | |||
{ | |||
textFields.add(Value(keyboardShortcutsXml->getAttributeValue(i))); | |||
attributeNames.add(keyboardShortcutsXml->getAttributeName(i)); | |||
props.add(new TextPropertyComponent(textFields[i], | |||
keyboardShortcutsXml->getAttributeName(i), | |||
100, false)); | |||
props[i]->setPreferredHeight(20); | |||
props[i]->setColour(TextPropertyComponent::backgroundColourId, Colours::red); | |||
} | |||
setSize(200, jmin(300, props.size()*props[0]->getPreferredHeight())); | |||
addProperties(props); | |||
} | |||
void paint(Graphics &g) | |||
{ | |||
g.fillAll(Colours::lightgrey); | |||
} | |||
~ShortcutsPanel() | |||
{ | |||
for(int i=0; i<keyboardShortcutsXml->getNumAttributes(); i++) | |||
keyboardShortcutsXml->setAttribute(attributeNames[i], textFields[i].toString()); | |||
appProperties->getUserSettings()->setValue("KeyboardShortcutXmlData", keyboardShortcutsXml); | |||
Logger::writeToLog("update all variables before closing"); | |||
keyboardShortcutsXml = nullptr; | |||
} | |||
Array<Value> textFields; | |||
ScopedPointer<XmlElement> keyboardShortcutsXml; | |||
StringArray attributeNames; | |||
}; | |||
@@ -25,10 +25,10 @@ | |||
class PythonTokeniser : public CodeTokeniser | |||
{ | |||
public: | |||
PythonTokeniser(){} | |||
~PythonTokeniser(){} | |||
//============================================================================== | |||
PythonTokeniser() {} | |||
~PythonTokeniser() {} | |||
//============================================================================== | |||
enum TokenType | |||
{ | |||
tokenType_error = 0, | |||
@@ -42,111 +42,111 @@ public: | |||
tokenType_bracket, | |||
tokenType_punctuation, | |||
tokenType_preprocessor, | |||
tokenType_csdTag | |||
tokenType_csdTag | |||
}; | |||
CodeEditorComponent::ColourScheme getDefaultColourScheme() | |||
{ | |||
struct Type | |||
{ | |||
const char* name; | |||
uint32 colour; | |||
}; | |||
const Type types[] = | |||
{ | |||
{ "Error", Colours::black.getARGB() }, | |||
{ "Comment", Colours::green.getARGB() }, | |||
{ "Keyword", Colours::blue.getARGB() }, | |||
{ "Identifier", Colours::black.getARGB() }, | |||
{ "Integer", Colours::orange.getARGB() }, | |||
{ "Float", Colours::black.getARGB() }, | |||
{ "String", Colours::red.getARGB() }, | |||
{ "Operator", Colours::pink.getARGB() }, | |||
{ "Bracket", Colours::darkgreen.getARGB() }, | |||
{ "Punctuation", Colours::black.getARGB() }, | |||
{ "Preprocessor Text", Colours::green.getARGB() }, | |||
{ "Csd Tag", Colours::brown.getARGB() } | |||
}; | |||
CodeEditorComponent::ColourScheme cs; | |||
for (int i = 0; i < sizeof (types) / sizeof (types[0]); ++i) // (NB: numElementsInArray doesn't work here in GCC4.2) | |||
cs.set (types[i].name, Colour (types[i].colour)); | |||
return cs; | |||
} | |||
CodeEditorComponent::ColourScheme getDarkColourScheme() | |||
{ | |||
struct Type | |||
{ | |||
const char* name; | |||
uint32 colour; | |||
}; | |||
const Type types[] = | |||
{ | |||
{ "Error", Colours::white.getARGB() }, | |||
{ "Comment", Colours::green.getARGB() }, | |||
{ "Keyword", Colours::cornflowerblue.getARGB() }, | |||
{ "Identifier", Colours::white.getARGB() }, | |||
{ "Integer", Colours::orange.getARGB() }, | |||
{ "Float", Colours::lime.getARGB() }, | |||
{ "String", Colours::red.getARGB() }, | |||
{ "Operator", Colours::pink.getARGB() }, | |||
{ "Bracket", Colours::darkgreen.getARGB() }, | |||
{ "Punctuation", Colours::white.getARGB() }, | |||
{ "Preprocessor Text", Colours::green.getARGB() }, | |||
{ "Csd Tag", Colours::brown.getARGB() } | |||
}; | |||
CodeEditorComponent::ColourScheme cs; | |||
for (int i = 0; i < sizeof (types) / sizeof (types[0]); ++i) // (NB: numElementsInArray doesn't work here in GCC4.2) | |||
cs.set (types[i].name, Colour (types[i].colour)); | |||
return cs; | |||
} | |||
CodeEditorComponent::ColourScheme getDefaultColourScheme() | |||
{ | |||
struct Type | |||
{ | |||
const char* name; | |||
uint32 colour; | |||
}; | |||
const Type types[] = | |||
{ | |||
{ "Error", Colours::black.getARGB() }, | |||
{ "Comment", Colours::green.getARGB() }, | |||
{ "Keyword", Colours::blue.getARGB() }, | |||
{ "Identifier", Colours::black.getARGB() }, | |||
{ "Integer", Colours::orange.getARGB() }, | |||
{ "Float", Colours::black.getARGB() }, | |||
{ "String", Colours::red.getARGB() }, | |||
{ "Operator", Colours::pink.getARGB() }, | |||
{ "Bracket", Colours::darkgreen.getARGB() }, | |||
{ "Punctuation", Colours::black.getARGB() }, | |||
{ "Preprocessor Text", Colours::green.getARGB() }, | |||
{ "Csd Tag", Colours::brown.getARGB() } | |||
}; | |||
CodeEditorComponent::ColourScheme cs; | |||
for (int i = 0; i < sizeof (types) / sizeof (types[0]); ++i) // (NB: numElementsInArray doesn't work here in GCC4.2) | |||
cs.set (types[i].name, Colour (types[i].colour)); | |||
return cs; | |||
} | |||
CodeEditorComponent::ColourScheme getDarkColourScheme() | |||
{ | |||
struct Type | |||
{ | |||
const char* name; | |||
uint32 colour; | |||
}; | |||
const Type types[] = | |||
{ | |||
{ "Error", Colours::white.getARGB() }, | |||
{ "Comment", Colours::green.getARGB() }, | |||
{ "Keyword", Colours::cornflowerblue.getARGB() }, | |||
{ "Identifier", Colours::white.getARGB() }, | |||
{ "Integer", Colours::orange.getARGB() }, | |||
{ "Float", Colours::lime.getARGB() }, | |||
{ "String", Colours::red.getARGB() }, | |||
{ "Operator", Colours::pink.getARGB() }, | |||
{ "Bracket", Colours::darkgreen.getARGB() }, | |||
{ "Punctuation", Colours::white.getARGB() }, | |||
{ "Preprocessor Text", Colours::green.getARGB() }, | |||
{ "Csd Tag", Colours::brown.getARGB() } | |||
}; | |||
CodeEditorComponent::ColourScheme cs; | |||
for (int i = 0; i < sizeof (types) / sizeof (types[0]); ++i) // (NB: numElementsInArray doesn't work here in GCC4.2) | |||
cs.set (types[i].name, Colour (types[i].colour)); | |||
return cs; | |||
} | |||
private: | |||
//============================================================================== | |||
StringArray getTokenTypes() | |||
{ | |||
StringArray s; | |||
s.add ("Error"); | |||
s.add ("Comment"); | |||
s.add ("C++ keyword"); | |||
s.add ("Identifier"); | |||
s.add ("Integer literal"); | |||
s.add ("Float literal"); | |||
s.add ("String literal"); | |||
s.add ("Operator"); | |||
s.add ("Bracket"); | |||
s.add ("Punctuation"); | |||
s.add ("Preprocessor line"); | |||
s.add ("CSD Tag"); | |||
return s; | |||
} | |||
//============================================================================== | |||
void skipQuotedString (CodeDocument::Iterator& source) | |||
{ | |||
const juce_wchar quote = source.nextChar(); | |||
for (;;) | |||
//============================================================================== | |||
StringArray getTokenTypes() | |||
{ | |||
const juce_wchar c = source.nextChar(); | |||
if (c == quote || c == 0) | |||
break; | |||
StringArray s; | |||
s.add ("Error"); | |||
s.add ("Comment"); | |||
s.add ("C++ keyword"); | |||
s.add ("Identifier"); | |||
s.add ("Integer literal"); | |||
s.add ("Float literal"); | |||
s.add ("String literal"); | |||
s.add ("Operator"); | |||
s.add ("Bracket"); | |||
s.add ("Punctuation"); | |||
s.add ("Preprocessor line"); | |||
s.add ("CSD Tag"); | |||
return s; | |||
} | |||
if (c == '\\') | |||
source.skip(); | |||
} | |||
} | |||
//============================================================================== | |||
void skipQuotedString (CodeDocument::Iterator& source) | |||
{ | |||
const juce_wchar quote = source.nextChar(); | |||
for (;;) | |||
{ | |||
const juce_wchar c = source.nextChar(); | |||
if (c == quote || c == 0) | |||
break; | |||
if (c == '\\') | |||
source.skip(); | |||
} | |||
} | |||
//============================================================================== | |||
//============================================================================== | |||
void skipCSDTag (CodeDocument::Iterator& source) noexcept | |||
{ | |||
for (;;) | |||
@@ -157,68 +157,69 @@ private: | |||
} | |||
} | |||
//============================================================================== | |||
bool isIdentifierStart (const char c) | |||
{ | |||
return CharacterFunctions::isLetter (c) | |||
|| c == '_' || c == '@'; | |||
} | |||
//============================================================================== | |||
bool isIdentifierBody (const char c) | |||
{ | |||
return CharacterFunctions::isLetter (c) | |||
|| CharacterFunctions::isDigit (c) | |||
|| c == '_' || c == '@'; | |||
} | |||
//============================================================================== | |||
//============================================================================== | |||
bool isIdentifierStart (const char c) | |||
{ | |||
return CharacterFunctions::isLetter (c) | |||
|| c == '_' || c == '@'; | |||
} | |||
//============================================================================== | |||
bool isIdentifierBody (const char c) | |||
{ | |||
return CharacterFunctions::isLetter (c) | |||
|| CharacterFunctions::isDigit (c) | |||
|| c == '_' || c == '@'; | |||
} | |||
//============================================================================== | |||
bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept | |||
{ | |||
//populate char array with Csound keywords | |||
//this list of keywords is not completely up to date! | |||
static const char* const keywords[] = | |||
{ | |||
"and", | |||
"as", | |||
"assert", | |||
"break", | |||
"class", | |||
"continue", | |||
"def", | |||
"del", | |||
"elif", | |||
"else", | |||
"except", | |||
"exec", | |||
"finally", | |||
"for", | |||
"from", | |||
"global", | |||
"if", | |||
"import", | |||
"in", | |||
"is", | |||
"lambda", | |||
"not", | |||
"or", | |||
"pass", | |||
"print", | |||
"raise", | |||
"return", | |||
"try", | |||
"while", | |||
"with", | |||
"yield"}; | |||
//populate char array with Csound keywords | |||
//this list of keywords is not completely up to date! | |||
static const char* const keywords[] = | |||
{ | |||
"and", | |||
"as", | |||
"assert", | |||
"break", | |||
"class", | |||
"continue", | |||
"def", | |||
"del", | |||
"elif", | |||
"else", | |||
"except", | |||
"exec", | |||
"finally", | |||
"for", | |||
"from", | |||
"global", | |||
"if", | |||
"import", | |||
"in", | |||
"is", | |||
"lambda", | |||
"not", | |||
"or", | |||
"pass", | |||
"print", | |||
"raise", | |||
"return", | |||
"try", | |||
"while", | |||
"with", | |||
"yield" | |||
}; | |||
const char* const* k; | |||
if (tokenLength < 2 || tokenLength > 16) | |||
return false; | |||
if (tokenLength < 2 || tokenLength > 16) | |||
return false; | |||
else | |||
k = keywords; | |||
else | |||
k = keywords; | |||
int i = 0; | |||
@@ -232,8 +233,8 @@ private: | |||
return false; | |||
} | |||
//============================================================================== | |||
int parseIdentifier (CodeDocument::Iterator& source) noexcept | |||
//============================================================================== | |||
int parseIdentifier (CodeDocument::Iterator& source) noexcept | |||
{ | |||
int tokenLength = 0; | |||
String::CharPointerType::CharType possibleIdentifier [100]; | |||
@@ -260,50 +261,52 @@ private: | |||
return CsoundTokeniser::tokenType_identifier; | |||
} | |||
//============================================================================== | |||
int readNextToken (CodeDocument::Iterator& source) | |||
{ | |||
int result = tokenType_error; | |||
source.skipWhitespace(); | |||
char firstChar = source.peekNextChar(); | |||
switch (firstChar) | |||
//============================================================================== | |||
int readNextToken (CodeDocument::Iterator& source) | |||
{ | |||
case 0: | |||
source.skip(); | |||
break; | |||
case ';': | |||
source.skipToEndOfLine(); | |||
result = tokenType_comment; | |||
break; | |||
case '"': | |||
// case T('\''): | |||
skipQuotedString (source); | |||
result = tokenType_stringLiteral; | |||
break; | |||
case '<': | |||
source.skip(); | |||
if((source.peekNextChar() == 'C') || | |||
(source.peekNextChar() == '/')){ | |||
skipCSDTag (source); | |||
result = tokenType_csdTag; | |||
} | |||
break; | |||
default: | |||
if (isIdentifierStart (firstChar)){ | |||
result = parseIdentifier (source); | |||
} | |||
else | |||
int result = tokenType_error; | |||
source.skipWhitespace(); | |||
char firstChar = source.peekNextChar(); | |||
switch (firstChar) | |||
{ | |||
case 0: | |||
source.skip(); | |||
break; | |||
break; | |||
case ';': | |||
source.skipToEndOfLine(); | |||
result = tokenType_comment; | |||
break; | |||
case '"': | |||
// case T('\''): | |||
skipQuotedString (source); | |||
result = tokenType_stringLiteral; | |||
break; | |||
case '<': | |||
source.skip(); | |||
if((source.peekNextChar() == 'C') || | |||
(source.peekNextChar() == '/')) | |||
{ | |||
skipCSDTag (source); | |||
result = tokenType_csdTag; | |||
} | |||
break; | |||
default: | |||
if (isIdentifierStart (firstChar)) | |||
{ | |||
result = parseIdentifier (source); | |||
} | |||
else | |||
source.skip(); | |||
break; | |||
} | |||
//jassert (result != tokenType_unknown); | |||
return result; | |||
} | |||
//jassert (result != tokenType_unknown); | |||
return result; | |||
} | |||
}; | |||
#endif |
@@ -0,0 +1,408 @@ | |||
/* | |||
============================================================================== | |||
Split component for Juce | |||
File: SplitComponent.cpp | |||
Created: 15 Mar 2014 | |||
-------------------------------------------------------------------------------- | |||
Copyright 2014 Jim Hewes | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
============================================================================== | |||
*/ | |||
#include <cassert> | |||
#include "SplitComponent.h" | |||
SplitComponent::SplitComponent(bool isVertical) | |||
: m_pTopLeftComponent(NULL) | |||
, m_pBottomRightComponent(NULL) | |||
, m_isVertical(isVertical) | |||
, m_splitBarGravity(0.0) | |||
, m_fitToParent(true) | |||
{ | |||
CommonConstruction(); | |||
} | |||
SplitComponent::SplitComponent(Component& topLeftComponent, Component& bottomRightComponent, bool isVertical) | |||
: m_pTopLeftComponent(&topLeftComponent) | |||
, m_pBottomRightComponent(&bottomRightComponent) | |||
, m_isVertical(isVertical) | |||
, m_splitBarGravity(0.0) | |||
, m_fitToParent(false) | |||
{ | |||
CommonConstruction(); | |||
} | |||
void SplitComponent::CommonConstruction() | |||
{ | |||
// Set the bounds of this split component based on the parent's size (if there is a parent). | |||
parentSizeChanged(); | |||
m_pSplitBar = new SplitBar(*this, m_isVertical); | |||
// set default position and width of the SplitBar | |||
if (m_isVertical) | |||
{ | |||
m_pSplitBar->setBounds(getWidth() / 2, 0, 8, getHeight()); | |||
m_lastSplitbarMovePosition = m_pSplitBar->getX(); | |||
m_lastSplitbarMoveExtent = getWidth(); | |||
} | |||
else | |||
{ | |||
m_pSplitBar->setBounds(0, getHeight() / 2, getWidth(), 8); | |||
m_lastSplitbarMovePosition = m_pSplitBar->getY(); | |||
m_lastSplitbarMoveExtent = getHeight(); | |||
} | |||
if (m_pTopLeftComponent) | |||
{ | |||
addAndMakeVisible(m_pTopLeftComponent, 0); | |||
} | |||
if (m_pBottomRightComponent) | |||
{ | |||
addAndMakeVisible(m_pBottomRightComponent, 1); | |||
} | |||
addAndMakeVisible(m_pSplitBar, -1); // make sure the split bar is in front of other components. | |||
} | |||
SplitComponent::~SplitComponent() | |||
{ | |||
removeAllChildren(); | |||
} | |||
void SplitComponent::SetTopLeftComponent(Component &component) | |||
{ | |||
if (m_pTopLeftComponent) | |||
{ | |||
removeChildComponent(m_pTopLeftComponent); | |||
} | |||
m_pTopLeftComponent = &component; | |||
addAndMakeVisible(m_pTopLeftComponent, 0); | |||
Layout(); | |||
} | |||
void SplitComponent::SetBottomRightComponent(Component &component) | |||
{ | |||
if (m_pBottomRightComponent) | |||
{ | |||
removeChildComponent(m_pBottomRightComponent); | |||
} | |||
m_pBottomRightComponent = &component; | |||
addAndMakeVisible(m_pBottomRightComponent, 1); | |||
Layout(); | |||
} | |||
void SplitComponent::Layout() | |||
{ | |||
Rectangle<int> topLeftComponentRect; | |||
Rectangle<int> bottomRightComponentRect; | |||
topLeftComponentRect.setTop(0); | |||
topLeftComponentRect.setLeft(0); | |||
if (m_isVertical) | |||
{ | |||
int splitBarPosX = m_pSplitBar->getX(); | |||
int splitBarWidth = m_pSplitBar->getWidth(); | |||
topLeftComponentRect.setWidth(splitBarPosX); | |||
topLeftComponentRect.setHeight(getHeight()); | |||
bottomRightComponentRect.setPosition(splitBarPosX + splitBarWidth, 0); | |||
bottomRightComponentRect.setWidth(getWidth() - (splitBarPosX + splitBarWidth)); | |||
bottomRightComponentRect.setHeight(getHeight()); | |||
} | |||
else | |||
{ | |||
int splitBarPosY = m_pSplitBar->getY(); | |||
int splitBarHeight = m_pSplitBar->getHeight(); | |||
topLeftComponentRect.setWidth(getWidth()); | |||
topLeftComponentRect.setHeight(splitBarPosY); | |||
bottomRightComponentRect.setPosition(0, splitBarPosY + splitBarHeight); | |||
bottomRightComponentRect.setWidth(getWidth()); | |||
bottomRightComponentRect.setHeight(getHeight() - (splitBarPosY + splitBarHeight)); | |||
} | |||
if (m_pTopLeftComponent) | |||
{ | |||
m_pTopLeftComponent->setBounds(topLeftComponentRect); | |||
} | |||
if (m_pBottomRightComponent) | |||
{ | |||
m_pBottomRightComponent->setBounds(bottomRightComponentRect); | |||
} | |||
} | |||
void SplitComponent::SetSplitBarPosition(int newPosition) | |||
{ | |||
if (m_isVertical) | |||
{ | |||
newPosition = jmax(0, jmin(newPosition, getWidth() - m_pSplitBar->getWidth())); // limit | |||
m_pSplitBar->setBounds(newPosition, 0, m_pSplitBar->getWidth(), m_pSplitBar->getHeight()); | |||
m_lastSplitbarMoveExtent = getWidth(); | |||
} | |||
else | |||
{ | |||
newPosition = jmax(0, jmin(newPosition, getHeight() - m_pSplitBar->getHeight())); // limit | |||
m_pSplitBar->setBounds(0, newPosition, m_pSplitBar->getWidth(), m_pSplitBar->getHeight()); | |||
m_lastSplitbarMoveExtent = getHeight(); | |||
} | |||
m_lastSplitbarMovePosition = newPosition; | |||
Layout(); | |||
} | |||
int SplitComponent::GetSplitBarPosition() const | |||
{ | |||
return m_isVertical ? m_pSplitBar->getX() : m_pSplitBar->getY(); | |||
} | |||
void SplitComponent::SetSplitBarThickness(int newThickness) | |||
{ | |||
// The position of the split bar may now be invalid as a result of the new thickness, so adjust. | |||
int splitBarPosition; | |||
if (m_isVertical) | |||
{ | |||
newThickness = jmax(0, jmin(newThickness, getWidth() - 2)); | |||
splitBarPosition = jmin(m_pSplitBar->getX(), getWidth() - newThickness); // limit split bar position | |||
m_pSplitBar->setBounds(splitBarPosition, 0, newThickness, m_pSplitBar->getHeight()); | |||
} | |||
else | |||
{ | |||
newThickness = jmax(0, jmin(newThickness, getHeight() - 2)); | |||
splitBarPosition = jmin(m_pSplitBar->getY(), getHeight() - newThickness); | |||
m_pSplitBar->setBounds(0, splitBarPosition, m_pSplitBar->getWidth(), newThickness); | |||
} | |||
SetSplitBarPosition(splitBarPosition); | |||
} | |||
int SplitComponent::GetSplitBarThickness() const | |||
{ | |||
return m_isVertical ? m_pSplitBar->getWidth() : m_pSplitBar->getHeight(); | |||
} | |||
void SplitComponent::SetSplitBarGravity(double gravity) | |||
{ | |||
assert((gravity >= 0.0) && (gravity <= 1.0)); | |||
// limit | |||
m_splitBarGravity = (gravity < 0.0) ? 0.0 : (gravity > 1.0) ? 1.0 : gravity; | |||
} | |||
double SplitComponent::GetSplitBarGravity() const | |||
{ | |||
return m_splitBarGravity;; | |||
} | |||
void SplitComponent::SetVerticalSplit(bool isVertical) | |||
{ | |||
if (m_isVertical != isVertical) | |||
{ | |||
// Change the orientation of the split bar. | |||
// The split bar position might now be invalid (outside the SplitComponent bounds). So move it to be valid. | |||
int splitbarThickness; | |||
int splitBarPosition; | |||
if (m_isVertical) // change from vertical to horizontal | |||
{ | |||
splitbarThickness = m_pSplitBar->getWidth(); | |||
splitBarPosition = m_pSplitBar->getX(); | |||
// limit split bar position | |||
splitBarPosition = jmin(splitBarPosition, getHeight() - splitbarThickness); | |||
m_pSplitBar->setBounds(0, splitBarPosition, getWidth(), splitbarThickness); | |||
} | |||
else // change from horizontal to vertical | |||
{ | |||
splitbarThickness = m_pSplitBar->getHeight(); | |||
splitBarPosition = m_pSplitBar->getY(); | |||
// limit split bar position | |||
splitBarPosition = jmin(splitBarPosition, getWidth() - splitbarThickness); | |||
m_pSplitBar->setBounds(splitBarPosition, 0, splitbarThickness, getHeight()); | |||
} | |||
m_pSplitBar->SetVertical(isVertical); | |||
m_isVertical = isVertical; | |||
SetSplitBarPosition(splitBarPosition); | |||
} | |||
} | |||
bool SplitComponent::IsVerticalSplit() const | |||
{ | |||
return m_isVertical; | |||
} | |||
void SplitComponent::SetFitToParent(bool fitToParent) | |||
{ | |||
if (m_fitToParent != fitToParent) | |||
{ | |||
m_fitToParent = fitToParent; | |||
parentSizeChanged(); | |||
} | |||
} | |||
bool SplitComponent::GetFitToParent() const | |||
{ | |||
return m_fitToParent; | |||
} | |||
void SplitComponent::resized() | |||
{ | |||
if (m_isVertical) | |||
{ | |||
// Account for gravity | |||
int widthDiff = getWidth() - m_lastSplitbarMoveExtent; // Get the difference in SplitComponent width since the split bar was moved manually. | |||
widthDiff = int(widthDiff * m_splitBarGravity); // Get a percentage of that difference based on the gravity setting. | |||
int newXPosition = widthDiff + m_lastSplitbarMovePosition; // Add the difference to getthe new desired right position. (which may get limited below) | |||
// Keep the split bar inside the visible area | |||
int maxSplitPosition = getWidth() - m_pSplitBar->getWidth(); | |||
newXPosition = juce::jmax(0, juce::jmin(maxSplitPosition, newXPosition)); | |||
// Essentially, adjust the height of the split bar to be the height of the SplitComponent. | |||
m_pSplitBar->setBounds(newXPosition, 0, m_pSplitBar->getWidth(), getHeight()); | |||
} | |||
else | |||
{ | |||
// Account for gravity | |||
int heightDiff = getHeight() - m_lastSplitbarMoveExtent; // Get the difference in SplitComponent width since the split bar was moved manually. | |||
heightDiff = int(heightDiff * m_splitBarGravity); // Get a percentage of that difference based on the gravity setting. | |||
int newYPosition = heightDiff + m_lastSplitbarMovePosition; // Add the difference to getthe new desired right position. (which may get limited below) | |||
// Keep the split bar inside the visible area | |||
newYPosition = juce::jlimit(0, getHeight() - m_pSplitBar->getHeight(), newYPosition); | |||
// Essentially, adjust the width of the split bar to be the width of the SplitComponent. | |||
m_pSplitBar->setBounds(0, newYPosition, getWidth(), m_pSplitBar->getHeight()); | |||
} | |||
Layout(); | |||
} | |||
/** | |||
Resize the SplitComponent to fills the area of it's parent if fit-to-parent is set. | |||
*/ | |||
void SplitComponent::parentSizeChanged() | |||
{ | |||
Component* pParentComponent = getParentComponent(); | |||
if (pParentComponent && m_fitToParent) | |||
{ | |||
// Occupy the entire space of the parent component. | |||
// Use Rectangle::setPosition(0,0) and NOT Rectangle::setLeft(0) Rectangle::setTop(0). | |||
// The later two would change the width and height of the rectangle so that the right and | |||
// bottom edges stay in the same place. setPosition does not have that side effect. | |||
Rectangle<int> bounds = pParentComponent->getBounds(); | |||
bounds.setPosition(0, 0); | |||
setBounds(bounds); // This will cause SplitComponent::resized() to be called. | |||
} | |||
} | |||
void SplitComponent::parentHierarchyChanged() | |||
{ | |||
// If the parent changed, we no longer know if the split bar position is within the parent's bounds. | |||
// So treat it as if the parent size changed. This also takes care of the case where a SplitComponent is added | |||
// to a parent for the first time and the split position was not initialized. | |||
parentSizeChanged(); | |||
} | |||
////////////////////////////////////////////////////////////////////////////////////////////////// | |||
// | |||
// Splitbar | |||
// | |||
// | |||
SplitComponent::SplitBar::SplitBar(SplitComponent& splitComponent, bool isVertical) | |||
: m_isVertical(isVertical) | |||
, m_splitComponent(splitComponent) | |||
{ | |||
setRepaintsOnMouseActivity(true); | |||
setMouseCursor(isVertical ? MouseCursor::LeftRightResizeCursor : MouseCursor::UpDownResizeCursor); | |||
} | |||
void SplitComponent::SplitBar::paint(Graphics& g) | |||
{ | |||
getLookAndFeel().drawStretchableLayoutResizerBar(g, | |||
getWidth(), getHeight(), | |||
m_isVertical, | |||
isMouseOver(), | |||
isMouseButtonDown()); | |||
} | |||
void SplitComponent::SplitBar::mouseDown(const MouseEvent&) | |||
{ | |||
const Point<int> pos = getPosition(); | |||
m_mouseDownPos = m_isVertical ? pos.getX() : pos.getY(); | |||
} | |||
void SplitComponent::SplitBar::mouseDrag(const MouseEvent& e) | |||
{ | |||
int desiredPos = m_mouseDownPos + (m_isVertical ? e.getDistanceFromDragStartX() : e.getDistanceFromDragStartY()); | |||
// Adjust position to keep the split bar inside the SplitComponent bounds. | |||
desiredPos = jmax(desiredPos, 0); | |||
if (m_isVertical) | |||
{ | |||
desiredPos = jmin(desiredPos, m_splitComponent.getWidth() - getWidth()); | |||
} | |||
else | |||
{ | |||
desiredPos = jmin(desiredPos, m_splitComponent.getHeight() - getHeight()); | |||
} | |||
if (desiredPos != m_mouseDownPos) | |||
{ | |||
m_splitComponent.SetSplitBarPosition(desiredPos); | |||
} | |||
} | |||
void SplitComponent::SplitBar::SetVertical(bool isVertical) | |||
{ | |||
if (m_isVertical != isVertical) | |||
{ | |||
m_isVertical = isVertical; | |||
setMouseCursor(m_isVertical ? MouseCursor::LeftRightResizeCursor : MouseCursor::UpDownResizeCursor); | |||
} | |||
} | |||
bool SplitComponent::SplitBar::IsVertical() | |||
{ | |||
return m_isVertical; | |||
} |
@@ -0,0 +1,273 @@ | |||
/* | |||
============================================================================== | |||
Split component for Juce | |||
File: SplitComponent.h | |||
Created: 15 Mar 2014 | |||
-------------------------------------------------------------------------------- | |||
Copyright 2014 Jim Hewes | |||
Licensed under the Apache License, Version 2.0 (the "License"); | |||
you may not use this file except in compliance with the License. | |||
You may obtain a copy of the License at | |||
http://www.apache.org/licenses/LICENSE-2.0 | |||
Unless required by applicable law or agreed to in writing, software | |||
distributed under the License is distributed on an "AS IS" BASIS, | |||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
See the License for the specific language governing permissions and | |||
limitations under the License. | |||
============================================================================== | |||
*/ | |||
#ifndef SPLITCOMPONENT_H_INCLUDED | |||
#define SPLITCOMPONENT_H_INCLUDED | |||
#include "../JuceHeader.h" | |||
/** | |||
SplitComponent is a simple "splitter window" in which two child components are divided by a split bar that can be moved.\n | |||
\n | |||
SplitComponent is useful when you want to divide an area into two halves and let the user move a middle split bar | |||
to resize the halves. You can split the area either vertically or horizontally. You can also set a "gravity" amount for | |||
the middle split bar so that when you resize the window the split bar will move proportionally to grow or shrink the | |||
child components.\n | |||
\n | |||
By default, a SplitComponent fills the entire area of it's parent. To limit its size within the parent, call | |||
FitToParent(false) and then set the bounds as needed. | |||
\n | |||
SplitComponents can be nested so that you can create more complex divisions, but since a SplitComponent fills the entire | |||
area of it's parent, it should be put inside another component first. | |||
\n | |||
To use the SplitComponent, you supply two child components to be the left and right sides (or top and bottom for a | |||
horzontal split). Here's an example: | |||
@code{.cpp} | |||
MyLeftComponent myLeftComponent; | |||
MyRightComponent myRightComponent; | |||
SplitComponent* pSplitComponent = new SplitComponent(myLeftComponent, myRightComponent); | |||
pSplitComponent->SetSplitBarPosition(getWidth() / 2); // Set the split bar to halfway so the area is divided equally. | |||
// The split bar thickness is 8 pixels by default, but you can change it. | |||
addAndMakeVisible(pSplitComponent); // Add the SplitComponent to this component is, (Maybe the MainComponent) | |||
@endcode | |||
If it's more convenient, you can construct an empty SplitComponent first, and then add the left and right child components later.\n | |||
\n | |||
Note that when the SplitComponent is resized or its split bar is moved, it resizes the child components. | |||
So if you have a child component that wants to resize itself according to its parent's size (for example, it | |||
fills the area of its parent) you need to first enclose it in another component. This can be as simple as | |||
just a Component object. For example, say that MyLeftComponent above wants to fill the area of its parent, | |||
you could implement it like this: | |||
@code{.cpp} | |||
MyLeftComponent myLeftComponent; | |||
MyRightComponent myRightComponent; | |||
Component leftPanel; | |||
leftPanel.addAndMakeVisible(myLeftComponent); | |||
SplitComponent* pSplitComponent = new SplitComponent(leftPanel, myRightComponent); | |||
...etc. | |||
@endcode | |||
This would be the case when nesting a SplitComponent that is set to fit to the area of it's parent.\n | |||
\n | |||
The split bar conforms to whatever look and feel you've set since it calls drawStretchableLayoutResizerBar() to paint itself. | |||
*/ | |||
class SplitComponent : public Component | |||
{ | |||
public: | |||
SplitComponent(bool isVertical = true); | |||
SplitComponent(Component& topLeftComponent, Component& bottomRightComponent, bool isVertical = true); | |||
virtual ~SplitComponent(); | |||
/** | |||
Sets (or replaces) the top component if the SplitComponent is horizontal, or the left component if the SplitComponent is vertical. | |||
The SplitComponent does not own the top/left component. It is not deleted when the SplitComponent is deleted. | |||
The caller must delete it. | |||
*/ | |||
void SetTopLeftComponent(Component &component); | |||
/** | |||
Sets (or replaces) the bottom component if the SplitComponent is horizontal, or the right component if the SplitComponent is vertical. | |||
The SplitComponent does not own the bottom/right component. It is not deleted when the SplitComponent is deleted. | |||
The caller must delete it. | |||
*/ | |||
void SetBottomRightComponent(Component &component); | |||
/** | |||
Sets the splitbar position vertically in terms of pixels if this is a horizontal SplitComponent.\n | |||
Sets the splitbar position horizontally in terms of pixels if this is a vertical SplitComponent.\n | |||
The position to which the split bar is actually set will be adjusted so it is inside the SplitComponent. | |||
@param[in] newPositionInPixels The new top/left position of the split bar. For a vertical split, the | |||
position will be limited to the width of the SplitComponent minus the | |||
thickness of the split bar. For a horizontal split, the position will | |||
be limited to the width of the SplitComponent minus the thickness of | |||
the split bar. | |||
*/ | |||
void SetSplitBarPosition(int newPositionInPixels); | |||
/** | |||
Gets the splitbar vertical position in terms of pixels if this is a horizontal SplitComponent. | |||
Sets the splitbar horizontal position in terms of pixels if this is a vertical SplitComponent. | |||
@returns The current split bar position. | |||
*/ | |||
int GetSplitBarPosition() const; | |||
/** | |||
Enables or disables the SplitComponent to always entirely fill it parent's client area. | |||
@param[in] fitToParent If true, the SplitComponent will always entirely fill it parent's client area. (The default) | |||
If false, the not fill it parent's client area, in which case you must set the bounds | |||
of the SplitContainer to be what you want. | |||
@see GetFitToParent | |||
*/ | |||
void SetFitToParent(bool fitToParent); | |||
/** | |||
Retrieves the current state of the fit-to-parent setting. | |||
@retval true If the SplitComponent is set to entirely fill it parent's client area. | |||
@retval false If the SplitComponent is notset to entirely fill it parent's client area. | |||
@see SetFitToParent | |||
*/ | |||
bool GetFitToParent() const; | |||
/** | |||
Sets the splitbar width in terms of pixels if this is a vertical SplitComponent.\n | |||
Sets the splitbar height in terms of pixels if this is a horizontal SplitComponent.\n | |||
The splitbar thickness can be set to 0 pixels in which case it's not visible and the | |||
user cannot move it. But its position can still be set programatically. | |||
@param[in] newThicknessInPixels The new width/height of the split bar. | |||
@see GetSplitBarThickness | |||
*/ | |||
void SetSplitBarThickness(int newThicknessInPixels); | |||
/** | |||
Gets the splitbar width in terms of pixels if this is a vertical SplitComponent.\n | |||
Gets the splitbar height in terms of pixels if this is a horizontal SplitComponent.\n | |||
@returns The current split bar thickness. | |||
@see SetSplitBarThickness | |||
*/ | |||
int GetSplitBarThickness() const; | |||
/** | |||
Sets the amount by which each component grows or shrinks when the windows is resized. | |||
- 0.0 means only the bottom/right component is resized. (The default) | |||
- 0.5 means each component is resized equally. | |||
- 1.0 means only the top/left component is resized. | |||
@param[in] gravity The gravity of the split bar. A value between 0.0 and 1.0. | |||
@see GetSplitBarGravity | |||
*/ | |||
void SetSplitBarGravity(double gravity); | |||
/** | |||
Gets the amount by which each component grows or shrinks when he windows is resized. | |||
@returns The current gravity of the split bar. A value between 0.0 and 1.0. | |||
@see SetSplitBarGravity | |||
*/ | |||
double GetSplitBarGravity() const; | |||
/** | |||
Sets the split direction of the SplitComponent. | |||
@param[in] isVertical If true, the split direction will be set (changed) to be vertical. | |||
If false, the split direction will be set (changed) to be horizontal. | |||
@see IstVerticalSplit | |||
*/ | |||
void SetVerticalSplit(bool isVertical); | |||
/** | |||
Gets the split direction of the SplitComponent. | |||
@retval true The split direction is currently vertical. | |||
@retval false The split direction is currently horizontal. | |||
@see SetVerticalSplit | |||
*/ | |||
bool IsVerticalSplit() const; | |||
/** Called when this component's immediate parent has been resized. | |||
@see resized, parentHierarchyChanged | |||
*/ | |||
void parentSizeChanged() override; | |||
void resized() override; | |||
/** | |||
This is defined for when the SplitContainer is added to a parent. It will resize itself to that parent. | |||
*/ | |||
void parentHierarchyChanged() override; | |||
private: | |||
class SplitBar : public Component | |||
{ | |||
public: | |||
SplitBar(SplitComponent& splitComponent, bool isVertical); | |||
void SetVertical(bool isVertical); | |||
bool IsVertical(); | |||
void paint(Graphics&) override; | |||
void mouseDown(const MouseEvent&) override; | |||
void mouseDrag(const MouseEvent&) override; | |||
private: | |||
bool m_isVertical; | |||
SplitComponent& m_splitComponent; | |||
int m_mouseDownPos; | |||
}; | |||
void CommonConstruction(); | |||
/** | |||
Lays out the two components on either side of the split bar by setting their bounds according to where the split bar is. | |||
Layout assumes that the split bar bounds and position have already been set. | |||
*/ | |||
void Layout(); | |||
bool m_isVertical; | |||
bool m_fitToParent; | |||
ScopedPointer<SplitBar> m_pSplitBar; | |||
Component* m_pTopLeftComponent; ///< A pointer to the top component if the splitter is horizontal, or the left component if the splitter is vertical. | |||
Component* m_pBottomRightComponent; ///< A pointer to the bottom component if the splitter is horizontal, or the right component if the splitter is vertical. | |||
double m_splitBarGravity; | |||
// The following two values are used with gravity. The purpose of keeping these two is to avoid having the | |||
// splitbar walk left or right due to accumulated roundoff error when the SplitComponent is resized many times. | |||
int m_lastSplitbarMovePosition; ///< The position of the split bar the last time it was moved manually or programmatically. (Not as a result of a window resize) | |||
int m_lastSplitbarMoveExtent; ///< The width/height of the SplitComponent the last time the split bar was moved manually or programmatically. (Not as a result of a window resize) | |||
}; | |||
#endif // SPLITCOMPONENT_H_INCLUDED |
@@ -16,6 +16,8 @@ | |||
#include "AppConfig.h" | |||
#include "JucePluginCharacteristics.h" | |||
#define UseNativeDialogue 0 | |||
#include "modules/juce_audio_basics/juce_audio_basics.h" | |||
#include "modules/juce_audio_devices/juce_audio_devices.h" | |||
#include "modules/juce_audio_formats/juce_audio_formats.h" | |||
@@ -59,10 +59,10 @@ | |||
#endif | |||
#define JucePlugin_SilenceInProducesSilenceOut 1 | |||
#define JucePlugin_TailLengthSeconds 0 | |||
#define JucePlugin_TailLengthSeconds 0 | |||
#define JucePlugin_EditorRequiresKeyboardFocus 1 | |||
#define JucePlugin_VersionCode 0x10000 | |||
#define JucePlugin_VersionString "0.0.0" | |||
#define JucePlugin_VersionString "1.0.0" | |||
#define JucePlugin_VSTUniqueID JucePlugin_PluginCode | |||
#define JucePlugin_VSTCategory kPlugCategEffect | |||
#define JucePlugin_AUSubType JucePlugin_PluginCode | |||
@@ -4,7 +4,7 @@ | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
@@ -29,35 +29,35 @@ | |||
#include "../CabbageLookAndFeel.h" | |||
class ProcessorParameterPropertyComp : public PropertyComponent, | |||
public AudioProcessorListener, | |||
public Timer | |||
public AudioProcessorListener, | |||
public Timer | |||
{ | |||
//============================================================================== | |||
//============================================================================== | |||
class ParamSlider : public Slider, | |||
public ActionBroadcaster | |||
// public ActionListener | |||
public ActionBroadcaster | |||
// public ActionListener | |||
{ | |||
public: | |||
ParamSlider (AudioProcessor& owner_, const int index_) | |||
: owner (owner_), | |||
index (index_) | |||
{ | |||
//basicLookAndFeel = new CabbageLookAndFeelBasic(); | |||
setLookAndFeel(basicLookAndFeel); | |||
this->setColour(Slider::textBoxBackgroundColourId, CabbageUtils::getBackgroundSkin()); | |||
//basicLookAndFeel = new CabbageLookAndFeelBasic(); | |||
setLookAndFeel(basicLookAndFeel); | |||
this->setColour(Slider::textBoxBackgroundColourId, CabbageUtils::getBackgroundSkin()); | |||
setRange (0.0, 1.0, 0.0); | |||
setSliderStyle (Slider::LinearHorizontal); | |||
setTextBoxStyle (Slider::TextBoxLeft, false, 80, 15); | |||
setSliderStyle (Slider::LinearHorizontal); | |||
setTextBoxStyle (Slider::TextBoxLeft, false, 80, 15); | |||
setTextBoxIsEditable (false); | |||
setScrollWheelEnabled (false); | |||
} | |||
void valueChanged() | |||
{ | |||
//this return the name of the plugin | |||
//this calls ProcessorParameterPropertyComp::actionListenerCallbck | |||
this->sendActionMessage(""); | |||
//this return the name of the plugin | |||
//this calls ProcessorParameterPropertyComp::actionListenerCallbck | |||
this->sendActionMessage(""); | |||
const float newVal = (float) getValue(); | |||
if (owner.getParameter (index) != newVal) | |||
@@ -75,15 +75,15 @@ class ProcessorParameterPropertyComp : public PropertyComponent, | |||
//============================================================================== | |||
AudioProcessor& owner; | |||
const int index; | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamSlider); | |||
}; | |||
public: | |||
ParamSlider slider; | |||
Colour highlightColour; | |||
bool moddedText; | |||
ParamSlider slider; | |||
Colour highlightColour; | |||
bool moddedText; | |||
ProcessorParameterPropertyComp (const String& name, AudioProcessor& owner_, const int index_) | |||
: PropertyComponent (name), | |||
@@ -92,12 +92,12 @@ public: | |||
paramHasChanged (false), | |||
slider (owner_, index_) | |||
{ | |||
moddedText = false; | |||
setPreferredHeight(20); | |||
startTimer (100); | |||
moddedText = false; | |||
setPreferredHeight(20); | |||
startTimer (100); | |||
addAndMakeVisible (&slider); | |||
owner_.addListener (this); | |||
highlightColour = CabbageUtils::getDarkerBackgroundSkin(); | |||
highlightColour = CabbageUtils::getDarkerBackgroundSkin(); | |||
} | |||
~ProcessorParameterPropertyComp() | |||
@@ -107,7 +107,7 @@ public: | |||
void refresh() | |||
{ | |||
paramHasChanged = false; | |||
paramHasChanged = false; | |||
slider.setValue (owner.getParameter (index), sendNotification); | |||
} | |||
@@ -133,30 +133,30 @@ public: | |||
} | |||
} | |||
void paint(Graphics &g) | |||
{ | |||
g.fillAll(CabbageUtils::getComponentSkin().darker(.4f)); //background | |||
String text = getName(); | |||
if(moddedText) | |||
g.setColour(Colours::yellow); | |||
else | |||
g.setColour(Colours::whitesmoke); | |||
Font font (CabbageUtils::getTitleFont()); | |||
//font.setFallbackFontName (String("Verdana")); //in case the user doesn't have the first font installed | |||
g.setFont (font); | |||
g.drawFittedText(text, 5, 5, | |||
font.getStringWidth(text), font.getHeight()-2, Justification::centredTop, 1); | |||
// g.drawFittedText(text, 5, 5, | |||
// font.getStringWidth(text), font.getHeight()-2, Justification::centredTop, 1); | |||
} | |||
void paint(Graphics &g) | |||
{ | |||
g.fillAll(CabbageUtils::getComponentSkin().darker(.4f)); //background | |||
String text = getName(); | |||
if(moddedText) | |||
g.setColour(Colours::yellow); | |||
else | |||
g.setColour(Colours::whitesmoke); | |||
Font font (CabbageUtils::getTitleFont()); | |||
//font.setFallbackFontName (String("Verdana")); //in case the user doesn't have the first font installed | |||
g.setFont (font); | |||
g.drawFittedText(text, 5, 5, | |||
font.getStringWidth(text), font.getHeight()-2, Justification::centredTop, 1); | |||
// g.drawFittedText(text, 5, 5, | |||
// font.getStringWidth(text), font.getHeight()-2, Justification::centredTop, 1); | |||
} | |||
private: | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
AudioProcessor& owner; | |||
const int index; | |||
bool volatile paramHasChanged; | |||
@@ -170,58 +170,58 @@ class CabbageGenericAudioProcessorEditor : public AudioProcessorEditor | |||
public: | |||
//============================================================================== | |||
CabbageGenericAudioProcessorEditor(AudioProcessor* const owner_) | |||
: AudioProcessorEditor (owner_) | |||
{ | |||
jassert (owner_ != nullptr); | |||
setOpaque (true); | |||
basicLookAndFeel = new CabbageLookAndFeelBasic(); | |||
this->setLookAndFeel(basicLookAndFeel); | |||
addAndMakeVisible (&panel); | |||
CabbageGenericAudioProcessorEditor(AudioProcessor* const owner_) | |||
: AudioProcessorEditor (owner_) | |||
{ | |||
jassert (owner_ != nullptr); | |||
setOpaque (true); | |||
basicLookAndFeel = new CabbageLookAndFeelBasic(); | |||
this->setLookAndFeel(basicLookAndFeel); | |||
addAndMakeVisible (&panel); | |||
Array <PropertyComponent*> params; | |||
Array <PropertyComponent*> params; | |||
const int numParams = owner_->getNumParameters(); | |||
Logger::writeToLog("NumParameters:" +String(numParams)); | |||
int totalHeight = 0; | |||
const int numParams = owner_->getNumParameters(); | |||
Logger::writeToLog("NumParameters:" +String(numParams)); | |||
int totalHeight = 0; | |||
for (int i = 0; i < numParams; ++i) | |||
{ | |||
String name (owner_->getParameterName (i)); | |||
if (name.trim().isEmpty()) | |||
name = "Unnamed"; | |||
for (int i = 0; i < numParams; ++i) | |||
{ | |||
String name (owner_->getParameterName (i)); | |||
if (name.trim().isEmpty()) | |||
name = "Unnamed"; | |||
ProcessorParameterPropertyComp* const pc = new ProcessorParameterPropertyComp (name, *owner_, i); | |||
params.add (pc); | |||
totalHeight += pc->getPreferredHeight(); | |||
} | |||
ProcessorParameterPropertyComp* const pc = new ProcessorParameterPropertyComp (name, *owner_, i); | |||
panel.addProperties (params); | |||
params.add (pc); | |||
totalHeight += pc->getPreferredHeight(); | |||
} | |||
setSize (400, jlimit (25, 400, totalHeight)); | |||
} | |||
panel.addProperties (params); | |||
~CabbageGenericAudioProcessorEditor() | |||
{ | |||
} | |||
setSize (400, jlimit (25, 400, totalHeight)); | |||
} | |||
~CabbageGenericAudioProcessorEditor() | |||
{ | |||
} | |||
void paint (Graphics& g) | |||
{ | |||
//background | |||
g.setColour(Colour::fromRGB(20, 20, 20)); | |||
g.fillAll(); | |||
} | |||
void paint (Graphics& g) | |||
{ | |||
//background | |||
g.setColour(Colour::fromRGB(20, 20, 20)); | |||
g.fillAll(); | |||
} | |||
void resized() | |||
{ | |||
panel.setBounds (getLocalBounds()); | |||
} | |||
void resized() | |||
{ | |||
panel.setBounds (getLocalBounds()); | |||
} | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
private: | |||
//============================================================================== | |||
PropertyPanel panel; | |||
@@ -4,7 +4,7 @@ | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
@@ -23,7 +23,6 @@ | |||
#include "../CabbageCustomWidgets.h" | |||
#include "../JuceHeader.h" | |||
#include "CabbagePluginProcessor.h" | |||
//#include "../CabbageLookAndFeel.h" | |||
#include "../CabbagePropertiesDialog.h" | |||
#include "../CabbageUtils.h" | |||
@@ -34,49 +33,88 @@ class CabbageMainPanel; | |||
class ComponentLayoutEditor; | |||
class CabbageCornerResizer; | |||
//============================================================================== | |||
// window used to display popup plants | |||
//============================================================================== | |||
class CabbagePlantWindow : public DocumentWindow | |||
{ | |||
public: | |||
CabbagePlantWindow(const String& title, const Colour& backgroundColour) | |||
: DocumentWindow (title, backgroundColour, DocumentWindow::closeButton){}; | |||
~CabbagePlantWindow(){ | |||
}; | |||
CabbagePlantWindow(const String& title, const Colour& backgroundColour) | |||
: DocumentWindow (title, backgroundColour, DocumentWindow::closeButton) | |||
{ | |||
setName(title); | |||
}; | |||
~CabbagePlantWindow() | |||
{ | |||
}; | |||
void closeButtonPressed(){ | |||
// void mouseMove(const MouseEvent& event) | |||
// { | |||
// Logger::writeToLog("planty"); | |||
// //Logger::writeToLog(String(this->getContentComponent()->getMouseXYRelative().getX())); | |||
// } | |||
// | |||
// | |||
void closeButtonPressed() | |||
{ | |||
setMinimised(true); | |||
setVisible(false); | |||
setAlwaysOnTop(false); | |||
}; | |||
setAlwaysOnTop(false); | |||
}; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePlantWindow); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePlantWindow); | |||
}; | |||
//============================================================================== | |||
// component that sits inside of main viewport class | |||
//============================================================================== | |||
class CabbageViewportComponent : public Component | |||
{ | |||
public: | |||
CabbageViewportComponent() : Component("CabbageViewportComponent") | |||
{ | |||
this->setInterceptsMouseClicks(false, true); | |||
} | |||
~CabbageViewportComponent() {} | |||
void paint(Graphics &g) | |||
{ | |||
Viewport* const viewport = findParentComponentOfClass<Viewport>(); //Get the parent viewport | |||
if(viewport != nullptr) //Check for nullness | |||
{ | |||
juce::Rectangle<int> viewRect(viewport->getViewPositionX(), viewport->getViewPositionY(), viewport->getViewWidth(), viewport->getViewHeight()); //Get the current displayed area in the viewport | |||
} | |||
} | |||
}; | |||
//============================================================================== | |||
// pointData class for holding info about each segment of a line | |||
class PointData | |||
//============================================================================== | |||
class PointData | |||
{ | |||
public: | |||
Point <int> point; | |||
int curveType; | |||
PointData(Point<int> point, int curveType):point(point),curveType(curveType) | |||
{} | |||
~PointData(){} | |||
Point <int> point; | |||
int curveType; | |||
PointData(Point<int> point, int curveType):point(point),curveType(curveType) | |||
{} | |||
~PointData() {} | |||
}; | |||
//============================================================================== | |||
// main GUI editor window | |||
//============================================================================== | |||
class CabbagePluginAudioProcessorEditor : public AudioProcessorEditor, | |||
public CabbageUtils, | |||
public SliderListener, | |||
public ComboBoxListener, | |||
public ButtonListener, | |||
public KeyListener, | |||
public ChangeBroadcaster, | |||
public ChangeListener, | |||
public ActionListener, | |||
public Timer | |||
public CabbageUtils, | |||
public SliderListener, | |||
public ComboBoxListener, | |||
public ButtonListener, | |||
public KeyListener, | |||
public ChangeBroadcaster, | |||
public ChangeListener, | |||
public ActionListener | |||
{ | |||
public: | |||
CabbagePluginAudioProcessorEditor (CabbagePluginAudioProcessor* ownerFilter); | |||
@@ -84,124 +122,134 @@ public: | |||
void paint (Graphics& g); | |||
void resized(); | |||
void setEditMode(bool on); | |||
void InsertGUIControls(CabbageGUIClass cAttr); | |||
void ksmpsYieldCallback(); | |||
void updateSize(); | |||
ScopedPointer<CabbagePropertiesDialog> propsWindow; | |||
//main GUI controls vectors.. | |||
OwnedArray<Component> comps; | |||
OwnedArray<Component> layoutComps; | |||
void updateLayoutEditorFrames(); | |||
ScopedPointer<CabbageTable> cabTable; | |||
ScopedPointer<CabbageCornerResizer> resizer; | |||
void setEditMode(bool on); | |||
void InsertGUIControls(CabbageGUIClass cAttr); | |||
void ksmpsYieldCallback(); | |||
void updateSize(); | |||
ScopedPointer<CabbagePropertiesDialog> propsWindow; | |||
//main GUI controls vectors.. | |||
OwnedArray<Component> comps; | |||
OwnedArray<Component> layoutComps; | |||
void updateLayoutEditorFrames(); | |||
ScopedPointer<CabbageTable> cabTable; | |||
ScopedPointer<CabbageCornerResizer> resizer; | |||
Point<int> getMousePos(); | |||
Array<int> popupMenus; | |||
void updateGUIControls(); | |||
OwnedArray<CabbagePlantWindow> subPatches; | |||
//CabbagePluginAudioProcessor* filter; | |||
CabbagePluginAudioProcessor* getFilter() const | |||
{ | |||
return static_cast <CabbagePluginAudioProcessor*> (getAudioProcessor()); | |||
} | |||
int currentPopupIndex; | |||
private: | |||
void createfTableData(Table* table); | |||
bool keyPressed(const juce::KeyPress &,Component *); | |||
void updateSizesAndPositionsOfComponents(int newLine = 0); | |||
void deleteComponents(); | |||
void duplicateComponents(); | |||
void populateLineNumberArray(StringArray csdArray); | |||
void addToRepository(String entryName); | |||
void convertIntoPlant(); | |||
void breakUpPlant(); | |||
void InsertGroupBox(CabbageGUIClass &cAttr); | |||
void comboBoxChanged (ComboBox* combo); | |||
void InsertComboBox(CabbageGUIClass &cAttr); | |||
void InsertSoundfiler(CabbageGUIClass &cAttr); | |||
void InsertDirectoryList(CabbageGUIClass &cAttr); | |||
void SetupWindow(CabbageGUIClass &cAttr); | |||
void InsertSlider(CabbageGUIClass &cAttr); | |||
void sliderValueChanged (Slider*); | |||
void InsertButton(CabbageGUIClass &cAttr); | |||
void InsertSourceButton(CabbageGUIClass &cAttr); | |||
void InsertVUMeter(CabbageGUIClass &cAttr); | |||
void InsertCheckBox(CabbageGUIClass &cAttr); | |||
void InsertCsoundOutput(CabbageGUIClass &cAttr); | |||
void InsertMIDIKeyboard(CabbageGUIClass &cAttr); | |||
void InsertXYPad(CabbageGUIClass &cAttr); | |||
void InsertFileButton(CabbageGUIClass &cAttr); | |||
void InsertImage(CabbageGUIClass &cAttr); | |||
void InsertLabel(CabbageGUIClass &cAttr); | |||
void InsertTable(CabbageGUIClass &cAttr); | |||
void InsertMultiTab(CabbageGUIClass &cAttr); | |||
void InsertInfoButton(CabbageGUIClass &cAttr); | |||
void InsertLineSeparator(CabbageGUIClass &cAttr); | |||
void InsertPatternMatrix(CabbageGUIClass &cAttr); | |||
void InsertSnapshot(CabbageGUIClass &cAttr); | |||
void InsertPVSViewer(CabbageGUIClass &cAttr); | |||
void InsertTransport(CabbageGUIClass &cAttr); | |||
void buttonClicked(Button*); | |||
void buttonStateChanged(Button*); | |||
void showInsertControlsMenu(int x, int y); | |||
void actionListenerCallbackForWidgets(const String message); | |||
void insertScoreStatementText(Table *table, bool overwrite); | |||
void restoreParametersFromPresets(XmlElement* xmlData); | |||
void savePresetsFromParameters(File selectedFile, String mode); | |||
void refreshDiskReadingGUIControls(String typeOfControl); | |||
void updateGUIControls(); | |||
void timerCallback(); | |||
bool LOCKED; | |||
void insertComponentsFromCabbageText(StringArray text, bool useOffset); | |||
// void insertComponentsFromCabbageTextArray(StringArray text, bool plant); | |||
Array<int> lineNumbers; | |||
Array<int> plantLineNumbers; | |||
int currentLineNumber; | |||
File SnapShotFile; | |||
String presetFileText; | |||
String tempPlantText; | |||
void actionListenerCallback (const String& message); | |||
int zero_dbfs; | |||
StringArray tempArray; | |||
StringArray pastEvents; | |||
Array<Rectangle <int> > boundsForDuplicatedCtrls; | |||
//CabbagePluginAudioProcessor* filter; | |||
CabbagePluginAudioProcessor* getFilter() const | |||
{ | |||
return static_cast <CabbagePluginAudioProcessor*> (getAudioProcessor()); | |||
} | |||
bool keyStateChanged(bool onoff){ | |||
keyIsPressed = onoff; | |||
return false; | |||
} | |||
bool keyIsPressed; | |||
bool isMouseDown; | |||
void positionComponentWithinPlant(String type, int idx, float left, float top, float width, float height, Component *layout, Component *control); | |||
//ScopedPointer<CabbagePlantWindow> subPatch; | |||
OwnedArray<CabbageButton> plantButton; | |||
OwnedArray<CabbagePlantWindow> subPatch; | |||
ScopedPointer<InfoWindow> infoWindow; | |||
void setPositionOfComponent(float x, float y, float width, float height, Component* comp, String reltoplant); | |||
void createfTableData(Table* table, bool sendToCsound); | |||
bool keyPressed(const juce::KeyPress &,Component *); | |||
void updateSizesAndPositionsOfComponents(int newLine = 0); | |||
void deleteComponents(); | |||
void duplicateComponents(); | |||
void populateLineNumberArray(StringArray csdArray); | |||
void addToRepository(String entryName); | |||
void convertIntoPlant(); | |||
void breakUpPlant(); | |||
void InsertGroupBox(CabbageGUIClass &cAttr); | |||
void comboBoxChanged (ComboBox* combo); | |||
void InsertComboBox(CabbageGUIClass &cAttr); | |||
void InsertSoundfiler(CabbageGUIClass &cAttr); | |||
void InsertDirectoryList(CabbageGUIClass &cAttr); | |||
void SetupWindow(CabbageGUIClass &cAttr); | |||
void InsertSlider(CabbageGUIClass &cAttr); | |||
void InsertTextEditor(CabbageGUIClass &cAttr); | |||
void sliderValueChanged (Slider*); | |||
void InsertButton(CabbageGUIClass &cAttr); | |||
void InsertCheckBox(CabbageGUIClass &cAttr); | |||
void InsertCsoundOutput(CabbageGUIClass &cAttr); | |||
void InsertMIDIKeyboard(CabbageGUIClass &cAttr); | |||
void InsertXYPad(CabbageGUIClass &cAttr); | |||
void InsertFileButton(CabbageGUIClass &cAttr); | |||
void InsertRecordButton(CabbageGUIClass &cAttr); | |||
void InsertImage(CabbageGUIClass &cAttr); | |||
void InsertLabel(CabbageGUIClass &cAttr); | |||
void InsertTable(CabbageGUIClass &cAttr); | |||
void InsertMultiTab(CabbageGUIClass &cAttr); | |||
void InsertInfoButton(CabbageGUIClass &cAttr); | |||
void InsertLineSeparator(CabbageGUIClass &cAttr); | |||
void InsertPatternMatrix(CabbageGUIClass &cAttr); | |||
void InsertSnapshot(CabbageGUIClass &cAttr); | |||
void InsertTransport(CabbageGUIClass &cAttr); | |||
void InsertPopupMenu(CabbageGUIClass &cAttr); | |||
void InsertGenTable(CabbageGUIClass &cAttr); | |||
void InsertTextbox(CabbageGUIClass &cAttr); | |||
void InsertNumberBox(CabbageGUIClass &cAttr); | |||
void buttonClicked(Button*); | |||
void mouseMove(const MouseEvent& event); | |||
void mouseDown(const MouseEvent& event); | |||
void mouseUp(const MouseEvent& event); | |||
void buttonStateChanged(Button*); | |||
void showInsertControlsMenu(int x, int y); | |||
void insertScoreStatementText(Table *table, bool overwrite); | |||
void restoreParametersFromPresets(XmlElement* xmlData); | |||
void savePresetsFromParameters(File selectedFile, String mode); | |||
void refreshDiskReadingGUIControls(String typeOfControl); | |||
void updatefTableData(GenTable* table); | |||
int mouseX, mouseY; | |||
bool LOCKED; | |||
void insertComponentsFromCabbageText(StringArray text, bool useOffset); | |||
Array<int> lineNumbers; | |||
Array<int> plantLineNumbers; | |||
int currentLineNumber; | |||
File SnapShotFile; | |||
String presetFileText; | |||
String tempPlantText; | |||
void actionListenerCallback (const String& message); | |||
int zero_dbfs; | |||
StringArray tempArray; | |||
StringArray pastEvents; | |||
Array <float, CriticalSection> tableValues; | |||
AudioSampleBuffer tableBuffer; | |||
ScopedPointer<Viewport> viewport; | |||
ScopedPointer<CabbageViewportComponent> viewportComponent; | |||
bool keyStateChanged(bool onoff) | |||
{ | |||
keyIsPressed = onoff; | |||
return false; | |||
} | |||
bool keyIsPressed; | |||
bool isMouseDown; | |||
bool showScrollbars; | |||
void positionComponentWithinPlant(String type, float left, float top, float width, float height, Component *layout, Component *control); | |||
//ScopedPointer<CabbagePlantWindow> subPatch; | |||
OwnedArray<CabbageButton> plantButton; | |||
ScopedPointer<InfoWindow> infoWindow; | |||
#ifdef Cabbage_GUI_Editor | |||
ScopedPointer<CabbageMainPanel> componentPanel; | |||
ScopedPointer<ComponentLayoutEditor> layoutEditor; | |||
ScopedPointer<CabbageMainPanel> componentPanel; | |||
ScopedPointer<ComponentLayoutEditor> layoutEditor; | |||
#else | |||
ScopedPointer<Component> componentPanel; | |||
ScopedPointer<Component> componentPanel; | |||
#endif | |||
ScopedPointer<MidiKeyboardComponent> midiKeyboard; | |||
ScopedPointer<LookAndFeel> feely; | |||
Array<float> incomingValues; | |||
ComponentBoundsConstrainer resizeLimits; | |||
AudioPlayHead::CurrentPositionInfo hostInfo; | |||
void changeListenerCallback (ChangeBroadcaster *source); | |||
Colour formColour, fontColour; | |||
String authorText; | |||
String formPic; | |||
float inValue; | |||
int xyPadIndex; | |||
ScopedPointer<CabbageLookAndFeel> lookAndFeel; | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
ScopedPointer<Label> debugLabel; | |||
StringArray scoreEvents; | |||
ScopedPointer<MidiKeyboardComponent> midiKeyboard; | |||
ScopedPointer<LookAndFeel> feely; | |||
ComponentBoundsConstrainer resizeLimits; | |||
AudioPlayHead::CurrentPositionInfo hostInfo; | |||
void changeListenerCallback (ChangeBroadcaster *source); | |||
Colour formColour, fontColour; | |||
String authorText; | |||
String formPic; | |||
float inValue; | |||
int xyPadIndex; | |||
ScopedPointer<CabbageLookAndFeel> lookAndFeel; | |||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||
ScopedPointer<Label> debugLabel; | |||
StringArray scoreEvents; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePluginAudioProcessorEditor); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePluginAudioProcessorEditor); | |||
}; | |||
@@ -209,17 +257,18 @@ private: | |||
//============================================================================== | |||
class CabbageCornerResizer : public ResizableCornerComponent | |||
{ | |||
CabbagePluginAudioProcessorEditor* editor; | |||
CabbagePluginAudioProcessorEditor* editor; | |||
public: | |||
CabbageCornerResizer(CabbagePluginAudioProcessorEditor* parent, Component* comp, ComponentBoundsConstrainer *constrainer): | |||
ResizableCornerComponent(comp, constrainer), editor(parent){}; | |||
~CabbageCornerResizer(){}; | |||
void mouseUp(const MouseEvent &e){ | |||
editor->updateSize(); | |||
} | |||
CabbageCornerResizer(CabbagePluginAudioProcessorEditor* parent, Component* comp, ComponentBoundsConstrainer *constrainer): | |||
ResizableCornerComponent(comp, constrainer), editor(parent) {}; | |||
~CabbageCornerResizer() {}; | |||
void mouseUp(const MouseEvent &e) | |||
{ | |||
editor->updateSize(); | |||
} | |||
}; | |||
#endif // __PLUGINEDITOR_H_F4EBBBA1__ | |||
@@ -27,12 +27,18 @@ | |||
#include "../XYPadAutomation.h" | |||
#include "../CabbageMessageSystem.h" | |||
#include "../Soundfiler.h" | |||
#include "CabbageGenericAudioProcessorEditor.h" | |||
#include "CabbageGenericAudioProcessorEditor.h" | |||
#include "../CabbageLookAndFeel.h" | |||
#ifndef Cabbage_No_Csound | |||
#include <csound.hpp> | |||
#include "cwindow.h" | |||
#ifdef AndroidBuild | |||
#include "AndroidCsound.hpp" | |||
#else | |||
#include <csound.hpp> | |||
#endif | |||
#include "csdl.h" | |||
//#include "cwindow.h" | |||
#include "../csPerfThread.hpp" | |||
#endif | |||
@@ -40,7 +46,11 @@ | |||
//#include "../Editor/CabbageEditorWindow.h" | |||
//#endif | |||
#define CABBAGE_VERSION "Cabbage v0.5.07 Alpha" | |||
#ifdef Cabbage64Bit | |||
#define CABBAGE_VERSION "Cabbage(64bit) v0.5.13 Alpha" | |||
#else | |||
#define CABBAGE_VERSION "Cabbage(32bit) v0.5.13 Alpha" | |||
#endif | |||
#define AUDIO_PLUGIN 1 | |||
#define EXTERNAL_PLUGIN 2 | |||
@@ -50,135 +60,179 @@ | |||
class CsoundCodeEditor; | |||
#endif | |||
extern CabbageLookAndFeel* lookAndFeel; | |||
extern CabbageLookAndFeelBasic* lookAndFeelBasic; | |||
#if defined(BUILD_DEBUGGER) && !defined(Cabbage_No_Csound) | |||
#include <csdebug.h> | |||
#endif | |||
//============================================================================== | |||
// CabbagePluginAudioProcessor definition | |||
//============================================================================== | |||
class CabbagePluginAudioProcessor : public AudioProcessor, | |||
public CabbageUtils, | |||
public ChangeBroadcaster, | |||
public Timer, | |||
public ActionBroadcaster, | |||
public ChangeListener | |||
public CabbageUtils, | |||
public ChangeBroadcaster, | |||
public Timer, | |||
public ActionBroadcaster, | |||
public ChangeListener | |||
{ | |||
//============================================================================== | |||
protected: | |||
File csdFile; | |||
int masterCounter; | |||
String filename; | |||
String pluginName; | |||
bool csoundStatus; | |||
int csCompileResult; | |||
void timerCallback(); | |||
String csoundOutput; | |||
void changeListenerCallback(ChangeBroadcaster *source); | |||
String changeMessageType; | |||
bool guiON; | |||
int currentLine; | |||
bool xyAutosCreated; | |||
bool updateTable; | |||
Array<int> tableNumbers; | |||
AudioSourceChannelInfo soundfilerChannelData; | |||
AudioPlayHead::CurrentPositionInfo hostInfo; | |||
int soundFileIndex; | |||
//ScopedPointer<FileLogger> fileLogger; | |||
File logFile; | |||
bool isAutomator; | |||
bool isNativeThreadRunning; | |||
//============== Csound related variables/methods ============================== | |||
File csdFile; | |||
int masterCounter; | |||
String filename; | |||
String pluginName; | |||
bool csoundStatus; | |||
int csCompileResult; | |||
void timerCallback(); | |||
String csoundOutput; | |||
String debuggerMessage; | |||
void changeListenerCallback(ChangeBroadcaster *source); | |||
String changeMessageType; | |||
bool guiON; | |||
int currentLine; | |||
bool xyAutosCreated; | |||
bool updateTable; | |||
Array<int> tableNumbers; | |||
AudioPlayHead::CurrentPositionInfo hostInfo; | |||
ScopedPointer<FileLogger> fileLogger; | |||
bool createLog; | |||
File logFile; | |||
bool isAutomator; | |||
bool isWinXP; | |||
bool isNativeThreadRunning; | |||
String csoundDebuggerOutput; | |||
//============== Csound related variables/methods ============================== | |||
#ifndef Cabbage_No_Csound | |||
ScopedPointer<CSOUND_PARAMS> csoundParams; | |||
ScopedPointer<CsoundPerformanceThread> csoundPerfThread; | |||
PVSDATEXT* dataout; | |||
MYFLT cs_scale; | |||
ScopedPointer<Csound> csound; //Csound instance | |||
MYFLT *CSspin, *CSspout; //Csound audio IO pointers | |||
int csndIndex; //Csound sample counter | |||
int csdKsmps; | |||
MYFLT *soundFilerTempVector; | |||
int CSCompResult; //result of Csound performKsmps | |||
controlChannelInfo_s* csoundChanList; | |||
int numCsoundChannels; //number of Csound channels | |||
static void messageCallback(CSOUND *csound, int attr, const char *fmt, va_list args); //message callback function | |||
int pos; | |||
//Csound API functions for deailing with midi input | |||
static int OpenMidiInputDevice(CSOUND * csnd, void **userData, const char *devName); | |||
static int OpenMidiOutputDevice(CSOUND * csnd, void **userData, const char *devName); | |||
static int ReadMidiData(CSOUND *csound, void *userData, unsigned char *mbuf, int nbytes); | |||
static int WriteMidiData(CSOUND *csound, void *userData, const unsigned char *mbuf, int nbytes); | |||
int getNumberCsoundOutChannels(){ | |||
return csound->GetNchnls(); | |||
} | |||
int getNumberCsoundInChannels(){ | |||
//return csound->GetInNchnls(); | |||
} | |||
int getCsoundSamplingRate(){ | |||
return csound->GetSr(); | |||
} | |||
int getCsoundKsmpsSize(){ | |||
return csound->GetKsmps(); | |||
} | |||
ScopedPointer<CSOUND_PARAMS> csoundParams; | |||
ScopedPointer<CsoundPerformanceThread> csoundPerfThread; | |||
PVSDATEXT* dataout; | |||
MYFLT cs_scale; | |||
#if !defined(AndroidBuild) | |||
ScopedPointer<Csound> csound; //Csound instance | |||
#else | |||
ScopedPointer<AndroidCsound> csound; | |||
#endif | |||
static void YieldCallback(void* data); | |||
void updateCabbageControls(); | |||
void sendOutgoingMessagesToCsound(); | |||
void sendAudioToCsoundFromSoundFilers(int numSamples); | |||
StringArray debugInfo; | |||
//basic classes that hold all information regarding GUI objects | |||
//guiLayoutControls are not used to send data to Csound, and don't show | |||
//as parameters in a host, guiCtrls do show are parameters, and can send | |||
//channel messages to Csound. | |||
Array<CabbageGUIClass, CriticalSection> guiLayoutCtrls; | |||
Array<CabbageGUIClass, CriticalSection> guiCtrls; | |||
String plantFlag, presetFlag; | |||
String debugMessage; | |||
StringArray debugMessageArray; | |||
String currentLineText; | |||
bool editorReOpened; | |||
OwnedArray<XYPadAutomation, CriticalSection> xyAutomation; | |||
void updateGUIControlsKsmps(int speed); | |||
int guiRefreshRate; | |||
public: | |||
MYFLT *CSspin, *CSspout; //Csound audio IO pointers | |||
int csndIndex; //Csound sample counter | |||
int csdKsmps; | |||
int CSCompResult; //result of Csound performKsmps | |||
controlChannelInfo_s* csoundChanList; | |||
int numCsoundChannels; //number of Csound channels | |||
static void messageCallback(CSOUND *csound, int attr, const char *fmt, va_list args); //message callback function | |||
#if defined(BUILD_DEBUGGER) && !defined(Cabbage_No_Csound) | |||
static void breakpointCallback(CSOUND *csound, debug_bkpt_info_t *bkpt_info, void *udata); | |||
#endif | |||
//Csound API functions for deailing with midi input | |||
static int OpenMidiInputDevice(CSOUND * csnd, void **userData, const char *devName); | |||
static int OpenMidiOutputDevice(CSOUND * csnd, void **userData, const char *devName); | |||
static int ReadMidiData(CSOUND *csound, void *userData, unsigned char *mbuf, int nbytes); | |||
static int WriteMidiData(CSOUND *csound, void *userData, const unsigned char *mbuf, int nbytes); | |||
int getNumberCsoundOutChannels() | |||
{ | |||
return csound->GetNchnls(); | |||
} | |||
int getNumberCsoundInChannels() | |||
{ | |||
//return csound->GetInNchnls(); | |||
} | |||
int getCsoundSamplingRate() | |||
{ | |||
return csound->GetSr(); | |||
} | |||
int getCsoundKsmpsSize() | |||
{ | |||
return csound->GetKsmps(); | |||
} | |||
#endif | |||
static void YieldCallback(void* data); | |||
void updateCabbageControls(); | |||
void sendOutgoingMessagesToCsound(); | |||
int ksmpsOffset; | |||
bool CS_DEBUG_MODE; | |||
int pos; | |||
StringArray debugInfo; | |||
//basic classes that hold all information regarding GUI objects | |||
//guiLayoutControls are not used to send data to Csound, and don't show | |||
//as parameters in a host, guiCtrls do show are parameters, and can send | |||
//channel messages to Csound. | |||
Array<CabbageGUIClass, CriticalSection> guiLayoutCtrls; | |||
Array<CabbageGUIClass, CriticalSection> guiCtrls; | |||
String plantFlag, presetFlag; | |||
String debugMessage; | |||
StringArray debugMessageArray; | |||
String currentLineText; | |||
bool editorReOpened; | |||
OwnedArray<XYPadAutomation, CriticalSection> xyAutomation; | |||
void updateGUIControlsKsmps(int speed); | |||
int guiRefreshRate; | |||
#ifdef Cabbage_No_Csound | |||
std::vector<float> temp; | |||
#else | |||
std::vector<MYFLT> temp; | |||
#endif | |||
TimeSliceThread backgroundThread; // the thread that will write our audio data to disk | |||
ScopedPointer<AudioFormatWriter::ThreadedWriter> threadedWriter; // the FIFO used to buffer the incoming data | |||
double sampleRate; | |||
int64 nextSampleNum; | |||
File tempAudioFile; | |||
CriticalSection writerLock; | |||
AudioFormatWriter::ThreadedWriter* volatile activeWriter; | |||
public: | |||
String changeMessage; | |||
Array<int> dirtyControls; | |||
bool CSOUND_DEBUG_MODE; | |||
void setCsoundInstrumentBreakpoint(int instr, int line); | |||
void removeCsoundInstrumentBreakpoint(int instr); | |||
void continueCsoundDebug(); | |||
void nextCsoundDebug(); | |||
void cleanCsoundDebug(); | |||
//============================================================================== | |||
#if defined(Cabbage_Build_Standalone) || (Cabbage_Plugin_Host) | |||
CabbagePluginAudioProcessor(String inputfile, bool guiOnOff, int pluginType); | |||
#else | |||
CabbagePluginAudioProcessor(); | |||
CabbagePluginAudioProcessor(); | |||
#endif | |||
~CabbagePluginAudioProcessor(); | |||
#ifdef Cabbage_Build_Standalone | |||
CsoundCodeEditor* codeEditor; | |||
#endif | |||
bool haveXYAutosBeenCreated(){ | |||
return xyAutosCreated; | |||
} | |||
void setHaveXYAutoBeenCreated(bool val){ | |||
xyAutosCreated = val; | |||
} | |||
double getTailLengthSeconds(void) const { | |||
return 1; | |||
} | |||
#ifdef Cabbage_Build_Standalone | |||
CsoundCodeEditor* codeEditor; | |||
#endif | |||
int performEntireScore(); | |||
void reCompileCsound(File file); | |||
void setupNativePluginEditor(); | |||
bool compiledOk() | |||
{ | |||
return csCompileResult; | |||
} | |||
bool haveXYAutosBeenCreated() | |||
{ | |||
return xyAutosCreated; | |||
} | |||
void setHaveXYAutoBeenCreated(bool val) | |||
{ | |||
xyAutosCreated = val; | |||
} | |||
double getTailLengthSeconds(void) const | |||
{ | |||
return 1; | |||
} | |||
int performEntireScore(); | |||
void startRecording(); | |||
void stopRecording(); | |||
void reCompileCsound(File file); | |||
void setupNativePluginEditor(); | |||
//============================================================================== | |||
void prepareToPlay (double sampleRate, int samplesPerBlock); | |||
void releaseResources(); | |||
@@ -199,16 +253,13 @@ public: | |||
bool isOutputChannelStereoPair (int index) const; | |||
bool acceptsMidi() const; | |||
bool producesMidi() const; | |||
Array<CabbagePatternMatrixStepData> patStepMatrix; | |||
StringArray patternNames; | |||
Array<CabbagePatternMatrixPfieldData> patPfieldMatrix; | |||
//Array<int> pField4, pField5, pField6, pField7; | |||
int noSteps; | |||
int noPatterns; | |||
int timeCounter; | |||
int beat; | |||
int patMatrixActive; | |||
float bpm; | |||
//Array<int> pField4, pField5, pField6, pField7; | |||
int noSteps; | |||
int noPatterns; | |||
int timeCounter; | |||
int beat; | |||
int patMatrixActive; | |||
float bpm; | |||
//============================================================================== | |||
int getNumPrograms(); | |||
int getCurrentProgram(); | |||
@@ -218,265 +269,318 @@ public: | |||
//============================================================================== | |||
void getStateInformation (MemoryBlock& destData); | |||
void setStateInformation (const void* data, int sizeInBytes); | |||
const Array<double, CriticalSection> getTable(int tableNum); | |||
void createGUI(String source, bool refresh); | |||
MidiKeyboardState keyboardState; | |||
//midiBuffers | |||
MidiBuffer midiBuffer; | |||
MidiBuffer midiOutputBuffer; | |||
MidiBuffer ccBuffer; | |||
bool showMIDI; | |||
bool yieldCallbackBool; | |||
int yieldCounter; | |||
bool nativePluginEditor; | |||
CabbageMessageQueue messageQueue; | |||
OwnedArray<CabbageAudioSource, CriticalSection> audioSourcesArray; | |||
void addSoundfilerSource(String filename, StringArray channels); | |||
StringArray scoreEvents; | |||
int averageSampleIndex; | |||
float outputNo1; | |||
int pluginType; | |||
float automationAmp; | |||
int automationParamID; | |||
int pluginCalls, csoundCalls; | |||
//============================================================================== | |||
File getCsoundInputFile(){ | |||
return csdFile; | |||
} | |||
inline String getCsoundInputFileText(){ | |||
String ret=""; | |||
#ifdef Cabbage_Build_Standalone | |||
if(codeEditor) | |||
ret = codeEditor->getAllText(); | |||
else | |||
ret = csdFile.loadFileAsString(); | |||
#endif | |||
return ret; | |||
} | |||
void updateCsoundFile(String text){ | |||
//csdFile.replaceWithText(text); | |||
#ifdef Cabbage_Build_Standalone | |||
//codeEditor->textChanged = true; | |||
codeEditor->setAllText(text); | |||
#endif | |||
} | |||
bool hasTextChanged(){ | |||
#ifdef Cabbage_Build_Standalone | |||
if(codeEditor) | |||
return codeEditor->textChanged; | |||
else return false; | |||
#else | |||
return false; | |||
#endif | |||
} | |||
void saveText(){ | |||
#ifdef Cabbage_Build_Standalone | |||
codeEditor->textChanged = false; | |||
#endif | |||
} | |||
void setOpcodeDirEnv(){ | |||
#ifdef WIN32 | |||
//showMessage(getenv("OPCODE6DIR64")); | |||
String opcodeDir = File::getSpecialLocation(File::currentExecutableFile).getParentDirectory().getFullPathName()+"\\CsoundPlugins"; | |||
//showMessage(opcodeDir); | |||
if(File(opcodeDir).exists()){ | |||
String env = "OPCODE6DIR64="+opcodeDir; | |||
_putenv(env.toUTF8().getAddress()); | |||
//showMessage(getenv("OPCODE6DIR64")); | |||
} | |||
#endif | |||
} | |||
void highlightLine(String text){ | |||
#ifdef Cabbage_Build_Standalone | |||
codeEditor->highlightLine(text); | |||
#endif | |||
} | |||
String getDebugMessage(){ | |||
return debugMessage; | |||
} | |||
void addDebugMessage(String message){ | |||
debugMessageArray.add(message);; | |||
} | |||
StringArray getDebugMessageArray(){ | |||
return debugMessageArray; | |||
} | |||
void clearDebugMessageArray(){ | |||
debugMessageArray.clear(); | |||
} | |||
int getCompileStatus(){ | |||
return csCompileResult; | |||
} | |||
void clearDebugMessage(){ | |||
debugMessage=""; | |||
} | |||
void setPluginName(String name){ | |||
pluginName = name; | |||
} | |||
String getPluginName(){ | |||
return pluginName; | |||
} | |||
StringArray getTableStatement(int tableNum); | |||
const Array<double, CriticalSection> getTable(int tableNum); | |||
const Array<float, CriticalSection> getTableFloats(int tableNum); | |||
void createGUI(String source, bool refresh); | |||
int checkTable(int tableNum); | |||
MidiKeyboardState keyboardState; | |||
//midiBuffers | |||
MidiBuffer midiBuffer; | |||
MidiBuffer midiOutputBuffer; | |||
MidiBuffer ccBuffer; | |||
bool showMIDI; | |||
bool yieldCallbackBool; | |||
int yieldCounter; | |||
bool nativePluginEditor; | |||
CabbageMessageQueue messageQueue; | |||
StringArray scoreEvents; | |||
int averageSampleIndex; | |||
bool stopProcessing; | |||
float outputNo1; | |||
int pluginType; | |||
float automationAmp; | |||
int automationParamID; | |||
int mouseX, mouseY; | |||
int breakCount; | |||
Array<int> breakpointInstruments; | |||
Array<Array <float > > tableArrays; | |||
Array<float> getTableArray(int index){ | |||
return tableArrays[index]; | |||
} | |||
//============================================================================== | |||
File getCsoundInputFile() | |||
{ | |||
return csdFile; | |||
} | |||
void setMidiDebug(bool val){ | |||
showMIDI=val; | |||
} | |||
bool getMidiDebug(){ | |||
return showMIDI; | |||
} | |||
//======== log information about GUI controls =============== | |||
StringArray logGUIAttributes(CabbageGUIClass cAttr, String type){ | |||
StringArray arr; | |||
/* | |||
arr.add(String("----------- ")+type+String(" -----------")); | |||
arr.add(String("Name:")+cAttr.getStringProp("name")+String(", Type:")+cAttr.getStringProp("type")+String(", Caption:")+cAttr.getStringProp("caption")+String(", RelToPlant:")+cAttr.getStringProp("reltoplant")+String(", Plant:")+cAttr.getStringProp("plant")); | |||
arr.add(String("PosX:")+String(cAttr.getNumProp("left"))+String(", PosY:")+String(cAttr.getNumProp("top"))+String(", Width:")+String(cAttr.getNumProp("width"))+String(", Height:")+String(cAttr.getNumProp("height"))); | |||
*/ | |||
arr.add(String(" ")); | |||
//Logger::writeToLog(String("----------- ")+type+String(" -----------")); | |||
//Logger::writeToLog(String("Name:")+cAttr.getStringProp("name")+String(", Type:")+cAttr.getStringProp("type")+String(", Caption:")+cAttr.getStringProp("caption")+String(", RelToPlant:")+cAttr.getStringProp("reltoplant")+String(", Plant:")+cAttr.getStringProp("plant")); | |||
//Logger::writeToLog(String("PosX:")+String(cAttr.getNumProp("left"))+String(", PosY:")+String(cAttr.getNumProp("top"))+String(", Width:")+String(cAttr.getNumProp("width"))+String(", Height:")+String(cAttr.getNumProp("height"))); | |||
//Logger::writeToLog(" "); | |||
return arr; | |||
} | |||
inline bool getCsoundStatus(){ | |||
return csoundStatus; | |||
} | |||
inline String getCsoundInputFileText() | |||
{ | |||
String ret=""; | |||
#if defined(Cabbage_Build_Standalone) && !defined(AndroidBuild) | |||
if(codeEditor) | |||
ret = codeEditor->getAllText(); | |||
else | |||
ret = csdFile.loadFileAsString(); | |||
#endif | |||
return ret; | |||
} | |||
//=========================================================== | |||
inline int getGUICtrlsSize(){ | |||
return (int)guiCtrls.size(); | |||
} | |||
void updateCsoundFile(String text) | |||
{ | |||
//csdFile.replaceWithText(text); | |||
#if defined(Cabbage_Build_Standalone) && !defined(AndroidBuild) | |||
codeEditor->setAllText(text); | |||
#endif | |||
} | |||
inline int getGUILayoutCtrlsSize(){ | |||
return (int)guiLayoutCtrls.size(); | |||
} | |||
int saveEditorFiles() | |||
{ | |||
#ifdef Cabbage_Build_Standalone | |||
if(codeEditor) | |||
return codeEditor->saveAllFiles(); | |||
#endif | |||
} | |||
inline CabbageGUIClass &getGUILayoutCtrls(int index){ | |||
return guiLayoutCtrls.getReference(index); | |||
void saveText() | |||
{ | |||
#ifdef Cabbage_Build_Standalone | |||
codeEditor->textChanged = false; | |||
#endif | |||
} | |||
void setOpcodeDirEnv() | |||
{ | |||
#ifdef WIN32 | |||
//showMessage(getenv("OPCODE6DIR64")); | |||
String opcodeDir = File::getSpecialLocation(File::currentExecutableFile).getParentDirectory().getFullPathName()+"\\CsoundPlugins"; | |||
if(!File(opcodeDir).exists()) | |||
opcodeDir = String(getenv("CABBAGE_OPCODE_PATH")); | |||
Logger::writeToLog("\n================================\nCabbage opcode plugins are located at:"+opcodeDir); | |||
//showMessage(opcodeDir); | |||
if(File(opcodeDir).exists()) | |||
{ | |||
String env = "OPCODE6DIR64="+opcodeDir; | |||
_putenv(env.toUTF8().getAddress()); | |||
Logger::writeToLog("Current opcodeDir is:"+String(getenv("OPCODE6DIR64"))); | |||
} | |||
#endif | |||
} | |||
inline CabbageGUIClass &getGUICtrls(int index){ | |||
return guiCtrls.getReference(index); | |||
} | |||
void highlightLine(String text) | |||
{ | |||
#if defined(Cabbage_Build_Standalone) && !defined(AndroidBuild) | |||
codeEditor->highlightLine(text); | |||
#endif | |||
} | |||
inline String getChangeMessageType(){ | |||
return changeMessageType; | |||
} | |||
String getDebugMessage() | |||
{ | |||
return debugMessage; | |||
} | |||
inline String getCsoundOutput(){ | |||
return csoundOutput; | |||
} | |||
void addDebugMessage(String message) | |||
{ | |||
debugMessageArray.add(message);; | |||
} | |||
inline void setChangeMessageType(String text){ | |||
changeMessageType = text; | |||
} | |||
StringArray getDebugMessageArray() | |||
{ | |||
return debugMessageArray; | |||
} | |||
inline int getCurrentLine(){ | |||
return currentLine; | |||
} | |||
void clearDebugMessageArray() | |||
{ | |||
debugMessageArray.clear(); | |||
} | |||
inline void setCurrentLine(int line){ | |||
currentLine = line; | |||
} | |||
int getCompileStatus() | |||
{ | |||
return csCompileResult; | |||
} | |||
inline void setCurrentLineText(String lineText){ | |||
currentLineText = lineText; | |||
} | |||
void clearDebugMessage() | |||
{ | |||
debugMessage=""; | |||
} | |||
String getCurrentLineText(){ | |||
return currentLineText; | |||
} | |||
void setPluginName(String name) | |||
{ | |||
pluginName = name; | |||
} | |||
void removeGUIComponent(int index, String type); | |||
String getPluginName() | |||
{ | |||
return pluginName; | |||
} | |||
Array<Array <float > > tableArrays; | |||
Array<float> getTableArray(int index) | |||
{ | |||
return tableArrays[index]; | |||
} | |||
void setMidiDebug(bool val) | |||
{ | |||
showMIDI=val; | |||
} | |||
bool getMidiDebug() | |||
{ | |||
return showMIDI; | |||
} | |||
//======== log information about GUI controls =============== | |||
StringArray logGUIAttributes(CabbageGUIClass cAttr, String type) | |||
{ | |||
StringArray arr; | |||
/* | |||
arr.add(String("----------- ")+type+String(" -----------")); | |||
arr.add(String("Name:")+cAttr.getStringProp("name")+String(", Type:")+cAttr.getStringProp("type")+String(", Caption:")+cAttr.getStringProp("caption")+String(", RelToPlant:")+cAttr.getStringProp("reltoplant")+String(", Plant:")+cAttr.getStringProp("plant")); | |||
arr.add(String("PosX:")+String(cAttr.getNumProp("left"))+String(", PosY:")+String(cAttr.getNumProp("top"))+String(", Width:")+String(cAttr.getNumProp("width"))+String(", Height:")+String(cAttr.getNumProp("height"))); | |||
*/ | |||
arr.add(String(" ")); | |||
//Logger::writeToLog(String("----------- ")+type+String(" -----------")); | |||
//Logger::writeToLog(String("Name:")+cAttr.getStringProp("name")+String(", Type:")+cAttr.getStringProp("type")+String(", Caption:")+cAttr.getStringProp("caption")+String(", RelToPlant:")+cAttr.getStringProp("reltoplant")+String(", Plant:")+cAttr.getStringProp("plant")); | |||
//Logger::writeToLog(String("PosX:")+String(cAttr.getNumProp("left"))+String(", PosY:")+String(cAttr.getNumProp("top"))+String(", Width:")+String(cAttr.getNumProp("width"))+String(", Height:")+String(cAttr.getNumProp("height"))); | |||
//Logger::writeToLog(" "); | |||
return arr; | |||
} | |||
inline bool getCsoundStatus() | |||
{ | |||
return csoundStatus; | |||
} | |||
//=========================================================== | |||
inline int getGUICtrlsSize() | |||
{ | |||
return (int)guiCtrls.size(); | |||
} | |||
inline int getGUILayoutCtrlsSize() | |||
{ | |||
return (int)guiLayoutCtrls.size(); | |||
} | |||
inline CabbageGUIClass &getGUILayoutCtrls(int index) | |||
{ | |||
return guiLayoutCtrls.getReference(index); | |||
} | |||
inline CabbageGUIClass &getGUICtrls(int index) | |||
{ | |||
return guiCtrls.getReference(index); | |||
} | |||
inline String getChangeMessageType() | |||
{ | |||
return changeMessageType; | |||
} | |||
inline String getCsoundOutput() | |||
{ | |||
return csoundOutput; | |||
} | |||
inline String getDebuggerOutput() | |||
{ | |||
return csoundDebuggerOutput; | |||
} | |||
inline void setChangeMessageType(String text) | |||
{ | |||
changeMessageType = text; | |||
} | |||
inline int getCurrentLine() | |||
{ | |||
return currentLine; | |||
} | |||
inline void setCurrentLine(int line) | |||
{ | |||
currentLine = line; | |||
} | |||
inline void setCurrentLineText(String lineText) | |||
{ | |||
currentLineText = lineText; | |||
} | |||
String getCurrentLineText() | |||
{ | |||
return currentLineText; | |||
} | |||
void removeGUIComponent(int index, String type); | |||
#ifndef Cabbage_No_Csound | |||
Csound* getCsound(){ | |||
return csound; | |||
} | |||
CSOUND* getCsoundStruct(){ | |||
return csound->GetCsound(); | |||
} | |||
MYFLT getCSScale(){ | |||
return cs_scale; | |||
} | |||
PVSDATEXT* getPVSDataOut(){ | |||
return dataout; | |||
} | |||
Csound* getCsound() | |||
{ | |||
return csound; | |||
} | |||
CSOUND* getCsoundStruct() | |||
{ | |||
return csound->GetCsound(); | |||
} | |||
MYFLT getCSScale() | |||
{ | |||
return cs_scale; | |||
} | |||
PVSDATEXT* getPVSDataOut() | |||
{ | |||
return dataout; | |||
} | |||
#endif | |||
void addLayoutCtrl(CabbageGUIClass cAttr){ | |||
guiLayoutCtrls.add(cAttr); | |||
} | |||
void addLayoutCtrl(CabbageGUIClass cAttr) | |||
{ | |||
guiLayoutCtrls.add(cAttr); | |||
} | |||
void addGUICtrl(CabbageGUIClass cAttr){ | |||
guiCtrls.add(cAttr); | |||
} | |||
void addGUICtrl(CabbageGUIClass cAttr) | |||
{ | |||
guiCtrls.add(cAttr); | |||
} | |||
bool isGuiEnabled(){ | |||
return guiON; | |||
} | |||
bool isGuiEnabled() | |||
{ | |||
return guiON; | |||
} | |||
void setGuiEnabled(bool val); | |||
void setGuiEnabled(bool val); | |||
void addXYAutomater(XYPadAutomation* xyAuto){ | |||
xyAutomation.add(xyAuto); | |||
} | |||
void addXYAutomater(XYPadAutomation* xyAuto) | |||
{ | |||
xyAutomation.add(xyAuto); | |||
} | |||
XYPadAutomation* getXYAutomater(int index){ | |||
return xyAutomation[index]; | |||
} | |||
XYPadAutomation* getXYAutomater(int index) | |||
{ | |||
return xyAutomation[index]; | |||
} | |||
int getXYAutomaterSize(){ | |||
return xyAutomation.size(); | |||
} | |||
int getXYAutomaterSize() | |||
{ | |||
return xyAutomation.size(); | |||
} | |||
void removeXYAutomaters(){ | |||
xyAutomation.clear(); | |||
} | |||
void removeXYAutomaters() | |||
{ | |||
xyAutomation.clear(); | |||
} | |||
bool silenceInProducesSilenceOut() const{ | |||
return true; | |||
} | |||
bool silenceInProducesSilenceOut() const | |||
{ | |||
return true; | |||
} | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePluginAudioProcessor); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CabbagePluginAudioProcessor); | |||
}; | |||
//pecial auotmation only plugin type. Does not output any audio. | |||
//special auotmation only plugin type. Does not output any audio. | |||
#ifdef Cabbage_Host | |||
class CabbagePluginAutomationProcessor : public CabbagePluginAudioProcessor | |||
{ | |||
public: | |||
CabbagePluginAutomationProcessor(AudioProcessor* filter, String inputfile, int pluginType): | |||
CabbagePluginAudioProcessor(inputfile, false, pluginType) | |||
{} | |||
~CabbagePluginAutomationProcessor(){} | |||
CabbagePluginAutomationProcessor(AudioProcessor* filter, String inputfile, int pluginType): | |||
CabbagePluginAudioProcessor(inputfile, false, pluginType) | |||
{} | |||
~CabbagePluginAutomationProcessor() {} | |||
}; | |||
@@ -4,7 +4,7 @@ | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
@@ -19,144 +19,303 @@ | |||
#include "Soundfiler.h" | |||
//============================================================================== | |||
// zooming button | |||
//============================================================================== | |||
class ZoomButton : public Component, | |||
public ChangeBroadcaster | |||
{ | |||
public: | |||
ZoomButton(String type):Component() | |||
{ | |||
setName(type); | |||
} | |||
~ZoomButton() {} | |||
void mouseDown(const MouseEvent& e) | |||
{ | |||
sendChangeMessage(); | |||
} | |||
void paint(Graphics& g) | |||
{ | |||
g.fillAll(Colours::transparentBlack); | |||
g.setColour(Colours::white.withAlpha(.8f)); | |||
g.fillEllipse(0, 0, getWidth(), getHeight()); | |||
g.setColour(Colours::black); | |||
g.fillRoundedRectangle(getWidth()*.18, getHeight()*.4f, getWidth()*.65, getHeight()*.25, 2); | |||
if(getName()=="zoomIn") | |||
g.fillRoundedRectangle(getWidth()*.38f, getHeight()*.20, getWidth()*.25, getHeight()*.65, 2); | |||
} | |||
}; | |||
//============================================================================== | |||
// soundfiler component | |||
// soundfiler display component | |||
//============================================================================== | |||
Soundfiler::Soundfiler(CabbageAudioSource& _audioSource, String fileName, int sr, Colour colour, Colour fontColour) | |||
:cabbageAudioSource(&_audioSource) | |||
Soundfiler::Soundfiler(int sr, Colour col, Colour fcol): thumbnailCache (5), | |||
colour(col), sampleRate(sr), | |||
currentPlayPosition(0), | |||
mouseDownX(0), | |||
mouseUpX(0), | |||
drawWaveform(false), | |||
regionWidth(1), | |||
loopLength(0), | |||
scrubberPosition(0), | |||
fontcolour(fcol), | |||
currentPositionMarker(new DrawableRectangle()) | |||
{ | |||
formatManager.registerBasicFormats(); | |||
thumbnail = new AudioThumbnail(2, formatManager, thumbnailCache); | |||
thumbnail->addChangeListener (this); | |||
//setSize(400, 200); | |||
sampleRate = sr; | |||
addAndMakeVisible(scrollbar = new ScrollBar(false)); | |||
scrollbar->setRangeLimits (visibleRange); | |||
//scrollbar->setAutoHide (false); | |||
scrollbar->addListener(this); | |||
currentPositionMarker->setFill (Colours::white.withAlpha (0.85f)); | |||
addAndMakeVisible(currentPositionMarker); | |||
addAndMakeVisible(zoomIn = new ZoomButton("zoomIn")); | |||
addAndMakeVisible(zoomOut = new ZoomButton("zoomOut")); | |||
zoomIn->addChangeListener(this); | |||
zoomOut->addChangeListener(this); | |||
} | |||
//============================================================================== | |||
Soundfiler::~Soundfiler() | |||
{ | |||
scrollbar->removeListener (this); | |||
thumbnail->removeChangeListener (this); | |||
} | |||
//============================================================================== | |||
void Soundfiler::changeListenerCallback(ChangeBroadcaster *source) | |||
{ | |||
ZoomButton* button = dynamic_cast<ZoomButton*>(source); | |||
if(button) | |||
{ | |||
if(button->getName()=="zoomIn") | |||
setZoomFactor(jmin(1.0, zoom+=0.1)); | |||
else | |||
setZoomFactor(jmax(0.0, zoom-=0.1)); | |||
} | |||
repaint(); | |||
Logger::writeToLog("soundfiler Change listener:"+String(thumbnail->getTotalLength())); | |||
} | |||
//============================================================================== | |||
void Soundfiler::resized() | |||
{ | |||
zoomIn->setBounds(getWidth()-43, getHeight()-40, 20, 20); | |||
zoomOut->setBounds(getWidth()-20, getHeight()-40, 20, 20); | |||
if(scrollbar) | |||
scrollbar->setBounds (getLocalBounds().removeFromBottom (20).reduced (2)); | |||
} | |||
//============================================================================== | |||
void Soundfiler::scrollBarMoved (ScrollBar* scrollBarThatHasMoved, double newRangeStart) | |||
{ | |||
if (scrollBarThatHasMoved == scrollbar) | |||
setRange (visibleRange.movedToStartAt (newRangeStart)); | |||
} | |||
viewport = new Viewport(); | |||
Logger::writeToLog("sample Rate:"+String(sr)); | |||
waveformDisplay = new WaveformDisplay(*cabbageAudioSource->audioSourceBuffer, sr, colour); | |||
//register a listener callback so that we know when to update our audioSource object | |||
cabbageAudioSource->addChangeListener(this); | |||
void Soundfiler::setFile (const File& file) | |||
{ | |||
if (! file.isDirectory()) | |||
{ | |||
//buffer.clear(); | |||
// | |||
//buffer.addFrom(0, 0, tableValues.getRawDataPointer(), tableValues.size()); | |||
//buffer.addFrom(1, 0, tableValues.getRawDataPointer(), tableValues.size()); | |||
AudioFormatManager format; | |||
format.registerBasicFormats(); | |||
//registers wav and aif format (just nescearry one time if you alays use the "getInstance()" method) | |||
AudioFormatReader* reader = format.createReaderFor(file); | |||
//creates a reader for the result file (may file, if the result/opened file is no wav or aif) | |||
if(reader) //if a reader got created | |||
{ | |||
AudioSampleBuffer buffer(reader->numChannels, reader->lengthInSamples); | |||
buffer.clear(); | |||
buffer.setSize(reader->numChannels, reader->lengthInSamples); | |||
reader->read(&buffer,0, buffer.getNumSamples(), 0, true, true); | |||
setWaveform(buffer, reader->numChannels); | |||
} | |||
playButton = new ImageButton("Play button"); | |||
playButton->addListener(this); | |||
addAndMakeVisible(playButton); | |||
skipToStartButton = new ImageButton("Skip to start button"); | |||
skipToStartButton->addListener(this); | |||
addAndMakeVisible(skipToStartButton); | |||
skipToEndButton = new ImageButton("Skip to end button"); | |||
skipToEndButton->addListener(this); | |||
//addAndMakeVisible(skipToEndButton); | |||
//playButton->setToggleState(false, true); | |||
playButton->setClickingTogglesState(true); | |||
//playButton->setState(Button::buttonDown); | |||
delete reader; | |||
playButton->setImages(false, true, true, | |||
CabbageUtils::drawSoundfilerButton("play_normal", fontColour.toString()), 1.0f, Colours::transparentBlack, | |||
CabbageUtils::drawSoundfilerButton("play_hover", fontColour.toString()), 1.0f, Colours::transparentBlack, | |||
CabbageUtils::drawSoundfilerButton("play_down", fontColour.toString()), 1.0f, Colours::transparentBlack); | |||
skipToStartButton->setImages(false, true, true, | |||
CabbageUtils::drawSoundfilerButton("skip_start_normal", fontColour.toString()), 1.0f, Colours::transparentBlack, | |||
CabbageUtils::drawSoundfilerButton("skip_start_hover", fontColour.toString()), 1.0f, Colours::transparentBlack, | |||
CabbageUtils::drawSoundfilerButton("skip_start_down", fontColour.toString()), 1.0f, Colours::transparentBlack); | |||
// thumbnail->setSource (new FileInputSource (file)); | |||
// const Range<double> newRange (0.0, thumbnail->getTotalLength()); | |||
// scrollbar->setRangeLimits (newRange); | |||
// setRange (newRange); | |||
} | |||
repaint(0, 0, getWidth(), getHeight()); | |||
} | |||
//============================================================================== | |||
void Soundfiler::setWaveform(AudioSampleBuffer buffer, int channels) | |||
{ | |||
thumbnail->clear(); | |||
repaint(); | |||
thumbnail->reset(channels, 44100, buffer.getNumSamples()); | |||
//thumbnail->clear(); | |||
thumbnail->addBlock(0, buffer, 0, buffer.getNumSamples()); | |||
const Range<double> newRange (0.0, thumbnail->getTotalLength()); | |||
scrollbar->setRangeLimits (newRange); | |||
setRange (newRange); | |||
setZoomFactor(zoom); | |||
repaint(); | |||
Logger::writeToLog("updating waveform"); | |||
} | |||
skipToEndButton->setImages(false, true, true, | |||
CabbageUtils::drawSoundfilerButton("skip_end_normal", fontColour.toString()), 1.0f, Colours::transparentBlack, | |||
CabbageUtils::drawSoundfilerButton("skip_end_hover", fontColour.toString()), 1.0f, Colours::transparentBlack, | |||
CabbageUtils::drawSoundfilerButton("skip_end_down", fontColour.toString()), 1.0f, Colours::transparentBlack); | |||
//============================================================================== | |||
void Soundfiler::setZoomFactor (double amount) | |||
{ | |||
if (thumbnail->getTotalLength() > 0) | |||
{ | |||
const double newScale = jmax (0.001, thumbnail->getTotalLength() * (1.0 - jlimit (0.0, 0.99, amount))); | |||
const double timeAtCentre = xToTime (getWidth() / 2.0f); | |||
setRange (Range<double> (timeAtCentre - newScale * 0.5, timeAtCentre + newScale * 0.5)); | |||
} | |||
zoom = amount; | |||
repaint(); | |||
} | |||
//============================================================================== | |||
void Soundfiler::setRange(Range<double> newRange) | |||
{ | |||
visibleRange = newRange; | |||
scrollbar->setCurrentRange (visibleRange); | |||
repaint(); | |||
} | |||
//============================================================================== | |||
void Soundfiler::paint (Graphics& g) | |||
{ | |||
g.fillAll (Colours::black); | |||
g.setColour (colour); | |||
if (thumbnail->getTotalLength() > 0.01) | |||
{ | |||
//if(GEN01 then draw thumbnail) | |||
Rectangle<int> thumbArea (getLocalBounds()); | |||
thumbArea.setHeight(getHeight()-14); | |||
thumbArea.setTop(10.f); | |||
thumbnail->drawChannels(g, thumbArea.reduced (2), | |||
visibleRange.getStart(), visibleRange.getEnd(), .8f); | |||
/* | |||
for(int i=0.f;i<getWidth();i++){ | |||
g.setColour (fontcolour); | |||
//float pos = visibleRange.getStart()+i; | |||
//float xPos = (jmax(1, i)/visibleRange.getStart()) / (visibleRange.getLength() * getWidth()); | |||
//double round = xToTime(i); | |||
loadFile = new TextButton("Open File"); | |||
loadFile->getProperties().set("fontcolour", fontColour.toString()); | |||
loopFile = new ToggleButton("Loop"); | |||
loopFile->getProperties().set("isRect", 1); | |||
loopFile->getProperties().set("colour", fontColour.toString()); | |||
loopFile->getProperties().set("fontcolour", fontColour.toString()); | |||
addAndMakeVisible(loopFile); | |||
loadFile->addListener(this); | |||
loopFile->addListener(this); | |||
double round = fabs(xToTime(i)); | |||
//Logger::writeToLog(String(round-abs((int)round))); | |||
if(round-abs((int)round)<(0.05*(1-zoom))) | |||
{ | |||
String test = CabbageUtils::setDecimalPlaces(xToTime(i), 1); | |||
g.setFont(10); | |||
g.drawFittedText(test, i, 0, 20, 11, Justification::left, 1); | |||
//g.drawVerticalLine(i+1, 5, 10); | |||
} | |||
addAndMakeVisible(loadFile); | |||
//g.drawVerticalLine(i, 5, 10); | |||
}*/ | |||
addAndMakeVisible(viewport); | |||
setSize (400, 300); | |||
waveformDisplay->setFile(File(fileName), true); | |||
waveformDisplay->setZoomFactor(1); | |||
//if(regionWidth>1){ | |||
g.setColour(colour.contrasting(.5f).withAlpha(.7f)); | |||
float zoomFactor = thumbnail->getTotalLength()/visibleRange.getLength(); | |||
//regionWidth = (regionWidth=2 ? 2 : regionWidth*zoomFactor) | |||
g.fillRect(timeToX(currentPlayPosition), 10.f, (regionWidth==2 ? 2 : regionWidth*zoomFactor), (float)getHeight()-26.f); | |||
//} | |||
viewport->setViewedComponent(waveformDisplay, false); | |||
viewport->setScrollBarsShown(true, true); | |||
} | |||
else | |||
{ | |||
g.setColour(Colours::whitesmoke); | |||
g.setFont (14.0f); | |||
g.drawFittedText ("(No audio file loaded)", getLocalBounds(), Justification::centred, 2); | |||
} | |||
} | |||
//============================================================================== | |||
void Soundfiler::mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel) | |||
{ | |||
if (thumbnail->getTotalLength() > 0.5) | |||
{ | |||
double newStart = visibleRange.getStart() - wheel.deltaX * (visibleRange.getLength()) / 10.0; | |||
newStart = jlimit (0.0, jmax (0.0, thumbnail->getTotalLength() - (visibleRange.getLength())), newStart); | |||
setRange (Range<double> (newStart, newStart + visibleRange.getLength())); | |||
void Soundfiler::changeListenerCallback(ChangeBroadcaster *source) | |||
{ | |||
CabbageAudioSource* const cabbageAudio = dynamic_cast <CabbageAudioSource*> (source); | |||
if(cabbageAudio){ | |||
waveformDisplay->source = cabbageAudio->audioSourceBuffer; | |||
} | |||
} | |||
void Soundfiler::buttonClicked(Button *button) | |||
{ | |||
if(button->getName()=="Play button"){ | |||
if(!cabbageAudioSource->isSourcePlaying && cabbageAudioSource->isValidFile){ | |||
waveformDisplay->startTimer(100); | |||
//startStop->setButtonText("Stop.."); | |||
//startStop->setState(Button::buttonDown); | |||
} | |||
else{ | |||
waveformDisplay->stopTimer(); | |||
//startStop->setButtonText("Play"); | |||
} | |||
cabbageAudioSource->isSourcePlaying=!cabbageAudioSource->isSourcePlaying; | |||
} | |||
else if(button->getName()=="Skip to start button"){ | |||
waveformDisplay->rewindToStart(); | |||
} | |||
else if(button->getName()=="Skip to end button"){ | |||
waveformDisplay->skipForward(); | |||
} | |||
else if(button->getName()=="Loop"){ | |||
if(cabbageAudioSource->isValidFile) | |||
if(button->getToggleState()==true) | |||
cabbageAudioSource->audioSource->setLooping(true); | |||
else | |||
cabbageAudioSource->audioSource->setLooping(false); | |||
} | |||
else{ | |||
FileChooser openFC(String("Open a Cabbage sound file..."), File::nonexistent, String("*.wav;*.mp3")); | |||
if(openFC.browseForFileToOpen()) | |||
if(cabbageAudioSource->setFile(openFC.getResult().getFullPathName(), 2)){ | |||
waveformDisplay->sampleRate = cabbageAudioSource->sampleRate; | |||
waveformDisplay->setFile(openFC.getResult(), false); | |||
waveformDisplay->setZoomFactor(1); | |||
waveformDisplay->stopTimer(); | |||
playButton->setToggleState(false, sendNotification); | |||
} | |||
} | |||
repaint(); | |||
} | |||
} | |||
//============================================================================== | |||
void Soundfiler::mouseDown (const MouseEvent& e) | |||
{ | |||
Logger::writeToLog("mouseDown soundfiler"); | |||
if(!e.mods.isPopupMenu()) | |||
{ | |||
regionWidth = (1.01-zoom)*1.5; | |||
currentPlayPosition = jmax (0.0, xToTime ((float) e.x)); | |||
loopStart = e.x; | |||
loopLength = 0; | |||
repaint(); | |||
sendChangeMessage(); | |||
} | |||
} | |||
//============================================================================== | |||
void Soundfiler::resized() | |||
void Soundfiler::mouseEnter(const MouseEvent& e) | |||
{ | |||
waveformDisplay->setSize(800, getHeight()-40); | |||
viewport->setBounds(0, 0, getWidth(), getHeight()-20); | |||
//startStop->setBounds(0, getHeight()-20, 40, 20); | |||
skipToStartButton->setBounds(90, getHeight()-20, 20, 20); | |||
playButton->setBounds(70, getHeight()-20, 20, 20); | |||
skipToEndButton->setBounds(100, getHeight()-20, 20, 20); | |||
loopFile->setBounds(115, getHeight()-20, 60, 20); | |||
loadFile->setBounds(0, getHeight()-20, 70, 20); | |||
//Logger::writeToLog("mouseOver soundfiler"); | |||
//if(thumbnail->getTotalLength()>0.01){ | |||
// zoomIn->setVisible(true); | |||
// zoomOut->setVisible(true); | |||
//} | |||
} | |||
//============================================================================== | |||
void Soundfiler::paint (Graphics& g) | |||
void Soundfiler::mouseExit(const MouseEvent& e) | |||
{ | |||
g.fillAll(Colours::black); | |||
// zoomIn->setVisible(false); | |||
// zoomOut->setVisible(false); | |||
} | |||
//============================================================================== | |||
void Soundfiler::mouseDrag(const MouseEvent& e) | |||
{ | |||
if(this->getLocalBounds().contains(e.getPosition())) | |||
{ | |||
if(e.mods.isLeftButtonDown()) | |||
{ | |||
double zoomFactor = visibleRange.getLength()/thumbnail->getTotalLength(); | |||
regionWidth = abs(e.getDistanceFromDragStartX())*zoomFactor; | |||
Logger::writeToLog(String(e.getDistanceFromDragStartX())); | |||
if(e.getDistanceFromDragStartX()<0) | |||
currentPlayPosition = jmax (0.0, xToTime (loopStart+(float)e.getDistanceFromDragStartX())); | |||
float widthInTime = ((float)e.getDistanceFromDragStartX() / (float)getWidth()) * (float)thumbnail->getTotalLength(); | |||
loopLength = jmax (0.0, widthInTime*zoomFactor); | |||
} | |||
repaint(); | |||
} | |||
} | |||
//============================================================================== | |||
void Soundfiler::setScrubberPos(double pos) | |||
{ | |||
currentPositionMarker->setVisible (true); | |||
pos = (pos/(thumbnail->getTotalLength()*sampleRate))*thumbnail->getTotalLength(); | |||
currentPositionMarker->setRectangle (Rectangle<float> (timeToX (pos) - 0.75f, 10, | |||
1.5f, (float) (getHeight() - scrollbar->getHeight()-10))); | |||
if(pos<0.5) | |||
setRange (visibleRange.movedToStartAt(0)); | |||
if(visibleRange.getEnd()<=thumbnail->getTotalLength()) | |||
setRange (visibleRange.movedToStartAt (jmax(0.0, pos - (visibleRange.getLength() / 2.0)))); | |||
} | |||
//============================================================================== | |||
void Soundfiler::mouseUp(const MouseEvent& e) | |||
{ | |||
sendChangeMessage(); | |||
} |
@@ -4,7 +4,7 @@ | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
@@ -20,198 +20,93 @@ | |||
#ifndef SOUNDFILEWAVEFORM_H | |||
#define SOUNDFILEWAVEFORM_H | |||
#include "JuceHeader.h" | |||
#include "JuceHeader.h" | |||
#include "CabbageUtils.h" | |||
#include "CabbageLookAndFeel.h" | |||
class ZoomButton; | |||
//================================================================= | |||
// display a sound file as a waveform.. | |||
//================================================================= | |||
class WaveformDisplay : public Component, | |||
public Timer | |||
class Soundfiler : public Component, | |||
public ChangeBroadcaster, | |||
private ScrollBar::Listener, | |||
public ChangeListener | |||
{ | |||
public: | |||
WaveformDisplay(BufferingAudioSource &source, int sr, Colour col): | |||
thumbnailCache (5), | |||
source(&source), | |||
colour(col), | |||
sampleRate(sr), | |||
currentPlayPosition(0), | |||
mouseDownX(0), | |||
mouseUpX(0), | |||
drawWaveform(true), | |||
numOfSamples(0) | |||
{ | |||
formatManager.registerBasicFormats(); | |||
thumbnail = new AudioThumbnail(512, formatManager, thumbnailCache); | |||
setSize(100, 100); | |||
} | |||
~WaveformDisplay() | |||
{ | |||
source = nullptr; | |||
} | |||
void resized() | |||
{ | |||
} | |||
void setFile (const File& file, bool firstTime) | |||
{ | |||
if(file.existsAsFile()){ | |||
if(firstTime){ | |||
thumbnail->setSource (new FileInputSource(file)); | |||
} | |||
else{ | |||
//FileInputStream* inFileStream = new FileInputStream(file); // jatFile is the saved thumbnail file | |||
thumbnail = nullptr; | |||
thumbnail = new AudioThumbnail(512, formatManager, thumbnailCache); | |||
thumbnail->setSource (new FileInputSource(file)); | |||
//delete inFileStream; | |||
} | |||
drawWaveform=true; | |||
} | |||
else | |||
drawWaveform = false; | |||
startTime = 0; | |||
endTime = thumbnail->getTotalLength(); | |||
repaint(); | |||
} | |||
Soundfiler(int sr, Colour col, Colour fcol); | |||
~Soundfiler(); | |||
void setZoomFactor (double amount) | |||
double getCurrentPlayPos() | |||
{ | |||
if (thumbnail->getTotalLength() > 0) | |||
{ | |||
const double newScale = jmax (0.001, thumbnail->getTotalLength() * (1.0 - jlimit (0.0, 0.99, amount))); | |||
const double timeAtCentre = xToTime (getWidth() / 2.0f); | |||
//startTime = timeAtCentre - newScale * 0.5; | |||
//endTime = timeAtCentre + newScale * 0.5; | |||
repaint(); | |||
} | |||
return currentPlayPosition; | |||
} | |||
void paint (Graphics& g) | |||
int getCurrentPlayPosInSamples() | |||
{ | |||
g.fillAll (Colours::black); | |||
g.setColour (colour); | |||
if(drawWaveform){ | |||
if (thumbnail->getTotalLength() > 0) | |||
{ | |||
thumbnail->drawChannels (g, getLocalBounds(), | |||
startTime, endTime, 2.0f); | |||
} | |||
else | |||
{ | |||
g.setFont (14.0f); | |||
g.drawFittedText ("(No audio file selected)", getLocalBounds(), Justification::centred, 2); | |||
} | |||
g.setColour(colour.brighter(.4f)); | |||
g.drawLine(timeToX(currentPlayPosition), 0, timeToX(currentPlayPosition), getHeight(), 2); | |||
} | |||
return currentPlayPosition*sampleRate; | |||
} | |||
void timerCallback() | |||
int getLoopLengthInSamples() | |||
{ | |||
Viewport* const viewport = findParentComponentOfClass <Viewport> (); //Get the parent viewport | |||
currentPlayPosition = source->getNextReadPosition()/sampleRate; | |||
if(viewport != nullptr) //Check for nullness | |||
viewport->setViewPosition(jmax(0.f, timeToX(currentPlayPosition)-100), 0); | |||
repaint(); | |||
return loopLength*sampleRate; | |||
} | |||
void mouseDown (const MouseEvent& e) | |||
{ | |||
if(e.mods.isCommandDown()){ | |||
if(e.mods.isLeftButtonDown()) | |||
this->setSize(jmin(1000, this->getWidth()+100), getHeight()); | |||
else | |||
this->setSize(jmax(400, this->getWidth()-100), getHeight()); | |||
Logger::writeToLog("command down"); | |||
} | |||
source->setNextReadPosition (jmax (0.0, xToTime ((float) e.x)*sampleRate)); | |||
currentPlayPosition = jmax (0.0, xToTime ((float) e.x)); | |||
mouseDownX = e.x; | |||
repaint(); | |||
} | |||
void mouseDrag(const MouseEvent& e) | |||
{ | |||
mouseUpX = e.x; | |||
currentPlayPosition = jmax (0.0, xToTime ((float) e.x)); | |||
repaint(); | |||
} | |||
void rewindToStart(){ | |||
if(source) | |||
source->setNextReadPosition (0); | |||
currentPlayPosition = 0.f; | |||
} | |||
void skipForward(){ | |||
currentPlayPosition = currentPlayPosition+1.f; | |||
} | |||
AudioThumbnailCache thumbnailCache; | |||
ScopedPointer<AudioThumbnail> thumbnail; | |||
ScopedPointer<BufferingAudioSource> source; | |||
float sampleRate; | |||
private: | |||
AudioFormatManager formatManager; | |||
int64 numOfSamples; | |||
Colour colour; | |||
int mouseDownX, mouseUpX; | |||
double startTime, endTime; | |||
Rectangle<int> localBounds; | |||
double currentPlayPosition; | |||
bool drawWaveform; | |||
DrawableRectangle currentPositionMarker; | |||
void setScrubberPos(double pos); | |||
float timeToX (const double time) const | |||
{ | |||
return getWidth() * (float) ((time - startTime) / (endTime - startTime)); | |||
return getWidth() * (float) ((time - visibleRange.getStart()) / (visibleRange.getLength())); | |||
} | |||
double xToTime (const float x) const | |||
{ | |||
return (x / getWidth()) * (endTime - startTime) + startTime; | |||
return (x / getWidth()) * (visibleRange.getLength()) + visibleRange.getStart(); | |||
} | |||
}; | |||
class Soundfiler : public Component, | |||
public Button::Listener, | |||
public ChangeListener | |||
{ | |||
public: | |||
Soundfiler(CabbageAudioSource& audioSource, String fileName, int sr, Colour colour, Colour fontcolour); | |||
~Soundfiler(){ | |||
cabbageAudioSource->isSourcePlaying = false; | |||
cabbageAudioSource->audioSourceBuffer = nullptr; | |||
cabbageAudioSource->removeAllChangeListeners(); | |||
cabbageAudioSource = nullptr; | |||
}; | |||
// This is just a standard Juce paint method... | |||
void setZoomFactor (double amount); | |||
void setFile (const File& file); | |||
void mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel); | |||
void setWaveform(AudioSampleBuffer buffer, int channels); | |||
void createImage(String filename); | |||
private: | |||
Image img; | |||
//Graphics& graphics; | |||
int imgCount; | |||
Range<double> visibleRange; | |||
double zoom; | |||
ScopedPointer<DrawableRectangle> currentPositionMarker; | |||
ScopedPointer<ScrollBar> scrollbar; | |||
void setRange(Range<double> newRange); | |||
void resized(); | |||
void paint (Graphics& g); | |||
void changeListenerCallback(ChangeBroadcaster *source); | |||
void resized(); | |||
void buttonClicked(Button *button); | |||
ScopedPointer<WaveformDisplay> waveformDisplay; | |||
ScopedPointer<ImageButton> playButton; | |||
ScopedPointer<ImageButton> skipToStartButton; | |||
ScopedPointer<ImageButton> skipToEndButton; | |||
ScopedPointer<TextButton> loadFile; | |||
ScopedPointer<ToggleButton> loopFile; | |||
ScopedPointer<Viewport> viewport; | |||
CabbageAudioSource* cabbageAudioSource; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Soundfiler); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseUp(const MouseEvent& e); | |||
void mouseEnter(const MouseEvent& e); | |||
void mouseDrag(const MouseEvent& e); | |||
void mouseExit(const MouseEvent& e); | |||
bool reDraw; | |||
double scrubberPosition; | |||
void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, double newRangeStart); | |||
void changeListenerCallback(ChangeBroadcaster *source); | |||
ScopedPointer<ZoomButton> zoomIn, zoomOut; | |||
AudioFormatManager formatManager; | |||
float sampleRate; | |||
float regionWidth; | |||
Image waveformImage; | |||
AudioThumbnailCache thumbnailCache; | |||
ScopedPointer<AudioThumbnail> thumbnail; | |||
Colour colour, fontcolour; | |||
int mouseDownX, mouseUpX; | |||
Rectangle<int> localBounds; | |||
double loopLength; | |||
double loopStart; | |||
double currentPlayPosition; | |||
bool drawWaveform; | |||
}; | |||
#endif // SOUNDFILEWAVEFORM_H |
@@ -0,0 +1,357 @@ | |||
/* | |||
Copyright (C) 20139 Rory Walsh | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
GNU Lesser General Public License for more details. | |||
You should have received a copy of the GNU Lesser General Public | |||
License along with Csound; if not, write to the Free Software | |||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | |||
02111-1307 USA | |||
*/ | |||
#ifndef GENTABLE_H | |||
#define GENTABLE_H | |||
#include "JuceHeader.h" | |||
#include "CabbageUtils.h" | |||
#include "CabbageLookAndFeel.h" | |||
class RoundButton; | |||
class HandleViewer; | |||
class HandleComponent; | |||
class GenTable; | |||
class TableManager : public Component, | |||
private ScrollBar::Listener, | |||
public ChangeListener | |||
{ | |||
double zoom; | |||
int currentTableIndex; | |||
var tableConfigList; | |||
int largestTable; | |||
double scrubberPosition; | |||
double scrubberFreq; | |||
bool shouldShowTableButtons; | |||
bool shouldShowZoomButtons; | |||
int mainFooterHeight; | |||
public: | |||
TableManager(); | |||
~TableManager(){}; | |||
void paint (Graphics& g){ | |||
g.fillAll(Colours::transparentBlack); | |||
}; | |||
void resized(); | |||
void setZoomFactor(double zoom); | |||
void setDrawMode(String mode); | |||
void bringButtonsToFront(); | |||
void setAmpRanges(Array<float> ampRange); | |||
void timerCallback(); | |||
void setRange(double start, double end); | |||
ScopedPointer<DrawableRectangle> currentPositionMarker; | |||
double getLengthInSamples(); | |||
void setScrubberPos(double pos, int tableNum); | |||
void scroll(double newRangeStart); | |||
void addTable(int sr, const String col, int gen, Array<float> ampRange, int ftnumber, ChangeListener* listener); | |||
void setWaveform(AudioSampleBuffer buffer, int ftNumber); | |||
void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, double newRangeStart); | |||
void setWaveform(Array<float, CriticalSection> buffer, int ftNumber, bool updateRange = true); | |||
void enableEditMode(StringArray pFields, int ftnumber); | |||
ScopedPointer<RoundButton> zoomIn, zoomOut; | |||
OwnedArray<RoundButton> tableButtons; | |||
OwnedArray<GenTable> tables; | |||
void showZoomButtons(bool show); | |||
void showTableButtons(bool show); | |||
void changeListenerCallback(ChangeBroadcaster *source); | |||
void bringTableToFront(int ftNumber); | |||
void configTableSizes(var tableConfig); | |||
GenTable* getLargestTable(); | |||
GenTable* getTableFromFtNumber(int ftnumber); | |||
}; | |||
//================================================================= | |||
// display a sound file as a waveform.. | |||
//================================================================= | |||
class GenTable : public Component, | |||
public ChangeBroadcaster, | |||
private ScrollBar::Listener, | |||
public ChangeListener | |||
{ | |||
public: | |||
GenTable(); | |||
~GenTable(); | |||
double getCurrentPlayPos() | |||
{ | |||
return currentPlayPosition; | |||
} | |||
int getCurrentPlayPosInSamples() | |||
{ | |||
return currentPlayPosition*sampleRate; | |||
} | |||
int getLoopLengthInSamples() | |||
{ | |||
return loopLength*sampleRate; | |||
} | |||
void setScrubberPos(double pos); | |||
float timeToX (const double time) const | |||
{ | |||
return getWidth() * (float) ((time - visibleRange.getStart()) / (visibleRange.getLength())); | |||
} | |||
double xToTime (const float x) const | |||
{ | |||
return (x / getWidth()) * (visibleRange.getLength()) + visibleRange.getStart(); | |||
} | |||
void setSampleRange(double pos, double end); | |||
void setZoomFactor (double amount); | |||
void setFile (const File& file); | |||
void mouseWheelMove (const MouseEvent&, const MouseWheelDetails& wheel); | |||
void setWaveform(AudioSampleBuffer buffer); | |||
void enableEditMode(StringArray pFields); | |||
Point<int> tableTopAndHeight; | |||
void setWaveform(Array<float, CriticalSection> buffer, bool updateRange = true); | |||
void createImage(String filename); | |||
void addTable(int sr, const String col, int gen, Array<float> ampRange); | |||
static float ampToPixel(int height, Range<float> minMax, float sampleVal); | |||
static float pixelToAmp(int height, Range<float> minMax, float sampleVal); | |||
Array<double> getPfields(); | |||
String changeMessage; | |||
int tableNumber, tableSize, genRoutine, realGenRoutine; | |||
void setRange(Range<double> newRange, bool isScrolling = false); | |||
Range<double> globalRange; | |||
bool isTableOnTop; | |||
ScopedPointer<ScrollBar> scrollbar; | |||
void resized(); | |||
Range<double> visibleRange; | |||
int scrollbarReduction; | |||
void showScrollbar(bool show); | |||
int mainFooterHeight, paintFooterHeight; | |||
HandleViewer* getHandleViewer(){ return handleViewer;} | |||
double quantiseSpace; | |||
void setAmpRanges(Array<float> ampRange); | |||
void setXPosition(double pos); | |||
bool drawAsVUMeter; | |||
private: | |||
Image img; | |||
bool shouldScroll; | |||
int normalised; | |||
int imgCount; | |||
Colour fillColour; | |||
float currentWidth; | |||
double zoom; | |||
bool showScroll; | |||
double qsteps; | |||
double numPixelsPerIndex; | |||
ColourGradient gradient; | |||
StringArray pFields; | |||
ScopedPointer<DrawableRectangle> currentPositionMarker; | |||
juce::Rectangle<int> thumbArea; | |||
juce::Rectangle<int> handleViewerRect; | |||
void paint (Graphics& g); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseUp(const MouseEvent& e); | |||
void mouseEnter(const MouseEvent& e); | |||
void mouseDrag(const MouseEvent& e); | |||
void mouseExit(const MouseEvent& e); | |||
bool reDraw; | |||
double scrubberPosition; | |||
void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, double newRangeStart); | |||
void changeListenerCallback(ChangeBroadcaster *source); | |||
ScopedPointer<HandleViewer> handleViewer; | |||
AudioFormatManager formatManager; | |||
double sampleRate; | |||
float regionWidth; | |||
Image waveformImage; | |||
AudioThumbnailCache thumbnailCache; | |||
ScopedPointer<AudioThumbnail> thumbnail; | |||
Colour colour, fontcolour; | |||
int mouseDownX, mouseUpX; | |||
juce::Rectangle<int> localBounds; | |||
double loopLength; | |||
double loopStart; | |||
double currentPlayPosition; | |||
bool drawWaveform; | |||
Array<float, CriticalSection> waveformBuffer; | |||
double visibleLength, visibleStart, visibleEnd, maxAmp; | |||
Range<float> minMax; | |||
Range<float> findMinMax(Array<float, CriticalSection> buffer) | |||
{ | |||
float min=buffer[0],max=buffer[0]; | |||
for(int i=0; i<buffer.size(); i++) | |||
{ | |||
if(buffer[i]>max) | |||
max=buffer[i]; | |||
if(buffer[i]<min) | |||
min=buffer[i]; | |||
} | |||
return Range<float>(min, max); | |||
} | |||
}; | |||
//============================================================================== | |||
// HandleViewer class, holds breakpoint handles | |||
//============================================================================== | |||
class HandleViewer : public Component, | |||
public ActionListener | |||
{ | |||
void actionListenerCallback(const String &message); | |||
ScopedPointer<Label> label; | |||
public: | |||
HandleViewer(); | |||
~HandleViewer(); | |||
ScopedPointer<TextButton> button1; | |||
ScopedPointer<TextButton> button2; | |||
void mouseDown(const MouseEvent& e); | |||
void mouseDrag(const MouseEvent& e); | |||
void positionHandle(const MouseEvent& e); | |||
void repaint(Graphics &g); | |||
void resized(); | |||
void addHandle(double x, double y, double width, double height, Colour colour); | |||
void insertHandle(double x, double y, Colour colour); | |||
double getSnapPosition(const double y); | |||
HandleComponent* getPreviousHandle(HandleComponent* thisHandle); | |||
HandleComponent* getNextHandle(HandleComponent* thisHandle); | |||
int getHandleIndex(HandleComponent* thisHandle); | |||
void removeHandle (HandleComponent* thisHandle); | |||
OwnedArray<HandleComponent, CriticalSection> handles; | |||
void fixEdgePoints(int gen); | |||
void showHandles(bool show); | |||
void showLabel(String message); | |||
int handleIndex; | |||
double tableSize; | |||
Range<float> minMax; | |||
Colour colour; | |||
int gen; | |||
bool shouldShowHandles; | |||
GenTable* getParentTable(){ | |||
return findParentComponentOfClass <GenTable>(); | |||
}; | |||
}; | |||
//============================================================================== | |||
// Handle class | |||
//============================================================================== | |||
class HandleComponent : public Component, | |||
public ChangeBroadcaster, | |||
public ActionBroadcaster | |||
{ | |||
public: | |||
HandleComponent(double xPos, double yPos, int index, bool fixed, int gen, Colour colour); | |||
~HandleComponent(); | |||
HandleViewer* getParentComponent(); | |||
void paint (Graphics& g); | |||
void removeThisHandle(); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
void mouseExit (const MouseEvent& e); | |||
int index; | |||
int height, width; | |||
int x,y; | |||
void setColour(Colour icolour); | |||
void setRelativePositions(Point<double> point); | |||
HandleViewer* getParentHandleViewer(){ | |||
return findParentComponentOfClass <HandleViewer>(); | |||
}; | |||
HandleComponent* getPreviousHandle(); | |||
HandleComponent* getNextHandle(); | |||
String changeMessage; | |||
String mouseStatus; | |||
double xPosRelative, yPosRelative; | |||
bool status; | |||
private: | |||
Colour colour; | |||
bool fixed; | |||
ComponentDragger dragger; | |||
int lastX, lastY; | |||
int offsetX, offsetY; | |||
int genRoutine; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HandleComponent); | |||
}; | |||
//============================================================================== | |||
// round button | |||
//============================================================================== | |||
class RoundButton : public Component, | |||
public ChangeBroadcaster | |||
{ | |||
String type; | |||
Colour colour; | |||
int mode; | |||
public: | |||
RoundButton(String _type, Colour _colour):Component() | |||
{ | |||
setName(_type); | |||
type = _type; | |||
colour = _colour; | |||
mode = 0; | |||
} | |||
~RoundButton() {} | |||
void mouseDown(const MouseEvent& e) | |||
{ | |||
//Logger::writeToLog("Mouse down on round button:"+String(type)); | |||
sendChangeMessage(); | |||
mode = (mode==1 ? 0 : mode+1); | |||
} | |||
void paint(Graphics& g) | |||
{ | |||
//Logger::writeToLog(type); | |||
if(type.contains("zoom")) | |||
{ | |||
g.fillAll(Colours::transparentBlack); | |||
g.setColour(Colours::white.withAlpha(.8f)); | |||
g.fillEllipse(0, 0, getWidth(), getHeight()); | |||
g.setColour(Colours::black); | |||
g.fillRoundedRectangle(getWidth()*.18, getHeight()*.4f, getWidth()*.65, getHeight()*.25, 2); | |||
if(getName()=="zoomIn") | |||
g.fillRoundedRectangle(getWidth()*.38f, getHeight()*.20, getWidth()*.25, getHeight()*.65, 2); | |||
} | |||
else{ | |||
g.fillAll(Colours::transparentBlack); | |||
g.setColour(colour); | |||
g.fillEllipse(0, 0, getWidth(), getHeight()); | |||
g.setColour(colour.contrasting()); | |||
g.drawFittedText(type, 0, 0, getWidth(), getHeight(), Justification::centred, 1); | |||
} | |||
} | |||
int getMode() | |||
{ | |||
return mode; | |||
} | |||
}; | |||
#endif // SOUNDFILEWAVEFORM_H |
@@ -4,7 +4,7 @@ | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
@@ -35,25 +35,25 @@ | |||
class XYHandleComponent : public Component | |||
{ | |||
public: | |||
XYHandleComponent(); | |||
~XYHandleComponent(); | |||
XYHandleComponent(); | |||
~XYHandleComponent(); | |||
class XYCanvas* getParentComponent(); | |||
void paint (Graphics& g); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
class XYCanvas* getParentComponent(); | |||
void paint (Graphics& g); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
private: | |||
ComponentDragger dragger; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYHandleComponent); | |||
ComponentDragger dragger; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYHandleComponent); | |||
}; | |||
/* | |||
============================================================================ | |||
XYImages | |||
------------------------------------------------------------------------- | |||
Returns custom images for toggle buttons. | |||
@@ -63,38 +63,40 @@ private: | |||
class XYImages | |||
{ | |||
public: | |||
XYImages() | |||
{ | |||
} | |||
~XYImages() | |||
{ | |||
} | |||
static Image getImage(int imageType, float width, float height) | |||
{ | |||
Image img = Image(Image::ARGB, width, height, true); | |||
Graphics g(img); | |||
g.setColour(Colours::white); | |||
Path pathLine, pathBall; | |||
if (imageType == 0) { | |||
pathLine.startNewSubPath(width*0.2, height*0.8); | |||
pathLine.lineTo(width*0.7, height*0.2); | |||
g.strokePath(pathLine, PathStrokeType(width*0.04)); | |||
pathBall.addEllipse(width*0.6, height*0.45, width*0.2, width*0.2); | |||
} | |||
else if (imageType == 1) { | |||
pathLine.startNewSubPath(width*0.2, height*0.8); | |||
pathLine.lineTo(width*0.8, height*0.2); | |||
g.strokePath(pathLine, PathStrokeType(width*0.05)); | |||
Point<float> pt = pathLine.getPointAlongPath(pathLine.getLength()*0.6); | |||
pathBall.addEllipse(pt.getX()-(width*0.1), pt.getY()-(width*0.1), width*0.2, width*0.2); | |||
} | |||
g.fillPath(pathBall); | |||
return img; | |||
} | |||
XYImages() | |||
{ | |||
} | |||
~XYImages() | |||
{ | |||
} | |||
static Image getImage(int imageType, float width, float height) | |||
{ | |||
Image img = Image(Image::ARGB, width, height, true); | |||
Graphics g(img); | |||
g.setColour(Colours::white); | |||
Path pathLine, pathBall; | |||
if (imageType == 0) | |||
{ | |||
pathLine.startNewSubPath(width*0.2, height*0.8); | |||
pathLine.lineTo(width*0.7, height*0.2); | |||
g.strokePath(pathLine, PathStrokeType(width*0.04)); | |||
pathBall.addEllipse(width*0.6, height*0.45, width*0.2, width*0.2); | |||
} | |||
else if (imageType == 1) | |||
{ | |||
pathLine.startNewSubPath(width*0.2, height*0.8); | |||
pathLine.lineTo(width*0.8, height*0.2); | |||
g.strokePath(pathLine, PathStrokeType(width*0.05)); | |||
Point<float> pt = pathLine.getPointAlongPath(pathLine.getLength()*0.6); | |||
pathBall.addEllipse(pt.getX()-(width*0.1), pt.getY()-(width*0.1), width*0.2, width*0.2); | |||
} | |||
g.fillPath(pathBall); | |||
return img; | |||
} | |||
}; | |||
@@ -103,7 +105,7 @@ public: | |||
============================================================================ | |||
XYToggle | |||
------------------------------------------------------------------------- | |||
Custom toggle button. | |||
@@ -113,17 +115,17 @@ public: | |||
class XYToggle : public ToggleButton | |||
{ | |||
public: | |||
XYToggle(int imageType, Colour col); | |||
~XYToggle(); | |||
void resized(); | |||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown); | |||
XYToggle(int imageType, Colour col); | |||
~XYToggle(); | |||
void resized(); | |||
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown); | |||
private: | |||
Image img; | |||
int imageType; | |||
Colour colourWhenOn; | |||
Image img; | |||
int imageType; | |||
Colour colourWhenOn; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYToggle); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYToggle); | |||
}; | |||
@@ -141,15 +143,15 @@ private: | |||
class XYValueDisplay : public Component | |||
{ | |||
public: | |||
XYValueDisplay(Colour col); | |||
~XYValueDisplay(); | |||
void setValue(String value); | |||
void paint(Graphics& g); | |||
XYValueDisplay(Colour col); | |||
~XYValueDisplay(); | |||
void setValue(String value); | |||
void paint(Graphics& g); | |||
private: | |||
Colour colour; | |||
String value; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYValueDisplay); | |||
Colour colour; | |||
String value; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYValueDisplay); | |||
}; | |||
/* | |||
@@ -162,14 +164,14 @@ private: | |||
class XYCanvasBackground : public Component | |||
{ | |||
public: | |||
XYCanvasBackground(); | |||
~XYCanvasBackground(); | |||
void resized(); | |||
void paint(Graphics& g); | |||
XYCanvasBackground(); | |||
~XYCanvasBackground(); | |||
void resized(); | |||
void paint(Graphics& g); | |||
private: | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYCanvasBackground); | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYCanvasBackground); | |||
}; | |||
/* | |||
@@ -185,78 +187,82 @@ private: | |||
*/ | |||
class XYCanvas : public Component, | |||
public MultiTimer | |||
public MultiTimer | |||
{ | |||
public: | |||
XYCanvas(Colour ballCol, float xMinimum, float xMaximum, float yMinimum, | |||
float yMaximum); | |||
~XYCanvas(); | |||
class XYPad* getParentComponent(); | |||
void resized(); | |||
void cacheStaticBallImage(); | |||
void cacheMovingBallImage(); | |||
void paint(Graphics& g); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
Point<float> checkBounds (Point<float> pt); | |||
void setBallPositionFromXYValues(float xValue, float yValue); | |||
void setBallAndHandleSize(float size); | |||
float getBallX(); | |||
float getBallY(); | |||
void updatePath(); | |||
XYHandleComponent* makeHandle(Point<float> pt); | |||
void setStartHandle(Point<float> pt); | |||
void setEndHandle(Point<float> pt); | |||
void clearHandles(); | |||
void setToggleId(int selection); | |||
void useStaticBall(bool useStaticBall); | |||
void startBallPathTimer(); | |||
XYCanvas(Colour ballCol, float xMinimum, float xMaximum, float yMinimum, | |||
float yMaximum); | |||
~XYCanvas(); | |||
class XYPad* getParentComponent(); | |||
void resized(); | |||
void cacheStaticBallImage(); | |||
void cacheMovingBallImage(); | |||
void paint(Graphics& g); | |||
void mouseEnter (const MouseEvent& e); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
Point<float> checkBounds (Point<float> pt); | |||
void setBallPositionFromXYValues(float xValue, float yValue); | |||
void setBallAndHandleSize(float size); | |||
float getBallX(); | |||
float getBallY(); | |||
void updatePath(); | |||
XYHandleComponent* makeHandle(Point<float> pt); | |||
void setStartHandle(Point<float> pt); | |||
void setEndHandle(Point<float> pt); | |||
void clearHandles(); | |||
void setToggleId(int selection); | |||
void useStaticBall(bool useStaticBall); | |||
void startBallPathTimer(); | |||
private: | |||
Image bgImage, staticBallImage, movingBallImage; | |||
float ballX, ballY; | |||
float ballSize, handleSize; | |||
float yMax, xMax, yMin, xMin, xRange, yRange; | |||
Colour ballColour; | |||
Path path; | |||
float pathOpacity, pathThickness, ballLineOpacity; | |||
int toggleId; | |||
bool paintStaticBall; | |||
OwnedArray<XYHandleComponent> handles; | |||
void timerCallback(int id) | |||
{ | |||
//This reduces the opacity that is used to paint the path and ball lines. It will | |||
//give it a fade out effect. | |||
// Path | |||
if (id == 1) { | |||
pathOpacity -= 0.1; | |||
pathThickness -= 0.1; | |||
if (toggleId == 0) { | |||
if (pathOpacity <= 0) | |||
stopTimer(1); | |||
} | |||
else if (toggleId == 1) { | |||
if (pathOpacity <= 0.4) | |||
stopTimer(1); | |||
} | |||
//repaint(); //gets repainted anyway | |||
} | |||
// Ball lines | |||
else if (id == 2) { | |||
ballLineOpacity -= 0.1; | |||
if (ballLineOpacity <= 0) | |||
stopTimer(2); | |||
repaint(); | |||
} | |||
} | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYCanvas); | |||
Image bgImage, staticBallImage, movingBallImage; | |||
float ballX, ballY; | |||
float ballSize, handleSize; | |||
float yMax, xMax, yMin, xMin, xRange, yRange; | |||
Colour ballColour; | |||
Path path; | |||
float pathOpacity, pathThickness, ballLineOpacity; | |||
int toggleId; | |||
bool paintStaticBall; | |||
OwnedArray<XYHandleComponent> handles; | |||
void timerCallback(int id) | |||
{ | |||
//This reduces the opacity that is used to paint the path and ball lines. It will | |||
//give it a fade out effect. | |||
// Path | |||
if (id == 1) | |||
{ | |||
pathOpacity -= 0.1; | |||
pathThickness -= 0.1; | |||
if (toggleId == 0) | |||
{ | |||
if (pathOpacity <= 0) | |||
stopTimer(1); | |||
} | |||
else if (toggleId == 1) | |||
{ | |||
if (pathOpacity <= 0.4) | |||
stopTimer(1); | |||
} | |||
//repaint(); //gets repainted anyway | |||
} | |||
// Ball lines | |||
else if (id == 2) | |||
{ | |||
ballLineOpacity -= 0.1; | |||
if (ballLineOpacity <= 0) | |||
stopTimer(2); | |||
repaint(); | |||
} | |||
} | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYCanvas); | |||
}; | |||
@@ -266,69 +272,70 @@ private: | |||
XYPad | |||
---------------------------------------------------------------------------- | |||
This is the main parent class!! | |||
============================================================================ | |||
*/ | |||
class XYPad : public Component, | |||
public SliderListener, | |||
public ButtonListener, | |||
public ActionBroadcaster | |||
public SliderListener, | |||
public ButtonListener, | |||
public ActionBroadcaster | |||
{ | |||
public: | |||
XYPad(XYPadAutomation* xyPadAutomation, String title, int minXValue, int maxXValue, | |||
int minYValue, | |||
int maxYValue, | |||
int numberOfDecimalPlaces, | |||
Colour ballCol, | |||
Colour fontCol, | |||
float initXVal, | |||
float initYVal); | |||
~XYPad(); | |||
void resized(); | |||
void buttonClicked(Button* button); | |||
void sliderValueChanged(Slider* slider); | |||
void paint (Graphics& g); | |||
void setXYValues(float x, float y); | |||
void setXYValuesFromNormalised(float xNorm, float yNorm); | |||
float getXValueWhenNotAutomating(float x); | |||
float getYValueWhenNotAutomating(float y); | |||
Point<float> checkBounds(float x, float y); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
void mouseEnter (const MouseEvent& e); | |||
void displayXYValues(float xValue, float yValue); | |||
bool isAutomationActive(){ | |||
return xyPadAutomation->isAutomationOn; | |||
} | |||
ScopedPointer<Slider> speedSlider; | |||
XYPadAutomation* xyPadAutomation; | |||
XYPad(XYPadAutomation* xyPadAutomation, String title, int minXValue, int maxXValue, | |||
int minYValue, | |||
int maxYValue, | |||
int numberOfDecimalPlaces, | |||
Colour ballCol, | |||
Colour fontCol, | |||
float initXVal, | |||
float initYVal); | |||
~XYPad(); | |||
void resized(); | |||
void buttonClicked(Button* button); | |||
void sliderValueChanged(Slider* slider); | |||
void paint (Graphics& g); | |||
void setXYValues(float x, float y); | |||
void setXYValuesFromNormalised(float xNorm, float yNorm); | |||
float getXValueWhenNotAutomating(float x); | |||
float getYValueWhenNotAutomating(float y); | |||
Point<float> checkBounds(float x, float y); | |||
void mouseDown (const MouseEvent& e); | |||
void mouseDrag (const MouseEvent& e); | |||
void mouseUp (const MouseEvent& e); | |||
void mouseEnter (const MouseEvent& e); | |||
void displayXYValues(float xValue, float yValue); | |||
bool isAutomationActive() | |||
{ | |||
return xyPadAutomation->isAutomationOn; | |||
} | |||
ScopedPointer<Slider> speedSlider; | |||
XYPadAutomation* xyPadAutomation; | |||
private: | |||
ScopedPointer<XYCanvas> canvas; | |||
ScopedPointer<XYCanvasBackground> canvasBackground; | |||
float ballSize; | |||
int speed; | |||
String title, name; | |||
Colour ballColour, fontColour, toggleColour; | |||
float yMax, xMax, yMin, xMin; | |||
float xOut, yOut, xRange, yRange, initX, initY; | |||
int decimalPlaces; | |||
OwnedArray<XYValueDisplay> valueDisplays; | |||
OwnedArray<XYToggle> xyToggles; | |||
ScopedPointer<CabbageLookAndFeel> lookAndFeel; | |||
ScopedPointer<CabbageLookAndFeelBasic> lookAndFeelBasic; | |||
bool canvasHasFocus; | |||
int currentSelectedToggle; | |||
String format; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYPad); | |||
ScopedPointer<XYCanvas> canvas; | |||
ScopedPointer<XYCanvasBackground> canvasBackground; | |||
float ballSize; | |||
int speed; | |||
String title, name; | |||
Colour ballColour, fontColour, toggleColour; | |||
float yMax, xMax, yMin, xMin; | |||
float xOut, yOut, xRange, yRange, initX, initY; | |||
int decimalPlaces; | |||
OwnedArray<XYValueDisplay> valueDisplays; | |||
OwnedArray<XYToggle> xyToggles; | |||
ScopedPointer<CabbageLookAndFeel> lookAndFeel; | |||
ScopedPointer<CabbageLookAndFeelBasic> lookAndFeelBasic; | |||
bool canvasHasFocus; | |||
int currentSelectedToggle; | |||
String format; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYPad); | |||
}; | |||
@@ -1,17 +1,17 @@ | |||
#include "XYPadAutomation.h" | |||
XYPadAutomation::XYPadAutomation() | |||
XYPadAutomation::XYPadAutomation() | |||
{ | |||
ballPathDirection = 1; | |||
timerInterval = 50; | |||
ballPathDirection = 1; | |||
timerInterval = 50; | |||
selectedToggle = 0; | |||
speedSliderValue = 0; | |||
isAutomationOn = false; | |||
updateCounter = 0; | |||
paramIndex = 0; | |||
creationCounter = 0; | |||
selectedToggle = 0; | |||
speedSliderValue = 0; | |||
isAutomationOn = false; | |||
updateCounter = 0; | |||
paramIndex = 0; | |||
creationCounter = 0; | |||
} | |||
XYPadAutomation::~XYPadAutomation() | |||
@@ -20,219 +20,229 @@ XYPadAutomation::~XYPadAutomation() | |||
void XYPadAutomation::updateCreationCounter() | |||
{ | |||
creationCounter++; | |||
creationCounter++; | |||
} | |||
int XYPadAutomation::getCreationCounter() | |||
{ | |||
return creationCounter; | |||
return creationCounter; | |||
} | |||
void XYPadAutomation::setBallSize (float size) | |||
{ | |||
ballSize = size; | |||
ballSize = size; | |||
} | |||
void XYPadAutomation::setBoundsForAutomation(Rectangle<int> bounds) | |||
{ | |||
availableBounds.setWidth(bounds.getWidth()-ballSize); | |||
availableBounds.setHeight(bounds.getHeight()-ballSize); | |||
} | |||
availableBounds.setWidth(bounds.getWidth()-ballSize); | |||
availableBounds.setHeight(bounds.getHeight()-ballSize); | |||
} | |||
void XYPadAutomation::setBallPath (Path path) | |||
{ | |||
AffineTransform transform = AffineTransform::translation((ballSize/2)*-1, (ballSize/2)*-1); | |||
path.applyTransform(transform); | |||
ballPath = path; | |||
AffineTransform transform = AffineTransform::translation((ballSize/2)*-1, (ballSize/2)*-1); | |||
path.applyTransform(transform); | |||
ballPath = path; | |||
} | |||
bool XYPadAutomation::isAutomating() | |||
{ | |||
return isAutomationOn; | |||
return isAutomationOn; | |||
} | |||
void XYPadAutomation::setMinMaxValues (float xMinimum, float xMaximum, float yMinimum, float yMaximum) | |||
{ | |||
xMin = xMinimum; | |||
yMin = yMinimum; | |||
xMax = xMaximum; | |||
yMax = yMaximum; | |||
xRange = xMax - xMin; | |||
yRange = yMax - yMin; | |||
xMin = xMinimum; | |||
yMin = yMinimum; | |||
xMax = xMaximum; | |||
yMax = yMaximum; | |||
xRange = xMax - xMin; | |||
yRange = yMax - yMin; | |||
xValue = getMinimumXValue(); | |||
yValue = getMinimumYValue(); | |||
xValue = getMinimumXValue(); | |||
yValue = getMinimumYValue(); | |||
} | |||
float XYPadAutomation::getMinimumXValue() | |||
{ | |||
return xMin; | |||
return xMin; | |||
} | |||
float XYPadAutomation::getMinimumYValue() | |||
{ | |||
return yMin; | |||
return yMin; | |||
} | |||
void XYPadAutomation::cancelAutomation() | |||
{ | |||
stopTimer(); | |||
isAutomationOn = false; | |||
xValueIncrement = yValueIncrement = 0; | |||
stopTimer(); | |||
isAutomationOn = false; | |||
xValueIncrement = yValueIncrement = 0; | |||
} | |||
void XYPadAutomation::setInitialSpeedSliderValue () | |||
{ | |||
// Function that calculates the initial speed slider value | |||
float length = ballPath.getLength(); | |||
// getting length of parent's diagonal using pythagoras's theorem | |||
int sumOfSquares = (availableBounds.getWidth()*availableBounds.getWidth()) + | |||
(availableBounds.getHeight()*availableBounds.getHeight()); | |||
int diagonal = pow(sumOfSquares, 0.5); //square root | |||
speedSliderValue = length / diagonal; | |||
// Function that calculates the initial speed slider value | |||
float length = ballPath.getLength(); | |||
// getting length of parent's diagonal using pythagoras's theorem | |||
int sumOfSquares = (availableBounds.getWidth()*availableBounds.getWidth()) + | |||
(availableBounds.getHeight()*availableBounds.getHeight()); | |||
int diagonal = pow(sumOfSquares, 0.5); //square root | |||
speedSliderValue = length / diagonal; | |||
} | |||
void XYPadAutomation::updateIncrements() | |||
{ | |||
xValueIncrement *= speedValue; | |||
yValueIncrement *= speedValue; | |||
xValueIncrement *= speedValue; | |||
yValueIncrement *= speedValue; | |||
} | |||
void XYPadAutomation::setSpeedSliderValue(float sliderValue) | |||
{ | |||
speedSliderValue = sliderValue; | |||
updateCounter = 0; //reset our counter | |||
speedSliderValue = sliderValue; | |||
updateCounter = 0; //reset our counter | |||
} | |||
void XYPadAutomation::beginAutomation(int selectedToggleButton) | |||
{ | |||
selectedToggle = selectedToggleButton; | |||
currentPointAlongPath = ballPath.getLength(); //ball begins traversing at the end of the path, rather than the start | |||
setInitialSpeedSliderValue (); | |||
Point<float> startDragPos = ballPath.getPointAlongPath(0); | |||
Point<float> secondPoint = ballPath.getPointAlongPath(1); | |||
Point<float> endDragPos = ballPath.getPointAlongPath(ballPath.getLength()); | |||
if (selectedToggle == 0) { | |||
xValueIncrement = ((secondPoint.getX()-startDragPos.getX()) / (float)availableBounds.getWidth()) * xRange; | |||
yValueIncrement = ((secondPoint.getY()-startDragPos.getY()) / (float)availableBounds.getHeight()) * yRange; | |||
yValueIncrement *= -1; //inverting because y axis is also inverted | |||
} | |||
//initialising | |||
xValue = ((endDragPos.getX()/(float)availableBounds.getWidth()) * xRange) + xMin; | |||
yValue = ((1 - (endDragPos.getY()/(float)availableBounds.getHeight())) * yRange) + yMin; //inverting y axis | |||
startTimer (timerInterval); | |||
isAutomationOn = true; | |||
selectedToggle = selectedToggleButton; | |||
currentPointAlongPath = ballPath.getLength(); //ball begins traversing at the end of the path, rather than the start | |||
setInitialSpeedSliderValue (); | |||
Point<float> startDragPos = ballPath.getPointAlongPath(0); | |||
Point<float> secondPoint = ballPath.getPointAlongPath(1); | |||
Point<float> endDragPos = ballPath.getPointAlongPath(ballPath.getLength()); | |||
if (selectedToggle == 0) | |||
{ | |||
xValueIncrement = ((secondPoint.getX()-startDragPos.getX()) / (float)availableBounds.getWidth()) * xRange; | |||
yValueIncrement = ((secondPoint.getY()-startDragPos.getY()) / (float)availableBounds.getHeight()) * yRange; | |||
yValueIncrement *= -1; //inverting because y axis is also inverted | |||
} | |||
//initialising | |||
xValue = ((endDragPos.getX()/(float)availableBounds.getWidth()) * xRange) + xMin; | |||
yValue = ((1 - (endDragPos.getY()/(float)availableBounds.getHeight())) * yRange) + yMin; //inverting y axis | |||
startTimer (timerInterval); | |||
isAutomationOn = true; | |||
} | |||
void XYPadAutomation::update() | |||
{ | |||
if (isAutomating()) { | |||
updateCounter = 0; | |||
if (selectedToggle == 0) { //first automation type | |||
xValue += xValueIncrement*(10*speedSliderValue); | |||
yValue += yValueIncrement*(10*speedSliderValue); | |||
// If a border is hit then the increment value should be reversed... | |||
if (xValue <= xMin) { | |||
xValue = xMin; | |||
xValueIncrement*=-1; | |||
} | |||
else if (xValue >= xMax) { | |||
xValue = xMax; | |||
xValueIncrement*=-1; | |||
} | |||
if (yValue <= yMin) { | |||
yValue = yMin; | |||
yValueIncrement*=-1; | |||
} | |||
else if (yValue >= yMax) { | |||
yValue = yMax; | |||
yValueIncrement*=-1; | |||
} | |||
} | |||
else if (selectedToggle == 1) { //2nd automation type | |||
Point<float> pt = ballPath.getPointAlongPath(currentPointAlongPath, AffineTransform::identity); | |||
xValue = (((pt.getX()/(float)availableBounds.getWidth()) * xRange) + xMin); | |||
yValue = ((pt.getY()/(float)availableBounds.getHeight()) * yRange); | |||
yValue = ((yRange-yValue) + yMin); //inverting and adding yMin | |||
currentPointAlongPath += ballPathDirection*(10*speedSliderValue); | |||
if (currentPointAlongPath > ballPath.getLength()) { | |||
currentPointAlongPath = ballPath.getLength(); | |||
ballPathDirection *= -1; | |||
} | |||
else if (currentPointAlongPath < 0) { | |||
currentPointAlongPath = 0; | |||
ballPathDirection *= -1; | |||
} | |||
} | |||
} | |||
if (isAutomating()) | |||
{ | |||
updateCounter = 0; | |||
if (selectedToggle == 0) //first automation type | |||
{ | |||
xValue += xValueIncrement*(10*speedSliderValue); | |||
yValue += yValueIncrement*(10*speedSliderValue); | |||
// If a border is hit then the increment value should be reversed... | |||
if (xValue <= xMin) | |||
{ | |||
xValue = xMin; | |||
xValueIncrement*=-1; | |||
} | |||
else if (xValue >= xMax) | |||
{ | |||
xValue = xMax; | |||
xValueIncrement*=-1; | |||
} | |||
if (yValue <= yMin) | |||
{ | |||
yValue = yMin; | |||
yValueIncrement*=-1; | |||
} | |||
else if (yValue >= yMax) | |||
{ | |||
yValue = yMax; | |||
yValueIncrement*=-1; | |||
} | |||
} | |||
else if (selectedToggle == 1) //2nd automation type | |||
{ | |||
Point<float> pt = ballPath.getPointAlongPath(currentPointAlongPath, AffineTransform::identity); | |||
xValue = (((pt.getX()/(float)availableBounds.getWidth()) * xRange) + xMin); | |||
yValue = ((pt.getY()/(float)availableBounds.getHeight()) * yRange); | |||
yValue = ((yRange-yValue) + yMin); //inverting and adding yMin | |||
currentPointAlongPath += ballPathDirection*(10*speedSliderValue); | |||
if (currentPointAlongPath > ballPath.getLength()) | |||
{ | |||
currentPointAlongPath = ballPath.getLength(); | |||
ballPathDirection *= -1; | |||
} | |||
else if (currentPointAlongPath < 0) | |||
{ | |||
currentPointAlongPath = 0; | |||
ballPathDirection *= -1; | |||
} | |||
} | |||
} | |||
} | |||
void XYPadAutomation::timerCallback() | |||
{ | |||
sendChangeMessage(); | |||
sendChangeMessage(); | |||
} | |||
Point<float> XYPadAutomation::getStartHandle() | |||
{ | |||
Point<float> startHandle = ballPath.getPointAlongPath(0); | |||
startHandle.setX(startHandle.getX() + (ballSize/2)); | |||
startHandle.setY(startHandle.getY() + (ballSize/2)); | |||
Point<float> startHandle = ballPath.getPointAlongPath(0); | |||
startHandle.setX(startHandle.getX() + (ballSize/2)); | |||
startHandle.setY(startHandle.getY() + (ballSize/2)); | |||
return startHandle; | |||
return startHandle; | |||
} | |||
Point<float> XYPadAutomation::getEndHandle() | |||
{ | |||
Point<float> endHandle = ballPath.getPointAlongPath(ballPath.getLength()); | |||
endHandle.setX(endHandle.getX() + (ballSize/2)); | |||
endHandle.setY(endHandle.getY() + (ballSize/2)); | |||
Point<float> endHandle = ballPath.getPointAlongPath(ballPath.getLength()); | |||
endHandle.setX(endHandle.getX() + (ballSize/2)); | |||
endHandle.setY(endHandle.getY() + (ballSize/2)); | |||
return endHandle; | |||
return endHandle; | |||
} | |||
float XYPadAutomation::getXValue() | |||
{ | |||
return xValue; | |||
return xValue; | |||
} | |||
float XYPadAutomation::getYValue() | |||
{ | |||
return yValue; | |||
return yValue; | |||
} | |||
float XYPadAutomation::getNormalisedXValue() | |||
{ | |||
return (xValue-xMin)/xRange; | |||
return (xValue-xMin)/xRange; | |||
} | |||
float XYPadAutomation::getNormalisedYValue() | |||
{ | |||
return (yValue-yMin)/yRange; | |||
return (yValue-yMin)/yRange; | |||
} | |||
void XYPadAutomation::setXValue(float value) | |||
{ | |||
xValue = value; | |||
sendChangeMessage(); | |||
xValue = value; | |||
sendChangeMessage(); | |||
} | |||
void XYPadAutomation::setYValue(float value) | |||
{ | |||
yValue = value; | |||
sendChangeMessage(); | |||
yValue = value; | |||
sendChangeMessage(); | |||
} | |||
int XYPadAutomation::getSelectedToggle() | |||
{ | |||
return selectedToggle; | |||
return selectedToggle; | |||
} | |||
float XYPadAutomation::getSpeedSliderValue() | |||
{ | |||
return speedSliderValue; | |||
return speedSliderValue; | |||
} |
@@ -4,7 +4,7 @@ | |||
Cabbage is free software; you can redistribute it | |||
and/or modify it under the terms of the GNU Lesser General Public | |||
License as published by the Free Software Foundation; either | |||
version 2.1 of the License, or (at your option) any later version. | |||
version 2.1 of the License, or (at your option) any later version. | |||
Cabbage is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
@@ -27,69 +27,71 @@ | |||
// XYPad Automation class. Allows plugin editor to close while maintining automation | |||
//============================================================================== | |||
class XYPadAutomation : public Timer, | |||
public ChangeBroadcaster | |||
public ChangeBroadcaster | |||
{ | |||
public: | |||
XYPadAutomation(); | |||
~XYPadAutomation(); | |||
void updateCreationCounter(); | |||
int getCreationCounter(); | |||
void beginAutomation(int selectedToggleButton); | |||
void setBallSize (float size); | |||
void setMinMaxValues (float xMinimum, float xMaximum, float yMinimum, float yMaximum); | |||
float getMinimumXValue(); | |||
float getMinimumYValue(); | |||
void updateIncrements(); | |||
void setInitialSpeedSliderValue (); | |||
void setBallPath (Path path); | |||
void cancelAutomation(); | |||
bool isAutomating(); | |||
void setSpeedSliderValue(float sliderValue); | |||
void setBoundsForAutomation(Rectangle<int> bounds); | |||
void timerCallback(); | |||
Point<float> getStartHandle(); | |||
Point<float> getEndHandle(); | |||
float getXValue(); | |||
float getYValue(); | |||
float getNormalisedXValue(); | |||
float getNormalisedYValue(); | |||
void setXValue(float value); | |||
void setYValue(float value); | |||
int getSelectedToggle(); | |||
float getSpeedSliderValue(); | |||
String xChannel, yChannel; | |||
void update(); | |||
int updateCounter; | |||
int paramIndex; | |||
int creationCounter; | |||
bool isAutomationOn; | |||
float getYRange(){ | |||
return yRange; | |||
} | |||
float getXRange(){ | |||
return xRange; | |||
} | |||
XYPadAutomation(); | |||
~XYPadAutomation(); | |||
void updateCreationCounter(); | |||
int getCreationCounter(); | |||
void beginAutomation(int selectedToggleButton); | |||
void setBallSize (float size); | |||
void setMinMaxValues (float xMinimum, float xMaximum, float yMinimum, float yMaximum); | |||
float getMinimumXValue(); | |||
float getMinimumYValue(); | |||
void updateIncrements(); | |||
void setInitialSpeedSliderValue (); | |||
void setBallPath (Path path); | |||
void cancelAutomation(); | |||
bool isAutomating(); | |||
void setSpeedSliderValue(float sliderValue); | |||
void setBoundsForAutomation(Rectangle<int> bounds); | |||
void timerCallback(); | |||
Point<float> getStartHandle(); | |||
Point<float> getEndHandle(); | |||
float getXValue(); | |||
float getYValue(); | |||
float getNormalisedXValue(); | |||
float getNormalisedYValue(); | |||
void setXValue(float value); | |||
void setYValue(float value); | |||
int getSelectedToggle(); | |||
float getSpeedSliderValue(); | |||
String xChannel, yChannel; | |||
void update(); | |||
int updateCounter; | |||
int paramIndex; | |||
int creationCounter; | |||
bool isAutomationOn; | |||
float getYRange() | |||
{ | |||
return yRange; | |||
} | |||
float getXRange() | |||
{ | |||
return xRange; | |||
} | |||
private: | |||
float xValue, yValue; | |||
int timerInterval, minTimerInterval; | |||
float xValueIncrement, yValueIncrement; | |||
float speedSliderValue, speedValue; | |||
Rectangle<int> availableBounds; | |||
float ballSize; | |||
float xMin, yMin, xMax, yMax, xRange, yRange; | |||
float xOut, yOut; | |||
int selectedToggle; | |||
Path ballPath; | |||
float currentPointAlongPath, ballPathDirection; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYPadAutomation); | |||
float xValue, yValue; | |||
int timerInterval, minTimerInterval; | |||
float xValueIncrement, yValueIncrement; | |||
float speedSliderValue, speedValue; | |||
Rectangle<int> availableBounds; | |||
float ballSize; | |||
float xMin, yMin, xMax, yMax, xRange, yRange; | |||
float xOut, yOut; | |||
int selectedToggle; | |||
Path ballPath; | |||
float currentPointAlongPath, ballPathDirection; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYPadAutomation); | |||
}; | |||
@@ -34,24 +34,25 @@ | |||
* Base class for event messages. | |||
*/ | |||
class CsoundPerformanceThreadMessage { | |||
protected: | |||
class CsoundPerformanceThreadMessage | |||
{ | |||
protected: | |||
CsoundPerformanceThread *pt_; | |||
void SetPaused(int state) | |||
{ | |||
pt_->paused = state; | |||
pt_->paused = state; | |||
} | |||
int GetPaused() | |||
{ | |||
return pt_->paused; | |||
return pt_->paused; | |||
} | |||
public: | |||
public: | |||
CsoundPerformanceThreadMessage *nxt; | |||
virtual int run() = 0; | |||
CsoundPerformanceThreadMessage(CsoundPerformanceThread *pt) | |||
{ | |||
pt_ = pt; | |||
nxt = (CsoundPerformanceThreadMessage*) 0; | |||
pt_ = pt; | |||
nxt = (CsoundPerformanceThreadMessage*) 0; | |||
} | |||
virtual ~CsoundPerformanceThreadMessage() | |||
{ | |||
@@ -62,16 +63,17 @@ class CsoundPerformanceThreadMessage { | |||
* Unpause performance | |||
*/ | |||
class CsPerfThreadMsg_Play : public CsoundPerformanceThreadMessage { | |||
public: | |||
class CsPerfThreadMsg_Play : public CsoundPerformanceThreadMessage | |||
{ | |||
public: | |||
CsPerfThreadMsg_Play(CsoundPerformanceThread *pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
{ | |||
} | |||
int run() | |||
{ | |||
SetPaused(0); | |||
return 0; | |||
SetPaused(0); | |||
return 0; | |||
} | |||
~CsPerfThreadMsg_Play() | |||
{ | |||
@@ -82,16 +84,17 @@ class CsPerfThreadMsg_Play : public CsoundPerformanceThreadMessage { | |||
* Pause performance | |||
*/ | |||
class CsPerfThreadMsg_Pause : public CsoundPerformanceThreadMessage { | |||
public: | |||
class CsPerfThreadMsg_Pause : public CsoundPerformanceThreadMessage | |||
{ | |||
public: | |||
CsPerfThreadMsg_Pause(CsoundPerformanceThread *pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
{ | |||
} | |||
int run() | |||
{ | |||
SetPaused(1); | |||
return 0; | |||
SetPaused(1); | |||
return 0; | |||
} | |||
~CsPerfThreadMsg_Pause() | |||
{ | |||
@@ -102,16 +105,17 @@ class CsPerfThreadMsg_Pause : public CsoundPerformanceThreadMessage { | |||
* Toggle pause mode | |||
*/ | |||
class CsPerfThreadMsg_TogglePause : public CsoundPerformanceThreadMessage { | |||
public: | |||
class CsPerfThreadMsg_TogglePause : public CsoundPerformanceThreadMessage | |||
{ | |||
public: | |||
CsPerfThreadMsg_TogglePause(CsoundPerformanceThread *pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
{ | |||
} | |||
int run() | |||
{ | |||
SetPaused(GetPaused() ? 0 : 1); | |||
return 0; | |||
SetPaused(GetPaused() ? 0 : 1); | |||
return 0; | |||
} | |||
~CsPerfThreadMsg_TogglePause() | |||
{ | |||
@@ -122,15 +126,16 @@ class CsPerfThreadMsg_TogglePause : public CsoundPerformanceThreadMessage { | |||
* Stop performance (cannot be continued) | |||
*/ | |||
class CsPerfThreadMsg_Stop : public CsoundPerformanceThreadMessage { | |||
public: | |||
class CsPerfThreadMsg_Stop : public CsoundPerformanceThreadMessage | |||
{ | |||
public: | |||
CsPerfThreadMsg_Stop(CsoundPerformanceThread *pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
{ | |||
} | |||
int run() | |||
{ | |||
return 1; | |||
return 1; | |||
} | |||
~CsPerfThreadMsg_Stop() | |||
{ | |||
@@ -147,54 +152,58 @@ class CsPerfThreadMsg_Stop : public CsoundPerformanceThreadMessage { | |||
* *p: array of p-fields, p[0] is p1 | |||
*/ | |||
class CsPerfThreadMsg_ScoreEvent : public CsoundPerformanceThreadMessage { | |||
private: | |||
class CsPerfThreadMsg_ScoreEvent : public CsoundPerformanceThreadMessage | |||
{ | |||
private: | |||
char opcod; | |||
int absp2mode; | |||
int pcnt; | |||
MYFLT *pp; | |||
MYFLT p[10]; | |||
public: | |||
public: | |||
CsPerfThreadMsg_ScoreEvent(CsoundPerformanceThread *pt, | |||
int absp2mode, char opcod, | |||
int pcnt, const MYFLT *p) | |||
: CsoundPerformanceThreadMessage(pt) | |||
{ | |||
this->opcod = opcod; | |||
this->absp2mode = absp2mode; | |||
this->pcnt = pcnt; | |||
if (pcnt <= 10) | |||
this->pp = &(this->p[0]); | |||
else | |||
this->pp = new MYFLT[(unsigned int) pcnt]; | |||
for (int i = 0; i < pcnt; i++) | |||
this->pp[i] = p[i]; | |||
: CsoundPerformanceThreadMessage(pt) | |||
{ | |||
this->opcod = opcod; | |||
this->absp2mode = absp2mode; | |||
this->pcnt = pcnt; | |||
if (pcnt <= 10) | |||
this->pp = &(this->p[0]); | |||
else | |||
this->pp = new MYFLT[(unsigned int) pcnt]; | |||
for (int i = 0; i < pcnt; i++) | |||
this->pp[i] = p[i]; | |||
} | |||
int run() | |||
{ | |||
CSOUND *csound = pt_->GetCsound(); | |||
if (absp2mode && pcnt > 1) { | |||
double p2 = (double) pp[1] - csoundGetScoreTime(csound); | |||
if (p2 < 0.0) { | |||
if (pcnt > 2 && pp[2] >= (MYFLT) 0 && | |||
(opcod == 'a' || opcod == 'i')) { | |||
pp[2] = (MYFLT) ((double) pp[2] + p2); | |||
if (pp[2] <= (MYFLT) 0) | |||
return 0; | |||
} | |||
p2 = 0.0; | |||
CSOUND *csound = pt_->GetCsound(); | |||
if (absp2mode && pcnt > 1) | |||
{ | |||
double p2 = (double) pp[1] - csoundGetScoreTime(csound); | |||
if (p2 < 0.0) | |||
{ | |||
if (pcnt > 2 && pp[2] >= (MYFLT) 0 && | |||
(opcod == 'a' || opcod == 'i')) | |||
{ | |||
pp[2] = (MYFLT) ((double) pp[2] + p2); | |||
if (pp[2] <= (MYFLT) 0) | |||
return 0; | |||
} | |||
p2 = 0.0; | |||
} | |||
pp[1] = (MYFLT) p2; | |||
} | |||
pp[1] = (MYFLT) p2; | |||
} | |||
if (csoundScoreEvent(csound, opcod, pp, (long) pcnt) != 0) | |||
csoundMessageS(csound, CSOUNDMSG_WARNING, | |||
"WARNING: could not create score event\n"); | |||
return 0; | |||
if (csoundScoreEvent(csound, opcod, pp, (long) pcnt) != 0) | |||
csoundMessageS(csound, CSOUNDMSG_WARNING, | |||
"WARNING: could not create score event\n"); | |||
return 0; | |||
} | |||
~CsPerfThreadMsg_ScoreEvent() | |||
{ | |||
if (pcnt > 10) | |||
delete[] pp; | |||
if (pcnt > 10) | |||
delete[] pp; | |||
} | |||
}; | |||
@@ -202,31 +211,32 @@ class CsPerfThreadMsg_ScoreEvent : public CsoundPerformanceThreadMessage { | |||
* Score event message as a string | |||
*/ | |||
class CsPerfThreadMsg_InputMessage : public CsoundPerformanceThreadMessage { | |||
private: | |||
class CsPerfThreadMsg_InputMessage : public CsoundPerformanceThreadMessage | |||
{ | |||
private: | |||
int len; | |||
char *sp; | |||
char s[128]; | |||
public: | |||
public: | |||
CsPerfThreadMsg_InputMessage(CsoundPerformanceThread *pt, const char *s) | |||
: CsoundPerformanceThreadMessage(pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
{ | |||
len = (int) strlen(s); | |||
if (len < 128) | |||
this->sp = &(this->s[0]); | |||
else | |||
this->sp = new char[(unsigned int) (len + 1)]; | |||
strcpy(this->sp, s); | |||
len = (int) strlen(s); | |||
if (len < 128) | |||
this->sp = &(this->s[0]); | |||
else | |||
this->sp = new char[(unsigned int) (len + 1)]; | |||
strcpy(this->sp, s); | |||
} | |||
int run() | |||
{ | |||
csoundInputMessage(pt_->GetCsound(), sp); | |||
return 0; | |||
csoundInputMessage(pt_->GetCsound(), sp); | |||
return 0; | |||
} | |||
~CsPerfThreadMsg_InputMessage() | |||
{ | |||
if (len >= 128) | |||
delete[] sp; | |||
if (len >= 128) | |||
delete[] sp; | |||
} | |||
}; | |||
@@ -235,20 +245,21 @@ class CsPerfThreadMsg_InputMessage : public CsoundPerformanceThreadMessage { | |||
*/ | |||
class CsPerfThreadMsg_SetScoreOffsetSeconds | |||
: public CsoundPerformanceThreadMessage { | |||
private: | |||
: public CsoundPerformanceThreadMessage | |||
{ | |||
private: | |||
double timeVal; | |||
public: | |||
public: | |||
CsPerfThreadMsg_SetScoreOffsetSeconds(CsoundPerformanceThread *pt, | |||
double timeVal) | |||
: CsoundPerformanceThreadMessage(pt) | |||
: CsoundPerformanceThreadMessage(pt) | |||
{ | |||
this->timeVal = timeVal; | |||
this->timeVal = timeVal; | |||
} | |||
int run() | |||
{ | |||
csoundSetScoreOffsetSeconds(pt_->GetCsound(), (MYFLT) timeVal); | |||
return 0; | |||
csoundSetScoreOffsetSeconds(pt_->GetCsound(), (MYFLT) timeVal); | |||
return 0; | |||
} | |||
~CsPerfThreadMsg_SetScoreOffsetSeconds() | |||
{ | |||
@@ -265,56 +276,62 @@ class CsPerfThreadMsg_SetScoreOffsetSeconds | |||
int CsoundPerformanceThread::Perform() | |||
{ | |||
int retval = 0; | |||
do { | |||
while (firstMessage) { | |||
csoundLockMutex(queueLock); | |||
do { | |||
CsoundPerformanceThreadMessage *msg; | |||
// get oldest message | |||
msg = (CsoundPerformanceThreadMessage*) firstMessage; | |||
if (!msg) | |||
break; | |||
// unlink from FIFO | |||
firstMessage = msg->nxt; | |||
if (!msg->nxt) | |||
lastMessage = (CsoundPerformanceThreadMessage*) 0; | |||
// process and destroy message | |||
retval = msg->run(); | |||
delete msg; | |||
} while (!retval); | |||
if (paused) | |||
csoundWaitThreadLock(pauseLock, (size_t) 0); | |||
// mark queue as empty | |||
csoundNotifyThreadLock(flushLock); | |||
csoundUnlockMutex(queueLock); | |||
// if error or end of score, return now | |||
if (retval) | |||
goto endOfPerf; | |||
// if paused, wait until a new message is received, then loop back | |||
if (!paused) | |||
break; | |||
csoundWaitThreadLockNoTimeout(pauseLock); | |||
csoundNotifyThreadLock(pauseLock); | |||
} | |||
if(processcallback != NULL) | |||
processcallback(cdata); | |||
retval = csoundPerformKsmps(csound); | |||
} while (!retval); | |||
endOfPerf: | |||
do | |||
{ | |||
while (firstMessage) | |||
{ | |||
csoundLockMutex(queueLock); | |||
do | |||
{ | |||
CsoundPerformanceThreadMessage *msg; | |||
// get oldest message | |||
msg = (CsoundPerformanceThreadMessage*) firstMessage; | |||
if (!msg) | |||
break; | |||
// unlink from FIFO | |||
firstMessage = msg->nxt; | |||
if (!msg->nxt) | |||
lastMessage = (CsoundPerformanceThreadMessage*) 0; | |||
// process and destroy message | |||
retval = msg->run(); | |||
delete msg; | |||
} | |||
while (!retval); | |||
if (paused) | |||
csoundWaitThreadLock(pauseLock, (size_t) 0); | |||
// mark queue as empty | |||
csoundNotifyThreadLock(flushLock); | |||
csoundUnlockMutex(queueLock); | |||
// if error or end of score, return now | |||
if (retval) | |||
goto endOfPerf; | |||
// if paused, wait until a new message is received, then loop back | |||
if (!paused) | |||
break; | |||
csoundWaitThreadLockNoTimeout(pauseLock); | |||
csoundNotifyThreadLock(pauseLock); | |||
} | |||
if(processcallback != NULL) | |||
processcallback(cdata); | |||
retval = csoundPerformKsmps(csound); | |||
} | |||
while (!retval); | |||
endOfPerf: | |||
status = retval; | |||
csoundCleanup(csound); | |||
// delete any pending messages | |||
csoundLockMutex(queueLock); | |||
{ | |||
CsoundPerformanceThreadMessage *msg; | |||
msg = (CsoundPerformanceThreadMessage*) firstMessage; | |||
firstMessage = (CsoundPerformanceThreadMessage*) 0; | |||
lastMessage = (CsoundPerformanceThreadMessage*) 0; | |||
while (msg) { | |||
CsoundPerformanceThreadMessage *nxt = msg->nxt; | |||
delete msg; | |||
msg = nxt; | |||
} | |||
CsoundPerformanceThreadMessage *msg; | |||
msg = (CsoundPerformanceThreadMessage*) firstMessage; | |||
firstMessage = (CsoundPerformanceThreadMessage*) 0; | |||
lastMessage = (CsoundPerformanceThreadMessage*) 0; | |||
while (msg) | |||
{ | |||
CsoundPerformanceThreadMessage *nxt = msg->nxt; | |||
delete msg; | |||
msg = nxt; | |||
} | |||
} | |||
csoundNotifyThreadLock(flushLock); | |||
csoundUnlockMutex(queueLock); | |||
@@ -322,17 +339,18 @@ int CsoundPerformanceThread::Perform() | |||
return retval; | |||
} | |||
class CsPerfThread_PerformScore { | |||
private: | |||
class CsPerfThread_PerformScore | |||
{ | |||
private: | |||
CsoundPerformanceThread *pt; | |||
public: | |||
public: | |||
int Perform() | |||
{ | |||
return pt->Perform(); | |||
return pt->Perform(); | |||
} | |||
CsPerfThread_PerformScore(void *p) | |||
{ | |||
pt = (CsoundPerformanceThread*) p; | |||
pt = (CsoundPerformanceThread*) p; | |||
} | |||
~CsPerfThread_PerformScore() | |||
{ | |||
@@ -340,14 +358,14 @@ class CsPerfThread_PerformScore { | |||
}; | |||
extern "C" { | |||
static uintptr_t csoundPerformanceThread_(void *userData) | |||
{ | |||
CsPerfThread_PerformScore p(userData); | |||
// perform the score | |||
int retval = p.Perform(); | |||
// return positive value if stopped or end of score, and negative on error | |||
return (uintptr_t) ((unsigned int) retval); | |||
} | |||
static uintptr_t csoundPerformanceThread_(void *userData) | |||
{ | |||
CsPerfThread_PerformScore p(userData); | |||
// perform the score | |||
int retval = p.Perform(); | |||
// return positive value if stopped or end of score, and negative on error | |||
return (uintptr_t) ((unsigned int) retval); | |||
} | |||
} | |||
void CsoundPerformanceThread::csPerfThread_constructor(CSOUND *csound) | |||
@@ -363,25 +381,27 @@ void CsoundPerformanceThread::csPerfThread_constructor(CSOUND *csound) | |||
status = CSOUND_MEMORY; | |||
queueLock = csoundCreateMutex(0); | |||
if (!queueLock) | |||
return; | |||
return; | |||
pauseLock = csoundCreateThreadLock(); | |||
if (!pauseLock) | |||
return; | |||
return; | |||
flushLock = csoundCreateThreadLock(); | |||
if (!flushLock) | |||
return; | |||
try { | |||
lastMessage = new CsPerfThreadMsg_Pause(this); | |||
return; | |||
try | |||
{ | |||
lastMessage = new CsPerfThreadMsg_Pause(this); | |||
} | |||
catch (std::bad_alloc&) { | |||
return; | |||
catch (std::bad_alloc&) | |||
{ | |||
return; | |||
} | |||
processcallback = NULL; | |||
running = 0; | |||
firstMessage = lastMessage; | |||
perfThread = csoundCreateThread(csoundPerformanceThread_, (void*) this); | |||
if (perfThread) | |||
status = 0; | |||
status = 0; | |||
} | |||
// ---------------------------------------------------------------------------- | |||
@@ -414,7 +434,7 @@ CsoundPerformanceThread::~CsoundPerformanceThread() | |||
{ | |||
// stop performance if it is still running | |||
if (!status) | |||
this->Stop(); // FIXME: should handle memory errors here | |||
this->Stop(); // FIXME: should handle memory errors here | |||
this->Join(); | |||
} | |||
@@ -426,16 +446,17 @@ CsoundPerformanceThread::~CsoundPerformanceThread() | |||
void CsoundPerformanceThread::QueueMessage(CsoundPerformanceThreadMessage *msg) | |||
{ | |||
if (status) { | |||
delete msg; | |||
return; | |||
if (status) | |||
{ | |||
delete msg; | |||
return; | |||
} | |||
csoundLockMutex(queueLock); | |||
// link message into FIFO | |||
if (!lastMessage) | |||
firstMessage = msg; | |||
firstMessage = msg; | |||
else | |||
lastMessage->nxt = msg; | |||
lastMessage->nxt = msg; | |||
lastMessage = msg; | |||
// mark queue as non-empty | |||
csoundWaitThreadLock(flushLock, (size_t) 0); | |||
@@ -489,10 +510,10 @@ void CsoundPerformanceThread::Stop() | |||
*/ | |||
void CsoundPerformanceThread::ScoreEvent(int absp2mode, char opcod, | |||
int pcnt, const MYFLT *p) | |||
int pcnt, const MYFLT *p) | |||
{ | |||
QueueMessage(new CsPerfThreadMsg_ScoreEvent(this, | |||
absp2mode, opcod, pcnt, p)); | |||
absp2mode, opcod, pcnt, p)); | |||
} | |||
/** | |||
@@ -527,37 +548,42 @@ int CsoundPerformanceThread::Join() | |||
int retval; | |||
retval = status; | |||
if (perfThread) { | |||
retval = csoundJoinThread(perfThread); | |||
perfThread = (void*) 0; | |||
if (perfThread) | |||
{ | |||
retval = csoundJoinThread(perfThread); | |||
perfThread = (void*) 0; | |||
} | |||
// delete any pending messages | |||
{ | |||
CsoundPerformanceThreadMessage *msg; | |||
msg = (CsoundPerformanceThreadMessage*) firstMessage; | |||
firstMessage = (CsoundPerformanceThreadMessage*) 0; | |||
lastMessage = (CsoundPerformanceThreadMessage*) 0; | |||
while (msg) { | |||
CsoundPerformanceThreadMessage *nxt = msg->nxt; | |||
delete msg; | |||
msg = nxt; | |||
} | |||
CsoundPerformanceThreadMessage *msg; | |||
msg = (CsoundPerformanceThreadMessage*) firstMessage; | |||
firstMessage = (CsoundPerformanceThreadMessage*) 0; | |||
lastMessage = (CsoundPerformanceThreadMessage*) 0; | |||
while (msg) | |||
{ | |||
CsoundPerformanceThreadMessage *nxt = msg->nxt; | |||
delete msg; | |||
msg = nxt; | |||
} | |||
} | |||
// delete all thread locks | |||
if (queueLock) { | |||
csoundDestroyMutex(queueLock); | |||
queueLock = (void*) 0; | |||
if (queueLock) | |||
{ | |||
csoundDestroyMutex(queueLock); | |||
queueLock = (void*) 0; | |||
} | |||
if (pauseLock) { | |||
csoundNotifyThreadLock(pauseLock); | |||
csoundDestroyThreadLock(pauseLock); | |||
pauseLock = (void*) 0; | |||
if (pauseLock) | |||
{ | |||
csoundNotifyThreadLock(pauseLock); | |||
csoundDestroyThreadLock(pauseLock); | |||
pauseLock = (void*) 0; | |||
} | |||
if (flushLock) { | |||
csoundNotifyThreadLock(flushLock); | |||
csoundDestroyThreadLock(flushLock); | |||
flushLock = (void*) 0; | |||
if (flushLock) | |||
{ | |||
csoundNotifyThreadLock(flushLock); | |||
csoundDestroyThreadLock(flushLock); | |||
flushLock = (void*) 0; | |||
} | |||
return retval; | |||
@@ -570,9 +596,10 @@ int CsoundPerformanceThread::Join() | |||
void CsoundPerformanceThread::FlushMessageQueue() | |||
{ | |||
if (firstMessage) { | |||
csoundWaitThreadLockNoTimeout(flushLock); | |||
csoundNotifyThreadLock(flushLock); | |||
if (firstMessage) | |||
{ | |||
csoundWaitThreadLockNoTimeout(flushLock); | |||
csoundNotifyThreadLock(flushLock); | |||
} | |||
} | |||
@@ -76,14 +76,16 @@ int main(int argc, char *argv[]) | |||
*/ | |||
#ifdef SWIGPYTHON | |||
struct PUBLIC pycallbackdata { | |||
PyObject *func; | |||
PyObject *data; | |||
struct PUBLIC pycallbackdata | |||
{ | |||
PyObject *func; | |||
PyObject *data; | |||
}; | |||
#endif | |||
class PUBLIC CsoundPerformanceThread { | |||
private: | |||
class PUBLIC CsoundPerformanceThread | |||
{ | |||
private: | |||
volatile CsoundPerformanceThreadMessage *firstMessage; | |||
CsoundPerformanceThreadMessage *lastMessage; | |||
CSOUND *csound; | |||
@@ -100,30 +102,37 @@ class PUBLIC CsoundPerformanceThread { | |||
void csPerfThread_constructor(CSOUND *); | |||
void QueueMessage(CsoundPerformanceThreadMessage *); | |||
void (*processcallback)(void *cdata); | |||
public: | |||
int isRunning() { return running;} | |||
public: | |||
int isRunning() | |||
{ | |||
return running; | |||
} | |||
#ifdef SWIGPYTHON | |||
PyThreadState *_tstate; | |||
pycallbackdata pydata; | |||
PyThreadState *_tstate; | |||
pycallbackdata pydata; | |||
#endif | |||
/** | |||
* Returns the process callback as a void pointer | |||
*/ | |||
void *GetProcessCallback() { return (void *)processcallback; } | |||
/** | |||
* Sets the process callback. | |||
*/ | |||
void SetProcessCallback(void (*Callback)(void *), void *cbdata){ | |||
processcallback = Callback; | |||
cdata = cbdata; | |||
} | |||
/** | |||
* Returns the process callback as a void pointer | |||
*/ | |||
void *GetProcessCallback() | |||
{ | |||
return (void *)processcallback; | |||
} | |||
/** | |||
* Sets the process callback. | |||
*/ | |||
void SetProcessCallback(void (*Callback)(void *), void *cbdata) | |||
{ | |||
processcallback = Callback; | |||
cdata = cbdata; | |||
} | |||
/** | |||
* Returns the Csound instance pointer. | |||
*/ | |||
CSOUND *GetCsound() | |||
{ | |||
return csound; | |||
return csound; | |||
} | |||
/** | |||
* Returns the current status, zero if still playing, positive if | |||
@@ -132,7 +141,7 @@ class PUBLIC CsoundPerformanceThread { | |||
*/ | |||
int GetStatus() | |||
{ | |||
return status; | |||
return status; | |||
} | |||
/** | |||
* Continues performance if it was paused. | |||