@@ -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); | setAlwaysOnTop (true); | ||||
updatePosition (area, Desktop::getInstance().getDisplays() | updatePosition (area, Desktop::getInstance().getDisplays() | ||||
.getDisplayContaining (area.getCentre()).userArea); | |||||
.getDisplayContaining (area.getCentre()).userArea); | |||||
addToDesktop (ComponentPeer::windowIsTemporary); | addToDesktop (ComponentPeer::windowIsTemporary); | ||||
} | } | ||||
@@ -48,8 +48,8 @@ public: | |||||
}; | }; | ||||
CabbageCallOutBox& CabbageCallOutBox::launchAsynchronously (Component* content, | 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! | jassert (content != nullptr); // must be a valid content component! | ||||
@@ -60,7 +60,7 @@ CabbageCallOutBox& CabbageCallOutBox::launchAsynchronously (Component* content, | |||||
void CabbageCallOutBox::paint (Graphics& g) | void CabbageCallOutBox::paint (Graphics& g) | ||||
{ | { | ||||
g.fillAll(Colours::black); | |||||
g.fillAll(Colours::black); | |||||
// getLookAndFeel().drawCallOutBoxBackground (*this, g, outline, background); | // 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> targets[4] = { Point<float> ((float) targetArea.getCentreX(), (float) targetArea.getBottom()), | ||||
Point<float> ((float) targetArea.getRight(), (float) targetArea.getCentreY()), | Point<float> ((float) targetArea.getRight(), (float) targetArea.getCentreY()), | ||||
Point<float> ((float) targetArea.getX(), (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> 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[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[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 Rectangle<float> centrePointArea (newAreaToFitIn.reduced (hw, hh).toFloat()); | ||||
const Point<float> targetCentre (targetArea.getCentre().toFloat()); | const Point<float> targetCentre (targetArea.getCentre().toFloat()); | ||||
@@ -186,12 +188,12 @@ void CabbageCallOutBox::refreshPath() | |||||
background = Image::null; | background = Image::null; | ||||
outline.clear(); | 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: | public: | ||||
//============================================================================== | //============================================================================== | ||||
CabbageCallOutBox (Component& contentComponent, | CabbageCallOutBox (Component& contentComponent, | ||||
const Rectangle<int>& areaToPointTo, | |||||
Component* parentComponent); | |||||
const juce::Rectangle<int>& areaToPointTo, | |||||
Component* parentComponent); | |||||
~CabbageCallOutBox(); | ~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, | static CabbageCallOutBox& launchAsynchronously (Component* contentComponent, | ||||
const Rectangle<int>& areaToPointTo, | |||||
Component* parentComponent); | |||||
const juce::Rectangle<int>& areaToPointTo, | |||||
Component* parentComponent); | |||||
//============================================================================== | //============================================================================== | ||||
void paint (Graphics& g); | void paint (Graphics& g); | ||||
@@ -54,7 +54,7 @@ private: | |||||
Component& content; | Component& content; | ||||
Path outline; | Path outline; | ||||
Point<float> targetPoint; | Point<float> targetPoint; | ||||
Rectangle<int> availableArea, targetArea; | |||||
juce::Rectangle<int> availableArea, targetArea; | |||||
Image background; | Image background; | ||||
void refreshPath(); | void refreshPath(); | ||||
@@ -15,7 +15,7 @@ | |||||
License along with Csound; if not, write to the Free Software | License along with Csound; if not, write to the Free Software | ||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||||
02111-1307 USA | 02111-1307 USA | ||||
*/ | */ | ||||
#ifndef CABBPARSE_H | #ifndef CABBPARSE_H | ||||
#define CABBPARSE_H | #define CABBPARSE_H | ||||
@@ -32,273 +32,323 @@ | |||||
#include "CabbageUtils.h" | #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 | 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 | 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: | public: | ||||
//constructor | |||||
NamedValueSet cabbageIdentifiers; | |||||
CabbageGUIClass(String str, int ID); | |||||
CabbageGUIClass(){}; | |||||
//constructor | |||||
NamedValueSet cabbageIdentifiers; | |||||
CabbageGUIClass(String str, int ID); | |||||
CabbageGUIClass() {}; | |||||
~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 | class CabbageLookAndFeel : public LookAndFeel_V2 | ||||
{ | { | ||||
public: | 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, | 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 getTabButtonOverlap (int tabDepth); | ||||
int getTabButtonBestWidth (TabBarButton&, int tabDepth); | int getTabButtonBestWidth (TabBarButton&, int tabDepth); | ||||
Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp); | 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 fillTabButtonShape (TabBarButton&, Graphics& g, const Path& path, bool isMouseOver, bool isMouseDown); | ||||
void drawFileBrowserRow (Graphics& g, int width, int height, | 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); | 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: | 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 | class CabbageLookAndFeelBasic : public LookAndFeel_V2 | ||||
{ | { | ||||
public: | 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); | 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: | 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. | // 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. | // create aliases of each so that they can be moved around and resized. | ||||
// When a user disables the ComponentLayoutEditor this panel is again brought | // 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 | // 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 | // by toggling these two classes toFront() we can swap between edit and lock mode | ||||
CabbageMainPanel::CabbageMainPanel() : width(-99), top(-99), height(-99), left(-99) | 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() | CabbageMainPanel::~CabbageMainPanel() | ||||
{ | { | ||||
@@ -46,23 +46,23 @@ CabbageMainPanel::~CabbageMainPanel() | |||||
void CabbageMainPanel::paint(Graphics &g) | void CabbageMainPanel::paint(Graphics &g) | ||||
{ | { | ||||
} | } | ||||
ComponentLayoutEditor* CabbageMainPanel::getLayoutEditor() | ComponentLayoutEditor* CabbageMainPanel::getLayoutEditor() | ||||
{ | { | ||||
return layoutEditor; | |||||
return layoutEditor; | |||||
} | } | ||||
void CabbageMainPanel::setLayoutEditor(ComponentLayoutEditor* ed) | 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, | 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: | 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 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||||
02111-1307 USA | 02111-1307 USA | ||||
*/ | |||||
*/ | |||||
#ifndef CABBMESS_H | #ifndef CABBMESS_H | ||||
#define CABBMESS_H | |||||
#define CABBMESS_H | |||||
#include "CabbageUtils.h" | #include "CabbageUtils.h" | ||||
#ifndef Cabbage_No_Csound | #ifndef Cabbage_No_Csound | ||||
#include "csound.hpp" | |||||
#endif | |||||
#ifdef AndroidBuild | |||||
#include "AndroidCsound.hpp" | |||||
#else | |||||
#include <csound.hpp> | |||||
#endif | |||||
#endif | |||||
using namespace std; | using namespace std; | ||||
//simple channel message classe | //simple channel message classe | ||||
class CabbageChannelMessage : public CabbageUtils | class CabbageChannelMessage : public CabbageUtils | ||||
{ | { | ||||
public: | public: | ||||
String channelName; | |||||
String channelName; | |||||
#ifndef Cabbage_No_Csound | #ifndef Cabbage_No_Csound | ||||
MYFLT value; | |||||
MYFLT value; | |||||
#else | #else | ||||
float value; | |||||
float value; | |||||
#endif | #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 | class CabbageMessageQueue : public CabbageUtils | ||||
{ | { | ||||
Array<CabbageChannelMessage> outgoingChannelMessages; | |||||
Array<CabbageChannelMessage, CriticalSection> outgoingChannelMessages; | |||||
public: | 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 | #endif |
@@ -15,43 +15,47 @@ | |||||
License along with Csound; if not, write to the Free Software | License along with Csound; if not, write to the Free Software | ||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA | ||||
02111-1307 USA | 02111-1307 USA | ||||
*/ | */ | ||||
#include "CabbagePropertiesDialog.h" | #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. | //when a user clicks escape from a propery component this method is called. | ||||
//everytime this method is called we update the parameters | //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() | 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 "JuceHeader.h" | ||||
#include "CabbageUtils.h" | #include "CabbageUtils.h" | ||||
#include "./Plugin/CabbagePluginProcessor.h" | |||||
#define HANDLESIZE 8 | #define HANDLESIZE 8 | ||||
#define LINEAR 0 | #define LINEAR 0 | ||||
@@ -18,35 +19,35 @@ | |||||
==================================================================================== | ==================================================================================== | ||||
*/ | */ | ||||
class CabbageEnvelopeHandleComponent : public Component, | class CabbageEnvelopeHandleComponent : public Component, | ||||
public ChangeBroadcaster | |||||
public ChangeBroadcaster | |||||
{ | { | ||||
public: | 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: | 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 | class TableData | ||||
{ | { | ||||
public: | public: | ||||
Array<double, CriticalSection> amps, x, y; | |||||
Array<float, CriticalSection> amps, x, y; | |||||
}; | }; | ||||
class OverviewData | class OverviewData | ||||
{ | { | ||||
public: | public: | ||||
Array<double> minAmps, maxAmps, minY, maxY; | |||||
Array<double> minAmps, maxAmps, minY, maxY; | |||||
}; | }; | ||||
/* | /* | ||||
@@ -77,78 +78,79 @@ public: | |||||
==================================================================================== | ==================================================================================== | ||||
*/ | */ | ||||
class Table : public Component, | class Table : public Component, | ||||
public ChangeBroadcaster, | |||||
public ChangeListener | |||||
public ChangeBroadcaster, | |||||
public ChangeListener | |||||
{ | { | ||||
public: | 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: | 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 | class CabbageTableManager : public Component | ||||
{ | { | ||||
public: | 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: | 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 | class CabbageTableViewer : public Viewport | ||||
//public Component | |||||
//public Component | |||||
{ | { | ||||
public: | 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: | 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 | * ComponentLayoutEditor.h | ||||
* | |||||
* | |||||
* Original written by Haydxn | * Original written by Haydxn | ||||
* Modified by Jordan Hochenbaum on 10/25/10. | * Modified by Jordan Hochenbaum on 10/25/10. | ||||
* http://www.rawmaterialsoftware.com/viewtopic.php?f=6&t=2635 | * http://www.rawmaterialsoftware.com/viewtopic.php?f=6&t=2635 | ||||
@@ -23,125 +23,128 @@ extern ApplicationProperties* appProperties; | |||||
class SelectedComponents : public SelectedItemSet<ChildAlias*> | class SelectedComponents : public SelectedItemSet<ChildAlias*> | ||||
{ | { | ||||
public: | public: | ||||
void itemSelected (ChildAlias* item); | |||||
void itemDeselected (ChildAlias* item); | |||||
void itemSelected (ChildAlias* item); | |||||
void itemDeselected (ChildAlias* item); | |||||
}; | }; | ||||
//============================================================================= | //============================================================================= | ||||
class ComponentLayoutEditor : public Component, | 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, | 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_ | #endif//_COMPONENTLAYOUTEDITOR_H_ |
@@ -4,7 +4,7 @@ | |||||
Cabbage is free software; you can redistribute it | Cabbage is free software; you can redistribute it | ||||
and/or modify it under the terms of the GNU Lesser General Public | and/or modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | 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, | Cabbage is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
@@ -21,215 +21,227 @@ | |||||
//============================================================================== | //============================================================================== | ||||
DirectoryContentsComponent::DirectoryContentsComponent(String dir, String files): | 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("*.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(); | 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(0x1000501, Colours::green);//linesColourId | ||||
fileTreeComp->setColour(DirectoryContentsDisplayComponent::textColourId, Colours::white); | 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() | DirectoryContentsComponent::~DirectoryContentsComponent() | ||||
{ | { | ||||
thread.stopThread(10); | |||||
thread.stopThread(10); | |||||
} | } | ||||
//==================================================================================== | //==================================================================================== | ||||
void DirectoryContentsComponent::paint (Graphics& g) | 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() | 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 | //populate table rows with new strings and add new items to listable | ||||
void DirectoryContentsComponent::fileClicked (const File& file, const MouseEvent& e) | 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 | //button clicks | ||||
void DirectoryContentsComponent::buttonClicked(Button* button) | 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() | 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() | const StringArray DirectoryContentsComponent::getFunctionTables() | ||||
{ | { | ||||
StringArray tables; | |||||
StringArray tables; | |||||
//only retrieve the current selected bank | //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 | Cabbage is free software; you can redistribute it | ||||
and/or modify it under the terms of the GNU Lesser General Public | and/or modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | 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, | Cabbage is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | 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 | /* 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 */ | * for the functoin tables number, and a string displaying the file name */ | ||||
//============================================================================== | |||||
//============================================================================== | |||||
class listBoxItem : public Component | 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: | 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 | this class can send action messages to MainContentComponent whenever something | ||||
happens to one of its cells...*/ | happens to one of its cells...*/ | ||||
//============================================================================== | |||||
//============================================================================== | |||||
class FunctionTableList : public TableListBoxModel, | class FunctionTableList : public TableListBoxModel, | ||||
public ActionBroadcaster | |||||
public ActionBroadcaster | |||||
{ | { | ||||
public: | 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) | if (rowIsSelected) | ||||
g.fillAll (Colours::cornflowerblue); | 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; | 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: | private: | ||||
Font font; | 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, | 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<CabbageLookAndFeel> lookAndFeel; | ||||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | ||||
StretchableLayoutManager horizontalLayout; | |||||
ScopedPointer<Viewport> viewPort; | |||||
StretchableLayoutManager horizontalLayout; | |||||
ScopedPointer<Viewport> viewPort; | |||||
ScopedPointer<StretchableLayoutResizerBar> horizontalDividerBar; | 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: | public: | ||||
//============================================================================== | //============================================================================== | ||||
DirectoryContentsComponent(String dir, String files); | DirectoryContentsComponent(String dir, String files); | ||||
@@ -218,32 +232,34 @@ public: | |||||
bool isFileSuitable(const juce::File&) const | bool isFileSuitable(const juce::File&) const | ||||
{ | |||||
return true; | |||||
} | |||||
{ | |||||
return true; | |||||
} | |||||
bool isDirectorySuitable(const juce::File&) const | 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 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) | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryContentsComponent) | ||||
@@ -30,68 +30,399 @@ | |||||
extern ApplicationProperties* appProperties; | extern ApplicationProperties* appProperties; | ||||
extern CabbageTimer* cabbageTimer; | 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 | #endif |
@@ -22,523 +22,227 @@ | |||||
#include "CodeEditor.h" | #include "CodeEditor.h" | ||||
#include "KeyboardShortcuts.h" | #include "KeyboardShortcuts.h" | ||||
#include "SplitComponent.h" | |||||
#include "../Plugin/CabbagePluginProcessor.h" | #include "../Plugin/CabbagePluginProcessor.h" | ||||
//class LiveCsound; | //class LiveCsound; | ||||
class PythonEditor; | 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: | 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: | 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: | 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__ | #endif // __MAINCOMPONENT_H_615ECE56__ |
@@ -2,7 +2,7 @@ | |||||
//============================================================================== | //============================================================================== | ||||
CommandManager::CommandManager () : | CommandManager::CommandManager () : | ||||
ApplicationCommandManager () | |||||
ApplicationCommandManager () | |||||
{ | { | ||||
} | } | ||||
@@ -24,55 +24,58 @@ | |||||
//============================================================================== | //============================================================================== | ||||
namespace CommandIDs | 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 | 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: | public: | ||||
CommandManager (); | |||||
CommandManager (); | |||||
~CommandManager (); | ~CommandManager (); | ||||
juce_DeclareSingleton (CommandManager, true) | |||||
juce_DeclareSingleton (CommandManager, true) | |||||
}; | }; | ||||
@@ -11,45 +11,47 @@ | |||||
class ShortcutsPanel : public PropertyPanel | class ShortcutsPanel : public PropertyPanel | ||||
{ | { | ||||
public: | 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 | class PythonTokeniser : public CodeTokeniser | ||||
{ | { | ||||
public: | public: | ||||
PythonTokeniser(){} | |||||
~PythonTokeniser(){} | |||||
//============================================================================== | |||||
PythonTokeniser() {} | |||||
~PythonTokeniser() {} | |||||
//============================================================================== | |||||
enum TokenType | enum TokenType | ||||
{ | { | ||||
tokenType_error = 0, | tokenType_error = 0, | ||||
@@ -42,111 +42,111 @@ public: | |||||
tokenType_bracket, | tokenType_bracket, | ||||
tokenType_punctuation, | tokenType_punctuation, | ||||
tokenType_preprocessor, | 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: | 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 | void skipCSDTag (CodeDocument::Iterator& source) noexcept | ||||
{ | { | ||||
for (;;) | 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 | 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; | 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; | int i = 0; | ||||
@@ -232,8 +233,8 @@ private: | |||||
return false; | return false; | ||||
} | } | ||||
//============================================================================== | |||||
int parseIdentifier (CodeDocument::Iterator& source) noexcept | |||||
//============================================================================== | |||||
int parseIdentifier (CodeDocument::Iterator& source) noexcept | |||||
{ | { | ||||
int tokenLength = 0; | int tokenLength = 0; | ||||
String::CharPointerType::CharType possibleIdentifier [100]; | String::CharPointerType::CharType possibleIdentifier [100]; | ||||
@@ -260,50 +261,52 @@ private: | |||||
return CsoundTokeniser::tokenType_identifier; | 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(); | 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 | #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 "AppConfig.h" | ||||
#include "JucePluginCharacteristics.h" | #include "JucePluginCharacteristics.h" | ||||
#define UseNativeDialogue 0 | |||||
#include "modules/juce_audio_basics/juce_audio_basics.h" | #include "modules/juce_audio_basics/juce_audio_basics.h" | ||||
#include "modules/juce_audio_devices/juce_audio_devices.h" | #include "modules/juce_audio_devices/juce_audio_devices.h" | ||||
#include "modules/juce_audio_formats/juce_audio_formats.h" | #include "modules/juce_audio_formats/juce_audio_formats.h" | ||||
@@ -59,10 +59,10 @@ | |||||
#endif | #endif | ||||
#define JucePlugin_SilenceInProducesSilenceOut 1 | #define JucePlugin_SilenceInProducesSilenceOut 1 | ||||
#define JucePlugin_TailLengthSeconds 0 | |||||
#define JucePlugin_TailLengthSeconds 0 | |||||
#define JucePlugin_EditorRequiresKeyboardFocus 1 | #define JucePlugin_EditorRequiresKeyboardFocus 1 | ||||
#define JucePlugin_VersionCode 0x10000 | #define JucePlugin_VersionCode 0x10000 | ||||
#define JucePlugin_VersionString "0.0.0" | |||||
#define JucePlugin_VersionString "1.0.0" | |||||
#define JucePlugin_VSTUniqueID JucePlugin_PluginCode | #define JucePlugin_VSTUniqueID JucePlugin_PluginCode | ||||
#define JucePlugin_VSTCategory kPlugCategEffect | #define JucePlugin_VSTCategory kPlugCategEffect | ||||
#define JucePlugin_AUSubType JucePlugin_PluginCode | #define JucePlugin_AUSubType JucePlugin_PluginCode | ||||
@@ -4,7 +4,7 @@ | |||||
Cabbage is free software; you can redistribute it | Cabbage is free software; you can redistribute it | ||||
and/or modify it under the terms of the GNU Lesser General Public | and/or modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | 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, | Cabbage is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
@@ -29,35 +29,35 @@ | |||||
#include "../CabbageLookAndFeel.h" | #include "../CabbageLookAndFeel.h" | ||||
class ProcessorParameterPropertyComp : public PropertyComponent, | class ProcessorParameterPropertyComp : public PropertyComponent, | ||||
public AudioProcessorListener, | |||||
public Timer | |||||
public AudioProcessorListener, | |||||
public Timer | |||||
{ | { | ||||
//============================================================================== | |||||
//============================================================================== | |||||
class ParamSlider : public Slider, | class ParamSlider : public Slider, | ||||
public ActionBroadcaster | |||||
// public ActionListener | |||||
public ActionBroadcaster | |||||
// public ActionListener | |||||
{ | { | ||||
public: | public: | ||||
ParamSlider (AudioProcessor& owner_, const int index_) | ParamSlider (AudioProcessor& owner_, const int index_) | ||||
: owner (owner_), | : owner (owner_), | ||||
index (index_) | 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); | 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); | setTextBoxIsEditable (false); | ||||
setScrollWheelEnabled (false); | setScrollWheelEnabled (false); | ||||
} | } | ||||
void valueChanged() | 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(); | const float newVal = (float) getValue(); | ||||
if (owner.getParameter (index) != newVal) | if (owner.getParameter (index) != newVal) | ||||
@@ -75,15 +75,15 @@ class ProcessorParameterPropertyComp : public PropertyComponent, | |||||
//============================================================================== | //============================================================================== | ||||
AudioProcessor& owner; | AudioProcessor& owner; | ||||
const int index; | const int index; | ||||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamSlider); | JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ParamSlider); | ||||
}; | }; | ||||
public: | public: | ||||
ParamSlider slider; | |||||
Colour highlightColour; | |||||
bool moddedText; | |||||
ParamSlider slider; | |||||
Colour highlightColour; | |||||
bool moddedText; | |||||
ProcessorParameterPropertyComp (const String& name, AudioProcessor& owner_, const int index_) | ProcessorParameterPropertyComp (const String& name, AudioProcessor& owner_, const int index_) | ||||
: PropertyComponent (name), | : PropertyComponent (name), | ||||
@@ -92,12 +92,12 @@ public: | |||||
paramHasChanged (false), | paramHasChanged (false), | ||||
slider (owner_, index_) | slider (owner_, index_) | ||||
{ | { | ||||
moddedText = false; | |||||
setPreferredHeight(20); | |||||
startTimer (100); | |||||
moddedText = false; | |||||
setPreferredHeight(20); | |||||
startTimer (100); | |||||
addAndMakeVisible (&slider); | addAndMakeVisible (&slider); | ||||
owner_.addListener (this); | owner_.addListener (this); | ||||
highlightColour = CabbageUtils::getDarkerBackgroundSkin(); | |||||
highlightColour = CabbageUtils::getDarkerBackgroundSkin(); | |||||
} | } | ||||
~ProcessorParameterPropertyComp() | ~ProcessorParameterPropertyComp() | ||||
@@ -107,7 +107,7 @@ public: | |||||
void refresh() | void refresh() | ||||
{ | { | ||||
paramHasChanged = false; | |||||
paramHasChanged = false; | |||||
slider.setValue (owner.getParameter (index), sendNotification); | 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: | private: | ||||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||||
ScopedPointer<CabbageLookAndFeelBasic> basicLookAndFeel; | |||||
AudioProcessor& owner; | AudioProcessor& owner; | ||||
const int index; | const int index; | ||||
bool volatile paramHasChanged; | bool volatile paramHasChanged; | ||||
@@ -170,58 +170,58 @@ class CabbageGenericAudioProcessorEditor : public AudioProcessorEditor | |||||
public: | 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: | private: | ||||
//============================================================================== | //============================================================================== | ||||
PropertyPanel panel; | PropertyPanel panel; | ||||
@@ -4,7 +4,7 @@ | |||||
Cabbage is free software; you can redistribute it | Cabbage is free software; you can redistribute it | ||||
and/or modify it under the terms of the GNU Lesser General Public | and/or modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | 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, | Cabbage is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
@@ -23,7 +23,6 @@ | |||||
#include "../CabbageCustomWidgets.h" | #include "../CabbageCustomWidgets.h" | ||||
#include "../JuceHeader.h" | #include "../JuceHeader.h" | ||||
#include "CabbagePluginProcessor.h" | #include "CabbagePluginProcessor.h" | ||||
//#include "../CabbageLookAndFeel.h" | |||||
#include "../CabbagePropertiesDialog.h" | #include "../CabbagePropertiesDialog.h" | ||||
#include "../CabbageUtils.h" | #include "../CabbageUtils.h" | ||||
@@ -34,49 +33,88 @@ class CabbageMainPanel; | |||||
class ComponentLayoutEditor; | class ComponentLayoutEditor; | ||||
class CabbageCornerResizer; | class CabbageCornerResizer; | ||||
//============================================================================== | //============================================================================== | ||||
// window used to display popup plants | |||||
//============================================================================== | |||||
class CabbagePlantWindow : public DocumentWindow | class CabbagePlantWindow : public DocumentWindow | ||||
{ | { | ||||
public: | 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); | 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 | // pointData class for holding info about each segment of a line | ||||
class PointData | |||||
//============================================================================== | |||||
class PointData | |||||
{ | { | ||||
public: | 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 | // main GUI editor window | ||||
//============================================================================== | //============================================================================== | ||||
class CabbagePluginAudioProcessorEditor : public AudioProcessorEditor, | 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: | public: | ||||
CabbagePluginAudioProcessorEditor (CabbagePluginAudioProcessor* ownerFilter); | CabbagePluginAudioProcessorEditor (CabbagePluginAudioProcessor* ownerFilter); | ||||
@@ -84,124 +122,134 @@ public: | |||||
void paint (Graphics& g); | void paint (Graphics& g); | ||||
void resized(); | 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: | 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 | #ifdef Cabbage_GUI_Editor | ||||
ScopedPointer<CabbageMainPanel> componentPanel; | |||||
ScopedPointer<ComponentLayoutEditor> layoutEditor; | |||||
ScopedPointer<CabbageMainPanel> componentPanel; | |||||
ScopedPointer<ComponentLayoutEditor> layoutEditor; | |||||
#else | #else | ||||
ScopedPointer<Component> componentPanel; | |||||
ScopedPointer<Component> componentPanel; | |||||
#endif | #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 | class CabbageCornerResizer : public ResizableCornerComponent | ||||
{ | { | ||||
CabbagePluginAudioProcessorEditor* editor; | |||||
CabbagePluginAudioProcessorEditor* editor; | |||||
public: | 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__ | #endif // __PLUGINEDITOR_H_F4EBBBA1__ | ||||
@@ -27,12 +27,18 @@ | |||||
#include "../XYPadAutomation.h" | #include "../XYPadAutomation.h" | ||||
#include "../CabbageMessageSystem.h" | #include "../CabbageMessageSystem.h" | ||||
#include "../Soundfiler.h" | #include "../Soundfiler.h" | ||||
#include "CabbageGenericAudioProcessorEditor.h" | |||||
#include "CabbageGenericAudioProcessorEditor.h" | |||||
#include "../CabbageLookAndFeel.h" | #include "../CabbageLookAndFeel.h" | ||||
#ifndef Cabbage_No_Csound | #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" | #include "../csPerfThread.hpp" | ||||
#endif | #endif | ||||
@@ -40,7 +46,11 @@ | |||||
//#include "../Editor/CabbageEditorWindow.h" | //#include "../Editor/CabbageEditorWindow.h" | ||||
//#endif | //#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 AUDIO_PLUGIN 1 | ||||
#define EXTERNAL_PLUGIN 2 | #define EXTERNAL_PLUGIN 2 | ||||
@@ -50,135 +60,179 @@ | |||||
class CsoundCodeEditor; | class CsoundCodeEditor; | ||||
#endif | #endif | ||||
extern CabbageLookAndFeel* lookAndFeel; | |||||
extern CabbageLookAndFeelBasic* lookAndFeelBasic; | |||||
#if defined(BUILD_DEBUGGER) && !defined(Cabbage_No_Csound) | |||||
#include <csdebug.h> | |||||
#endif | |||||
//============================================================================== | //============================================================================== | ||||
// CabbagePluginAudioProcessor definition | // CabbagePluginAudioProcessor definition | ||||
//============================================================================== | //============================================================================== | ||||
class CabbagePluginAudioProcessor : public AudioProcessor, | 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 | #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 | #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) | #if defined(Cabbage_Build_Standalone) || (Cabbage_Plugin_Host) | ||||
CabbagePluginAudioProcessor(String inputfile, bool guiOnOff, int pluginType); | CabbagePluginAudioProcessor(String inputfile, bool guiOnOff, int pluginType); | ||||
#else | #else | ||||
CabbagePluginAudioProcessor(); | |||||
CabbagePluginAudioProcessor(); | |||||
#endif | #endif | ||||
~CabbagePluginAudioProcessor(); | ~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 prepareToPlay (double sampleRate, int samplesPerBlock); | ||||
void releaseResources(); | void releaseResources(); | ||||
@@ -199,16 +253,13 @@ public: | |||||
bool isOutputChannelStereoPair (int index) const; | bool isOutputChannelStereoPair (int index) const; | ||||
bool acceptsMidi() const; | bool acceptsMidi() const; | ||||
bool producesMidi() 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 getNumPrograms(); | ||||
int getCurrentProgram(); | int getCurrentProgram(); | ||||
@@ -218,265 +269,318 @@ public: | |||||
//============================================================================== | //============================================================================== | ||||
void getStateInformation (MemoryBlock& destData); | void getStateInformation (MemoryBlock& destData); | ||||
void setStateInformation (const void* data, int sizeInBytes); | 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 | #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 | #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 | #ifdef Cabbage_Host | ||||
class CabbagePluginAutomationProcessor : public CabbagePluginAudioProcessor | class CabbagePluginAutomationProcessor : public CabbagePluginAudioProcessor | ||||
{ | { | ||||
public: | 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 | Cabbage is free software; you can redistribute it | ||||
and/or modify it under the terms of the GNU Lesser General Public | and/or modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | 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, | Cabbage is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
@@ -19,144 +19,303 @@ | |||||
#include "Soundfiler.h" | #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 | Cabbage is free software; you can redistribute it | ||||
and/or modify it under the terms of the GNU Lesser General Public | and/or modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | 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, | Cabbage is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
@@ -20,198 +20,93 @@ | |||||
#ifndef SOUNDFILEWAVEFORM_H | #ifndef SOUNDFILEWAVEFORM_H | ||||
#define SOUNDFILEWAVEFORM_H | #define SOUNDFILEWAVEFORM_H | ||||
#include "JuceHeader.h" | |||||
#include "JuceHeader.h" | |||||
#include "CabbageUtils.h" | #include "CabbageUtils.h" | ||||
#include "CabbageLookAndFeel.h" | #include "CabbageLookAndFeel.h" | ||||
class ZoomButton; | |||||
//================================================================= | //================================================================= | ||||
// display a sound file as a waveform.. | // 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: | 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 | 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 | 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 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 | #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 | Cabbage is free software; you can redistribute it | ||||
and/or modify it under the terms of the GNU Lesser General Public | and/or modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | 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, | Cabbage is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
@@ -35,25 +35,25 @@ | |||||
class XYHandleComponent : public Component | class XYHandleComponent : public Component | ||||
{ | { | ||||
public: | 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: | private: | ||||
ComponentDragger dragger; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYHandleComponent); | |||||
ComponentDragger dragger; | |||||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XYHandleComponent); | |||||
}; | }; | ||||
/* | /* | ||||
============================================================================ | ============================================================================ | ||||
XYImages | XYImages | ||||
------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ||||
Returns custom images for toggle buttons. | Returns custom images for toggle buttons. | ||||
@@ -63,38 +63,40 @@ private: | |||||
class XYImages | class XYImages | ||||
{ | { | ||||
public: | 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 | XYToggle | ||||
------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ||||
Custom toggle button. | Custom toggle button. | ||||
@@ -113,17 +115,17 @@ public: | |||||
class XYToggle : public ToggleButton | class XYToggle : public ToggleButton | ||||
{ | { | ||||
public: | 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: | 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 | class XYValueDisplay : public Component | ||||
{ | { | ||||
public: | 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: | 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 | class XYCanvasBackground : public Component | ||||
{ | { | ||||
public: | public: | ||||
XYCanvasBackground(); | |||||
~XYCanvasBackground(); | |||||
void resized(); | |||||
void paint(Graphics& g); | |||||
XYCanvasBackground(); | |||||
~XYCanvasBackground(); | |||||
void resized(); | |||||
void paint(Graphics& g); | |||||
private: | 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, | class XYCanvas : public Component, | ||||
public MultiTimer | |||||
public MultiTimer | |||||
{ | { | ||||
public: | 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: | 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 | XYPad | ||||
---------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | ||||
This is the main parent class!! | This is the main parent class!! | ||||
============================================================================ | ============================================================================ | ||||
*/ | */ | ||||
class XYPad : public Component, | class XYPad : public Component, | ||||
public SliderListener, | |||||
public ButtonListener, | |||||
public ActionBroadcaster | |||||
public SliderListener, | |||||
public ButtonListener, | |||||
public ActionBroadcaster | |||||
{ | { | ||||
public: | 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: | 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" | #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() | XYPadAutomation::~XYPadAutomation() | ||||
@@ -20,219 +20,229 @@ XYPadAutomation::~XYPadAutomation() | |||||
void XYPadAutomation::updateCreationCounter() | void XYPadAutomation::updateCreationCounter() | ||||
{ | { | ||||
creationCounter++; | |||||
creationCounter++; | |||||
} | } | ||||
int XYPadAutomation::getCreationCounter() | int XYPadAutomation::getCreationCounter() | ||||
{ | { | ||||
return creationCounter; | |||||
return creationCounter; | |||||
} | } | ||||
void XYPadAutomation::setBallSize (float size) | void XYPadAutomation::setBallSize (float size) | ||||
{ | { | ||||
ballSize = size; | |||||
ballSize = size; | |||||
} | } | ||||
void XYPadAutomation::setBoundsForAutomation(Rectangle<int> bounds) | 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) | 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() | bool XYPadAutomation::isAutomating() | ||||
{ | { | ||||
return isAutomationOn; | |||||
return isAutomationOn; | |||||
} | } | ||||
void XYPadAutomation::setMinMaxValues (float xMinimum, float xMaximum, float yMinimum, float yMaximum) | 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() | float XYPadAutomation::getMinimumXValue() | ||||
{ | { | ||||
return xMin; | |||||
return xMin; | |||||
} | } | ||||
float XYPadAutomation::getMinimumYValue() | float XYPadAutomation::getMinimumYValue() | ||||
{ | { | ||||
return yMin; | |||||
return yMin; | |||||
} | } | ||||
void XYPadAutomation::cancelAutomation() | void XYPadAutomation::cancelAutomation() | ||||
{ | { | ||||
stopTimer(); | |||||
isAutomationOn = false; | |||||
xValueIncrement = yValueIncrement = 0; | |||||
stopTimer(); | |||||
isAutomationOn = false; | |||||
xValueIncrement = yValueIncrement = 0; | |||||
} | } | ||||
void XYPadAutomation::setInitialSpeedSliderValue () | 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() | void XYPadAutomation::updateIncrements() | ||||
{ | { | ||||
xValueIncrement *= speedValue; | |||||
yValueIncrement *= speedValue; | |||||
xValueIncrement *= speedValue; | |||||
yValueIncrement *= speedValue; | |||||
} | } | ||||
void XYPadAutomation::setSpeedSliderValue(float sliderValue) | void XYPadAutomation::setSpeedSliderValue(float sliderValue) | ||||
{ | { | ||||
speedSliderValue = sliderValue; | |||||
updateCounter = 0; //reset our counter | |||||
speedSliderValue = sliderValue; | |||||
updateCounter = 0; //reset our counter | |||||
} | } | ||||
void XYPadAutomation::beginAutomation(int selectedToggleButton) | 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() | 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() | void XYPadAutomation::timerCallback() | ||||
{ | { | ||||
sendChangeMessage(); | |||||
sendChangeMessage(); | |||||
} | } | ||||
Point<float> XYPadAutomation::getStartHandle() | 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> 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() | float XYPadAutomation::getXValue() | ||||
{ | { | ||||
return xValue; | |||||
return xValue; | |||||
} | } | ||||
float XYPadAutomation::getYValue() | float XYPadAutomation::getYValue() | ||||
{ | { | ||||
return yValue; | |||||
return yValue; | |||||
} | } | ||||
float XYPadAutomation::getNormalisedXValue() | float XYPadAutomation::getNormalisedXValue() | ||||
{ | { | ||||
return (xValue-xMin)/xRange; | |||||
return (xValue-xMin)/xRange; | |||||
} | } | ||||
float XYPadAutomation::getNormalisedYValue() | float XYPadAutomation::getNormalisedYValue() | ||||
{ | { | ||||
return (yValue-yMin)/yRange; | |||||
return (yValue-yMin)/yRange; | |||||
} | } | ||||
void XYPadAutomation::setXValue(float value) | void XYPadAutomation::setXValue(float value) | ||||
{ | { | ||||
xValue = value; | |||||
sendChangeMessage(); | |||||
xValue = value; | |||||
sendChangeMessage(); | |||||
} | } | ||||
void XYPadAutomation::setYValue(float value) | void XYPadAutomation::setYValue(float value) | ||||
{ | { | ||||
yValue = value; | |||||
sendChangeMessage(); | |||||
yValue = value; | |||||
sendChangeMessage(); | |||||
} | } | ||||
int XYPadAutomation::getSelectedToggle() | int XYPadAutomation::getSelectedToggle() | ||||
{ | { | ||||
return selectedToggle; | |||||
return selectedToggle; | |||||
} | } | ||||
float XYPadAutomation::getSpeedSliderValue() | float XYPadAutomation::getSpeedSliderValue() | ||||
{ | { | ||||
return speedSliderValue; | |||||
return speedSliderValue; | |||||
} | } |
@@ -4,7 +4,7 @@ | |||||
Cabbage is free software; you can redistribute it | Cabbage is free software; you can redistribute it | ||||
and/or modify it under the terms of the GNU Lesser General Public | and/or modify it under the terms of the GNU Lesser General Public | ||||
License as published by the Free Software Foundation; either | 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, | Cabbage is distributed in the hope that it will be useful, | ||||
but WITHOUT ANY WARRANTY; without even the implied warranty of | 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 | // XYPad Automation class. Allows plugin editor to close while maintining automation | ||||
//============================================================================== | //============================================================================== | ||||
class XYPadAutomation : public Timer, | class XYPadAutomation : public Timer, | ||||
public ChangeBroadcaster | |||||
public ChangeBroadcaster | |||||
{ | { | ||||
public: | 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: | 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. | * Base class for event messages. | ||||
*/ | */ | ||||
class CsoundPerformanceThreadMessage { | |||||
protected: | |||||
class CsoundPerformanceThreadMessage | |||||
{ | |||||
protected: | |||||
CsoundPerformanceThread *pt_; | CsoundPerformanceThread *pt_; | ||||
void SetPaused(int state) | void SetPaused(int state) | ||||
{ | { | ||||
pt_->paused = state; | |||||
pt_->paused = state; | |||||
} | } | ||||
int GetPaused() | int GetPaused() | ||||
{ | { | ||||
return pt_->paused; | |||||
return pt_->paused; | |||||
} | } | ||||
public: | |||||
public: | |||||
CsoundPerformanceThreadMessage *nxt; | CsoundPerformanceThreadMessage *nxt; | ||||
virtual int run() = 0; | virtual int run() = 0; | ||||
CsoundPerformanceThreadMessage(CsoundPerformanceThread *pt) | CsoundPerformanceThreadMessage(CsoundPerformanceThread *pt) | ||||
{ | { | ||||
pt_ = pt; | |||||
nxt = (CsoundPerformanceThreadMessage*) 0; | |||||
pt_ = pt; | |||||
nxt = (CsoundPerformanceThreadMessage*) 0; | |||||
} | } | ||||
virtual ~CsoundPerformanceThreadMessage() | virtual ~CsoundPerformanceThreadMessage() | ||||
{ | { | ||||
@@ -62,16 +63,17 @@ class CsoundPerformanceThreadMessage { | |||||
* Unpause performance | * Unpause performance | ||||
*/ | */ | ||||
class CsPerfThreadMsg_Play : public CsoundPerformanceThreadMessage { | |||||
public: | |||||
class CsPerfThreadMsg_Play : public CsoundPerformanceThreadMessage | |||||
{ | |||||
public: | |||||
CsPerfThreadMsg_Play(CsoundPerformanceThread *pt) | CsPerfThreadMsg_Play(CsoundPerformanceThread *pt) | ||||
: CsoundPerformanceThreadMessage(pt) | |||||
: CsoundPerformanceThreadMessage(pt) | |||||
{ | { | ||||
} | } | ||||
int run() | int run() | ||||
{ | { | ||||
SetPaused(0); | |||||
return 0; | |||||
SetPaused(0); | |||||
return 0; | |||||
} | } | ||||
~CsPerfThreadMsg_Play() | ~CsPerfThreadMsg_Play() | ||||
{ | { | ||||
@@ -82,16 +84,17 @@ class CsPerfThreadMsg_Play : public CsoundPerformanceThreadMessage { | |||||
* Pause performance | * Pause performance | ||||
*/ | */ | ||||
class CsPerfThreadMsg_Pause : public CsoundPerformanceThreadMessage { | |||||
public: | |||||
class CsPerfThreadMsg_Pause : public CsoundPerformanceThreadMessage | |||||
{ | |||||
public: | |||||
CsPerfThreadMsg_Pause(CsoundPerformanceThread *pt) | CsPerfThreadMsg_Pause(CsoundPerformanceThread *pt) | ||||
: CsoundPerformanceThreadMessage(pt) | |||||
: CsoundPerformanceThreadMessage(pt) | |||||
{ | { | ||||
} | } | ||||
int run() | int run() | ||||
{ | { | ||||
SetPaused(1); | |||||
return 0; | |||||
SetPaused(1); | |||||
return 0; | |||||
} | } | ||||
~CsPerfThreadMsg_Pause() | ~CsPerfThreadMsg_Pause() | ||||
{ | { | ||||
@@ -102,16 +105,17 @@ class CsPerfThreadMsg_Pause : public CsoundPerformanceThreadMessage { | |||||
* Toggle pause mode | * Toggle pause mode | ||||
*/ | */ | ||||
class CsPerfThreadMsg_TogglePause : public CsoundPerformanceThreadMessage { | |||||
public: | |||||
class CsPerfThreadMsg_TogglePause : public CsoundPerformanceThreadMessage | |||||
{ | |||||
public: | |||||
CsPerfThreadMsg_TogglePause(CsoundPerformanceThread *pt) | CsPerfThreadMsg_TogglePause(CsoundPerformanceThread *pt) | ||||
: CsoundPerformanceThreadMessage(pt) | |||||
: CsoundPerformanceThreadMessage(pt) | |||||
{ | { | ||||
} | } | ||||
int run() | int run() | ||||
{ | { | ||||
SetPaused(GetPaused() ? 0 : 1); | |||||
return 0; | |||||
SetPaused(GetPaused() ? 0 : 1); | |||||
return 0; | |||||
} | } | ||||
~CsPerfThreadMsg_TogglePause() | ~CsPerfThreadMsg_TogglePause() | ||||
{ | { | ||||
@@ -122,15 +126,16 @@ class CsPerfThreadMsg_TogglePause : public CsoundPerformanceThreadMessage { | |||||
* Stop performance (cannot be continued) | * Stop performance (cannot be continued) | ||||
*/ | */ | ||||
class CsPerfThreadMsg_Stop : public CsoundPerformanceThreadMessage { | |||||
public: | |||||
class CsPerfThreadMsg_Stop : public CsoundPerformanceThreadMessage | |||||
{ | |||||
public: | |||||
CsPerfThreadMsg_Stop(CsoundPerformanceThread *pt) | CsPerfThreadMsg_Stop(CsoundPerformanceThread *pt) | ||||
: CsoundPerformanceThreadMessage(pt) | |||||
: CsoundPerformanceThreadMessage(pt) | |||||
{ | { | ||||
} | } | ||||
int run() | int run() | ||||
{ | { | ||||
return 1; | |||||
return 1; | |||||
} | } | ||||
~CsPerfThreadMsg_Stop() | ~CsPerfThreadMsg_Stop() | ||||
{ | { | ||||
@@ -147,54 +152,58 @@ class CsPerfThreadMsg_Stop : public CsoundPerformanceThreadMessage { | |||||
* *p: array of p-fields, p[0] is p1 | * *p: array of p-fields, p[0] is p1 | ||||
*/ | */ | ||||
class CsPerfThreadMsg_ScoreEvent : public CsoundPerformanceThreadMessage { | |||||
private: | |||||
class CsPerfThreadMsg_ScoreEvent : public CsoundPerformanceThreadMessage | |||||
{ | |||||
private: | |||||
char opcod; | char opcod; | ||||
int absp2mode; | int absp2mode; | ||||
int pcnt; | int pcnt; | ||||
MYFLT *pp; | MYFLT *pp; | ||||
MYFLT p[10]; | MYFLT p[10]; | ||||
public: | |||||
public: | |||||
CsPerfThreadMsg_ScoreEvent(CsoundPerformanceThread *pt, | CsPerfThreadMsg_ScoreEvent(CsoundPerformanceThread *pt, | ||||
int absp2mode, char opcod, | int absp2mode, char opcod, | ||||
int pcnt, const MYFLT *p) | 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() | 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() | ~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 | * Score event message as a string | ||||
*/ | */ | ||||
class CsPerfThreadMsg_InputMessage : public CsoundPerformanceThreadMessage { | |||||
private: | |||||
class CsPerfThreadMsg_InputMessage : public CsoundPerformanceThreadMessage | |||||
{ | |||||
private: | |||||
int len; | int len; | ||||
char *sp; | char *sp; | ||||
char s[128]; | char s[128]; | ||||
public: | |||||
public: | |||||
CsPerfThreadMsg_InputMessage(CsoundPerformanceThread *pt, const char *s) | 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() | int run() | ||||
{ | { | ||||
csoundInputMessage(pt_->GetCsound(), sp); | |||||
return 0; | |||||
csoundInputMessage(pt_->GetCsound(), sp); | |||||
return 0; | |||||
} | } | ||||
~CsPerfThreadMsg_InputMessage() | ~CsPerfThreadMsg_InputMessage() | ||||
{ | { | ||||
if (len >= 128) | |||||
delete[] sp; | |||||
if (len >= 128) | |||||
delete[] sp; | |||||
} | } | ||||
}; | }; | ||||
@@ -235,20 +245,21 @@ class CsPerfThreadMsg_InputMessage : public CsoundPerformanceThreadMessage { | |||||
*/ | */ | ||||
class CsPerfThreadMsg_SetScoreOffsetSeconds | class CsPerfThreadMsg_SetScoreOffsetSeconds | ||||
: public CsoundPerformanceThreadMessage { | |||||
private: | |||||
: public CsoundPerformanceThreadMessage | |||||
{ | |||||
private: | |||||
double timeVal; | double timeVal; | ||||
public: | |||||
public: | |||||
CsPerfThreadMsg_SetScoreOffsetSeconds(CsoundPerformanceThread *pt, | CsPerfThreadMsg_SetScoreOffsetSeconds(CsoundPerformanceThread *pt, | ||||
double timeVal) | double timeVal) | ||||
: CsoundPerformanceThreadMessage(pt) | |||||
: CsoundPerformanceThreadMessage(pt) | |||||
{ | { | ||||
this->timeVal = timeVal; | |||||
this->timeVal = timeVal; | |||||
} | } | ||||
int run() | int run() | ||||
{ | { | ||||
csoundSetScoreOffsetSeconds(pt_->GetCsound(), (MYFLT) timeVal); | |||||
return 0; | |||||
csoundSetScoreOffsetSeconds(pt_->GetCsound(), (MYFLT) timeVal); | |||||
return 0; | |||||
} | } | ||||
~CsPerfThreadMsg_SetScoreOffsetSeconds() | ~CsPerfThreadMsg_SetScoreOffsetSeconds() | ||||
{ | { | ||||
@@ -265,56 +276,62 @@ class CsPerfThreadMsg_SetScoreOffsetSeconds | |||||
int CsoundPerformanceThread::Perform() | int CsoundPerformanceThread::Perform() | ||||
{ | { | ||||
int retval = 0; | 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; | status = retval; | ||||
csoundCleanup(csound); | csoundCleanup(csound); | ||||
// delete any pending messages | // delete any pending messages | ||||
csoundLockMutex(queueLock); | 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); | csoundNotifyThreadLock(flushLock); | ||||
csoundUnlockMutex(queueLock); | csoundUnlockMutex(queueLock); | ||||
@@ -322,17 +339,18 @@ int CsoundPerformanceThread::Perform() | |||||
return retval; | return retval; | ||||
} | } | ||||
class CsPerfThread_PerformScore { | |||||
private: | |||||
class CsPerfThread_PerformScore | |||||
{ | |||||
private: | |||||
CsoundPerformanceThread *pt; | CsoundPerformanceThread *pt; | ||||
public: | |||||
public: | |||||
int Perform() | int Perform() | ||||
{ | { | ||||
return pt->Perform(); | |||||
return pt->Perform(); | |||||
} | } | ||||
CsPerfThread_PerformScore(void *p) | CsPerfThread_PerformScore(void *p) | ||||
{ | { | ||||
pt = (CsoundPerformanceThread*) p; | |||||
pt = (CsoundPerformanceThread*) p; | |||||
} | } | ||||
~CsPerfThread_PerformScore() | ~CsPerfThread_PerformScore() | ||||
{ | { | ||||
@@ -340,14 +358,14 @@ class CsPerfThread_PerformScore { | |||||
}; | }; | ||||
extern "C" { | 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) | void CsoundPerformanceThread::csPerfThread_constructor(CSOUND *csound) | ||||
@@ -363,25 +381,27 @@ void CsoundPerformanceThread::csPerfThread_constructor(CSOUND *csound) | |||||
status = CSOUND_MEMORY; | status = CSOUND_MEMORY; | ||||
queueLock = csoundCreateMutex(0); | queueLock = csoundCreateMutex(0); | ||||
if (!queueLock) | if (!queueLock) | ||||
return; | |||||
return; | |||||
pauseLock = csoundCreateThreadLock(); | pauseLock = csoundCreateThreadLock(); | ||||
if (!pauseLock) | if (!pauseLock) | ||||
return; | |||||
return; | |||||
flushLock = csoundCreateThreadLock(); | flushLock = csoundCreateThreadLock(); | ||||
if (!flushLock) | 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; | processcallback = NULL; | ||||
running = 0; | running = 0; | ||||
firstMessage = lastMessage; | firstMessage = lastMessage; | ||||
perfThread = csoundCreateThread(csoundPerformanceThread_, (void*) this); | perfThread = csoundCreateThread(csoundPerformanceThread_, (void*) this); | ||||
if (perfThread) | if (perfThread) | ||||
status = 0; | |||||
status = 0; | |||||
} | } | ||||
// ---------------------------------------------------------------------------- | // ---------------------------------------------------------------------------- | ||||
@@ -414,7 +434,7 @@ CsoundPerformanceThread::~CsoundPerformanceThread() | |||||
{ | { | ||||
// stop performance if it is still running | // stop performance if it is still running | ||||
if (!status) | if (!status) | ||||
this->Stop(); // FIXME: should handle memory errors here | |||||
this->Stop(); // FIXME: should handle memory errors here | |||||
this->Join(); | this->Join(); | ||||
} | } | ||||
@@ -426,16 +446,17 @@ CsoundPerformanceThread::~CsoundPerformanceThread() | |||||
void CsoundPerformanceThread::QueueMessage(CsoundPerformanceThreadMessage *msg) | void CsoundPerformanceThread::QueueMessage(CsoundPerformanceThreadMessage *msg) | ||||
{ | { | ||||
if (status) { | |||||
delete msg; | |||||
return; | |||||
if (status) | |||||
{ | |||||
delete msg; | |||||
return; | |||||
} | } | ||||
csoundLockMutex(queueLock); | csoundLockMutex(queueLock); | ||||
// link message into FIFO | // link message into FIFO | ||||
if (!lastMessage) | if (!lastMessage) | ||||
firstMessage = msg; | |||||
firstMessage = msg; | |||||
else | else | ||||
lastMessage->nxt = msg; | |||||
lastMessage->nxt = msg; | |||||
lastMessage = msg; | lastMessage = msg; | ||||
// mark queue as non-empty | // mark queue as non-empty | ||||
csoundWaitThreadLock(flushLock, (size_t) 0); | csoundWaitThreadLock(flushLock, (size_t) 0); | ||||
@@ -489,10 +510,10 @@ void CsoundPerformanceThread::Stop() | |||||
*/ | */ | ||||
void CsoundPerformanceThread::ScoreEvent(int absp2mode, char opcod, | void CsoundPerformanceThread::ScoreEvent(int absp2mode, char opcod, | ||||
int pcnt, const MYFLT *p) | |||||
int pcnt, const MYFLT *p) | |||||
{ | { | ||||
QueueMessage(new CsPerfThreadMsg_ScoreEvent(this, | QueueMessage(new CsPerfThreadMsg_ScoreEvent(this, | ||||
absp2mode, opcod, pcnt, p)); | |||||
absp2mode, opcod, pcnt, p)); | |||||
} | } | ||||
/** | /** | ||||
@@ -527,37 +548,42 @@ int CsoundPerformanceThread::Join() | |||||
int retval; | int retval; | ||||
retval = status; | retval = status; | ||||
if (perfThread) { | |||||
retval = csoundJoinThread(perfThread); | |||||
perfThread = (void*) 0; | |||||
if (perfThread) | |||||
{ | |||||
retval = csoundJoinThread(perfThread); | |||||
perfThread = (void*) 0; | |||||
} | } | ||||
// delete any pending messages | // 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 | // 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; | return retval; | ||||
@@ -570,9 +596,10 @@ int CsoundPerformanceThread::Join() | |||||
void CsoundPerformanceThread::FlushMessageQueue() | 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 | #ifdef SWIGPYTHON | ||||
struct PUBLIC pycallbackdata { | |||||
PyObject *func; | |||||
PyObject *data; | |||||
struct PUBLIC pycallbackdata | |||||
{ | |||||
PyObject *func; | |||||
PyObject *data; | |||||
}; | }; | ||||
#endif | #endif | ||||
class PUBLIC CsoundPerformanceThread { | |||||
private: | |||||
class PUBLIC CsoundPerformanceThread | |||||
{ | |||||
private: | |||||
volatile CsoundPerformanceThreadMessage *firstMessage; | volatile CsoundPerformanceThreadMessage *firstMessage; | ||||
CsoundPerformanceThreadMessage *lastMessage; | CsoundPerformanceThreadMessage *lastMessage; | ||||
CSOUND *csound; | CSOUND *csound; | ||||
@@ -100,30 +102,37 @@ class PUBLIC CsoundPerformanceThread { | |||||
void csPerfThread_constructor(CSOUND *); | void csPerfThread_constructor(CSOUND *); | ||||
void QueueMessage(CsoundPerformanceThreadMessage *); | void QueueMessage(CsoundPerformanceThreadMessage *); | ||||
void (*processcallback)(void *cdata); | void (*processcallback)(void *cdata); | ||||
public: | |||||
int isRunning() { return running;} | |||||
public: | |||||
int isRunning() | |||||
{ | |||||
return running; | |||||
} | |||||
#ifdef SWIGPYTHON | #ifdef SWIGPYTHON | ||||
PyThreadState *_tstate; | |||||
pycallbackdata pydata; | |||||
PyThreadState *_tstate; | |||||
pycallbackdata pydata; | |||||
#endif | #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. | * Returns the Csound instance pointer. | ||||
*/ | */ | ||||
CSOUND *GetCsound() | CSOUND *GetCsound() | ||||
{ | { | ||||
return csound; | |||||
return csound; | |||||
} | } | ||||
/** | /** | ||||
* Returns the current status, zero if still playing, positive if | * Returns the current status, zero if still playing, positive if | ||||
@@ -132,7 +141,7 @@ class PUBLIC CsoundPerformanceThread { | |||||
*/ | */ | ||||
int GetStatus() | int GetStatus() | ||||
{ | { | ||||
return status; | |||||
return status; | |||||
} | } | ||||
/** | /** | ||||
* Continues performance if it was paused. | * Continues performance if it was paused. | ||||