Browse Source

More internal changes to drawables. Linux URL header retrieval. Small fix for AudioProcessorPlayer. Jucer development.

tags/2021-05-28
Julian Storer 15 years ago
parent
commit
8e1b74a8fc
21 changed files with 1217 additions and 705 deletions
  1. +2
    -0
      extras/Jucer (experimental)/Source/jucer_Main.cpp
  2. +7
    -0
      extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h
  3. +4
    -0
      extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h
  4. +71
    -0
      extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h
  5. +40
    -34
      extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp
  6. +12
    -6
      extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h
  7. +5
    -0
      extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorDragOperation.h
  8. +298
    -11
      extras/Jucer (experimental)/Source/utility/jucer_FillTypePropertyComponent.h
  9. +8
    -0
      extras/Jucer (experimental)/Source/utility/jucer_StoredSettings.cpp
  10. +5
    -1
      extras/Jucer (experimental)/Source/utility/jucer_StoredSettings.h
  11. +119
    -81
      juce_amalgamated.cpp
  12. +34
    -16
      juce_amalgamated.h
  13. +6
    -1
      src/audio/processors/juce_AudioProcessorPlayer.cpp
  14. +1
    -1
      src/core/juce_StandardHeader.h
  15. +29
    -22
      src/gui/graphics/colour/juce_ColourGradient.cpp
  16. +15
    -7
      src/gui/graphics/colour/juce_ColourGradient.h
  17. +27
    -22
      src/gui/graphics/drawables/juce_Drawable.cpp
  18. +10
    -4
      src/gui/graphics/drawables/juce_Drawable.h
  19. +34
    -12
      src/gui/graphics/drawables/juce_DrawablePath.cpp
  20. +9
    -5
      src/gui/graphics/drawables/juce_DrawablePath.h
  21. +481
    -482
      src/native/linux/juce_linux_Network.cpp

+ 2
- 0
extras/Jucer (experimental)/Source/jucer_Main.cpp View File

@@ -68,6 +68,8 @@ public:
anotherInstanceStarted (commandLine);
theMainWindow->reloadLastProject();
theMainWindow->getLookAndFeel().setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
}
void shutdown()


+ 7
- 0
extras/Jucer (experimental)/Source/model/Drawable/jucer_DrawableTypeHandler.h View File

@@ -146,6 +146,13 @@ public:
void createPropertyEditors (DrawableTypeInstance& item, Array <PropertyComponent*>& props)
{
DrawablePath::ValueTreeWrapper wrapper (item.getState());
props.add (new FillTypePropertyComponent (item.getDocument().getUndoManager(),
"Fill", wrapper.getMainFillState()));
props.add (new FillTypePropertyComponent (item.getDocument().getUndoManager(),
"Stroke", wrapper.getStrokeFillState()));
}
void itemDoubleClicked (const MouseEvent& e, DrawableTypeInstance& item)


+ 4
- 0
extras/Jucer (experimental)/Source/ui/Component Editor/jucer_ComponentEditorCanvas.h View File

@@ -146,6 +146,10 @@ public:
return getDocument().getCoordsFor (state);
}
void updateExtraComponentsForObject (const ValueTree& state, Component* parent, OwnedArray<OverlayItemComponent>& existingComps)
{
}
SelectedItems& getSelection()
{
return editor.getSelection();


+ 71
- 0
extras/Jucer (experimental)/Source/ui/Drawable Editor/jucer_DrawableEditorCanvas.h View File

@@ -207,6 +207,77 @@ public:
return RelativeRectangle();
}
class ControlPointComponent : public OverlayItemComponent
{
public:
ControlPointComponent (DrawableEditorCanvas* canvas)
: OverlayItemComponent (canvas)
{
}
~ControlPointComponent()
{
}
void paint (Graphics& g)
{
g.fillAll (Colours::pink);
}
void mouseDown (const MouseEvent& e)
{
}
void mouseDrag (const MouseEvent& e)
{
}
void mouseUp (const MouseEvent& e)
{
}
void updatePosition (const RelativePoint& point, RelativeCoordinate::NamedCoordinateFinder* nameFinder)
{
const Point<float> p (point.resolve (nameFinder));
setBoundsInTargetSpace (Rectangle<int> (roundToInt (p.getX()) - 2, roundToInt (p.getY()) - 2, 5, 5));
}
};
void updateExtraComponentsForObject (const ValueTree& state, Component* parent, OwnedArray<OverlayItemComponent>& comps)
{
if (drawable == 0)
{
comps.clear();
return;
}
DrawableTypeInstance item (getDocument(), state);
Array<RelativePoint> points;
item.getAllControlPoints (points);
Drawable* d = drawable->getDrawableWithName (Drawable::ValueTreeWrapperBase (state).getID());
DrawableComposite* parentDrawable = d->getParent();
comps.removeRange (points.size(), comps.size());
BigInteger requiredIndexes;
requiredIndexes.setRange (0, points.size(), true);
for (int i = 0; i < points.size(); ++i)
{
ControlPointComponent* c = dynamic_cast <ControlPointComponent*> (comps[i]);
if (c == 0)
{
c = new ControlPointComponent (this);
comps.set (i, c);
parent->addAndMakeVisible (c);
}
c->updatePosition (points.getReference(i), parentDrawable);
}
}
SelectedItems& getSelection()
{
return editor.getSelection();


+ 40
- 34
extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.cpp View File

@@ -114,12 +114,14 @@ public:
const Rectangle<int> bounds (canvas->getObjectPosition (objectState));
setBoundsInTargetSpace (bounds.expanded (borderThickness, borderThickness));
for (int i = sizeGuides.size(); --i >= 0;)
int i;
for (i = sizeGuides.size(); --i >= 0;)
{
sizeGuides.getUnchecked(i)->setVisible (isVisible());
sizeGuides.getUnchecked(i)->updatePosition (bounds);
}
canvas->updateExtraComponentsForObject (objectState, getParentComponent(), extraEditorComps);
return true;
}
@@ -200,6 +202,7 @@ private:
const int borderThickness;
OwnedArray <SizeGuideComponent> sizeGuides;
bool isDragging;
OwnedArray <OverlayItemComponent> extraEditorComps;
const Rectangle<int> getCentreArea() const
{
@@ -399,6 +402,8 @@ public:
getSelection().removeChangeListener (this);
lasso = 0;
resizers.clear();
markersX.clear();
markersY.clear();
deleteAllChildren();
}
@@ -563,6 +568,21 @@ public:
}
}
void update()
{
updateResizeFrames();
updateMarkers();
}
private:
//==============================================================================
EditorCanvasBase* canvas;
ScopedPointer <LassoComponent <SelectedItems::ItemType> > lasso;
bool mouseDownResult, isDraggingClickedComp;
SelectedItems::ItemType mouseDownCompUID;
OwnedArray <ResizeFrame> resizers;
OwnedArray <MarkerComponent> markersX, markersY;
void updateResizeFrames()
{
SelectedItems& selection = getSelection();
@@ -610,49 +630,34 @@ public:
}
}
void update()
void updateMarkers (OwnedArray <MarkerComponent>& markers, const bool isX)
{
updateResizeFrames();
updateMarkers();
}
private:
//==============================================================================
EditorCanvasBase* canvas;
ScopedPointer <LassoComponent <SelectedItems::ItemType> > lasso;
bool mouseDownResult, isDraggingClickedComp;
SelectedItems::ItemType mouseDownCompUID;
OwnedArray <ResizeFrame> resizers;
MarkerListBase& markerList = canvas->getMarkerList (isX);
const int num = markerList.size();
void updateMarkers (bool isX)
{
Array<ValueTree> requiredMarkers;
requiredMarkers.ensureStorageAllocated (num);
MarkerListBase& markerList = canvas->getMarkerList (isX);
const int num = markerList.size();
int i;
for (i = 0; i < num; ++i)
requiredMarkers.add (markerList.getMarker (i));
for (i = getNumChildComponents(); --i >= 0;)
for (i = markers.size(); --i >= 0;)
{
MarkerComponent* marker = dynamic_cast <MarkerComponent*> (getChildComponent(i));
MarkerComponent* marker = markers.getUnchecked (i);
const int index = requiredMarkers.indexOf (marker->marker);
if (marker != 0 && marker->isX == isX)
if (index >= 0)
{
if (requiredMarkers.contains (marker->marker))
{
marker->setVisible (true);
marker->updatePosition();
requiredMarkers.removeValue (marker->marker);
}
marker->updatePosition();
requiredMarkers.removeValue (marker->marker);
}
else
{
if (marker->isMouseButtonDown())
marker->setBounds (-1, -1, 1, 1);
else
{
if (marker->isMouseButtonDown())
marker->setBounds (-1, -1, 1, 1);
else
delete marker;
}
markers.remove (i);
}
}
@@ -661,6 +666,7 @@ private:
MarkerComponent* marker = new MarkerComponent (canvas, requiredMarkers.getReference(i),
isX, isX ? canvas->border.getTop()
: canvas->border.getLeft());
markers.add (marker);
addAndMakeVisible (marker);
marker->updatePosition();
}
@@ -668,8 +674,8 @@ private:
void updateMarkers()
{
updateMarkers (true);
updateMarkers (false);
updateMarkers (markersX, true);
updateMarkers (markersY, false);
}
};


+ 12
- 6
extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorCanvas.h View File

