Browse Source

Tweaks to streams and gzip compressor.

tags/2021-05-28
Julian Storer 14 years ago
parent
commit
9a9f570781
27 changed files with 445 additions and 448 deletions
  1. +12
    -20
      modules/juce_core/files/juce_File.cpp
  2. +2
    -0
      modules/juce_core/files/juce_FileInputStream.cpp
  3. +12
    -2
      modules/juce_core/files/juce_FileInputStream.h
  4. +2
    -0
      modules/juce_core/files/juce_FileOutputStream.cpp
  5. +7
    -5
      modules/juce_core/files/juce_FileOutputStream.h
  6. +2
    -0
      modules/juce_core/native/juce_android_Network.cpp
  7. +2
    -0
      modules/juce_core/native/juce_mac_Network.mm
  8. +2
    -0
      modules/juce_core/native/juce_posix_SharedCode.h
  9. +1
    -0
      modules/juce_core/native/juce_win32_Network.cpp
  10. +2
    -0
      modules/juce_core/streams/juce_BufferedInputStream.cpp
  11. +1
    -1
      modules/juce_core/streams/juce_InputStream.cpp
  12. +3
    -3
      modules/juce_core/streams/juce_InputStream.h
  13. +2
    -1
      modules/juce_core/streams/juce_MemoryInputStream.cpp
  14. +2
    -0
      modules/juce_core/streams/juce_MemoryOutputStream.cpp
  15. +6
    -4
      modules/juce_core/streams/juce_OutputStream.cpp
  16. +6
    -1
      modules/juce_core/streams/juce_OutputStream.h
  17. +2
    -0
      modules/juce_core/streams/juce_SubregionStream.cpp
  18. +58
    -80
      modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp
  19. +11
    -3
      modules/juce_core/zip/juce_GZIPCompressorOutputStream.h
  20. +30
    -33
      modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp
  21. +46
    -41
      modules/juce_core/zip/juce_ZipFile.cpp
  22. +9
    -8
      modules/juce_core/zip/juce_ZipFile.h
  23. +1
    -1
      modules/juce_graphics/image_formats/juce_JPEGLoader.cpp
  24. +3
    -3
      modules/juce_gui_basics/drawables/juce_Drawable.cpp
  25. +12
    -17
      modules/juce_gui_basics/layout/juce_ScrollBar.cpp
  26. +203
    -223
      modules/juce_gui_basics/widgets/juce_Slider.cpp
  27. +6
    -2
      modules/juce_gui_basics/widgets/juce_Slider.h

+ 12
- 20
modules/juce_core/files/juce_File.cpp View File