@@ -64,27 +64,29 @@ public:
void hideSizeGuides();
//==============================================================================
virtual UndoManager& getUndoManager() = 0;
virtual void documentChanged() = 0;
virtual Component* createComponentHolder() = 0;
virtual const Rectangle<int> getCanvasBounds() = 0;
virtual void setCanvasBounds (const Rectangle<int>& newBounds) = 0;
virtual bool canResizeCanvas() const = 0;
virtual MarkerListBase& getMarkerList (bool isX) = 0;
virtual double limitMarkerPosition (double pos) = 0;
virtual const SelectedItems::ItemType findObjectIdAt (const Point<int>& position) = 0;
virtual void showPopupMenu (bool isClickOnSelectedObject) = 0;
virtual void objectDoubleClicked (const MouseEvent& e, const ValueTree& state) = 0;
virtual const ValueTree getObjectState (const String& objectId) = 0;
virtual RelativeRectangle getObjectCoords (const ValueTree& state) = 0;
virtual const Rectangle<int> getObjectPosition (const ValueTree& state) = 0;
virtual bool hasSizeGuides() const = 0;
virtual RelativeRectangle getObjectCoords (const ValueTree& state) = 0;
virtual MarkerListBase& getMarkerList (bool isX) = 0;
virtual double limitMarkerPosition (double pos) = 0;
virtual SelectedItems& getSelection() = 0;
virtual UndoManager& getUndoManager() = 0;
virtual void deselectNonDraggableObjects() = 0;
virtual void findLassoItemsInArea (Array <SelectedItems::ItemType>& itemsFound, const Rectangle<int>& area) = 0;
virtual Component* createComponentHolder() = 0;
class DragOperation
{
@@ -126,6 +128,10 @@ public:
EditorCanvasBase* canvas;
};
//==============================================================================
virtual void updateExtraComponentsForObject (const ValueTree& state, Component* parent,
OwnedArray<OverlayItemComponent>& existingComps) = 0;
protected:
//==============================================================================
const BorderSize border;


+ 5
- 0
extras/Jucer (experimental)/Source/ui/Editor Base/jucer_EditorDragOperation.h View File

@@ -172,6 +172,11 @@ public:
roundToInt (line.end - line.start) + extraEndLength * 2, 1));
}
bool updatePosition()
{
return true;
}
void paint (Graphics& g)
{
g.fillAll (alignmentMarkerColour);


+ 298
- 11
extras/Jucer (experimental)/Source/utility/jucer_FillTypePropertyComponent.h View File

@@ -37,15 +37,43 @@ public:
: fillState (fillState_),
undoManager (undoManager_)
{
addAndMakeVisible (&colourPicker);
colourButton.setButtonText ("Colour");
colourButton.setConnectedEdges (TextButton::ConnectedOnRight);
gradientButton.setButtonText ("Gradient");
gradientButton.setConnectedEdges (TextButton::ConnectedOnRight | TextButton::ConnectedOnLeft);
imageButton.setButtonText ("Image");
imageButton.setConnectedEdges (TextButton::ConnectedOnLeft);
addAndMakeVisible (&colourButton);
addAndMakeVisible (&gradientButton);
addAndMakeVisible (&imageButton);
addChildComponent (&colourPicker);
colourPicker.setCurrentColour (Colours::green);
colourPicker.setName ("Colour");
colourPicker.addChangeListener (this);
addChildComponent (&gradientPicker);
gradientPicker.addChangeListener (this);
fillState.addListener (this);
colourButton.setRadioGroupId (123);
gradientButton.setRadioGroupId (123);
imageButton.setRadioGroupId (123);
colourButton.addButtonListener (this);
gradientButton.addButtonListener (this);
imageButton.addButtonListener (this);
refresh();
}
~PopupFillSelector()
{
colourButton.removeButtonListener (this);
gradientButton.removeButtonListener (this);
imageButton.removeButtonListener (this);
}
static void showAt (Component* comp, const ValueTree& fill, UndoManager* undoManager)
@@ -59,32 +87,84 @@ public:
void resized()
{
colourPicker.setBounds (0, 0, getWidth(), getHeight());
const int y = 2, w = 80, h = 22;
gradientButton.setBounds (getWidth() / 2 - w / 2, y, w, h);
colourButton.setBounds (gradientButton.getX() - w, y, w, h);
imageButton.setBounds (gradientButton.getRight(), y, w, h);
const Rectangle<int> content (2, y + h + 4, getWidth() - 4, getHeight() - (y + h + 6));
colourPicker.setBounds (content);
gradientPicker.setBounds (content);
}
void buttonClicked (Button*)
void buttonClicked (Button* b)
{
if (b == &colourButton)
{
setFillType (colourPicker.getCurrentColour());
}
else if (b == &gradientButton)
{
setFillType (gradientPicker.getGradient());
}
else if (b == &imageButton)
{
setFillType (FillType (*StoredSettings::getInstance()->getFallbackImage(),
AffineTransform::identity));
}
}
void changeListenerCallback (void* source)
const FillType readFillType (RelativePoint* gp1, RelativePoint* gp2) const
{
const FillType currentFill (Drawable::ValueTreeWrapperBase::readFillType (fillState));
return Drawable::ValueTreeWrapperBase::readFillType (fillState, gp1, gp2, 0);
}
if (currentFill.isColour())
void setFillType (const FillType& newFill)
{
RelativePoint gp1, gp2;
const FillType currentFill (readFillType (&gp1, &gp2));
if (currentFill != newFill)
{
const FillType newFill (colourPicker.getCurrentColour());
if (undoManager != 0)
undoManager->undoCurrentTransactionOnly();
if (currentFill != newFill)
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, undoManager);
Drawable::ValueTreeWrapperBase::writeFillType (fillState, newFill, &gp1, &gp2, undoManager);
refresh();
}
}
void changeListenerCallback (void*)
{
const FillType currentFill (readFillType (0, 0));
if (currentFill.isColour())
setFillType (colourPicker.getCurrentColour());
else if (currentFill.isGradient())
setFillType (gradientPicker.getGradient());
}
void refresh()
{
const FillType newFill (Drawable::ValueTreeWrapperBase::readFillType (fillState));
const FillType newFill (readFillType (0, 0));
colourPicker.setVisible (newFill.isColour());
gradientPicker.setVisible (newFill.isGradient());
if (newFill.isColour())
{
colourButton.setToggleState (true, false);
colourPicker.setCurrentColour (newFill.colour);
}
else if (newFill.isGradient())
{
gradientButton.setToggleState (true, false);
gradientPicker.setGradient (*newFill.gradient);
}
else
{
imageButton.setToggleState (true, false);
}
}
void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property) { refresh(); }
@@ -92,9 +172,215 @@ public:
void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) {}
private:
//==============================================================================
class GradientDesigner : public Component,
public ChangeBroadcaster,
private ChangeListener
{
public:
GradientDesigner()
: gradient (Colours::red, 0.0f, 0.0f, Colours::blue, 200.0f, 200.0f, false),
selectedPoint (-1),
dragging (false),
draggingNewPoint (false),
draggingPos (0)
{
addChildComponent (&colourPicker);
colourPicker.addChangeListener (this);
}
~GradientDesigner()
{
}
void paint (Graphics& g)
{
g.fillAll (getLookAndFeel().findColour (ColourSelector::backgroundColourId));
g.fillCheckerBoard (previewArea.getX(), previewArea.getY(),
previewArea.getWidth(), previewArea.getHeight(), 10, 10,
Colour (0xffdddddd), Colour (0xffffffff));
FillType f (gradient);
f.gradient->point1.setXY ((float) previewArea.getX(), (float) previewArea.getCentreY());
f.gradient->point2.setXY ((float) previewArea.getRight(), (float) previewArea.getCentreY());
g.setFillType (f);
g.fillRect (previewArea);
Path marker;
const float headSize = 4.5f;
marker.addLineSegment (0.0f, -2.0f, 0.0f, previewArea.getHeight() + 2.0f, 1.5f);
marker.addTriangle (0.0f, 1.0f, -headSize, -headSize, headSize, -headSize);
for (int i = 0; i < gradient.getNumColours(); ++i)
{
const double pos = gradient.getColourPosition (i);
const Colour col (gradient.getColour (i));
const AffineTransform t (AffineTransform::translation (previewArea.getX() + 0.5f + (float) (previewArea.getWidth() * pos),
(float) previewArea.getY()));
g.setColour (Colours::black.withAlpha (0.8f));
g.strokePath (marker, PathStrokeType (i == selectedPoint ? 2.0f : 1.5f), t);
g.setColour (i == selectedPoint ? Colours::lightblue : Colours::white);
g.fillPath (marker, t);
}
}
void resized()
{
previewArea.setBounds (7, 8, getWidth() - 14, 24);
colourPicker.setBounds (0, previewArea.getBottom() + 8,
getWidth(), getHeight() - previewArea.getBottom() - 8);
}
void mouseDown (const MouseEvent& e)
{
dragging = false;
draggingNewPoint = false;
int point = getPointAt (e.x);
if (point >= 0)
setSelectedPoint (point);
}
void mouseDrag (const MouseEvent& e)
{
if ((! dragging) && ! e.mouseWasClicked())
{
preDragGradient = gradient;
const int mouseDownPoint = getPointAt (e.getMouseDownX());
if (mouseDownPoint >= 0)
{
if (mouseDownPoint > 0 && mouseDownPoint < gradient.getNumColours() - 1)
{
dragging = true;
draggingNewPoint = false;
draggingColour = gradient.getColour (mouseDownPoint);
preDragGradient.removeColour (mouseDownPoint);
selectedPoint = -1;
}
}
else
{
dragging = true;
draggingNewPoint = true;
selectedPoint = -1;
}
}
if (dragging)
{
draggingPos = jlimit (0.001, 0.999, (e.x - previewArea.getX()) / (double) previewArea.getWidth());
gradient = preDragGradient;
if (previewArea.expanded (6, 6).contains (e.x, e.y))
{
if (draggingNewPoint)
draggingColour = preDragGradient.getColourAtPosition (draggingPos);
selectedPoint = gradient.addColour (draggingPos, draggingColour);
updatePicker();
}
else
{
selectedPoint = -1;
}
sendChangeMessage (this);
repaint (previewArea.expanded (30, 30));
}
}
void mouseUp (const MouseEvent& e)
{
dragging = false;
}
const ColourGradient& getGradient() const throw() { return gradient; }
void setGradient (const ColourGradient& newGradient)
{
if (newGradient != gradient)
{
gradient = newGradient;
if (selectedPoint < 0)
selectedPoint = 0;
updatePicker();
sendChangeMessage (this);
repaint();
}
}
void setSelectedPoint (int newIndex)
{
if (selectedPoint != newIndex)
{
selectedPoint = newIndex;
updatePicker();
repaint();
}
}
void changeListenerCallback (void*)
{
if (selectedPoint >= 0 && (! dragging) && gradient.getColour (selectedPoint) != colourPicker.getCurrentColour())
{
gradient.setColour (selectedPoint, colourPicker.getCurrentColour());
repaint (previewArea);
sendChangeMessage (this);
}
}
private:
StoredSettings::ColourSelectorWithSwatches colourPicker;
ColourGradient gradient;
int selectedPoint;
bool dragging, draggingNewPoint;
double draggingPos;
Colour draggingColour;
ColourGradient preDragGradient;
Rectangle<int> previewArea;
void updatePicker()
{
colourPicker.setVisible (selectedPoint >= 0);
if (selectedPoint >= 0)
colourPicker.setCurrentColour (gradient.getColour (selectedPoint));
}
int getPointAt (const int x) const
{
int best = -1;
double bestDiff = 6;
for (int i = gradient.getNumColours(); --i >= 0;)
{
const double pos = previewArea.getX() + previewArea.getWidth() * gradient.getColourPosition (i);
const double diff = std::abs (pos - x);
if (diff < bestDiff)
{
bestDiff = diff;
best = i;
}
}
return best;
}
};
//==============================================================================
StoredSettings::ColourSelectorWithSwatches colourPicker;
GradientDesigner gradientPicker;
ValueTree fillState;
UndoManager* undoManager;
TextButton colourButton, gradientButton, imageButton;
};
@@ -149,7 +435,7 @@ public:
void refresh()
{
const FillType newFill (Drawable::ValueTreeWrapperBase::readFillType (fillState));
const FillType newFill (Drawable::ValueTreeWrapperBase::readFillType (fillState, 0, 0, 0));
if (newFill != fillType)
{
@@ -185,6 +471,7 @@ public:
: PropertyComponent (name),
editor (fill, undoManager)
{
jassert (fill.isValid());
addAndMakeVisible (&editor);
}


+ 8
- 0
extras/Jucer (experimental)/Source/utility/jucer_StoredSettings.cpp View File

@@ -134,3 +134,11 @@ const StringArray& StoredSettings::getFontNames()
return fontNames;
}
Image* StoredSettings::getFallbackImage()
{
if (fallbackImage == 0)
fallbackImage = ImageFileFormat::loadFrom (BinaryData::juce_icon_png, BinaryData::juce_icon_pngSize);
return fallbackImage;
}

+ 5
- 1
extras/Jucer (experimental)/Source/utility/jucer_StoredSettings.h View File

@@ -53,7 +53,6 @@ public:
const File getLastKnownJuceFolder() const;
void setLastKnownJuceFolder (const File& file);
const StringArray& getFontNames();
//==============================================================================
@@ -69,12 +68,17 @@ public:
void setSwatchColour (int index, const Colour& newColour) const { StoredSettings::getInstance()->swatchColours.set (index, newColour); }
};
Image* getFallbackImage();
//==============================================================================
juce_UseDebuggingNewOperator
private:
ScopedPointer<PropertiesFile> props;
StringArray fontNames;
ScopedPointer<Image> fallbackImage;
};


+ 119
- 81
juce_amalgamated.cpp View File

@@ -36166,7 +36166,12 @@ void AudioProcessorPlayer::audioDeviceIOCallback (const float** inputChannelData
const ScopedLock sl (lock);

if (processor != 0)
processor->processBlock (buffer, incomingMidi);
{
const ScopedLock sl (processor->getCallbackLock());

if (! processor->isSuspended())
processor->processBlock (buffer, incomingMidi);
}
}

void AudioProcessorPlayer::audioDeviceAboutToStart (AudioIODevice* device)
@@ -78867,19 +78872,15 @@ ColourGradient::ColourGradient() throw()
#endif
}

ColourGradient::ColourGradient (const Colour& colour1,
const float x1_,
const float y1_,
const Colour& colour2,
const float x2_,
const float y2_,
ColourGradient::ColourGradient (const Colour& colour1, const float x1_, const float y1_,
const Colour& colour2, const float x2_, const float y2_,
const bool isRadial_)
: point1 (x1_, y1_),
point2 (x2_, y2_),
isRadial (isRadial_)
{
colours.add (ColourPoint (0, colour1));
colours.add (ColourPoint (1 << 16, colour2));
colours.add (ColourPoint (0.0, colour1));
colours.add (ColourPoint (1.0, colour2));
}

ColourGradient::~ColourGradient()
@@ -78903,13 +78904,12 @@ void ColourGradient::clearColours()
colours.clear();
}

void ColourGradient::addColour (const double proportionAlongGradient,
const Colour& colour)
int ColourGradient::addColour (const double proportionAlongGradient, const Colour& colour)
{
// must be within the two end-points
jassert (proportionAlongGradient >= 0 && proportionAlongGradient <= 1.0);

const uint32 pos = jlimit (0, 65535, roundToInt (proportionAlongGradient * 65536.0));
const double pos = jlimit (0.0, 1.0, proportionAlongGradient);

int i;
for (i = 0; i < colours.size(); ++i)
@@ -78917,6 +78917,13 @@ void ColourGradient::addColour (const double proportionAlongGradient,
break;

colours.insert (i, ColourPoint (pos, colour));
return i;
}

void ColourGradient::removeColour (int index)
{
jassert (index > 0 && index < colours.size() - 1);
colours.remove (index);
}

void ColourGradient::multiplyOpacity (const float multiplier) throw()
@@ -78936,7 +78943,7 @@ int ColourGradient::getNumColours() const throw()
double ColourGradient::getColourPosition (const int index) const throw()
{
if (((unsigned int) index) < (unsigned int) colours.size())
return jlimit (0.0, 1.0, colours.getReference (index).position / 65535.0);
return colours.getReference (index).position;

return 0;
}
@@ -78949,26 +78956,31 @@ const Colour ColourGradient::getColour (const int index) const throw()
return Colour();
}

const Colour ColourGradient::getColourAtPosition (const float position) const throw()
void ColourGradient::setColour (int index, const Colour& newColour) throw()
{
jassert (colours.getReference(0).position == 0); // the first colour specified has to go at position 0
if (((unsigned int) index) < (unsigned int) colours.size())
colours.getReference (index).colour = newColour;
}

const int integerPos = jlimit (0, 65535, roundToInt (position * 65536.0f));
const Colour ColourGradient::getColourAtPosition (const double position) const throw()
{
jassert (colours.getReference(0).position == 0); // the first colour specified has to go at position 0

if (integerPos <= 0 || colours.size() <= 1)
return getColour (0);
if (position <= 0 || colours.size() <= 1)
return colours.getReference(0).colour;

int i = colours.size() - 1;
while (integerPos < (int) colours.getReference(i).position)
while (position < colours.getReference(i).position)
--i;

const ColourPoint& p1 = colours.getReference (i);

if (i >= colours.size() - 1)
return colours.getReference(i).colour;
return p1.colour;

const ColourPoint& p1 = colours.getReference (i);
const ColourPoint& p2 = colours.getReference (i + 1);

return p1.colour.interpolatedWith (p2.colour, (integerPos - p1.position) / (float) (p2.position - p1.position));
return p1.colour.interpolatedWith (p2.colour, (float) ((position - p1.position) / (p2.position - p1.position)));
}

int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlock <PixelARGB>& lookupTable) const
@@ -78994,7 +79006,7 @@ int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlo
for (int j = 1; j < colours.size(); ++j)
{
const ColourPoint& p = colours.getReference (j);
const int numToDo = ((p.position * (numEntries - 1)) >> 16) - index;
const int numToDo = roundToInt (p.position * (numEntries - 1)) - index;
const PixelARGB pix2 (p.colour.getPixelARGB());

for (int i = 0; i < numToDo; ++i)
@@ -83854,10 +83866,8 @@ Drawable* Drawable::createFromValueTree (const ValueTree& tree, ImageProvider* i

const Identifier Drawable::ValueTreeWrapperBase::idProperty ("id");
const Identifier Drawable::ValueTreeWrapperBase::type ("type");
const Identifier Drawable::ValueTreeWrapperBase::x1 ("x1");
const Identifier Drawable::ValueTreeWrapperBase::x2 ("x2");
const Identifier Drawable::ValueTreeWrapperBase::y1 ("y1");
const Identifier Drawable::ValueTreeWrapperBase::y2 ("y2");
const Identifier Drawable::ValueTreeWrapperBase::gradientPoint1 ("point1");
const Identifier Drawable::ValueTreeWrapperBase::gradientPoint2 ("point2");
const Identifier Drawable::ValueTreeWrapperBase::colour ("colour");
const Identifier Drawable::ValueTreeWrapperBase::radial ("radial");
const Identifier Drawable::ValueTreeWrapperBase::colours ("colours");
@@ -83884,7 +83894,8 @@ void Drawable::ValueTreeWrapperBase::setID (const String& newID, UndoManager* un
state.setProperty (idProperty, newID, undoManager);
}

const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v)
const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v, RelativePoint* gp1, RelativePoint* gp2,
RelativeCoordinate::NamedCoordinateFinder* nameFinder)
{
const String newType (v[type].toString());

@@ -83896,9 +83907,17 @@ const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v)
}
else if (newType == "gradient")
{
RelativePoint p1 (v [gradientPoint1]), p2 (v [gradientPoint2]);

ColourGradient g;
g.point1.setXY (v[x1], v[y1]);
g.point2.setXY (v[x2], v[y2]);

if (gp1 != 0)
*gp1 = p1;
if (gp2 != 0)
*gp2 = p2;

g.point1 = p1.resolve (nameFinder);
g.point2 = p2.resolve (nameFinder);
g.isRadial = v[radial];

StringArray colourSteps;
@@ -83919,26 +83938,24 @@ const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v)
return FillType();
}