@@ -688,27 +688,21 @@ FileInputStream* File::createInputStream() const
FileOutputStream* File::createOutputStream (const int bufferSize) const FileOutputStream* File::createOutputStream (const int bufferSize) const
{ {
ScopedPointer <FileOutputStream> out (new FileOutputStream (*this, bufferSize));
ScopedPointer<FileOutputStream> out (new FileOutputStream (*this, bufferSize));
if (out->failedToOpen())
return nullptr;
return out.release();
return out->failedToOpen() ? nullptr
: out.release();
} }
//============================================================================== //==============================================================================
bool File::appendData (const void* const dataToAppend, bool File::appendData (const void* const dataToAppend,
const int numberOfBytes) const const int numberOfBytes) const
{ {
if (numberOfBytes > 0)
{
FileOutputStream out (*this, 8192);
return (! out.failedToOpen())
&& out.write (dataToAppend, numberOfBytes);
}
if (numberOfBytes <= 0)
return true;
return true;
FileOutputStream out (*this, 8192);
return out.openedOk() && out.write (dataToAppend, numberOfBytes);
} }
bool File::replaceWithData (const void* const dataToWrite, bool File::replaceWithData (const void* const dataToWrite,
@@ -728,15 +722,13 @@ bool File::appendText (const String& text,
const bool asUnicode, const bool asUnicode,
const bool writeUnicodeHeaderBytes) const const bool writeUnicodeHeaderBytes) const
{ {
const ScopedPointer <FileOutputStream> out (createOutputStream());
FileOutputStream out (*this);
if (out != nullptr)
{
out->writeText (text, asUnicode, writeUnicodeHeaderBytes);
return true;
}
if (out.failedToOpen())
return false;
return false;
out.writeText (text, asUnicode, writeUnicodeHeaderBytes);
return true;
} }
bool File::replaceWithText (const String& textToWrite, bool File::replaceWithText (const String& textToWrite,


+ 2
- 0
modules/juce_core/files/juce_FileInputStream.cpp View File

@@ -53,6 +53,8 @@ int64 FileInputStream::getTotalLength()
int FileInputStream::read (void* buffer, int bytesToRead) int FileInputStream::read (void* buffer, int bytesToRead)
{ {
jassert (buffer != nullptr && bytesToRead >= 0);
if (needToSeek) if (needToSeek)
{ {
if (juce_fileSetPosition (fileHandle, currentPosition) < 0) if (juce_fileSetPosition (fileHandle, currentPosition) < 0)


+ 12
- 2
modules/juce_core/files/juce_FileInputStream.h View File

@@ -58,7 +58,18 @@ public:
The result will be ok if the file opened successfully. If an error occurs while The result will be ok if the file opened successfully. If an error occurs while
opening or reading from the file, this will contain an error message. opening or reading from the file, this will contain an error message.
*/ */
Result getStatus() const { return status; }
const Result& getStatus() const noexcept { return status; }
/** Returns true if the stream couldn't be opened for some reason.
@see getResult()
*/
bool failedToOpen() const noexcept { return status.failed(); }
/** Returns true if the stream opened without problems.
@see getResult()
*/
bool openedOk() const noexcept { return status.wasOk(); }
//============================================================================== //==============================================================================
int64 getTotalLength(); int64 getTotalLength();
@@ -67,7 +78,6 @@ public:
int64 getPosition(); int64 getPosition();
bool setPosition (int64 pos); bool setPosition (int64 pos);
private: private:
//============================================================================== //==============================================================================
File file; File file;


+ 2
- 0
modules/juce_core/files/juce_FileOutputStream.cpp View File

@@ -84,6 +84,8 @@ void FileOutputStream::flush()
bool FileOutputStream::write (const void* const src, const int numBytes) bool FileOutputStream::write (const void* const src, const int numBytes)
{ {
jassert (src != nullptr && numBytes >= 0);
if (bytesInBuffer + numBytes < bufferSize) if (bytesInBuffer + numBytes < bufferSize)
{ {
memcpy (buffer + bytesInBuffer, src, (size_t) numBytes); memcpy (buffer + bytesInBuffer, src, (size_t) numBytes);


+ 7
- 5
modules/juce_core/files/juce_FileOutputStream.h View File

@@ -51,9 +51,6 @@ public:
use File::deleteFile() before opening the stream, or use setPosition(0) use File::deleteFile() before opening the stream, or use setPosition(0)
after it's opened (although this won't truncate the file). after it's opened (although this won't truncate the file).
It's better to use File::createOutputStream() to create one of these, rather
than using the class directly.
@see TemporaryFile @see TemporaryFile
*/ */
FileOutputStream (const File& fileToWriteTo, FileOutputStream (const File& fileToWriteTo,
@@ -71,12 +68,17 @@ public:
The result will be ok if the file opened successfully. If an error occurs while The result will be ok if the file opened successfully. If an error occurs while
opening or writing to the file, this will contain an error message. opening or writing to the file, this will contain an error message.
*/ */
Result getStatus() const { return status; }
const Result& getStatus() const noexcept { return status; }
/** Returns true if the stream couldn't be opened for some reason. /** Returns true if the stream couldn't be opened for some reason.
@see getResult() @see getResult()
*/ */
bool failedToOpen() const { return status.failed(); }
bool failedToOpen() const noexcept { return status.failed(); }
/** Returns true if the stream opened without problems.
@see getResult()
*/
bool openedOk() const noexcept { return status.wasOk(); }
//============================================================================== //==============================================================================
void flush(); void flush();


+ 2
- 0
modules/juce_core/native/juce_android_Network.cpp View File

@@ -136,6 +136,8 @@ public:
int read (void* buffer, int bytesToRead) int read (void* buffer, int bytesToRead)
{ {
jassert (buffer != nullptr && bytesToRead >= 0);
if (stream == nullptr) if (stream == nullptr)
return 0; return 0;


+ 2
- 0
modules/juce_core/native/juce_mac_Network.mm View File

@@ -361,6 +361,8 @@ public:
int read (void* buffer, int bytesToRead) int read (void* buffer, int bytesToRead)
{ {
jassert (buffer != nullptr && bytesToRead >= 0);
if (finished || isError()) if (finished || isError())
{ {
return 0; return 0;


+ 2
- 0
modules/juce_core/native/juce_posix_SharedCode.h View File

@@ -988,6 +988,8 @@ public:
int read (void* const dest, const int numBytes) int read (void* const dest, const int numBytes)
{ {
jassert (dest != nullptr);
if (readHandle == 0 && childPID != 0) if (readHandle == 0 && childPID != 0)
readHandle = fdopen (pipeHandle, "r"); readHandle = fdopen (pipeHandle, "r");


+ 1
- 0
modules/juce_core/native/juce_win32_Network.cpp View File

@@ -145,6 +145,7 @@ public:
int read (void* buffer, int bytesToRead) int read (void* buffer, int bytesToRead)
{ {
jassert (buffer != nullptr && bytesToRead >= 0);
DWORD bytesRead = 0; DWORD bytesRead = 0;
if (! (finished || isError())) if (! (finished || isError()))


+ 2
- 0
modules/juce_core/streams/juce_BufferedInputStream.cpp View File

@@ -131,6 +131,8 @@ void BufferedInputStream::ensureBuffered()
int BufferedInputStream::read (void* destBuffer, int maxBytesToRead) int BufferedInputStream::read (void* destBuffer, int maxBytesToRead)
{ {
jassert (destBuffer != nullptr && maxBytesToRead >= 0);
if (position >= bufferStart if (position >= bufferStart
&& position + maxBytesToRead <= lastReadPos) && position + maxBytesToRead <= lastReadPos)
{ {


+ 1
- 1
modules/juce_core/streams/juce_InputStream.cpp View File

@@ -208,7 +208,7 @@ int InputStream::readIntoMemoryBlock (MemoryBlock& block, int numBytes)
String InputStream::readEntireStreamAsString() String InputStream::readEntireStreamAsString()
{ {
MemoryOutputStream mo; MemoryOutputStream mo;
mo.writeFromInputStream (*this, -1);
mo << *this;
return mo.toString(); return mo.toString();
} }


+ 3
- 3
modules/juce_core/streams/juce_InputStream.h View File

@@ -59,16 +59,16 @@ public:
virtual bool isExhausted() = 0; virtual bool isExhausted() = 0;
//============================================================================== //==============================================================================
/** Reads a set of bytes from the stream into a memory buffer.
/** Reads some data from the stream into a memory buffer.
This is the only read method that subclasses actually need to implement, as the This is the only read method that subclasses actually need to implement, as the
InputStream base class implements the other read methods in terms of this one (although InputStream base class implements the other read methods in terms of this one (although
it's often more efficient for subclasses to implement them directly). it's often more efficient for subclasses to implement them directly).
@param destBuffer the destination buffer for the data
@param destBuffer the destination buffer for the data. This must not be null.
@param maxBytesToRead the maximum number of bytes to read - make sure the @param maxBytesToRead the maximum number of bytes to read - make sure the
memory block passed in is big enough to contain this memory block passed in is big enough to contain this
many bytes.
many bytes. This value must not be negative.
@returns the actual number of bytes that were read, which may be less than @returns the actual number of bytes that were read, which may be less than
maxBytesToRead if the stream is exhausted before it gets that far maxBytesToRead if the stream is exhausted before it gets that far


+ 2
- 1
modules/juce_core/streams/juce_MemoryInputStream.cpp View File

@@ -65,7 +65,8 @@ int64 MemoryInputStream::getTotalLength()
int MemoryInputStream::read (void* const buffer, const int howMany) int MemoryInputStream::read (void* const buffer, const int howMany)
{ {
jassert (howMany >= 0);
jassert (buffer != nullptr && howMany >= 0);
const int num = jmin (howMany, (int) (dataSize - position)); const int num = jmin (howMany, (int) (dataSize - position));
if (num <= 0) if (num <= 0)
return 0; return 0;


+ 2
- 0
modules/juce_core/streams/juce_MemoryOutputStream.cpp View File

@@ -81,6 +81,8 @@ void MemoryOutputStream::prepareToWrite (int numBytes)
bool MemoryOutputStream::write (const void* const buffer, int howMany) bool MemoryOutputStream::write (const void* const buffer, int howMany)
{ {
jassert (buffer != nullptr && howMany >= 0);
if (howMany > 0) if (howMany > 0)
{ {
prepareToWrite (howMany); prepareToWrite (howMany);


+ 6
- 4
modules/juce_core/streams/juce_OutputStream.cpp View File

@@ -298,11 +298,13 @@ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock&
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead) OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead)
{ {
const ScopedPointer<FileInputStream> in (fileToRead.createInputStream());
if (in != nullptr)
stream.writeFromInputStream (*in, -1);
FileInputStream in (fileToRead);
return stream << in;
}
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead)
{
stream.writeFromInputStream (streamToRead, -1);
return stream; return stream;
} }


+ 6
- 1
modules/juce_core/streams/juce_OutputStream.h View File

@@ -83,10 +83,12 @@ public:
that needs to be overloaded - the base class has methods for writing other that needs to be overloaded - the base class has methods for writing other
types of data which use this to do the work. types of data which use this to do the work.
@param dataToWrite the target buffer to receive the data. This must not be null.
@param numberOfBytes the number of bytes to write. This must not be negative.
@returns false if the write operation fails for some reason @returns false if the write operation fails for some reason
*/ */
virtual bool write (const void* dataToWrite, virtual bool write (const void* dataToWrite,
int howManyBytes) = 0;
int numberOfBytes) = 0;
//============================================================================== //==============================================================================
/** Writes a single byte to the stream. /** Writes a single byte to the stream.
@@ -243,6 +245,9 @@ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock&
/** Writes the contents of a file to a stream. */ /** Writes the contents of a file to a stream. */
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead); OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead);
/** Writes the complete contents of an input stream to an output stream. */
OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, InputStream& streamToRead);
/** Writes a new-line to a stream. /** Writes a new-line to a stream.
You can use the predefined symbol 'newLine' to invoke this, e.g. You can use the predefined symbol 'newLine' to invoke this, e.g.
@code @code


+ 2
- 0
modules/juce_core/streams/juce_SubregionStream.cpp View File

@@ -61,6 +61,8 @@ bool SubregionStream::setPosition (int64 newPosition)
int SubregionStream::read (void* destBuffer, int maxBytesToRead) int SubregionStream::read (void* destBuffer, int maxBytesToRead)
{ {
jassert (destBuffer != nullptr && maxBytesToRead >= 0);
if (lengthOfSourceStream < 0) if (lengthOfSourceStream < 0)
{ {
return source->read (destBuffer, maxBytesToRead); return source->read (destBuffer, maxBytesToRead);


+ 58
- 80
modules/juce_core/zip/juce_GZIPCompressorOutputStream.cpp View File

@@ -42,14 +42,12 @@ class GZIPCompressorOutputStream::GZIPCompressorHelper
{ {
public: public:
GZIPCompressorHelper (const int compressionLevel, const int windowBits) GZIPCompressorHelper (const int compressionLevel, const int windowBits)
: data (nullptr),
dataSize (0),
: buffer ((size_t) gzipCompBufferSize),
compLevel (compressionLevel), compLevel (compressionLevel),
strategy (0), strategy (0),
setParams (true),
isFirstDeflate (true),
streamIsValid (false), streamIsValid (false),
finished (false),
shouldFinish (false)
finished (false)
{ {
using namespace zlibNamespace; using namespace zlibNamespace;
zerostruct (stream); zerostruct (stream);
@@ -61,67 +59,74 @@ public:
~GZIPCompressorHelper() ~GZIPCompressorHelper()
{ {
using namespace zlibNamespace;
if (streamIsValid) if (streamIsValid)
deflateEnd (&stream);
zlibNamespace::deflateEnd (&stream);
} }
bool needsInput() const noexcept
bool write (const uint8* data, int dataSize, OutputStream& destStream)
{ {
return dataSize <= 0;
// When you call flush() on a gzip stream, the stream is closed, and you can
// no longer continue to write data to it!
jassert (! finished);
while (dataSize > 0)
if (! doNextBlock (data, dataSize, destStream, Z_NO_FLUSH))
return false;
return true;
} }
void setInput (const uint8* const newData, const size_t size) noexcept
void finish (OutputStream& destStream)
{ {
data = newData;
dataSize = size;
const uint8* data = nullptr;
int dataSize = 0;
while (! finished)
doNextBlock (data, dataSize, destStream, Z_FINISH);
} }
int doNextBlock (uint8* const dest, const int destSize) noexcept
private:
enum { gzipCompBufferSize = 32768 };
HeapBlock <zlibNamespace::Bytef> buffer;
zlibNamespace::z_stream stream;
int compLevel, strategy;
bool isFirstDeflate, streamIsValid, finished;
bool doNextBlock (const uint8*& data, int& dataSize, OutputStream& destStream, const int flushMode)
{ {
using namespace zlibNamespace; using namespace zlibNamespace;
if (streamIsValid) if (streamIsValid)
{ {
stream.next_in = const_cast <uint8*> (data);
stream.next_out = dest;
stream.avail_in = (z_uInt) dataSize;
stream.avail_out = (z_uInt) destSize;
stream.next_in = const_cast <uint8*> (data);
stream.next_out = buffer;
stream.avail_in = (z_uInt) dataSize;
stream.avail_out = (z_uInt) gzipCompBufferSize;
const int result = setParams ? deflateParams (&stream, compLevel, strategy)
: deflate (&stream, shouldFinish ? Z_FINISH : Z_NO_FLUSH);
setParams = false;
const int result = isFirstDeflate ? deflateParams (&stream, compLevel, strategy)
: deflate (&stream, flushMode);
isFirstDeflate = false;
switch (result) switch (result)
{ {
case Z_STREAM_END:
finished = true;
// Deliberate fall-through..
case Z_OK:
data += dataSize - stream.avail_in;
dataSize = stream.avail_in;
return (int) (destSize - stream.avail_out);
case Z_STREAM_END:
finished = true;
// Deliberate fall-through..
case Z_OK:
{
data += dataSize - stream.avail_in;
dataSize = (int) stream.avail_in;
const int bytesDone = (int) (gzipCompBufferSize - stream.avail_out);
return bytesDone <= 0 || destStream.write (buffer, bytesDone);
}
default:
break;
default:
break;
} }
} }
return 0;
return false;
} }
enum { gzipCompBufferSize = 32768 };
private:
zlibNamespace::z_stream stream;
const uint8* data;
size_t dataSize;
int compLevel, strategy;
bool setParams, streamIsValid;
public:
bool finished, shouldFinish;
}; };
//============================================================================== //==============================================================================
@@ -129,9 +134,10 @@ GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const dest
int compressionLevel, int compressionLevel,
const bool deleteDestStream, const bool deleteDestStream,
const int windowBits) const int windowBits)
: destStream (destStream_, deleteDestStream),
buffer ((size_t) GZIPCompressorHelper::gzipCompBufferSize)
: destStream (destStream_, deleteDestStream)
{ {
jassert (destStream_ != nullptr);
if (compressionLevel < 1 || compressionLevel > 9) if (compressionLevel < 1 || compressionLevel > 9)
compressionLevel = -1; compressionLevel = -1;
@@ -140,48 +146,20 @@ GZIPCompressorOutputStream::GZIPCompressorOutputStream (OutputStream* const dest
GZIPCompressorOutputStream::~GZIPCompressorOutputStream() GZIPCompressorOutputStream::~GZIPCompressorOutputStream()
{ {
flushInternal();
}
//==============================================================================
void GZIPCompressorOutputStream::flushInternal()
{
if (! helper->finished)
{
helper->shouldFinish = true;
while (! helper->finished)
doNextBlock();
}
destStream->flush();
flush();
} }
void GZIPCompressorOutputStream::flush() void GZIPCompressorOutputStream::flush()
{ {
flushInternal();
helper->finish (*destStream);
destStream->flush();
} }
bool GZIPCompressorOutputStream::write (const void* destBuffer, int howMany) bool GZIPCompressorOutputStream::write (const void* destBuffer, int howMany)
{ {
if (! helper->finished)
{
helper->setInput (static_cast <const uint8*> (destBuffer), (size_t) howMany);
while (! helper->needsInput())
{
if (! doNextBlock())
return false;
}
}
jassert (destBuffer != nullptr && howMany >= 0);
return true;
}
bool GZIPCompressorOutputStream::doNextBlock()
{
const int len = helper->doNextBlock (buffer, (int) GZIPCompressorHelper::gzipCompBufferSize);
return len <= 0 || destStream->write (buffer, len);
return helper->write (static_cast <const uint8*> (destBuffer), howMany, *destStream);
} }
int64 GZIPCompressorOutputStream::getPosition() int64 GZIPCompressorOutputStream::getPosition()
@@ -231,7 +209,7 @@ public:
MemoryInputStream compressedInput (compressed.getData(), compressed.getDataSize(), false); MemoryInputStream compressedInput (compressed.getData(), compressed.getDataSize(), false);
GZIPDecompressorInputStream unzipper (compressedInput); GZIPDecompressorInputStream unzipper (compressedInput);
uncompressed.writeFromInputStream (unzipper, -1);
uncompressed << unzipper;
} }
expectEquals ((int) uncompressed.getDataSize(), expectEquals ((int) uncompressed.getDataSize(),


+ 11
- 3
modules/juce_core/zip/juce_GZIPCompressorOutputStream.h View File

@@ -35,6 +35,10 @@
/** /**
A stream which uses zlib to compress the data written into it. A stream which uses zlib to compress the data written into it.
Important note: When you call flush() on a GZIPCompressorOutputStream,
the gzip data is closed - this means that no more data can be written to
it, and any subsequent attempts to call write() will cause an assertion.
@see GZIPDecompressorInputStream @see GZIPDecompressorInputStream
*/ */
class JUCE_API GZIPCompressorOutputStream : public OutputStream class JUCE_API GZIPCompressorOutputStream : public OutputStream
@@ -64,7 +68,13 @@ public:
~GZIPCompressorOutputStream(); ~GZIPCompressorOutputStream();
//============================================================================== //==============================================================================
/** Flushes and closes the stream.
Note that unlike most streams, when you call flush() on a GZIPCompressorOutputStream,
the stream is closed - this means that no more data can be written to it, and any
subsequent attempts to call write() will cause an assertion.
*/
void flush(); void flush();
int64 getPosition(); int64 getPosition();
bool setPosition (int64 newPosition); bool setPosition (int64 newPosition);
bool write (const void* destBuffer, int howMany); bool write (const void* destBuffer, int howMany);
@@ -81,12 +91,10 @@ public:
private: private:
//============================================================================== //==============================================================================
OptionalScopedPointer<OutputStream> destStream; OptionalScopedPointer<OutputStream> destStream;
HeapBlock <uint8> buffer;
class GZIPCompressorHelper; class GZIPCompressorHelper;
friend class ScopedPointer <GZIPCompressorHelper>; friend class ScopedPointer <GZIPCompressorHelper>;
ScopedPointer <GZIPCompressorHelper> helper; ScopedPointer <GZIPCompressorHelper> helper;
bool doNextBlock();
void flushInternal();
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream);
}; };


+ 30
- 33
modules/juce_core/zip/juce_GZIPDecompressorInputStream.cpp View File

@@ -192,52 +192,49 @@ int64 GZIPDecompressorInputStream::getTotalLength()
int GZIPDecompressorInputStream::read (void* destBuffer, int howMany) int GZIPDecompressorInputStream::read (void* destBuffer, int howMany)
{ {
if ((howMany > 0) && ! isEof)
jassert (destBuffer != nullptr && howMany >= 0);
if (howMany > 0 && ! isEof)
{ {
jassert (destBuffer != nullptr);
int numRead = 0;
uint8* d = static_cast <uint8*> (destBuffer);
if (destBuffer != nullptr)
while (! helper->error)
{ {
int numRead = 0;
uint8* d = static_cast <uint8*> (destBuffer);
const int n = helper->doNextBlock (d, howMany);
currentPos += n;
while (! helper->error)
if (n == 0)
{ {
const int n = helper->doNextBlock (d, howMany);
currentPos += n;
if (helper->finished || helper->needsDictionary)
{
isEof = true;
return numRead;
}
if (n == 0)
if (helper->needsInput())
{ {
if (helper->finished || helper->needsDictionary)
activeBufferSize = sourceStream->read (buffer, (int) GZIPDecompressHelper::gzipDecompBufferSize);
if (activeBufferSize > 0)
{ {
isEof = true;
return numRead;
helper->setInput (buffer, (size_t) activeBufferSize);
} }
if (helper->needsInput())
else
{ {
activeBufferSize = sourceStream->read (buffer, (int) GZIPDecompressHelper::gzipDecompBufferSize);
if (activeBufferSize > 0)
{
helper->setInput (buffer, (size_t) activeBufferSize);
}
else
{
isEof = true;
return numRead;
}
isEof = true;
return numRead;
} }
} }
else
{
numRead += n;
howMany -= n;
d += n;
}
else
{
numRead += n;
howMany -= n;
d += n;
if (howMany <= 0)
return numRead;
}
if (howMany <= 0)
return numRead;
} }
} }
} }


+ 46
- 41
modules/juce_core/zip/juce_ZipFile.cpp View File

@@ -354,60 +354,65 @@ int ZipFile::findEndOfZipEntryTable (InputStream& input, int& numEntries)
return 0; return 0;
} }
bool ZipFile::uncompressTo (const File& targetDirectory,
const bool shouldOverwriteFiles)
Result ZipFile::uncompressTo (const File& targetDirectory,
const bool shouldOverwriteFiles)
{ {
for (int i = 0; i < entries.size(); ++i) for (int i = 0; i < entries.size(); ++i)
if (! uncompressEntry (i, targetDirectory, shouldOverwriteFiles))
return false;
{
Result result (uncompressEntry (i, targetDirectory, shouldOverwriteFiles));
if (result.failed())
return result;
}
return true;
return Result::ok();
} }
bool ZipFile::uncompressEntry (const int index,
const File& targetDirectory,
bool shouldOverwriteFiles)
Result ZipFile::uncompressEntry (const int index,
const File& targetDirectory,
bool shouldOverwriteFiles)
{ {
const ZipEntryInfo* zei = entries [index];
const ZipEntryInfo* zei = entries.getUnchecked (index);
if (zei != nullptr)
const File targetFile (targetDirectory.getChildFile (zei->entry.filename));
if (zei->entry.filename.endsWithChar ('/'))
{ {
const File targetFile (targetDirectory.getChildFile (zei->entry.filename));
return targetFile.createDirectory(); // (entry is a directory, not a file)
}
else
{
ScopedPointer<InputStream> in (createStreamForEntry (index));
if (zei->entry.filename.endsWithChar ('/'))
{
return targetFile.createDirectory(); // (entry is a directory, not a file)
}
else
if (in == nullptr)
return Result::fail ("Failed to open the zip file for reading");
if (targetFile.exists())
{ {
ScopedPointer<InputStream> in (createStreamForEntry (index));
if (! shouldOverwriteFiles)
return Result::ok();
if (in != nullptr)
{
if (shouldOverwriteFiles && ! targetFile.deleteFile())
return false;
if (! targetFile.deleteFile())
return Result::fail ("Failed to write to target file: " + targetFile.getFullPathName());
}
if ((! targetFile.exists()) && targetFile.getParentDirectory().createDirectory())
{
ScopedPointer<FileOutputStream> out (targetFile.createOutputStream());
if (! targetFile.getParentDirectory().createDirectory())
return Result::fail ("Failed to create target folder: " + targetFile.getParentDirectory().getFullPathName());
if (out != nullptr)
{
out->writeFromInputStream (*in, -1);
out = nullptr;
{
FileOutputStream out (targetFile);
targetFile.setCreationTime (zei->entry.fileTime);
targetFile.setLastModificationTime (zei->entry.fileTime);
targetFile.setLastAccessTime (zei->entry.fileTime);
if (out.failedToOpen())
return Result::fail ("Failed to write to target file: " + targetFile.getFullPathName());
return true;
}
}
}
out << *in;
} }
}
return false;
targetFile.setCreationTime (zei->entry.fileTime);
targetFile.setLastModificationTime (zei->entry.fileTime);
targetFile.setLastAccessTime (zei->entry.fileTime);
return Result::ok();
}
} }
@@ -485,17 +490,17 @@ private:
bool writeSource (OutputStream& target) bool writeSource (OutputStream& target)
{ {
checksum = 0; checksum = 0;
ScopedPointer<FileInputStream> input (file.createInputStream());
FileInputStream input (file);
if (input == nullptr)
if (input.failedToOpen())
return false; return false;
const int bufferSize = 2048; const int bufferSize = 2048;
HeapBlock<unsigned char> buffer (bufferSize); HeapBlock<unsigned char> buffer (bufferSize);
while (! input->isExhausted())
while (! input.isExhausted())
{ {
const int bytesRead = input->read (buffer, bufferSize);
const int bytesRead = input.read (buffer, bufferSize);
if (bytesRead < 0) if (bytesRead < 0)
return false; return false;


+ 9
- 8
modules/juce_core/zip/juce_ZipFile.h View File

@@ -145,24 +145,25 @@ public:
@param targetDirectory the root folder to uncompress to @param targetDirectory the root folder to uncompress to
@param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones @param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones
@returns true if all the files are successfully unzipped
@returns success if the file is successfully unzipped
*/ */
bool uncompressTo (const File& targetDirectory,
bool shouldOverwriteFiles = true);
Result uncompressTo (const File& targetDirectory,
bool shouldOverwriteFiles = true);
/** Uncompresses one of the entries from the zip file. /** Uncompresses one of the entries from the zip file.
This will expand the entry and write it in a target directory. The entry's path is used to This will expand the entry and write it in a target directory. The entry's path is used to
determine which subfolder of the target should contain the new file. determine which subfolder of the target should contain the new file.
@param index the index of the entry to uncompress
@param index the index of the entry to uncompress - this must be a valid index
between 0 and (getNumEntries() - 1).
@param targetDirectory the root folder to uncompress into @param targetDirectory the root folder to uncompress into
@param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones @param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones
@returns true if the files is successfully unzipped
@returns success if all the files are successfully unzipped
*/ */
bool uncompressEntry (int index,
const File& targetDirectory,
bool shouldOverwriteFiles = true);
Result uncompressEntry (int index,
const File& targetDirectory,
bool shouldOverwriteFiles = true);
//============================================================================== //==============================================================================


+ 1
- 1
modules/juce_graphics/image_formats/juce_JPEGLoader.cpp View File

@@ -241,7 +241,7 @@ Image JPEGImageFormat::decodeImage (InputStream& in)
using namespace JPEGHelpers; using namespace JPEGHelpers;
MemoryOutputStream mb; MemoryOutputStream mb;
mb.writeFromInputStream (in, -1);
mb << in;
Image image; Image image;


+ 3
- 3
modules/juce_gui_basics/drawables/juce_Drawable.cpp View File

@@ -145,16 +145,16 @@ Drawable* Drawable::createFromImageData (const void* data, const size_t numBytes
Drawable* Drawable::createFromImageDataStream (InputStream& dataSource) Drawable* Drawable::createFromImageDataStream (InputStream& dataSource)
{ {
MemoryOutputStream mo; MemoryOutputStream mo;
mo.writeFromInputStream (dataSource, -1);
mo << dataSource;
return createFromImageData (mo.getData(), mo.getDataSize()); return createFromImageData (mo.getData(), mo.getDataSize());
} }
Drawable* Drawable::createFromImageFile (const File& file) Drawable* Drawable::createFromImageFile (const File& file)
{ {
const ScopedPointer <FileInputStream> fin (file.createInputStream());
FileInputStream fin (file);
return fin != nullptr ? createFromImageDataStream (*fin) : nullptr;
return fin.openedOk() ? createFromImageDataStream (fin) : nullptr;
} }
//============================================================================== //==============================================================================


+ 12
- 17
modules/juce_gui_basics/layout/juce_ScrollBar.cpp View File

@@ -387,12 +387,12 @@ void ScrollBar::mouseWheelMove (const MouseEvent&,
float wheelIncrementX, float wheelIncrementX,
float wheelIncrementY) float wheelIncrementY)
{ {
float increment = vertical ? wheelIncrementY : wheelIncrementX;
float increment = 10.0f * (vertical ? wheelIncrementY : wheelIncrementX);
if (increment < 0) if (increment < 0)
increment = jmin (increment * 10.0f, -1.0f);
increment = jmin (increment, -1.0f);
else if (increment > 0) else if (increment > 0)
increment = jmax (increment * 10.0f, 1.0f);
increment = jmax (increment, 1.0f);
setCurrentRange (visibleRange - singleStepSize * increment); setCurrentRange (visibleRange - singleStepSize * increment);
} }
@@ -419,20 +419,15 @@ bool ScrollBar::keyPressed (const KeyPress& key)
if (! isVisible()) if (! isVisible())
return false; return false;
if (key.isKeyCode (KeyPress::upKey) || key.isKeyCode (KeyPress::leftKey))
moveScrollbarInSteps (-1);
else if (key.isKeyCode (KeyPress::downKey) || key.isKeyCode (KeyPress::rightKey))
moveScrollbarInSteps (1);
else if (key.isKeyCode (KeyPress::pageUpKey))
moveScrollbarInPages (-1);
else if (key.isKeyCode (KeyPress::pageDownKey))
moveScrollbarInPages (1);
else if (key.isKeyCode (KeyPress::homeKey))
scrollToTop();
else if (key.isKeyCode (KeyPress::endKey))
scrollToBottom();
else
return false;
if (key.isKeyCode (KeyPress::upKey)
|| key.isKeyCode (KeyPress::leftKey)) moveScrollbarInSteps (-1);
else if (key.isKeyCode (KeyPress::downKey)
|| key.isKeyCode (KeyPress::rightKey)) moveScrollbarInSteps (1);
else if (key.isKeyCode (KeyPress::pageUpKey)) moveScrollbarInPages (-1);
else if (key.isKeyCode (KeyPress::pageDownKey)) moveScrollbarInPages (1);
else if (key.isKeyCode (KeyPress::homeKey)) scrollToTop();
else if (key.isKeyCode (KeyPress::endKey)) scrollToBottom();
else return false;
return true; return true;
} }


+ 203
- 223
modules/juce_gui_basics/widgets/juce_Slider.cpp View File

@@ -30,7 +30,6 @@ class Slider::PopupDisplayComponent : public BubbleComponent,
public Timer public Timer
{ {
public: public:
//==============================================================================
PopupDisplayComponent (Slider& owner_) PopupDisplayComponent (Slider& owner_)
: owner (owner_), : owner (owner_),
font (15.0f, Font::bold) font (15.0f, Font::bold)
@@ -53,12 +52,7 @@ public:
void updatePosition (const String& newText) void updatePosition (const String& newText)
{ {
if (text != newText)
{
text = newText;
repaint();
}
text = newText;
BubbleComponent::setPosition (&owner); BubbleComponent::setPosition (&owner);
repaint(); repaint();
} }
@@ -962,36 +956,18 @@ void Slider::resized()
if (incDecButtonsSideBySide) if (incDecButtonsSideBySide)
{ {
decButton->setBounds (buttonRect.getX(),
buttonRect.getY(),
buttonRect.getWidth() / 2,
buttonRect.getHeight());
decButton->setBounds (buttonRect.removeFromLeft (buttonRect.getWidth() / 2));
decButton->setConnectedEdges (Button::ConnectedOnRight); decButton->setConnectedEdges (Button::ConnectedOnRight);
incButton->setBounds (buttonRect.getCentreX(),
buttonRect.getY(),
buttonRect.getWidth() / 2,
buttonRect.getHeight());
incButton->setConnectedEdges (Button::ConnectedOnLeft); incButton->setConnectedEdges (Button::ConnectedOnLeft);
} }
else else
{ {
incButton->setBounds (buttonRect.getX(),
buttonRect.getY(),
buttonRect.getWidth(),
buttonRect.getHeight() / 2);
incButton->setConnectedEdges (Button::ConnectedOnBottom);
decButton->setBounds (buttonRect.getX(),
buttonRect.getCentreY(),
buttonRect.getWidth(),
buttonRect.getHeight() / 2);
decButton->setBounds (buttonRect.removeFromBottom (buttonRect.getHeight() / 2));
decButton->setConnectedEdges (Button::ConnectedOnTop); decButton->setConnectedEdges (Button::ConnectedOnTop);
incButton->setConnectedEdges (Button::ConnectedOnBottom);
} }
incButton->setBounds (buttonRect);
} }
} }
@@ -1000,52 +976,90 @@ void Slider::focusOfChildComponentChanged (FocusChangeType)
repaint(); repaint();
} }
static void sliderMenuCallback (int result, Slider* slider)
namespace SliderHelpers
{ {
if (slider != nullptr)
double smallestAngleBetween (double a1, double a2) noexcept
{
return jmin (std::abs (a1 - a2),
std::abs (a1 + double_Pi * 2.0 - a2),
std::abs (a2 + double_Pi * 2.0 - a1));
}
void sliderMenuCallback (int result, Slider* slider)
{ {
switch (result)
if (slider != nullptr)
{ {
case 1: slider->setVelocityBasedMode (! slider->getVelocityBasedMode()); break;
case 2: slider->setSliderStyle (Slider::Rotary); break;
case 3: slider->setSliderStyle (Slider::RotaryHorizontalDrag); break;
case 4: slider->setSliderStyle (Slider::RotaryVerticalDrag); break;
default: break;
switch (result)
{
case 1: slider->setVelocityBasedMode (! slider->getVelocityBasedMode()); break;
case 2: slider->setSliderStyle (Slider::Rotary); break;
case 3: slider->setSliderStyle (Slider::RotaryHorizontalDrag); break;
case 4: slider->setSliderStyle (Slider::RotaryVerticalDrag); break;
default: break;
}
} }
} }
} }
void Slider::showPopupMenu()
{
menuShown = true;
PopupMenu m;
m.setLookAndFeel (&getLookAndFeel());
m.addItem (1, TRANS ("velocity-sensitive mode"), true, isVelocityBased);
m.addSeparator();
if (style == Rotary || style == RotaryHorizontalDrag || style == RotaryVerticalDrag)
{
PopupMenu rotaryMenu;
rotaryMenu.addItem (2, TRANS ("use circular dragging"), true, style == Rotary);
rotaryMenu.addItem (3, TRANS ("use left-right dragging"), true, style == RotaryHorizontalDrag);
rotaryMenu.addItem (4, TRANS ("use up-down dragging"), true, style == RotaryVerticalDrag);
m.addSubMenu (TRANS ("rotary mode"), rotaryMenu);
}
m.showMenuAsync (PopupMenu::Options(),
ModalCallbackFunction::forComponent (SliderHelpers::sliderMenuCallback, this));
}
int Slider::getThumbIndexAt (const MouseEvent& e)
{
const bool isTwoValue = (style == TwoValueHorizontal || style == TwoValueVertical);
const bool isThreeValue = (style == ThreeValueHorizontal || style == ThreeValueVertical);
if (isTwoValue || isThreeValue)
{
const float mousePos = (float) (isVertical() ? e.y : e.x);
const float normalPosDistance = std::abs (getLinearSliderPos (currentValue.getValue()) - mousePos);
const float minPosDistance = std::abs (getLinearSliderPos (valueMin.getValue()) - 0.1f - mousePos);
const float maxPosDistance = std::abs (getLinearSliderPos (valueMax.getValue()) + 0.1f - mousePos);
if (isTwoValue)
return maxPosDistance <= minPosDistance ? 2 : 1;
if (normalPosDistance >= minPosDistance && maxPosDistance >= minPosDistance)
return 1;
else if (normalPosDistance >= maxPosDistance)
return 2;
}
return 0;
}
void Slider::mouseDown (const MouseEvent& e) void Slider::mouseDown (const MouseEvent& e)
{ {
mouseWasHidden = false; mouseWasHidden = false;
incDecDragged = false; incDecDragged = false;
mousePosWhenLastDragged = e.getPosition();
mouseDragStartX = e.getMouseDownX();
mouseDragStartY = e.getMouseDownY();
mouseDragStartPos = mousePosWhenLastDragged = e.getPosition();
if (isEnabled()) if (isEnabled())
{ {
if (e.mods.isPopupMenu() && menuEnabled) if (e.mods.isPopupMenu() && menuEnabled)
{ {
menuShown = true;
PopupMenu m;
m.setLookAndFeel (&getLookAndFeel());
m.addItem (1, TRANS ("velocity-sensitive mode"), true, isVelocityBased);
m.addSeparator();
if (style == Rotary || style == RotaryHorizontalDrag || style == RotaryVerticalDrag)
{
PopupMenu rotaryMenu;
rotaryMenu.addItem (2, TRANS ("use circular dragging"), true, style == Rotary);
rotaryMenu.addItem (3, TRANS ("use left-right dragging"), true, style == RotaryHorizontalDrag);
rotaryMenu.addItem (4, TRANS ("use up-down dragging"), true, style == RotaryVerticalDrag);
m.addSubMenu (TRANS ("rotary mode"), rotaryMenu);
}
m.showMenuAsync (PopupMenu::Options(),
ModalCallbackFunction::forComponent (sliderMenuCallback, this));
showPopupMenu();
} }
else if (maximum > minimum) else if (maximum > minimum)
{ {
@@ -1054,44 +1068,16 @@ void Slider::mouseDown (const MouseEvent& e)
if (valueBox != nullptr) if (valueBox != nullptr)
valueBox->hideEditor (true); valueBox->hideEditor (true);
sliderBeingDragged = 0;
if (style == TwoValueHorizontal
|| style == TwoValueVertical
|| style == ThreeValueHorizontal
|| style == ThreeValueVertical)
{
const float mousePos = (float) (isVertical() ? e.y : e.x);
const float normalPosDistance = std::abs (getLinearSliderPos (currentValue.getValue()) - mousePos);
const float minPosDistance = std::abs (getLinearSliderPos (valueMin.getValue()) - 0.1f - mousePos);
const float maxPosDistance = std::abs (getLinearSliderPos (valueMax.getValue()) + 0.1f - mousePos);
if (style == TwoValueHorizontal || style == TwoValueVertical)
{
if (maxPosDistance <= minPosDistance)
sliderBeingDragged = 2;
else
sliderBeingDragged = 1;
}
else if (style == ThreeValueHorizontal || style == ThreeValueVertical)
{
if (normalPosDistance >= minPosDistance && maxPosDistance >= minPosDistance)
sliderBeingDragged = 1;
else if (normalPosDistance >= maxPosDistance)
sliderBeingDragged = 2;
}
}
sliderBeingDragged = getThumbIndexAt (e);
minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue(); minMaxDiff = (double) valueMax.getValue() - (double) valueMin.getValue();
lastAngle = rotaryStart + (rotaryEnd - rotaryStart) lastAngle = rotaryStart + (rotaryEnd - rotaryStart)
* valueToProportionOfLength (currentValue.getValue()); * valueToProportionOfLength (currentValue.getValue());
valueWhenLastDragged = ((sliderBeingDragged == 2) ? valueMax
: ((sliderBeingDragged == 1) ? valueMin
: currentValue)).getValue();
valueWhenLastDragged = (sliderBeingDragged == 2 ? valueMax
: (sliderBeingDragged == 1 ? valueMin
: currentValue)).getValue();
valueOnMouseDown = valueWhenLastDragged; valueOnMouseDown = valueWhenLastDragged;
if (popupDisplayEnabled) if (popupDisplayEnabled)
@@ -1108,7 +1094,6 @@ void Slider::mouseDown (const MouseEvent& e)
} }
sendDragStart(); sendDragStart();
mouseDrag (e); mouseDrag (e);
} }
} }
@@ -1150,10 +1135,9 @@ void Slider::restoreMouseIfHidden()
for (int i = Desktop::getInstance().getNumMouseSources(); --i >= 0;) for (int i = Desktop::getInstance().getNumMouseSources(); --i >= 0;)
Desktop::getInstance().getMouseSource(i)->enableUnboundedMouseMovement (false); Desktop::getInstance().getMouseSource(i)->enableUnboundedMouseMovement (false);
const double pos = (sliderBeingDragged == 2) ? getMaxValue()
: ((sliderBeingDragged == 1) ? getMinValue()
: (double) currentValue.getValue());
const double pos = sliderBeingDragged == 2 ? getMaxValue()
: (sliderBeingDragged == 1 ? getMinValue()
: (double) currentValue.getValue());
Point<int> mousePos; Point<int> mousePos;
if (style == RotaryHorizontalDrag || style == RotaryVerticalDrag) if (style == RotaryHorizontalDrag || style == RotaryVerticalDrag)
@@ -1194,158 +1178,154 @@ void Slider::modifierKeysChanged (const ModifierKeys& modifiers)
} }
} }
namespace SliderHelpers
void Slider::handleRotaryDrag (const MouseEvent& e)
{ {
double smallestAngleBetween (double a1, double a2) noexcept
const int dx = e.x - sliderRect.getCentreX();
const int dy = e.y - sliderRect.getCentreY();
if (dx * dx + dy * dy > 25)
{ {
return jmin (std::abs (a1 - a2),
std::abs (a1 + double_Pi * 2.0 - a2),
std::abs (a2 + double_Pi * 2.0 - a1));
double angle = std::atan2 ((double) dx, (double) -dy);
while (angle < 0.0)
angle += double_Pi * 2.0;
if (rotaryStop && ! e.mouseWasClicked())
{
if (std::abs (angle - lastAngle) > double_Pi)
{
if (angle >= lastAngle)
angle -= double_Pi * 2.0;
else
angle += double_Pi * 2.0;
}
if (angle >= lastAngle)
angle = jmin (angle, (double) jmax (rotaryStart, rotaryEnd));
else
angle = jmax (angle, (double) jmin (rotaryStart, rotaryEnd));
}
else
{
while (angle < rotaryStart)
angle += double_Pi * 2.0;
if (angle > rotaryEnd)
{
if (SliderHelpers::smallestAngleBetween (angle, rotaryStart)
<= SliderHelpers::smallestAngleBetween (angle, rotaryEnd))
angle = rotaryStart;
else
angle = rotaryEnd;
}
}
const double proportion = (angle - rotaryStart) / (rotaryEnd - rotaryStart);
valueWhenLastDragged = proportionOfLengthToValue (jlimit (0.0, 1.0, proportion));
lastAngle = angle;
} }
} }
void Slider::mouseDrag (const MouseEvent& e)
void Slider::handleAbsoluteDrag (const MouseEvent& e)
{ {
if (isEnabled()
&& (! menuShown)
&& (maximum > minimum))
const int mousePos = (isHorizontal() || style == RotaryHorizontalDrag) ? e.x : e.y;
double scaledMousePos = (mousePos - sliderRegionStart) / (double) sliderRegionSize;
if (style == RotaryHorizontalDrag
|| style == RotaryVerticalDrag
|| style == IncDecButtons
|| ((style == LinearHorizontal || style == LinearVertical || style == LinearBar)
&& ! snapsToMousePos))
{ {
if (style == Rotary)
const int mouseDiff = (style == RotaryHorizontalDrag
|| style == LinearHorizontal
|| style == LinearBar
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
? e.x - mouseDragStartPos.getX()
: mouseDragStartPos.getY() - e.y;
double newPos = valueToProportionOfLength (valueOnMouseDown)
+ mouseDiff * (1.0 / pixelsForFullDragExtent);
valueWhenLastDragged = proportionOfLengthToValue (jlimit (0.0, 1.0, newPos));
if (style == IncDecButtons)
{ {
const int dx = e.x - sliderRect.getCentreX();
const int dy = e.y - sliderRect.getCentreY();
incButton->setState (mouseDiff < 0 ? Button::buttonNormal : Button::buttonDown);
decButton->setState (mouseDiff > 0 ? Button::buttonNormal : Button::buttonDown);
}
}
else
{
if (isVertical())
scaledMousePos = 1.0 - scaledMousePos;
if (dx * dx + dy * dy > 25)
{
double angle = std::atan2 ((double) dx, (double) -dy);
while (angle < 0.0)
angle += double_Pi * 2.0;
valueWhenLastDragged = proportionOfLengthToValue (jlimit (0.0, 1.0, scaledMousePos));
}
}
if (rotaryStop && ! e.mouseWasClicked())
{
if (std::abs (angle - lastAngle) > double_Pi)
{
if (angle >= lastAngle)
angle -= double_Pi * 2.0;
else
angle += double_Pi * 2.0;
}
if (angle >= lastAngle)
angle = jmin (angle, (double) jmax (rotaryStart, rotaryEnd));
else
angle = jmax (angle, (double) jmin (rotaryStart, rotaryEnd));
}
else
{
while (angle < rotaryStart)
angle += double_Pi * 2.0;
void Slider::handleVelocityDrag (const MouseEvent& e)
{
const int mouseDiff = (isHorizontal() || style == RotaryHorizontalDrag
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
? e.x - mousePosWhenLastDragged.getX()
: e.y - mousePosWhenLastDragged.getY();
const double maxSpeed = jmax (200, sliderRegionSize);
double speed = jlimit (0.0, maxSpeed, (double) abs (mouseDiff));
if (angle > rotaryEnd)
{
if (SliderHelpers::smallestAngleBetween (angle, rotaryStart)
<= SliderHelpers::smallestAngleBetween (angle, rotaryEnd))
angle = rotaryStart;
else
angle = rotaryEnd;
}
}
if (speed != 0)
{
speed = 0.2 * velocityModeSensitivity
* (1.0 + std::sin (double_Pi * (1.5 + jmin (0.5, velocityModeOffset
+ jmax (0.0, (double) (speed - velocityModeThreshold))
/ maxSpeed))));
const double proportion = (angle - rotaryStart) / (rotaryEnd - rotaryStart);
if (mouseDiff < 0)
speed = -speed;
valueWhenLastDragged = proportionOfLengthToValue (jlimit (0.0, 1.0, proportion));
if (isVertical() || style == RotaryVerticalDrag
|| (style == IncDecButtons && ! incDecDragDirectionIsHorizontal()))
speed = -speed;
lastAngle = angle;
}
const double currentPos = valueToProportionOfLength (valueWhenLastDragged);
valueWhenLastDragged = proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + speed));
e.source.enableUnboundedMouseMovement (true, false);
mouseWasHidden = true;
}
}
void Slider::mouseDrag (const MouseEvent& e)
{
if (isEnabled()
&& (! menuShown)
&& (maximum > minimum)
&& ! (style == LinearBar && e.mouseWasClicked() && valueBox != nullptr && valueBox->isEditable()))
{
if (style == Rotary)
{
handleRotaryDrag (e);
} }
else else
{ {
if (style == LinearBar && e.mouseWasClicked()
&& valueBox != nullptr && valueBox->isEditable())
return;
if (style == IncDecButtons && ! incDecDragged) if (style == IncDecButtons && ! incDecDragged)
{ {
if (e.getDistanceFromDragStart() < 10 || e.mouseWasClicked()) if (e.getDistanceFromDragStart() < 10 || e.mouseWasClicked())
return; return;
incDecDragged = true; incDecDragged = true;
mouseDragStartX = e.x;
mouseDragStartY = e.y;
mouseDragStartPos = e.getPosition();
} }
if ((isVelocityBased == (userKeyOverridesVelocity ? e.mods.testFlags (ModifierKeys::ctrlModifier | ModifierKeys::commandModifier | ModifierKeys::altModifier)
: false))
|| ((maximum - minimum) / sliderRegionSize < interval))
{
const int mousePos = (isHorizontal() || style == RotaryHorizontalDrag) ? e.x : e.y;
double scaledMousePos = (mousePos - sliderRegionStart) / (double) sliderRegionSize;
if (style == RotaryHorizontalDrag
|| style == RotaryVerticalDrag
|| style == IncDecButtons
|| ((style == LinearHorizontal || style == LinearVertical || style == LinearBar)
&& ! snapsToMousePos))
{
const int mouseDiff = (style == RotaryHorizontalDrag
|| style == LinearHorizontal
|| style == LinearBar
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
? e.x - mouseDragStartX
: mouseDragStartY - e.y;
double newPos = valueToProportionOfLength (valueOnMouseDown)
+ mouseDiff * (1.0 / pixelsForFullDragExtent);
valueWhenLastDragged = proportionOfLengthToValue (jlimit (0.0, 1.0, newPos));
if (style == IncDecButtons)
{
incButton->setState (mouseDiff < 0 ? Button::buttonNormal : Button::buttonDown);
decButton->setState (mouseDiff > 0 ? Button::buttonNormal : Button::buttonDown);
}
}
else
{
if (isVertical())
scaledMousePos = 1.0 - scaledMousePos;
valueWhenLastDragged = proportionOfLengthToValue (jlimit (0.0, 1.0, scaledMousePos));
}
}
if (isVelocityBased == (userKeyOverridesVelocity && e.mods.testFlags (ModifierKeys::ctrlModifier
| ModifierKeys::commandModifier
| ModifierKeys::altModifier))
|| (maximum - minimum) / sliderRegionSize < interval)
handleAbsoluteDrag (e);
else else
{
const int mouseDiff = (isHorizontal() || style == RotaryHorizontalDrag
|| (style == IncDecButtons && incDecDragDirectionIsHorizontal()))
? e.x - mousePosWhenLastDragged.getX()
: e.y - mousePosWhenLastDragged.getY();
const double maxSpeed = jmax (200, sliderRegionSize);
double speed = jlimit (0.0, maxSpeed, (double) abs (mouseDiff));
if (speed != 0)
{
speed = 0.2 * velocityModeSensitivity
* (1.0 + std::sin (double_Pi * (1.5 + jmin (0.5, velocityModeOffset
+ jmax (0.0, (double) (speed - velocityModeThreshold))
/ maxSpeed))));
if (mouseDiff < 0)
speed = -speed;
if (isVertical() || style == RotaryVerticalDrag
|| (style == IncDecButtons && ! incDecDragDirectionIsHorizontal()))
speed = -speed;
const double currentPos = valueToProportionOfLength (valueWhenLastDragged);
valueWhenLastDragged = proportionOfLengthToValue (jlimit (0.0, 1.0, currentPos + speed));
e.source.enableUnboundedMouseMovement (true, false);
mouseWasHidden = true;
}
}
handleVelocityDrag (e);
} }
valueWhenLastDragged = jlimit (minimum, maximum, valueWhenLastDragged); valueWhenLastDragged = jlimit (minimum, maximum, valueWhenLastDragged);


+ 6
- 2
modules/juce_gui_basics/widgets/juce_Slider.h View File

@@ -827,8 +827,7 @@ private:
int velocityModeThreshold; int velocityModeThreshold;
float rotaryStart, rotaryEnd; float rotaryStart, rotaryEnd;
int numDecimalPlaces; int numDecimalPlaces;
Point<int> mousePosWhenLastDragged;
int mouseDragStartX, mouseDragStartY;
Point<int> mouseDragStartPos, mousePosWhenLastDragged;
int sliderRegionStart, sliderRegionSize; int sliderRegionStart, sliderRegionSize;
int sliderBeingDragged; int sliderBeingDragged;
int pixelsForFullDragExtent; int pixelsForFullDragExtent;
@@ -854,6 +853,11 @@ private:
ScopedPointer <PopupDisplayComponent> popupDisplay; ScopedPointer <PopupDisplayComponent> popupDisplay;
Component* parentForPopupDisplay; Component* parentForPopupDisplay;
void showPopupMenu();
int getThumbIndexAt (const MouseEvent&);
void handleRotaryDrag (const MouseEvent&);
void handleAbsoluteDrag (const MouseEvent&);
void handleVelocityDrag (const MouseEvent&);
float getLinearSliderPos (double value); float getLinearSliderPos (double value);
void restoreMouseIfHidden(); void restoreMouseIfHidden();
void sendDragStart(); void sendDragStart();


Loading…
Cancel
Save