void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType& fillType, UndoManager* const undoManager)
void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType& fillType,
const RelativePoint* gp1, const RelativePoint* gp2,
UndoManager* const undoManager)
{
if (fillType.isColour())
{
v.setProperty (type, "solid", undoManager);
v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), undoManager);
v.removeProperty (x1, undoManager);
v.removeProperty (x2, undoManager);
v.removeProperty (y1, undoManager);
v.removeProperty (y2, undoManager);
v.removeProperty (gradientPoint1, undoManager);
v.removeProperty (gradientPoint2, undoManager);
v.removeProperty (radial, undoManager);
v.removeProperty (colours, undoManager);
}
else if (fillType.isGradient())
{
v.setProperty (type, "gradient", undoManager);
v.setProperty (x1, fillType.gradient->point1.getX(), undoManager);
v.setProperty (y1, fillType.gradient->point1.getY(), undoManager);
v.setProperty (x2, fillType.gradient->point2.getX(), undoManager);
v.setProperty (y2, fillType.gradient->point2.getY(), undoManager);
v.setProperty (gradientPoint1, gp1 != 0 ? gp1->toString() : fillType.gradient->point1.toString(), undoManager);
v.setProperty (gradientPoint2, gp2 != 0 ? gp2->toString() : fillType.gradient->point2.toString(), undoManager);
v.setProperty (radial, fillType.gradient->isRadial, undoManager);

String s;
@@ -83955,10 +83972,8 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType

jassertfalse; //xxx todo

v.removeProperty (x1, undoManager);
v.removeProperty (x2, undoManager);
v.removeProperty (y1, undoManager);
v.removeProperty (y2, undoManager);
v.removeProperty (gradientPoint1, undoManager);
v.removeProperty (gradientPoint2, undoManager);
v.removeProperty (radial, undoManager);
v.removeProperty (colours, undoManager);
v.removeProperty (colour, undoManager);
@@ -83969,7 +83984,9 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
}
}

void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, const FillType& fillType, UndoManager* const undoManager)
void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, const FillType& fillType,
const RelativePoint* gp1, const RelativePoint* gp2,
UndoManager* const undoManager)
{
ValueTree v (state.getChildWithName (tag));

@@ -83979,7 +83996,7 @@ void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, con
v = state.getChildWithName (tag);
}

writeFillType (v, fillType, undoManager);
writeFillType (v, fillType, gp1, gp2, undoManager);
}

END_JUCE_NAMESPACE
@@ -85114,24 +85131,46 @@ DrawablePath::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
jassert (state.hasType (valueTreeType));
}

const FillType DrawablePath::ValueTreeWrapper::getMainFill() const
ValueTree DrawablePath::ValueTreeWrapper::getMainFillState()
{
ValueTree v (state.getChildWithName (fill));
if (v.isValid())
return v;

setMainFill (Colours::black, 0, 0, 0);
return getMainFillState();
}

ValueTree DrawablePath::ValueTreeWrapper::getStrokeFillState()
{
ValueTree v (state.getChildWithName (stroke));
if (v.isValid())
return v;

setStrokeFill (Colours::black, 0, 0, 0);
return getStrokeFillState();
}

const FillType DrawablePath::ValueTreeWrapper::getMainFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const
{
return readFillType (state.getChildWithName (fill));
return readFillType (state.getChildWithName (fill), 0, 0, nameFinder);
}

void DrawablePath::ValueTreeWrapper::setMainFill (const FillType& newFill, UndoManager* undoManager)
void DrawablePath::ValueTreeWrapper::setMainFill (const FillType& newFill, const RelativePoint* gp1,
const RelativePoint* gp2, UndoManager* undoManager)
{
replaceFillType (fill, newFill, undoManager);
replaceFillType (fill, newFill, gp1, gp2, undoManager);
}

const FillType DrawablePath::ValueTreeWrapper::getStrokeFill() const
const FillType DrawablePath::ValueTreeWrapper::getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const
{
return readFillType (state.getChildWithName (stroke));
return readFillType (state.getChildWithName (stroke), 0, 0, nameFinder);
}

void DrawablePath::ValueTreeWrapper::setStrokeFill (const FillType& newFill, UndoManager* undoManager)
void DrawablePath::ValueTreeWrapper::setStrokeFill (const FillType& newFill, const RelativePoint* gp1,
const RelativePoint* gp2, UndoManager* undoManager)
{
replaceFillType (stroke, newFill, undoManager);
replaceFillType (stroke, newFill, gp1, gp2, undoManager);
}

const PathStrokeType DrawablePath::ValueTreeWrapper::getStrokeType() const
@@ -85175,7 +85214,7 @@ const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree
setName (v.getID());

bool needsRedraw = false;
const FillType newFill (v.getMainFill());
const FillType newFill (v.getMainFill (parent));

if (mainFill != newFill)
{
@@ -85183,7 +85222,7 @@ const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree
mainFill = newFill;
}

const FillType newStrokeFill (v.getStrokeFill());
const FillType newStrokeFill (v.getStrokeFill (parent));

if (strokeFill != newStrokeFill)
{
@@ -85224,8 +85263,8 @@ const ValueTree DrawablePath::createValueTree (ImageProvider*) const
ValueTreeWrapper v (tree);

v.setID (getName(), 0);
v.setMainFill (mainFill, 0);
v.setStrokeFill (strokeFill, 0);
v.setMainFill (mainFill, 0, 0, 0);
v.setStrokeFill (strokeFill, 0, 0, 0);
v.setStrokeType (strokeType, 0);

if (relativePath != 0)
@@ -253051,8 +253090,8 @@ public:
{
//DBG (responseHeader);

StringArray lines;
lines.addLines (responseHeader);
headerLines.clear();
headerLines.addLines (responseHeader);

const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
.substring (0, 3).getIntValue();
@@ -253060,7 +253099,7 @@ public:
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");

String location (findHeaderItem (lines, "Location:"));
String location (findHeaderItem (headerLines, "Location:"));

if (statusCode >= 300 && statusCode < 400
&& location.isNotEmpty())
@@ -253101,6 +253140,7 @@ public:
}

int readPosition;
StringArray headerLines;

juce_UseDebuggingNewOperator

@@ -253250,13 +253290,11 @@ void* juce_openInternetFile (const String& url,
void* callbackContext,
int timeOutMs)
{
JUCE_HTTPSocketStream* const s = new JUCE_HTTPSocketStream();
ScopedPointer<JUCE_HTTPSocketStream> s (new JUCE_HTTPSocketStream());

if (s->open (url, headers, postData, isPost,
callback, callbackContext, timeOutMs))
return s;
if (s->open (url, headers, postData, isPost, callback, callbackContext, timeOutMs))
return s.release();

delete s;
return 0;
}

@@ -253267,46 +253305,46 @@ void juce_closeInternetFile (void* handle)

int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
{
JUCE_HTTPSocketStream* const s = (JUCE_HTTPSocketStream*) handle;

if (s != 0)
return s->read (buffer, bytesToRead);
JUCE_HTTPSocketStream* const s = static_cast <JUCE_HTTPSocketStream*> (handle);

return 0;
return s != 0 ? s->read (buffer, bytesToRead) : 0;
}

int64 juce_getInternetFileContentLength (void* handle)
{
JUCE_HTTPSocketStream* const s = (JUCE_HTTPSocketStream*) handle;
JUCE_HTTPSocketStream* const s = static_cast <JUCE_HTTPSocketStream*> (handle);

if (s != 0)
{
//xxx todo
jassertfalse;
jassertfalse
}

return -1;
}

void juce_getInternetFileHeaders (void* handle, StringPairArray& headers)
bool juce_getInternetFileHeaders (void* handle, StringPairArray& headers)
{
JUCE_HTTPSocketStream* const s = (JUCE_HTTPSocketStream*) handle;
JUCE_HTTPSocketStream* const s = static_cast <JUCE_HTTPSocketStream*> (handle);

if (s != 0)
{
// xxx todo
jassertfalse;
for (int i = 0; i < s->headerLines.size(); ++i)
{
const String& headersEntry = s->headerLines[i];
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
const String previousValue (headers [key]);
headers.set (key, previousValue.isEmpty() ? value : (previousValue + ";" + value));
}
}
}

int juce_seekInInternetFile (void* handle, int newPosition)
{
JUCE_HTTPSocketStream* const s = (JUCE_HTTPSocketStream*) handle;
JUCE_HTTPSocketStream* const s = static_cast <JUCE_HTTPSocketStream*> (handle);

if (s != 0)
return s->readPosition;

return 0;
return s != 0 ? s->readPosition : 0;
}

#endif


+ 34
- 16
juce_amalgamated.h View File

@@ -64,7 +64,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 6
#define JUCE_BUILDNUMBER 7

/** Current Juce version number.

@@ -23179,9 +23179,13 @@ public:
of the distance along the line between the two points
at which the colour should occur.
@param colour the colour that should be used at this point
@returns the index at which the new point was added
*/
void addColour (double proportionAlongGradient,
const Colour& colour);
int addColour (double proportionAlongGradient,
const Colour& colour);

/** Removes one of the colours from the gradient. */
void removeColour (int index);

/** Multiplies the alpha value of all the colours by the given scale factor */
void multiplyOpacity (float multiplier) throw();
@@ -23196,15 +23200,19 @@ public:
double getColourPosition (int index) const throw();

/** Returns the colour that was added with a given index.

The index is from 0 to getNumColours() - 1. The return value will be between 0.0 and 1.0
The index is from 0 to getNumColours() - 1.
*/
const Colour getColour (int index) const throw();

/** Changes the colour at a given index.
The index is from 0 to getNumColours() - 1.
*/
void setColour (int index, const Colour& newColour) throw();

/** Returns the an interpolated colour at any position along the gradient.
@param position the position along the gradient, between 0 and 1
*/
const Colour getColourAtPosition (float position) const throw();
const Colour getColourAtPosition (double position) const throw();

/** Creates a set of interpolated premultiplied ARGB values.
This will resize the HeapBlock, fill it with the colours, and will return the number of
@@ -23237,14 +23245,14 @@ private:
{
ColourPoint() throw() {}

ColourPoint (uint32 position_, const Colour& colour_) throw()
ColourPoint (const double position_, const Colour& colour_) throw()
: position (position_), colour (colour_)
{}

bool operator== (const ColourPoint& other) const throw() { return position == other.position && colour == other.colour; }
bool operator!= (const ColourPoint& other) const throw() { return position != other.position || colour != other.colour; }

uint32 position;
double position;
Colour colour;
};

@@ -42586,14 +42594,20 @@ public:
void setID (const String& newID, UndoManager* undoManager);
static const Identifier idProperty;

static const FillType readFillType (const ValueTree& v);
static void writeFillType (ValueTree& v, const FillType& fillType, UndoManager* undoManager);
static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1, RelativePoint* gradientPoint2,
RelativeCoordinate::NamedCoordinateFinder* nameFinder);

static void writeFillType (ValueTree& v, const FillType& fillType,
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
UndoManager* undoManager);

protected:
ValueTree state;
static const Identifier type, x1, x2, y1, y2, colour, radial, colours;
static const Identifier type, gradientPoint1, gradientPoint2, colour, radial, colours;

void replaceFillType (const Identifier& tag, const FillType& fillType, UndoManager* undoManager);
void replaceFillType (const Identifier& tag, const FillType& fillType,
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
UndoManager* undoManager);
};

juce_UseDebuggingNewOperator
@@ -58593,11 +58607,15 @@ public:
public:
ValueTreeWrapper (const ValueTree& state);

const FillType getMainFill() const;
void setMainFill (const FillType& newFill, UndoManager* undoManager);
const FillType getMainFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const;
ValueTree getMainFillState();
void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, UndoManager* undoManager);

const FillType getStrokeFill() const;
void setStrokeFill (const FillType& newFill, UndoManager* undoManager);
const FillType getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const;
ValueTree getStrokeFillState();
void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, UndoManager* undoManager);

const PathStrokeType getStrokeType() const;
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager);


+ 6
- 1
src/audio/processors/juce_AudioProcessorPlayer.cpp View File

@@ -133,7 +133,12 @@ void AudioProcessorPlayer::audioDeviceIOCallback (const float** inputChannelData
const ScopedLock sl (lock);
if (processor != 0)
processor->processBlock (buffer, incomingMidi);
{
const ScopedLock sl (processor->getCallbackLock());
if (! processor->isSuspended())
processor->processBlock (buffer, incomingMidi);
}
}
void AudioProcessorPlayer::audioDeviceAboutToStart (AudioIODevice* device)


+ 1
- 1
src/core/juce_StandardHeader.h View File

@@ -33,7 +33,7 @@
*/
#define JUCE_MAJOR_VERSION 1
#define JUCE_MINOR_VERSION 52
#define JUCE_BUILDNUMBER 6
#define JUCE_BUILDNUMBER 7
/** Current Juce version number.


+ 29
- 22
src/gui/graphics/colour/juce_ColourGradient.cpp View File

@@ -38,19 +38,15 @@ ColourGradient::ColourGradient() throw()
#endif
}
ColourGradient::ColourGradient (const Colour& colour1,
const float x1_,
const float y1_,
const Colour& colour2,
const float x2_,
const float y2_,
ColourGradient::ColourGradient (const Colour& colour1, const float x1_, const float y1_,
const Colour& colour2, const float x2_, const float y2_,
const bool isRadial_)
: point1 (x1_, y1_),
point2 (x2_, y2_),
isRadial (isRadial_)
{
colours.add (ColourPoint (0, colour1));
colours.add (ColourPoint (1 << 16, colour2));
colours.add (ColourPoint (0.0, colour1));
colours.add (ColourPoint (1.0, colour2));
}
ColourGradient::~ColourGradient()
@@ -75,13 +71,12 @@ void ColourGradient::clearColours()
colours.clear();
}
void ColourGradient::addColour (const double proportionAlongGradient,
const Colour& colour)
int ColourGradient::addColour (const double proportionAlongGradient, const Colour& colour)
{
// must be within the two end-points
jassert (proportionAlongGradient >= 0 && proportionAlongGradient <= 1.0);
const uint32 pos = jlimit (0, 65535, roundToInt (proportionAlongGradient * 65536.0));
const double pos = jlimit (0.0, 1.0, proportionAlongGradient);
int i;
for (i = 0; i < colours.size(); ++i)
@@ -89,6 +84,13 @@ void ColourGradient::addColour (const double proportionAlongGradient,
break;
colours.insert (i, ColourPoint (pos, colour));
return i;
}
void ColourGradient::removeColour (int index)
{
jassert (index > 0 && index < colours.size() - 1);
colours.remove (index);
}
void ColourGradient::multiplyOpacity (const float multiplier) throw()
@@ -109,7 +111,7 @@ int ColourGradient::getNumColours() const throw()
double ColourGradient::getColourPosition (const int index) const throw()
{
if (((unsigned int) index) < (unsigned int) colours.size())
return jlimit (0.0, 1.0, colours.getReference (index).position / 65535.0);
return colours.getReference (index).position;
return 0;
}
@@ -122,26 +124,31 @@ const Colour ColourGradient::getColour (const int index) const throw()
return Colour();
}
const Colour ColourGradient::getColourAtPosition (const float position) const throw()
void ColourGradient::setColour (int index, const Colour& newColour) throw()
{
jassert (colours.getReference(0).position == 0); // the first colour specified has to go at position 0
if (((unsigned int) index) < (unsigned int) colours.size())
colours.getReference (index).colour = newColour;
}
const int integerPos = jlimit (0, 65535, roundToInt (position * 65536.0f));
const Colour ColourGradient::getColourAtPosition (const double position) const throw()
{
jassert (colours.getReference(0).position == 0); // the first colour specified has to go at position 0
if (integerPos <= 0 || colours.size() <= 1)
return getColour (0);
if (position <= 0 || colours.size() <= 1)
return colours.getReference(0).colour;
int i = colours.size() - 1;
while (integerPos < (int) colours.getReference(i).position)
while (position < colours.getReference(i).position)
--i;
const ColourPoint& p1 = colours.getReference (i);
if (i >= colours.size() - 1)
return colours.getReference(i).colour;
return p1.colour;
const ColourPoint& p1 = colours.getReference (i);
const ColourPoint& p2 = colours.getReference (i + 1);
return p1.colour.interpolatedWith (p2.colour, (integerPos - p1.position) / (float) (p2.position - p1.position));
return p1.colour.interpolatedWith (p2.colour, (float) ((position - p1.position) / (p2.position - p1.position)));
}
//==============================================================================
@@ -168,7 +175,7 @@ int ColourGradient::createLookupTable (const AffineTransform& transform, HeapBlo
for (int j = 1; j < colours.size(); ++j)
{
const ColourPoint& p = colours.getReference (j);
const int numToDo = ((p.position * (numEntries - 1)) >> 16) - index;
const int numToDo = roundToInt (p.position * (numEntries - 1)) - index;
const PixelARGB pix2 (p.colour.getPixelARGB());
for (int i = 0; i < numToDo; ++i)


+ 15
- 7
src/gui/graphics/colour/juce_ColourGradient.h View File

@@ -90,9 +90,13 @@ public:
of the distance along the line between the two points
at which the colour should occur.
@param colour the colour that should be used at this point
@returns the index at which the new point was added
*/
void addColour (double proportionAlongGradient,
const Colour& colour);
int addColour (double proportionAlongGradient,
const Colour& colour);
/** Removes one of the colours from the gradient. */
void removeColour (int index);
/** Multiplies the alpha value of all the colours by the given scale factor */
void multiplyOpacity (float multiplier) throw();
@@ -108,15 +112,19 @@ public:
double getColourPosition (int index) const throw();
/** Returns the colour that was added with a given index.
The index is from 0 to getNumColours() - 1. The return value will be between 0.0 and 1.0
The index is from 0 to getNumColours() - 1.
*/
const Colour getColour (int index) const throw();
/** Changes the colour at a given index.
The index is from 0 to getNumColours() - 1.
*/
void setColour (int index, const Colour& newColour) throw();
/** Returns the an interpolated colour at any position along the gradient.
@param position the position along the gradient, between 0 and 1
*/
const Colour getColourAtPosition (float position) const throw();
const Colour getColourAtPosition (double position) const throw();
//==============================================================================
/** Creates a set of interpolated premultiplied ARGB values.
@@ -152,14 +160,14 @@ private:
{
ColourPoint() throw() {}
ColourPoint (uint32 position_, const Colour& colour_) throw()
ColourPoint (const double position_, const Colour& colour_) throw()
: position (position_), colour (colour_)
{}
bool operator== (const ColourPoint& other) const throw() { return position == other.position && colour == other.colour; }
bool operator!= (const ColourPoint& other) const throw() { return position != other.position || colour != other.colour; }
uint32 position;
double position;
Colour colour;
};


+ 27
- 22
src/gui/graphics/drawables/juce_Drawable.cpp View File

@@ -158,10 +158,8 @@ Drawable* Drawable::createFromValueTree (const ValueTree& tree, ImageProvider* i
//==============================================================================
const Identifier Drawable::ValueTreeWrapperBase::idProperty ("id");
const Identifier Drawable::ValueTreeWrapperBase::type ("type");
const Identifier Drawable::ValueTreeWrapperBase::x1 ("x1");
const Identifier Drawable::ValueTreeWrapperBase::x2 ("x2");
const Identifier Drawable::ValueTreeWrapperBase::y1 ("y1");
const Identifier Drawable::ValueTreeWrapperBase::y2 ("y2");
const Identifier Drawable::ValueTreeWrapperBase::gradientPoint1 ("point1");
const Identifier Drawable::ValueTreeWrapperBase::gradientPoint2 ("point2");
const Identifier Drawable::ValueTreeWrapperBase::colour ("colour");
const Identifier Drawable::ValueTreeWrapperBase::radial ("radial");
const Identifier Drawable::ValueTreeWrapperBase::colours ("colours");
@@ -188,7 +186,8 @@ void Drawable::ValueTreeWrapperBase::setID (const String& newID, UndoManager* un
state.setProperty (idProperty, newID, undoManager);
}
const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v)
const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v, RelativePoint* gp1, RelativePoint* gp2,
RelativeCoordinate::NamedCoordinateFinder* nameFinder)
{
const String newType (v[type].toString());
@@ -200,9 +199,17 @@ const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v)
}
else if (newType == "gradient")
{
RelativePoint p1 (v [gradientPoint1]), p2 (v [gradientPoint2]);
ColourGradient g;
g.point1.setXY (v[x1], v[y1]);
g.point2.setXY (v[x2], v[y2]);
if (gp1 != 0)
*gp1 = p1;
if (gp2 != 0)
*gp2 = p2;
g.point1 = p1.resolve (nameFinder);
g.point2 = p2.resolve (nameFinder);
g.isRadial = v[radial];
StringArray colourSteps;
@@ -223,26 +230,24 @@ const FillType Drawable::ValueTreeWrapperBase::readFillType (const ValueTree& v)
return FillType();
}
void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType& fillType, UndoManager* const undoManager)
void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType& fillType,
const RelativePoint* gp1, const RelativePoint* gp2,
UndoManager* const undoManager)
{
if (fillType.isColour())
{
v.setProperty (type, "solid", undoManager);
v.setProperty (colour, String::toHexString ((int) fillType.colour.getARGB()), undoManager);
v.removeProperty (x1, undoManager);
v.removeProperty (x2, undoManager);
v.removeProperty (y1, undoManager);
v.removeProperty (y2, undoManager);
v.removeProperty (gradientPoint1, undoManager);
v.removeProperty (gradientPoint2, undoManager);
v.removeProperty (radial, undoManager);
v.removeProperty (colours, undoManager);
}
else if (fillType.isGradient())
{
v.setProperty (type, "gradient", undoManager);
v.setProperty (x1, fillType.gradient->point1.getX(), undoManager);
v.setProperty (y1, fillType.gradient->point1.getY(), undoManager);
v.setProperty (x2, fillType.gradient->point2.getX(), undoManager);
v.setProperty (y2, fillType.gradient->point2.getY(), undoManager);
v.setProperty (gradientPoint1, gp1 != 0 ? gp1->toString() : fillType.gradient->point1.toString(), undoManager);
v.setProperty (gradientPoint2, gp2 != 0 ? gp2->toString() : fillType.gradient->point2.toString(), undoManager);
v.setProperty (radial, fillType.gradient->isRadial, undoManager);
String s;
@@ -259,10 +264,8 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
jassertfalse; //xxx todo
v.removeProperty (x1, undoManager);
v.removeProperty (x2, undoManager);
v.removeProperty (y1, undoManager);
v.removeProperty (y2, undoManager);
v.removeProperty (gradientPoint1, undoManager);
v.removeProperty (gradientPoint2, undoManager);
v.removeProperty (radial, undoManager);
v.removeProperty (colours, undoManager);
v.removeProperty (colour, undoManager);
@@ -273,7 +276,9 @@ void Drawable::ValueTreeWrapperBase::writeFillType (ValueTree& v, const FillType
}
}
void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, const FillType& fillType, UndoManager* const undoManager)
void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, const FillType& fillType,
const RelativePoint* gp1, const RelativePoint* gp2,
UndoManager* const undoManager)
{
ValueTree v (state.getChildWithName (tag));
@@ -283,7 +288,7 @@ void Drawable::ValueTreeWrapperBase::replaceFillType (const Identifier& tag, con
v = state.getChildWithName (tag);
}
writeFillType (v, fillType, undoManager);
writeFillType (v, fillType, gp1, gp2, undoManager);
}


+ 10
- 4
src/gui/graphics/drawables/juce_Drawable.h View File

@@ -248,14 +248,20 @@ public:
void setID (const String& newID, UndoManager* undoManager);
static const Identifier idProperty;
static const FillType readFillType (const ValueTree& v);
static void writeFillType (ValueTree& v, const FillType& fillType, UndoManager* undoManager);
static const FillType readFillType (const ValueTree& v, RelativePoint* gradientPoint1, RelativePoint* gradientPoint2,
RelativeCoordinate::NamedCoordinateFinder* nameFinder);
static void writeFillType (ValueTree& v, const FillType& fillType,
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
UndoManager* undoManager);
protected:
ValueTree state;
static const Identifier type, x1, x2, y1, y2, colour, radial, colours;
static const Identifier type, gradientPoint1, gradientPoint2, colour, radial, colours;
void replaceFillType (const Identifier& tag, const FillType& fillType, UndoManager* undoManager);
void replaceFillType (const Identifier& tag, const FillType& fillType,
const RelativePoint* gradientPoint1, const RelativePoint* gradientPoint2,
UndoManager* undoManager);
};
//==============================================================================


+ 34
- 12
src/gui/graphics/drawables/juce_DrawablePath.cpp View File

@@ -197,24 +197,46 @@ DrawablePath::ValueTreeWrapper::ValueTreeWrapper (const ValueTree& state_)
jassert (state.hasType (valueTreeType));
}
const FillType DrawablePath::ValueTreeWrapper::getMainFill() const
ValueTree DrawablePath::ValueTreeWrapper::getMainFillState()
{
return readFillType (state.getChildWithName (fill));
ValueTree v (state.getChildWithName (fill));
if (v.isValid())
return v;
setMainFill (Colours::black, 0, 0, 0);
return getMainFillState();
}
ValueTree DrawablePath::ValueTreeWrapper::getStrokeFillState()
{
ValueTree v (state.getChildWithName (stroke));
if (v.isValid())
return v;
setStrokeFill (Colours::black, 0, 0, 0);
return getStrokeFillState();
}
const FillType DrawablePath::ValueTreeWrapper::getMainFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const
{
return readFillType (state.getChildWithName (fill), 0, 0, nameFinder);
}
void DrawablePath::ValueTreeWrapper::setMainFill (const FillType& newFill, UndoManager* undoManager)
void DrawablePath::ValueTreeWrapper::setMainFill (const FillType& newFill, const RelativePoint* gp1,
const RelativePoint* gp2, UndoManager* undoManager)
{
replaceFillType (fill, newFill, undoManager);
replaceFillType (fill, newFill, gp1, gp2, undoManager);
}
const FillType DrawablePath::ValueTreeWrapper::getStrokeFill() const
const FillType DrawablePath::ValueTreeWrapper::getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const
{
return readFillType (state.getChildWithName (stroke));
return readFillType (state.getChildWithName (stroke), 0, 0, nameFinder);
}
void DrawablePath::ValueTreeWrapper::setStrokeFill (const FillType& newFill, UndoManager* undoManager)
void DrawablePath::ValueTreeWrapper::setStrokeFill (const FillType& newFill, const RelativePoint* gp1,
const RelativePoint* gp2, UndoManager* undoManager)
{
replaceFillType (stroke, newFill, undoManager);
replaceFillType (stroke, newFill, gp1, gp2, undoManager);
}
const PathStrokeType DrawablePath::ValueTreeWrapper::getStrokeType() const
@@ -258,7 +280,7 @@ const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree
setName (v.getID());
bool needsRedraw = false;
const FillType newFill (v.getMainFill());
const FillType newFill (v.getMainFill (parent));
if (mainFill != newFill)
{
@@ -266,7 +288,7 @@ const Rectangle<float> DrawablePath::refreshFromValueTree (const ValueTree& tree
mainFill = newFill;
}
const FillType newStrokeFill (v.getStrokeFill());
const FillType newStrokeFill (v.getStrokeFill (parent));
if (strokeFill != newStrokeFill)
{
@@ -307,8 +329,8 @@ const ValueTree DrawablePath::createValueTree (ImageProvider*) const
ValueTreeWrapper v (tree);
v.setID (getName(), 0);
v.setMainFill (mainFill, 0);
v.setStrokeFill (strokeFill, 0);
v.setMainFill (mainFill, 0, 0, 0);
v.setStrokeFill (strokeFill, 0, 0, 0);
v.setStrokeType (strokeType, 0);
if (relativePath != 0)


+ 9
- 5
src/gui/graphics/drawables/juce_DrawablePath.h View File

@@ -128,11 +128,15 @@ public:
public:
ValueTreeWrapper (const ValueTree& state);
const FillType getMainFill() const;
void setMainFill (const FillType& newFill, UndoManager* undoManager);
const FillType getStrokeFill() const;
void setStrokeFill (const FillType& newFill, UndoManager* undoManager);
const FillType getMainFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const;
ValueTree getMainFillState();
void setMainFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, UndoManager* undoManager);
const FillType getStrokeFill (RelativeCoordinate::NamedCoordinateFinder* nameFinder) const;
ValueTree getStrokeFillState();
void setStrokeFill (const FillType& newFill, const RelativePoint* gradientPoint1,
const RelativePoint* gradientPoint2, UndoManager* undoManager);
const PathStrokeType getStrokeType() const;
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager* undoManager);


+ 481
- 482
src/native/linux/juce_linux_Network.cpp View File

@@ -1,482 +1,481 @@
/*
==============================================================================
This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-10 by Raw Material Software Ltd.
------------------------------------------------------------------------------
JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.
JUCE 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 General Public License for more details.
------------------------------------------------------------------------------
To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.
==============================================================================
*/
// (This file gets included by juce_linux_NativeCode.cpp, rather than being
// compiled on its own).
#if JUCE_INCLUDED_FILE
//==============================================================================
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
{
int numResults = 0;
const int s = socket (AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
char buf [1024];
struct ifconf ifc;
ifc.ifc_len = sizeof (buf);
ifc.ifc_buf = buf;
ioctl (s, SIOCGIFCONF, &ifc);
for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
{
struct ifreq ifr;
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);
if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0
&& numResults < maxNum)
{
int64 a = 0;
for (int j = 6; --j >= 0;)
a = (a << 8) | (uint8) ifr.ifr_hwaddr.sa_data [littleEndian ? j : (5 - j)];
*addresses++ = a;
++numResults;
}
}
close (s);
}
return numResults;
}
bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
const String& emailSubject,
const String& bodyText,
const StringArray& filesToAttach)
{
jassertfalse; // xxx todo
return false;
}
//==============================================================================
/** A HTTP input stream that uses sockets.
*/
class JUCE_HTTPSocketStream
{
public:
//==============================================================================
JUCE_HTTPSocketStream()
: readPosition (0),
socketHandle (-1),
levelsOfRedirection (0),
timeoutSeconds (15)
{
}
~JUCE_HTTPSocketStream()
{
closeSocket();
}
//==============================================================================
bool open (const String& url,
const String& headers,
const MemoryBlock& postData,
const bool isPost,
URL::OpenStreamProgressCallback* callback,
void* callbackContext,
int timeOutMs)
{
closeSocket();
uint32 timeOutTime = Time::getMillisecondCounter();
if (timeOutMs == 0)
timeOutTime += 60000;
else if (timeOutMs < 0)
timeOutTime = 0xffffffff;
else
timeOutTime += timeOutMs;
String hostName, hostPath;
int hostPort;
if (! decomposeURL (url, hostName, hostPath, hostPort))
return false;
const struct hostent* host = 0;
int port = 0;
String proxyName, proxyPath;
int proxyPort = 0;
String proxyURL (getenv ("http_proxy"));
if (proxyURL.startsWithIgnoreCase ("http://"))
{
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
return false;
host = gethostbyname (proxyName.toUTF8());
port = proxyPort;
}
else
{
host = gethostbyname (hostName.toUTF8());
port = hostPort;
}
if (host == 0)
return false;
struct sockaddr_in address;
zerostruct (address);
memcpy (&address.sin_addr, host->h_addr, host->h_length);
address.sin_family = host->h_addrtype;
address.sin_port = htons (port);
socketHandle = socket (host->h_addrtype, SOCK_STREAM, 0);
if (socketHandle == -1)
return false;
int receiveBufferSize = 16384;
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);
#if JUCE_MAC
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
#endif
if (connect (socketHandle, (struct sockaddr*) &address, sizeof (address)) == -1)
{
closeSocket();
return false;
}
const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort,
proxyName, proxyPort,
hostPath, url,
headers, postData,
isPost));
size_t totalHeaderSent = 0;
while (totalHeaderSent < requestHeader.getSize())
{
if (Time::getMillisecondCounter() > timeOutTime)
{
closeSocket();
return false;
}
const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));
if (send (socketHandle,
((const char*) requestHeader.getData()) + totalHeaderSent,
numToSend, 0)
!= numToSend)
{
closeSocket();
return false;
}
totalHeaderSent += numToSend;
if (callback != 0 && ! callback (callbackContext, totalHeaderSent, requestHeader.getSize()))
{
closeSocket();
return false;
}
}
const String responseHeader (readResponse (timeOutTime));
if (responseHeader.isNotEmpty())
{
//DBG (responseHeader);
StringArray lines;
lines.addLines (responseHeader);
const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
.substring (0, 3).getIntValue();
//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");
String location (findHeaderItem (lines, "Location:"));
if (statusCode >= 300 && statusCode < 400
&& location.isNotEmpty())
{
if (! location.startsWithIgnoreCase ("http://"))
location = "http://" + location;
if (levelsOfRedirection++ < 3)
return open (location, headers, postData, isPost, callback, callbackContext, timeOutMs);
}
else
{
levelsOfRedirection = 0;
return true;
}
}
closeSocket();
return false;
}
//==============================================================================
int read (void* buffer, int bytesToRead)
{
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = timeoutSeconds;
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return 0; // (timeout)
const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
readPosition += bytesRead;
return bytesRead;
}
//==============================================================================
int readPosition;
//==============================================================================
juce_UseDebuggingNewOperator
private:
int socketHandle, levelsOfRedirection;
const int timeoutSeconds;
//==============================================================================
void closeSocket()
{
if (socketHandle >= 0)
close (socketHandle);
socketHandle = -1;
}
const MemoryBlock createRequestHeader (const String& hostName,
const int hostPort,
const String& proxyName,
const int proxyPort,
const String& hostPath,
const String& originalURL,
const String& headers,
const MemoryBlock& postData,
const bool isPost)
{
String header (isPost ? "POST " : "GET ");
if (proxyName.isEmpty())
{
header << hostPath << " HTTP/1.0\r\nHost: "
<< hostName << ':' << hostPort;
}
else
{
header << originalURL << " HTTP/1.0\r\nHost: "
<< proxyName << ':' << proxyPort;
}
header << "\r\nUser-Agent: JUCE/"
<< JUCE_MAJOR_VERSION << '.' << JUCE_MINOR_VERSION
<< "\r\nConnection: Close\r\nContent-Length: "
<< postData.getSize() << "\r\n"
<< headers << "\r\n";
MemoryBlock mb;
mb.append (header.toUTF8(), (int) strlen (header.toUTF8()));
mb.append (postData.getData(), postData.getSize());
return mb;
}
const String readResponse (const uint32 timeOutTime)
{
int bytesRead = 0, numConsecutiveLFs = 0;
MemoryBlock buffer (1024, true);
while (numConsecutiveLFs < 2 && bytesRead < 32768
&& Time::getMillisecondCounter() <= timeOutTime)
{
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);
struct timeval tv;
tv.tv_sec = timeoutSeconds;
tv.tv_usec = 0;
if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return String::empty; // (timeout)
buffer.ensureSize (bytesRead + 8, true);
char* const dest = (char*) buffer.getData() + bytesRead;
if (recv (socketHandle, dest, 1, 0) == -1)
return String::empty;
const char lastByte = *dest;
++bytesRead;
if (lastByte == '\n')
++numConsecutiveLFs;
else if (lastByte != '\r')
numConsecutiveLFs = 0;
}
const String header (String::fromUTF8 ((const char*) buffer.getData()));
if (header.startsWithIgnoreCase ("HTTP/"))
return header.trimEnd();
return String::empty;
}
//==============================================================================
static bool decomposeURL (const String& url,
String& host, String& path, int& port)
{
if (! url.startsWithIgnoreCase ("http://"))
return false;
const int nextSlash = url.indexOfChar (7, '/');
int nextColon = url.indexOfChar (7, ':');
if (nextColon > nextSlash && nextSlash > 0)
nextColon = -1;
if (nextColon >= 0)
{
host = url.substring (7, nextColon);
if (nextSlash >= 0)
port = url.substring (nextColon + 1, nextSlash).getIntValue();
else
port = url.substring (nextColon + 1).getIntValue();
}
else
{
port = 80;
if (nextSlash >= 0)
host = url.substring (7, nextSlash);
else
host = url.substring (7);
}
if (nextSlash >= 0)
path = url.substring (nextSlash);
else
path = "/";
return true;
}
//==============================================================================
static const String findHeaderItem (const StringArray& lines, const String& itemName)
{
for (int i = 0; i < lines.size(); ++i)
if (lines[i].startsWithIgnoreCase (itemName))
return lines[i].substring (itemName.length()).trim();
return String::empty;
}
};
//==============================================================================
void* juce_openInternetFile (const String& url,
const String& headers,
const MemoryBlock& postData,
const bool isPost,
URL::OpenStreamProgressCallback* callback,
void* callbackContext,
int timeOutMs)
{
JUCE_HTTPSocketStream* const s = new JUCE_HTTPSocketStream();
if (s->open (url, headers, postData, isPost,
callback, callbackContext, timeOutMs))
return s;
delete s;
return 0;
}
void juce_closeInternetFile (void* handle)
{
delete static_cast <JUCE_HTTPSocketStream*> (handle);
}
int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
{
JUCE_HTTPSocketStream* const s = (JUCE_HTTPSocketStream*) handle;
if (s != 0)
return s->read (buffer, bytesToRead);
return 0;
}
int64 juce_getInternetFileContentLength (void* handle)
{
JUCE_HTTPSocketStream* const s = (JUCE_HTTPSocketStream*) handle;
if (s != 0)
{
//xxx todo
jassertfalse;
}
return -1;
}
void juce_getInternetFileHeaders (void* handle, StringPairArray& headers)
{
JUCE_HTTPSocketStream* const s = (JUCE_HTTPSocketStream*) handle;
if (s != 0)
{
// xxx todo
jassertfalse;
}
}
int juce_seekInInternetFile (void* handle, int newPosition)
{
JUCE_HTTPSocketStream* const s = (JUCE_HTTPSocketStream*) handle;
if (s != 0)
return s->readPosition;
return 0;
}
#endif
/*
==============================================================================

This file is part of the JUCE library - "Jules' Utility Class Extensions"
Copyright 2004-10 by Raw Material Software Ltd.

------------------------------------------------------------------------------

JUCE can be redistributed and/or modified under the terms of the GNU General
Public License (Version 2), as published by the Free Software Foundation.
A copy of the license is included in the JUCE distribution, or can be found
online at www.gnu.org/licenses.

JUCE 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 General Public License for more details.

------------------------------------------------------------------------------

To release a closed-source product which uses JUCE, commercial licenses are
available: visit www.rawmaterialsoftware.com/juce for more information.

==============================================================================
*/

// (This file gets included by juce_linux_NativeCode.cpp, rather than being
// compiled on its own).
#if JUCE_INCLUDED_FILE


//==============================================================================
int SystemStats::getMACAddresses (int64* addresses, int maxNum, const bool littleEndian)
{
int numResults = 0;

const int s = socket (AF_INET, SOCK_DGRAM, 0);
if (s != -1)
{
char buf [1024];
struct ifconf ifc;
ifc.ifc_len = sizeof (buf);
ifc.ifc_buf = buf;
ioctl (s, SIOCGIFCONF, &ifc);

for (unsigned int i = 0; i < ifc.ifc_len / sizeof (struct ifreq); ++i)
{
struct ifreq ifr;
strcpy (ifr.ifr_name, ifc.ifc_req[i].ifr_name);

if (ioctl (s, SIOCGIFFLAGS, &ifr) == 0
&& (ifr.ifr_flags & IFF_LOOPBACK) == 0
&& ioctl (s, SIOCGIFHWADDR, &ifr) == 0
&& numResults < maxNum)
{
int64 a = 0;
for (int j = 6; --j >= 0;)
a = (a << 8) | (uint8) ifr.ifr_hwaddr.sa_data [littleEndian ? j : (5 - j)];

*addresses++ = a;
++numResults;
}
}

close (s);
}

return numResults;
}


bool PlatformUtilities::launchEmailWithAttachments (const String& targetEmailAddress,
const String& emailSubject,
const String& bodyText,
const StringArray& filesToAttach)
{
jassertfalse; // xxx todo

return false;
}

//==============================================================================
/** A HTTP input stream that uses sockets.
*/
class JUCE_HTTPSocketStream
{
public:
//==============================================================================
JUCE_HTTPSocketStream()
: readPosition (0),
socketHandle (-1),
levelsOfRedirection (0),
timeoutSeconds (15)
{
}

~JUCE_HTTPSocketStream()
{
closeSocket();
}

//==============================================================================
bool open (const String& url,
const String& headers,
const MemoryBlock& postData,
const bool isPost,
URL::OpenStreamProgressCallback* callback,
void* callbackContext,
int timeOutMs)
{
closeSocket();

uint32 timeOutTime = Time::getMillisecondCounter();

if (timeOutMs == 0)
timeOutTime += 60000;
else if (timeOutMs < 0)
timeOutTime = 0xffffffff;
else
timeOutTime += timeOutMs;

String hostName, hostPath;
int hostPort;

if (! decomposeURL (url, hostName, hostPath, hostPort))
return false;

const struct hostent* host = 0;
int port = 0;

String proxyName, proxyPath;
int proxyPort = 0;

String proxyURL (getenv ("http_proxy"));
if (proxyURL.startsWithIgnoreCase ("http://"))
{
if (! decomposeURL (proxyURL, proxyName, proxyPath, proxyPort))
return false;

host = gethostbyname (proxyName.toUTF8());
port = proxyPort;
}
else
{
host = gethostbyname (hostName.toUTF8());
port = hostPort;
}

if (host == 0)
return false;

struct sockaddr_in address;
zerostruct (address);
memcpy (&address.sin_addr, host->h_addr, host->h_length);
address.sin_family = host->h_addrtype;
address.sin_port = htons (port);

socketHandle = socket (host->h_addrtype, SOCK_STREAM, 0);

if (socketHandle == -1)
return false;

int receiveBufferSize = 16384;
setsockopt (socketHandle, SOL_SOCKET, SO_RCVBUF, (char*) &receiveBufferSize, sizeof (receiveBufferSize));
setsockopt (socketHandle, SOL_SOCKET, SO_KEEPALIVE, 0, 0);

#if JUCE_MAC
setsockopt (socketHandle, SOL_SOCKET, SO_NOSIGPIPE, 0, 0);
#endif

if (connect (socketHandle, (struct sockaddr*) &address, sizeof (address)) == -1)
{
closeSocket();
return false;
}

const MemoryBlock requestHeader (createRequestHeader (hostName, hostPort,
proxyName, proxyPort,
hostPath, url,
headers, postData,
isPost));
size_t totalHeaderSent = 0;

while (totalHeaderSent < requestHeader.getSize())
{
if (Time::getMillisecondCounter() > timeOutTime)
{
closeSocket();
return false;
}

const int numToSend = jmin (1024, (int) (requestHeader.getSize() - totalHeaderSent));

if (send (socketHandle,
((const char*) requestHeader.getData()) + totalHeaderSent,
numToSend, 0)
!= numToSend)
{
closeSocket();
return false;
}

totalHeaderSent += numToSend;

if (callback != 0 && ! callback (callbackContext, totalHeaderSent, requestHeader.getSize()))
{
closeSocket();
return false;
}
}

const String responseHeader (readResponse (timeOutTime));

if (responseHeader.isNotEmpty())
{
//DBG (responseHeader);

headerLines.clear();
headerLines.addLines (responseHeader);

const int statusCode = responseHeader.fromFirstOccurrenceOf (" ", false, false)
.substring (0, 3).getIntValue();

//int contentLength = findHeaderItem (lines, "Content-Length:").getIntValue();
//bool isChunked = findHeaderItem (lines, "Transfer-Encoding:").equalsIgnoreCase ("chunked");

String location (findHeaderItem (headerLines, "Location:"));

if (statusCode >= 300 && statusCode < 400
&& location.isNotEmpty())
{
if (! location.startsWithIgnoreCase ("http://"))
location = "http://" + location;

if (levelsOfRedirection++ < 3)
return open (location, headers, postData, isPost, callback, callbackContext, timeOutMs);
}
else
{
levelsOfRedirection = 0;
return true;
}
}

closeSocket();
return false;
}

//==============================================================================
int read (void* buffer, int bytesToRead)
{
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);

struct timeval tv;
tv.tv_sec = timeoutSeconds;
tv.tv_usec = 0;

if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return 0; // (timeout)

const int bytesRead = jmax (0, (int) recv (socketHandle, buffer, bytesToRead, MSG_WAITALL));
readPosition += bytesRead;
return bytesRead;
}

//==============================================================================
int readPosition;
StringArray headerLines;

//==============================================================================
juce_UseDebuggingNewOperator

private:
int socketHandle, levelsOfRedirection;
const int timeoutSeconds;

//==============================================================================
void closeSocket()
{
if (socketHandle >= 0)
close (socketHandle);

socketHandle = -1;
}

const MemoryBlock createRequestHeader (const String& hostName,
const int hostPort,
const String& proxyName,
const int proxyPort,
const String& hostPath,
const String& originalURL,
const String& headers,
const MemoryBlock& postData,
const bool isPost)
{
String header (isPost ? "POST " : "GET ");

if (proxyName.isEmpty())
{
header << hostPath << " HTTP/1.0\r\nHost: "
<< hostName << ':' << hostPort;
}
else
{
header << originalURL << " HTTP/1.0\r\nHost: "
<< proxyName << ':' << proxyPort;
}

header << "\r\nUser-Agent: JUCE/"
<< JUCE_MAJOR_VERSION << '.' << JUCE_MINOR_VERSION
<< "\r\nConnection: Close\r\nContent-Length: "
<< postData.getSize() << "\r\n"
<< headers << "\r\n";

MemoryBlock mb;
mb.append (header.toUTF8(), (int) strlen (header.toUTF8()));
mb.append (postData.getData(), postData.getSize());

return mb;
}

const String readResponse (const uint32 timeOutTime)
{
int bytesRead = 0, numConsecutiveLFs = 0;
MemoryBlock buffer (1024, true);

while (numConsecutiveLFs < 2 && bytesRead < 32768
&& Time::getMillisecondCounter() <= timeOutTime)
{
fd_set readbits;
FD_ZERO (&readbits);
FD_SET (socketHandle, &readbits);

struct timeval tv;
tv.tv_sec = timeoutSeconds;
tv.tv_usec = 0;

if (select (socketHandle + 1, &readbits, 0, 0, &tv) <= 0)
return String::empty; // (timeout)

buffer.ensureSize (bytesRead + 8, true);
char* const dest = (char*) buffer.getData() + bytesRead;

if (recv (socketHandle, dest, 1, 0) == -1)
return String::empty;

const char lastByte = *dest;
++bytesRead;

if (lastByte == '\n')
++numConsecutiveLFs;
else if (lastByte != '\r')
numConsecutiveLFs = 0;
}

const String header (String::fromUTF8 ((const char*) buffer.getData()));

if (header.startsWithIgnoreCase ("HTTP/"))
return header.trimEnd();

return String::empty;
}

//==============================================================================
static bool decomposeURL (const String& url,
String& host, String& path, int& port)
{
if (! url.startsWithIgnoreCase ("http://"))
return false;

const int nextSlash = url.indexOfChar (7, '/');
int nextColon = url.indexOfChar (7, ':');
if (nextColon > nextSlash && nextSlash > 0)
nextColon = -1;

if (nextColon >= 0)
{
host = url.substring (7, nextColon);

if (nextSlash >= 0)
port = url.substring (nextColon + 1, nextSlash).getIntValue();
else
port = url.substring (nextColon + 1).getIntValue();
}
else
{
port = 80;

if (nextSlash >= 0)
host = url.substring (7, nextSlash);
else
host = url.substring (7);
}

if (nextSlash >= 0)
path = url.substring (nextSlash);
else
path = "/";

return true;
}

//==============================================================================
static const String findHeaderItem (const StringArray& lines, const String& itemName)
{
for (int i = 0; i < lines.size(); ++i)
if (lines[i].startsWithIgnoreCase (itemName))
return lines[i].substring (itemName.length()).trim();

return String::empty;
}
};

//==============================================================================
void* juce_openInternetFile (const String& url,
const String& headers,
const MemoryBlock& postData,
const bool isPost,
URL::OpenStreamProgressCallback* callback,
void* callbackContext,
int timeOutMs)
{
ScopedPointer<JUCE_HTTPSocketStream> s (new JUCE_HTTPSocketStream());

if (s->open (url, headers, postData, isPost, callback, callbackContext, timeOutMs))
return s.release();

return 0;
}

void juce_closeInternetFile (void* handle)
{
delete static_cast <JUCE_HTTPSocketStream*> (handle);
}

int juce_readFromInternetFile (void* handle, void* buffer, int bytesToRead)
{
JUCE_HTTPSocketStream* const s = static_cast <JUCE_HTTPSocketStream*> (handle);

return s != 0 ? s->read (buffer, bytesToRead) : 0;
}

int64 juce_getInternetFileContentLength (void* handle)
{
JUCE_HTTPSocketStream* const s = static_cast <JUCE_HTTPSocketStream*> (handle);

if (s != 0)
{
//xxx todo
jassertfalse
}

return -1;
}

bool juce_getInternetFileHeaders (void* handle, StringPairArray& headers)
{
JUCE_HTTPSocketStream* const s = static_cast <JUCE_HTTPSocketStream*> (handle);

if (s != 0)
{
for (int i = 0; i < s->headerLines.size(); ++i)
{
const String& headersEntry = s->headerLines[i];
const String key (headersEntry.upToFirstOccurrenceOf (": ", false, false));
const String value (headersEntry.fromFirstOccurrenceOf (": ", false, false));
const String previousValue (headers [key]);
headers.set (key, previousValue.isEmpty() ? value : (previousValue + ";" + value));
}
}
}

int juce_seekInInternetFile (void* handle, int newPosition)
{
JUCE_HTTPSocketStream* const s = static_cast <JUCE_HTTPSocketStream*> (handle);

return s != 0 ? s->readPosition : 0;
}

#endif

Loading…
Cancel
Save