/* ============================================================================== This file is part of the JUCE library - "Jules' Utility Class Extensions" Copyright 2004-9 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 header contains the entire Juce source tree, and can be #included in all your source files. As well as including this in your files, you should also add juce_inline.cpp to your project (or juce_inline.mm on the Mac). ============================================================================== */ #ifndef __JUCE_AMALGAMATED_TEMPLATE_JUCEHEADER__ #define __JUCE_AMALGAMATED_TEMPLATE_JUCEHEADER__ #define DONT_AUTOLINK_TO_JUCE_LIBRARY 1 /*** Start of inlined file: juce.h ***/ #ifndef __JUCE_JUCEHEADER__ #define __JUCE_JUCEHEADER__ /* This is the main JUCE header file that applications need to include. */ /* This line is here just to help catch syntax errors caused by mistakes in other header files that are included before juce.h. If you hit an error at this line, it must be some kind of syntax problem in whatever code immediately precedes this header. This also acts as a sanity-check in case you're trying to build with a C or obj-C compiler rather than a proper C++ one. */ namespace JuceDummyNamespace {} #define JUCE_PUBLIC_INCLUDES 1 // (this includes things that need defining outside of the JUCE namespace) /*** Start of inlined file: juce_StandardHeader.h ***/ #ifndef __JUCE_STANDARDHEADER_JUCEHEADER__ #define __JUCE_STANDARDHEADER_JUCEHEADER__ /** Current Juce version number. See also SystemStats::getJUCEVersion() for a string version. */ #define JUCE_MAJOR_VERSION 1 #define JUCE_MINOR_VERSION 53 #define JUCE_BUILDNUMBER 11 /** Current Juce version number. Bits 16 to 32 = major version. Bits 8 to 16 = minor version. Bits 0 to 8 = point release (not currently used). See also SystemStats::getJUCEVersion() for a string version. */ #define JUCE_VERSION ((JUCE_MAJOR_VERSION << 16) + (JUCE_MINOR_VERSION << 8) + JUCE_BUILDNUMBER) /*** Start of inlined file: juce_TargetPlatform.h ***/ #ifndef __JUCE_TARGETPLATFORM_JUCEHEADER__ #define __JUCE_TARGETPLATFORM_JUCEHEADER__ /* This file figures out which platform is being built, and defines some macros that the rest of the code can use for OS-specific compilation. Macros that will be set here are: - One of JUCE_WINDOWS, JUCE_MAC or JUCE_LINUX. - Either JUCE_32BIT or JUCE_64BIT, depending on the architecture. - Either JUCE_LITTLE_ENDIAN or JUCE_BIG_ENDIAN. - Either JUCE_INTEL or JUCE_PPC - Either JUCE_GCC or JUCE_MSVC */ #if (defined (_WIN32) || defined (_WIN64)) #define JUCE_WIN32 1 #define JUCE_WINDOWS 1 #elif defined (LINUX) || defined (__linux__) #define JUCE_LINUX 1 #elif defined(__APPLE_CPP__) || defined(__APPLE_CC__) #include // (needed to find out what platform we're using) #if TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR #define JUCE_IPHONE 1 #define JUCE_IOS 1 #else #define JUCE_MAC 1 #endif #else #error "Unknown platform!" #endif #if JUCE_WINDOWS #ifdef _MSC_VER #ifdef _WIN64 #define JUCE_64BIT 1 #else #define JUCE_32BIT 1 #endif #endif #ifdef _DEBUG #define JUCE_DEBUG 1 #endif #ifdef __MINGW32__ #define JUCE_MINGW 1 #endif /** If defined, this indicates that the processor is little-endian. */ #define JUCE_LITTLE_ENDIAN 1 #define JUCE_INTEL 1 #endif #if JUCE_MAC || JUCE_IOS #if defined (DEBUG) || defined (_DEBUG) || ! (defined (NDEBUG) || defined (_NDEBUG)) #define JUCE_DEBUG 1 #endif #if ! (defined (DEBUG) || defined (_DEBUG) || defined (NDEBUG) || defined (_NDEBUG)) #warning "Neither NDEBUG or DEBUG has been defined - you should set one of these to make it clear whether this is a release build," #endif #ifdef __LITTLE_ENDIAN__ #define JUCE_LITTLE_ENDIAN 1 #else #define JUCE_BIG_ENDIAN 1 #endif #endif #if JUCE_MAC #if defined (__ppc__) || defined (__ppc64__) #define JUCE_PPC 1 #else #define JUCE_INTEL 1 #endif #ifdef __LP64__ #define JUCE_64BIT 1 #else #define JUCE_32BIT 1 #endif #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_4 #error "Building for OSX 10.3 is no longer supported!" #endif #ifndef MAC_OS_X_VERSION_10_5 #error "To build with 10.4 compatibility, use a 10.5 or 10.6 SDK and set the deployment target to 10.4" #endif #endif #if JUCE_LINUX #ifdef _DEBUG #define JUCE_DEBUG 1 #endif // Allow override for big-endian Linux platforms #ifndef JUCE_BIG_ENDIAN #define JUCE_LITTLE_ENDIAN 1 #endif #if defined (__LP64__) || defined (_LP64) #define JUCE_64BIT 1 #else #define JUCE_32BIT 1 #endif #define JUCE_INTEL 1 #endif // Compiler type macros. #ifdef __GNUC__ #define JUCE_GCC 1 #elif defined (_MSC_VER) #define JUCE_MSVC 1 #if _MSC_VER < 1500 #define JUCE_VC8_OR_EARLIER 1 #if _MSC_VER < 1400 #define JUCE_VC7_OR_EARLIER 1 #if _MSC_VER < 1300 #define JUCE_VC6 1 #endif #endif #endif #if ! JUCE_VC7_OR_EARLIER #define JUCE_USE_INTRINSICS 1 #endif #else #error unknown compiler #endif #endif // __JUCE_TARGETPLATFORM_JUCEHEADER__ /*** End of inlined file: juce_TargetPlatform.h ***/ // (sets up the various JUCE_WINDOWS, JUCE_MAC, etc flags) /*** Start of inlined file: juce_Config.h ***/ #ifndef __JUCE_CONFIG_JUCEHEADER__ #define __JUCE_CONFIG_JUCEHEADER__ /* This file contains macros that enable/disable various JUCE features. */ /** The name of the namespace that all Juce classes and functions will be put inside. If this is not defined, no namespace will be used. */ #ifndef JUCE_NAMESPACE #define JUCE_NAMESPACE juce #endif /** JUCE_FORCE_DEBUG: Normally, JUCE_DEBUG is set to 1 or 0 based on compiler and project settings, but if you define this value, you can override this to force it to be true or false. */ #ifndef JUCE_FORCE_DEBUG //#define JUCE_FORCE_DEBUG 0 #endif /** JUCE_LOG_ASSERTIONS: If this flag is enabled, the the jassert and jassertfalse macros will always use Logger::writeToLog() to write a message when an assertion happens. Enabling it will also leave this turned on in release builds. When it's disabled, however, the jassert and jassertfalse macros will not be compiled in a release build. @see jassert, jassertfalse, Logger */ #ifndef JUCE_LOG_ASSERTIONS #define JUCE_LOG_ASSERTIONS 0 #endif /** JUCE_ASIO: Enables ASIO audio devices (MS Windows only). Turning this on means that you'll need to have the Steinberg ASIO SDK installed on your Windows build machine. See the comments in the ASIOAudioIODevice class's header file for more info about this. */ #ifndef JUCE_ASIO #define JUCE_ASIO 0 #endif /** JUCE_WASAPI: Enables WASAPI audio devices (Windows Vista and above). */ #ifndef JUCE_WASAPI #define JUCE_WASAPI 0 #endif /** JUCE_DIRECTSOUND: Enables DirectSound audio (MS Windows only). */ #ifndef JUCE_DIRECTSOUND #define JUCE_DIRECTSOUND 1 #endif /** JUCE_ALSA: Enables ALSA audio devices (Linux only). */ #ifndef JUCE_ALSA #define JUCE_ALSA 1 #endif /** JUCE_JACK: Enables JACK audio devices (Linux only). */ #ifndef JUCE_JACK #define JUCE_JACK 0 #endif /** JUCE_QUICKTIME: Enables the QuickTimeMovieComponent class (Mac and Windows). If you're building on Windows, you'll need to have the Apple QuickTime SDK installed, and its header files will need to be on your include path. */ #if ! (defined (JUCE_QUICKTIME) || JUCE_LINUX || JUCE_IOS || (JUCE_WINDOWS && ! JUCE_MSVC)) #define JUCE_QUICKTIME 0 #endif #if (JUCE_IOS || JUCE_LINUX) && JUCE_QUICKTIME #undef JUCE_QUICKTIME #endif /** JUCE_OPENGL: Enables the OpenGLComponent class (available on all platforms). If you're not using OpenGL, you might want to turn this off to reduce your binary's size. */ #ifndef JUCE_OPENGL #define JUCE_OPENGL 1 #endif /** JUCE_DIRECT2D: Enables the Windows 7 Direct2D renderer. If you're building on a platform older than Vista, you won't be able to compile with this feature. */ #ifndef JUCE_DIRECT2D #define JUCE_DIRECT2D 0 #endif /** JUCE_USE_FLAC: Enables the FLAC audio codec classes (available on all platforms). If your app doesn't need to read FLAC files, you might want to disable this to reduce the size of your codebase and build time. */ #ifndef JUCE_USE_FLAC #define JUCE_USE_FLAC 1 #endif /** JUCE_USE_OGGVORBIS: Enables the Ogg-Vorbis audio codec classes (available on all platforms). If your app doesn't need to read Ogg-Vorbis files, you might want to disable this to reduce the size of your codebase and build time. */ #ifndef JUCE_USE_OGGVORBIS #define JUCE_USE_OGGVORBIS 1 #endif /** JUCE_USE_CDBURNER: Enables the audio CD reader code (Mac and Windows only). Unless you're using CD-burning, you should probably turn this flag off to reduce code size. */ #if (! defined (JUCE_USE_CDBURNER)) && ! (JUCE_WINDOWS && ! JUCE_MSVC) #define JUCE_USE_CDBURNER 1 #endif /** JUCE_USE_CDREADER: Enables the audio CD reader code (Mac and Windows only). Unless you're using CD-reading, you should probably turn this flag off to reduce code size. */ #ifndef JUCE_USE_CDREADER #define JUCE_USE_CDREADER 1 #endif /** JUCE_USE_CAMERA: Enables web-cam support using the CameraDevice class (Mac and Windows). */ #if (JUCE_QUICKTIME || JUCE_WINDOWS) && ! defined (JUCE_USE_CAMERA) #define JUCE_USE_CAMERA 0 #endif /** JUCE_ENABLE_REPAINT_DEBUGGING: If this option is turned on, each area of the screen that gets repainted will flash in a random colour, so that you can check exactly how much and how often your components are being drawn. */ #ifndef JUCE_ENABLE_REPAINT_DEBUGGING #define JUCE_ENABLE_REPAINT_DEBUGGING 0 #endif /** JUCE_USE_XINERAMA: Enables Xinerama multi-monitor support (Linux only). Unless you specifically want to disable this, it's best to leave this option turned on. */ #ifndef JUCE_USE_XINERAMA #define JUCE_USE_XINERAMA 1 #endif /** JUCE_USE_XSHM: Enables X shared memory for faster rendering on Linux. This is best left turned on unless you have a good reason to disable it. */ #ifndef JUCE_USE_XSHM #define JUCE_USE_XSHM 1 #endif /** JUCE_USE_XRENDER: Uses XRender to allow semi-transparent windowing on Linux. */ #ifndef JUCE_USE_XRENDER #define JUCE_USE_XRENDER 0 #endif /** JUCE_USE_XCURSOR: Uses XCursor to allow ARGB cursor on Linux. This is best left turned on unless you have a good reason to disable it. */ #ifndef JUCE_USE_XCURSOR #define JUCE_USE_XCURSOR 1 #endif /** JUCE_PLUGINHOST_VST: Enables the VST audio plugin hosting classes. This requires the Steinberg VST SDK to be installed on your machine, and should be left turned off unless you're building a plugin hosting app. @see VSTPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_AU */ #ifndef JUCE_PLUGINHOST_VST #define JUCE_PLUGINHOST_VST 0 #endif /** JUCE_PLUGINHOST_AU: Enables the AudioUnit plugin hosting classes. This is Mac-only, of course, and should only be enabled if you're building a plugin hosting app. @see AudioUnitPluginFormat, AudioPluginFormat, AudioPluginFormatManager, JUCE_PLUGINHOST_VST */ #ifndef JUCE_PLUGINHOST_AU #define JUCE_PLUGINHOST_AU 0 #endif /** JUCE_ONLY_BUILD_CORE_LIBRARY: Enabling this will avoid including any UI classes in the build. This should be enabled if you're writing a console application. */ #ifndef JUCE_ONLY_BUILD_CORE_LIBRARY #define JUCE_ONLY_BUILD_CORE_LIBRARY 0 #endif /** JUCE_WEB_BROWSER: This lets you disable the WebBrowserComponent class (Mac and Windows). If you're not using any embedded web-pages, turning this off may reduce your code size. */ #ifndef JUCE_WEB_BROWSER #define JUCE_WEB_BROWSER 1 #endif /** JUCE_SUPPORT_CARBON: Enabling this allows the Mac code to use old Carbon library functions. Carbon isn't required for a normal app, but may be needed by specialised classes like plugin-hosts, which support older APIs. */ #if ! (defined (JUCE_SUPPORT_CARBON) || defined (__LP64__)) #define JUCE_SUPPORT_CARBON 1 #endif /* JUCE_INCLUDE_ZLIB_CODE: Can be used to disable Juce's embedded 3rd-party zlib code. You might need to tweak this if you're linking to an external zlib library in your app, but for normal apps, this option should be left alone. */ #ifndef JUCE_INCLUDE_ZLIB_CODE #define JUCE_INCLUDE_ZLIB_CODE 1 #endif #ifndef JUCE_INCLUDE_FLAC_CODE #define JUCE_INCLUDE_FLAC_CODE 1 #endif #ifndef JUCE_INCLUDE_OGGVORBIS_CODE #define JUCE_INCLUDE_OGGVORBIS_CODE 1 #endif #ifndef JUCE_INCLUDE_PNGLIB_CODE #define JUCE_INCLUDE_PNGLIB_CODE 1 #endif #ifndef JUCE_INCLUDE_JPEGLIB_CODE #define JUCE_INCLUDE_JPEGLIB_CODE 1 #endif /** JUCE_CHECK_MEMORY_LEAKS: Enables a memory-leak check for certain objects when the app terminates. See the LeakedObjectDetector class and the JUCE_LEAK_DETECTOR macro for more details about enabling leak checking for specific classes. */ #if JUCE_DEBUG && ! defined (JUCE_CHECK_MEMORY_LEAKS) #define JUCE_CHECK_MEMORY_LEAKS 1 #endif /** JUCE_CATCH_UNHANDLED_EXCEPTIONS: Turn on juce's internal catching of exceptions that are thrown by the message dispatch loop. With it enabled, any unhandled exceptions are passed to the JUCEApplication::unhandledException() callback for logging. */ #ifndef JUCE_CATCH_UNHANDLED_EXCEPTIONS #define JUCE_CATCH_UNHANDLED_EXCEPTIONS 1 #endif // If only building the core classes, we can explicitly turn off some features to avoid including them: #if JUCE_ONLY_BUILD_CORE_LIBRARY #undef JUCE_QUICKTIME #define JUCE_QUICKTIME 0 #undef JUCE_OPENGL #define JUCE_OPENGL 0 #undef JUCE_USE_CDBURNER #define JUCE_USE_CDBURNER 0 #undef JUCE_USE_CDREADER #define JUCE_USE_CDREADER 0 #undef JUCE_WEB_BROWSER #define JUCE_WEB_BROWSER 0 #undef JUCE_PLUGINHOST_AU #define JUCE_PLUGINHOST_AU 0 #undef JUCE_PLUGINHOST_VST #define JUCE_PLUGINHOST_VST 0 #endif #endif /*** End of inlined file: juce_Config.h ***/ #ifdef JUCE_NAMESPACE #define BEGIN_JUCE_NAMESPACE namespace JUCE_NAMESPACE { #define END_JUCE_NAMESPACE } #else #define BEGIN_JUCE_NAMESPACE #define END_JUCE_NAMESPACE #endif /*** Start of inlined file: juce_PlatformDefs.h ***/ #ifndef __JUCE_PLATFORMDEFS_JUCEHEADER__ #define __JUCE_PLATFORMDEFS_JUCEHEADER__ /* This file defines miscellaneous macros for debugging, assertions, etc. */ #ifdef JUCE_FORCE_DEBUG #undef JUCE_DEBUG #if JUCE_FORCE_DEBUG #define JUCE_DEBUG 1 #endif #endif /** This macro defines the C calling convention used as the standard for Juce calls. */ #if JUCE_MSVC #define JUCE_CALLTYPE __stdcall #define JUCE_CDECL __cdecl #else #define JUCE_CALLTYPE #define JUCE_CDECL #endif // Debugging and assertion macros // (For info about JUCE_LOG_ASSERTIONS, have a look in juce_Config.h) #if JUCE_LOG_ASSERTIONS #define juce_LogCurrentAssertion juce_LogAssertion (__FILE__, __LINE__); #elif JUCE_DEBUG #define juce_LogCurrentAssertion std::cerr << "JUCE Assertion failure in " << __FILE__ << ", line " << __LINE__ << std::endl; #else #define juce_LogCurrentAssertion #endif #if JUCE_DEBUG // If debugging is enabled.. /** Writes a string to the standard error stream. This is only compiled in a debug build. @see Logger::outputDebugString */ #define DBG(dbgtext) { JUCE_NAMESPACE::String tempDbgBuf; tempDbgBuf << dbgtext; JUCE_NAMESPACE::Logger::outputDebugString (tempDbgBuf); } // Assertions.. #if JUCE_WINDOWS || DOXYGEN #if JUCE_USE_INTRINSICS #pragma intrinsic (__debugbreak) /** This will try to break the debugger if one is currently hosting this app. @see jassert() */ #define juce_breakDebugger __debugbreak(); #elif JUCE_GCC /** This will try to break the debugger if one is currently hosting this app. @see jassert() */ #define juce_breakDebugger asm("int $3"); #else /** This will try to break the debugger if one is currently hosting this app. @see jassert() */ #define juce_breakDebugger { __asm int 3 } #endif #elif JUCE_MAC #define juce_breakDebugger Debugger(); #elif JUCE_IOS #define juce_breakDebugger kill (0, SIGTRAP); #elif JUCE_LINUX #define juce_breakDebugger kill (0, SIGTRAP); #endif /** This will always cause an assertion failure. It is only compiled in a debug build, (unless JUCE_LOG_ASSERTIONS is enabled in juce_Config.h). @see jassert() */ #define jassertfalse { juce_LogCurrentAssertion; if (JUCE_NAMESPACE::juce_isRunningUnderDebugger()) juce_breakDebugger; } /** Platform-independent assertion macro. This gets optimised out when not being built with debugging turned on. Be careful not to call any functions within its arguments that are vital to the behaviour of the program, because these won't get called in the release build. @see jassertfalse */ #define jassert(expression) { if (! (expression)) jassertfalse; } #else // If debugging is disabled, these dummy debug and assertion macros are used.. #define DBG(dbgtext) #define jassertfalse { juce_LogCurrentAssertion } #if JUCE_LOG_ASSERTIONS #define jassert(expression) { if (! (expression)) jassertfalse; } #else #define jassert(a) { } #endif #endif #ifndef DOXYGEN BEGIN_JUCE_NAMESPACE template struct JuceStaticAssert; template <> struct JuceStaticAssert { static void dummy() {} }; END_JUCE_NAMESPACE #endif /** A compile-time assertion macro. If the expression parameter is false, the macro will cause a compile error. */ #define static_jassert(expression) JUCE_NAMESPACE::JuceStaticAssert::dummy(); /** This is a shorthand macro for declaring stubs for a class's copy constructor and operator=. For example, instead of @code class MyClass { etc.. private: MyClass (const MyClass&); MyClass& operator= (const MyClass&); };@endcode ..you can just write: @code class MyClass { etc.. private: JUCE_DECLARE_NON_COPYABLE (MyClass); };@endcode */ #define JUCE_DECLARE_NON_COPYABLE(className) \ className (const className&);\ className& operator= (const className&) /** This is a shorthand way of writing both a JUCE_DECLARE_NON_COPYABLE and JUCE_LEAK_DETECTOR macro for a class. */ #define JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(className) \ JUCE_DECLARE_NON_COPYABLE(className);\ JUCE_LEAK_DETECTOR(className) #if ! DOXYGEN #define JUCE_JOIN_MACRO_HELPER(a, b) a ## b #endif /** Good old C macro concatenation helper. This combines two items (which may themselves be macros) into a single string, avoiding the pitfalls of the ## macro operator. */ #define JUCE_JOIN_MACRO(a, b) JUCE_JOIN_MACRO_HELPER (a, b) #if JUCE_CATCH_UNHANDLED_EXCEPTIONS #define JUCE_TRY try #define JUCE_CATCH_ALL catch (...) {} #define JUCE_CATCH_ALL_ASSERT catch (...) { jassertfalse; } #if JUCE_ONLY_BUILD_CORE_LIBRARY #define JUCE_CATCH_EXCEPTION JUCE_CATCH_ALL #else /** Used in try-catch blocks, this macro will send exceptions to the JUCEApplication object so they can be logged by the application if it wants to. */ #define JUCE_CATCH_EXCEPTION \ catch (const std::exception& e) \ { \ JUCEApplication::sendUnhandledException (&e, __FILE__, __LINE__); \ } \ catch (...) \ { \ JUCEApplication::sendUnhandledException (0, __FILE__, __LINE__); \ } #endif #else #define JUCE_TRY #define JUCE_CATCH_EXCEPTION #define JUCE_CATCH_ALL #define JUCE_CATCH_ALL_ASSERT #endif // Macros for inlining. #if JUCE_MSVC /** A platform-independent way of forcing an inline function. Use the syntax: @code forcedinline void myfunction (int x) @endcode */ #ifndef JUCE_DEBUG #define forcedinline __forceinline #else #define forcedinline inline #endif #define JUCE_ALIGN(bytes) __declspec (align (bytes)) #else /** A platform-independent way of forcing an inline function. Use the syntax: @code forcedinline void myfunction (int x) @endcode */ #ifndef JUCE_DEBUG #define forcedinline inline __attribute__((always_inline)) #else #define forcedinline inline #endif #define JUCE_ALIGN(bytes) __attribute__ ((aligned (bytes))) #endif // Cross-compiler deprecation macros.. #if JUCE_MSVC && ! JUCE_NO_DEPRECATION_WARNINGS #define JUCE_DEPRECATED(functionDef) __declspec(deprecated) functionDef #elif JUCE_GCC && ! JUCE_NO_DEPRECATION_WARNINGS #define JUCE_DEPRECATED(functionDef) functionDef __attribute__ ((deprecated)) #else #define JUCE_DEPRECATED(functionDef) functionDef #endif #endif // __JUCE_PLATFORMDEFS_JUCEHEADER__ /*** End of inlined file: juce_PlatformDefs.h ***/ // Now we'll include any OS headers we need.. (at this point we are outside the Juce namespace). #if JUCE_MSVC #if JUCE_VC6 #pragma warning (disable: 4284 4786) // (spurious VC6 warnings) namespace std // VC6 doesn't have sqrt/sin/cos/tan/abs in std, so declare them here: { template Type abs (Type a) { if (a < 0) return -a; return a; } template Type tan (Type a) { return static_cast (::tan (static_cast (a))); } template Type sin (Type a) { return static_cast (::sin (static_cast (a))); } template Type cos (Type a) { return static_cast (::cos (static_cast (a))); } template Type sqrt (Type a) { return static_cast (::sqrt (static_cast (a))); } template Type floor (Type a) { return static_cast (::floor (static_cast (a))); } template Type ceil (Type a) { return static_cast (::ceil (static_cast (a))); } template Type atan2 (Type a, Type b) { return static_cast (::atan2 (static_cast (a), static_cast (b))); } } #endif #pragma warning (push) #pragma warning (disable: 4514 4245 4100) #endif #include #include #include #include #include #include #include #include #include #include #include #if JUCE_USE_INTRINSICS #include #endif #if JUCE_MAC || JUCE_IOS #include #endif #if JUCE_LINUX #include #if __INTEL_COMPILER #if __ia64__ #include #else #include #endif #endif #endif #if JUCE_MSVC && JUCE_DEBUG #include #endif #if JUCE_MSVC #include #pragma warning (pop) #if ! JUCE_PUBLIC_INCLUDES #pragma warning (4: 4511 4512 4100) // (enable some warnings that are turned off in VC8) #endif #endif // DLL building settings on Win32 #if JUCE_MSVC #ifdef JUCE_DLL_BUILD #define JUCE_API __declspec (dllexport) #pragma warning (disable: 4251) #elif defined (JUCE_DLL) #define JUCE_API __declspec (dllimport) #pragma warning (disable: 4251) #endif #elif defined (__GNUC__) && ((__GNUC__ >= 4) || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) #ifdef JUCE_DLL_BUILD #define JUCE_API __attribute__ ((visibility("default"))) #endif #endif #ifndef JUCE_API /** This macro is added to all juce public class declarations. */ #define JUCE_API #endif /** This macro is added to all juce public function declarations. */ #define JUCE_PUBLIC_FUNCTION JUCE_API JUCE_CALLTYPE /** This turns on some non-essential bits of code that should prevent old code from compiling in cases where method signatures have changed, etc. */ #if (! defined (JUCE_CATCH_DEPRECATED_CODE_MISUSE)) && JUCE_DEBUG && ! DOXYGEN #define JUCE_CATCH_DEPRECATED_CODE_MISUSE 1 #endif // Now include some basics that are needed by most of the Juce classes... BEGIN_JUCE_NAMESPACE extern JUCE_API bool JUCE_CALLTYPE juce_isRunningUnderDebugger(); #if JUCE_LOG_ASSERTIONS extern JUCE_API void juce_LogAssertion (const char* filename, int lineNum) throw(); #endif /*** Start of inlined file: juce_Memory.h ***/ #ifndef __JUCE_MEMORY_JUCEHEADER__ #define __JUCE_MEMORY_JUCEHEADER__ /* This file defines the various juce_malloc(), juce_free() macros that can be used in preference to the standard calls. None of this stuff is actually used in the library itself, and will probably be deprecated at some point in the future, to force everyone to use HeapBlock and other safer allocation methods. */ #if JUCE_MSVC && JUCE_CHECK_MEMORY_LEAKS && ! DOXYGEN #ifndef JUCE_DLL // Win32 debug non-DLL versions.. #define juce_malloc(numBytes) _malloc_dbg (numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) #define juce_calloc(numBytes) _calloc_dbg (1, numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) #define juce_realloc(location, numBytes) _realloc_dbg (location, numBytes, _NORMAL_BLOCK, __FILE__, __LINE__) #define juce_free(location) _free_dbg (location, _NORMAL_BLOCK) #else // Win32 debug DLL versions.. // For the DLL, we'll define some functions in the DLL that will be used for allocation - that // way all juce calls in the DLL and in the host API will all use the same allocator. extern JUCE_API void* juce_DebugMalloc (int size, const char* file, int line); extern JUCE_API void* juce_DebugCalloc (int size, const char* file, int line); extern JUCE_API void* juce_DebugRealloc (void* block, int size, const char* file, int line); extern JUCE_API void juce_DebugFree (void* block); #define juce_malloc(numBytes) JUCE_NAMESPACE::juce_DebugMalloc (numBytes, __FILE__, __LINE__) #define juce_calloc(numBytes) JUCE_NAMESPACE::juce_DebugCalloc (numBytes, __FILE__, __LINE__) #define juce_realloc(location, numBytes) JUCE_NAMESPACE::juce_DebugRealloc (location, numBytes, __FILE__, __LINE__) #define juce_free(location) JUCE_NAMESPACE::juce_DebugFree (location) #define JUCE_LEAK_DETECTOR(OwnerClass) public:\ static void* operator new (size_t sz) { void* const p = juce_malloc ((int) sz); return (p != 0) ? p : ::operator new (sz); } \ static void* operator new (size_t, void* p) { return p; } \ static void operator delete (void* p) { juce_free (p); } \ static void operator delete (void*, void*) {} #endif #elif defined (JUCE_DLL) && ! DOXYGEN // Win32 DLL (release) versions.. // For the DLL, we'll define some functions in the DLL that will be used for allocation - that // way all juce calls in the DLL and in the host API will all use the same allocator. extern JUCE_API void* juce_Malloc (int size); extern JUCE_API void* juce_Calloc (int size); extern JUCE_API void* juce_Realloc (void* block, int size); extern JUCE_API void juce_Free (void* block); #define juce_malloc(numBytes) JUCE_NAMESPACE::juce_Malloc (numBytes) #define juce_calloc(numBytes) JUCE_NAMESPACE::juce_Calloc (numBytes) #define juce_realloc(location, numBytes) JUCE_NAMESPACE::juce_Realloc (location, numBytes) #define juce_free(location) JUCE_NAMESPACE::juce_Free (location) #define JUCE_LEAK_DETECTOR(OwnerClass) public:\ static void* operator new (size_t sz) { void* const p = juce_malloc ((int) sz); return (p != 0) ? p : ::operator new (sz); } \ static void* operator new (size_t, void* p) { return p; } \ static void operator delete (void* p) { juce_free (p); } \ static void operator delete (void*, void*) {} #else // Mac, Linux and Win32 (release) versions.. /** This can be used instead of calling malloc directly. Only use direct memory allocation if there's really no way to use a HeapBlock object instead! */ #define juce_malloc(numBytes) malloc (numBytes) /** This can be used instead of calling calloc directly. Only use direct memory allocation if there's really no way to use a HeapBlock object instead! */ #define juce_calloc(numBytes) calloc (1, numBytes) /** This can be used instead of calling realloc directly. Only use direct memory allocation if there's really no way to use a HeapBlock object instead! */ #define juce_realloc(location, numBytes) realloc (location, numBytes) /** This can be used instead of calling free directly. Only use direct memory allocation if there's really no way to use a HeapBlock object instead! */ #define juce_free(location) free (location) #endif /** (Deprecated) This was a win32-specific way of checking for object leaks - now please use the JUCE_LEAK_DETECTOR instead. */ #ifndef juce_UseDebuggingNewOperator #define juce_UseDebuggingNewOperator #endif #if JUCE_MSVC || DOXYGEN /** This is a compiler-independent way of declaring a variable as being thread-local. E.g. @code juce_ThreadLocal int myVariable; @endcode */ #define juce_ThreadLocal __declspec(thread) #else #define juce_ThreadLocal __thread #endif #if JUCE_MINGW /** This allocator is not defined in mingw gcc. */ #define alloca __builtin_alloca #endif /** Fills a block of memory with zeros. */ inline void zeromem (void* memory, size_t numBytes) throw() { memset (memory, 0, numBytes); } /** Overwrites a structure or object with zeros. */ template inline void zerostruct (Type& structure) throw() { memset (&structure, 0, sizeof (structure)); } /** Delete an object pointer, and sets the pointer to null. Remember that it's not good c++ practice to use delete directly - always try to use a ScopedPointer or other automatic lieftime-management system rather than resorting to deleting raw pointers! */ template inline void deleteAndZero (Type& pointer) { delete pointer; pointer = 0; } /** A handy function which adds a number of bytes to any type of pointer and returns the result. This can be useful to avoid casting pointers to a char* and back when you want to move them by a specific number of bytes, */ template inline Type* addBytesToPointer (Type* pointer, int bytes) throw() { return (Type*) (((char*) pointer) + bytes); } #endif // __JUCE_MEMORY_JUCEHEADER__ /*** End of inlined file: juce_Memory.h ***/ /*** Start of inlined file: juce_MathsFunctions.h ***/ #ifndef __JUCE_MATHSFUNCTIONS_JUCEHEADER__ #define __JUCE_MATHSFUNCTIONS_JUCEHEADER__ /* This file sets up some handy mathematical typdefs and functions. */ // Definitions for the int8, int16, int32, int64 and pointer_sized_int types. /** A platform-independent 8-bit signed integer type. */ typedef signed char int8; /** A platform-independent 8-bit unsigned integer type. */ typedef unsigned char uint8; /** A platform-independent 16-bit signed integer type. */ typedef signed short int16; /** A platform-independent 16-bit unsigned integer type. */ typedef unsigned short uint16; /** A platform-independent 32-bit signed integer type. */ typedef signed int int32; /** A platform-independent 32-bit unsigned integer type. */ typedef unsigned int uint32; #if JUCE_MSVC /** A platform-independent 64-bit integer type. */ typedef __int64 int64; /** A platform-independent 64-bit unsigned integer type. */ typedef unsigned __int64 uint64; /** A platform-independent macro for writing 64-bit literals, needed because different compilers have different syntaxes for this. E.g. writing literal64bit (0x1000000000) will translate to 0x1000000000LL for GCC, or 0x1000000000 for MSVC. */ #define literal64bit(longLiteral) ((__int64) longLiteral) #else /** A platform-independent 64-bit integer type. */ typedef long long int64; /** A platform-independent 64-bit unsigned integer type. */ typedef unsigned long long uint64; /** A platform-independent macro for writing 64-bit literals, needed because different compilers have different syntaxes for this. E.g. writing literal64bit (0x1000000000) will translate to 0x1000000000LL for GCC, or 0x1000000000 for MSVC. */ #define literal64bit(longLiteral) (longLiteral##LL) #endif #if JUCE_64BIT /** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */ typedef int64 pointer_sized_int; /** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */ typedef uint64 pointer_sized_uint; #elif JUCE_MSVC && ! JUCE_VC6 /** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */ typedef _W64 int pointer_sized_int; /** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */ typedef _W64 unsigned int pointer_sized_uint; #else /** A signed integer type that's guaranteed to be large enough to hold a pointer without truncating it. */ typedef int pointer_sized_int; /** An unsigned integer type that's guaranteed to be large enough to hold a pointer without truncating it. */ typedef unsigned int pointer_sized_uint; #endif /** A platform-independent unicode character type. */ typedef wchar_t juce_wchar; // Some indispensible min/max functions /** Returns the larger of two values. */ template inline Type jmax (const Type a, const Type b) { return (a < b) ? b : a; } /** Returns the larger of three values. */ template inline Type jmax (const Type a, const Type b, const Type c) { return (a < b) ? ((b < c) ? c : b) : ((a < c) ? c : a); } /** Returns the larger of four values. */ template inline Type jmax (const Type a, const Type b, const Type c, const Type d) { return jmax (a, jmax (b, c, d)); } /** Returns the smaller of two values. */ template inline Type jmin (const Type a, const Type b) { return (b < a) ? b : a; } /** Returns the smaller of three values. */ template inline Type jmin (const Type a, const Type b, const Type c) { return (b < a) ? ((c < b) ? c : b) : ((c < a) ? c : a); } /** Returns the smaller of four values. */ template inline Type jmin (const Type a, const Type b, const Type c, const Type d) { return jmin (a, jmin (b, c, d)); } /** Scans an array of values, returning the minimum value that it contains. */ template const Type findMinimum (const Type* data, int numValues) { if (numValues <= 0) return Type(); Type result (*data++); while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample) { const Type& v = *data++; if (v < result) result = v; } return result; } /** Scans an array of values, returning the minimum value that it contains. */ template const Type findMaximum (const Type* values, int numValues) { if (numValues <= 0) return Type(); Type result (*values++); while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample) { const Type& v = *values++; if (result > v) result = v; } return result; } /** Scans an array of values, returning the minimum and maximum values that it contains. */ template void findMinAndMax (const Type* values, int numValues, Type& lowest, Type& highest) { if (numValues <= 0) { lowest = Type(); highest = Type(); } else { Type mn (*values++); Type mx (mn); while (--numValues > 0) // (> 0 rather than >= 0 because we've already taken the first sample) { const Type& v = *values++; if (mx < v) mx = v; if (v < mn) mn = v; } lowest = mn; highest = mx; } } /** Constrains a value to keep it within a given range. This will check that the specified value lies between the lower and upper bounds specified, and if not, will return the nearest value that would be in-range. Effectively, it's like calling jmax (lowerLimit, jmin (upperLimit, value)). Note that it expects that lowerLimit <= upperLimit. If this isn't true, the results will be unpredictable. @param lowerLimit the minimum value to return @param upperLimit the maximum value to return @param valueToConstrain the value to try to return @returns the closest value to valueToConstrain which lies between lowerLimit and upperLimit (inclusive) @see jlimit0To, jmin, jmax */ template inline Type jlimit (const Type lowerLimit, const Type upperLimit, const Type valueToConstrain) throw() { jassert (lowerLimit <= upperLimit); // if these are in the wrong order, results are unpredictable.. return (valueToConstrain < lowerLimit) ? lowerLimit : ((upperLimit < valueToConstrain) ? upperLimit : valueToConstrain); } /** Returns true if a value is at least zero, and also below a specified upper limit. This is basically a quicker way to write: @code valueToTest >= 0 && valueToTest < upperLimit @endcode */ template inline bool isPositiveAndBelow (Type valueToTest, Type upperLimit) throw() { jassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero.. return Type() <= valueToTest && valueToTest < upperLimit; } #if ! JUCE_VC6 template <> inline bool isPositiveAndBelow (const int valueToTest, const int upperLimit) throw() { jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero.. return static_cast (valueToTest) < static_cast (upperLimit); } #endif /** Returns true if a value is at least zero, and also less than or equal to a specified upper limit. This is basically a quicker way to write: @code valueToTest >= 0 && valueToTest <= upperLimit @endcode */ template inline bool isPositiveAndNotGreaterThan (Type valueToTest, Type upperLimit) throw() { jassert (Type() <= upperLimit); // makes no sense to call this if the upper limit is itself below zero.. return Type() <= valueToTest && valueToTest <= upperLimit; } #if ! JUCE_VC6 template <> inline bool isPositiveAndNotGreaterThan (const int valueToTest, const int upperLimit) throw() { jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero.. return static_cast (valueToTest) <= static_cast (upperLimit); } #endif /** Handy function to swap two values over. */ template inline void swapVariables (Type& variable1, Type& variable2) { const Type tempVal = variable1; variable1 = variable2; variable2 = tempVal; } #if JUCE_VC6 #define numElementsInArray(X) (sizeof((X)) / sizeof(0[X])) #else /** Handy function for getting the number of elements in a simple const C array. E.g. @code static int myArray[] = { 1, 2, 3 }; int numElements = numElementsInArray (myArray) // returns 3 @endcode */ template inline int numElementsInArray (Type (&array)[N]) { (void) array; // (required to avoid a spurious warning in MS compilers) (void) sizeof (0[array]); // This line should cause an error if you pass an object with a user-defined subscript operator return N; } #endif // Some useful maths functions that aren't always present with all compilers and build settings. /** Using juce_hypot is easier than dealing with the different types of hypot function that are provided by the various platforms and compilers. */ template inline Type juce_hypot (Type a, Type b) throw() { #if JUCE_WINDOWS return static_cast (_hypot (a, b)); #else return static_cast (hypot (a, b)); #endif } /** 64-bit abs function. */ inline int64 abs64 (const int64 n) throw() { return (n >= 0) ? n : -n; } /** This templated negate function will negate pointers as well as integers */ template inline Type juce_negate (Type n) throw() { return sizeof (Type) == 1 ? (Type) -(char) n : (sizeof (Type) == 2 ? (Type) -(short) n : (sizeof (Type) == 4 ? (Type) -(int) n : ((Type) -(int64) n))); } /** This templated negate function will negate pointers as well as integers */ template inline Type* juce_negate (Type* n) throw() { return (Type*) -(pointer_sized_int) n; } /** A predefined value for Pi, at double-precision. @see float_Pi */ const double double_Pi = 3.1415926535897932384626433832795; /** A predefined value for Pi, at sngle-precision. @see double_Pi */ const float float_Pi = 3.14159265358979323846f; /** The isfinite() method seems to vary between platforms, so this is a platform-independent function for it. */ template inline bool juce_isfinite (FloatingPointType value) { #if JUCE_WINDOWS return _finite (value); #else return std::isfinite (value); #endif } /** Fast floating-point-to-integer conversion. This is faster than using the normal c++ cast to convert a float to an int, and it will round the value to the nearest integer, rather than rounding it down like the normal cast does. Note that this routine gets its speed at the expense of some accuracy, and when rounding values whose floating point component is exactly 0.5, odd numbers and even numbers will be rounded up or down differently. */ template inline int roundToInt (const FloatType value) throw() { union { int asInt[2]; double asDouble; } n; n.asDouble = ((double) value) + 6755399441055744.0; #if JUCE_BIG_ENDIAN return n.asInt [1]; #else return n.asInt [0]; #endif } /** Fast floating-point-to-integer conversion. This is a slightly slower and slightly more accurate version of roundDoubleToInt(). It works fine for values above zero, but negative numbers are rounded the wrong way. */ inline int roundToIntAccurate (const double value) throw() { return roundToInt (value + 1.5e-8); } /** Fast floating-point-to-integer conversion. This is faster than using the normal c++ cast to convert a double to an int, and it will round the value to the nearest integer, rather than rounding it down like the normal cast does. Note that this routine gets its speed at the expense of some accuracy, and when rounding values whose floating point component is exactly 0.5, odd numbers and even numbers will be rounded up or down differently. For a more accurate conversion, see roundDoubleToIntAccurate(). */ inline int roundDoubleToInt (const double value) throw() { return roundToInt (value); } /** Fast floating-point-to-integer conversion. This is faster than using the normal c++ cast to convert a float to an int, and it will round the value to the nearest integer, rather than rounding it down like the normal cast does. Note that this routine gets its speed at the expense of some accuracy, and when rounding values whose floating point component is exactly 0.5, odd numbers and even numbers will be rounded up or down differently. */ inline int roundFloatToInt (const float value) throw() { return roundToInt (value); } /** This namespace contains a few template classes for helping work out class type variations. */ namespace TypeHelpers { #if JUCE_VC8_OR_EARLIER #define PARAMETER_TYPE(a) a #else /** The ParameterType struct is used to find the best type to use when passing some kind of object as a parameter. Of course, this is only likely to be useful in certain esoteric template situations. Because "typename TypeHelpers::ParameterType::type" is a bit of a mouthful, there's a PARAMETER_TYPE(SomeClass) macro that you can use to get the same effect. E.g. "myFunction (PARAMETER_TYPE (int), PARAMETER_TYPE (MyObject))" would evaluate to "myfunction (int, const MyObject&)", keeping any primitive types as pass-by-value, but passing objects as a const reference, to avoid copying. */ template struct ParameterType { typedef const Type& type; }; #if ! DOXYGEN template struct ParameterType { typedef Type& type; }; template struct ParameterType { typedef Type* type; }; template <> struct ParameterType { typedef char type; }; template <> struct ParameterType { typedef unsigned char type; }; template <> struct ParameterType { typedef short type; }; template <> struct ParameterType { typedef unsigned short type; }; template <> struct ParameterType { typedef int type; }; template <> struct ParameterType { typedef unsigned int type; }; template <> struct ParameterType { typedef long type; }; template <> struct ParameterType { typedef unsigned long type; }; template <> struct ParameterType { typedef int64 type; }; template <> struct ParameterType { typedef uint64 type; }; template <> struct ParameterType { typedef bool type; }; template <> struct ParameterType { typedef float type; }; template <> struct ParameterType { typedef double type; }; #endif /** A helpful macro to simplify the use of the ParameterType template. @see ParameterType */ #define PARAMETER_TYPE(a) typename TypeHelpers::ParameterType::type #endif } #endif // __JUCE_MATHSFUNCTIONS_JUCEHEADER__ /*** End of inlined file: juce_MathsFunctions.h ***/ /*** Start of inlined file: juce_ByteOrder.h ***/ #ifndef __JUCE_BYTEORDER_JUCEHEADER__ #define __JUCE_BYTEORDER_JUCEHEADER__ /** Contains static methods for converting the byte order between different endiannesses. */ class JUCE_API ByteOrder { public: /** Swaps the upper and lower bytes of a 16-bit integer. */ static uint16 swap (uint16 value); /** Reverses the order of the 4 bytes in a 32-bit integer. */ static uint32 swap (uint32 value); /** Reverses the order of the 8 bytes in a 64-bit integer. */ static uint64 swap (uint64 value); /** Swaps the byte order of a 16-bit int if the CPU is big-endian */ static uint16 swapIfBigEndian (uint16 value); /** Swaps the byte order of a 32-bit int if the CPU is big-endian */ static uint32 swapIfBigEndian (uint32 value); /** Swaps the byte order of a 64-bit int if the CPU is big-endian */ static uint64 swapIfBigEndian (uint64 value); /** Swaps the byte order of a 16-bit int if the CPU is little-endian */ static uint16 swapIfLittleEndian (uint16 value); /** Swaps the byte order of a 32-bit int if the CPU is little-endian */ static uint32 swapIfLittleEndian (uint32 value); /** Swaps the byte order of a 64-bit int if the CPU is little-endian */ static uint64 swapIfLittleEndian (uint64 value); /** Turns 4 bytes into a little-endian integer. */ static uint32 littleEndianInt (const void* bytes); /** Turns 2 bytes into a little-endian integer. */ static uint16 littleEndianShort (const void* bytes); /** Turns 4 bytes into a big-endian integer. */ static uint32 bigEndianInt (const void* bytes); /** Turns 2 bytes into a big-endian integer. */ static uint16 bigEndianShort (const void* bytes); /** Converts 3 little-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */ static int littleEndian24Bit (const char* bytes); /** Converts 3 big-endian bytes into a signed 24-bit value (which is sign-extended to 32 bits). */ static int bigEndian24Bit (const char* bytes); /** Copies a 24-bit number to 3 little-endian bytes. */ static void littleEndian24BitToChars (int value, char* destBytes); /** Copies a 24-bit number to 3 big-endian bytes. */ static void bigEndian24BitToChars (int value, char* destBytes); /** Returns true if the current CPU is big-endian. */ static bool isBigEndian(); private: ByteOrder(); JUCE_DECLARE_NON_COPYABLE (ByteOrder); }; #if JUCE_USE_INTRINSICS #pragma intrinsic (_byteswap_ulong) #endif inline uint16 ByteOrder::swap (uint16 n) { #if JUCE_USE_INTRINSICSxxx // agh - the MS compiler has an internal error when you try to use this intrinsic! return static_cast (_byteswap_ushort (n)); #else return static_cast ((n << 8) | (n >> 8)); #endif } inline uint32 ByteOrder::swap (uint32 n) { #if JUCE_MAC || JUCE_IOS return OSSwapInt32 (n); #elif JUCE_GCC asm("bswap %%eax" : "=a"(n) : "a"(n)); return n; #elif JUCE_USE_INTRINSICS return _byteswap_ulong (n); #else __asm { mov eax, n bswap eax mov n, eax } return n; #endif } inline uint64 ByteOrder::swap (uint64 value) { #if JUCE_MAC || JUCE_IOS return OSSwapInt64 (value); #elif JUCE_USE_INTRINSICS return _byteswap_uint64 (value); #else return (((int64) swap ((uint32) value)) << 32) | swap ((uint32) (value >> 32)); #endif } #if JUCE_LITTLE_ENDIAN inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) { return v; } inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) { return v; } inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) { return v; } inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) { return swap (v); } inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) { return swap (v); } inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) { return swap (v); } inline uint32 ByteOrder::littleEndianInt (const void* const bytes) { return *static_cast (bytes); } inline uint16 ByteOrder::littleEndianShort (const void* const bytes) { return *static_cast (bytes); } inline uint32 ByteOrder::bigEndianInt (const void* const bytes) { return swap (*static_cast (bytes)); } inline uint16 ByteOrder::bigEndianShort (const void* const bytes) { return swap (*static_cast (bytes)); } inline bool ByteOrder::isBigEndian() { return false; } #else inline uint16 ByteOrder::swapIfBigEndian (const uint16 v) { return swap (v); } inline uint32 ByteOrder::swapIfBigEndian (const uint32 v) { return swap (v); } inline uint64 ByteOrder::swapIfBigEndian (const uint64 v) { return swap (v); } inline uint16 ByteOrder::swapIfLittleEndian (const uint16 v) { return v; } inline uint32 ByteOrder::swapIfLittleEndian (const uint32 v) { return v; } inline uint64 ByteOrder::swapIfLittleEndian (const uint64 v) { return v; } inline uint32 ByteOrder::littleEndianInt (const void* const bytes) { return swap (*static_cast (bytes)); } inline uint16 ByteOrder::littleEndianShort (const void* const bytes) { return swap (*static_cast (bytes)); } inline uint32 ByteOrder::bigEndianInt (const void* const bytes) { return *static_cast (bytes); } inline uint16 ByteOrder::bigEndianShort (const void* const bytes) { return *static_cast (bytes); } inline bool ByteOrder::isBigEndian() { return true; } #endif inline int ByteOrder::littleEndian24Bit (const char* const bytes) { return (((int) bytes[2]) << 16) | (((uint32) (uint8) bytes[1]) << 8) | ((uint32) (uint8) bytes[0]); } inline int ByteOrder::bigEndian24Bit (const char* const bytes) { return (((int) bytes[0]) << 16) | (((uint32) (uint8) bytes[1]) << 8) | ((uint32) (uint8) bytes[2]); } inline void ByteOrder::littleEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)(value & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)((value >> 16) & 0xff); } inline void ByteOrder::bigEndian24BitToChars (const int value, char* const destBytes) { destBytes[0] = (char)((value >> 16) & 0xff); destBytes[1] = (char)((value >> 8) & 0xff); destBytes[2] = (char)(value & 0xff); } #endif // __JUCE_BYTEORDER_JUCEHEADER__ /*** End of inlined file: juce_ByteOrder.h ***/ /*** Start of inlined file: juce_Logger.h ***/ #ifndef __JUCE_LOGGER_JUCEHEADER__ #define __JUCE_LOGGER_JUCEHEADER__ /*** Start of inlined file: juce_String.h ***/ #ifndef __JUCE_STRING_JUCEHEADER__ #define __JUCE_STRING_JUCEHEADER__ /*** Start of inlined file: juce_CharacterFunctions.h ***/ #ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__ #define __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__ #define JUCE_T(stringLiteral) (L##stringLiteral) typedef juce_wchar tchar; #if ! JUCE_DONT_DEFINE_MACROS /** The 'T' macro allows a literal string to be compiled as unicode. If you write your string literals in the form T("xyz"), it will be compiled as L"xyz" or "xyz", depending on which representation is best for the String class to work with. Because the 'T' symbol is occasionally used inside 3rd-party library headers which you may need to include after juce.h, you can use the juce_withoutMacros.h file (in the juce/src directory) to avoid defining this macro. See the comments in juce_withoutMacros.h for more info. */ #define T(stringLiteral) JUCE_T(stringLiteral) #endif /** A set of methods for manipulating characters and character strings, with duplicate methods to handle 8-bit and unicode characters. These are defined as wrappers around the basic C string handlers, to provide a clean, cross-platform layer, (because various platforms differ in the range of C library calls that they provide). @see String */ class JUCE_API CharacterFunctions { public: static int length (const char* s) throw(); static int length (const juce_wchar* s) throw(); static void copy (char* dest, const char* src, int maxBytes) throw(); static void copy (juce_wchar* dest, const juce_wchar* src, int maxChars) throw(); static void copy (juce_wchar* dest, const char* src, int maxChars) throw(); static void copy (char* dest, const juce_wchar* src, int maxBytes) throw(); static int bytesRequiredForCopy (const juce_wchar* src) throw(); static void append (char* dest, const char* src) throw(); static void append (juce_wchar* dest, const juce_wchar* src) throw(); static int compare (const char* s1, const char* s2) throw(); static int compare (const juce_wchar* s1, const juce_wchar* s2) throw(); static int compare (const juce_wchar* s1, const char* s2) throw(); static int compare (const char* s1, const juce_wchar* s2) throw(); static int compare (const char* s1, const char* s2, int maxChars) throw(); static int compare (const juce_wchar* s1, const juce_wchar* s2, int maxChars) throw(); static int compareIgnoreCase (const char* s1, const char* s2) throw(); static int compareIgnoreCase (const juce_wchar* s1, const juce_wchar* s2) throw(); static int compareIgnoreCase (const juce_wchar* s1, const char* s2) throw(); static int compareIgnoreCase (const char* s1, const char* s2, int maxChars) throw(); static int compareIgnoreCase (const juce_wchar* s1, const juce_wchar* s2, int maxChars) throw(); static const char* find (const char* haystack, const char* needle) throw(); static const juce_wchar* find (const juce_wchar* haystack, const juce_wchar* needle) throw(); static int indexOfChar (const char* haystack, char needle, bool ignoreCase) throw(); static int indexOfChar (const juce_wchar* haystack, juce_wchar needle, bool ignoreCase) throw(); static int indexOfCharFast (const char* haystack, char needle) throw(); static int indexOfCharFast (const juce_wchar* haystack, juce_wchar needle) throw(); static int getIntialSectionContainingOnly (const char* text, const char* allowedChars) throw(); static int getIntialSectionContainingOnly (const juce_wchar* text, const juce_wchar* allowedChars) throw(); static int ftime (char* dest, int maxChars, const char* format, const struct tm* tm) throw(); static int ftime (juce_wchar* dest, int maxChars, const juce_wchar* format, const struct tm* tm) throw(); static int getIntValue (const char* s) throw(); static int getIntValue (const juce_wchar* s) throw(); static int64 getInt64Value (const char* s) throw(); static int64 getInt64Value (const juce_wchar* s) throw(); static double getDoubleValue (const char* s) throw(); static double getDoubleValue (const juce_wchar* s) throw(); static char toUpperCase (char character) throw(); static juce_wchar toUpperCase (juce_wchar character) throw(); static void toUpperCase (char* s) throw(); static void toUpperCase (juce_wchar* s) throw(); static bool isUpperCase (char character) throw(); static bool isUpperCase (juce_wchar character) throw(); static char toLowerCase (char character) throw(); static juce_wchar toLowerCase (juce_wchar character) throw(); static void toLowerCase (char* s) throw(); static void toLowerCase (juce_wchar* s) throw(); static bool isLowerCase (char character) throw(); static bool isLowerCase (juce_wchar character) throw(); static bool isWhitespace (char character) throw(); static bool isWhitespace (juce_wchar character) throw(); static bool isDigit (char character) throw(); static bool isDigit (juce_wchar character) throw(); static bool isLetter (char character) throw(); static bool isLetter (juce_wchar character) throw(); static bool isLetterOrDigit (char character) throw(); static bool isLetterOrDigit (juce_wchar character) throw(); /** Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legel hex digit. */ static int getHexDigitValue (juce_wchar digit) throw(); }; #endif // __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__ /*** End of inlined file: juce_CharacterFunctions.h ***/ class OutputStream; /** The JUCE String class! Using a reference-counted internal representation, these strings are fast and efficient, and there are methods to do just about any operation you'll ever dream of. @see StringArray, StringPairArray */ class JUCE_API String { public: /** Creates an empty string. @see empty */ String() throw(); /** Creates a copy of another string. */ String (const String& other) throw(); /** Creates a string from a zero-terminated text string. The string is assumed to be stored in the default system encoding. */ String (const char* text); /** Creates a string from an string of characters. This will use up the the first maxChars characters of the string (or less if the string is actually shorter) */ String (const char* text, size_t maxChars); /** Creates a string from a zero-terminated unicode text string. */ String (const juce_wchar* unicodeText); /** Creates a string from a unicode text string. This will use up the the first maxChars characters of the string (or less if the string is actually shorter) */ String (const juce_wchar* unicodeText, size_t maxChars); /** Creates a string from a single character. */ static const String charToString (juce_wchar character); /** Destructor. */ ~String() throw(); /** This is an empty string that can be used whenever one is needed. It's better to use this than String() because it explains what's going on and is more efficient. */ static const String empty; /** Generates a probably-unique 32-bit hashcode from this string. */ int hashCode() const throw(); /** Generates a probably-unique 64-bit hashcode from this string. */ int64 hashCode64() const throw(); /** Returns the number of characters in the string. */ int length() const throw(); // Assignment and concatenation operators.. /** Replaces this string's contents with another string. */ String& operator= (const String& other) throw(); /** Appends another string at the end of this one. */ String& operator+= (const juce_wchar* textToAppend); /** Appends another string at the end of this one. */ String& operator+= (const String& stringToAppend); /** Appends a character at the end of this string. */ String& operator+= (char characterToAppend); /** Appends a character at the end of this string. */ String& operator+= (juce_wchar characterToAppend); /** Appends a decimal number at the end of this string. */ String& operator+= (int numberToAppend); /** Appends a decimal number at the end of this string. */ String& operator+= (unsigned int numberToAppend); /** Appends a string at the end of this one. @param textToAppend the string to add @param maxCharsToTake the maximum number of characters to take from the string passed in */ void append (const juce_wchar* textToAppend, int maxCharsToTake); // Comparison methods.. /** Returns true if the string contains no characters. Note that there's also an isNotEmpty() method to help write readable code. @see containsNonWhitespaceChars() */ inline bool isEmpty() const throw() { return text[0] == 0; } /** Returns true if the string contains at least one character. Note that there's also an isEmpty() method to help write readable code. @see containsNonWhitespaceChars() */ inline bool isNotEmpty() const throw() { return text[0] != 0; } /** Case-insensitive comparison with another string. */ bool equalsIgnoreCase (const String& other) const throw(); /** Case-insensitive comparison with another string. */ bool equalsIgnoreCase (const juce_wchar* other) const throw(); /** Case-insensitive comparison with another string. */ bool equalsIgnoreCase (const char* other) const throw(); /** Case-sensitive comparison with another string. @returns 0 if the two strings are identical; negative if this string comes before the other one alphabetically, or positive if it comes after it. */ int compare (const String& other) const throw(); /** Case-sensitive comparison with another string. @returns 0 if the two strings are identical; negative if this string comes before the other one alphabetically, or positive if it comes after it. */ int compare (const char* other) const throw(); /** Case-sensitive comparison with another string. @returns 0 if the two strings are identical; negative if this string comes before the other one alphabetically, or positive if it comes after it. */ int compare (const juce_wchar* other) const throw(); /** Case-insensitive comparison with another string. @returns 0 if the two strings are identical; negative if this string comes before the other one alphabetically, or positive if it comes after it. */ int compareIgnoreCase (const String& other) const throw(); /** Lexicographic comparison with another string. The comparison used here is case-insensitive and ignores leading non-alphanumeric characters, making it good for sorting human-readable strings. @returns 0 if the two strings are identical; negative if this string comes before the other one alphabetically, or positive if it comes after it. */ int compareLexicographically (const String& other) const throw(); /** Tests whether the string begins with another string. If the parameter is an empty string, this will always return true. Uses a case-sensitive comparison. */ bool startsWith (const String& text) const throw(); /** Tests whether the string begins with a particular character. If the character is 0, this will always return false. Uses a case-sensitive comparison. */ bool startsWithChar (juce_wchar character) const throw(); /** Tests whether the string begins with another string. If the parameter is an empty string, this will always return true. Uses a case-insensitive comparison. */ bool startsWithIgnoreCase (const String& text) const throw(); /** Tests whether the string ends with another string. If the parameter is an empty string, this will always return true. Uses a case-sensitive comparison. */ bool endsWith (const String& text) const throw(); /** Tests whether the string ends with a particular character. If the character is 0, this will always return false. Uses a case-sensitive comparison. */ bool endsWithChar (juce_wchar character) const throw(); /** Tests whether the string ends with another string. If the parameter is an empty string, this will always return true. Uses a case-insensitive comparison. */ bool endsWithIgnoreCase (const String& text) const throw(); /** Tests whether the string contains another substring. If the parameter is an empty string, this will always return true. Uses a case-sensitive comparison. */ bool contains (const String& text) const throw(); /** Tests whether the string contains a particular character. Uses a case-sensitive comparison. */ bool containsChar (juce_wchar character) const throw(); /** Tests whether the string contains another substring. Uses a case-insensitive comparison. */ bool containsIgnoreCase (const String& text) const throw(); /** Tests whether the string contains another substring as a distict word. @returns true if the string contains this word, surrounded by non-alphanumeric characters @see indexOfWholeWord, containsWholeWordIgnoreCase */ bool containsWholeWord (const String& wordToLookFor) const throw(); /** Tests whether the string contains another substring as a distict word. @returns true if the string contains this word, surrounded by non-alphanumeric characters @see indexOfWholeWordIgnoreCase, containsWholeWord */ bool containsWholeWordIgnoreCase (const String& wordToLookFor) const throw(); /** Finds an instance of another substring if it exists as a distict word. @returns if the string contains this word, surrounded by non-alphanumeric characters, then this will return the index of the start of the substring. If it isn't found, then it will return -1 @see indexOfWholeWordIgnoreCase, containsWholeWord */ int indexOfWholeWord (const String& wordToLookFor) const throw(); /** Finds an instance of another substring if it exists as a distict word. @returns if the string contains this word, surrounded by non-alphanumeric characters, then this will return the index of the start of the substring. If it isn't found, then it will return -1 @see indexOfWholeWord, containsWholeWordIgnoreCase */ int indexOfWholeWordIgnoreCase (const String& wordToLookFor) const throw(); /** Looks for any of a set of characters in the string. Uses a case-sensitive comparison. @returns true if the string contains any of the characters from the string that is passed in. */ bool containsAnyOf (const String& charactersItMightContain) const throw(); /** Looks for a set of characters in the string. Uses a case-sensitive comparison. @returns Returns false if any of the characters in this string do not occur in the parameter string. If this string is empty, the return value will always be true. */ bool containsOnly (const String& charactersItMightContain) const throw(); /** Returns true if this string contains any non-whitespace characters. This will return false if the string contains only whitespace characters, or if it's empty. It is equivalent to calling "myString.trim().isNotEmpty()". */ bool containsNonWhitespaceChars() const throw(); /** Returns true if the string matches this simple wildcard expression. So for example String ("abcdef").matchesWildcard ("*DEF", true) would return true. This isn't a full-blown regex though! The only wildcard characters supported are "*" and "?". It's mainly intended for filename pattern matching. */ bool matchesWildcard (const String& wildcard, bool ignoreCase) const throw(); // Substring location methods.. /** Searches for a character inside this string. Uses a case-sensitive comparison. @returns the index of the first occurrence of the character in this string, or -1 if it's not found. */ int indexOfChar (juce_wchar characterToLookFor) const throw(); /** Searches for a character inside this string. Uses a case-sensitive comparison. @param startIndex the index from which the search should proceed @param characterToLookFor the character to look for @returns the index of the first occurrence of the character in this string, or -1 if it's not found. */ int indexOfChar (int startIndex, juce_wchar characterToLookFor) const throw(); /** Returns the index of the first character that matches one of the characters passed-in to this method. This scans the string, beginning from the startIndex supplied, and if it finds a character that appears in the string charactersToLookFor, it returns its index. If none of these characters are found, it returns -1. If ignoreCase is true, the comparison will be case-insensitive. @see indexOfChar, lastIndexOfAnyOf */ int indexOfAnyOf (const String& charactersToLookFor, int startIndex = 0, bool ignoreCase = false) const throw(); /** Searches for a substring within this string. Uses a case-sensitive comparison. @returns the index of the first occurrence of this substring, or -1 if it's not found. */ int indexOf (const String& text) const throw(); /** Searches for a substring within this string. Uses a case-sensitive comparison. @param startIndex the index from which the search should proceed @param textToLookFor the string to search for @returns the index of the first occurrence of this substring, or -1 if it's not found. */ int indexOf (int startIndex, const String& textToLookFor) const throw(); /** Searches for a substring within this string. Uses a case-insensitive comparison. @returns the index of the first occurrence of this substring, or -1 if it's not found. */ int indexOfIgnoreCase (const String& textToLookFor) const throw(); /** Searches for a substring within this string. Uses a case-insensitive comparison. @param startIndex the index from which the search should proceed @param textToLookFor the string to search for @returns the index of the first occurrence of this substring, or -1 if it's not found. */ int indexOfIgnoreCase (int startIndex, const String& textToLookFor) const throw(); /** Searches for a character inside this string (working backwards from the end of the string). Uses a case-sensitive comparison. @returns the index of the last occurrence of the character in this string, or -1 if it's not found. */ int lastIndexOfChar (juce_wchar character) const throw(); /** Searches for a substring inside this string (working backwards from the end of the string). Uses a case-sensitive comparison. @returns the index of the start of the last occurrence of the substring within this string, or -1 if it's not found. */ int lastIndexOf (const String& textToLookFor) const throw(); /** Searches for a substring inside this string (working backwards from the end of the string). Uses a case-insensitive comparison. @returns the index of the start of the last occurrence of the substring within this string, or -1 if it's not found. */ int lastIndexOfIgnoreCase (const String& textToLookFor) const throw(); /** Returns the index of the last character in this string that matches one of the characters passed-in to this method. This scans the string backwards, starting from its end, and if it finds a character that appears in the string charactersToLookFor, it returns its index. If none of these characters are found, it returns -1. If ignoreCase is true, the comparison will be case-insensitive. @see lastIndexOf, indexOfAnyOf */ int lastIndexOfAnyOf (const String& charactersToLookFor, bool ignoreCase = false) const throw(); // Substring extraction and manipulation methods.. /** Returns the character at this index in the string. No checks are made to see if the index is within a valid range, so be careful! */ inline const juce_wchar& operator[] (int index) const throw() { jassert (isPositiveAndNotGreaterThan (index, length())); return text [index]; } /** Returns a character from the string such that it can also be altered. This can be used as a way of easily changing characters in the string. Note that the index passed-in is not checked to see whether it's in-range, so be careful when using this. */ juce_wchar& operator[] (int index); /** Returns the final character of the string. If the string is empty this will return 0. */ juce_wchar getLastCharacter() const throw(); /** Returns a subsection of the string. If the range specified is beyond the limits of the string, as much as possible is returned. @param startIndex the index of the start of the substring needed @param endIndex all characters from startIndex up to (but not including) this index are returned @see fromFirstOccurrenceOf, dropLastCharacters, getLastCharacters, upToFirstOccurrenceOf */ const String substring (int startIndex, int endIndex) const; /** Returns a section of the string, starting from a given position. @param startIndex the first character to include. If this is beyond the end of the string, an empty string is returned. If it is zero or less, the whole string is returned. @returns the substring from startIndex up to the end of the string @see dropLastCharacters, getLastCharacters, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf */ const String substring (int startIndex) const; /** Returns a version of this string with a number of characters removed from the end. @param numberToDrop the number of characters to drop from the end of the string. If this is greater than the length of the string, an empty string will be returned. If zero or less, the original string will be returned. @see substring, fromFirstOccurrenceOf, upToFirstOccurrenceOf, fromLastOccurrenceOf, getLastCharacter */ const String dropLastCharacters (int numberToDrop) const; /** Returns a number of characters from the end of the string. This returns the last numCharacters characters from the end of the string. If the string is shorter than numCharacters, the whole string is returned. @see substring, dropLastCharacters, getLastCharacter */ const String getLastCharacters (int numCharacters) const; /** Returns a section of the string starting from a given substring. This will search for the first occurrence of the given substring, and return the section of the string starting from the point where this is found (optionally not including the substring itself). e.g. for the string "123456", fromFirstOccurrenceOf ("34", true) would return "3456", and fromFirstOccurrenceOf ("34", false) would return "56". If the substring isn't found, the method will return an empty string. If ignoreCase is true, the comparison will be case-insensitive. @see upToFirstOccurrenceOf, fromLastOccurrenceOf */ const String fromFirstOccurrenceOf (const String& substringToStartFrom, bool includeSubStringInResult, bool ignoreCase) const; /** Returns a section of the string starting from the last occurrence of a given substring. Similar to fromFirstOccurrenceOf(), but using the last occurrence of the substring, and unlike fromFirstOccurrenceOf(), if the substring isn't found, this method will return the whole of the original string. @see fromFirstOccurrenceOf, upToLastOccurrenceOf */ const String fromLastOccurrenceOf (const String& substringToFind, bool includeSubStringInResult, bool ignoreCase) const; /** Returns the start of this string, up to the first occurrence of a substring. This will search for the first occurrence of a given substring, and then return a copy of the string, up to the position of this substring, optionally including or excluding the substring itself in the result. e.g. for the string "123456", upTo ("34", false) would return "12", and upTo ("34", true) would return "1234". If the substring isn't found, this will return the whole of the original string. @see upToLastOccurrenceOf, fromFirstOccurrenceOf */ const String upToFirstOccurrenceOf (const String& substringToEndWith, bool includeSubStringInResult, bool ignoreCase) const; /** Returns the start of this string, up to the last occurrence of a substring. Similar to upToFirstOccurrenceOf(), but this finds the last occurrence rather than the first. If the substring isn't found, this will return the whole of the original string. @see upToFirstOccurrenceOf, fromFirstOccurrenceOf */ const String upToLastOccurrenceOf (const String& substringToFind, bool includeSubStringInResult, bool ignoreCase) const; /** Returns a copy of this string with any whitespace characters removed from the start and end. */ const String trim() const; /** Returns a copy of this string with any whitespace characters removed from the start. */ const String trimStart() const; /** Returns a copy of this string with any whitespace characters removed from the end. */ const String trimEnd() const; /** Returns a copy of this string, having removed a specified set of characters from its start. Characters are removed from the start of the string until it finds one that is not in the specified set, and then it stops. @param charactersToTrim the set of characters to remove. @see trim, trimStart, trimCharactersAtEnd */ const String trimCharactersAtStart (const String& charactersToTrim) const; /** Returns a copy of this string, having removed a specified set of characters from its end. Characters are removed from the end of the string until it finds one that is not in the specified set, and then it stops. @param charactersToTrim the set of characters to remove. @see trim, trimEnd, trimCharactersAtStart */ const String trimCharactersAtEnd (const String& charactersToTrim) const; /** Returns an upper-case version of this string. */ const String toUpperCase() const; /** Returns an lower-case version of this string. */ const String toLowerCase() const; /** Replaces a sub-section of the string with another string. This will return a copy of this string, with a set of characters from startIndex to startIndex + numCharsToReplace removed, and with a new string inserted in their place. Note that this is a const method, and won't alter the string itself. @param startIndex the first character to remove. If this is beyond the bounds of the string, it will be constrained to a valid range. @param numCharactersToReplace the number of characters to remove. If zero or less, no characters will be taken out. @param stringToInsert the new string to insert at startIndex after the characters have been removed. */ const String replaceSection (int startIndex, int numCharactersToReplace, const String& stringToInsert) const; /** Replaces all occurrences of a substring with another string. Returns a copy of this string, with any occurrences of stringToReplace swapped for stringToInsertInstead. Note that this is a const method, and won't alter the string itself. */ const String replace (const String& stringToReplace, const String& stringToInsertInstead, bool ignoreCase = false) const; /** Returns a string with all occurrences of a character replaced with a different one. */ const String replaceCharacter (juce_wchar characterToReplace, juce_wchar characterToInsertInstead) const; /** Replaces a set of characters with another set. Returns a string in which each character from charactersToReplace has been replaced by the character at the equivalent position in newCharacters (so the two strings passed in must be the same length). e.g. replaceCharacters ("abc", "def") replaces 'a' with 'd', 'b' with 'e', etc. Note that this is a const method, and won't affect the string itself. */ const String replaceCharacters (const String& charactersToReplace, const String& charactersToInsertInstead) const; /** Returns a version of this string that only retains a fixed set of characters. This will return a copy of this string, omitting any characters which are not found in the string passed-in. e.g. for "1122334455", retainCharacters ("432") would return "223344" Note that this is a const method, and won't alter the string itself. */ const String retainCharacters (const String& charactersToRetain) const; /** Returns a version of this string with a set of characters removed. This will return a copy of this string, omitting any characters which are found in the string passed-in. e.g. for "1122334455", removeCharacters ("432") would return "1155" Note that this is a const method, and won't alter the string itself. */ const String removeCharacters (const String& charactersToRemove) const; /** Returns a section from the start of the string that only contains a certain set of characters. This returns the leftmost section of the string, up to (and not including) the first character that doesn't appear in the string passed in. */ const String initialSectionContainingOnly (const String& permittedCharacters) const; /** Returns a section from the start of the string that only contains a certain set of characters. This returns the leftmost section of the string, up to (and not including) the first character that occurs in the string passed in. */ const String initialSectionNotContaining (const String& charactersToStopAt) const; /** Checks whether the string might be in quotation marks. @returns true if the string begins with a quote character (either a double or single quote). It is also true if there is whitespace before the quote, but it doesn't check the end of the string. @see unquoted, quoted */ bool isQuotedString() const; /** Removes quotation marks from around the string, (if there are any). Returns a copy of this string with any quotes removed from its ends. Quotes that aren't at the ends of the string are not affected. If there aren't any quotes, the original string is returned. Note that this is a const method, and won't alter the string itself. @see isQuotedString, quoted */ const String unquoted() const; /** Adds quotation marks around a string. This will return a copy of the string with a quote at the start and end, (but won't add the quote if there's already one there, so it's safe to call this on strings that may already have quotes around them). Note that this is a const method, and won't alter the string itself. @param quoteCharacter the character to add at the start and end @see isQuotedString, unquoted */ const String quoted (juce_wchar quoteCharacter = '"') const; /** Creates a string which is a version of a string repeated and joined together. @param stringToRepeat the string to repeat @param numberOfTimesToRepeat how many times to repeat it */ static const String repeatedString (const String& stringToRepeat, int numberOfTimesToRepeat); /** Returns a copy of this string with the specified character repeatedly added to its beginning until the total length is at least the minimum length specified. */ const String paddedLeft (juce_wchar padCharacter, int minimumLength) const; /** Returns a copy of this string with the specified character repeatedly added to its end until the total length is at least the minimum length specified. */ const String paddedRight (juce_wchar padCharacter, int minimumLength) const; /** Creates a string from data in an unknown format. This looks at some binary data and tries to guess whether it's Unicode or 8-bit characters, then returns a string that represents it correctly. Should be able to handle Unicode endianness correctly, by looking at the first two bytes. */ static const String createStringFromData (const void* data, int size); /** Creates a String from a printf-style parameter list. I don't like this method. I don't use it myself, and I recommend avoiding it and using the operator<< methods or pretty much anything else instead. It's only provided here because of the popular unrest that was stirred-up when I tried to remove it... If you're really determined to use it, at least make sure that you never, ever, pass any String objects to it as parameters. */ static const String formatted (const juce_wchar* formatString, ... ); // Numeric conversions.. /** Creates a string containing this signed 32-bit integer as a decimal number. @see getIntValue, getFloatValue, getDoubleValue, toHexString */ explicit String (int decimalInteger); /** Creates a string containing this unsigned 32-bit integer as a decimal number. @see getIntValue, getFloatValue, getDoubleValue, toHexString */ explicit String (unsigned int decimalInteger); /** Creates a string containing this signed 16-bit integer as a decimal number. @see getIntValue, getFloatValue, getDoubleValue, toHexString */ explicit String (short decimalInteger); /** Creates a string containing this unsigned 16-bit integer as a decimal number. @see getIntValue, getFloatValue, getDoubleValue, toHexString */ explicit String (unsigned short decimalInteger); /** Creates a string containing this signed 64-bit integer as a decimal number. @see getLargeIntValue, getFloatValue, getDoubleValue, toHexString */ explicit String (int64 largeIntegerValue); /** Creates a string containing this unsigned 64-bit integer as a decimal number. @see getLargeIntValue, getFloatValue, getDoubleValue, toHexString */ explicit String (uint64 largeIntegerValue); /** Creates a string representing this floating-point number. @param floatValue the value to convert to a string @param numberOfDecimalPlaces if this is > 0, it will format the number using that many decimal places, and will not use exponent notation. If 0 or less, it will use exponent notation if necessary. @see getDoubleValue, getIntValue */ explicit String (float floatValue, int numberOfDecimalPlaces = 0); /** Creates a string representing this floating-point number. @param doubleValue the value to convert to a string @param numberOfDecimalPlaces if this is > 0, it will format the number using that many decimal places, and will not use exponent notation. If 0 or less, it will use exponent notation if necessary. @see getFloatValue, getIntValue */ explicit String (double doubleValue, int numberOfDecimalPlaces = 0); /** Reads the value of the string as a decimal number (up to 32 bits in size). @returns the value of the string as a 32 bit signed base-10 integer. @see getTrailingIntValue, getHexValue32, getHexValue64 */ int getIntValue() const throw(); /** Reads the value of the string as a decimal number (up to 64 bits in size). @returns the value of the string as a 64 bit signed base-10 integer. */ int64 getLargeIntValue() const throw(); /** Parses a decimal number from the end of the string. This will look for a value at the end of the string. e.g. for "321 xyz654" it will return 654; for "2 3 4" it'll return 4. Negative numbers are not handled, so "xyz-5" returns 5. @see getIntValue */ int getTrailingIntValue() const throw(); /** Parses this string as a floating point number. @returns the value of the string as a 32-bit floating point value. @see getDoubleValue */ float getFloatValue() const throw(); /** Parses this string as a floating point number. @returns the value of the string as a 64-bit floating point value. @see getFloatValue */ double getDoubleValue() const throw(); /** Parses the string as a hexadecimal number. Non-hexadecimal characters in the string are ignored. If the string contains too many characters, then the lowest significant digits are returned, e.g. "ffff12345678" would produce 0x12345678. @returns a 32-bit number which is the value of the string in hex. */ int getHexValue32() const throw(); /** Parses the string as a hexadecimal number. Non-hexadecimal characters in the string are ignored. If the string contains too many characters, then the lowest significant digits are returned, e.g. "ffff1234567812345678" would produce 0x1234567812345678. @returns a 64-bit number which is the value of the string in hex. */ int64 getHexValue64() const throw(); /** Creates a string representing this 32-bit value in hexadecimal. */ static const String toHexString (int number); /** Creates a string representing this 64-bit value in hexadecimal. */ static const String toHexString (int64 number); /** Creates a string representing this 16-bit value in hexadecimal. */ static const String toHexString (short number); /** Creates a string containing a hex dump of a block of binary data. @param data the binary data to use as input @param size how many bytes of data to use @param groupSize how many bytes are grouped together before inserting a space into the output. e.g. group size 0 has no spaces, group size 1 looks like: "be a1 c2 ff", group size 2 looks like "bea1 c2ff". */ static const String toHexString (const unsigned char* data, int size, int groupSize = 1); /** Returns a unicode version of this string. Because it returns a reference to the string's internal data, the pointer that is returned must not be stored anywhere, as it can become invalid whenever any string methods (even some const ones!) are called. */ inline operator const juce_wchar*() const throw() { return text; } /** Returns a unicode version of this string. Because it returns a reference to the string's internal data, the pointer that is returned must not be stored anywhere, as it can become invalid whenever any string methods (even some const ones!) are called. */ inline operator juce_wchar*() throw() { return text; } /** Returns a pointer to a UTF-8 version of this string. Because it returns a reference to the string's internal data, the pointer that is returned must not be stored anywhere, as it can be deleted whenever the string changes. @see getNumBytesAsUTF8, fromUTF8, copyToUTF8, toCString */ const char* toUTF8() const; /** Creates a String from a UTF-8 encoded buffer. If the size is < 0, it'll keep reading until it hits a zero. */ static const String fromUTF8 (const char* utf8buffer, int bufferSizeBytes = -1); /** Returns the number of bytes required to represent this string as UTF8. The number returned does NOT include the trailing zero. @see toUTF8, copyToUTF8 */ int getNumBytesAsUTF8() const throw(); /** Copies the string to a buffer as UTF-8 characters. Returns the number of bytes copied to the buffer, including the terminating null character. @param destBuffer the place to copy it to; if this is a null pointer, the method just returns the number of bytes required (including the terminating null character). @param maxBufferSizeBytes the size of the destination buffer, in bytes. If the string won't fit, it'll put in as many as it can while still allowing for a terminating null char at the end, and will return the number of bytes that were actually used. */ int copyToUTF8 (char* destBuffer, int maxBufferSizeBytes) const throw(); /** Returns a version of this string using the default 8-bit multi-byte system encoding. Because it returns a reference to the string's internal data, the pointer that is returned must not be stored anywhere, as it can be deleted whenever the string changes. @see getNumBytesAsCString, copyToCString, toUTF8 */ const char* toCString() const; /** Returns the number of bytes */ int getNumBytesAsCString() const throw(); /** Copies the string to a buffer. @param destBuffer the place to copy it to; if this is a null pointer, the method just returns the number of bytes required (including the terminating null character). @param maxBufferSizeBytes the size of the destination buffer, in bytes. If the string won't fit, it'll put in as many as it can while still allowing for a terminating null char at the end, and will return the number of bytes that were actually used. */ int copyToCString (char* destBuffer, int maxBufferSizeBytes) const throw(); /** Copies the string to a unicode buffer. @param destBuffer the place to copy it to @param maxCharsToCopy the maximum number of characters to copy to the buffer, NOT including the trailing zero, so this shouldn't be larger than the size of your destination buffer - 1 */ void copyToUnicode (juce_wchar* destBuffer, int maxCharsToCopy) const throw(); /** Increases the string's internally allocated storage. Although the string's contents won't be affected by this call, it will increase the amount of memory allocated internally for the string to grow into. If you're about to make a large number of calls to methods such as += or <<, it's more efficient to preallocate enough extra space beforehand, so that these methods won't have to keep resizing the string to append the extra characters. @param numCharsNeeded the number of characters to allocate storage for. If this value is less than the currently allocated size, it will have no effect. */ void preallocateStorage (size_t numCharsNeeded); /** Swaps the contents of this string with another one. This is a very fast operation, as no allocation or copying needs to be done. */ void swapWith (String& other) throw(); /** A helper class to improve performance when concatenating many large strings together. Because appending one string to another involves measuring the length of both strings, repeatedly doing this for many long strings will become an exponentially slow operation. This class uses some internal state to avoid that, so that each append operation only needs to measure the length of the appended string. */ class JUCE_API Concatenator { public: Concatenator (String& stringToAppendTo); ~Concatenator(); void append (const String& s); private: String& result; int nextIndex; JUCE_DECLARE_NON_COPYABLE (Concatenator); }; private: juce_wchar* text; struct Preallocation { explicit Preallocation (size_t); size_t numChars; }; // This constructor preallocates a certain amount of memory explicit String (const Preallocation&); String (const String& stringToCopy, size_t charsToAllocate); void createInternal (const juce_wchar* text, size_t numChars); void appendInternal (const juce_wchar* text, int numExtraChars); // This private cast operator should prevent strings being accidentally cast // to bools (this is possible because the compiler can add an implicit cast // via a const char*) operator bool() const throw() { return false; } }; /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (const char* string1, const String& string2); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (const juce_wchar* string1, const String& string2); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (char string1, const String& string2); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (juce_wchar string1, const String& string2); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const String& string2); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const char* string2); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, const juce_wchar* string2); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, char characterToAppend); /** Concatenates two strings. */ JUCE_API const String JUCE_CALLTYPE operator+ (String string1, juce_wchar characterToAppend); /** Appends a character at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, char characterToAppend); /** Appends a character at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, juce_wchar characterToAppend); /** Appends a string to the end of the first one. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const char* string2); /** Appends a string to the end of the first one. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const juce_wchar* string2); /** Appends a string to the end of the first one. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const String& string2); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, short number); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, int number); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, unsigned int number); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, long number); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, unsigned long number); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, float number); /** Appends a decimal number at the end of a string. */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, double number); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const char* string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const juce_wchar* string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const char* string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const juce_wchar* string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator< (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator>= (const String& string1, const String& string2) throw(); /** Case-sensitive comparison of two strings. */ JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, const String& string2) throw(); /** This streaming override allows you to pass a juce String directly into std output streams. This is very handy for writing strings to std::cout, std::cerr, etc. */ template JUCE_API std::basic_ostream & JUCE_CALLTYPE operator<< (std::basic_ostream & stream, const String& stringToWrite) { return stream << stringToWrite.toUTF8(); } /** Writes a string to an OutputStream as UTF8. */ JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& text); #endif // __JUCE_STRING_JUCEHEADER__ /*** End of inlined file: juce_String.h ***/ /** Acts as an application-wide logging class. A subclass of Logger can be created and passed into the Logger::setCurrentLogger method and this will then be used by all calls to writeToLog. The logger class also contains methods for writing messages to the debugger's output stream. @see FileLogger */ class JUCE_API Logger { public: /** Destructor. */ virtual ~Logger(); /** Sets the current logging class to use. Note that the object passed in won't be deleted when no longer needed. A null pointer can be passed-in to disable any logging. If deleteOldLogger is set to true, the existing logger will be deleted (if there is one). */ static void JUCE_CALLTYPE setCurrentLogger (Logger* newLogger, bool deleteOldLogger = false); /** Writes a string to the current logger. This will pass the string to the logger's logMessage() method if a logger has been set. @see logMessage */ static void JUCE_CALLTYPE writeToLog (const String& message); /** Writes a message to the standard error stream. This can be called directly, or by using the DBG() macro in juce_PlatformDefs.h (which will avoid calling the method in non-debug builds). */ static void JUCE_CALLTYPE outputDebugString (const String& text); protected: Logger(); /** This is overloaded by subclasses to implement custom logging behaviour. @see setCurrentLogger */ virtual void logMessage (const String& message) = 0; private: static Logger* currentLogger; }; #endif // __JUCE_LOGGER_JUCEHEADER__ /*** End of inlined file: juce_Logger.h ***/ /*** Start of inlined file: juce_LeakedObjectDetector.h ***/ #ifndef __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__ #define __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__ /*** Start of inlined file: juce_Atomic.h ***/ #ifndef __JUCE_ATOMIC_JUCEHEADER__ #define __JUCE_ATOMIC_JUCEHEADER__ /** Simple class to hold a primitive value and perform atomic operations on it. The type used must be a 32 or 64 bit primitive, like an int, pointer, etc. There are methods to perform most of the basic atomic operations. */ template class Atomic { public: /** Creates a new value, initialised to zero. */ inline Atomic() throw() : value (0) { } /** Creates a new value, with a given initial value. */ inline Atomic (const Type initialValue) throw() : value (initialValue) { } /** Copies another value (atomically). */ inline Atomic (const Atomic& other) throw() : value (other.get()) { } /** Destructor. */ inline ~Atomic() throw() { // This class can only be used for types which are 32 or 64 bits in size. static_jassert (sizeof (Type) == 4 || sizeof (Type) == 8); } /** Atomically reads and returns the current value. */ Type get() const throw(); /** Copies another value onto this one (atomically). */ inline Atomic& operator= (const Atomic& other) throw() { exchange (other.get()); return *this; } /** Copies another value onto this one (atomically). */ inline Atomic& operator= (const Type newValue) throw() { exchange (newValue); return *this; } /** Atomically sets the current value. */ void set (Type newValue) throw() { exchange (newValue); } /** Atomically sets the current value, returning the value that was replaced. */ Type exchange (Type value) throw(); /** Atomically adds a number to this value, returning the new value. */ Type operator+= (Type amountToAdd) throw(); /** Atomically subtracts a number from this value, returning the new value. */ Type operator-= (Type amountToSubtract) throw(); /** Atomically increments this value, returning the new value. */ Type operator++() throw(); /** Atomically decrements this value, returning the new value. */ Type operator--() throw(); /** Atomically compares this value with a target value, and if it is equal, sets this to be equal to a new value. This operation is the atomic equivalent of doing this: @code bool compareAndSetBool (Type newValue, Type valueToCompare) { if (get() == valueToCompare) { set (newValue); return true; } return false; } @endcode @returns true if the comparison was true and the value was replaced; false if the comparison failed and the value was left unchanged. @see compareAndSetValue */ bool compareAndSetBool (Type newValue, Type valueToCompare) throw(); /** Atomically compares this value with a target value, and if it is equal, sets this to be equal to a new value. This operation is the atomic equivalent of doing this: @code Type compareAndSetValue (Type newValue, Type valueToCompare) { Type oldValue = get(); if (oldValue == valueToCompare) set (newValue); return oldValue; } @endcode @returns the old value before it was changed. @see compareAndSetBool */ Type compareAndSetValue (Type newValue, Type valueToCompare) throw(); /** Implements a memory read/write barrier. */ static void memoryBarrier() throw(); JUCE_ALIGN(8) /** The raw value that this class operates on. This is exposed publically in case you need to manipulate it directly for performance reasons. */ volatile Type value; private: static inline Type castFrom32Bit (int32 value) throw() { return *(Type*) &value; } static inline Type castFrom64Bit (int64 value) throw() { return *(Type*) &value; } static inline int32 castTo32Bit (Type value) throw() { return *(int32*) &value; } static inline int64 castTo64Bit (Type value) throw() { return *(int64*) &value; } Type operator++ (int); // better to just use pre-increment with atomics.. Type operator-- (int); }; /* The following code is in the header so that the atomics can be inlined where possible... */ #if (JUCE_IOS && (__IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_3_2 || ! defined (__IPHONE_3_2))) \ || (JUCE_MAC && (JUCE_PPC || __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2))) #define JUCE_ATOMICS_MAC 1 // Older OSX builds using gcc4.1 or earlier #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 #define JUCE_MAC_ATOMICS_VOLATILE #else #define JUCE_MAC_ATOMICS_VOLATILE volatile #endif #if JUCE_PPC || JUCE_IOS // None of these atomics are available for PPC or for iPhoneOS 3.1 or earlier!! template static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return *a += b; } template static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return ++*a; } template static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) throw() { jassertfalse; return --*a; } template static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) throw() { jassertfalse; if (old == *value) { *value = newValue; return true; } return false; } #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 #endif #elif JUCE_GCC #define JUCE_ATOMICS_GCC 1 // GCC with intrinsics #if JUCE_IOS #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 // (on the iphone, the 64-bit ops will compile but not link) #endif #else #define JUCE_ATOMICS_WINDOWS 1 // Windows with intrinsics #if JUCE_USE_INTRINSICS || JUCE_64BIT #pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \ _InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier) #define juce_InterlockedExchange(a, b) _InterlockedExchange(a, b) #define juce_InterlockedIncrement(a) _InterlockedIncrement(a) #define juce_InterlockedDecrement(a) _InterlockedDecrement(a) #define juce_InterlockedExchangeAdd(a, b) _InterlockedExchangeAdd(a, b) #define juce_InterlockedCompareExchange(a, b, c) _InterlockedCompareExchange(a, b, c) #define juce_InterlockedCompareExchange64(a, b, c) _InterlockedCompareExchange64(a, b, c) #define juce_MemoryBarrier _ReadWriteBarrier #else // (these are defined in juce_win32_Threads.cpp) long juce_InterlockedExchange (volatile long* a, long b) throw(); long juce_InterlockedIncrement (volatile long* a) throw(); long juce_InterlockedDecrement (volatile long* a) throw(); long juce_InterlockedExchangeAdd (volatile long* a, long b) throw(); long juce_InterlockedCompareExchange (volatile long* a, long b, long c) throw(); __int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) throw(); inline void juce_MemoryBarrier() throw() { long x = 0; juce_InterlockedIncrement (&x); } #endif #if JUCE_64BIT #pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64) #define juce_InterlockedExchangeAdd64(a, b) _InterlockedExchangeAdd64(a, b) #define juce_InterlockedExchange64(a, b) _InterlockedExchange64(a, b) #define juce_InterlockedIncrement64(a) _InterlockedIncrement64(a) #define juce_InterlockedDecrement64(a) _InterlockedDecrement64(a) #else // None of these atomics are available in a 32-bit Windows build!! template static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a += b; return old; } template static Type juce_InterlockedExchange64 (volatile Type* a, Type b) throw() { jassertfalse; Type old = *a; *a = b; return old; } template static Type juce_InterlockedIncrement64 (volatile Type* a) throw() { jassertfalse; return ++*a; } template static Type juce_InterlockedDecrement64 (volatile Type* a) throw() { jassertfalse; return --*a; } #define JUCE_64BIT_ATOMICS_UNAVAILABLE 1 #endif #endif #if JUCE_MSVC #pragma warning (push) #pragma warning (disable: 4311) // (truncation warning) #endif template inline Type Atomic::get() const throw() { #if JUCE_ATOMICS_MAC return sizeof (Type) == 4 ? castFrom32Bit ((int32) OSAtomicAdd32Barrier ((int32_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value)) : castFrom64Bit ((int64) OSAtomicAdd64Barrier ((int64_t) 0, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value)); #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchangeAdd ((volatile long*) &value, (long) 0)) : castFrom64Bit ((int64) juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) 0)); #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_add_and_fetch ((volatile int32*) &value, 0)) : castFrom64Bit ((int64) __sync_add_and_fetch ((volatile int64*) &value, 0)); #endif } template inline Type Atomic::exchange (const Type newValue) throw() { #if JUCE_ATOMICS_MAC || JUCE_ATOMICS_GCC Type currentVal = value; while (! compareAndSetBool (newValue, currentVal)) { currentVal = value; } return currentVal; #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedExchange ((volatile long*) &value, (long) castTo32Bit (newValue))) : castFrom64Bit ((int64) juce_InterlockedExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue))); #endif } template inline Type Atomic::operator+= (const Type amountToAdd) throw() { #if JUCE_ATOMICS_MAC return sizeof (Type) == 4 ? (Type) OSAtomicAdd32Barrier ((int32_t) castTo32Bit (amountToAdd), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) : (Type) OSAtomicAdd64Barrier ((int64_t) amountToAdd, (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) (juce_InterlockedExchangeAdd ((volatile long*) &value, (long) amountToAdd) + (long) amountToAdd) : (Type) (juce_InterlockedExchangeAdd64 ((volatile __int64*) &value, (__int64) amountToAdd) + (__int64) amountToAdd); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, amountToAdd); #endif } template inline Type Atomic::operator-= (const Type amountToSubtract) throw() { return operator+= (juce_negate (amountToSubtract)); } template inline Type Atomic::operator++() throw() { #if JUCE_ATOMICS_MAC return sizeof (Type) == 4 ? (Type) OSAtomicIncrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) : (Type) OSAtomicIncrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) juce_InterlockedIncrement ((volatile long*) &value) : (Type) juce_InterlockedIncrement64 ((volatile __int64*) &value); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, 1); #endif } template inline Type Atomic::operator--() throw() { #if JUCE_ATOMICS_MAC return sizeof (Type) == 4 ? (Type) OSAtomicDecrement32Barrier ((JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) : (Type) OSAtomicDecrement64Barrier ((JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? (Type) juce_InterlockedDecrement ((volatile long*) &value) : (Type) juce_InterlockedDecrement64 ((volatile __int64*) &value); #elif JUCE_ATOMICS_GCC return (Type) __sync_add_and_fetch (&value, -1); #endif } template inline bool Atomic::compareAndSetBool (const Type newValue, const Type valueToCompare) throw() { #if JUCE_ATOMICS_MAC return sizeof (Type) == 4 ? OSAtomicCompareAndSwap32Barrier ((int32_t) castTo32Bit (valueToCompare), (int32_t) castTo32Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int32_t*) &value) : OSAtomicCompareAndSwap64Barrier ((int64_t) castTo64Bit (valueToCompare), (int64_t) castTo64Bit (newValue), (JUCE_MAC_ATOMICS_VOLATILE int64_t*) &value); #elif JUCE_ATOMICS_WINDOWS return compareAndSetValue (newValue, valueToCompare) == valueToCompare; #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? __sync_bool_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue)) : __sync_bool_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue)); #endif } template inline Type Atomic::compareAndSetValue (const Type newValue, const Type valueToCompare) throw() { #if JUCE_ATOMICS_MAC for (;;) // Annoying workaround for OSX only having a bool CAS operation.. { if (compareAndSetBool (newValue, valueToCompare)) return valueToCompare; const Type result = value; if (result != valueToCompare) return result; } #elif JUCE_ATOMICS_WINDOWS return sizeof (Type) == 4 ? castFrom32Bit ((int32) juce_InterlockedCompareExchange ((volatile long*) &value, (long) castTo32Bit (newValue), (long) castTo32Bit (valueToCompare))) : castFrom64Bit ((int64) juce_InterlockedCompareExchange64 ((volatile __int64*) &value, (__int64) castTo64Bit (newValue), (__int64) castTo64Bit (valueToCompare))); #elif JUCE_ATOMICS_GCC return sizeof (Type) == 4 ? castFrom32Bit ((int32) __sync_val_compare_and_swap ((volatile int32*) &value, castTo32Bit (valueToCompare), castTo32Bit (newValue))) : castFrom64Bit ((int64) __sync_val_compare_and_swap ((volatile int64*) &value, castTo64Bit (valueToCompare), castTo64Bit (newValue))); #endif } template inline void Atomic::memoryBarrier() throw() { #if JUCE_ATOMICS_MAC OSMemoryBarrier(); #elif JUCE_ATOMICS_GCC __sync_synchronize(); #elif JUCE_ATOMICS_WINDOWS juce_MemoryBarrier(); #endif } #if JUCE_MSVC #pragma warning (pop) #endif #endif // __JUCE_ATOMIC_JUCEHEADER__ /*** End of inlined file: juce_Atomic.h ***/ /** Embedding an instance of this class inside another class can be used as a low-overhead way of detecting leaked instances. This class keeps an internal static count of the number of instances that are active, so that when the app is shutdown and the static destructors are called, it can check whether there are any left-over instances that may have been leaked. To use it, use the JUCE_LEAK_DETECTOR macro as a simple way to put one in your class declaration. Have a look through the juce codebase for examples, it's used in most of the classes. */ template class LeakedObjectDetector { public: LeakedObjectDetector() throw() { ++(getCounter().numObjects); } LeakedObjectDetector (const LeakedObjectDetector&) throw() { ++(getCounter().numObjects); } ~LeakedObjectDetector() { if (--(getCounter().numObjects) < 0) { DBG ("*** Dangling pointer deletion! Class: " << String (typeid (OwnerClass).name())); /** If you hit this, then you've managed to delete more instances of this class than you've created.. That indicates that you're deleting some dangling pointers. Note that although this assertion will have been triggered during a destructor, it might not be this particular deletion that's at fault - the incorrect one may have happened at an earlier point in the program, and simply not been detected until now. Most errors like this are caused by using old-fashioned, non-RAII techniques for your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays, ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs! */ jassertfalse; } } private: class LeakCounter { public: LeakCounter() {} ~LeakCounter() { if (numObjects.value > 0) { DBG ("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << String (typeid (OwnerClass).name())); /** If you hit this, then you've leaked one or more objects of the type specified by the 'OwnerClass' template parameter - the name should have been printed by the line above. If you're leaking, it's probably because you're using old-fashioned, non-RAII techniques for your object management. Tut, tut. Always, always use ScopedPointers, OwnedArrays, ReferenceCountedObjects, etc, and avoid the 'delete' operator at all costs! */ jassertfalse; } } Atomic numObjects; }; static LeakCounter& getCounter() throw() { static LeakCounter counter; return counter; } }; #if DOXYGEN || ! defined (JUCE_LEAK_DETECTOR) #if (DOXYGEN || JUCE_CHECK_MEMORY_LEAKS) /** This macro lets you embed a leak-detecting object inside a class. To use it, simply declare a JUCE_LEAK_DETECTOR(YourClassName) inside a private section of the class declaration. E.g. @code class MyClass { public: MyClass(); void blahBlah(); private: JUCE_LEAK_DETECTOR (MyClass); };@endcode @see JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR, LeakedObjectDetector */ #define JUCE_LEAK_DETECTOR(OwnerClass) JUCE_NAMESPACE::LeakedObjectDetector JUCE_JOIN_MACRO (leakDetector, __LINE__); #else #define JUCE_LEAK_DETECTOR(OwnerClass) #endif #endif #endif // __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__ /*** End of inlined file: juce_LeakedObjectDetector.h ***/ END_JUCE_NAMESPACE #endif // __JUCE_STANDARDHEADER_JUCEHEADER__ /*** End of inlined file: juce_StandardHeader.h ***/ BEGIN_JUCE_NAMESPACE #if JUCE_MSVC // this is set explicitly in case the app is using a different packing size. #pragma pack (push, 8) #pragma warning (push) #pragma warning (disable: 4786) // (old vc6 warning about long class names) #endif // this is where all the class header files get brought in.. /*** Start of inlined file: juce_core_includes.h ***/ #ifndef __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__ #define __JUCE_JUCE_CORE_INCLUDES_INCLUDEFILES__ #ifndef __JUCE_ABSTRACTFIFO_JUCEHEADER__ /*** Start of inlined file: juce_AbstractFifo.h ***/ #ifndef __JUCE_ABSTRACTFIFO_JUCEHEADER__ #define __JUCE_ABSTRACTFIFO_JUCEHEADER__ /** Encapsulates the logic required to implement a lock-free FIFO. This class handles the logic needed when building a single-reader, single-writer FIFO. It doesn't actually hold any data itself, but your FIFO class can use one of these to manage its position and status when reading or writing to it. To use it, you can call prepareToWrite() to determine the position within your own buffer that an incoming block of data should be stored, and prepareToRead() to find out when the next outgoing block should be read from. e.g. @code class MyFifo { public: MyFifo() : abstractFifo (1024) { } void addToFifo (const int* someData, int numItems) { int start1, size1, start2, size2; prepareToWrite (numItems, start1, size1, start2, size2); if (size1 > 0) copySomeData (myBuffer + start1, someData, size1); if (size2 > 0) copySomeData (myBuffer + start2, someData + size1, size2); finishedWrite (size1 + size2); } void readFromFifo (int* someData, int numItems) { int start1, size1, start2, size2; prepareToRead (numSamples, start1, size1, start2, size2); if (size1 > 0) copySomeData (someData, myBuffer + start1, size1); if (size2 > 0) copySomeData (someData + size1, myBuffer + start2, size2); finishedRead (size1 + size2); } private: AbstractFifo abstractFifo; int myBuffer [1024]; }; @endcode */ class JUCE_API AbstractFifo { public: /** Creates a FIFO to manage a buffer with the specified capacity. */ AbstractFifo (int capacity) throw(); /** Destructor */ ~AbstractFifo(); /** Returns the total size of the buffer being managed. */ int getTotalSize() const throw(); /** Returns the number of items that can currently be added to the buffer without it overflowing. */ int getFreeSpace() const throw(); /** Returns the number of items that can currently be read from the buffer. */ int getNumReady() const throw(); /** Clears the buffer positions, so that it appears empty. */ void reset() throw(); /** Changes the buffer's total size. Note that this isn't thread-safe, so don't call it if there's any danger that it might overlap with a call to any other method in this class! */ void setTotalSize (int newSize) throw(); /** Returns the location within the buffer at which an incoming block of data should be written. Because the section of data that you want to add to the buffer may overlap the end and wrap around to the start, two blocks within your buffer are returned, and you should copy your data into the first one, with any remaining data spilling over into the second. If the number of items you ask for is too large to fit within the buffer's free space, then blockSize1 + blockSize2 may add up to a lower value than numToWrite. If this happens, you may decide to keep waiting and re-trying the method until there's enough space available. After calling this method, if you choose to write your data into the blocks returned, you must call finishedWrite() to tell the FIFO how much data you actually added. e.g. @code void addToFifo (const int* someData, int numItems) { int start1, size1, start2, size2; prepareToWrite (numItems, start1, size1, start2, size2); if (size1 > 0) copySomeData (myBuffer + start1, someData, size1); if (size2 > 0) copySomeData (myBuffer + start2, someData + size1, size2); finishedWrite (size1 + size2); } @endcode @param numToWrite indicates how many items you'd like to add to the buffer @param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1 @param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into the first block should be written @param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2 @see finishedWrite */ void prepareToWrite (int numToWrite, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const throw(); /** Called after reading from the FIFO, to indicate that this many items have been added. @see prepareToWrite */ void finishedWrite (int numWritten) throw(); /** Returns the location within the buffer from which the next block of data should be read. Because the section of data that you want to read from the buffer may overlap the end and wrap around to the start, two blocks within your buffer are returned, and you should read from both of them. If the number of items you ask for is greater than the amount of data available, then blockSize1 + blockSize2 may add up to a lower value than numWanted. If this happens, you may decide to keep waiting and re-trying the method until there's enough data available. After calling this method, if you choose to read the data, you must call finishedRead() to tell the FIFO how much data you have consumed. e.g. @code void readFromFifo (int* someData, int numItems) { int start1, size1, start2, size2; prepareToRead (numSamples, start1, size1, start2, size2); if (size1 > 0) copySomeData (someData, myBuffer + start1, size1); if (size2 > 0) copySomeData (someData + size1, myBuffer + start2, size2); finishedRead (size1 + size2); } @endcode @param numWanted indicates how many items you'd like to add to the buffer @param startIndex1 on exit, this will contain the start index in your buffer at which your data should be written @param blockSize1 on exit, this indicates how many items can be written to the block starting at startIndex1 @param startIndex2 on exit, this will contain the start index in your buffer at which any data that didn't fit into the first block should be written @param blockSize2 on exit, this indicates how many items can be written to the block starting at startIndex2 @see finishedRead */ void prepareToRead (int numWanted, int& startIndex1, int& blockSize1, int& startIndex2, int& blockSize2) const throw(); /** Called after reading from the FIFO, to indicate that this many items have now been consumed. @see prepareToRead */ void finishedRead (int numRead) throw(); private: int bufferSize; Atomic validStart, validEnd; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AbstractFifo); }; #endif // __JUCE_ABSTRACTFIFO_JUCEHEADER__ /*** End of inlined file: juce_AbstractFifo.h ***/ #endif #ifndef __JUCE_ARRAY_JUCEHEADER__ /*** Start of inlined file: juce_Array.h ***/ #ifndef __JUCE_ARRAY_JUCEHEADER__ #define __JUCE_ARRAY_JUCEHEADER__ /*** Start of inlined file: juce_ArrayAllocationBase.h ***/ #ifndef __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ #define __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ /*** Start of inlined file: juce_HeapBlock.h ***/ #ifndef __JUCE_HEAPBLOCK_JUCEHEADER__ #define __JUCE_HEAPBLOCK_JUCEHEADER__ /** Very simple container class to hold a pointer to some data on the heap. When you need to allocate some heap storage for something, always try to use this class instead of allocating the memory directly using malloc/free. A HeapBlock object can be treated in pretty much exactly the same way as an char*, but as long as you allocate it on the stack or as a class member, it's almost impossible for it to leak memory. It also makes your code much more concise and readable than doing the same thing using direct allocations, E.g. instead of this: @code int* temp = (int*) malloc (1024 * sizeof (int)); memcpy (temp, xyz, 1024 * sizeof (int)); free (temp); temp = (int*) calloc (2048 * sizeof (int)); temp[0] = 1234; memcpy (foobar, temp, 2048 * sizeof (int)); free (temp); @endcode ..you could just write this: @code HeapBlock temp (1024); memcpy (temp, xyz, 1024 * sizeof (int)); temp.calloc (2048); temp[0] = 1234; memcpy (foobar, temp, 2048 * sizeof (int)); @endcode The class is extremely lightweight, containing only a pointer to the data, and exposes malloc/realloc/calloc/free methods that do the same jobs as their less object-oriented counterparts. Despite adding safety, you probably won't sacrifice any performance by using this in place of normal pointers. @see Array, OwnedArray, MemoryBlock */ template class HeapBlock { public: /** Creates a HeapBlock which is initially just a null pointer. After creation, you can resize the array using the malloc(), calloc(), or realloc() methods. */ HeapBlock() throw() : data (0) { } /** Creates a HeapBlock containing a number of elements. The contents of the block are undefined, as it will have been created by a malloc call. If you want an array of zero values, you can use the calloc() method instead. */ explicit HeapBlock (const size_t numElements) : data (static_cast (::malloc (numElements * sizeof (ElementType)))) { } /** Destructor. This will free the data, if any has been allocated. */ ~HeapBlock() { ::free (data); } /** Returns a raw pointer to the allocated data. This may be a null pointer if the data hasn't yet been allocated, or if it has been freed by calling the free() method. */ inline operator ElementType*() const throw() { return data; } /** Returns a raw pointer to the allocated data. This may be a null pointer if the data hasn't yet been allocated, or if it has been freed by calling the free() method. */ inline ElementType* getData() const throw() { return data; } /** Returns a void pointer to the allocated data. This may be a null pointer if the data hasn't yet been allocated, or if it has been freed by calling the free() method. */ inline operator void*() const throw() { return static_cast (data); } /** Returns a void pointer to the allocated data. This may be a null pointer if the data hasn't yet been allocated, or if it has been freed by calling the free() method. */ inline operator const void*() const throw() { return static_cast (data); } /** Lets you use indirect calls to the first element in the array. Obviously this will cause problems if the array hasn't been initialised, because it'll be referencing a null pointer. */ inline ElementType* operator->() const throw() { return data; } /** Returns a reference to one of the data elements. Obviously there's no bounds-checking here, as this object is just a dumb pointer and has no idea of the size it currently has allocated. */ template inline ElementType& operator[] (IndexType index) const throw() { return data [index]; } /** Returns a pointer to a data element at an offset from the start of the array. This is the same as doing pointer arithmetic on the raw pointer itself. */ template inline ElementType* operator+ (IndexType index) const throw() { return data + index; } /** Compares the pointer with another pointer. This can be handy for checking whether this is a null pointer. */ inline bool operator== (const ElementType* const otherPointer) const throw() { return otherPointer == data; } /** Compares the pointer with another pointer. This can be handy for checking whether this is a null pointer. */ inline bool operator!= (const ElementType* const otherPointer) const throw() { return otherPointer != data; } /** Allocates a specified amount of memory. This uses the normal malloc to allocate an amount of memory for this object. Any previously allocated memory will be freed by this method. The number of bytes allocated will be (newNumElements * elementSize). Normally you wouldn't need to specify the second parameter, but it can be handy if you need to allocate a size in bytes rather than in terms of the number of elements. The data that is allocated will be freed when this object is deleted, or when you call free() or any of the allocation methods. */ void malloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) { ::free (data); data = static_cast (::malloc (newNumElements * elementSize)); } /** Allocates a specified amount of memory and clears it. This does the same job as the malloc() method, but clears the memory that it allocates. */ void calloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) { ::free (data); data = static_cast (::calloc (newNumElements, elementSize)); } /** Allocates a specified amount of memory and optionally clears it. This does the same job as either malloc() or calloc(), depending on the initialiseToZero parameter. */ void allocate (const size_t newNumElements, const bool initialiseToZero) { ::free (data); if (initialiseToZero) data = static_cast (::calloc (newNumElements, sizeof (ElementType))); else data = static_cast (::malloc (newNumElements * sizeof (ElementType))); } /** Re-allocates a specified amount of memory. The semantics of this method are the same as malloc() and calloc(), but it uses realloc() to keep as much of the existing data as possible. */ void realloc (const size_t newNumElements, const size_t elementSize = sizeof (ElementType)) { if (data == 0) data = static_cast (::malloc (newNumElements * elementSize)); else data = static_cast (::realloc (data, newNumElements * elementSize)); } /** Frees any currently-allocated data. This will free the data and reset this object to be a null pointer. */ void free() { ::free (data); data = 0; } /** Swaps this object's data with the data of another HeapBlock. The two objects simply exchange their data pointers. */ void swapWith (HeapBlock & other) throw() { swapVariables (data, other.data); } private: ElementType* data; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HeapBlock); }; #endif // __JUCE_HEAPBLOCK_JUCEHEADER__ /*** End of inlined file: juce_HeapBlock.h ***/ /** Implements some basic array storage allocation functions. This class isn't really for public use - it's used by the other array classes, but might come in handy for some purposes. It inherits from a critical section class to allow the arrays to use the "empty base class optimisation" pattern to reduce their footprint. @see Array, OwnedArray, ReferenceCountedArray */ template class ArrayAllocationBase : public TypeOfCriticalSectionToUse { public: /** Creates an empty array. */ ArrayAllocationBase() throw() : numAllocated (0) { } /** Destructor. */ ~ArrayAllocationBase() { } /** Changes the amount of storage allocated. This will retain any data currently held in the array, and either add or remove extra space at the end. @param numElements the number of elements that are needed */ void setAllocatedSize (const int numElements) { if (numAllocated != numElements) { if (numElements > 0) elements.realloc (numElements); else elements.free(); numAllocated = numElements; } } /** Increases the amount of storage allocated if it is less than a given amount. This will retain any data currently held in the array, but will add extra space at the end to make sure there it's at least as big as the size passed in. If it's already bigger, no action is taken. @param minNumElements the minimum number of elements that are needed */ void ensureAllocatedSize (const int minNumElements) { if (minNumElements > numAllocated) setAllocatedSize ((minNumElements + minNumElements / 2 + 8) & ~7); } /** Minimises the amount of storage allocated so that it's no more than the given number of elements. */ void shrinkToNoMoreThan (const int maxNumElements) { if (maxNumElements < numAllocated) setAllocatedSize (maxNumElements); } /** Swap the contents of two objects. */ void swapWith (ArrayAllocationBase & other) throw() { elements.swapWith (other.elements); swapVariables (numAllocated, other.numAllocated); } HeapBlock elements; int numAllocated; private: JUCE_DECLARE_NON_COPYABLE (ArrayAllocationBase); }; #endif // __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ /*** End of inlined file: juce_ArrayAllocationBase.h ***/ /*** Start of inlined file: juce_ElementComparator.h ***/ #ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ #define __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ /** Sorts a range of elements in an array. The comparator object that is passed-in must define a public method with the following signature: @code int compareElements (ElementType first, ElementType second); @endcode ..and this method must return: - a value of < 0 if the first comes before the second - a value of 0 if the two objects are equivalent - a value of > 0 if the second comes before the first To improve performance, the compareElements() method can be declared as static or const. @param comparator an object which defines a compareElements() method @param array the array to sort @param firstElement the index of the first element of the range to be sorted @param lastElement the index of the last element in the range that needs sorting (this is inclusive) @param retainOrderOfEquivalentItems if true, the order of items that the comparator deems the same will be maintained - this will be a slower algorithm than if they are allowed to be moved around. @see sortArrayRetainingOrder */ template static void sortArray (ElementComparator& comparator, ElementType* const array, int firstElement, int lastElement, const bool retainOrderOfEquivalentItems) { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused if (lastElement > firstElement) { if (retainOrderOfEquivalentItems) { for (int i = firstElement; i < lastElement; ++i) { if (comparator.compareElements (array[i], array [i + 1]) > 0) { swapVariables (array[i], array[i + 1]); if (i > firstElement) i -= 2; } } } else { int fromStack[30], toStack[30]; int stackIndex = 0; for (;;) { const int size = (lastElement - firstElement) + 1; if (size <= 8) { int j = lastElement; int maxIndex; while (j > firstElement) { maxIndex = firstElement; for (int k = firstElement + 1; k <= j; ++k) if (comparator.compareElements (array[k], array [maxIndex]) > 0) maxIndex = k; swapVariables (array[j], array[maxIndex]); --j; } } else { const int mid = firstElement + (size >> 1); swapVariables (array[mid], array[firstElement]); int i = firstElement; int j = lastElement + 1; for (;;) { while (++i <= lastElement && comparator.compareElements (array[i], array [firstElement]) <= 0) {} while (--j > firstElement && comparator.compareElements (array[j], array [firstElement]) >= 0) {} if (j < i) break; swapVariables (array[i], array[j]); } swapVariables (array[j], array[firstElement]); if (j - 1 - firstElement >= lastElement - i) { if (firstElement + 1 < j) { fromStack [stackIndex] = firstElement; toStack [stackIndex] = j - 1; ++stackIndex; } if (i < lastElement) { firstElement = i; continue; } } else { if (i < lastElement) { fromStack [stackIndex] = i; toStack [stackIndex] = lastElement; ++stackIndex; } if (firstElement + 1 < j) { lastElement = j - 1; continue; } } } if (--stackIndex < 0) break; jassert (stackIndex < numElementsInArray (fromStack)); firstElement = fromStack [stackIndex]; lastElement = toStack [stackIndex]; } } } } /** Searches a sorted array of elements, looking for the index at which a specified value should be inserted for it to be in the correct order. The comparator object that is passed-in must define a public method with the following signature: @code int compareElements (ElementType first, ElementType second); @endcode ..and this method must return: - a value of < 0 if the first comes before the second - a value of 0 if the two objects are equivalent - a value of > 0 if the second comes before the first To improve performance, the compareElements() method can be declared as static or const. @param comparator an object which defines a compareElements() method @param array the array to search @param newElement the value that is going to be inserted @param firstElement the index of the first element to search @param lastElement the index of the last element in the range (this is non-inclusive) */ template static int findInsertIndexInSortedArray (ElementComparator& comparator, ElementType* const array, const ElementType newElement, int firstElement, int lastElement) { jassert (firstElement <= lastElement); (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused while (firstElement < lastElement) { if (comparator.compareElements (newElement, array [firstElement]) == 0) { ++firstElement; break; } else { const int halfway = (firstElement + lastElement) >> 1; if (halfway == firstElement) { if (comparator.compareElements (newElement, array [halfway]) >= 0) ++firstElement; break; } else if (comparator.compareElements (newElement, array [halfway]) >= 0) { firstElement = halfway; } else { lastElement = halfway; } } } return firstElement; } /** A simple ElementComparator class that can be used to sort an array of objects that support the '<' operator. This will work for primitive types and objects that implement operator<(). Example: @code Array myArray; DefaultElementComparator sorter; myArray.sort (sorter); @endcode @see ElementComparator */ template class DefaultElementComparator { private: typedef PARAMETER_TYPE (ElementType) ParameterType; public: static int compareElements (ParameterType first, ParameterType second) { return (first < second) ? -1 : ((second < first) ? 1 : 0); } }; #endif // __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ /*** End of inlined file: juce_ElementComparator.h ***/ /*** Start of inlined file: juce_CriticalSection.h ***/ #ifndef __JUCE_CRITICALSECTION_JUCEHEADER__ #define __JUCE_CRITICALSECTION_JUCEHEADER__ #ifndef DOXYGEN class JUCE_API ScopedLock; class JUCE_API ScopedUnlock; #endif /** Prevents multiple threads from accessing shared objects at the same time. @see ScopedLock, Thread, InterProcessLock */ class JUCE_API CriticalSection { public: /** Creates a CriticalSection object */ CriticalSection() throw(); /** Destroys a CriticalSection object. If the critical section is deleted whilst locked, its subsequent behaviour is unpredictable. */ ~CriticalSection() throw(); /** Locks this critical section. If the lock is currently held by another thread, this will wait until it becomes free. If the lock is already held by the caller thread, the method returns immediately. @see exit, ScopedLock */ void enter() const throw(); /** Attempts to lock this critical section without blocking. This method behaves identically to CriticalSection::enter, except that the caller thread does not wait if the lock is currently held by another thread but returns false immediately. @returns false if the lock is currently held by another thread, true otherwise. @see enter */ bool tryEnter() const throw(); /** Releases the lock. If the caller thread hasn't got the lock, this can have unpredictable results. If the enter() method has been called multiple times by the thread, each call must be matched by a call to exit() before other threads will be allowed to take over the lock. @see enter, ScopedLock */ void exit() const throw(); /** Provides the type of scoped lock to use with this type of critical section object. */ typedef ScopedLock ScopedLockType; /** Provides the type of scoped unlocker to use with this type of critical section object. */ typedef ScopedUnlock ScopedUnlockType; private: #if JUCE_WINDOWS #if JUCE_64BIT // To avoid including windows.h in the public Juce includes, we'll just allocate a // block of memory here that's big enough to be used internally as a windows critical // section object. uint8 internal [44]; #else uint8 internal [24]; #endif #else mutable pthread_mutex_t internal; #endif JUCE_DECLARE_NON_COPYABLE (CriticalSection); }; /** A class that can be used in place of a real CriticalSection object. This is currently used by some templated classes, and should get optimised out by the compiler. @see Array, OwnedArray, ReferenceCountedArray */ class JUCE_API DummyCriticalSection { public: inline DummyCriticalSection() throw() {} inline ~DummyCriticalSection() throw() {} inline void enter() const throw() {} inline void exit() const throw() {} /** A dummy scoped-lock type to use with a dummy critical section. */ struct ScopedLockType { ScopedLockType (const DummyCriticalSection&) throw() {} }; /** A dummy scoped-unlocker type to use with a dummy critical section. */ typedef ScopedLockType ScopedUnlockType; private: JUCE_DECLARE_NON_COPYABLE (DummyCriticalSection); }; #endif // __JUCE_CRITICALSECTION_JUCEHEADER__ /*** End of inlined file: juce_CriticalSection.h ***/ /** Holds a resizable array of primitive or copy-by-value objects. Examples of arrays are: Array, Array or Array The Array class can be used to hold simple, non-polymorphic objects as well as primitive types - to do so, the class must fulfil these requirements: - it must have a copy constructor and assignment operator - it must be able to be relocated in memory by a memcpy without this causing any problems - so objects whose functionality relies on external pointers or references to themselves can be used. You can of course have an array of pointers to any kind of object, e.g. Array , but if you do this, the array doesn't take any ownership of the objects - see the OwnedArray class or the ReferenceCountedArray class for more powerful ways of holding lists of objects. For holding lists of strings, you can use Array\, but it's usually better to use the specialised class StringArray, which provides more useful functions. To make all the array's methods thread-safe, pass in "CriticalSection" as the templated TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. @see OwnedArray, ReferenceCountedArray, StringArray, CriticalSection */ template class Array { private: #if JUCE_VC8_OR_EARLIER typedef const ElementType& ParameterType; #else typedef PARAMETER_TYPE (ElementType) ParameterType; #endif public: /** Creates an empty array. */ Array() throw() : numUsed (0) { } /** Creates a copy of another array. @param other the array to copy */ Array (const Array& other) { const ScopedLockType lock (other.getLock()); numUsed = other.numUsed; data.setAllocatedSize (other.numUsed); for (int i = 0; i < numUsed; ++i) new (data.elements + i) ElementType (other.data.elements[i]); } /** Initalises from a null-terminated C array of values. @param values the array to copy from */ template explicit Array (const TypeToCreateFrom* values) : numUsed (0) { while (*values != TypeToCreateFrom()) add (*values++); } /** Initalises from a C array of values. @param values the array to copy from @param numValues the number of values in the array */ template Array (const TypeToCreateFrom* values, int numValues) : numUsed (numValues) { data.setAllocatedSize (numValues); for (int i = 0; i < numValues; ++i) new (data.elements + i) ElementType (values[i]); } /** Destructor. */ ~Array() { for (int i = 0; i < numUsed; ++i) data.elements[i].~ElementType(); } /** Copies another array. @param other the array to copy */ Array& operator= (const Array& other) { if (this != &other) { Array otherCopy (other); swapWithArray (otherCopy); } return *this; } /** Compares this array to another one. Two arrays are considered equal if they both contain the same set of elements, in the same order. @param other the other array to compare with */ template bool operator== (const OtherArrayType& other) const { const ScopedLockType lock (getLock()); if (numUsed != other.numUsed) return false; for (int i = numUsed; --i >= 0;) if (! (data.elements [i] == other.data.elements [i])) return false; return true; } /** Compares this array to another one. Two arrays are considered equal if they both contain the same set of elements, in the same order. @param other the other array to compare with */ template bool operator!= (const OtherArrayType& other) const { return ! operator== (other); } /** Removes all elements from the array. This will remove all the elements, and free any storage that the array is using. To clear the array without freeing the storage, use the clearQuick() method instead. @see clearQuick */ void clear() { const ScopedLockType lock (getLock()); for (int i = 0; i < numUsed; ++i) data.elements[i].~ElementType(); data.setAllocatedSize (0); numUsed = 0; } /** Removes all elements from the array without freeing the array's allocated storage. @see clear */ void clearQuick() { const ScopedLockType lock (getLock()); for (int i = 0; i < numUsed; ++i) data.elements[i].~ElementType(); numUsed = 0; } /** Returns the current number of elements in the array. */ inline int size() const throw() { return numUsed; } /** Returns one of the elements in the array. If the index passed in is beyond the range of valid elements, this will return zero. If you're certain that the index will always be a valid element, you can call getUnchecked() instead, which is faster. @param index the index of the element being requested (0 is the first element in the array) @see getUnchecked, getFirst, getLast */ inline ElementType operator[] (const int index) const { const ScopedLockType lock (getLock()); return isPositiveAndBelow (index, numUsed) ? data.elements [index] : ElementType(); } /** Returns one of the elements in the array, without checking the index passed in. Unlike the operator[] method, this will try to return an element without checking that the index is within the bounds of the array, so should only be used when you're confident that it will always be a valid index. @param index the index of the element being requested (0 is the first element in the array) @see operator[], getFirst, getLast */ inline const ElementType getUnchecked (const int index) const { const ScopedLockType lock (getLock()); jassert (isPositiveAndBelow (index, numUsed)); return data.elements [index]; } /** Returns a direct reference to one of the elements in the array, without checking the index passed in. This is like getUnchecked, but returns a direct reference to the element, so that you can alter it directly. Obviously this can be dangerous, so only use it when absolutely necessary. @param index the index of the element being requested (0 is the first element in the array) @see operator[], getFirst, getLast */ inline ElementType& getReference (const int index) const throw() { const ScopedLockType lock (getLock()); jassert (isPositiveAndBelow (index, numUsed)); return data.elements [index]; } /** Returns the first element in the array, or 0 if the array is empty. @see operator[], getUnchecked, getLast */ inline ElementType getFirst() const { const ScopedLockType lock (getLock()); return (numUsed > 0) ? data.elements [0] : ElementType(); } /** Returns the last element in the array, or 0 if the array is empty. @see operator[], getUnchecked, getFirst */ inline ElementType getLast() const { const ScopedLockType lock (getLock()); return (numUsed > 0) ? data.elements [numUsed - 1] : ElementType(); } /** Returns a pointer to the actual array data. This pointer will only be valid until the next time a non-const method is called on the array. */ inline ElementType* getRawDataPointer() throw() { return data.elements; } /** Finds the index of the first element which matches the value passed in. This will search the array for the given object, and return the index of its first occurrence. If the object isn't found, the method will return -1. @param elementToLookFor the value or object to look for @returns the index of the object, or -1 if it's not found */ int indexOf (ParameterType elementToLookFor) const { const ScopedLockType lock (getLock()); const ElementType* e = data.elements.getData(); const ElementType* const end = e + numUsed; while (e != end) { if (elementToLookFor == *e) return static_cast (e - data.elements.getData()); ++e; } return -1; } /** Returns true if the array contains at least one occurrence of an object. @param elementToLookFor the value or object to look for @returns true if the item is found */ bool contains (ParameterType elementToLookFor) const { const ScopedLockType lock (getLock()); const ElementType* e = data.elements.getData(); const ElementType* const end = e + numUsed; while (e != end) { if (elementToLookFor == *e) return true; ++e; } return false; } /** Appends a new element at the end of the array. @param newElement the new object to add to the array @see set, insert, addIfNotAlreadyThere, addSorted, addUsingDefaultSort, addArray */ void add (ParameterType newElement) { const ScopedLockType lock (getLock()); data.ensureAllocatedSize (numUsed + 1); new (data.elements + numUsed++) ElementType (newElement); } /** Inserts a new element into the array at a given position. If the index is less than 0 or greater than the size of the array, the element will be added to the end of the array. Otherwise, it will be inserted into the array, moving all the later elements along to make room. @param indexToInsertAt the index at which the new element should be inserted (pass in -1 to add it to the end) @param newElement the new object to add to the array @see add, addSorted, addUsingDefaultSort, set */ void insert (int indexToInsertAt, ParameterType newElement) { const ScopedLockType lock (getLock()); data.ensureAllocatedSize (numUsed + 1); if (isPositiveAndBelow (indexToInsertAt, numUsed)) { ElementType* const insertPos = data.elements + indexToInsertAt; const int numberToMove = numUsed - indexToInsertAt; if (numberToMove > 0) memmove (insertPos + 1, insertPos, numberToMove * sizeof (ElementType)); new (insertPos) ElementType (newElement); ++numUsed; } else { new (data.elements + numUsed++) ElementType (newElement); } } /** Inserts multiple copies of an element into the array at a given position. If the index is less than 0 or greater than the size of the array, the element will be added to the end of the array. Otherwise, it will be inserted into the array, moving all the later elements along to make room. @param indexToInsertAt the index at which the new element should be inserted @param newElement the new object to add to the array @param numberOfTimesToInsertIt how many copies of the value to insert @see insert, add, addSorted, set */ void insertMultiple (int indexToInsertAt, ParameterType newElement, int numberOfTimesToInsertIt) { if (numberOfTimesToInsertIt > 0) { const ScopedLockType lock (getLock()); data.ensureAllocatedSize (numUsed + numberOfTimesToInsertIt); ElementType* insertPos; if (isPositiveAndBelow (indexToInsertAt, numUsed)) { insertPos = data.elements + indexToInsertAt; const int numberToMove = numUsed - indexToInsertAt; memmove (insertPos + numberOfTimesToInsertIt, insertPos, numberToMove * sizeof (ElementType)); } else { insertPos = data.elements + numUsed; } numUsed += numberOfTimesToInsertIt; while (--numberOfTimesToInsertIt >= 0) new (insertPos++) ElementType (newElement); } } /** Inserts an array of values into this array at a given position. If the index is less than 0 or greater than the size of the array, the new elements will be added to the end of the array. Otherwise, they will be inserted into the array, moving all the later elements along to make room. @param indexToInsertAt the index at which the first new element should be inserted @param newElements the new values to add to the array @param numberOfElements how many items are in the array @see insert, add, addSorted, set */ void insertArray (int indexToInsertAt, const ElementType* newElements, int numberOfElements) { if (numberOfElements > 0) { const ScopedLockType lock (getLock()); data.ensureAllocatedSize (numUsed + numberOfElements); ElementType* insertPos; if (isPositiveAndBelow (indexToInsertAt, numUsed)) { insertPos = data.elements + indexToInsertAt; const int numberToMove = numUsed - indexToInsertAt; memmove (insertPos + numberOfElements, insertPos, numberToMove * sizeof (ElementType)); } else { insertPos = data.elements + numUsed; } numUsed += numberOfElements; while (--numberOfElements >= 0) new (insertPos++) ElementType (*newElements++); } } /** Appends a new element at the end of the array as long as the array doesn't already contain it. If the array already contains an element that matches the one passed in, nothing will be done. @param newElement the new object to add to the array */ void addIfNotAlreadyThere (ParameterType newElement) { const ScopedLockType lock (getLock()); if (! contains (newElement)) add (newElement); } /** Replaces an element with a new value. If the index is less than zero, this method does nothing. If the index is beyond the end of the array, the item is added to the end of the array. @param indexToChange the index whose value you want to change @param newValue the new value to set for this index. @see add, insert */ void set (const int indexToChange, ParameterType newValue) { jassert (indexToChange >= 0); const ScopedLockType lock (getLock()); if (isPositiveAndBelow (indexToChange, numUsed)) { data.elements [indexToChange] = newValue; } else if (indexToChange >= 0) { data.ensureAllocatedSize (numUsed + 1); new (data.elements + numUsed++) ElementType (newValue); } } /** Replaces an element with a new value without doing any bounds-checking. This just sets a value directly in the array's internal storage, so you'd better make sure it's in range! @param indexToChange the index whose value you want to change @param newValue the new value to set for this index. @see set, getUnchecked */ void setUnchecked (const int indexToChange, ParameterType newValue) { const ScopedLockType lock (getLock()); jassert (isPositiveAndBelow (indexToChange, numUsed)); data.elements [indexToChange] = newValue; } /** Adds elements from an array to the end of this array. @param elementsToAdd the array of elements to add @param numElementsToAdd how many elements are in this other array @see add */ void addArray (const ElementType* elementsToAdd, int numElementsToAdd) { const ScopedLockType lock (getLock()); if (numElementsToAdd > 0) { data.ensureAllocatedSize (numUsed + numElementsToAdd); while (--numElementsToAdd >= 0) { new (data.elements + numUsed) ElementType (*elementsToAdd++); ++numUsed; } } } /** This swaps the contents of this array with those of another array. If you need to exchange two arrays, this is vastly quicker than using copy-by-value because it just swaps their internal pointers. */ void swapWithArray (Array& otherArray) throw() { const ScopedLockType lock1 (getLock()); const ScopedLockType lock2 (otherArray.getLock()); data.swapWith (otherArray.data); swapVariables (numUsed, otherArray.numUsed); } /** Adds elements from another array to the end of this array. @param arrayToAddFrom the array from which to copy the elements @param startIndex the first element of the other array to start copying from @param numElementsToAdd how many elements to add from the other array. If this value is negative or greater than the number of available elements, all available elements will be copied. @see add */ template void addArray (const OtherArrayType& arrayToAddFrom, int startIndex = 0, int numElementsToAdd = -1) { const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock()); { const ScopedLockType lock2 (getLock()); if (startIndex < 0) { jassertfalse; startIndex = 0; } if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size()) numElementsToAdd = arrayToAddFrom.size() - startIndex; while (--numElementsToAdd >= 0) add (arrayToAddFrom.getUnchecked (startIndex++)); } } /** Inserts a new element into the array, assuming that the array is sorted. This will use a comparator to find the position at which the new element should go. If the array isn't sorted, the behaviour of this method will be unpredictable. @param comparator the comparator to use to compare the elements - see the sort() method for details about the form this object should take @param newElement the new element to insert to the array @see addUsingDefaultSort, add, sort */ template void addSorted (ElementComparator& comparator, ParameterType newElement) { const ScopedLockType lock (getLock()); insert (findInsertIndexInSortedArray (comparator, data.elements.getData(), newElement, 0, numUsed), newElement); } /** Inserts a new element into the array, assuming that the array is sorted. This will use the DefaultElementComparator class for sorting, so your ElementType must be suitable for use with that class. If the array isn't sorted, the behaviour of this method will be unpredictable. @param newElement the new element to insert to the array @see addSorted, sort */ void addUsingDefaultSort (ParameterType newElement) { DefaultElementComparator comparator; addSorted (comparator, newElement); } /** Finds the index of an element in the array, assuming that the array is sorted. This will use a comparator to do a binary-chop to find the index of the given element, if it exists. If the array isn't sorted, the behaviour of this method will be unpredictable. @param comparator the comparator to use to compare the elements - see the sort() method for details about the form this object should take @param elementToLookFor the element to search for @returns the index of the element, or -1 if it's not found @see addSorted, sort */ template int indexOfSorted (ElementComparator& comparator, ParameterType elementToLookFor) const { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused const ScopedLockType lock (getLock()); int start = 0; int end = numUsed; for (;;) { if (start >= end) { return -1; } else if (comparator.compareElements (elementToLookFor, data.elements [start]) == 0) { return start; } else { const int halfway = (start + end) >> 1; if (halfway == start) return -1; else if (comparator.compareElements (elementToLookFor, data.elements [halfway]) >= 0) start = halfway; else end = halfway; } } } /** Removes an element from the array. This will remove the element at a given index, and move back all the subsequent elements to close the gap. If the index passed in is out-of-range, nothing will happen. @param indexToRemove the index of the element to remove @returns the element that has been removed @see removeValue, removeRange */ ElementType remove (const int indexToRemove) { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (indexToRemove, numUsed)) { --numUsed; ElementType* const e = data.elements + indexToRemove; ElementType removed (*e); e->~ElementType(); const int numberToShift = numUsed - indexToRemove; if (numberToShift > 0) memmove (e, e + 1, numberToShift * sizeof (ElementType)); if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); return removed; } else { return ElementType(); } } /** Removes an item from the array. This will remove the first occurrence of the given element from the array. If the item isn't found, no action is taken. @param valueToRemove the object to try to remove @see remove, removeRange */ void removeValue (ParameterType valueToRemove) { const ScopedLockType lock (getLock()); ElementType* e = data.elements; for (int i = numUsed; --i >= 0;) { if (valueToRemove == *e) { remove (static_cast (e - data.elements.getData())); break; } ++e; } } /** Removes a range of elements from the array. This will remove a set of elements, starting from the given index, and move subsequent elements down to close the gap. If the range extends beyond the bounds of the array, it will be safely clipped to the size of the array. @param startIndex the index of the first element to remove @param numberToRemove how many elements should be removed @see remove, removeValue */ void removeRange (int startIndex, int numberToRemove) { const ScopedLockType lock (getLock()); const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove); startIndex = jlimit (0, numUsed, startIndex); if (endIndex > startIndex) { ElementType* const e = data.elements + startIndex; numberToRemove = endIndex - startIndex; for (int i = 0; i < numberToRemove; ++i) e[i].~ElementType(); const int numToShift = numUsed - endIndex; if (numToShift > 0) memmove (e, e + numberToRemove, numToShift * sizeof (ElementType)); numUsed -= numberToRemove; if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); } } /** Removes the last n elements from the array. @param howManyToRemove how many elements to remove from the end of the array @see remove, removeValue, removeRange */ void removeLast (int howManyToRemove = 1) { const ScopedLockType lock (getLock()); if (howManyToRemove > numUsed) howManyToRemove = numUsed; for (int i = 1; i <= howManyToRemove; ++i) data.elements [numUsed - i].~ElementType(); numUsed -= howManyToRemove; if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); } /** Removes any elements which are also in another array. @param otherArray the other array in which to look for elements to remove @see removeValuesNotIn, remove, removeValue, removeRange */ template void removeValuesIn (const OtherArrayType& otherArray) { const typename OtherArrayType::ScopedLockType lock1 (otherArray.getLock()); const ScopedLockType lock2 (getLock()); if (this == &otherArray) { clear(); } else { if (otherArray.size() > 0) { for (int i = numUsed; --i >= 0;) if (otherArray.contains (data.elements [i])) remove (i); } } } /** Removes any elements which are not found in another array. Only elements which occur in this other array will be retained. @param otherArray the array in which to look for elements NOT to remove @see removeValuesIn, remove, removeValue, removeRange */ template void removeValuesNotIn (const OtherArrayType& otherArray) { const typename OtherArrayType::ScopedLockType lock1 (otherArray.getLock()); const ScopedLockType lock2 (getLock()); if (this != &otherArray) { if (otherArray.size() <= 0) { clear(); } else { for (int i = numUsed; --i >= 0;) if (! otherArray.contains (data.elements [i])) remove (i); } } } /** Swaps over two elements in the array. This swaps over the elements found at the two indexes passed in. If either index is out-of-range, this method will do nothing. @param index1 index of one of the elements to swap @param index2 index of the other element to swap */ void swap (const int index1, const int index2) { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (index1, numUsed) && isPositiveAndBelow (index2, numUsed)) { swapVariables (data.elements [index1], data.elements [index2]); } } /** Moves one of the values to a different position. This will move the value to a specified index, shuffling along any intervening elements as required. So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. @param currentIndex the index of the value to be moved. If this isn't a valid index, then nothing will be done @param newIndex the index at which you'd like this value to end up. If this is less than zero, the value will be moved to the end of the array */ void move (const int currentIndex, int newIndex) throw() { if (currentIndex != newIndex) { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (currentIndex, numUsed)) { if (! isPositiveAndBelow (newIndex, numUsed)) newIndex = numUsed - 1; char tempCopy [sizeof (ElementType)]; memcpy (tempCopy, data.elements + currentIndex, sizeof (ElementType)); if (newIndex > currentIndex) { memmove (data.elements + currentIndex, data.elements + currentIndex + 1, (newIndex - currentIndex) * sizeof (ElementType)); } else { memmove (data.elements + newIndex + 1, data.elements + newIndex, (currentIndex - newIndex) * sizeof (ElementType)); } memcpy (data.elements + newIndex, tempCopy, sizeof (ElementType)); } } } /** Reduces the amount of storage being used by the array. Arrays typically allocate slightly more storage than they need, and after removing elements, they may have quite a lot of unused space allocated. This method will reduce the amount of allocated storage to a minimum. */ void minimiseStorageOverheads() { const ScopedLockType lock (getLock()); data.shrinkToNoMoreThan (numUsed); } /** Increases the array's internal storage to hold a minimum number of elements. Calling this before adding a large known number of elements means that the array won't have to keep dynamically resizing itself as the elements are added, and it'll therefore be more efficient. */ void ensureStorageAllocated (const int minNumElements) { const ScopedLockType lock (getLock()); data.ensureAllocatedSize (minNumElements); } /** Sorts the elements in the array. This will use a comparator object to sort the elements into order. The object passed must have a method of the form: @code int compareElements (ElementType first, ElementType second); @endcode ..and this method must return: - a value of < 0 if the first comes before the second - a value of 0 if the two objects are equivalent - a value of > 0 if the second comes before the first To improve performance, the compareElements() method can be declared as static or const. @param comparator the comparator to use for comparing elements. @param retainOrderOfEquivalentItems if this is true, then items which the comparator says are equivalent will be kept in the order in which they currently appear in the array. This is slower to perform, but may be important in some cases. If it's false, a faster algorithm is used, but equivalent elements may be rearranged. @see addSorted, indexOfSorted, sortArray */ template void sort (ElementComparator& comparator, const bool retainOrderOfEquivalentItems = false) const { const ScopedLockType lock (getLock()); (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems); } /** Returns the CriticalSection that locks this array. To lock, you can call getLock().enter() and getLock().exit(), or preferably use an object of ScopedLockType as an RAII lock for it. */ inline const TypeOfCriticalSectionToUse& getLock() const throw() { return data; } /** Returns the type of scoped lock to use for locking this array */ typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; private: ArrayAllocationBase data; int numUsed; }; #endif // __JUCE_ARRAY_JUCEHEADER__ /*** End of inlined file: juce_Array.h ***/ #endif #ifndef __JUCE_ARRAYALLOCATIONBASE_JUCEHEADER__ #endif #ifndef __JUCE_DYNAMICOBJECT_JUCEHEADER__ /*** Start of inlined file: juce_DynamicObject.h ***/ #ifndef __JUCE_DYNAMICOBJECT_JUCEHEADER__ #define __JUCE_DYNAMICOBJECT_JUCEHEADER__ /*** Start of inlined file: juce_NamedValueSet.h ***/ #ifndef __JUCE_NAMEDVALUESET_JUCEHEADER__ #define __JUCE_NAMEDVALUESET_JUCEHEADER__ /*** Start of inlined file: juce_Variant.h ***/ #ifndef __JUCE_VARIANT_JUCEHEADER__ #define __JUCE_VARIANT_JUCEHEADER__ /*** Start of inlined file: juce_Identifier.h ***/ #ifndef __JUCE_IDENTIFIER_JUCEHEADER__ #define __JUCE_IDENTIFIER_JUCEHEADER__ /*** Start of inlined file: juce_StringPool.h ***/ #ifndef __JUCE_STRINGPOOL_JUCEHEADER__ #define __JUCE_STRINGPOOL_JUCEHEADER__ /** A StringPool holds a set of shared strings, which reduces storage overheads and improves comparison speed when dealing with many duplicate strings. When you add a string to a pool using getPooledString, it'll return a character array containing the same string. This array is owned by the pool, and the same array is returned every time a matching string is asked for. This means that it's trivial to compare two pooled strings for equality, as you can simply compare their pointers. It also cuts down on storage if you're using many copies of the same string. */ class JUCE_API StringPool { public: /** Creates an empty pool. */ StringPool() throw(); /** Destructor */ ~StringPool(); /** Returns a pointer to a copy of the string that is passed in. The pool will always return the same pointer when asked for a string that matches it. The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ const juce_wchar* getPooledString (const String& original); /** Returns a pointer to a copy of the string that is passed in. The pool will always return the same pointer when asked for a string that matches it. The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ const juce_wchar* getPooledString (const char* original); /** Returns a pointer to a copy of the string that is passed in. The pool will always return the same pointer when asked for a string that matches it. The pool will own all the pointers that it returns, deleting them when the pool itself is deleted. */ const juce_wchar* getPooledString (const juce_wchar* original); /** Returns the number of strings in the pool. */ int size() const throw(); /** Returns one of the strings in the pool, by index. */ const juce_wchar* operator[] (int index) const throw(); private: Array strings; }; #endif // __JUCE_STRINGPOOL_JUCEHEADER__ /*** End of inlined file: juce_StringPool.h ***/ /** Represents a string identifier, designed for accessing properties by name. Identifier objects are very light and fast to copy, but slower to initialise from a string, so it's much faster to keep a static identifier object to refer to frequently-used names, rather than constructing them each time you need it. @see NamedPropertySet, ValueTree */ class JUCE_API Identifier { public: /** Creates a null identifier. */ Identifier() throw(); /** Creates an identifier with a specified name. Because this name may need to be used in contexts such as script variables or XML tags, it must only contain ascii letters and digits, or the underscore character. */ Identifier (const char* name); /** Creates an identifier with a specified name. Because this name may need to be used in contexts such as script variables or XML tags, it must only contain ascii letters and digits, or the underscore character. */ Identifier (const String& name); /** Creates a copy of another identifier. */ Identifier (const Identifier& other) throw(); /** Creates a copy of another identifier. */ Identifier& operator= (const Identifier& other) throw(); /** Destructor */ ~Identifier(); /** Compares two identifiers. This is a very fast operation. */ inline bool operator== (const Identifier& other) const throw() { return name == other.name; } /** Compares two identifiers. This is a very fast operation. */ inline bool operator!= (const Identifier& other) const throw() { return name != other.name; } /** Returns this identifier as a string. */ const String toString() const { return name; } /** Returns this identifier's raw string pointer. */ operator const juce_wchar*() const throw() { return name; } private: const juce_wchar* name; static StringPool& getPool(); }; #endif // __JUCE_IDENTIFIER_JUCEHEADER__ /*** End of inlined file: juce_Identifier.h ***/ /*** Start of inlined file: juce_OutputStream.h ***/ #ifndef __JUCE_OUTPUTSTREAM_JUCEHEADER__ #define __JUCE_OUTPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_NewLine.h ***/ #ifndef __JUCE_NEWLINE_JUCEHEADER__ #define __JUCE_NEWLINE_JUCEHEADER__ /** This class is used for represent a new-line character sequence. To write a new-line to a stream, you can use the predefined 'newLine' variable, e.g. @code myOutputStream << "Hello World" << newLine << newLine; @endcode The exact character sequence that will be used for the new-line can be set and retrieved with OutputStream::setNewLineString() and OutputStream::getNewLineString(). */ class JUCE_API NewLine { public: /** Returns the default new-line sequence that the library uses. @see OutputStream::setNewLineString() */ static const char* getDefault() throw() { return "\r\n"; } /** Returns the default new-line sequence that the library uses. @see getDefault() */ operator const String() const { return getDefault(); } }; /** An predefined object representing a new-line, which can be written to a string or stream. To write a new-line to a stream, you can use the predefined 'newLine' variable like this: @code myOutputStream << "Hello World" << newLine << newLine; @endcode */ extern NewLine newLine; /** Writes a new-line sequence to a string. You can use the predefined object 'newLine' to invoke this, e.g. @code myString << "Hello World" << newLine << newLine; @endcode */ JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, const NewLine&); #endif // __JUCE_NEWLINE_JUCEHEADER__ /*** End of inlined file: juce_NewLine.h ***/ /*** Start of inlined file: juce_InputStream.h ***/ #ifndef __JUCE_INPUTSTREAM_JUCEHEADER__ #define __JUCE_INPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_MemoryBlock.h ***/ #ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ #define __JUCE_MEMORYBLOCK_JUCEHEADER__ /** A class to hold a resizable block of raw data. */ class JUCE_API MemoryBlock { public: /** Create an uninitialised block with 0 size. */ MemoryBlock() throw(); /** Creates a memory block with a given initial size. @param initialSize the size of block to create @param initialiseToZero whether to clear the memory or just leave it uninitialised */ MemoryBlock (const size_t initialSize, bool initialiseToZero = false); /** Creates a copy of another memory block. */ MemoryBlock (const MemoryBlock& other); /** Creates a memory block using a copy of a block of data. @param dataToInitialiseFrom some data to copy into this block @param sizeInBytes how much space to use */ MemoryBlock (const void* dataToInitialiseFrom, size_t sizeInBytes); /** Destructor. */ ~MemoryBlock() throw(); /** Copies another memory block onto this one. This block will be resized and copied to exactly match the other one. */ MemoryBlock& operator= (const MemoryBlock& other); /** Compares two memory blocks. @returns true only if the two blocks are the same size and have identical contents. */ bool operator== (const MemoryBlock& other) const throw(); /** Compares two memory blocks. @returns true if the two blocks are different sizes or have different contents. */ bool operator!= (const MemoryBlock& other) const throw(); /** Returns true if the data in this MemoryBlock matches the raw bytes passed-in. */ bool matches (const void* data, size_t dataSize) const throw(); /** Returns a void pointer to the data. Note that the pointer returned will probably become invalid when the block is resized. */ void* getData() const throw() { return data; } /** Returns a byte from the memory block. This returns a reference, so you can also use it to set a byte. */ template char& operator[] (const Type offset) const throw() { return data [offset]; } /** Returns the block's current allocated size, in bytes. */ size_t getSize() const throw() { return size; } /** Resizes the memory block. This will try to keep as much of the block's current content as it can, and can optionally be made to clear any new space that gets allocated at the end of the block. @param newSize the new desired size for the block @param initialiseNewSpaceToZero if the block gets enlarged, this determines whether to clear the new section or just leave it uninitialised @see ensureSize */ void setSize (const size_t newSize, bool initialiseNewSpaceToZero = false); /** Increases the block's size only if it's smaller than a given size. @param minimumSize if the block is already bigger than this size, no action will be taken; otherwise it will be increased to this size @param initialiseNewSpaceToZero if the block gets enlarged, this determines whether to clear the new section or just leave it uninitialised @see setSize */ void ensureSize (const size_t minimumSize, bool initialiseNewSpaceToZero = false); /** Fills the entire memory block with a repeated byte value. This is handy for clearing a block of memory to zero. */ void fillWith (uint8 valueToUse) throw(); /** Adds another block of data to the end of this one. This block's size will be increased accordingly. */ void append (const void* data, size_t numBytes); /** Exchanges the contents of this and another memory block. No actual copying is required for this, so it's very fast. */ void swapWith (MemoryBlock& other) throw(); /** Copies data into this MemoryBlock from a memory address. @param srcData the memory location of the data to copy into this block @param destinationOffset the offset in this block at which the data being copied should begin @param numBytes how much to copy in (if this goes beyond the size of the memory block, it will be clipped so not to do anything nasty) */ void copyFrom (const void* srcData, int destinationOffset, size_t numBytes) throw(); /** Copies data from this MemoryBlock to a memory address. @param destData the memory location to write to @param sourceOffset the offset within this block from which the copied data will be read @param numBytes how much to copy (if this extends beyond the limits of the memory block, zeros will be used for that portion of the data) */ void copyTo (void* destData, int sourceOffset, size_t numBytes) const throw(); /** Chops out a section of the block. This will remove a section of the memory block and close the gap around it, shifting any subsequent data downwards and reducing the size of the block. If the range specified goes beyond the size of the block, it will be clipped. */ void removeSection (size_t startByte, size_t numBytesToRemove); /** Attempts to parse the contents of the block as a zero-terminated string of 8-bit characters in the system's default encoding. */ const String toString() const; /** Parses a string of hexadecimal numbers and writes this data into the memory block. The block will be resized to the number of valid bytes read from the string. Non-hex characters in the string will be ignored. @see String::toHexString() */ void loadFromHexString (const String& sourceHexString); /** Sets a number of bits in the memory block, treating it as a long binary sequence. */ void setBitRange (size_t bitRangeStart, size_t numBits, int binaryNumberToApply) throw(); /** Reads a number of bits from the memory block, treating it as one long binary sequence */ int getBitRange (size_t bitRangeStart, size_t numBitsToRead) const throw(); /** Returns a string of characters that represent the binary contents of this block. Uses a 64-bit encoding system to allow binary data to be turned into a string of simple non-extended characters, e.g. for storage in XML. @see fromBase64Encoding */ const String toBase64Encoding() const; /** Takes a string of encoded characters and turns it into binary data. The string passed in must have been created by to64BitEncoding(), and this block will be resized to recreate the original data block. @see toBase64Encoding */ bool fromBase64Encoding (const String& encodedString); private: HeapBlock data; size_t size; static const char* const encodingTable; JUCE_LEAK_DETECTOR (MemoryBlock); }; #endif // __JUCE_MEMORYBLOCK_JUCEHEADER__ /*** End of inlined file: juce_MemoryBlock.h ***/ /** The base class for streams that read data. Input and output streams are used throughout the library - subclasses can override some or all of the virtual functions to implement their behaviour. @see OutputStream, MemoryInputStream, BufferedInputStream, FileInputStream */ class JUCE_API InputStream { public: /** Destructor. */ virtual ~InputStream() {} /** Returns the total number of bytes available for reading in this stream. Note that this is the number of bytes available from the start of the stream, not from the current position. If the size of the stream isn't actually known, this may return -1. */ virtual int64 getTotalLength() = 0; /** Returns true if the stream has no more data to read. */ virtual bool isExhausted() = 0; /** Reads a set of bytes from the stream into a memory buffer. 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 it's often more efficient for subclasses to implement them directly). @param destBuffer the destination buffer for the data @param maxBytesToRead the maximum number of bytes to read - make sure the memory block passed in is big enough to contain this many bytes. @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 */ virtual int read (void* destBuffer, int maxBytesToRead) = 0; /** Reads a byte from the stream. If the stream is exhausted, this will return zero. @see OutputStream::writeByte */ virtual char readByte(); /** Reads a boolean from the stream. The bool is encoded as a single byte - 1 for true, 0 for false. If the stream is exhausted, this will return false. @see OutputStream::writeBool */ virtual bool readBool(); /** Reads two bytes from the stream as a little-endian 16-bit value. If the next two bytes read are byte1 and byte2, this returns (byte1 | (byte2 << 8)). If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeShort, readShortBigEndian */ virtual short readShort(); /** Reads two bytes from the stream as a little-endian 16-bit value. If the next two bytes read are byte1 and byte2, this returns (byte2 | (byte1 << 8)). If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeShortBigEndian, readShort */ virtual short readShortBigEndian(); /** Reads four bytes from the stream as a little-endian 32-bit value. If the next four bytes are byte1 to byte4, this returns (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24)). If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeInt, readIntBigEndian */ virtual int readInt(); /** Reads four bytes from the stream as a big-endian 32-bit value. If the next four bytes are byte1 to byte4, this returns (byte4 | (byte3 << 8) | (byte2 << 16) | (byte1 << 24)). If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeIntBigEndian, readInt */ virtual int readIntBigEndian(); /** Reads eight bytes from the stream as a little-endian 64-bit value. If the next eight bytes are byte1 to byte8, this returns (byte1 | (byte2 << 8) | (byte3 << 16) | (byte4 << 24) | (byte5 << 32) | (byte6 << 40) | (byte7 << 48) | (byte8 << 56)). If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeInt64, readInt64BigEndian */ virtual int64 readInt64(); /** Reads eight bytes from the stream as a big-endian 64-bit value. If the next eight bytes are byte1 to byte8, this returns (byte8 | (byte7 << 8) | (byte6 << 16) | (byte5 << 24) | (byte4 << 32) | (byte3 << 40) | (byte2 << 48) | (byte1 << 56)). If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeInt64BigEndian, readInt64 */ virtual int64 readInt64BigEndian(); /** Reads four bytes as a 32-bit floating point value. The raw 32-bit encoding of the float is read from the stream as a little-endian int. If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeFloat, readDouble */ virtual float readFloat(); /** Reads four bytes as a 32-bit floating point value. The raw 32-bit encoding of the float is read from the stream as a big-endian int. If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeFloatBigEndian, readDoubleBigEndian */ virtual float readFloatBigEndian(); /** Reads eight bytes as a 64-bit floating point value. The raw 64-bit encoding of the double is read from the stream as a little-endian int64. If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeDouble, readFloat */ virtual double readDouble(); /** Reads eight bytes as a 64-bit floating point value. The raw 64-bit encoding of the double is read from the stream as a big-endian int64. If the stream is exhausted partway through reading the bytes, this will return zero. @see OutputStream::writeDoubleBigEndian, readFloatBigEndian */ virtual double readDoubleBigEndian(); /** Reads an encoded 32-bit number from the stream using a space-saving compressed format. For small values, this is more space-efficient than using readInt() and OutputStream::writeInt() The format used is: number of significant bytes + up to 4 bytes in little-endian order. @see OutputStream::writeCompressedInt() */ virtual int readCompressedInt(); /** Reads a UTF8 string from the stream, up to the next linefeed or carriage return. This will read up to the next "\n" or "\r\n" or end-of-stream. After this call, the stream's position will be left pointing to the next character following the line-feed, but the linefeeds aren't included in the string that is returned. */ virtual const String readNextLine(); /** Reads a zero-terminated UTF8 string from the stream. This will read characters from the stream until it hits a zero character or end-of-stream. @see OutputStream::writeString, readEntireStreamAsString */ virtual const String readString(); /** Tries to read the whole stream and turn it into a string. This will read from the stream's current position until the end-of-stream, and will try to make an educated guess about whether it's unicode or an 8-bit encoding. */ virtual const String readEntireStreamAsString(); /** Reads from the stream and appends the data to a MemoryBlock. @param destBlock the block to append the data onto @param maxNumBytesToRead if this is a positive value, it sets a limit to the number of bytes that will be read - if it's negative, data will be read until the stream is exhausted. @returns the number of bytes that were added to the memory block */ virtual int readIntoMemoryBlock (MemoryBlock& destBlock, int maxNumBytesToRead = -1); /** Returns the offset of the next byte that will be read from the stream. @see setPosition */ virtual int64 getPosition() = 0; /** Tries to move the current read position of the stream. The position is an absolute number of bytes from the stream's start. Some streams might not be able to do this, in which case they should do nothing and return false. Others might be able to manage it by resetting themselves and skipping to the correct position, although this is obviously a bit slow. @returns true if the stream manages to reposition itself correctly @see getPosition */ virtual bool setPosition (int64 newPosition) = 0; /** Reads and discards a number of bytes from the stream. Some input streams might implement this efficiently, but the base class will just keep reading data until the requisite number of bytes have been done. */ virtual void skipNextBytes (int64 numBytesToSkip); protected: InputStream() throw() {} private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InputStream); }; #endif // __JUCE_INPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_InputStream.h ***/ class File; /** The base class for streams that write data to some kind of destination. Input and output streams are used throughout the library - subclasses can override some or all of the virtual functions to implement their behaviour. @see InputStream, MemoryOutputStream, FileOutputStream */ class JUCE_API OutputStream { protected: OutputStream(); public: /** Destructor. Some subclasses might want to do things like call flush() during their destructors. */ virtual ~OutputStream(); /** If the stream is using a buffer, this will ensure it gets written out to the destination. */ virtual void flush() = 0; /** Tries to move the stream's output position. Not all streams will be able to seek to a new position - this will return false if it fails to work. @see getPosition */ virtual bool setPosition (int64 newPosition) = 0; /** Returns the stream's current position. @see setPosition */ virtual int64 getPosition() = 0; /** Writes a block of data to the stream. When creating a subclass of OutputStream, this is the only write method that needs to be overloaded - the base class has methods for writing other types of data which use this to do the work. @returns false if the write operation fails for some reason */ virtual bool write (const void* dataToWrite, int howManyBytes) = 0; /** Writes a single byte to the stream. @see InputStream::readByte */ virtual void writeByte (char byte); /** Writes a boolean to the stream as a single byte. This is encoded as a binary byte (not as text) with a value of 1 or 0. @see InputStream::readBool */ virtual void writeBool (bool boolValue); /** Writes a 16-bit integer to the stream in a little-endian byte order. This will write two bytes to the stream: (value & 0xff), then (value >> 8). @see InputStream::readShort */ virtual void writeShort (short value); /** Writes a 16-bit integer to the stream in a big-endian byte order. This will write two bytes to the stream: (value >> 8), then (value & 0xff). @see InputStream::readShortBigEndian */ virtual void writeShortBigEndian (short value); /** Writes a 32-bit integer to the stream in a little-endian byte order. @see InputStream::readInt */ virtual void writeInt (int value); /** Writes a 32-bit integer to the stream in a big-endian byte order. @see InputStream::readIntBigEndian */ virtual void writeIntBigEndian (int value); /** Writes a 64-bit integer to the stream in a little-endian byte order. @see InputStream::readInt64 */ virtual void writeInt64 (int64 value); /** Writes a 64-bit integer to the stream in a big-endian byte order. @see InputStream::readInt64BigEndian */ virtual void writeInt64BigEndian (int64 value); /** Writes a 32-bit floating point value to the stream in a binary format. The binary 32-bit encoding of the float is written as a little-endian int. @see InputStream::readFloat */ virtual void writeFloat (float value); /** Writes a 32-bit floating point value to the stream in a binary format. The binary 32-bit encoding of the float is written as a big-endian int. @see InputStream::readFloatBigEndian */ virtual void writeFloatBigEndian (float value); /** Writes a 64-bit floating point value to the stream in a binary format. The eight raw bytes of the double value are written out as a little-endian 64-bit int. @see InputStream::readDouble */ virtual void writeDouble (double value); /** Writes a 64-bit floating point value to the stream in a binary format. The eight raw bytes of the double value are written out as a big-endian 64-bit int. @see InputStream::readDoubleBigEndian */ virtual void writeDoubleBigEndian (double value); /** Writes a condensed binary encoding of a 32-bit integer. If you're storing a lot of integers which are unlikely to have very large values, this can save a lot of space, because values under 0xff will only take up 2 bytes, under 0xffff only 3 bytes, etc. The format used is: number of significant bytes + up to 4 bytes in little-endian order. @see InputStream::readCompressedInt */ virtual void writeCompressedInt (int value); /** Stores a string in the stream in a binary format. This isn't the method to use if you're trying to append text to the end of a text-file! It's intended for storing a string so that it can be retrieved later by InputStream::readString(). It writes the string to the stream as UTF8, including the null termination character. For appending text to a file, instead use writeText, or operator<< @see InputStream::readString, writeText, operator<< */ virtual void writeString (const String& text); /** Writes a string of text to the stream. It can either write it as UTF8 characters or as unicode, and can also add unicode header bytes (0xff, 0xfe) to indicate the endianness (this should only be done at the start of a file). The method also replaces '\\n' characters in the text with '\\r\\n'. */ virtual void writeText (const String& text, bool asUnicode, bool writeUnicodeHeaderBytes); /** Reads data from an input stream and writes it to this stream. @param source the stream to read from @param maxNumBytesToWrite the number of bytes to read from the stream (if this is less than zero, it will keep reading until the input is exhausted) */ virtual int writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite); /** Sets the string that will be written to the stream when the writeNewLine() method is called. By default this will be set the the value of NewLine::getDefault(). */ void setNewLineString (const String& newLineString); /** Returns the current new-line string that was set by setNewLineString(). */ const String& getNewLineString() const throw() { return newLineString; } private: String newLineString; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OutputStream); }; /** Writes a number to a stream as 8-bit characters in the default system encoding. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, int number); /** Writes a number to a stream as 8-bit characters in the default system encoding. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, double number); /** Writes a character to a stream. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, char character); /** Writes a null-terminated text string to a stream. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const char* text); /** Writes a block of data from a MemoryBlock to a stream. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryBlock& data); /** Writes the contents of a file to a stream. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const File& fileToRead); /** Writes a new-line to a stream. You can use the predefined symbol 'newLine' to invoke this, e.g. @code myOutputStream << "Hello World" << newLine << newLine; @endcode @see OutputStream::setNewLineString */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const NewLine&); #endif // __JUCE_OUTPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_OutputStream.h ***/ #ifndef DOXYGEN class JUCE_API DynamicObject; #endif /** A variant class, that can be used to hold a range of primitive values. A var object can hold a range of simple primitive values, strings, or a reference-counted pointer to a DynamicObject. The var class is intended to act like the values used in dynamic scripting languages. @see DynamicObject */ class JUCE_API var { public: typedef const var (DynamicObject::*MethodFunction) (const var* arguments, int numArguments); typedef Identifier identifier; /** Creates a void variant. */ var() throw(); /** Destructor. */ ~var() throw(); /** A static var object that can be used where you need an empty variant object. */ static const var null; var (const var& valueToCopy); var (int value) throw(); var (bool value) throw(); var (double value) throw(); var (const char* value); var (const juce_wchar* value); var (const String& value); var (DynamicObject* object); var (MethodFunction method) throw(); var& operator= (const var& valueToCopy); var& operator= (int value); var& operator= (bool value); var& operator= (double value); var& operator= (const char* value); var& operator= (const juce_wchar* value); var& operator= (const String& value); var& operator= (DynamicObject* object); var& operator= (MethodFunction method); void swapWith (var& other) throw(); operator int() const; operator bool() const; operator float() const; operator double() const; operator const String() const; const String toString() const; DynamicObject* getObject() const; bool isVoid() const throw(); bool isInt() const throw(); bool isBool() const throw(); bool isDouble() const throw(); bool isString() const throw(); bool isObject() const throw(); bool isMethod() const throw(); /** Writes a binary representation of this value to a stream. The data can be read back later using readFromStream(). */ void writeToStream (OutputStream& output) const; /** Reads back a stored binary representation of a value. The data in the stream must have been written using writeToStream(), or this will have unpredictable results. */ static const var readFromStream (InputStream& input); /** If this variant is an object, this returns one of its properties. */ const var operator[] (const Identifier& propertyName) const; /** If this variant is an object, this invokes one of its methods with no arguments. */ const var call (const Identifier& method) const; /** If this variant is an object, this invokes one of its methods with one argument. */ const var call (const Identifier& method, const var& arg1) const; /** If this variant is an object, this invokes one of its methods with 2 arguments. */ const var call (const Identifier& method, const var& arg1, const var& arg2) const; /** If this variant is an object, this invokes one of its methods with 3 arguments. */ const var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3); /** If this variant is an object, this invokes one of its methods with 4 arguments. */ const var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4) const; /** If this variant is an object, this invokes one of its methods with 5 arguments. */ const var call (const Identifier& method, const var& arg1, const var& arg2, const var& arg3, const var& arg4, const var& arg5) const; /** If this variant is an object, this invokes one of its methods with a list of arguments. */ const var invoke (const Identifier& method, const var* arguments, int numArguments) const; /** If this variant is a method pointer, this invokes it on a target object. */ const var invoke (const var& targetObject, const var* arguments, int numArguments) const; /** Returns true if this var has the same value as the one supplied. */ bool equals (const var& other) const throw(); private: class VariantType; friend class VariantType; class VariantType_Void; friend class VariantType_Void; class VariantType_Int; friend class VariantType_Int; class VariantType_Double; friend class VariantType_Double; class VariantType_Float; friend class VariantType_Float; class VariantType_Bool; friend class VariantType_Bool; class VariantType_String; friend class VariantType_String; class VariantType_Object; friend class VariantType_Object; class VariantType_Method; friend class VariantType_Method; union ValueUnion { int intValue; bool boolValue; double doubleValue; String* stringValue; DynamicObject* objectValue; MethodFunction methodValue; }; const VariantType* type; ValueUnion value; }; bool operator== (const var& v1, const var& v2) throw(); bool operator!= (const var& v1, const var& v2) throw(); bool operator== (const var& v1, const String& v2) throw(); bool operator!= (const var& v1, const String& v2) throw(); #endif // __JUCE_VARIANT_JUCEHEADER__ /*** End of inlined file: juce_Variant.h ***/ /*** Start of inlined file: juce_LinkedListPointer.h ***/ #ifndef __JUCE_LINKEDLISTPOINTER_JUCEHEADER__ #define __JUCE_LINKEDLISTPOINTER_JUCEHEADER__ /** Helps to manipulate singly-linked lists of objects. For objects that are designed to contain a pointer to the subsequent item in the list, this class contains methods to deal with the list. To use it, the ObjectType class that it points to must contain a LinkedListPointer called nextListItem, e.g. @code struct MyObject { int x, y, z; // A linkable object must contain a member with this name and type, which must be // accessible by the LinkedListPointer class. (This doesn't mean it has to be public - // you could make your class a friend of a LinkedListPointer instead). LinkedListPointer nextListItem; }; LinkedListPointer myList; myList.append (new MyObject()); myList.append (new MyObject()); int numItems = myList.size(); // returns 2 MyObject* lastInList = myList.getLast(); @endcode */ template class LinkedListPointer { public: /** Creates a null pointer to an empty list. */ LinkedListPointer() throw() : item (0) { } /** Creates a pointer to a list whose head is the item provided. */ explicit LinkedListPointer (ObjectType* const headItem) throw() : item (headItem) { } /** Sets this pointer to point to a new list. */ LinkedListPointer& operator= (ObjectType* const newItem) throw() { item = newItem; return *this; } /** Returns the item which this pointer points to. */ inline operator ObjectType*() const throw() { return item; } /** Returns the item which this pointer points to. */ inline ObjectType* get() const throw() { return item; } /** Returns the last item in the list which this pointer points to. This will iterate the list and return the last item found. Obviously the speed of this operation will be proportional to the size of the list. If the list is empty the return value will be this object. If you're planning on appending a number of items to your list, it's much more efficient to use the Appender class than to repeatedly call getLast() to find the end. */ LinkedListPointer& getLast() throw() { LinkedListPointer* l = this; while (l->item != 0) l = &(l->item->nextListItem); return *l; } /** Returns the number of items in the list. Obviously with a simple linked list, getting the size involves iterating the list, so this can be a lengthy operation - be careful when using this method in your code. */ int size() const throw() { int total = 0; for (ObjectType* i = item; i != 0; i = i->nextListItem) ++total; return total; } /** Returns the item at a given index in the list. Since the only way to find an item is to iterate the list, this operation can obviously be slow, depending on its size, so you should be careful when using this in algorithms. */ LinkedListPointer& operator[] (int index) throw() { LinkedListPointer* l = this; while (--index >= 0 && l->item != 0) l = &(l->item->nextListItem); return *l; } /** Returns the item at a given index in the list. Since the only way to find an item is to iterate the list, this operation can obviously be slow, depending on its size, so you should be careful when using this in algorithms. */ const LinkedListPointer& operator[] (int index) const throw() { const LinkedListPointer* l = this; while (--index >= 0 && l->item != 0) l = &(l->item->nextListItem); return *l; } /** Returns true if the list contains the given item. */ bool contains (const ObjectType* const itemToLookFor) const throw() { for (ObjectType* i = item; i != 0; i = i->nextListItem) if (itemToLookFor == i) return true; return false; } /** Inserts an item into the list, placing it before the item that this pointer currently points to. */ void insertNext (ObjectType* const newItem) { jassert (newItem != 0); jassert (newItem->nextListItem == 0); newItem->nextListItem = item; item = newItem; } /** Inserts an item at a numeric index in the list. Obviously this will involve iterating the list to find the item at the given index, so be careful about the impact this may have on execution time. */ void insertAtIndex (int index, ObjectType* newItem) { jassert (newItem != 0); LinkedListPointer* l = this; while (index != 0 && l->item != 0) { l = &(l->item->nextListItem); --index; } l->insertNext (newItem); } /** Replaces the object that this pointer points to, appending the rest of the list to the new object, and returning the old one. */ ObjectType* replaceNext (ObjectType* const newItem) throw() { jassert (newItem != 0); jassert (newItem->nextListItem == 0); ObjectType* const oldItem = item; item = newItem; item->nextListItem = oldItem->nextListItem; oldItem->nextListItem = 0; return oldItem; } /** Adds an item to the end of the list. This operation involves iterating the whole list, so can be slow - if you need to append a number of items to your list, it's much more efficient to use the Appender class than to repeatedly call append(). */ void append (ObjectType* const newItem) { getLast().item = newItem; } /** Creates copies of all the items in another list and adds them to this one. This will use the ObjectType's copy constructor to try to create copies of each item in the other list, and appends them to this list. */ void addCopyOfList (const LinkedListPointer& other) { LinkedListPointer* insertPoint = this; for (ObjectType* i = other.item; i != 0; i = i->nextListItem) { insertPoint->insertNext (new ObjectType (*i)); insertPoint = &(insertPoint->item->nextListItem); } } /** Removes the head item from the list. This won't delete the object that is removed, but returns it, so the caller can delete it if necessary. */ ObjectType* removeNext() throw() { ObjectType* const oldItem = item; if (oldItem != 0) { item = oldItem->nextListItem; oldItem->nextListItem = 0; } return oldItem; } /** Removes a specific item from the list. Note that this will not delete the item, it simply unlinks it from the list. */ void remove (ObjectType* const itemToRemove) { LinkedListPointer* const l = findPointerTo (itemToRemove); if (l != 0) l->removeNext(); } /** Iterates the list, calling the delete operator on all of its elements and leaving this pointer empty. */ void deleteAll() { while (item != 0) { ObjectType* const oldItem = item; item = oldItem->nextListItem; delete oldItem; } } /** Finds a pointer to a given item. If the item is found in the list, this returns the pointer that points to it. If the item isn't found, this returns null. */ LinkedListPointer* findPointerTo (ObjectType* const itemToLookFor) throw() { LinkedListPointer* l = this; while (l->item != 0) { if (l->item == itemToLookFor) return l; l = &(l->item->nextListItem); } return 0; } /** Copies the items in the list to an array. The destArray must contain enough elements to hold the entire list - no checks are made for this! */ void copyToArray (ObjectType** destArray) const throw() { jassert (destArray != 0); for (ObjectType* i = item; i != 0; i = i->nextListItem) *destArray++ = i; } /** Allows efficient repeated insertions into a list. You can create an Appender object which points to the last element in your list, and then repeatedly call Appender::append() to add items to the end of the list in O(1) time. */ class Appender { public: /** Creates an appender which will add items to the given list. */ Appender (LinkedListPointer& endOfListPointer) throw() : endOfList (&endOfListPointer) { // This can only be used to add to the end of a list. jassert (endOfListPointer.item == 0); } /** Appends an item to the list. */ void append (ObjectType* const newItem) throw() { *endOfList = newItem; endOfList = &(newItem->nextListItem); } private: LinkedListPointer* endOfList; JUCE_DECLARE_NON_COPYABLE (Appender); }; private: ObjectType* item; }; #endif // __JUCE_LINKEDLISTPOINTER_JUCEHEADER__ /*** End of inlined file: juce_LinkedListPointer.h ***/ class XmlElement; /** Holds a set of named var objects. This can be used as a basic structure to hold a set of var object, which can be retrieved by using their identifier. */ class JUCE_API NamedValueSet { public: /** Creates an empty set. */ NamedValueSet() throw(); /** Creates a copy of another set. */ NamedValueSet (const NamedValueSet& other); /** Replaces this set with a copy of another set. */ NamedValueSet& operator= (const NamedValueSet& other); /** Destructor. */ ~NamedValueSet(); bool operator== (const NamedValueSet& other) const; bool operator!= (const NamedValueSet& other) const; /** Returns the total number of values that the set contains. */ int size() const throw(); /** Returns the value of a named item. If the name isn't found, this will return a void variant. @see getProperty */ const var& operator[] (const Identifier& name) const; /** Tries to return the named value, but if no such value is found, this will instead return the supplied default value. */ const var getWithDefault (const Identifier& name, const var& defaultReturnValue) const; /** Changes or adds a named value. @returns true if a value was changed or added; false if the value was already set the the value passed-in. */ bool set (const Identifier& name, const var& newValue); /** Returns true if the set contains an item with the specified name. */ bool contains (const Identifier& name) const; /** Removes a value from the set. @returns true if a value was removed; false if there was no value with the name that was given. */ bool remove (const Identifier& name); /** Returns the name of the value at a given index. The index must be between 0 and size() - 1. */ const Identifier getName (int index) const; /** Returns the value of the item at a given index. The index must be between 0 and size() - 1. */ const var getValueAt (int index) const; /** Removes all values. */ void clear(); /** Returns a pointer to the var that holds a named value, or null if there is no value with this name. Do not use this method unless you really need access to the internal var object for some reason - for normal reading and writing always prefer operator[]() and set(). */ var* getVarPointer (const Identifier& name) const; /** Sets properties to the values of all of an XML element's attributes. */ void setFromXmlAttributes (const XmlElement& xml); /** Sets attributes in an XML element corresponding to each of this object's properties. */ void copyToXmlAttributes (XmlElement& xml) const; private: class NamedValue { public: NamedValue() throw(); NamedValue (const Identifier& name, const var& value); bool operator== (const NamedValue& other) const throw(); LinkedListPointer nextListItem; Identifier name; var value; private: JUCE_LEAK_DETECTOR (NamedValue); }; friend class LinkedListPointer; LinkedListPointer values; }; #endif // __JUCE_NAMEDVALUESET_JUCEHEADER__ /*** End of inlined file: juce_NamedValueSet.h ***/ /*** Start of inlined file: juce_ReferenceCountedObject.h ***/ #ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ #define __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ /** Adds reference-counting to an object. To add reference-counting to a class, derive it from this class, and use the ReferenceCountedObjectPtr class to point to it. e.g. @code class MyClass : public ReferenceCountedObject { void foo(); // This is a neat way of declaring a typedef for a pointer class, // rather than typing out the full templated name each time.. typedef ReferenceCountedObjectPtr Ptr; }; MyClass::Ptr p = new MyClass(); MyClass::Ptr p2 = p; p = 0; p2->foo(); @endcode Once a new ReferenceCountedObject has been assigned to a pointer, be careful not to delete the object manually. @see ReferenceCountedObjectPtr, ReferenceCountedArray */ class JUCE_API ReferenceCountedObject { public: /** Increments the object's reference count. This is done automatically by the smart pointer, but is public just in case it's needed for nefarious purposes. */ inline void incReferenceCount() throw() { ++refCount; } /** Decreases the object's reference count. If the count gets to zero, the object will be deleted. */ inline void decReferenceCount() throw() { jassert (getReferenceCount() > 0); if (--refCount == 0) delete this; } /** Returns the object's current reference count. */ inline int getReferenceCount() const throw() { return refCount.get(); } protected: /** Creates the reference-counted object (with an initial ref count of zero). */ ReferenceCountedObject() { } /** Destructor. */ virtual ~ReferenceCountedObject() { // it's dangerous to delete an object that's still referenced by something else! jassert (getReferenceCount() == 0); } private: Atomic refCount; }; /** Used to point to an object of type ReferenceCountedObject. It's wise to use a typedef instead of typing out the templated name each time - e.g. typedef ReferenceCountedObjectPtr MyClassPtr; @see ReferenceCountedObject, ReferenceCountedObjectArray */ template class ReferenceCountedObjectPtr { public: /** Creates a pointer to a null object. */ inline ReferenceCountedObjectPtr() throw() : referencedObject (0) { } /** Creates a pointer to an object. This will increment the object's reference-count if it is non-null. */ inline ReferenceCountedObjectPtr (ReferenceCountedObjectClass* const refCountedObject) throw() : referencedObject (refCountedObject) { if (refCountedObject != 0) refCountedObject->incReferenceCount(); } /** Copies another pointer. This will increment the object's reference-count (if it is non-null). */ inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr& other) throw() : referencedObject (other.referencedObject) { if (referencedObject != 0) referencedObject->incReferenceCount(); } /** Changes this pointer to point at a different object. The reference count of the old object is decremented, and it might be deleted if it hits zero. The new object's count is incremented. */ ReferenceCountedObjectPtr& operator= (const ReferenceCountedObjectPtr& other) { ReferenceCountedObjectClass* const newObject = other.referencedObject; if (newObject != referencedObject) { if (newObject != 0) newObject->incReferenceCount(); ReferenceCountedObjectClass* const oldObject = referencedObject; referencedObject = newObject; if (oldObject != 0) oldObject->decReferenceCount(); } return *this; } /** Changes this pointer to point at a different object. The reference count of the old object is decremented, and it might be deleted if it hits zero. The new object's count is incremented. */ ReferenceCountedObjectPtr& operator= (ReferenceCountedObjectClass* const newObject) { if (referencedObject != newObject) { if (newObject != 0) newObject->incReferenceCount(); ReferenceCountedObjectClass* const oldObject = referencedObject; referencedObject = newObject; if (oldObject != 0) oldObject->decReferenceCount(); } return *this; } /** Destructor. This will decrement the object's reference-count, and may delete it if it gets to zero. */ inline ~ReferenceCountedObjectPtr() { if (referencedObject != 0) referencedObject->decReferenceCount(); } /** Returns the object that this pointer references. The pointer returned may be zero, of course. */ inline operator ReferenceCountedObjectClass*() const throw() { return referencedObject; } // the -> operator is called on the referenced object inline ReferenceCountedObjectClass* operator->() const throw() { return referencedObject; } /** Returns the object that this pointer references. The pointer returned may be zero, of course. */ inline ReferenceCountedObjectClass* getObject() const throw() { return referencedObject; } private: ReferenceCountedObjectClass* referencedObject; }; /** Compares two ReferenceCountedObjectPointers. */ template bool operator== (const ReferenceCountedObjectPtr& object1, ReferenceCountedObjectClass* const object2) throw() { return object1.getObject() == object2; } /** Compares two ReferenceCountedObjectPointers. */ template bool operator== (const ReferenceCountedObjectPtr& object1, const ReferenceCountedObjectPtr& object2) throw() { return object1.getObject() == object2.getObject(); } /** Compares two ReferenceCountedObjectPointers. */ template bool operator== (ReferenceCountedObjectClass* object1, ReferenceCountedObjectPtr& object2) throw() { return object1 == object2.getObject(); } /** Compares two ReferenceCountedObjectPointers. */ template bool operator!= (const ReferenceCountedObjectPtr& object1, const ReferenceCountedObjectClass* object2) throw() { return object1.getObject() != object2; } /** Compares two ReferenceCountedObjectPointers. */ template bool operator!= (const ReferenceCountedObjectPtr& object1, ReferenceCountedObjectPtr& object2) throw() { return object1.getObject() != object2.getObject(); } /** Compares two ReferenceCountedObjectPointers. */ template bool operator!= (ReferenceCountedObjectClass* object1, ReferenceCountedObjectPtr& object2) throw() { return object1 != object2.getObject(); } #endif // __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ /*** End of inlined file: juce_ReferenceCountedObject.h ***/ /** Represents a dynamically implemented object. This class is primarily intended for wrapping scripting language objects, but could be used for other purposes. An instance of a DynamicObject can be used to store named properties, and by subclassing hasMethod() and invokeMethod(), you can give your object methods. */ class JUCE_API DynamicObject : public ReferenceCountedObject { public: DynamicObject(); /** Destructor. */ virtual ~DynamicObject(); /** Returns true if the object has a property with this name. Note that if the property is actually a method, this will return false. */ virtual bool hasProperty (const Identifier& propertyName) const; /** Returns a named property. This returns a void if no such property exists. */ virtual const var getProperty (const Identifier& propertyName) const; /** Sets a named property. */ virtual void setProperty (const Identifier& propertyName, const var& newValue); /** Removes a named property. */ virtual void removeProperty (const Identifier& propertyName); /** Checks whether this object has the specified method. The default implementation of this just checks whether there's a property with this name that's actually a method, but this can be overridden for building objects with dynamic invocation. */ virtual bool hasMethod (const Identifier& methodName) const; /** Invokes a named method on this object. The default implementation looks up the named property, and if it's a method call, then it invokes it. This method is virtual to allow more dynamic invocation to used for objects where the methods may not already be set as properies. */ virtual const var invokeMethod (const Identifier& methodName, const var* parameters, int numParameters); /** Sets up a method. This is basically the same as calling setProperty (methodName, (var::MethodFunction) myFunction), but helps to avoid accidentally invoking the wrong type of var constructor. It also makes the code easier to read, The compiler will probably force you to use an explicit cast your method to a (var::MethodFunction), e.g. @code setMethod ("doSomething", (var::MethodFunction) &MyClass::doSomething); @endcode */ void setMethod (const Identifier& methodName, var::MethodFunction methodFunction); /** Removes all properties and methods from the object. */ void clear(); private: NamedValueSet properties; JUCE_LEAK_DETECTOR (DynamicObject); }; #endif // __JUCE_DYNAMICOBJECT_JUCEHEADER__ /*** End of inlined file: juce_DynamicObject.h ***/ #endif #ifndef __JUCE_ELEMENTCOMPARATOR_JUCEHEADER__ #endif #ifndef __JUCE_LINKEDLISTPOINTER_JUCEHEADER__ #endif #ifndef __JUCE_NAMEDVALUESET_JUCEHEADER__ #endif #ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ /*** Start of inlined file: juce_OwnedArray.h ***/ #ifndef __JUCE_OWNEDARRAY_JUCEHEADER__ #define __JUCE_OWNEDARRAY_JUCEHEADER__ /** An array designed for holding objects. This holds a list of pointers to objects, and will automatically delete the objects when they are removed from the array, or when the array is itself deleted. Declare it in the form: OwnedArray ..and then add new objects, e.g. myOwnedArray.add (new MyObjectClass()); After adding objects, they are 'owned' by the array and will be deleted when removed or replaced. To make all the array's methods thread-safe, pass in "CriticalSection" as the templated TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. @see Array, ReferenceCountedArray, StringArray, CriticalSection */ template class OwnedArray { public: /** Creates an empty array. */ OwnedArray() throw() : numUsed (0) { } /** Deletes the array and also deletes any objects inside it. To get rid of the array without deleting its objects, use its clear (false) method before deleting it. */ ~OwnedArray() { clear (true); } /** Clears the array, optionally deleting the objects inside it first. */ void clear (const bool deleteObjects = true) { const ScopedLockType lock (getLock()); if (deleteObjects) { while (numUsed > 0) delete data.elements [--numUsed]; } data.setAllocatedSize (0); numUsed = 0; } /** Returns the number of items currently in the array. @see operator[] */ inline int size() const throw() { return numUsed; } /** Returns a pointer to the object at this index in the array. If the index is out-of-range, this will return a null pointer, (and it could be null anyway, because it's ok for the array to hold null pointers as well as objects). @see getUnchecked */ inline ObjectClass* operator[] (const int index) const throw() { const ScopedLockType lock (getLock()); return isPositiveAndBelow (index, numUsed) ? data.elements [index] : static_cast (0); } /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. This is a faster and less safe version of operator[] which doesn't check the index passed in, so it can be used when you're sure the index if always going to be legal. */ inline ObjectClass* getUnchecked (const int index) const throw() { const ScopedLockType lock (getLock()); jassert (isPositiveAndBelow (index, numUsed)); return data.elements [index]; } /** Returns a pointer to the first object in the array. This will return a null pointer if the array's empty. @see getLast */ inline ObjectClass* getFirst() const throw() { const ScopedLockType lock (getLock()); return numUsed > 0 ? data.elements [0] : static_cast (0); } /** Returns a pointer to the last object in the array. This will return a null pointer if the array's empty. @see getFirst */ inline ObjectClass* getLast() const throw() { const ScopedLockType lock (getLock()); return numUsed > 0 ? data.elements [numUsed - 1] : static_cast (0); } /** Returns a pointer to the actual array data. This pointer will only be valid until the next time a non-const method is called on the array. */ inline ObjectClass** getRawDataPointer() throw() { return data.elements; } /** Finds the index of an object which might be in the array. @param objectToLookFor the object to look for @returns the index at which the object was found, or -1 if it's not found */ int indexOf (const ObjectClass* const objectToLookFor) const throw() { const ScopedLockType lock (getLock()); ObjectClass* const* e = data.elements.getData(); ObjectClass* const* const end = e + numUsed; while (e != end) { if (objectToLookFor == *e) return static_cast (e - data.elements.getData()); ++e; } return -1; } /** Returns true if the array contains a specified object. @param objectToLookFor the object to look for @returns true if the object is in the array */ bool contains (const ObjectClass* const objectToLookFor) const throw() { const ScopedLockType lock (getLock()); ObjectClass* const* e = data.elements.getData(); ObjectClass* const* const end = e + numUsed; while (e != end) { if (objectToLookFor == *e) return true; ++e; } return false; } /** Appends a new object to the end of the array. Note that the this object will be deleted by the OwnedArray when it is removed, so be careful not to delete it somewhere else. Also be careful not to add the same object to the array more than once, as this will obviously cause deletion of dangling pointers. @param newObject the new object to add to the array @see set, insert, addIfNotAlreadyThere, addSorted */ void add (const ObjectClass* const newObject) throw() { const ScopedLockType lock (getLock()); data.ensureAllocatedSize (numUsed + 1); data.elements [numUsed++] = const_cast (newObject); } /** Inserts a new object into the array at the given index. Note that the this object will be deleted by the OwnedArray when it is removed, so be careful not to delete it somewhere else. If the index is less than 0 or greater than the size of the array, the element will be added to the end of the array. Otherwise, it will be inserted into the array, moving all the later elements along to make room. Be careful not to add the same object to the array more than once, as this will obviously cause deletion of dangling pointers. @param indexToInsertAt the index at which the new element should be inserted @param newObject the new object to add to the array @see add, addSorted, addIfNotAlreadyThere, set */ void insert (int indexToInsertAt, const ObjectClass* const newObject) throw() { if (indexToInsertAt >= 0) { const ScopedLockType lock (getLock()); if (indexToInsertAt > numUsed) indexToInsertAt = numUsed; data.ensureAllocatedSize (numUsed + 1); ObjectClass** const e = data.elements + indexToInsertAt; const int numToMove = numUsed - indexToInsertAt; if (numToMove > 0) memmove (e + 1, e, numToMove * sizeof (ObjectClass*)); *e = const_cast (newObject); ++numUsed; } else { add (newObject); } } /** Appends a new object at the end of the array as long as the array doesn't already contain it. If the array already contains a matching object, nothing will be done. @param newObject the new object to add to the array */ void addIfNotAlreadyThere (const ObjectClass* const newObject) throw() { const ScopedLockType lock (getLock()); if (! contains (newObject)) add (newObject); } /** Replaces an object in the array with a different one. If the index is less than zero, this method does nothing. If the index is beyond the end of the array, the new object is added to the end of the array. Be careful not to add the same object to the array more than once, as this will obviously cause deletion of dangling pointers. @param indexToChange the index whose value you want to change @param newObject the new value to set for this index. @param deleteOldElement whether to delete the object that's being replaced with the new one @see add, insert, remove */ void set (const int indexToChange, const ObjectClass* const newObject, const bool deleteOldElement = true) { if (indexToChange >= 0) { ObjectClass* toDelete = 0; { const ScopedLockType lock (getLock()); if (indexToChange < numUsed) { if (deleteOldElement) { toDelete = data.elements [indexToChange]; if (toDelete == newObject) toDelete = 0; } data.elements [indexToChange] = const_cast (newObject); } else { data.ensureAllocatedSize (numUsed + 1); data.elements [numUsed++] = const_cast (newObject); } } delete toDelete; // don't want to use a ScopedPointer here because if the // object has a private destructor, both OwnedArray and // ScopedPointer would need to be friend classes.. } else { jassertfalse; // you're trying to set an object at a negative index, which doesn't have // any effect - but since the object is not being added, it may be leaking.. } } /** Adds elements from another array to the end of this array. @param arrayToAddFrom the array from which to copy the elements @param startIndex the first element of the other array to start copying from @param numElementsToAdd how many elements to add from the other array. If this value is negative or greater than the number of available elements, all available elements will be copied. @see add */ template void addArray (const OtherArrayType& arrayToAddFrom, int startIndex = 0, int numElementsToAdd = -1) { const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock()); const ScopedLockType lock2 (getLock()); if (startIndex < 0) { jassertfalse; startIndex = 0; } if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size()) numElementsToAdd = arrayToAddFrom.size() - startIndex; data.ensureAllocatedSize (numUsed + numElementsToAdd); while (--numElementsToAdd >= 0) { data.elements [numUsed] = arrayToAddFrom.getUnchecked (startIndex++); ++numUsed; } } /** Adds copies of the elements in another array to the end of this array. The other array must be either an OwnedArray of a compatible type of object, or an Array containing pointers to the same kind of object. The objects involved must provide a copy constructor, and this will be used to create new copies of each element, and add them to this array. @param arrayToAddFrom the array from which to copy the elements @param startIndex the first element of the other array to start copying from @param numElementsToAdd how many elements to add from the other array. If this value is negative or greater than the number of available elements, all available elements will be copied. @see add */ template void addCopiesOf (const OtherArrayType& arrayToAddFrom, int startIndex = 0, int numElementsToAdd = -1) { const typename OtherArrayType::ScopedLockType lock1 (arrayToAddFrom.getLock()); const ScopedLockType lock2 (getLock()); if (startIndex < 0) { jassertfalse; startIndex = 0; } if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size()) numElementsToAdd = arrayToAddFrom.size() - startIndex; data.ensureAllocatedSize (numUsed + numElementsToAdd); while (--numElementsToAdd >= 0) { data.elements [numUsed] = new ObjectClass (*arrayToAddFrom.getUnchecked (startIndex++)); ++numUsed; } } /** Inserts a new object into the array assuming that the array is sorted. This will use a comparator to find the position at which the new object should go. If the array isn't sorted, the behaviour of this method will be unpredictable. @param comparator the comparator to use to compare the elements - see the sort method for details about this object's structure @param newObject the new object to insert to the array @see add, sort, indexOfSorted */ template void addSorted (ElementComparator& comparator, ObjectClass* const newObject) throw() { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused const ScopedLockType lock (getLock()); insert (findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed), newObject); } /** Finds the index of an object in the array, assuming that the array is sorted. This will use a comparator to do a binary-chop to find the index of the given element, if it exists. If the array isn't sorted, the behaviour of this method will be unpredictable. @param comparator the comparator to use to compare the elements - see the sort() method for details about the form this object should take @param objectToLookFor the object to search for @returns the index of the element, or -1 if it's not found @see addSorted, sort */ template int indexOfSorted (ElementComparator& comparator, const ObjectClass* const objectToLookFor) const throw() { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused const ScopedLockType lock (getLock()); int start = 0; int end = numUsed; for (;;) { if (start >= end) { return -1; } else if (comparator.compareElements (objectToLookFor, data.elements [start]) == 0) { return start; } else { const int halfway = (start + end) >> 1; if (halfway == start) return -1; else if (comparator.compareElements (objectToLookFor, data.elements [halfway]) >= 0) start = halfway; else end = halfway; } } } /** Removes an object from the array. This will remove the object at a given index (optionally also deleting it) and move back all the subsequent objects to close the gap. If the index passed in is out-of-range, nothing will happen. @param indexToRemove the index of the element to remove @param deleteObject whether to delete the object that is removed @see removeObject, removeRange */ void remove (const int indexToRemove, const bool deleteObject = true) { ObjectClass* toDelete = 0; { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (indexToRemove, numUsed)) { ObjectClass** const e = data.elements + indexToRemove; if (deleteObject) toDelete = *e; --numUsed; const int numToShift = numUsed - indexToRemove; if (numToShift > 0) memmove (e, e + 1, numToShift * sizeof (ObjectClass*)); } } delete toDelete; // don't want to use a ScopedPointer here because if the // object has a private destructor, both OwnedArray and // ScopedPointer would need to be friend classes.. if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); } /** Removes and returns an object from the array without deleting it. This will remove the object at a given index and return it, moving back all the subsequent objects to close the gap. If the index passed in is out-of-range, nothing will happen. @param indexToRemove the index of the element to remove @see remove, removeObject, removeRange */ ObjectClass* removeAndReturn (const int indexToRemove) { ObjectClass* removedItem = 0; const ScopedLockType lock (getLock()); if (isPositiveAndBelow (indexToRemove, numUsed)) { ObjectClass** const e = data.elements + indexToRemove; removedItem = *e; --numUsed; const int numToShift = numUsed - indexToRemove; if (numToShift > 0) memmove (e, e + 1, numToShift * sizeof (ObjectClass*)); if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); } return removedItem; } /** Removes a specified object from the array. If the item isn't found, no action is taken. @param objectToRemove the object to try to remove @param deleteObject whether to delete the object (if it's found) @see remove, removeRange */ void removeObject (const ObjectClass* const objectToRemove, const bool deleteObject = true) { const ScopedLockType lock (getLock()); ObjectClass** e = data.elements.getData(); for (int i = numUsed; --i >= 0;) { if (objectToRemove == *e) { remove (static_cast (e - data.elements.getData()), deleteObject); break; } ++e; } } /** Removes a range of objects from the array. This will remove a set of objects, starting from the given index, and move any subsequent elements down to close the gap. If the range extends beyond the bounds of the array, it will be safely clipped to the size of the array. @param startIndex the index of the first object to remove @param numberToRemove how many objects should be removed @param deleteObjects whether to delete the objects that get removed @see remove, removeObject */ void removeRange (int startIndex, const int numberToRemove, const bool deleteObjects = true) { const ScopedLockType lock (getLock()); const int endIndex = jlimit (0, numUsed, startIndex + numberToRemove); startIndex = jlimit (0, numUsed, startIndex); if (endIndex > startIndex) { if (deleteObjects) { for (int i = startIndex; i < endIndex; ++i) { delete data.elements [i]; data.elements [i] = 0; // (in case one of the destructors accesses this array and hits a dangling pointer) } } const int rangeSize = endIndex - startIndex; ObjectClass** e = data.elements + startIndex; int numToShift = numUsed - endIndex; numUsed -= rangeSize; while (--numToShift >= 0) { *e = e [rangeSize]; ++e; } if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); } } /** Removes the last n objects from the array. @param howManyToRemove how many objects to remove from the end of the array @param deleteObjects whether to also delete the objects that are removed @see remove, removeObject, removeRange */ void removeLast (int howManyToRemove = 1, const bool deleteObjects = true) { const ScopedLockType lock (getLock()); if (howManyToRemove >= numUsed) clear (deleteObjects); else removeRange (numUsed - howManyToRemove, howManyToRemove, deleteObjects); } /** Swaps a pair of objects in the array. If either of the indexes passed in is out-of-range, nothing will happen, otherwise the two objects at these positions will be exchanged. */ void swap (const int index1, const int index2) throw() { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (index1, numUsed) && isPositiveAndBelow (index2, numUsed)) { swapVariables (data.elements [index1], data.elements [index2]); } } /** Moves one of the objects to a different position. This will move the object to a specified index, shuffling along any intervening elements as required. So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. @param currentIndex the index of the object to be moved. If this isn't a valid index, then nothing will be done @param newIndex the index at which you'd like this object to end up. If this is less than zero, it will be moved to the end of the array */ void move (const int currentIndex, int newIndex) throw() { if (currentIndex != newIndex) { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (currentIndex, numUsed)) { if (! isPositiveAndBelow (newIndex, numUsed)) newIndex = numUsed - 1; ObjectClass* const value = data.elements [currentIndex]; if (newIndex > currentIndex) { memmove (data.elements + currentIndex, data.elements + currentIndex + 1, (newIndex - currentIndex) * sizeof (ObjectClass*)); } else { memmove (data.elements + newIndex + 1, data.elements + newIndex, (currentIndex - newIndex) * sizeof (ObjectClass*)); } data.elements [newIndex] = value; } } } /** This swaps the contents of this array with those of another array. If you need to exchange two arrays, this is vastly quicker than using copy-by-value because it just swaps their internal pointers. */ void swapWithArray (OwnedArray& otherArray) throw() { const ScopedLockType lock1 (getLock()); const ScopedLockType lock2 (otherArray.getLock()); data.swapWith (otherArray.data); swapVariables (numUsed, otherArray.numUsed); } /** Reduces the amount of storage being used by the array. Arrays typically allocate slightly more storage than they need, and after removing elements, they may have quite a lot of unused space allocated. This method will reduce the amount of allocated storage to a minimum. */ void minimiseStorageOverheads() throw() { const ScopedLockType lock (getLock()); data.shrinkToNoMoreThan (numUsed); } /** Increases the array's internal storage to hold a minimum number of elements. Calling this before adding a large known number of elements means that the array won't have to keep dynamically resizing itself as the elements are added, and it'll therefore be more efficient. */ void ensureStorageAllocated (const int minNumElements) throw() { const ScopedLockType lock (getLock()); data.ensureAllocatedSize (minNumElements); } /** Sorts the elements in the array. This will use a comparator object to sort the elements into order. The object passed must have a method of the form: @code int compareElements (ElementType first, ElementType second); @endcode ..and this method must return: - a value of < 0 if the first comes before the second - a value of 0 if the two objects are equivalent - a value of > 0 if the second comes before the first To improve performance, the compareElements() method can be declared as static or const. @param comparator the comparator to use for comparing elements. @param retainOrderOfEquivalentItems if this is true, then items which the comparator says are equivalent will be kept in the order in which they currently appear in the array. This is slower to perform, but may be important in some cases. If it's false, a faster algorithm is used, but equivalent elements may be rearranged. @see sortArray, indexOfSorted */ template void sort (ElementComparator& comparator, const bool retainOrderOfEquivalentItems = false) const throw() { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused const ScopedLockType lock (getLock()); sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems); } /** Returns the CriticalSection that locks this array. To lock, you can call getLock().enter() and getLock().exit(), or preferably use an object of ScopedLockType as an RAII lock for it. */ inline const TypeOfCriticalSectionToUse& getLock() const throw() { return data; } /** Returns the type of scoped lock to use for locking this array */ typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; private: ArrayAllocationBase data; int numUsed; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray); }; #endif // __JUCE_OWNEDARRAY_JUCEHEADER__ /*** End of inlined file: juce_OwnedArray.h ***/ #endif #ifndef __JUCE_PROPERTYSET_JUCEHEADER__ /*** Start of inlined file: juce_PropertySet.h ***/ #ifndef __JUCE_PROPERTYSET_JUCEHEADER__ #define __JUCE_PROPERTYSET_JUCEHEADER__ /*** Start of inlined file: juce_StringPairArray.h ***/ #ifndef __JUCE_STRINGPAIRARRAY_JUCEHEADER__ #define __JUCE_STRINGPAIRARRAY_JUCEHEADER__ /*** Start of inlined file: juce_StringArray.h ***/ #ifndef __JUCE_STRINGARRAY_JUCEHEADER__ #define __JUCE_STRINGARRAY_JUCEHEADER__ /** A special array for holding a list of strings. @see String, StringPairArray */ class JUCE_API StringArray { public: /** Creates an empty string array */ StringArray() throw(); /** Creates a copy of another string array */ StringArray (const StringArray& other); /** Creates an array containing a single string. */ explicit StringArray (const String& firstValue); /** Creates a copy of an array of string literals. @param strings an array of strings to add. Null pointers in the array will be treated as empty strings @param numberOfStrings how many items there are in the array */ StringArray (const juce_wchar* const* strings, int numberOfStrings); /** Creates a copy of an array of string literals. @param strings an array of strings to add. Null pointers in the array will be treated as empty strings @param numberOfStrings how many items there are in the array */ StringArray (const char* const* strings, int numberOfStrings); /** Creates a copy of a null-terminated array of string literals. Each item from the array passed-in is added, until it encounters a null pointer, at which point it stops. */ explicit StringArray (const juce_wchar* const* strings); /** Creates a copy of a null-terminated array of string literals. Each item from the array passed-in is added, until it encounters a null pointer, at which point it stops. */ explicit StringArray (const char* const* strings); /** Destructor. */ ~StringArray(); /** Copies the contents of another string array into this one */ StringArray& operator= (const StringArray& other); /** Compares two arrays. Comparisons are case-sensitive. @returns true only if the other array contains exactly the same strings in the same order */ bool operator== (const StringArray& other) const throw(); /** Compares two arrays. Comparisons are case-sensitive. @returns false if the other array contains exactly the same strings in the same order */ bool operator!= (const StringArray& other) const throw(); /** Returns the number of strings in the array */ inline int size() const throw() { return strings.size(); }; /** Returns one of the strings from the array. If the index is out-of-range, an empty string is returned. Obviously the reference returned shouldn't be stored for later use, as the string it refers to may disappear when the array changes. */ const String& operator[] (int index) const throw(); /** Returns a reference to one of the strings in the array. This lets you modify a string in-place in the array, but you must be sure that the index is in-range. */ String& getReference (int index) throw(); /** Searches for a string in the array. The comparison will be case-insensitive if the ignoreCase parameter is true. @returns true if the string is found inside the array */ bool contains (const String& stringToLookFor, bool ignoreCase = false) const; /** Searches for a string in the array. The comparison will be case-insensitive if the ignoreCase parameter is true. @param stringToLookFor the string to try to find @param ignoreCase whether the comparison should be case-insensitive @param startIndex the first index to start searching from @returns the index of the first occurrence of the string in this array, or -1 if it isn't found. */ int indexOf (const String& stringToLookFor, bool ignoreCase = false, int startIndex = 0) const; /** Appends a string at the end of the array. */ void add (const String& stringToAdd); /** Inserts a string into the array. This will insert a string into the array at the given index, moving up the other elements to make room for it. If the index is less than zero or greater than the size of the array, the new string will be added to the end of the array. */ void insert (int index, const String& stringToAdd); /** Adds a string to the array as long as it's not already in there. The search can optionally be case-insensitive. */ void addIfNotAlreadyThere (const String& stringToAdd, bool ignoreCase = false); /** Replaces one of the strings in the array with another one. If the index is higher than the array's size, the new string will be added to the end of the array; if it's less than zero nothing happens. */ void set (int index, const String& newString); /** Appends some strings from another array to the end of this one. @param other the array to add @param startIndex the first element of the other array to add @param numElementsToAdd the maximum number of elements to add (if this is less than zero, they are all added) */ void addArray (const StringArray& other, int startIndex = 0, int numElementsToAdd = -1); /** Breaks up a string into tokens and adds them to this array. This will tokenise the given string using whitespace characters as the token delimiters, and will add these tokens to the end of the array. @returns the number of tokens added */ int addTokens (const String& stringToTokenise, bool preserveQuotedStrings); /** Breaks up a string into tokens and adds them to this array. This will tokenise the given string (using the string passed in to define the token delimiters), and will add these tokens to the end of the array. @param stringToTokenise the string to tokenise @param breakCharacters a string of characters, any of which will be considered to be a token delimiter. @param quoteCharacters if this string isn't empty, it defines a set of characters which are treated as quotes. Any text occurring between quotes is not broken up into tokens. @returns the number of tokens added */ int addTokens (const String& stringToTokenise, const String& breakCharacters, const String& quoteCharacters); /** Breaks up a string into lines and adds them to this array. This breaks a string down into lines separated by \\n or \\r\\n, and adds each line to the array. Line-break characters are omitted from the strings that are added to the array. */ int addLines (const String& stringToBreakUp); /** Removes all elements from the array. */ void clear(); /** Removes a string from the array. If the index is out-of-range, no action will be taken. */ void remove (int index); /** Finds a string in the array and removes it. This will remove the first occurrence of the given string from the array. The comparison may be case-insensitive depending on the ignoreCase parameter. */ void removeString (const String& stringToRemove, bool ignoreCase = false); /** Removes a range of elements from the array. This will remove a set of elements, starting from the given index, and move subsequent elements down to close the gap. If the range extends beyond the bounds of the array, it will be safely clipped to the size of the array. @param startIndex the index of the first element to remove @param numberToRemove how many elements should be removed */ void removeRange (int startIndex, int numberToRemove); /** Removes any duplicated elements from the array. If any string appears in the array more than once, only the first occurrence of it will be retained. @param ignoreCase whether to use a case-insensitive comparison */ void removeDuplicates (bool ignoreCase); /** Removes empty strings from the array. @param removeWhitespaceStrings if true, strings that only contain whitespace characters will also be removed */ void removeEmptyStrings (bool removeWhitespaceStrings = true); /** Moves one of the strings to a different position. This will move the string to a specified index, shuffling along any intervening elements as required. So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. @param currentIndex the index of the value to be moved. If this isn't a valid index, then nothing will be done @param newIndex the index at which you'd like this value to end up. If this is less than zero, the value will be moved to the end of the array */ void move (int currentIndex, int newIndex) throw(); /** Deletes any whitespace characters from the starts and ends of all the strings. */ void trim(); /** Adds numbers to the strings in the array, to make each string unique. This will add numbers to the ends of groups of similar strings. e.g. if there are two "moose" strings, they will become "moose (1)" and "moose (2)" @param ignoreCaseWhenComparing whether the comparison used is case-insensitive @param appendNumberToFirstInstance whether the first of a group of similar strings also has a number appended to it. @param preNumberString when adding a number, this string is added before the number. If you pass 0, a default string will be used, which adds brackets around the number. @param postNumberString this string is appended after any numbers that are added. If you pass 0, a default string will be used, which adds brackets around the number. */ void appendNumbersToDuplicates (bool ignoreCaseWhenComparing, bool appendNumberToFirstInstance, const juce_wchar* preNumberString = 0, const juce_wchar* postNumberString = 0); /** Joins the strings in the array together into one string. This will join a range of elements from the array into a string, separating them with a given string. e.g. joinIntoString (",") will turn an array of "a" "b" and "c" into "a,b,c". @param separatorString the string to insert between all the strings @param startIndex the first element to join @param numberOfElements how many elements to join together. If this is less than zero, all available elements will be used. */ const String joinIntoString (const String& separatorString, int startIndex = 0, int numberOfElements = -1) const; /** Sorts the array into alphabetical order. @param ignoreCase if true, the comparisons used will be case-sensitive. */ void sort (bool ignoreCase); /** Reduces the amount of storage being used by the array. Arrays typically allocate slightly more storage than they need, and after removing elements, they may have quite a lot of unused space allocated. This method will reduce the amount of allocated storage to a minimum. */ void minimiseStorageOverheads(); private: Array strings; JUCE_LEAK_DETECTOR (StringArray); }; #endif // __JUCE_STRINGARRAY_JUCEHEADER__ /*** End of inlined file: juce_StringArray.h ***/ /** A container for holding a set of strings which are keyed by another string. @see StringArray */ class JUCE_API StringPairArray { public: /** Creates an empty array */ StringPairArray (bool ignoreCaseWhenComparingKeys = true); /** Creates a copy of another array */ StringPairArray (const StringPairArray& other); /** Destructor. */ ~StringPairArray(); /** Copies the contents of another string array into this one */ StringPairArray& operator= (const StringPairArray& other); /** Compares two arrays. Comparisons are case-sensitive. @returns true only if the other array contains exactly the same strings with the same keys */ bool operator== (const StringPairArray& other) const; /** Compares two arrays. Comparisons are case-sensitive. @returns false if the other array contains exactly the same strings with the same keys */ bool operator!= (const StringPairArray& other) const; /** Finds the value corresponding to a key string. If no such key is found, this will just return an empty string. To check whether a given key actually exists (because it might actually be paired with an empty string), use the getAllKeys() method to obtain a list. Obviously the reference returned shouldn't be stored for later use, as the string it refers to may disappear when the array changes. @see getValue */ const String& operator[] (const String& key) const; /** Finds the value corresponding to a key string. If no such key is found, this will just return the value provided as a default. @see operator[] */ const String getValue (const String& key, const String& defaultReturnValue) const; /** Returns a list of all keys in the array. */ const StringArray& getAllKeys() const throw() { return keys; } /** Returns a list of all values in the array. */ const StringArray& getAllValues() const throw() { return values; } /** Returns the number of strings in the array */ inline int size() const throw() { return keys.size(); }; /** Adds or amends a key/value pair. If a value already exists with this key, its value will be overwritten, otherwise the key/value pair will be added to the array. */ void set (const String& key, const String& value); /** Adds the items from another array to this one. This is equivalent to using set() to add each of the pairs from the other array. */ void addArray (const StringPairArray& other); /** Removes all elements from the array. */ void clear(); /** Removes a string from the array based on its key. If the key isn't found, nothing will happen. */ void remove (const String& key); /** Removes a string from the array based on its index. If the index is out-of-range, no action will be taken. */ void remove (int index); /** Indicates whether to use a case-insensitive search when looking up a key string. */ void setIgnoresCase (bool shouldIgnoreCase); /** Returns a descriptive string containing the items. This is handy for dumping the contents of an array. */ const String getDescription() const; /** Reduces the amount of storage being used by the array. Arrays typically allocate slightly more storage than they need, and after removing elements, they may have quite a lot of unused space allocated. This method will reduce the amount of allocated storage to a minimum. */ void minimiseStorageOverheads(); private: StringArray keys, values; bool ignoreCase; JUCE_LEAK_DETECTOR (StringPairArray); }; #endif // __JUCE_STRINGPAIRARRAY_JUCEHEADER__ /*** End of inlined file: juce_StringPairArray.h ***/ /*** Start of inlined file: juce_XmlElement.h ***/ #ifndef __JUCE_XMLELEMENT_JUCEHEADER__ #define __JUCE_XMLELEMENT_JUCEHEADER__ /*** Start of inlined file: juce_File.h ***/ #ifndef __JUCE_FILE_JUCEHEADER__ #define __JUCE_FILE_JUCEHEADER__ /*** Start of inlined file: juce_Time.h ***/ #ifndef __JUCE_TIME_JUCEHEADER__ #define __JUCE_TIME_JUCEHEADER__ /*** Start of inlined file: juce_RelativeTime.h ***/ #ifndef __JUCE_RELATIVETIME_JUCEHEADER__ #define __JUCE_RELATIVETIME_JUCEHEADER__ /** A relative measure of time. The time is stored as a number of seconds, at double-precision floating point accuracy, and may be positive or negative. If you need an absolute time, (i.e. a date + time), see the Time class. */ class JUCE_API RelativeTime { public: /** Creates a RelativeTime. @param seconds the number of seconds, which may be +ve or -ve. @see milliseconds, minutes, hours, days, weeks */ explicit RelativeTime (double seconds = 0.0) throw(); /** Copies another relative time. */ RelativeTime (const RelativeTime& other) throw(); /** Copies another relative time. */ RelativeTime& operator= (const RelativeTime& other) throw(); /** Destructor. */ ~RelativeTime() throw(); /** Creates a new RelativeTime object representing a number of milliseconds. @see minutes, hours, days, weeks */ static const RelativeTime milliseconds (int milliseconds) throw(); /** Creates a new RelativeTime object representing a number of milliseconds. @see minutes, hours, days, weeks */ static const RelativeTime milliseconds (int64 milliseconds) throw(); /** Creates a new RelativeTime object representing a number of minutes. @see milliseconds, hours, days, weeks */ static const RelativeTime minutes (double numberOfMinutes) throw(); /** Creates a new RelativeTime object representing a number of hours. @see milliseconds, minutes, days, weeks */ static const RelativeTime hours (double numberOfHours) throw(); /** Creates a new RelativeTime object representing a number of days. @see milliseconds, minutes, hours, weeks */ static const RelativeTime days (double numberOfDays) throw(); /** Creates a new RelativeTime object representing a number of weeks. @see milliseconds, minutes, hours, days */ static const RelativeTime weeks (double numberOfWeeks) throw(); /** Returns the number of milliseconds this time represents. @see milliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks */ int64 inMilliseconds() const throw(); /** Returns the number of seconds this time represents. @see inMilliseconds, inMinutes, inHours, inDays, inWeeks */ double inSeconds() const throw() { return seconds; } /** Returns the number of minutes this time represents. @see inMilliseconds, inSeconds, inHours, inDays, inWeeks */ double inMinutes() const throw(); /** Returns the number of hours this time represents. @see inMilliseconds, inSeconds, inMinutes, inDays, inWeeks */ double inHours() const throw(); /** Returns the number of days this time represents. @see inMilliseconds, inSeconds, inMinutes, inHours, inWeeks */ double inDays() const throw(); /** Returns the number of weeks this time represents. @see inMilliseconds, inSeconds, inMinutes, inHours, inDays */ double inWeeks() const throw(); /** Returns a readable textual description of the time. The exact format of the string returned will depend on the magnitude of the time - e.g. "1 min 4 secs", "1 hr 45 mins", "2 weeks 5 days", "140 ms" so that only the two most significant units are printed. The returnValueForZeroTime value is the result that is returned if the length is zero. Depending on your application you might want to use this to return something more relevant like "empty" or "0 secs", etc. @see inMilliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks */ const String getDescription (const String& returnValueForZeroTime = "0") const; /** Adds another RelativeTime to this one. */ const RelativeTime& operator+= (const RelativeTime& timeToAdd) throw(); /** Subtracts another RelativeTime from this one. */ const RelativeTime& operator-= (const RelativeTime& timeToSubtract) throw(); /** Adds a number of seconds to this time. */ const RelativeTime& operator+= (double secondsToAdd) throw(); /** Subtracts a number of seconds from this time. */ const RelativeTime& operator-= (double secondsToSubtract) throw(); private: double seconds; }; /** Compares two RelativeTimes. */ bool operator== (const RelativeTime& t1, const RelativeTime& t2) throw(); /** Compares two RelativeTimes. */ bool operator!= (const RelativeTime& t1, const RelativeTime& t2) throw(); /** Compares two RelativeTimes. */ bool operator> (const RelativeTime& t1, const RelativeTime& t2) throw(); /** Compares two RelativeTimes. */ bool operator< (const RelativeTime& t1, const RelativeTime& t2) throw(); /** Compares two RelativeTimes. */ bool operator>= (const RelativeTime& t1, const RelativeTime& t2) throw(); /** Compares two RelativeTimes. */ bool operator<= (const RelativeTime& t1, const RelativeTime& t2) throw(); /** Adds two RelativeTimes together. */ const RelativeTime operator+ (const RelativeTime& t1, const RelativeTime& t2) throw(); /** Subtracts two RelativeTimes. */ const RelativeTime operator- (const RelativeTime& t1, const RelativeTime& t2) throw(); #endif // __JUCE_RELATIVETIME_JUCEHEADER__ /*** End of inlined file: juce_RelativeTime.h ***/ /** Holds an absolute date and time. Internally, the time is stored at millisecond precision. @see RelativeTime */ class JUCE_API Time { public: /** Creates a Time object. This default constructor creates a time of 1st January 1970, (which is represented internally as 0ms). To create a time object representing the current time, use getCurrentTime(). @see getCurrentTime */ Time() throw(); /** Creates a time based on a number of milliseconds. The internal millisecond count is set to 0 (1st January 1970). To create a time object set to the current time, use getCurrentTime(). @param millisecondsSinceEpoch the number of milliseconds since the unix 'epoch' (midnight Jan 1st 1970). @see getCurrentTime, currentTimeMillis */ explicit Time (int64 millisecondsSinceEpoch) throw(); /** Creates a time from a set of date components. The timezone is assumed to be whatever the system is using as its locale. @param year the year, in 4-digit format, e.g. 2004 @param month the month, in the range 0 to 11 @param day the day of the month, in the range 1 to 31 @param hours hours in 24-hour clock format, 0 to 23 @param minutes minutes 0 to 59 @param seconds seconds 0 to 59 @param milliseconds milliseconds 0 to 999 @param useLocalTime if true, encode using the current machine's local time; if false, it will always work in GMT. */ Time (int year, int month, int day, int hours, int minutes, int seconds = 0, int milliseconds = 0, bool useLocalTime = true) throw(); /** Creates a copy of another Time object. */ Time (const Time& other) throw(); /** Destructor. */ ~Time() throw(); /** Copies this time from another one. */ Time& operator= (const Time& other) throw(); /** Returns a Time object that is set to the current system time. @see currentTimeMillis */ static const Time JUCE_CALLTYPE getCurrentTime() throw(); /** Returns the time as a number of milliseconds. @returns the number of milliseconds this Time object represents, since midnight jan 1st 1970. @see getMilliseconds */ int64 toMilliseconds() const throw() { return millisSinceEpoch; } /** Returns the year. A 4-digit format is used, e.g. 2004. */ int getYear() const throw(); /** Returns the number of the month. The value returned is in the range 0 to 11. @see getMonthName */ int getMonth() const throw(); /** Returns the name of the month. @param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false it'll return the long form, e.g. "January" @see getMonth */ const String getMonthName (bool threeLetterVersion) const; /** Returns the day of the month. The value returned is in the range 1 to 31. */ int getDayOfMonth() const throw(); /** Returns the number of the day of the week. The value returned is in the range 0 to 6 (0 = sunday, 1 = monday, etc). */ int getDayOfWeek() const throw(); /** Returns the name of the weekday. @param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if false, it'll return the full version, e.g. "Tuesday". */ const String getWeekdayName (bool threeLetterVersion) const; /** Returns the number of hours since midnight. This is in 24-hour clock format, in the range 0 to 23. @see getHoursInAmPmFormat, isAfternoon */ int getHours() const throw(); /** Returns true if the time is in the afternoon. So it returns true for "PM", false for "AM". @see getHoursInAmPmFormat, getHours */ bool isAfternoon() const throw(); /** Returns the hours in 12-hour clock format. This will return a value 1 to 12 - use isAfternoon() to find out whether this is in the afternoon or morning. @see getHours, isAfternoon */ int getHoursInAmPmFormat() const throw(); /** Returns the number of minutes, 0 to 59. */ int getMinutes() const throw(); /** Returns the number of seconds, 0 to 59. */ int getSeconds() const throw(); /** Returns the number of milliseconds, 0 to 999. Unlike toMilliseconds(), this just returns the position within the current second rather than the total number since the epoch. @see toMilliseconds */ int getMilliseconds() const throw(); /** Returns true if the local timezone uses a daylight saving correction. */ bool isDaylightSavingTime() const throw(); /** Returns a 3-character string to indicate the local timezone. */ const String getTimeZone() const throw(); /** Quick way of getting a string version of a date and time. For a more powerful way of formatting the date and time, see the formatted() method. @param includeDate whether to include the date in the string @param includeTime whether to include the time in the string @param includeSeconds if the time is being included, this provides an option not to include the seconds in it @param use24HourClock if the time is being included, sets whether to use am/pm or 24 hour notation. @see formatted */ const String toString (bool includeDate, bool includeTime, bool includeSeconds = true, bool use24HourClock = false) const throw(); /** Converts this date/time to a string with a user-defined format. This uses the C strftime() function to format this time as a string. To save you looking it up, these are the escape codes that strftime uses (other codes might work on some platforms and not others, but these are the common ones): %a is replaced by the locale's abbreviated weekday name. %A is replaced by the locale's full weekday name. %b is replaced by the locale's abbreviated month name. %B is replaced by the locale's full month name. %c is replaced by the locale's appropriate date and time representation. %d is replaced by the day of the month as a decimal number [01,31]. %H is replaced by the hour (24-hour clock) as a decimal number [00,23]. %I is replaced by the hour (12-hour clock) as a decimal number [01,12]. %j is replaced by the day of the year as a decimal number [001,366]. %m is replaced by the month as a decimal number [01,12]. %M is replaced by the minute as a decimal number [00,59]. %p is replaced by the locale's equivalent of either a.m. or p.m. %S is replaced by the second as a decimal number [00,61]. %U is replaced by the week number of the year (Sunday as the first day of the week) as a decimal number [00,53]. %w is replaced by the weekday as a decimal number [0,6], with 0 representing Sunday. %W is replaced by the week number of the year (Monday as the first day of the week) as a decimal number [00,53]. All days in a new year preceding the first Monday are considered to be in week 0. %x is replaced by the locale's appropriate date representation. %X is replaced by the locale's appropriate time representation. %y is replaced by the year without century as a decimal number [00,99]. %Y is replaced by the year with century as a decimal number. %Z is replaced by the timezone name or abbreviation, or by no bytes if no timezone information exists. %% is replaced by %. @see toString */ const String formatted (const String& format) const; /** Adds a RelativeTime to this time. */ Time& operator+= (const RelativeTime& delta); /** Subtracts a RelativeTime from this time. */ Time& operator-= (const RelativeTime& delta); /** Tries to set the computer's clock. @returns true if this succeeds, although depending on the system, the application might not have sufficient privileges to do this. */ bool setSystemTimeToThisTime() const; /** Returns the name of a day of the week. @param dayNumber the day, 0 to 6 (0 = sunday, 1 = monday, etc) @param threeLetterVersion if true, it'll return a 3-letter abbreviation, e.g. "Tue"; if false, it'll return the full version, e.g. "Tuesday". */ static const String getWeekdayName (int dayNumber, bool threeLetterVersion); /** Returns the name of one of the months. @param monthNumber the month, 0 to 11 @param threeLetterVersion if true, it'll be a 3-letter abbreviation, e.g. "Jan"; if false it'll return the long form, e.g. "January" */ static const String getMonthName (int monthNumber, bool threeLetterVersion); // Static methods for getting system timers directly.. /** Returns the current system time. Returns the number of milliseconds since midnight jan 1st 1970. Should be accurate to within a few millisecs, depending on platform, hardware, etc. */ static int64 currentTimeMillis() throw(); /** Returns the number of millisecs since a fixed event (usually system startup). This returns a monotonically increasing value which it unaffected by changes to the system clock. It should be accurate to within a few millisecs, depending on platform, hardware, etc. @see getApproximateMillisecondCounter */ static uint32 getMillisecondCounter() throw(); /** Returns the number of millisecs since a fixed event (usually system startup). This has the same function as getMillisecondCounter(), but returns a more accurate value, using a higher-resolution timer if one is available. @see getMillisecondCounter */ static double getMillisecondCounterHiRes() throw(); /** Waits until the getMillisecondCounter() reaches a given value. This will make the thread sleep as efficiently as it can while it's waiting. */ static void waitForMillisecondCounter (uint32 targetTime) throw(); /** Less-accurate but faster version of getMillisecondCounter(). This will return the last value that getMillisecondCounter() returned, so doesn't need to make a system call, but is less accurate - it shouldn't be more than 100ms away from the correct time, though, so is still accurate enough for a lot of purposes. @see getMillisecondCounter */ static uint32 getApproximateMillisecondCounter() throw(); // High-resolution timers.. /** Returns the current high-resolution counter's tick-count. This is a similar idea to getMillisecondCounter(), but with a higher resolution. @see getHighResolutionTicksPerSecond, highResolutionTicksToSeconds, secondsToHighResolutionTicks */ static int64 getHighResolutionTicks() throw(); /** Returns the resolution of the high-resolution counter in ticks per second. @see getHighResolutionTicks, highResolutionTicksToSeconds, secondsToHighResolutionTicks */ static int64 getHighResolutionTicksPerSecond() throw(); /** Converts a number of high-resolution ticks into seconds. @see getHighResolutionTicks, getHighResolutionTicksPerSecond, secondsToHighResolutionTicks */ static double highResolutionTicksToSeconds (int64 ticks) throw(); /** Converts a number seconds into high-resolution ticks. @see getHighResolutionTicks, getHighResolutionTicksPerSecond, highResolutionTicksToSeconds */ static int64 secondsToHighResolutionTicks (double seconds) throw(); private: int64 millisSinceEpoch; }; /** Adds a RelativeTime to a Time. */ const Time operator+ (const Time& time, const RelativeTime& delta); /** Adds a RelativeTime to a Time. */ const Time operator+ (const RelativeTime& delta, const Time& time); /** Subtracts a RelativeTime from a Time. */ const Time operator- (const Time& time, const RelativeTime& delta); /** Returns the relative time difference between two times. */ const RelativeTime operator- (const Time& time1, const Time& time2); /** Compares two Time objects. */ bool operator== (const Time& time1, const Time& time2); /** Compares two Time objects. */ bool operator!= (const Time& time1, const Time& time2); /** Compares two Time objects. */ bool operator< (const Time& time1, const Time& time2); /** Compares two Time objects. */ bool operator<= (const Time& time1, const Time& time2); /** Compares two Time objects. */ bool operator> (const Time& time1, const Time& time2); /** Compares two Time objects. */ bool operator>= (const Time& time1, const Time& time2); #endif // __JUCE_TIME_JUCEHEADER__ /*** End of inlined file: juce_Time.h ***/ /*** Start of inlined file: juce_ScopedPointer.h ***/ #ifndef __JUCE_SCOPEDPOINTER_JUCEHEADER__ #define __JUCE_SCOPEDPOINTER_JUCEHEADER__ /** This class holds a pointer which is automatically deleted when this object goes out of scope. Once a pointer has been passed to a ScopedPointer, it will make sure that the pointer gets deleted when the ScopedPointer is deleted. Using the ScopedPointer on the stack or as member variables is a good way to use RAII to avoid accidentally leaking dynamically created objects. A ScopedPointer can be used in pretty much the same way that you'd use a normal pointer to an object. If you use the assignment operator to assign a different object to a ScopedPointer, the old one will be automatically deleted. A const ScopedPointer is guaranteed not to lose ownership of its object or change the object to which it points during its lifetime. This means that making a copy of a const ScopedPointer is impossible, as that would involve the new copy taking ownership from the old one. If you need to get a pointer out of a ScopedPointer without it being deleted, you can use the release() method. */ template class ScopedPointer { public: /** Creates a ScopedPointer containing a null pointer. */ inline ScopedPointer() throw() : object (0) { } /** Creates a ScopedPointer that owns the specified object. */ inline ScopedPointer (ObjectType* const objectToTakePossessionOf) throw() : object (objectToTakePossessionOf) { } /** Creates a ScopedPointer that takes its pointer from another ScopedPointer. Because a pointer can only belong to one ScopedPointer, this transfers the pointer from the other object to this one, and the other object is reset to be a null pointer. */ ScopedPointer (ScopedPointer& objectToTransferFrom) throw() : object (objectToTransferFrom.object) { objectToTransferFrom.object = 0; } /** Destructor. This will delete the object that this ScopedPointer currently refers to. */ inline ~ScopedPointer() { delete object; } /** Changes this ScopedPointer to point to a new object. Because a pointer can only belong to one ScopedPointer, this transfers the pointer from the other object to this one, and the other object is reset to be a null pointer. If this ScopedPointer already points to an object, that object will first be deleted. */ ScopedPointer& operator= (ScopedPointer& objectToTransferFrom) { if (this != objectToTransferFrom.getAddress()) { // Two ScopedPointers should never be able to refer to the same object - if // this happens, you must have done something dodgy! jassert (object == 0 || object != objectToTransferFrom.object); ObjectType* const oldObject = object; object = objectToTransferFrom.object; objectToTransferFrom.object = 0; delete oldObject; } return *this; } /** Changes this ScopedPointer to point to a new object. If this ScopedPointer already points to an object, that object will first be deleted. The pointer that you pass is may be null. */ ScopedPointer& operator= (ObjectType* const newObjectToTakePossessionOf) { if (object != newObjectToTakePossessionOf) { ObjectType* const oldObject = object; object = newObjectToTakePossessionOf; delete oldObject; } return *this; } /** Returns the object that this ScopedPointer refers to. */ inline operator ObjectType*() const throw() { return object; } /** Returns the object that this ScopedPointer refers to. */ inline ObjectType& operator*() const throw() { return *object; } /** Lets you access methods and properties of the object that this ScopedPointer refers to. */ inline ObjectType* operator->() const throw() { return object; } /** Removes the current object from this ScopedPointer without deleting it. This will return the current object, and set the ScopedPointer to a null pointer. */ ObjectType* release() throw() { ObjectType* const o = object; object = 0; return o; } /** Swaps this object with that of another ScopedPointer. The two objects simply exchange their pointers. */ void swapWith (ScopedPointer & other) throw() { // Two ScopedPointers should never be able to refer to the same object - if // this happens, you must have done something dodgy! jassert (object != other.object); swapVariables (object, other.object); } private: ObjectType* object; // (Required as an alternative to the overloaded & operator). const ScopedPointer* getAddress() const throw() { return this; } #if ! JUCE_MSVC // (MSVC can't deal with multiple copy constructors) /* This is private to stop people accidentally copying a const ScopedPointer (the compiler would let you do so by implicitly casting the source to its raw object pointer). A side effect of this is that you may hit a puzzling compiler error when you write something like this: ScopedPointer m = new MyClass(); // Compile error: copy constructor is private. Even though the compiler would normally ignore the assignment here, it can't do so when the copy constructor is private. It's very easy to fis though - just write it like this: ScopedPointer m (new MyClass()); // Compiles OK It's good practice to always use the latter form when writing your object declarations anyway, rather than writing them as assignments and assuming (or hoping) that the compiler will be smart enough to replace your construction + assignment with a single constructor. */ ScopedPointer (const ScopedPointer&); #endif }; /** Compares a ScopedPointer with another pointer. This can be handy for checking whether this is a null pointer. */ template bool operator== (const ScopedPointer& pointer1, ObjectType* const pointer2) throw() { return static_cast (pointer1) == pointer2; } /** Compares a ScopedPointer with another pointer. This can be handy for checking whether this is a null pointer. */ template bool operator!= (const ScopedPointer& pointer1, ObjectType* const pointer2) throw() { return static_cast (pointer1) != pointer2; } #endif // __JUCE_SCOPEDPOINTER_JUCEHEADER__ /*** End of inlined file: juce_ScopedPointer.h ***/ class FileInputStream; class FileOutputStream; /** Represents a local file or directory. This class encapsulates the absolute pathname of a file or directory, and has methods for finding out about the file and changing its properties. To read or write to the file, there are methods for returning an input or output stream. @see FileInputStream, FileOutputStream */ class JUCE_API File { public: /** Creates an (invalid) file object. The file is initially set to an empty path, so getFullPath() will return an empty string, and comparing the file to File::nonexistent will return true. You can use its operator= method to point it at a proper file. */ File() {} /** Creates a file from an absolute path. If the path supplied is a relative path, it is taken to be relative to the current working directory (see File::getCurrentWorkingDirectory()), but this isn't a recommended way of creating a file, because you never know what the CWD is going to be. On the Mac/Linux, the path can include "~" notation for referring to user home directories. */ File (const String& path); /** Creates a copy of another file object. */ File (const File& other); /** Destructor. */ ~File() {} /** Sets the file based on an absolute pathname. If the path supplied is a relative path, it is taken to be relative to the current working directory (see File::getCurrentWorkingDirectory()), but this isn't a recommended way of creating a file, because you never know what the CWD is going to be. On the Mac/Linux, the path can include "~" notation for referring to user home directories. */ File& operator= (const String& newFilePath); /** Copies from another file object. */ File& operator= (const File& otherFile); /** This static constant is used for referring to an 'invalid' file. */ static const File nonexistent; /** Checks whether the file actually exists. @returns true if the file exists, either as a file or a directory. @see existsAsFile, isDirectory */ bool exists() const; /** Checks whether the file exists and is a file rather than a directory. @returns true only if this is a real file, false if it's a directory or doesn't exist @see exists, isDirectory */ bool existsAsFile() const; /** Checks whether the file is a directory that exists. @returns true only if the file is a directory which actually exists, so false if it's a file or doesn't exist at all @see exists, existsAsFile */ bool isDirectory() const; /** Returns the size of the file in bytes. @returns the number of bytes in the file, or 0 if it doesn't exist. */ int64 getSize() const; /** Utility function to convert a file size in bytes to a neat string description. So for example 100 would return "100 bytes", 2000 would return "2 KB", 2000000 would produce "2 MB", etc. */ static const String descriptionOfSizeInBytes (int64 bytes); /** Returns the complete, absolute path of this file. This includes the filename and all its parent folders. On Windows it'll also include the drive letter prefix; on Mac or Linux it'll be a complete path starting from the root folder. If you just want the file's name, you should use getFileName() or getFileNameWithoutExtension(). @see getFileName, getRelativePathFrom */ const String& getFullPathName() const throw() { return fullPath; } /** Returns the last section of the pathname. Returns just the final part of the path - e.g. if the whole path is "/moose/fish/foo.txt" this will return "foo.txt". For a directory, it returns the final part of the path - e.g. for the directory "/moose/fish" it'll return "fish". If the filename begins with a dot, it'll return the whole filename, e.g. for "/moose/.fish", it'll return ".fish" @see getFullPathName, getFileNameWithoutExtension */ const String getFileName() const; /** Creates a relative path that refers to a file relatively to a given directory. e.g. File ("/moose/foo.txt").getRelativePathFrom ("/moose/fish/haddock") would return "../../foo.txt". If it's not possible to navigate from one file to the other, an absolute path is returned. If the paths are invalid, an empty string may also be returned. @param directoryToBeRelativeTo the directory which the resultant string will be relative to. If this is actually a file rather than a directory, its parent directory will be used instead. If it doesn't exist, it's assumed to be a directory. @see getChildFile, isAbsolutePath */ const String getRelativePathFrom (const File& directoryToBeRelativeTo) const; /** Returns the file's extension. Returns the file extension of this file, also including the dot. e.g. "/moose/fish/foo.txt" would return ".txt" @see hasFileExtension, withFileExtension, getFileNameWithoutExtension */ const String getFileExtension() const; /** Checks whether the file has a given extension. @param extensionToTest the extension to look for - it doesn't matter whether or not this string has a dot at the start, so ".wav" and "wav" will have the same effect. The comparison used is case-insensitve. To compare with multiple extensions, this parameter can contain multiple strings, separated by semi-colons - so, for example: hasFileExtension (".jpeg;png;gif") would return true if the file has any of those three extensions. @see getFileExtension, withFileExtension, getFileNameWithoutExtension */ bool hasFileExtension (const String& extensionToTest) const; /** Returns a version of this file with a different file extension. e.g. File ("/moose/fish/foo.txt").withFileExtension ("html") returns "/moose/fish/foo.html" @param newExtension the new extension, either with or without a dot at the start (this doesn't make any difference). To get remove a file's extension altogether, pass an empty string into this function. @see getFileName, getFileExtension, hasFileExtension, getFileNameWithoutExtension */ const File withFileExtension (const String& newExtension) const; /** Returns the last part of the filename, without its file extension. e.g. for "/moose/fish/foo.txt" this will return "foo". @see getFileName, getFileExtension, hasFileExtension, withFileExtension */ const String getFileNameWithoutExtension() const; /** Returns a 32-bit hash-code that identifies this file. This is based on the filename. Obviously it's possible, although unlikely, that two files will have the same hash-code. */ int hashCode() const; /** Returns a 64-bit hash-code that identifies this file. This is based on the filename. Obviously it's possible, although unlikely, that two files will have the same hash-code. */ int64 hashCode64() const; /** Returns a file based on a relative path. This will find a child file or directory of the current object. e.g. File ("/moose/fish").getChildFile ("foo.txt") will produce "/moose/fish/foo.txt". File ("/moose/fish").getChildFile ("../foo.txt") will produce "/moose/foo.txt". If the string is actually an absolute path, it will be treated as such, e.g. File ("/moose/fish").getChildFile ("/foo.txt") will produce "/foo.txt" @see getSiblingFile, getParentDirectory, getRelativePathFrom, isAChildOf */ const File getChildFile (String relativePath) const; /** Returns a file which is in the same directory as this one. This is equivalent to getParentDirectory().getChildFile (name). @see getChildFile, getParentDirectory */ const File getSiblingFile (const String& siblingFileName) const; /** Returns the directory that contains this file or directory. e.g. for "/moose/fish/foo.txt" this will return "/moose/fish". */ const File getParentDirectory() const; /** Checks whether a file is somewhere inside a directory. Returns true if this file is somewhere inside a subdirectory of the directory that is passed in. Neither file actually has to exist, because the function just checks the paths for similarities. e.g. File ("/moose/fish/foo.txt").isAChildOf ("/moose") is true. File ("/moose/fish/foo.txt").isAChildOf ("/moose/fish") is also true. */ bool isAChildOf (const File& potentialParentDirectory) const; /** Chooses a filename relative to this one that doesn't already exist. If this file is a directory, this will return a child file of this directory that doesn't exist, by adding numbers to a prefix and suffix until it finds one that isn't already there. If the prefix + the suffix doesn't exist, it won't bother adding a number. e.g. File ("/moose/fish").getNonexistentChildFile ("foo", ".txt", true) might return "/moose/fish/foo(2).txt" if there's already a file called "foo.txt". @param prefix the string to use for the filename before the number @param suffix the string to add to the filename after the number @param putNumbersInBrackets if true, this will create filenames in the format "prefix(number)suffix", if false, it will leave the brackets out. */ const File getNonexistentChildFile (const String& prefix, const String& suffix, bool putNumbersInBrackets = true) const; /** Chooses a filename for a sibling file to this one that doesn't already exist. If this file doesn't exist, this will just return itself, otherwise it will return an appropriate sibling that doesn't exist, e.g. if a file "/moose/fish/foo.txt" exists, this might return "/moose/fish/foo(2).txt". @param putNumbersInBrackets whether to add brackets around the numbers that get appended to the new filename. */ const File getNonexistentSibling (bool putNumbersInBrackets = true) const; /** Compares the pathnames for two files. */ bool operator== (const File& otherFile) const; /** Compares the pathnames for two files. */ bool operator!= (const File& otherFile) const; /** Compares the pathnames for two files. */ bool operator< (const File& otherFile) const; /** Compares the pathnames for two files. */ bool operator> (const File& otherFile) const; /** Checks whether a file can be created or written to. @returns true if it's possible to create and write to this file. If the file doesn't already exist, this will check its parent directory to see if writing is allowed. @see setReadOnly */ bool hasWriteAccess() const; /** Changes the write-permission of a file or directory. @param shouldBeReadOnly whether to add or remove write-permission @param applyRecursively if the file is a directory and this is true, it will recurse through all the subfolders changing the permissions of all files @returns true if it manages to change the file's permissions. @see hasWriteAccess */ bool setReadOnly (bool shouldBeReadOnly, bool applyRecursively = false) const; /** Returns true if this file is a hidden or system file. The criteria for deciding whether a file is hidden are platform-dependent. */ bool isHidden() const; /** If this file is a link, this returns the file that it points to. If this file isn't actually link, it'll just return itself. */ const File getLinkedTarget() const; /** Returns the last modification time of this file. @returns the time, or an invalid time if the file doesn't exist. @see setLastModificationTime, getLastAccessTime, getCreationTime */ const Time getLastModificationTime() const; /** Returns the last time this file was accessed. @returns the time, or an invalid time if the file doesn't exist. @see setLastAccessTime, getLastModificationTime, getCreationTime */ const Time getLastAccessTime() const; /** Returns the time that this file was created. @returns the time, or an invalid time if the file doesn't exist. @see getLastModificationTime, getLastAccessTime */ const Time getCreationTime() const; /** Changes the modification time for this file. @param newTime the time to apply to the file @returns true if it manages to change the file's time. @see getLastModificationTime, setLastAccessTime, setCreationTime */ bool setLastModificationTime (const Time& newTime) const; /** Changes the last-access time for this file. @param newTime the time to apply to the file @returns true if it manages to change the file's time. @see getLastAccessTime, setLastModificationTime, setCreationTime */ bool setLastAccessTime (const Time& newTime) const; /** Changes the creation date for this file. @param newTime the time to apply to the file @returns true if it manages to change the file's time. @see getCreationTime, setLastModificationTime, setLastAccessTime */ bool setCreationTime (const Time& newTime) const; /** If possible, this will try to create a version string for the given file. The OS may be able to look at the file and give a version for it - e.g. with executables, bundles, dlls, etc. If no version is available, this will return an empty string. */ const String getVersion() const; /** Creates an empty file if it doesn't already exist. If the file that this object refers to doesn't exist, this will create a file of zero size. If it already exists or is a directory, this method will do nothing. @returns true if the file has been created (or if it already existed). @see createDirectory */ bool create() const; /** Creates a new directory for this filename. This will try to create the file as a directory, and fill also create any parent directories it needs in order to complete the operation. @returns true if the directory has been created successfully, (or if it already existed beforehand). @see create */ bool createDirectory() const; /** Deletes a file. If this file is actually a directory, it may not be deleted correctly if it contains files. See deleteRecursively() as a better way of deleting directories. @returns true if the file has been successfully deleted (or if it didn't exist to begin with). @see deleteRecursively */ bool deleteFile() const; /** Deletes a file or directory and all its subdirectories. If this file is a directory, this will try to delete it and all its subfolders. If it's just a file, it will just try to delete the file. @returns true if the file and all its subfolders have been successfully deleted (or if it didn't exist to begin with). @see deleteFile */ bool deleteRecursively() const; /** Moves this file or folder to the trash. @returns true if the operation succeeded. It could fail if the trash is full, or if the file is write-protected, so you should check the return value and act appropriately. */ bool moveToTrash() const; /** Moves or renames a file. Tries to move a file to a different location. If the target file already exists, this will attempt to delete it first, and will fail if this can't be done. Note that the destination file isn't the directory to put it in, it's the actual filename that you want the new file to have. @returns true if the operation succeeds */ bool moveFileTo (const File& targetLocation) const; /** Copies a file. Tries to copy a file to a different location. If the target file already exists, this will attempt to delete it first, and will fail if this can't be done. @returns true if the operation succeeds */ bool copyFileTo (const File& targetLocation) const; /** Copies a directory. Tries to copy an entire directory, recursively. If this file isn't a directory or if any target files can't be created, this will return false. @param newDirectory the directory that this one should be copied to. Note that this is the name of the actual directory to create, not the directory into which the new one should be placed, so there must be enough write privileges to create it if it doesn't exist. Any files inside it will be overwritten by similarly named ones that are copied. */ bool copyDirectoryTo (const File& newDirectory) const; /** Used in file searching, to specify whether to return files, directories, or both. */ enum TypesOfFileToFind { findDirectories = 1, /**< Use this flag to indicate that you want to find directories. */ findFiles = 2, /**< Use this flag to indicate that you want to find files. */ findFilesAndDirectories = 3, /**< Use this flag to indicate that you want to find both files and directories. */ ignoreHiddenFiles = 4 /**< Add this flag to avoid returning any hidden files in the results. */ }; /** Searches inside a directory for files matching a wildcard pattern. Assuming that this file is a directory, this method will search it for either files or subdirectories whose names match a filename pattern. @param results an array to which File objects will be added for the files that the search comes up with @param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to return files, directories, or both. If the ignoreHiddenFiles flag is also added to this value, hidden files won't be returned @param searchRecursively if true, all subdirectories will be recursed into to do an exhaustive search @param wildCardPattern the filename pattern to search for, e.g. "*.txt" @returns the number of results that have been found @see getNumberOfChildFiles, DirectoryIterator */ int findChildFiles (Array& results, int whatToLookFor, bool searchRecursively, const String& wildCardPattern = "*") const; /** Searches inside a directory and counts how many files match a wildcard pattern. Assuming that this file is a directory, this method will search it for either files or subdirectories whose names match a filename pattern, and will return the number of matches found. This isn't a recursive call, and will only search this directory, not its children. @param whatToLookFor a value from the TypesOfFileToFind enum, specifying whether to count files, directories, or both. If the ignoreHiddenFiles flag is also added to this value, hidden files won't be counted @param wildCardPattern the filename pattern to search for, e.g. "*.txt" @returns the number of matches found @see findChildFiles, DirectoryIterator */ int getNumberOfChildFiles (int whatToLookFor, const String& wildCardPattern = "*") const; /** Returns true if this file is a directory that contains one or more subdirectories. @see isDirectory, findChildFiles */ bool containsSubDirectories() const; /** Creates a stream to read from this file. @returns a stream that will read from this file (initially positioned at the start of the file), or 0 if the file can't be opened for some reason @see createOutputStream, loadFileAsData */ FileInputStream* createInputStream() const; /** Creates a stream to write to this file. If the file exists, the stream that is returned will be positioned ready for writing at the end of the file, so you might want to use deleteFile() first to write to an empty file. @returns a stream that will write to this file (initially positioned at the end of the file), or 0 if the file can't be opened for some reason @see createInputStream, appendData, appendText */ FileOutputStream* createOutputStream (int bufferSize = 0x8000) const; /** Loads a file's contents into memory as a block of binary data. Of course, trying to load a very large file into memory will blow up, so it's better to check first. @param result the data block to which the file's contents should be appended - note that if the memory block might already contain some data, you might want to clear it first @returns true if the file could all be read into memory */ bool loadFileAsData (MemoryBlock& result) const; /** Reads a file into memory as a string. Attempts to load the entire file as a zero-terminated string. This makes use of InputStream::readEntireStreamAsString, which should automatically cope with unicode/acsii file formats. */ const String loadFileAsString() const; /** Appends a block of binary data to the end of the file. This will try to write the given buffer to the end of the file. @returns false if it can't write to the file for some reason */ bool appendData (const void* dataToAppend, int numberOfBytes) const; /** Replaces this file's contents with a given block of data. This will delete the file and replace it with the given data. A nice feature of this method is that it's safe - instead of deleting the file first and then re-writing it, it creates a new temporary file, writes the data to that, and then moves the new file to replace the existing file. This means that if the power gets pulled out or something crashes, you're a lot less likely to end up with a corrupted or unfinished file.. Returns true if the operation succeeds, or false if it fails. @see appendText */ bool replaceWithData (const void* dataToWrite, int numberOfBytes) const; /** Appends a string to the end of the file. This will try to append a text string to the file, as either 16-bit unicode or 8-bit characters in the default system encoding. It can also write the 'ff fe' unicode header bytes before the text to indicate the endianness of the file. Any single \\n characters in the string are replaced with \\r\\n before it is written. @see replaceWithText */ bool appendText (const String& textToAppend, bool asUnicode = false, bool writeUnicodeHeaderBytes = false) const; /** Replaces this file's contents with a given text string. This will delete the file and replace it with the given text. A nice feature of this method is that it's safe - instead of deleting the file first and then re-writing it, it creates a new temporary file, writes the text to that, and then moves the new file to replace the existing file. This means that if the power gets pulled out or something crashes, you're a lot less likely to end up with an empty file.. For an explanation of the parameters here, see the appendText() method. Returns true if the operation succeeds, or false if it fails. @see appendText */ bool replaceWithText (const String& textToWrite, bool asUnicode = false, bool writeUnicodeHeaderBytes = false) const; /** Attempts to scan the contents of this file and compare it to another file, returning true if this is possible and they match byte-for-byte. */ bool hasIdenticalContentTo (const File& other) const; /** Creates a set of files to represent each file root. e.g. on Windows this will create files for "c:\", "d:\" etc according to which ones are available. On the Mac/Linux, this will probably just add a single entry for "/". */ static void findFileSystemRoots (Array& results); /** Finds the name of the drive on which this file lives. @returns the volume label of the drive, or an empty string if this isn't possible */ const String getVolumeLabel() const; /** Returns the serial number of the volume on which this file lives. @returns the serial number, or zero if there's a problem doing this */ int getVolumeSerialNumber() const; /** Returns the number of bytes free on the drive that this file lives on. @returns the number of bytes free, or 0 if there's a problem finding this out @see getVolumeTotalSize */ int64 getBytesFreeOnVolume() const; /** Returns the total size of the drive that contains this file. @returns the total number of bytes that the volume can hold @see getBytesFreeOnVolume */ int64 getVolumeTotalSize() const; /** Returns true if this file is on a CD or DVD drive. */ bool isOnCDRomDrive() const; /** Returns true if this file is on a hard disk. This will fail if it's a network drive, but will still be true for removable hard-disks. */ bool isOnHardDisk() const; /** Returns true if this file is on a removable disk drive. This might be a usb-drive, a CD-rom, or maybe a network drive. */ bool isOnRemovableDrive() const; /** Launches the file as a process. - if the file is executable, this will run it. - if it's a document of some kind, it will launch the document with its default viewer application. - if it's a folder, it will be opened in Explorer, Finder, or equivalent. @see revealToUser */ bool startAsProcess (const String& parameters = String::empty) const; /** Opens Finder, Explorer, or whatever the OS uses, to show the user this file's location. @see startAsProcess */ void revealToUser() const; /** A set of types of location that can be passed to the getSpecialLocation() method. */ enum SpecialLocationType { /** The user's home folder. This is the same as using File ("~"). */ userHomeDirectory, /** The user's default documents folder. On Windows, this might be the user's "My Documents" folder. On the Mac it'll be their "Documents" folder. Linux doesn't tend to have one of these, so it might just return their home folder. */ userDocumentsDirectory, /** The folder that contains the user's desktop objects. */ userDesktopDirectory, /** The folder in which applications store their persistent user-specific settings. On Windows, this might be "\Documents and Settings\username\Application Data". On the Mac, it might be "~/Library". If you're going to store your settings in here, always create your own sub-folder to put them in, to avoid making a mess. */ userApplicationDataDirectory, /** An equivalent of the userApplicationDataDirectory folder that is shared by all users of the computer, rather than just the current user. On the Mac it'll be "/Library", on Windows, it could be something like "\Documents and Settings\All Users\Application Data". Depending on the setup, this folder may be read-only. */ commonApplicationDataDirectory, /** The folder that should be used for temporary files. Always delete them when you're finished, to keep the user's computer tidy! */ tempDirectory, /** Returns this application's executable file. If running as a plug-in or DLL, this will (where possible) be the DLL rather than the host app. On the mac this will return the unix binary, not the package folder - see currentApplicationFile for that. See also invokedExecutableFile, which is similar, but if the exe was launched from a file link, invokedExecutableFile will return the name of the link. */ currentExecutableFile, /** Returns this application's location. If running as a plug-in or DLL, this will (where possible) be the DLL rather than the host app. On the mac this will return the package folder (if it's in one), not the unix binary that's inside it - compare with currentExecutableFile. */ currentApplicationFile, /** Returns the file that was invoked to launch this executable. This may differ from currentExecutableFile if the app was started from e.g. a link - this will return the name of the link that was used, whereas currentExecutableFile will return the actual location of the target executable. */ invokedExecutableFile, /** In a plugin, this will return the path of the host executable. */ hostApplicationPath, /** The directory in which applications normally get installed. So on windows, this would be something like "c:\program files", on the Mac "/Applications", or "/usr" on linux. */ globalApplicationsDirectory, /** The most likely place where a user might store their music files. */ userMusicDirectory, /** The most likely place where a user might store their movie files. */ userMoviesDirectory, }; /** Finds the location of a special type of file or directory, such as a home folder or documents folder. @see SpecialLocationType */ static const File JUCE_CALLTYPE getSpecialLocation (const SpecialLocationType type); /** Returns a temporary file in the system's temp directory. This will try to return the name of a non-existent temp file. To get the temp folder, you can use getSpecialLocation (File::tempDirectory). */ static const File createTempFile (const String& fileNameEnding); /** Returns the current working directory. @see setAsCurrentWorkingDirectory */ static const File getCurrentWorkingDirectory(); /** Sets the current working directory to be this file. For this to work the file must point to a valid directory. @returns true if the current directory has been changed. @see getCurrentWorkingDirectory */ bool setAsCurrentWorkingDirectory() const; /** The system-specific file separator character. On Windows, this will be '\', on Mac/Linux, it'll be '/' */ static const juce_wchar separator; /** The system-specific file separator character, as a string. On Windows, this will be '\', on Mac/Linux, it'll be '/' */ static const String separatorString; /** Removes illegal characters from a filename. This will return a copy of the given string after removing characters that are not allowed in a legal filename, and possibly shortening the string if it's too long. Because this will remove slashes, don't use it on an absolute pathname. @see createLegalPathName */ static const String createLegalFileName (const String& fileNameToFix); /** Removes illegal characters from a pathname. Similar to createLegalFileName(), but this won't remove slashes, so can be used on a complete pathname. @see createLegalFileName */ static const String createLegalPathName (const String& pathNameToFix); /** Indicates whether filenames are case-sensitive on the current operating system. */ static bool areFileNamesCaseSensitive(); /** Returns true if the string seems to be a fully-specified absolute path. */ static bool isAbsolutePath (const String& path); /** Creates a file that simply contains this string, without doing the sanity-checking that the normal constructors do. Best to avoid this unless you really know what you're doing. */ static const File createFileWithoutCheckingPath (const String& path); /** Adds a separator character to the end of a path if it doesn't already have one. */ static const String addTrailingSeparator (const String& path); private: String fullPath; // internal way of contructing a file without checking the path friend class DirectoryIterator; File (const String&, int); const String getPathUpToLastSlash() const; void createDirectoryInternal (const String& fileName) const; bool copyInternal (const File& dest) const; bool moveInternal (const File& dest) const; bool setFileTimesInternal (int64 modificationTime, int64 accessTime, int64 creationTime) const; void getFileTimesInternal (int64& modificationTime, int64& accessTime, int64& creationTime) const; bool setFileReadOnlyInternal (bool shouldBeReadOnly) const; static const String parseAbsolutePath (const String& path); JUCE_LEAK_DETECTOR (File); }; #endif // __JUCE_FILE_JUCEHEADER__ /*** End of inlined file: juce_File.h ***/ /** A handy macro to make it easy to iterate all the child elements in an XmlElement. The parentXmlElement should be a reference to the parent XML, and the childElementVariableName will be the name of a pointer to each child element. E.g. @code XmlElement* myParentXml = createSomeKindOfXmlDocument(); forEachXmlChildElement (*myParentXml, child) { if (child->hasTagName ("FOO")) doSomethingWithXmlElement (child); } @endcode @see forEachXmlChildElementWithTagName */ #define forEachXmlChildElement(parentXmlElement, childElementVariableName) \ \ for (XmlElement* childElementVariableName = (parentXmlElement).getFirstChildElement(); \ childElementVariableName != 0; \ childElementVariableName = childElementVariableName->getNextElement()) /** A macro that makes it easy to iterate all the child elements of an XmlElement which have a specified tag. This does the same job as the forEachXmlChildElement macro, but only for those elements that have a particular tag name. The parentXmlElement should be a reference to the parent XML, and the childElementVariableName will be the name of a pointer to each child element. The requiredTagName is the tag name to match. E.g. @code XmlElement* myParentXml = createSomeKindOfXmlDocument(); forEachXmlChildElementWithTagName (*myParentXml, child, "MYTAG") { // the child object is now guaranteed to be a element.. doSomethingWithMYTAGElement (child); } @endcode @see forEachXmlChildElement */ #define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \ \ for (XmlElement* childElementVariableName = (parentXmlElement).getChildByName (requiredTagName); \ childElementVariableName != 0; \ childElementVariableName = childElementVariableName->getNextElementWithTagName (requiredTagName)) /** Used to build a tree of elements representing an XML document. An XML document can be parsed into a tree of XmlElements, each of which represents an XML tag structure, and which may itself contain other nested elements. An XmlElement can also be converted back into a text document, and has lots of useful methods for manipulating its attributes and sub-elements, so XmlElements can actually be used as a handy general-purpose data structure. Here's an example of parsing some elements: @code // check we're looking at the right kind of document.. if (myElement->hasTagName ("ANIMALS")) { // now we'll iterate its sub-elements looking for 'giraffe' elements.. forEachXmlChildElement (*myElement, e) { if (e->hasTagName ("GIRAFFE")) { // found a giraffe, so use some of its attributes.. String giraffeName = e->getStringAttribute ("name"); int giraffeAge = e->getIntAttribute ("age"); bool isFriendly = e->getBoolAttribute ("friendly"); } } } @endcode And here's an example of how to create an XML document from scratch: @code // create an outer node called "ANIMALS" XmlElement animalsList ("ANIMALS"); for (int i = 0; i < numAnimals; ++i) { // create an inner element.. XmlElement* giraffe = new XmlElement ("GIRAFFE"); giraffe->setAttribute ("name", "nigel"); giraffe->setAttribute ("age", 10); giraffe->setAttribute ("friendly", true); // ..and add our new element to the parent node animalsList.addChildElement (giraffe); } // now we can turn the whole thing into a text document.. String myXmlDoc = animalsList.createDocument (String::empty); @endcode @see XmlDocument */ class JUCE_API XmlElement { public: /** Creates an XmlElement with this tag name. */ explicit XmlElement (const String& tagName) throw(); /** Creates a (deep) copy of another element. */ XmlElement (const XmlElement& other); /** Creates a (deep) copy of another element. */ XmlElement& operator= (const XmlElement& other); /** Deleting an XmlElement will also delete all its child elements. */ ~XmlElement() throw(); /** Compares two XmlElements to see if they contain the same text and attiributes. The elements are only considered equivalent if they contain the same attiributes with the same values, and have the same sub-nodes. @param other the other element to compare to @param ignoreOrderOfAttributes if true, this means that two elements with the same attributes in a different order will be considered the same; if false, the attributes must be in the same order as well */ bool isEquivalentTo (const XmlElement* other, bool ignoreOrderOfAttributes) const throw(); /** Returns an XML text document that represents this element. The string returned can be parsed to recreate the same XmlElement that was used to create it. @param dtdToUse the DTD to add to the document @param allOnOneLine if true, this means that the document will not contain any linefeeds, so it'll be smaller but not very easy to read. @param includeXmlHeader whether to add the ", this would return "MOOSE". @see hasTagName */ inline const String& getTagName() const throw() { return tagName; } /** Tests whether this element has a particular tag name. @param possibleTagName the tag name you're comparing it with @see getTagName */ bool hasTagName (const String& possibleTagName) const throw(); /** Returns the number of XML attributes this element contains. E.g. for an element such as \, this would return 2. */ int getNumAttributes() const throw(); /** Returns the name of one of the elements attributes. E.g. for an element such as \, then getAttributeName(1) would return "antlers". @see getAttributeValue, getStringAttribute */ const String& getAttributeName (int attributeIndex) const throw(); /** Returns the value of one of the elements attributes. E.g. for an element such as \, then getAttributeName(1) would return "2". @see getAttributeName, getStringAttribute */ const String& getAttributeValue (int attributeIndex) const throw(); // Attribute-handling methods.. /** Checks whether the element contains an attribute with a certain name. */ bool hasAttribute (const String& attributeName) const throw(); /** Returns the value of a named attribute. @param attributeName the name of the attribute to look up */ const String& getStringAttribute (const String& attributeName) const throw(); /** Returns the value of a named attribute. @param attributeName the name of the attribute to look up @param defaultReturnValue a value to return if the element doesn't have an attribute with this name */ const String getStringAttribute (const String& attributeName, const String& defaultReturnValue) const; /** Compares the value of a named attribute with a value passed-in. @param attributeName the name of the attribute to look up @param stringToCompareAgainst the value to compare it with @param ignoreCase whether the comparison should be case-insensitive @returns true if the value of the attribute is the same as the string passed-in; false if it's different (or if no such attribute exists) */ bool compareAttribute (const String& attributeName, const String& stringToCompareAgainst, bool ignoreCase = false) const throw(); /** Returns the value of a named attribute as an integer. This will try to find the attribute and convert it to an integer (using the String::getIntValue() method). @param attributeName the name of the attribute to look up @param defaultReturnValue a value to return if the element doesn't have an attribute with this name @see setAttribute */ int getIntAttribute (const String& attributeName, int defaultReturnValue = 0) const; /** Returns the value of a named attribute as floating-point. This will try to find the attribute and convert it to an integer (using the String::getDoubleValue() method). @param attributeName the name of the attribute to look up @param defaultReturnValue a value to return if the element doesn't have an attribute with this name @see setAttribute */ double getDoubleAttribute (const String& attributeName, double defaultReturnValue = 0.0) const; /** Returns the value of a named attribute as a boolean. This will try to find the attribute and interpret it as a boolean. To do this, it'll return true if the value is "1", "true", "y", etc, or false for other values. @param attributeName the name of the attribute to look up @param defaultReturnValue a value to return if the element doesn't have an attribute with this name */ bool getBoolAttribute (const String& attributeName, bool defaultReturnValue = false) const; /** Adds a named attribute to the element. If the element already contains an attribute with this name, it's value will be updated to the new value. If there's no such attribute yet, a new one will be added. Note that there are other setAttribute() methods that take integers, doubles, etc. to make it easy to store numbers. @param attributeName the name of the attribute to set @param newValue the value to set it to @see removeAttribute */ void setAttribute (const String& attributeName, const String& newValue); /** Adds a named attribute to the element, setting it to an integer value. If the element already contains an attribute with this name, it's value will be updated to the new value. If there's no such attribute yet, a new one will be added. Note that there are other setAttribute() methods that take integers, doubles, etc. to make it easy to store numbers. @param attributeName the name of the attribute to set @param newValue the value to set it to */ void setAttribute (const String& attributeName, int newValue); /** Adds a named attribute to the element, setting it to a floating-point value. If the element already contains an attribute with this name, it's value will be updated to the new value. If there's no such attribute yet, a new one will be added. Note that there are other setAttribute() methods that take integers, doubles, etc. to make it easy to store numbers. @param attributeName the name of the attribute to set @param newValue the value to set it to */ void setAttribute (const String& attributeName, double newValue); /** Removes a named attribute from the element. @param attributeName the name of the attribute to remove @see removeAllAttributes */ void removeAttribute (const String& attributeName) throw(); /** Removes all attributes from this element. */ void removeAllAttributes() throw(); // Child element methods.. /** Returns the first of this element's sub-elements. see getNextElement() for an example of how to iterate the sub-elements. @see forEachXmlChildElement */ XmlElement* getFirstChildElement() const throw() { return firstChildElement; } /** Returns the next of this element's siblings. This can be used for iterating an element's sub-elements, e.g. @code XmlElement* child = myXmlDocument->getFirstChildElement(); while (child != 0) { ...do stuff with this child.. child = child->getNextElement(); } @endcode Note that when iterating the child elements, some of them might be text elements as well as XML tags - use isTextElement() to work this out. Also, it's much easier and neater to use this method indirectly via the forEachXmlChildElement macro. @returns the sibling element that follows this one, or zero if this is the last element in its parent @see getNextElement, isTextElement, forEachXmlChildElement */ inline XmlElement* getNextElement() const throw() { return nextListItem; } /** Returns the next of this element's siblings which has the specified tag name. This is like getNextElement(), but will scan through the list until it finds an element with the given tag name. @see getNextElement, forEachXmlChildElementWithTagName */ XmlElement* getNextElementWithTagName (const String& requiredTagName) const; /** Returns the number of sub-elements in this element. @see getChildElement */ int getNumChildElements() const throw(); /** Returns the sub-element at a certain index. It's not very efficient to iterate the sub-elements by index - see getNextElement() for an example of how best to iterate. @returns the n'th child of this element, or 0 if the index is out-of-range @see getNextElement, isTextElement, getChildByName */ XmlElement* getChildElement (int index) const throw(); /** Returns the first sub-element with a given tag-name. @param tagNameToLookFor the tag name of the element you want to find @returns the first element with this tag name, or 0 if none is found @see getNextElement, isTextElement, getChildElement */ XmlElement* getChildByName (const String& tagNameToLookFor) const throw(); /** Appends an element to this element's list of children. Child elements are deleted automatically when their parent is deleted, so make sure the object that you pass in will not be deleted by anything else, and make sure it's not already the child of another element. @see getFirstChildElement, getNextElement, getNumChildElements, getChildElement, removeChildElement */ void addChildElement (XmlElement* newChildElement) throw(); /** Inserts an element into this element's list of children. Child elements are deleted automatically when their parent is deleted, so make sure the object that you pass in will not be deleted by anything else, and make sure it's not already the child of another element. @param newChildNode the element to add @param indexToInsertAt the index at which to insert the new element - if this is below zero, it will be added to the end of the list @see addChildElement, insertChildElement */ void insertChildElement (XmlElement* newChildNode, int indexToInsertAt) throw(); /** Creates a new element with the given name and returns it, after adding it as a child element. This is a handy method that means that instead of writing this: @code XmlElement* newElement = new XmlElement ("foobar"); myParentElement->addChildElement (newElement); @endcode ..you could just write this: @code XmlElement* newElement = myParentElement->createNewChildElement ("foobar"); @endcode */ XmlElement* createNewChildElement (const String& tagName); /** Replaces one of this element's children with another node. If the current element passed-in isn't actually a child of this element, this will return false and the new one won't be added. Otherwise, the existing element will be deleted, replaced with the new one, and it will return true. */ bool replaceChildElement (XmlElement* currentChildElement, XmlElement* newChildNode) throw(); /** Removes a child element. @param childToRemove the child to look for and remove @param shouldDeleteTheChild if true, the child will be deleted, if false it'll just remove it */ void removeChildElement (XmlElement* childToRemove, bool shouldDeleteTheChild) throw(); /** Deletes all the child elements in the element. @see removeChildElement, deleteAllChildElementsWithTagName */ void deleteAllChildElements() throw(); /** Deletes all the child elements with a given tag name. @see removeChildElement */ void deleteAllChildElementsWithTagName (const String& tagName) throw(); /** Returns true if the given element is a child of this one. */ bool containsChildElement (const XmlElement* possibleChild) const throw(); /** Recursively searches all sub-elements to find one that contains the specified child element. */ XmlElement* findParentElementOf (const XmlElement* elementToLookFor) throw(); /** Sorts the child elements using a comparator. This will use a comparator object to sort the elements into order. The object passed must have a method of the form: @code int compareElements (const XmlElement* first, const XmlElement* second); @endcode ..and this method must return: - a value of < 0 if the first comes before the second - a value of 0 if the two objects are equivalent - a value of > 0 if the second comes before the first To improve performance, the compareElements() method can be declared as static or const. @param comparator the comparator to use for comparing elements. @param retainOrderOfEquivalentItems if this is true, then items which the comparator says are equivalent will be kept in the order in which they currently appear in the array. This is slower to perform, but may be important in some cases. If it's false, a faster algorithm is used, but equivalent elements may be rearranged. */ template void sortChildElements (ElementComparator& comparator, bool retainOrderOfEquivalentItems = false) { const int num = getNumChildElements(); if (num > 1) { HeapBlock elems (num); getChildElementsAsArray (elems); sortArray (comparator, (XmlElement**) elems, 0, num - 1, retainOrderOfEquivalentItems); reorderChildElements (elems, num); } } /** Returns true if this element is a section of text. Elements can either be an XML tag element or a secton of text, so this is used to find out what kind of element this one is. @see getAllText, addTextElement, deleteAllTextElements */ bool isTextElement() const throw(); /** Returns the text for a text element. Note that if you have an element like this: @codehello@endcode then calling getText on the "xyz" element won't return "hello", because that is actually stored in a special text sub-element inside the xyz element. To get the "hello" string, you could either call getText on the (unnamed) sub-element, or use getAllSubText() to do this automatically. Note that leading and trailing whitespace will be included in the string - to remove if, just call String::trim() on the result. @see isTextElement, getAllSubText, getChildElementAllSubText */ const String& getText() const throw(); /** Sets the text in a text element. Note that this is only a valid call if this element is a text element. If it's not, then no action will be performed. */ void setText (const String& newText); /** Returns all the text from this element's child nodes. This iterates all the child elements and when it finds text elements, it concatenates their text into a big string which it returns. E.g. @codehello there world@endcode if you called getAllSubText on the "xyz" element, it'd return "hello there world". Note that leading and trailing whitespace will be included in the string - to remove if, just call String::trim() on the result. @see isTextElement, getChildElementAllSubText, getText, addTextElement */ const String getAllSubText() const; /** Returns all the sub-text of a named child element. If there is a child element with the given tag name, this will return all of its sub-text (by calling getAllSubText() on it). If there is no such child element, this will return the default string passed-in. @see getAllSubText */ const String getChildElementAllSubText (const String& childTagName, const String& defaultReturnValue) const; /** Appends a section of text to this element. @see isTextElement, getText, getAllSubText */ void addTextElement (const String& text); /** Removes all the text elements from this element. @see isTextElement, getText, getAllSubText, addTextElement */ void deleteAllTextElements() throw(); /** Creates a text element that can be added to a parent element. */ static XmlElement* createTextElement (const String& text); private: struct XmlAttributeNode { XmlAttributeNode (const XmlAttributeNode& other) throw(); XmlAttributeNode (const String& name, const String& value) throw(); LinkedListPointer nextListItem; String name, value; bool hasName (const String& name) const throw(); private: XmlAttributeNode& operator= (const XmlAttributeNode&); }; friend class XmlDocument; friend class LinkedListPointer; friend class LinkedListPointer ; friend class LinkedListPointer ::Appender; LinkedListPointer nextListItem; LinkedListPointer firstChildElement; LinkedListPointer attributes; String tagName; XmlElement (int) throw(); void copyChildrenAndAttributesFrom (const XmlElement& other); void writeElementAsText (OutputStream& out, int indentationLevel, int lineWrapLength) const; void getChildElementsAsArray (XmlElement**) const throw(); void reorderChildElements (XmlElement**, int) throw(); JUCE_LEAK_DETECTOR (XmlElement); }; #endif // __JUCE_XMLELEMENT_JUCEHEADER__ /*** End of inlined file: juce_XmlElement.h ***/ /** A set of named property values, which can be strings, integers, floating point, etc. Effectively, this just wraps a StringPairArray in an interface that makes it easier to load and save types other than strings. See the PropertiesFile class for a subclass of this, which automatically broadcasts change messages and saves/loads the list from a file. */ class JUCE_API PropertySet { public: /** Creates an empty PropertySet. @param ignoreCaseOfKeyNames if true, the names of properties are compared in a case-insensitive way */ PropertySet (bool ignoreCaseOfKeyNames = false); /** Creates a copy of another PropertySet. */ PropertySet (const PropertySet& other); /** Copies another PropertySet over this one. */ PropertySet& operator= (const PropertySet& other); /** Destructor. */ virtual ~PropertySet(); /** Returns one of the properties as a string. If the value isn't found in this set, then this will look for it in a fallback property set (if you've specified one with the setFallbackPropertySet() method), and if it can't find one there, it'll return the default value passed-in. @param keyName the name of the property to retrieve @param defaultReturnValue a value to return if the named property doesn't actually exist */ const String getValue (const String& keyName, const String& defaultReturnValue = String::empty) const throw(); /** Returns one of the properties as an integer. If the value isn't found in this set, then this will look for it in a fallback property set (if you've specified one with the setFallbackPropertySet() method), and if it can't find one there, it'll return the default value passed-in. @param keyName the name of the property to retrieve @param defaultReturnValue a value to return if the named property doesn't actually exist */ int getIntValue (const String& keyName, const int defaultReturnValue = 0) const throw(); /** Returns one of the properties as an double. If the value isn't found in this set, then this will look for it in a fallback property set (if you've specified one with the setFallbackPropertySet() method), and if it can't find one there, it'll return the default value passed-in. @param keyName the name of the property to retrieve @param defaultReturnValue a value to return if the named property doesn't actually exist */ double getDoubleValue (const String& keyName, const double defaultReturnValue = 0.0) const throw(); /** Returns one of the properties as an boolean. The result will be true if the string found for this key name can be parsed as a non-zero integer. If the value isn't found in this set, then this will look for it in a fallback property set (if you've specified one with the setFallbackPropertySet() method), and if it can't find one there, it'll return the default value passed-in. @param keyName the name of the property to retrieve @param defaultReturnValue a value to return if the named property doesn't actually exist */ bool getBoolValue (const String& keyName, const bool defaultReturnValue = false) const throw(); /** Returns one of the properties as an XML element. The result will a new XMLElement object that the caller must delete. If may return 0 if the key isn't found, or if the entry contains an string that isn't valid XML. If the value isn't found in this set, then this will look for it in a fallback property set (if you've specified one with the setFallbackPropertySet() method), and if it can't find one there, it'll return the default value passed-in. @param keyName the name of the property to retrieve */ XmlElement* getXmlValue (const String& keyName) const; /** Sets a named property. @param keyName the name of the property to set. (This mustn't be an empty string) @param value the new value to set it to */ void setValue (const String& keyName, const var& value); /** Sets a named property to an XML element. @param keyName the name of the property to set. (This mustn't be an empty string) @param xml the new element to set it to. If this is zero, the value will be set to an empty string @see getXmlValue */ void setValue (const String& keyName, const XmlElement* xml); /** Deletes a property. @param keyName the name of the property to delete. (This mustn't be an empty string) */ void removeValue (const String& keyName); /** Returns true if the properies include the given key. */ bool containsKey (const String& keyName) const throw(); /** Removes all values. */ void clear(); /** Returns the keys/value pair array containing all the properties. */ StringPairArray& getAllProperties() throw() { return properties; } /** Returns the lock used when reading or writing to this set */ const CriticalSection& getLock() const throw() { return lock; } /** Returns an XML element which encapsulates all the items in this property set. The string parameter is the tag name that should be used for the node. @see restoreFromXml */ XmlElement* createXml (const String& nodeName) const; /** Reloads a set of properties that were previously stored as XML. The node passed in must have been created by the createXml() method. @see createXml */ void restoreFromXml (const XmlElement& xml); /** Sets up a second PopertySet that will be used to look up any values that aren't set in this one. If you set this up to be a pointer to a second property set, then whenever one of the getValue() methods fails to find an entry in this set, it will look up that value in the fallback set, and if it finds it, it will return that. Make sure that you don't delete the fallback set while it's still being used by another set! To remove the fallback set, just call this method with a null pointer. @see getFallbackPropertySet */ void setFallbackPropertySet (PropertySet* fallbackProperties) throw(); /** Returns the fallback property set. @see setFallbackPropertySet */ PropertySet* getFallbackPropertySet() const throw() { return fallbackProperties; } protected: /** Subclasses can override this to be told when one of the properies has been changed. */ virtual void propertyChanged(); private: StringPairArray properties; PropertySet* fallbackProperties; CriticalSection lock; bool ignoreCaseOfKeys; JUCE_LEAK_DETECTOR (PropertySet); }; #endif // __JUCE_PROPERTYSET_JUCEHEADER__ /*** End of inlined file: juce_PropertySet.h ***/ #endif #ifndef __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ /*** Start of inlined file: juce_ReferenceCountedArray.h ***/ #ifndef __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ #define __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ /** Holds a list of objects derived from ReferenceCountedObject. A ReferenceCountedArray holds objects derived from ReferenceCountedObject, and takes care of incrementing and decrementing their ref counts when they are added and removed from the array. To make all the array's methods thread-safe, pass in "CriticalSection" as the templated TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. @see Array, OwnedArray, StringArray */ template class ReferenceCountedArray { public: typedef ReferenceCountedObjectPtr ObjectClassPtr; /** Creates an empty array. @see ReferenceCountedObject, Array, OwnedArray */ ReferenceCountedArray() throw() : numUsed (0) { } /** Creates a copy of another array */ ReferenceCountedArray (const ReferenceCountedArray& other) throw() { const ScopedLockType lock (other.getLock()); numUsed = other.numUsed; data.setAllocatedSize (numUsed); memcpy (data.elements, other.data.elements, numUsed * sizeof (ObjectClass*)); for (int i = numUsed; --i >= 0;) if (data.elements[i] != 0) data.elements[i]->incReferenceCount(); } /** Copies another array into this one. Any existing objects in this array will first be released. */ ReferenceCountedArray& operator= (const ReferenceCountedArray& other) throw() { if (this != &other) { ReferenceCountedArray otherCopy (other); swapWithArray (otherCopy); } return *this; } /** Destructor. Any objects in the array will be released, and may be deleted if not referenced from elsewhere. */ ~ReferenceCountedArray() { clear(); } /** Removes all objects from the array. Any objects in the array that are not referenced from elsewhere will be deleted. */ void clear() { const ScopedLockType lock (getLock()); while (numUsed > 0) if (data.elements [--numUsed] != 0) data.elements [numUsed]->decReferenceCount(); jassert (numUsed == 0); data.setAllocatedSize (0); } /** Returns the current number of objects in the array. */ inline int size() const throw() { return numUsed; } /** Returns a pointer to the object at this index in the array. If the index is out-of-range, this will return a null pointer, (and it could be null anyway, because it's ok for the array to hold null pointers as well as objects). @see getUnchecked */ inline const ObjectClassPtr operator[] (const int index) const throw() { const ScopedLockType lock (getLock()); return isPositiveAndBelow (index, numUsed) ? data.elements [index] : static_cast (0); } /** Returns a pointer to the object at this index in the array, without checking whether the index is in-range. This is a faster and less safe version of operator[] which doesn't check the index passed in, so it can be used when you're sure the index if always going to be legal. */ inline const ObjectClassPtr getUnchecked (const int index) const throw() { const ScopedLockType lock (getLock()); jassert (isPositiveAndBelow (index, numUsed)); return data.elements [index]; } /** Returns a pointer to the first object in the array. This will return a null pointer if the array's empty. @see getLast */ inline const ObjectClassPtr getFirst() const throw() { const ScopedLockType lock (getLock()); return numUsed > 0 ? data.elements [0] : static_cast (0); } /** Returns a pointer to the last object in the array. This will return a null pointer if the array's empty. @see getFirst */ inline const ObjectClassPtr getLast() const throw() { const ScopedLockType lock (getLock()); return numUsed > 0 ? data.elements [numUsed - 1] : static_cast (0); } /** Finds the index of the first occurrence of an object in the array. @param objectToLookFor the object to look for @returns the index at which the object was found, or -1 if it's not found */ int indexOf (const ObjectClass* const objectToLookFor) const throw() { const ScopedLockType lock (getLock()); ObjectClass** e = data.elements.getData(); ObjectClass** const end = e + numUsed; while (e != end) { if (objectToLookFor == *e) return static_cast (e - data.elements.getData()); ++e; } return -1; } /** Returns true if the array contains a specified object. @param objectToLookFor the object to look for @returns true if the object is in the array */ bool contains (const ObjectClass* const objectToLookFor) const throw() { const ScopedLockType lock (getLock()); ObjectClass** e = data.elements.getData(); ObjectClass** const end = e + numUsed; while (e != end) { if (objectToLookFor == *e) return true; ++e; } return false; } /** Appends a new object to the end of the array. This will increase the new object's reference count. @param newObject the new object to add to the array @see set, insert, addIfNotAlreadyThere, addSorted, addArray */ void add (ObjectClass* const newObject) throw() { const ScopedLockType lock (getLock()); data.ensureAllocatedSize (numUsed + 1); data.elements [numUsed++] = newObject; if (newObject != 0) newObject->incReferenceCount(); } /** Inserts a new object into the array at the given index. If the index is less than 0 or greater than the size of the array, the element will be added to the end of the array. Otherwise, it will be inserted into the array, moving all the later elements along to make room. This will increase the new object's reference count. @param indexToInsertAt the index at which the new element should be inserted @param newObject the new object to add to the array @see add, addSorted, addIfNotAlreadyThere, set */ void insert (int indexToInsertAt, ObjectClass* const newObject) throw() { if (indexToInsertAt >= 0) { const ScopedLockType lock (getLock()); if (indexToInsertAt > numUsed) indexToInsertAt = numUsed; data.ensureAllocatedSize (numUsed + 1); ObjectClass** const e = data.elements + indexToInsertAt; const int numToMove = numUsed - indexToInsertAt; if (numToMove > 0) memmove (e + 1, e, numToMove * sizeof (ObjectClass*)); *e = newObject; if (newObject != 0) newObject->incReferenceCount(); ++numUsed; } else { add (newObject); } } /** Appends a new object at the end of the array as long as the array doesn't already contain it. If the array already contains a matching object, nothing will be done. @param newObject the new object to add to the array */ void addIfNotAlreadyThere (ObjectClass* const newObject) throw() { const ScopedLockType lock (getLock()); if (! contains (newObject)) add (newObject); } /** Replaces an object in the array with a different one. If the index is less than zero, this method does nothing. If the index is beyond the end of the array, the new object is added to the end of the array. The object being added has its reference count increased, and if it's replacing another object, then that one has its reference count decreased, and may be deleted. @param indexToChange the index whose value you want to change @param newObject the new value to set for this index. @see add, insert, remove */ void set (const int indexToChange, ObjectClass* const newObject) { if (indexToChange >= 0) { const ScopedLockType lock (getLock()); if (newObject != 0) newObject->incReferenceCount(); if (indexToChange < numUsed) { if (data.elements [indexToChange] != 0) data.elements [indexToChange]->decReferenceCount(); data.elements [indexToChange] = newObject; } else { data.ensureAllocatedSize (numUsed + 1); data.elements [numUsed++] = newObject; } } } /** Adds elements from another array to the end of this array. @param arrayToAddFrom the array from which to copy the elements @param startIndex the first element of the other array to start copying from @param numElementsToAdd how many elements to add from the other array. If this value is negative or greater than the number of available elements, all available elements will be copied. @see add */ void addArray (const ReferenceCountedArray& arrayToAddFrom, int startIndex = 0, int numElementsToAdd = -1) throw() { const ScopedLockType lock1 (arrayToAddFrom.getLock()); { const ScopedLockType lock2 (getLock()); if (startIndex < 0) { jassertfalse; startIndex = 0; } if (numElementsToAdd < 0 || startIndex + numElementsToAdd > arrayToAddFrom.size()) numElementsToAdd = arrayToAddFrom.size() - startIndex; if (numElementsToAdd > 0) { data.ensureAllocatedSize (numUsed + numElementsToAdd); while (--numElementsToAdd >= 0) add (arrayToAddFrom.getUnchecked (startIndex++)); } } } /** Inserts a new object into the array assuming that the array is sorted. This will use a comparator to find the position at which the new object should go. If the array isn't sorted, the behaviour of this method will be unpredictable. @param comparator the comparator object to use to compare the elements - see the sort() method for details about this object's form @param newObject the new object to insert to the array @see add, sort */ template void addSorted (ElementComparator& comparator, ObjectClass* newObject) throw() { const ScopedLockType lock (getLock()); insert (findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed), newObject); } /** Inserts or replaces an object in the array, assuming it is sorted. This is similar to addSorted, but if a matching element already exists, then it will be replaced by the new one, rather than the new one being added as well. */ template void addOrReplaceSorted (ElementComparator& comparator, ObjectClass* newObject) throw() { const ScopedLockType lock (getLock()); const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed); if (index > 0 && comparator.compareElements (newObject, data.elements [index - 1]) == 0) set (index - 1, newObject); // replace an existing object that matches else insert (index, newObject); // no match, so insert the new one } /** Removes an object from the array. This will remove the object at a given index and move back all the subsequent objects to close the gap. If the index passed in is out-of-range, nothing will happen. The object that is removed will have its reference count decreased, and may be deleted if not referenced from elsewhere. @param indexToRemove the index of the element to remove @see removeObject, removeRange */ void remove (const int indexToRemove) { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (indexToRemove, numUsed)) { ObjectClass** const e = data.elements + indexToRemove; if (*e != 0) (*e)->decReferenceCount(); --numUsed; const int numberToShift = numUsed - indexToRemove; if (numberToShift > 0) memmove (e, e + 1, numberToShift * sizeof (ObjectClass*)); if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); } } /** Removes and returns an object from the array. This will remove the object at a given index and return it, moving back all the subsequent objects to close the gap. If the index passed in is out-of-range, nothing will happen and a null pointer will be returned. @param indexToRemove the index of the element to remove @see remove, removeObject, removeRange */ const ObjectClassPtr removeAndReturn (const int indexToRemove) { ObjectClassPtr removedItem; const ScopedLockType lock (getLock()); if (isPositiveAndBelow (indexToRemove, numUsed)) { ObjectClass** const e = data.elements + indexToRemove; if (*e != 0) { removedItem = *e; (*e)->decReferenceCount(); } --numUsed; const int numberToShift = numUsed - indexToRemove; if (numberToShift > 0) memmove (e, e + 1, numberToShift * sizeof (ObjectClass*)); if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); } return removedItem; } /** Removes the first occurrence of a specified object from the array. If the item isn't found, no action is taken. If it is found, it is removed and has its reference count decreased. @param objectToRemove the object to try to remove @see remove, removeRange */ void removeObject (ObjectClass* const objectToRemove) { const ScopedLockType lock (getLock()); remove (indexOf (objectToRemove)); } /** Removes a range of objects from the array. This will remove a set of objects, starting from the given index, and move any subsequent elements down to close the gap. If the range extends beyond the bounds of the array, it will be safely clipped to the size of the array. The objects that are removed will have their reference counts decreased, and may be deleted if not referenced from elsewhere. @param startIndex the index of the first object to remove @param numberToRemove how many objects should be removed @see remove, removeObject */ void removeRange (const int startIndex, const int numberToRemove) { const ScopedLockType lock (getLock()); const int start = jlimit (0, numUsed, startIndex); const int end = jlimit (0, numUsed, startIndex + numberToRemove); if (end > start) { int i; for (i = start; i < end; ++i) { if (data.elements[i] != 0) { data.elements[i]->decReferenceCount(); data.elements[i] = 0; // (in case one of the destructors accesses this array and hits a dangling pointer) } } const int rangeSize = end - start; ObjectClass** e = data.elements + start; i = numUsed - end; numUsed -= rangeSize; while (--i >= 0) { *e = e [rangeSize]; ++e; } if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); } } /** Removes the last n objects from the array. The objects that are removed will have their reference counts decreased, and may be deleted if not referenced from elsewhere. @param howManyToRemove how many objects to remove from the end of the array @see remove, removeObject, removeRange */ void removeLast (int howManyToRemove = 1) { const ScopedLockType lock (getLock()); if (howManyToRemove > numUsed) howManyToRemove = numUsed; while (--howManyToRemove >= 0) remove (numUsed - 1); } /** Swaps a pair of objects in the array. If either of the indexes passed in is out-of-range, nothing will happen, otherwise the two objects at these positions will be exchanged. */ void swap (const int index1, const int index2) throw() { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (index1, numUsed) && isPositiveAndBelow (index2, numUsed)) { swapVariables (data.elements [index1], data.elements [index2]); } } /** Moves one of the objects to a different position. This will move the object to a specified index, shuffling along any intervening elements as required. So for example, if you have the array { 0, 1, 2, 3, 4, 5 } then calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. @param currentIndex the index of the object to be moved. If this isn't a valid index, then nothing will be done @param newIndex the index at which you'd like this object to end up. If this is less than zero, it will be moved to the end of the array */ void move (const int currentIndex, int newIndex) throw() { if (currentIndex != newIndex) { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (currentIndex, numUsed)) { if (! isPositiveAndBelow (newIndex, numUsed)) newIndex = numUsed - 1; ObjectClass* const value = data.elements [currentIndex]; if (newIndex > currentIndex) { memmove (data.elements + currentIndex, data.elements + currentIndex + 1, (newIndex - currentIndex) * sizeof (ObjectClass*)); } else { memmove (data.elements + newIndex + 1, data.elements + newIndex, (currentIndex - newIndex) * sizeof (ObjectClass*)); } data.elements [newIndex] = value; } } } /** This swaps the contents of this array with those of another array. If you need to exchange two arrays, this is vastly quicker than using copy-by-value because it just swaps their internal pointers. */ void swapWithArray (ReferenceCountedArray& otherArray) throw() { const ScopedLockType lock1 (getLock()); const ScopedLockType lock2 (otherArray.getLock()); data.swapWith (otherArray.data); swapVariables (numUsed, otherArray.numUsed); } /** Compares this array to another one. @returns true only if the other array contains the same objects in the same order */ bool operator== (const ReferenceCountedArray& other) const throw() { const ScopedLockType lock2 (other.getLock()); const ScopedLockType lock1 (getLock()); if (numUsed != other.numUsed) return false; for (int i = numUsed; --i >= 0;) if (data.elements [i] != other.data.elements [i]) return false; return true; } /** Compares this array to another one. @see operator== */ bool operator!= (const ReferenceCountedArray& other) const throw() { return ! operator== (other); } /** Sorts the elements in the array. This will use a comparator object to sort the elements into order. The object passed must have a method of the form: @code int compareElements (ElementType first, ElementType second); @endcode ..and this method must return: - a value of < 0 if the first comes before the second - a value of 0 if the two objects are equivalent - a value of > 0 if the second comes before the first To improve performance, the compareElements() method can be declared as static or const. @param comparator the comparator to use for comparing elements. @param retainOrderOfEquivalentItems if this is true, then items which the comparator says are equivalent will be kept in the order in which they currently appear in the array. This is slower to perform, but may be important in some cases. If it's false, a faster algorithm is used, but equivalent elements may be rearranged. @see sortArray */ template void sort (ElementComparator& comparator, const bool retainOrderOfEquivalentItems = false) const throw() { (void) comparator; // if you pass in an object with a static compareElements() method, this // avoids getting warning messages about the parameter being unused const ScopedLockType lock (getLock()); sortArray (comparator, data.elements.getData(), 0, size() - 1, retainOrderOfEquivalentItems); } /** Reduces the amount of storage being used by the array. Arrays typically allocate slightly more storage than they need, and after removing elements, they may have quite a lot of unused space allocated. This method will reduce the amount of allocated storage to a minimum. */ void minimiseStorageOverheads() throw() { const ScopedLockType lock (getLock()); data.shrinkToNoMoreThan (numUsed); } /** Returns the CriticalSection that locks this array. To lock, you can call getLock().enter() and getLock().exit(), or preferably use an object of ScopedLockType as an RAII lock for it. */ inline const TypeOfCriticalSectionToUse& getLock() const throw() { return data; } /** Returns the type of scoped lock to use for locking this array */ typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; private: ArrayAllocationBase data; int numUsed; }; #endif // __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__ /*** End of inlined file: juce_ReferenceCountedArray.h ***/ #endif #ifndef __JUCE_SORTEDSET_JUCEHEADER__ /*** Start of inlined file: juce_SortedSet.h ***/ #ifndef __JUCE_SORTEDSET_JUCEHEADER__ #define __JUCE_SORTEDSET_JUCEHEADER__ #if JUCE_MSVC #pragma warning (push) #pragma warning (disable: 4512) #endif /** Holds a set of unique primitive objects, such as ints or doubles. A set can only hold one item with a given value, so if for example it's a set of integers, attempting to add the same integer twice will do nothing the second time. Internally, the list of items is kept sorted (which means that whatever kind of primitive type is used must support the ==, <, >, <= and >= operators to determine the order), and searching the set for known values is very fast because it uses a binary-chop method. Note that if you're using a class or struct as the element type, it must be capable of being copied or moved with a straightforward memcpy, rather than needing construction and destruction code. To make all the set's methods thread-safe, pass in "CriticalSection" as the templated TypeOfCriticalSectionToUse parameter, instead of the default DummyCriticalSection. @see Array, OwnedArray, ReferenceCountedArray, StringArray, CriticalSection */ template class SortedSet { public: /** Creates an empty set. */ SortedSet() throw() : numUsed (0) { } /** Creates a copy of another set. @param other the set to copy */ SortedSet (const SortedSet& other) throw() { const ScopedLockType lock (other.getLock()); numUsed = other.numUsed; data.setAllocatedSize (other.numUsed); memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); } /** Destructor. */ ~SortedSet() throw() { } /** Copies another set over this one. @param other the set to copy */ SortedSet& operator= (const SortedSet& other) throw() { if (this != &other) { const ScopedLockType lock1 (other.getLock()); const ScopedLockType lock2 (getLock()); data.ensureAllocatedSize (other.size()); numUsed = other.numUsed; memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType)); minimiseStorageOverheads(); } return *this; } /** Compares this set to another one. Two sets are considered equal if they both contain the same set of elements. @param other the other set to compare with */ bool operator== (const SortedSet& other) const throw() { const ScopedLockType lock (getLock()); if (numUsed != other.numUsed) return false; for (int i = numUsed; --i >= 0;) if (data.elements[i] != other.data.elements[i]) return false; return true; } /** Compares this set to another one. Two sets are considered equal if they both contain the same set of elements. @param other the other set to compare with */ bool operator!= (const SortedSet& other) const throw() { return ! operator== (other); } /** Removes all elements from the set. This will remove all the elements, and free any storage that the set is using. To clear it without freeing the storage, use the clearQuick() method instead. @see clearQuick */ void clear() throw() { const ScopedLockType lock (getLock()); data.setAllocatedSize (0); numUsed = 0; } /** Removes all elements from the set without freeing the array's allocated storage. @see clear */ void clearQuick() throw() { const ScopedLockType lock (getLock()); numUsed = 0; } /** Returns the current number of elements in the set. */ inline int size() const throw() { return numUsed; } /** Returns one of the elements in the set. If the index passed in is beyond the range of valid elements, this will return zero. If you're certain that the index will always be a valid element, you can call getUnchecked() instead, which is faster. @param index the index of the element being requested (0 is the first element in the set) @see getUnchecked, getFirst, getLast */ inline ElementType operator[] (const int index) const throw() { const ScopedLockType lock (getLock()); return isPositiveAndBelow (index, numUsed) ? data.elements [index] : ElementType(); } /** Returns one of the elements in the set, without checking the index passed in. Unlike the operator[] method, this will try to return an element without checking that the index is within the bounds of the set, so should only be used when you're confident that it will always be a valid index. @param index the index of the element being requested (0 is the first element in the set) @see operator[], getFirst, getLast */ inline ElementType getUnchecked (const int index) const throw() { const ScopedLockType lock (getLock()); jassert (isPositiveAndBelow (index, numUsed)); return data.elements [index]; } /** Returns the first element in the set, or 0 if the set is empty. @see operator[], getUnchecked, getLast */ inline ElementType getFirst() const throw() { const ScopedLockType lock (getLock()); return numUsed > 0 ? data.elements [0] : ElementType(); } /** Returns the last element in the set, or 0 if the set is empty. @see operator[], getUnchecked, getFirst */ inline ElementType getLast() const throw() { const ScopedLockType lock (getLock()); return numUsed > 0 ? data.elements [numUsed - 1] : ElementType(); } /** Finds the index of the first element which matches the value passed in. This will search the set for the given object, and return the index of its first occurrence. If the object isn't found, the method will return -1. @param elementToLookFor the value or object to look for @returns the index of the object, or -1 if it's not found */ int indexOf (const ElementType elementToLookFor) const throw() { const ScopedLockType lock (getLock()); int start = 0; int end = numUsed; for (;;) { if (start >= end) { return -1; } else if (elementToLookFor == data.elements [start]) { return start; } else { const int halfway = (start + end) >> 1; if (halfway == start) return -1; else if (elementToLookFor >= data.elements [halfway]) start = halfway; else end = halfway; } } } /** Returns true if the set contains at least one occurrence of an object. @param elementToLookFor the value or object to look for @returns true if the item is found */ bool contains (const ElementType elementToLookFor) const throw() { const ScopedLockType lock (getLock()); int start = 0; int end = numUsed; for (;;) { if (start >= end) { return false; } else if (elementToLookFor == data.elements [start]) { return true; } else { const int halfway = (start + end) >> 1; if (halfway == start) return false; else if (elementToLookFor >= data.elements [halfway]) start = halfway; else end = halfway; } } } /** Adds a new element to the set, (as long as it's not already in there). @param newElement the new object to add to the set @see set, insert, addIfNotAlreadyThere, addSorted, addSet, addArray */ void add (const ElementType newElement) throw() { const ScopedLockType lock (getLock()); int start = 0; int end = numUsed; for (;;) { if (start >= end) { jassert (start <= end); insertInternal (start, newElement); break; } else if (newElement == data.elements [start]) { break; } else { const int halfway = (start + end) >> 1; if (halfway == start) { if (newElement >= data.elements [halfway]) insertInternal (start + 1, newElement); else insertInternal (start, newElement); break; } else if (newElement >= data.elements [halfway]) start = halfway; else end = halfway; } } } /** Adds elements from an array to this set. @param elementsToAdd the array of elements to add @param numElementsToAdd how many elements are in this other array @see add */ void addArray (const ElementType* elementsToAdd, int numElementsToAdd) throw() { const ScopedLockType lock (getLock()); while (--numElementsToAdd >= 0) add (*elementsToAdd++); } /** Adds elements from another set to this one. @param setToAddFrom the set from which to copy the elements @param startIndex the first element of the other set to start copying from @param numElementsToAdd how many elements to add from the other set. If this value is negative or greater than the number of available elements, all available elements will be copied. @see add */ template void addSet (const OtherSetType& setToAddFrom, int startIndex = 0, int numElementsToAdd = -1) throw() { const typename OtherSetType::ScopedLockType lock1 (setToAddFrom.getLock()); { const ScopedLockType lock2 (getLock()); jassert (this != &setToAddFrom); if (this != &setToAddFrom) { if (startIndex < 0) { jassertfalse; startIndex = 0; } if (numElementsToAdd < 0 || startIndex + numElementsToAdd > setToAddFrom.size()) numElementsToAdd = setToAddFrom.size() - startIndex; addArray (setToAddFrom.elements + startIndex, numElementsToAdd); } } } /** Removes an element from the set. This will remove the element at a given index. If the index passed in is out-of-range, nothing will happen. @param indexToRemove the index of the element to remove @returns the element that has been removed @see removeValue, removeRange */ ElementType remove (const int indexToRemove) throw() { const ScopedLockType lock (getLock()); if (isPositiveAndBelow (indexToRemove, numUsed)) { --numUsed; ElementType* const e = data.elements + indexToRemove; ElementType const removed = *e; const int numberToShift = numUsed - indexToRemove; if (numberToShift > 0) memmove (e, e + 1, numberToShift * sizeof (ElementType)); if ((numUsed << 1) < data.numAllocated) minimiseStorageOverheads(); return removed; } return 0; } /** Removes an item from the set. This will remove the given element from the set, if it's there. @param valueToRemove the object to try to remove @see remove, removeRange */ void removeValue (const ElementType valueToRemove) throw() { const ScopedLockType lock (getLock()); remove (indexOf (valueToRemove)); } /** Removes any elements which are also in another set. @param otherSet the other set in which to look for elements to remove @see removeValuesNotIn, remove, removeValue, removeRange */ template void removeValuesIn (const OtherSetType& otherSet) throw() { const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock()); const ScopedLockType lock2 (getLock()); if (this == &otherSet) { clear(); } else { if (otherSet.size() > 0) { for (int i = numUsed; --i >= 0;) if (otherSet.contains (data.elements [i])) remove (i); } } } /** Removes any elements which are not found in another set. Only elements which occur in this other set will be retained. @param otherSet the set in which to look for elements NOT to remove @see removeValuesIn, remove, removeValue, removeRange */ template void removeValuesNotIn (const OtherSetType& otherSet) throw() { const typename OtherSetType::ScopedLockType lock1 (otherSet.getLock()); const ScopedLockType lock2 (getLock()); if (this != &otherSet) { if (otherSet.size() <= 0) { clear(); } else { for (int i = numUsed; --i >= 0;) if (! otherSet.contains (data.elements [i])) remove (i); } } } /** Reduces the amount of storage being used by the set. Sets typically allocate slightly more storage than they need, and after removing elements, they may have quite a lot of unused space allocated. This method will reduce the amount of allocated storage to a minimum. */ void minimiseStorageOverheads() throw() { const ScopedLockType lock (getLock()); data.shrinkToNoMoreThan (numUsed); } /** Returns the CriticalSection that locks this array. To lock, you can call getLock().enter() and getLock().exit(), or preferably use an object of ScopedLockType as an RAII lock for it. */ inline const TypeOfCriticalSectionToUse& getLock() const throw() { return data; } /** Returns the type of scoped lock to use for locking this array */ typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType; private: ArrayAllocationBase data; int numUsed; void insertInternal (const int indexToInsertAt, const ElementType newElement) throw() { data.ensureAllocatedSize (numUsed + 1); ElementType* const insertPos = data.elements + indexToInsertAt; const int numberToMove = numUsed - indexToInsertAt; if (numberToMove > 0) memmove (insertPos + 1, insertPos, numberToMove * sizeof (ElementType)); *insertPos = newElement; ++numUsed; } }; #if JUCE_MSVC #pragma warning (pop) #endif #endif // __JUCE_SORTEDSET_JUCEHEADER__ /*** End of inlined file: juce_SortedSet.h ***/ #endif #ifndef __JUCE_SPARSESET_JUCEHEADER__ /*** Start of inlined file: juce_SparseSet.h ***/ #ifndef __JUCE_SPARSESET_JUCEHEADER__ #define __JUCE_SPARSESET_JUCEHEADER__ /*** Start of inlined file: juce_Range.h ***/ #ifndef __JUCE_RANGE_JUCEHEADER__ #define __JUCE_RANGE_JUCEHEADER__ /** A general-purpose range object, that simply represents any linear range with a start and end point. The templated parameter is expected to be a primitive integer or floating point type, though class types could also be used if they behave in a number-like way. */ template class Range { public: /** Constructs an empty range. */ Range() throw() : start (ValueType()), end (ValueType()) { } /** Constructs a range with given start and end values. */ Range (const ValueType start_, const ValueType end_) throw() : start (start_), end (jmax (start_, end_)) { } /** Constructs a copy of another range. */ Range (const Range& other) throw() : start (other.start), end (other.end) { } /** Copies another range object. */ Range& operator= (const Range& other) throw() { start = other.start; end = other.end; return *this; } /** Destructor. */ ~Range() throw() { } /** Returns the range that lies between two positions (in either order). */ static const Range between (const ValueType position1, const ValueType position2) throw() { return (position1 < position2) ? Range (position1, position2) : Range (position2, position1); } /** Returns a range with the specified start position and a length of zero. */ static const Range emptyRange (const ValueType start) throw() { return Range (start, start); } /** Returns the start of the range. */ inline ValueType getStart() const throw() { return start; } /** Returns the length of the range. */ inline ValueType getLength() const throw() { return end - start; } /** Returns the end of the range. */ inline ValueType getEnd() const throw() { return end; } /** Returns true if the range has a length of zero. */ inline bool isEmpty() const throw() { return start == end; } /** Changes the start position of the range, leaving the end position unchanged. If the new start position is higher than the current end of the range, the end point will be pushed along to equal it, leaving an empty range at the new position. */ void setStart (const ValueType newStart) throw() { start = newStart; if (end < newStart) end = newStart; } /** Returns a range with the same end as this one, but a different start. If the new start position is higher than the current end of the range, the end point will be pushed along to equal it, returning an empty range at the new position. */ const Range withStart (const ValueType newStart) const throw() { return Range (newStart, jmax (newStart, end)); } /** Returns a range with the same length as this one, but moved to have the given start position. */ const Range movedToStartAt (const ValueType newStart) const throw() { return Range (newStart, end + (newStart - start)); } /** Changes the end position of the range, leaving the start unchanged. If the new end position is below the current start of the range, the start point will be pushed back to equal the new end point. */ void setEnd (const ValueType newEnd) throw() { end = newEnd; if (newEnd < start) start = newEnd; } /** Returns a range with the same start position as this one, but a different end. If the new end position is below the current start of the range, the start point will be pushed back to equal the new end point. */ const Range withEnd (const ValueType newEnd) const throw() { return Range (jmin (start, newEnd), newEnd); } /** Returns a range with the same length as this one, but moved to have the given start position. */ const Range movedToEndAt (const ValueType newEnd) const throw() { return Range (start + (newEnd - end), newEnd); } /** Changes the length of the range. Lengths less than zero are treated as zero. */ void setLength (const ValueType newLength) throw() { end = start + jmax (ValueType(), newLength); } /** Returns a range with the same start as this one, but a different length. Lengths less than zero are treated as zero. */ const Range withLength (const ValueType newLength) const throw() { return Range (start, start + newLength); } /** Adds an amount to the start and end of the range. */ inline const Range& operator+= (const ValueType amountToAdd) throw() { start += amountToAdd; end += amountToAdd; return *this; } /** Subtracts an amount from the start and end of the range. */ inline const Range& operator-= (const ValueType amountToSubtract) throw() { start -= amountToSubtract; end -= amountToSubtract; return *this; } /** Returns a range that is equal to this one with an amount added to its start and end. */ const Range operator+ (const ValueType amountToAdd) const throw() { return Range (start + amountToAdd, end + amountToAdd); } /** Returns a range that is equal to this one with the specified amount subtracted from its start and end. */ const Range operator- (const ValueType amountToSubtract) const throw() { return Range (start - amountToSubtract, end - amountToSubtract); } bool operator== (const Range& other) const throw() { return start == other.start && end == other.end; } bool operator!= (const Range& other) const throw() { return start != other.start || end != other.end; } /** Returns true if the given position lies inside this range. */ bool contains (const ValueType position) const throw() { return start <= position && position < end; } /** Returns the nearest value to the one supplied, which lies within the range. */ ValueType clipValue (const ValueType value) const throw() { return jlimit (start, end, value); } /** Returns true if the given range lies entirely inside this range. */ bool contains (const Range& other) const throw() { return start <= other.start && end >= other.end; } /** Returns true if the given range intersects this one. */ bool intersects (const Range& other) const throw() { return other.start < end && start < other.end; } /** Returns the range that is the intersection of the two ranges, or an empty range with an undefined start position if they don't overlap. */ const Range getIntersectionWith (const Range& other) const throw() { return Range (jmax (start, other.start), jmin (end, other.end)); } /** Returns the smallest range that contains both this one and the other one. */ const Range getUnionWith (const Range& other) const throw() { return Range (jmin (start, other.start), jmax (end, other.end)); } /** Returns a given range, after moving it forwards or backwards to fit it within this range. If the supplied range has a greater length than this one, the return value will be this range. Otherwise, if the supplied range is smaller than this one, the return value will be the new range, shifted forwards or backwards so that it doesn't extend beyond this one, but keeping its original length. */ const Range constrainRange (const Range& rangeToConstrain) const throw() { const ValueType otherLen = rangeToConstrain.getLength(); return getLength() <= otherLen ? *this : rangeToConstrain.movedToStartAt (jlimit (start, end - otherLen, rangeToConstrain.getStart())); } private: ValueType start, end; }; #endif // __JUCE_RANGE_JUCEHEADER__ /*** End of inlined file: juce_Range.h ***/ /** Holds a set of primitive values, storing them as a set of ranges. This container acts like an array, but can efficiently hold large continguous ranges of values. It's quite a specialised class, mostly useful for things like keeping the set of selected rows in a listbox. The type used as a template paramter must be an integer type, such as int, short, int64, etc. */ template class SparseSet { public: /** Creates a new empty set. */ SparseSet() { } /** Creates a copy of another SparseSet. */ SparseSet (const SparseSet& other) : values (other.values) { } /** Destructor. */ ~SparseSet() { } /** Clears the set. */ void clear() { values.clear(); } /** Checks whether the set is empty. This is much quicker than using (size() == 0). */ bool isEmpty() const throw() { return values.size() == 0; } /** Returns the number of values in the set. Because of the way the data is stored, this method can take longer if there are a lot of items in the set. Use isEmpty() for a quick test of whether there are any items. */ Type size() const { Type total (0); for (int i = 0; i < values.size(); i += 2) total += values.getUnchecked (i + 1) - values.getUnchecked (i); return total; } /** Returns one of the values in the set. @param index the index of the value to retrieve, in the range 0 to (size() - 1). @returns the value at this index, or 0 if it's out-of-range */ Type operator[] (Type index) const { for (int i = 0; i < values.size(); i += 2) { const Type start (values.getUnchecked (i)); const Type len (values.getUnchecked (i + 1) - start); if (index < len) return start + index; index -= len; } return Type (0); } /** Checks whether a particular value is in the set. */ bool contains (const Type valueToLookFor) const { for (int i = 0; i < values.size(); ++i) if (valueToLookFor < values.getUnchecked(i)) return (i & 1) != 0; return false; } /** Returns the number of contiguous blocks of values. @see getRange */ int getNumRanges() const throw() { return values.size() >> 1; } /** Returns one of the contiguous ranges of values stored. @param rangeIndex the index of the range to look up, between 0 and (getNumRanges() - 1) @see getTotalRange */ const Range getRange (const int rangeIndex) const { if (isPositiveAndBelow (rangeIndex, getNumRanges())) return Range (values.getUnchecked (rangeIndex << 1), values.getUnchecked ((rangeIndex << 1) + 1)); else return Range(); } /** Returns the range between the lowest and highest values in the set. @see getRange */ const Range getTotalRange() const { if (values.size() > 0) { jassert ((values.size() & 1) == 0); return Range (values.getUnchecked (0), values.getUnchecked (values.size() - 1)); } return Range(); } /** Adds a range of contiguous values to the set. e.g. addRange (Range \ (10, 14)) will add (10, 11, 12, 13) to the set. */ void addRange (const Range& range) { jassert (range.getLength() >= 0); if (range.getLength() > 0) { removeRange (range); values.addUsingDefaultSort (range.getStart()); values.addUsingDefaultSort (range.getEnd()); simplify(); } } /** Removes a range of values from the set. e.g. removeRange (Range\ (10, 14)) will remove (10, 11, 12, 13) from the set. */ void removeRange (const Range& rangeToRemove) { jassert (rangeToRemove.getLength() >= 0); if (rangeToRemove.getLength() > 0 && values.size() > 0 && rangeToRemove.getStart() < values.getUnchecked (values.size() - 1) && values.getUnchecked(0) < rangeToRemove.getEnd()) { const bool onAtStart = contains (rangeToRemove.getStart() - 1); const Type lastValue (jmin (rangeToRemove.getEnd(), values.getLast())); const bool onAtEnd = contains (lastValue); for (int i = values.size(); --i >= 0;) { if (values.getUnchecked(i) <= lastValue) { while (values.getUnchecked(i) >= rangeToRemove.getStart()) { values.remove (i); if (--i < 0) break; } break; } } if (onAtStart) values.addUsingDefaultSort (rangeToRemove.getStart()); if (onAtEnd) values.addUsingDefaultSort (lastValue); simplify(); } } /** Does an XOR of the values in a given range. */ void invertRange (const Range& range) { SparseSet newItems; newItems.addRange (range); int i; for (i = getNumRanges(); --i >= 0;) newItems.removeRange (getRange (i)); removeRange (range); for (i = newItems.getNumRanges(); --i >= 0;) addRange (newItems.getRange(i)); } /** Checks whether any part of a given range overlaps any part of this set. */ bool overlapsRange (const Range& range) { if (range.getLength() > 0) { for (int i = getNumRanges(); --i >= 0;) { if (values.getUnchecked ((i << 1) + 1) <= range.getStart()) return false; if (values.getUnchecked (i << 1) < range.getEnd()) return true; } } return false; } /** Checks whether the whole of a given range is contained within this one. */ bool containsRange (const Range& range) { if (range.getLength() > 0) { for (int i = getNumRanges(); --i >= 0;) { if (values.getUnchecked ((i << 1) + 1) <= range.getStart()) return false; if (values.getUnchecked (i << 1) <= range.getStart() && range.getEnd() <= values.getUnchecked ((i << 1) + 1)) return true; } } return false; } bool operator== (const SparseSet& other) throw() { return values == other.values; } bool operator!= (const SparseSet& other) throw() { return values != other.values; } private: // alternating start/end values of ranges of values that are present. Array values; void simplify() { jassert ((values.size() & 1) == 0); for (int i = values.size(); --i > 0;) if (values.getUnchecked(i) == values.getUnchecked (i - 1)) values.removeRange (--i, 2); } }; #endif // __JUCE_SPARSESET_JUCEHEADER__ /*** End of inlined file: juce_SparseSet.h ***/ #endif #ifndef __JUCE_VALUE_JUCEHEADER__ /*** Start of inlined file: juce_Value.h ***/ #ifndef __JUCE_VALUE_JUCEHEADER__ #define __JUCE_VALUE_JUCEHEADER__ /*** Start of inlined file: juce_AsyncUpdater.h ***/ #ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__ #define __JUCE_ASYNCUPDATER_JUCEHEADER__ /*** Start of inlined file: juce_CallbackMessage.h ***/ #ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__ #define __JUCE_CALLBACKMESSAGE_JUCEHEADER__ /*** Start of inlined file: juce_Message.h ***/ #ifndef __JUCE_MESSAGE_JUCEHEADER__ #define __JUCE_MESSAGE_JUCEHEADER__ class MessageListener; class MessageManager; /** The base class for objects that can be delivered to a MessageListener. The simplest Message object contains a few integer and pointer parameters that the user can set, and this is enough for a lot of purposes. For passing more complex data, subclasses of Message can also be used. @see MessageListener, MessageManager, ActionListener, ChangeListener */ class JUCE_API Message : public ReferenceCountedObject { public: /** Creates an uninitialised message. The class's variables will also be left uninitialised. */ Message() throw(); /** Creates a message object, filling in the member variables. The corresponding public member variables will be set from the parameters passed in. */ Message (int intParameter1, int intParameter2, int intParameter3, void* pointerParameter) throw(); /** Destructor. */ virtual ~Message(); // These values can be used for carrying simple data that the application needs to // pass around. For more complex messages, just create a subclass. int intParameter1; /**< user-defined integer value. */ int intParameter2; /**< user-defined integer value. */ int intParameter3; /**< user-defined integer value. */ void* pointerParameter; /**< user-defined pointer value. */ /** A typedef for pointers to messages. */ typedef ReferenceCountedObjectPtr Ptr; private: friend class MessageListener; friend class MessageManager; MessageListener* messageRecipient; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Message); }; #endif // __JUCE_MESSAGE_JUCEHEADER__ /*** End of inlined file: juce_Message.h ***/ /** A message that calls a custom function when it gets delivered. You can use this class to fire off actions that you want to be performed later on the message thread. Unlike other Message objects, these don't get sent to a MessageListener, you just call the post() method to send them, and when they arrive, your messageCallback() method will automatically be invoked. Always create an instance of a CallbackMessage on the heap, as it will be deleted automatically after the message has been delivered. @see MessageListener, MessageManager, ActionListener, ChangeListener */ class JUCE_API CallbackMessage : public Message { public: CallbackMessage() throw(); /** Destructor. */ ~CallbackMessage(); /** Called when the message is delivered. You should implement this method and make it do whatever action you want to perform. Note that like all other messages, this object will be deleted immediately after this method has been invoked. */ virtual void messageCallback() = 0; /** Instead of sending this message to a MessageListener, just call this method to post it to the event queue. After you've called this, this object will belong to the MessageManager, which will delete it later. So make sure you don't delete the object yourself, call post() more than once, or call post() on a stack-based obect! */ void post(); private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallbackMessage); }; #endif // __JUCE_CALLBACKMESSAGE_JUCEHEADER__ /*** End of inlined file: juce_CallbackMessage.h ***/ /** Has a callback method that is triggered asynchronously. This object allows an asynchronous callback function to be triggered, for tasks such as coalescing multiple updates into a single callback later on. Basically, one or more calls to the triggerAsyncUpdate() will result in the message thread calling handleAsyncUpdate() as soon as it can. */ class JUCE_API AsyncUpdater { public: /** Creates an AsyncUpdater object. */ AsyncUpdater(); /** Destructor. If there are any pending callbacks when the object is deleted, these are lost. */ virtual ~AsyncUpdater(); /** Causes the callback to be triggered at a later time. This method returns immediately, having made sure that a callback to the handleAsyncUpdate() method will occur as soon as possible. If an update callback is already pending but hasn't happened yet, calls to this method will be ignored. It's thread-safe to call this method from any number of threads without needing to worry about locking. */ void triggerAsyncUpdate(); /** This will stop any pending updates from happening. If called after triggerAsyncUpdate() and before the handleAsyncUpdate() callback happens, this will cancel the handleAsyncUpdate() callback. Note that this method simply cancels the next callback - if a callback is already in progress on a different thread, this won't block until it finishes, so there's no guarantee that the callback isn't still running when you return from */ void cancelPendingUpdate() throw(); /** If an update has been triggered and is pending, this will invoke it synchronously. Use this as a kind of "flush" operation - if an update is pending, the handleAsyncUpdate() method will be called immediately; if no update is pending, then nothing will be done. Because this may invoke the callback, this method must only be called on the main event thread. */ void handleUpdateNowIfNeeded(); /** Returns true if there's an update callback in the pipeline. */ bool isUpdatePending() const throw(); /** Called back to do whatever your class needs to do. This method is called by the message thread at the next convenient time after the triggerAsyncUpdate() method has been called. */ virtual void handleAsyncUpdate() = 0; private: ReferenceCountedObjectPtr message; Atomic& getDeliveryFlag() const throw(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AsyncUpdater); }; #endif // __JUCE_ASYNCUPDATER_JUCEHEADER__ /*** End of inlined file: juce_AsyncUpdater.h ***/ /*** Start of inlined file: juce_ListenerList.h ***/ #ifndef __JUCE_LISTENERLIST_JUCEHEADER__ #define __JUCE_LISTENERLIST_JUCEHEADER__ /** Holds a set of objects and can invoke a member function callback on each object in the set with a single call. Use a ListenerList to manage a set of objects which need a callback, and you can invoke a member function by simply calling call() or callChecked(). E.g. @code class MyListenerType { public: void myCallbackMethod (int foo, bool bar); }; ListenerList listeners; listeners.add (someCallbackObjects...); // This will invoke myCallbackMethod (1234, true) on each of the objects // in the list... listeners.call (&MyListenerType::myCallbackMethod, 1234, true); @endcode If you add or remove listeners from the list during one of the callbacks - i.e. while it's in the middle of iterating the listeners, then it's guaranteed that no listeners will be mistakenly called after they've been removed, but it may mean that some of the listeners could be called more than once, or not at all, depending on the list's order. Sometimes, there's a chance that invoking one of the callbacks might result in the list itself being deleted while it's still iterating - to survive this situation, you can use callChecked() instead of call(), passing it a local object to act as a "BailOutChecker". The BailOutChecker must implement a method of the form "bool shouldBailOut()", and the list will check this after each callback to determine whether it should abort the operation. For an example of a bail-out checker, see the Component::BailOutChecker class, which can be used to check when a Component has been deleted. See also ListenerList::DummyBailOutChecker, which is a dummy checker that always returns false. */ template > class ListenerList { // Horrible macros required to support VC6/7.. #ifndef DOXYGEN #if JUCE_VC8_OR_EARLIER #define LL_TEMPLATE(a) typename P##a, typename Q##a #define LL_PARAM(a) Q##a& param##a #else #define LL_TEMPLATE(a) typename P##a #define LL_PARAM(a) PARAMETER_TYPE(P##a) param##a #endif #endif public: /** Creates an empty list. */ ListenerList() { } /** Destructor. */ ~ListenerList() { } /** Adds a listener to the list. A listener can only be added once, so if the listener is already in the list, this method has no effect. @see remove */ void add (ListenerClass* const listenerToAdd) { // Listeners can't be null pointers! jassert (listenerToAdd != 0); if (listenerToAdd != 0) listeners.addIfNotAlreadyThere (listenerToAdd); } /** Removes a listener from the list. If the listener wasn't in the list, this has no effect. */ void remove (ListenerClass* const listenerToRemove) { // Listeners can't be null pointers! jassert (listenerToRemove != 0); listeners.removeValue (listenerToRemove); } /** Returns the number of registered listeners. */ int size() const throw() { return listeners.size(); } /** Returns true if any listeners are registered. */ bool isEmpty() const throw() { return listeners.size() == 0; } /** Clears the list. */ void clear() { listeners.clear(); } /** Returns true if the specified listener has been added to the list. */ bool contains (ListenerClass* const listener) const throw() { return listeners.contains (listener); } /** Calls a member function on each listener in the list, with no parameters. */ void call (void (ListenerClass::*callbackFunction) ()) { callChecked (static_cast (DummyBailOutChecker()), callbackFunction); } /** Calls a member function on each listener in the list, with no parameters and a bail-out-checker. See the class description for info about writing a bail-out checker. */ template void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) ()) { for (Iterator iter (*this); iter.next (bailOutChecker);) (iter.getListener()->*callbackFunction) (); } /** Calls a member function on each listener in the list, with 1 parameter. */ template void call (void (ListenerClass::*callbackFunction) (P1), LL_PARAM(1)) { for (Iterator iter (*this); iter.next();) (iter.getListener()->*callbackFunction) (param1); } /** Calls a member function on each listener in the list, with one parameter and a bail-out-checker. See the class description for info about writing a bail-out checker. */ template void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) (P1), LL_PARAM(1)) { for (Iterator iter (*this); iter.next (bailOutChecker);) (iter.getListener()->*callbackFunction) (param1); } /** Calls a member function on each listener in the list, with 2 parameters. */ template void call (void (ListenerClass::*callbackFunction) (P1, P2), LL_PARAM(1), LL_PARAM(2)) { for (Iterator iter (*this); iter.next();) (iter.getListener()->*callbackFunction) (param1, param2); } /** Calls a member function on each listener in the list, with 2 parameters and a bail-out-checker. See the class description for info about writing a bail-out checker. */ template void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) (P1, P2), LL_PARAM(1), LL_PARAM(2)) { for (Iterator iter (*this); iter.next (bailOutChecker);) (iter.getListener()->*callbackFunction) (param1, param2); } /** Calls a member function on each listener in the list, with 3 parameters. */ template void call (void (ListenerClass::*callbackFunction) (P1, P2, P3), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3)) { for (Iterator iter (*this); iter.next();) (iter.getListener()->*callbackFunction) (param1, param2, param3); } /** Calls a member function on each listener in the list, with 3 parameters and a bail-out-checker. See the class description for info about writing a bail-out checker. */ template void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) (P1, P2, P3), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3)) { for (Iterator iter (*this); iter.next (bailOutChecker);) (iter.getListener()->*callbackFunction) (param1, param2, param3); } /** Calls a member function on each listener in the list, with 4 parameters. */ template void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4)) { for (Iterator iter (*this); iter.next();) (iter.getListener()->*callbackFunction) (param1, param2, param3, param4); } /** Calls a member function on each listener in the list, with 4 parameters and a bail-out-checker. See the class description for info about writing a bail-out checker. */ template void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) (P1, P2, P3, P4), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4)) { for (Iterator iter (*this); iter.next (bailOutChecker);) (iter.getListener()->*callbackFunction) (param1, param2, param3, param4); } /** Calls a member function on each listener in the list, with 5 parameters. */ template void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5)) { for (Iterator iter (*this); iter.next();) (iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5); } /** Calls a member function on each listener in the list, with 5 parameters and a bail-out-checker. See the class description for info about writing a bail-out checker. */ template void callChecked (const BailOutCheckerType& bailOutChecker, void (ListenerClass::*callbackFunction) (P1, P2, P3, P4, P5), LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4), LL_PARAM(5)) { for (Iterator iter (*this); iter.next (bailOutChecker);) (iter.getListener()->*callbackFunction) (param1, param2, param3, param4, param5); } /** A dummy bail-out checker that always returns false. See the ListenerList notes for more info about bail-out checkers. */ class DummyBailOutChecker { public: inline bool shouldBailOut() const throw() { return false; } }; /** Iterates the listeners in a ListenerList. */ template class Iterator { public: Iterator (const ListType& list_) : list (list_), index (list_.size()) {} ~Iterator() {} bool next() { if (index <= 0) return false; const int listSize = list.size(); if (--index < listSize) return true; index = listSize - 1; return index >= 0; } bool next (const BailOutCheckerType& bailOutChecker) { return (! bailOutChecker.shouldBailOut()) && next(); } typename ListType::ListenerType* getListener() const throw() { return list.getListeners().getUnchecked (index); } private: const ListType& list; int index; JUCE_DECLARE_NON_COPYABLE (Iterator); }; typedef ListenerList ThisType; typedef ListenerClass ListenerType; const ArrayType& getListeners() const throw() { return listeners; } private: ArrayType listeners; JUCE_DECLARE_NON_COPYABLE (ListenerList); #undef LL_TEMPLATE #undef LL_PARAM }; #endif // __JUCE_LISTENERLIST_JUCEHEADER__ /*** End of inlined file: juce_ListenerList.h ***/ /** Represents a shared variant value. A Value object contains a reference to a var object, and can get and set its value. Listeners can be attached to be told when the value is changed. The Value class is a wrapper around a shared, reference-counted underlying data object - this means that multiple Value objects can all refer to the same piece of data, allowing all of them to be notified when any of them changes it. When you create a Value with its default constructor, it acts as a wrapper around a simple var object, but by creating a Value that refers to a custom subclass of ValueSource, you can map the Value onto any kind of underlying data. */ class JUCE_API Value { public: /** Creates an empty Value, containing a void var. */ Value(); /** Creates a Value that refers to the same value as another one. Note that this doesn't make a copy of the other value - both this and the other Value will share the same underlying value, so that when either one alters it, both will see it change. */ Value (const Value& other); /** Creates a Value that is set to the specified value. */ explicit Value (const var& initialValue); /** Destructor. */ ~Value(); /** Returns the current value. */ const var getValue() const; /** Returns the current value. */ operator const var() const; /** Returns the value as a string. This is alternative to writing things like "myValue.getValue().toString()". */ const String toString() const; /** Sets the current value. You can also use operator= to set the value. If there are any listeners registered, they will be notified of the change asynchronously. */ void setValue (const var& newValue); /** Sets the current value. This is the same as calling setValue(). If there are any listeners registered, they will be notified of the change asynchronously. */ Value& operator= (const var& newValue); /** Makes this object refer to the same underlying ValueSource as another one. Once this object has been connected to another one, changing either one will update the other. Existing listeners will still be registered after you call this method, and they'll continue to receive messages when the new value changes. */ void referTo (const Value& valueToReferTo); /** Returns true if this value and the other one are references to the same value. */ bool refersToSameSourceAs (const Value& other) const; /** Compares two values. This is a compare-by-value comparison, so is effectively the same as saying (this->getValue() == other.getValue()). */ bool operator== (const Value& other) const; /** Compares two values. This is a compare-by-value comparison, so is effectively the same as saying (this->getValue() != other.getValue()). */ bool operator!= (const Value& other) const; /** Receives callbacks when a Value object changes. @see Value::addListener */ class JUCE_API Listener { public: Listener() {} virtual ~Listener() {} /** Called when a Value object is changed. Note that the Value object passed as a parameter may not be exactly the same object that you registered the listener with - it might be a copy that refers to the same underlying ValueSource. To find out, you can call Value::refersToSameSourceAs(). */ virtual void valueChanged (Value& value) = 0; }; /** Adds a listener to receive callbacks when the value changes. The listener is added to this specific Value object, and not to the shared object that it refers to. When this object is deleted, all the listeners will be lost, even if other references to the same Value still exist. So when you're adding a listener, make sure that you add it to a ValueTree instance that will last for as long as you need the listener. In general, you'd never want to add a listener to a local stack-based ValueTree, but more likely to one that's a member variable. @see removeListener */ void addListener (Listener* listener); /** Removes a listener that was previously added with addListener(). */ void removeListener (Listener* listener); /** Used internally by the Value class as the base class for its shared value objects. The Value class is essentially a reference-counted pointer to a shared instance of a ValueSource object. If you're feeling adventurous, you can create your own custom ValueSource classes to allow Value objects to represent your own custom data items. */ class JUCE_API ValueSource : public ReferenceCountedObject, public AsyncUpdater { public: ValueSource(); virtual ~ValueSource(); /** Returns the current value of this object. */ virtual const var getValue() const = 0; /** Changes the current value. This must also trigger a change message if the value actually changes. */ virtual void setValue (const var& newValue) = 0; /** Delivers a change message to all the listeners that are registered with this value. If dispatchSynchronously is true, the method will call all the listeners before returning; otherwise it'll dispatch a message and make the call later. */ void sendChangeMessage (bool dispatchSynchronously); protected: friend class Value; SortedSet valuesWithListeners; void handleAsyncUpdate(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ValueSource); }; /** Creates a Value object that uses this valueSource object as its underlying data. */ explicit Value (ValueSource* valueSource); /** Returns the ValueSource that this value is referring to. */ ValueSource& getValueSource() throw() { return *value; } private: friend class ValueSource; ReferenceCountedObjectPtr value; ListenerList listeners; void callListeners(); // This is disallowed to avoid confusion about whether it should // do a by-value or by-reference copy. Value& operator= (const Value& other); }; /** Writes a Value to an OutputStream as a UTF8 string. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const Value& value); /** This typedef is just for compatibility with old code - newer code should use the Value::Listener class directly. */ typedef Value::Listener ValueListener; #endif // __JUCE_VALUE_JUCEHEADER__ /*** End of inlined file: juce_Value.h ***/ #endif #ifndef __JUCE_VALUETREE_JUCEHEADER__ /*** Start of inlined file: juce_ValueTree.h ***/ #ifndef __JUCE_VALUETREE_JUCEHEADER__ #define __JUCE_VALUETREE_JUCEHEADER__ /*** Start of inlined file: juce_UndoManager.h ***/ #ifndef __JUCE_UNDOMANAGER_JUCEHEADER__ #define __JUCE_UNDOMANAGER_JUCEHEADER__ /*** Start of inlined file: juce_ChangeBroadcaster.h ***/ #ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__ #define __JUCE_CHANGEBROADCASTER_JUCEHEADER__ /*** Start of inlined file: juce_ChangeListener.h ***/ #ifndef __JUCE_CHANGELISTENER_JUCEHEADER__ #define __JUCE_CHANGELISTENER_JUCEHEADER__ class ChangeBroadcaster; /** Receives change event callbacks that are sent out by a ChangeBroadcaster. A ChangeBroadcaster keeps a set of listeners to which it broadcasts a message when the ChangeBroadcaster::sendChangeMessage() method is called. A subclass of ChangeListener is used to receive these callbacks. Note that the major difference between an ActionListener and a ChangeListener is that for a ChangeListener, multiple changes will be coalesced into fewer callbacks, but ActionListeners perform one callback for every event posted. @see ChangeBroadcaster, ActionListener */ class JUCE_API ChangeListener { public: /** Destructor. */ virtual ~ChangeListener() {} /** Your subclass should implement this method to receive the callback. @param source the ChangeBroadcaster that triggered the callback. */ virtual void changeListenerCallback (ChangeBroadcaster* source) = 0; #if JUCE_CATCH_DEPRECATED_CODE_MISUSE // This method's signature has changed to take a ChangeBroadcaster parameter - please update your code! private: virtual int changeListenerCallback (void*) { return 0; } #endif }; #endif // __JUCE_CHANGELISTENER_JUCEHEADER__ /*** End of inlined file: juce_ChangeListener.h ***/ /** Holds a list of ChangeListeners, and sends messages to them when instructed. @see ChangeListener */ class JUCE_API ChangeBroadcaster { public: /** Creates an ChangeBroadcaster. */ ChangeBroadcaster() throw(); /** Destructor. */ virtual ~ChangeBroadcaster(); /** Registers a listener to receive change callbacks from this broadcaster. Trying to add a listener that's already on the list will have no effect. */ void addChangeListener (ChangeListener* listener); /** Unregisters a listener from the list. If the listener isn't on the list, this won't have any effect. */ void removeChangeListener (ChangeListener* listener); /** Removes all listeners from the list. */ void removeAllChangeListeners(); /** Causes an asynchronous change message to be sent to all the registered listeners. The message will be delivered asynchronously by the main message thread, so this method will return immediately. To call the listeners synchronously use sendSynchronousChangeMessage(). */ void sendChangeMessage(); /** Sends a synchronous change message to all the registered listeners. This will immediately call all the listeners that are registered. For thread-safety reasons, you must only call this method on the main message thread. @see dispatchPendingMessages */ void sendSynchronousChangeMessage(); /** If a change message has been sent but not yet dispatched, this will call sendSynchronousChangeMessage() to make the callback immediately. For thread-safety reasons, you must only call this method on the main message thread. */ void dispatchPendingMessages(); private: class ChangeBroadcasterCallback : public AsyncUpdater { public: ChangeBroadcasterCallback(); void handleAsyncUpdate(); ChangeBroadcaster* owner; }; friend class ChangeBroadcasterCallback; ChangeBroadcasterCallback callback; ListenerList changeListeners; void callListeners(); JUCE_DECLARE_NON_COPYABLE (ChangeBroadcaster); }; #endif // __JUCE_CHANGEBROADCASTER_JUCEHEADER__ /*** End of inlined file: juce_ChangeBroadcaster.h ***/ /*** Start of inlined file: juce_UndoableAction.h ***/ #ifndef __JUCE_UNDOABLEACTION_JUCEHEADER__ #define __JUCE_UNDOABLEACTION_JUCEHEADER__ /** Used by the UndoManager class to store an action which can be done and undone. @see UndoManager */ class JUCE_API UndoableAction { protected: /** Creates an action. */ UndoableAction() throw() {} public: /** Destructor. */ virtual ~UndoableAction() {} /** Overridden by a subclass to perform the action. This method is called by the UndoManager, and shouldn't be used directly by applications. Be careful not to make any calls in a perform() method that could call recursively back into the UndoManager::perform() method @returns true if the action could be performed. @see UndoManager::perform */ virtual bool perform() = 0; /** Overridden by a subclass to undo the action. This method is called by the UndoManager, and shouldn't be used directly by applications. Be careful not to make any calls in an undo() method that could call recursively back into the UndoManager::perform() method @returns true if the action could be undone without any errors. @see UndoManager::perform */ virtual bool undo() = 0; /** Returns a value to indicate how much memory this object takes up. Because the UndoManager keeps a list of UndoableActions, this is used to work out how much space each one will take up, so that the UndoManager can work out how many to keep. The default value returned here is 10 - units are arbitrary and don't have to be accurate. @see UndoManager::getNumberOfUnitsTakenUpByStoredCommands, UndoManager::setMaxNumberOfStoredUnits */ virtual int getSizeInUnits() { return 10; } /** Allows multiple actions to be coalesced into a single action object, to reduce storage space. If possible, this method should create and return a single action that does the same job as this one followed by the supplied action. If it's not possible to merge the two actions, the method should return zero. */ virtual UndoableAction* createCoalescedAction (UndoableAction* nextAction) { (void) nextAction; return 0; } }; #endif // __JUCE_UNDOABLEACTION_JUCEHEADER__ /*** End of inlined file: juce_UndoableAction.h ***/ /** Manages a list of undo/redo commands. An UndoManager object keeps a list of past actions and can use these actions to move backwards and forwards through an undo history. To use it, create subclasses of UndoableAction which perform all the actions you need, then when you need to actually perform an action, create one and pass it to the UndoManager's perform() method. The manager also uses the concept of 'transactions' to group the actions together - all actions performed between calls to beginNewTransaction() are grouped together and are all undone/redone as a group. The UndoManager is a ChangeBroadcaster, so listeners can register to be told when actions are performed or undone. @see UndoableAction */ class JUCE_API UndoManager : public ChangeBroadcaster { public: /** Creates an UndoManager. @param maxNumberOfUnitsToKeep each UndoableAction object returns a value to indicate how much storage it takes up (UndoableAction::getSizeInUnits()), so this lets you specify the maximum total number of units that the undomanager is allowed to keep in memory before letting the older actions drop off the end of the list. @param minimumTransactionsToKeep this specifies the minimum number of transactions that will be kept, even if this involves exceeding the amount of space specified in maxNumberOfUnitsToKeep */ UndoManager (int maxNumberOfUnitsToKeep = 30000, int minimumTransactionsToKeep = 30); /** Destructor. */ ~UndoManager(); /** Deletes all stored actions in the list. */ void clearUndoHistory(); /** Returns the current amount of space to use for storing UndoableAction objects. @see setMaxNumberOfStoredUnits */ int getNumberOfUnitsTakenUpByStoredCommands() const; /** Sets the amount of space that can be used for storing UndoableAction objects. @param maxNumberOfUnitsToKeep each UndoableAction object returns a value to indicate how much storage it takes up (UndoableAction::getSizeInUnits()), so this lets you specify the maximum total number of units that the undomanager is allowed to keep in memory before letting the older actions drop off the end of the list. @param minimumTransactionsToKeep this specifies the minimum number of transactions that will be kept, even if this involves exceeding the amount of space specified in maxNumberOfUnitsToKeep @see getNumberOfUnitsTakenUpByStoredCommands */ void setMaxNumberOfStoredUnits (int maxNumberOfUnitsToKeep, int minimumTransactionsToKeep); /** Performs an action and adds it to the undo history list. @param action the action to perform - this will be deleted by the UndoManager when no longer needed @param actionName if this string is non-empty, the current transaction will be given this name; if it's empty, the current transaction name will be left unchanged. See setCurrentTransactionName() @returns true if the command succeeds - see UndoableAction::perform @see beginNewTransaction */ bool perform (UndoableAction* action, const String& actionName = String::empty); /** Starts a new group of actions that together will be treated as a single transaction. All actions that are passed to the perform() method between calls to this method are grouped together and undone/redone together by a single call to undo() or redo(). @param actionName a description of the transaction that is about to be performed */ void beginNewTransaction (const String& actionName = String::empty); /** Changes the name stored for the current transaction. Each transaction is given a name when the beginNewTransaction() method is called, but this can be used to change that name without starting a new transaction. */ void setCurrentTransactionName (const String& newName); /** Returns true if there's at least one action in the list to undo. @see getUndoDescription, undo, canRedo */ bool canUndo() const; /** Returns the description of the transaction that would be next to get undone. The description returned is the one that was passed into beginNewTransaction before the set of actions was performed. @see undo */ const String getUndoDescription() const; /** Tries to roll-back the last transaction. @returns true if the transaction can be undone, and false if it fails, or if there aren't any transactions to undo */ bool undo(); /** Tries to roll-back any actions that were added to the current transaction. This will perform an undo() only if there are some actions in the undo list that were added after the last call to beginNewTransaction(). This is useful because it lets you call beginNewTransaction(), then perform an operation which may or may not actually perform some actions, and then call this method to get rid of any actions that might have been done without it rolling back the previous transaction if nothing was actually done. @returns true if any actions were undone. */ bool undoCurrentTransactionOnly(); /** Returns a list of the UndoableAction objects that have been performed during the transaction that is currently open. Effectively, this is the list of actions that would be undone if undoCurrentTransactionOnly() were to be called now. The first item in the list is the earliest action performed. */ void getActionsInCurrentTransaction (Array & actionsFound) const; /** Returns the number of UndoableAction objects that have been performed during the transaction that is currently open. @see getActionsInCurrentTransaction */ int getNumActionsInCurrentTransaction() const; /** Returns true if there's at least one action in the list to redo. @see getRedoDescription, redo, canUndo */ bool canRedo() const; /** Returns the description of the transaction that would be next to get redone. The description returned is the one that was passed into beginNewTransaction before the set of actions was performed. @see redo */ const String getRedoDescription() const; /** Tries to redo the last transaction that was undone. @returns true if the transaction can be redone, and false if it fails, or if there aren't any transactions to redo */ bool redo(); private: OwnedArray > transactions; StringArray transactionNames; String currentTransactionName; int totalUnitsStored, maxNumUnitsToKeep, minimumTransactionsToKeep, nextIndex; bool newTransaction, reentrancyCheck; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UndoManager); }; #endif // __JUCE_UNDOMANAGER_JUCEHEADER__ /*** End of inlined file: juce_UndoManager.h ***/ /** A powerful tree structure that can be used to hold free-form data, and which can handle its own undo and redo behaviour. A ValueTree contains a list of named properties as var objects, and also holds any number of sub-trees. Create ValueTree objects on the stack, and don't be afraid to copy them around, as they're simply a lightweight reference to a shared data container. Creating a copy of another ValueTree simply creates a new reference to the same underlying object - to make a separate, deep copy of a tree you should explicitly call createCopy(). Each ValueTree has a type name, in much the same way as an XmlElement has a tag name, and much of the structure of a ValueTree is similar to an XmlElement tree. You can convert a ValueTree to and from an XmlElement, and as long as the XML doesn't contain text elements, the conversion works well and makes a good serialisation format. They can also be serialised to a binary format, which is very fast and compact. All the methods that change data take an optional UndoManager, which will be used to track any changes to the object. For this to work, you have to be careful to consistently always use the same UndoManager for all operations to any node inside the tree. A ValueTree can only be a child of one parent at a time, so if you're moving one from one tree to another, be careful to always remove it first, before adding it. This could also mess up your undo/redo chain, so be wary! In a debug build you should hit assertions if you try to do anything dangerous, but there are still plenty of ways it could go wrong. Listeners can be added to a ValueTree to be told when properies change and when nodes are added or removed. @see var, XmlElement */ class JUCE_API ValueTree { public: /** Creates an empty, invalid ValueTree. A ValueTree that is created with this constructor can't actually be used for anything, it's just a default 'null' ValueTree that can be returned to indicate some sort of failure. To create a real one, use the constructor that takes a string. @see ValueTree::invalid */ ValueTree() throw(); /** Creates an empty ValueTree with the given type name. Like an XmlElement, each ValueTree node has a type, which you can access with getType() and hasType(). */ explicit ValueTree (const Identifier& type); /** Creates a reference to another ValueTree. */ ValueTree (const ValueTree& other); /** Makes this object reference another node. */ ValueTree& operator= (const ValueTree& other); /** Destructor. */ ~ValueTree(); /** Returns true if both this and the other tree node refer to the same underlying structure. Note that this isn't a value comparison - two independently-created trees which contain identical data are not considered equal. */ bool operator== (const ValueTree& other) const throw(); /** Returns true if this and the other node refer to different underlying structures. Note that this isn't a value comparison - two independently-created trees which contain identical data are not considered equal. */ bool operator!= (const ValueTree& other) const throw(); /** Performs a deep comparison between the properties and children of two trees. If all the properties and children of the two trees are the same (recursively), this returns true. The normal operator==() only checks whether two trees refer to the same shared data structure, so use this method if you need to do a proper value comparison. */ bool isEquivalentTo (const ValueTree& other) const; /** Returns true if this node refers to some valid data. It's hard to create an invalid node, but you might get one returned, e.g. by an out-of-range call to getChild(). */ bool isValid() const { return object != 0; } /** Returns a deep copy of this tree and all its sub-nodes. */ ValueTree createCopy() const; /** Returns the type of this node. The type is specified when the ValueTree is created. @see hasType */ const Identifier getType() const; /** Returns true if the node has this type. The comparison is case-sensitive. */ bool hasType (const Identifier& typeName) const; /** Returns the value of a named property. If no such property has been set, this will return a void variant. You can also use operator[] to get a property. @see var, setProperty, hasProperty */ const var& getProperty (const Identifier& name) const; /** Returns the value of a named property, or a user-specified default if the property doesn't exist. If no such property has been set, this will return the value of defaultReturnValue. You can also use operator[] and getProperty to get a property. @see var, getProperty, setProperty, hasProperty */ const var getProperty (const Identifier& name, const var& defaultReturnValue) const; /** Returns the value of a named property. If no such property has been set, this will return a void variant. This is the same as calling getProperty(). @see getProperty */ const var& operator[] (const Identifier& name) const; /** Changes a named property of the node. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. @see var, getProperty, removeProperty */ void setProperty (const Identifier& name, const var& newValue, UndoManager* undoManager); /** Returns true if the node contains a named property. */ bool hasProperty (const Identifier& name) const; /** Removes a property from the node. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ void removeProperty (const Identifier& name, UndoManager* undoManager); /** Removes all properties from the node. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ void removeAllProperties (UndoManager* undoManager); /** Returns the total number of properties that the node contains. @see getProperty. */ int getNumProperties() const; /** Returns the identifier of the property with a given index. @see getNumProperties */ const Identifier getPropertyName (int index) const; /** Returns a Value object that can be used to control and respond to one of the tree's properties. The Value object will maintain a reference to this tree, and will use the undo manager when it needs to change the value. Attaching a Value::Listener to the value object will provide callbacks whenever the property changes. */ Value getPropertyAsValue (const Identifier& name, UndoManager* undoManager) const; /** Returns the number of child nodes belonging to this one. @see getChild */ int getNumChildren() const; /** Returns one of this node's child nodes. If the index is out of range, it'll return an invalid node. (See isValid() to find out whether a node is valid). */ ValueTree getChild (int index) const; /** Returns the first child node with the speficied type name. If no such node is found, it'll return an invalid node. (See isValid() to find out whether a node is valid). @see getOrCreateChildWithName */ ValueTree getChildWithName (const Identifier& type) const; /** Returns the first child node with the speficied type name, creating and adding a child with this name if there wasn't already one there. The only time this will return an invalid object is when the object that you're calling the method on is itself invalid. @see getChildWithName */ ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager); /** Looks for the first child node that has the speficied property value. This will scan the child nodes in order, until it finds one that has property that matches the specified value. If no such node is found, it'll return an invalid node. (See isValid() to find out whether a node is valid). */ ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const; /** Adds a child to this node. Make sure that the child is removed from any former parent node before calling this, or you'll hit an assertion. If the index is < 0 or greater than the current number of child nodes, the new node will be added at the end of the list. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ void addChild (const ValueTree& child, int index, UndoManager* undoManager); /** Removes the specified child from this node's child-list. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ void removeChild (const ValueTree& child, UndoManager* undoManager); /** Removes a child from this node's child-list. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ void removeChild (int childIndex, UndoManager* undoManager); /** Removes all child-nodes from this node. If the undoManager parameter is non-null, its UndoManager::perform() method will be used, so that this change can be undone. */ void removeAllChildren (UndoManager* undoManager); /** Moves one of the children to a different index. This will move the child to a specified index, shuffling along any intervening items as required. So for example, if you have a list of { 0, 1, 2, 3, 4, 5 }, then calling move (2, 4) would result in { 0, 1, 3, 4, 2, 5 }. @param currentIndex the index of the item to be moved. If this isn't a valid index, then nothing will be done @param newIndex the index at which you'd like this item to end up. If this is less than zero, the value will be moved to the end of the list @param undoManager the optional UndoManager to use to store this transaction */ void moveChild (int currentIndex, int newIndex, UndoManager* undoManager); /** Returns true if this node is anywhere below the specified parent node. This returns true if the node is a child-of-a-child, as well as a direct child. */ bool isAChildOf (const ValueTree& possibleParent) const; /** Returns the index of a child item in this parent. If the child isn't found, this returns -1. */ int indexOf (const ValueTree& child) const; /** Returns the parent node that contains this one. If the node has no parent, this will return an invalid node. (See isValid() to find out whether a node is valid). */ ValueTree getParent() const; /** Returns one of this node's siblings in its parent's child list. The delta specifies how far to move through the list, so a value of 1 would return the node that follows this one, -1 would return the node before it, 0 will return this node itself, etc. If the requested position is beyond the range of available nodes, this will return ValueTree::invalid. */ ValueTree getSibling (int delta) const; /** Creates an XmlElement that holds a complete image of this node and all its children. If this node is invalid, this may return 0. Otherwise, the XML that is produced can be used to recreate a similar node by calling fromXml() @see fromXml */ XmlElement* createXml() const; /** Tries to recreate a node from its XML representation. This isn't designed to cope with random XML data - for a sensible result, it should only be fed XML that was created by the createXml() method. */ static ValueTree fromXml (const XmlElement& xml); /** Stores this tree (and all its children) in a binary format. Once written, the data can be read back with readFromStream(). It's much faster to load/save your tree in binary form than as XML, but obviously isn't human-readable. */ void writeToStream (OutputStream& output); /** Reloads a tree from a stream that was written with writeToStream(). */ static ValueTree readFromStream (InputStream& input); /** Reloads a tree from a data block that was written with writeToStream(). */ static ValueTree readFromData (const void* data, size_t numBytes); /** Listener class for events that happen to a ValueTree. To get events from a ValueTree, make your class implement this interface, and use ValueTree::addListener() and ValueTree::removeListener() to register it. */ class JUCE_API Listener { public: /** Destructor. */ virtual ~Listener() {} /** This method is called when a property of this node (or of one of its sub-nodes) has changed. The tree parameter indicates which tree has had its property changed, and the property parameter indicates the property. Note that when you register a listener to a tree, it will receive this callback for property changes in that tree, and also for any of its children, (recursively, at any depth). If your tree has sub-trees but you only want to know about changes to the top level tree, simply check the tree parameter in this callback to make sure it's the tree you're interested in. */ virtual void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property) = 0; /** This method is called when a child sub-tree is added or removed. The tree parameter indicates the tree whose child was added or removed. Note that when you register a listener to a tree, it will receive this callback for child changes in that tree, and also in any of its children, (recursively, at any depth). If your tree has sub-trees but you only want to know about changes to the top level tree, simply check the tree parameter in this callback to make sure it's the tree you're interested in. */ virtual void valueTreeChildrenChanged (ValueTree& treeWhoseChildHasChanged) = 0; /** This method is called when a tree has been added or removed from a parent node. This callback happens when the tree to which the listener was registered is added or removed from a parent. Unlike the other callbacks, it applies only to the tree to which the listener is registered, and not to any of its children. */ virtual void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged) = 0; }; /** Adds a listener to receive callbacks when this node is changed. The listener is added to this specific ValueTree object, and not to the shared object that it refers to. When this object is deleted, all the listeners will be lost, even if other references to the same ValueTree still exist. And if you use the operator= to make this refer to a different ValueTree, any listeners will begin listening to changes to the new tree instead of the old one. When you're adding a listener, make sure that you add it to a ValueTree instance that will last for as long as you need the listener. In general, you'd never want to add a listener to a local stack-based ValueTree, and would usually add one to a member variable. @see removeListener */ void addListener (Listener* listener); /** Removes a listener that was previously added with addListener(). */ void removeListener (Listener* listener); /** This method uses a comparator object to sort the tree's children into order. The object provided must have a method of the form: @code int compareElements (const ValueTree& first, const ValueTree& second); @endcode ..and this method must return: - a value of < 0 if the first comes before the second - a value of 0 if the two objects are equivalent - a value of > 0 if the second comes before the first To improve performance, the compareElements() method can be declared as static or const. @param comparator the comparator to use for comparing elements. @param undoManager optional UndoManager for storing the changes @param retainOrderOfEquivalentItems if this is true, then items which the comparator says are equivalent will be kept in the order in which they currently appear in the array. This is slower to perform, but may be important in some cases. If it's false, a faster algorithm is used, but equivalent elements may be rearranged. */ template void sort (ElementComparator& comparator, UndoManager* undoManager, bool retainOrderOfEquivalentItems) { if (object != 0) { ReferenceCountedArray sortedList (object->children); ComparatorAdapter adapter (comparator); sortedList.sort (adapter, retainOrderOfEquivalentItems); object->reorderChildren (sortedList, undoManager); } } /** An invalid ValueTree that can be used if you need to return one as an error condition, etc. This invalid object is equivalent to ValueTree created with its default constructor. */ static const ValueTree invalid; private: class SetPropertyAction; friend class SetPropertyAction; class AddOrRemoveChildAction; friend class AddOrRemoveChildAction; class MoveChildAction; friend class MoveChildAction; class JUCE_API SharedObject : public ReferenceCountedObject { public: explicit SharedObject (const Identifier& type); SharedObject (const SharedObject& other); ~SharedObject(); const Identifier type; NamedValueSet properties; ReferenceCountedArray children; SortedSet valueTreesWithListeners; SharedObject* parent; void sendPropertyChangeMessage (const Identifier& property); void sendPropertyChangeMessage (ValueTree& tree, const Identifier& property); void sendChildChangeMessage(); void sendChildChangeMessage (ValueTree& tree); void sendParentChangeMessage(); const var& getProperty (const Identifier& name) const; const var getProperty (const Identifier& name, const var& defaultReturnValue) const; void setProperty (const Identifier& name, const var& newValue, UndoManager*); bool hasProperty (const Identifier& name) const; void removeProperty (const Identifier& name, UndoManager*); void removeAllProperties (UndoManager*); bool isAChildOf (const SharedObject* possibleParent) const; int indexOf (const ValueTree& child) const; ValueTree getChildWithName (const Identifier& type) const; ValueTree getOrCreateChildWithName (const Identifier& type, UndoManager* undoManager); ValueTree getChildWithProperty (const Identifier& propertyName, const var& propertyValue) const; void addChild (SharedObject* child, int index, UndoManager*); void removeChild (int childIndex, UndoManager*); void removeAllChildren (UndoManager*); void moveChild (int currentIndex, int newIndex, UndoManager*); void reorderChildren (const ReferenceCountedArray & newOrder, UndoManager*); bool isEquivalentTo (const SharedObject& other) const; XmlElement* createXml() const; private: SharedObject& operator= (const SharedObject&); JUCE_LEAK_DETECTOR (SharedObject); }; template class ComparatorAdapter { public: ComparatorAdapter (ElementComparator& comparator_) throw() : comparator (comparator_) {} int compareElements (SharedObject* const first, SharedObject* const second) { return comparator.compareElements (ValueTree (first), ValueTree (second)); } private: ElementComparator& comparator; JUCE_DECLARE_NON_COPYABLE (ComparatorAdapter); }; friend class SharedObject; typedef ReferenceCountedObjectPtr SharedObjectPtr; SharedObjectPtr object; ListenerList listeners; #if JUCE_MSVC && ! DOXYGEN public: // (workaround for VC6) #endif explicit ValueTree (SharedObject*); }; #endif // __JUCE_VALUETREE_JUCEHEADER__ /*** End of inlined file: juce_ValueTree.h ***/ #endif #ifndef __JUCE_VARIANT_JUCEHEADER__ #endif #ifndef __JUCE_FILELOGGER_JUCEHEADER__ /*** Start of inlined file: juce_FileLogger.h ***/ #ifndef __JUCE_FILELOGGER_JUCEHEADER__ #define __JUCE_FILELOGGER_JUCEHEADER__ /** A simple implemenation of a Logger that writes to a file. @see Logger */ class JUCE_API FileLogger : public Logger { public: /** Creates a FileLogger for a given file. @param fileToWriteTo the file that to use - new messages will be appended to the file. If the file doesn't exist, it will be created, along with any parent directories that are needed. @param welcomeMessage when opened, the logger will write a header to the log, along with the current date and time, and this welcome message @param maxInitialFileSizeBytes if this is zero or greater, then if the file already exists but is larger than this number of bytes, then the start of the file will be truncated to keep the size down. This prevents a log file getting ridiculously large over time. The file will be truncated at a new-line boundary. If this value is less than zero, no size limit will be imposed; if it's zero, the file will always be deleted. Note that the size is only checked once when this object is created - any logging that is done later will be appended without any checking */ FileLogger (const File& fileToWriteTo, const String& welcomeMessage, const int maxInitialFileSizeBytes = 128 * 1024); /** Destructor. */ ~FileLogger(); void logMessage (const String& message); const File getLogFile() const { return logFile; } /** Helper function to create a log file in the correct place for this platform. On Windows this will return a logger with a path such as: c:\\Documents and Settings\\username\\Application Data\\[logFileSubDirectoryName]\\[logFileName] On the Mac it'll create something like: ~/Library/Logs/[logFileName] The method might return 0 if the file can't be created for some reason. @param logFileSubDirectoryName if a subdirectory is needed, this is what it will be called - it's best to use the something like the name of your application here. @param logFileName the name of the file to create, e.g. "MyAppLog.txt". Don't just call it "log.txt" because if it goes in a directory with logs from other applications (as it will do on the Mac) then no-one will know which one is yours! @param welcomeMessage a message that will be written to the log when it's opened. @param maxInitialFileSizeBytes (see the FileLogger constructor for more info on this) */ static FileLogger* createDefaultAppLogger (const String& logFileSubDirectoryName, const String& logFileName, const String& welcomeMessage, const int maxInitialFileSizeBytes = 128 * 1024); private: File logFile; CriticalSection logLock; void trimFileSize (int maxFileSizeBytes) const; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileLogger); }; #endif // __JUCE_FILELOGGER_JUCEHEADER__ /*** End of inlined file: juce_FileLogger.h ***/ #endif #ifndef __JUCE_INITIALISATION_JUCEHEADER__ /*** Start of inlined file: juce_Initialisation.h ***/ #ifndef __JUCE_INITIALISATION_JUCEHEADER__ #define __JUCE_INITIALISATION_JUCEHEADER__ /** Initialises Juce's GUI classes. If you're embedding Juce into an application that uses its own event-loop rather than using the START_JUCE_APPLICATION macro, call this function before making any Juce calls, to make sure things are initialised correctly. Note that if you're creating a Juce DLL for Windows, you may also need to call the PlatformUtilities::setCurrentModuleInstanceHandle() method. @see shutdownJuce_GUI(), initialiseJuce_NonGUI() */ JUCE_API void JUCE_CALLTYPE initialiseJuce_GUI(); /** Clears up any static data being used by Juce's GUI classes. If you're embedding Juce into an application that uses its own event-loop rather than using the START_JUCE_APPLICATION macro, call this function in your shutdown code to clean up any juce objects that might be lying around. @see initialiseJuce_GUI(), initialiseJuce_NonGUI() */ JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI(); /** Initialises the core parts of Juce. If you're embedding Juce into either a command-line program, call this function at the start of your main() function to make sure that Juce is initialised correctly. Note that if you're creating a Juce DLL for Windows, you may also need to call the PlatformUtilities::setCurrentModuleInstanceHandle() method. @see shutdownJuce_NonGUI, initialiseJuce_GUI */ JUCE_API void JUCE_CALLTYPE initialiseJuce_NonGUI(); /** Clears up any static data being used by Juce's non-gui core classes. If you're embedding Juce into either a command-line program, call this function at the end of your main() function if you want to make sure any Juce objects are cleaned up correctly. @see initialiseJuce_NonGUI, initialiseJuce_GUI */ JUCE_API void JUCE_CALLTYPE shutdownJuce_NonGUI(); /** A utility object that helps you initialise and shutdown Juce correctly using an RAII pattern. When an instance of this class is created, it calls initialiseJuce_NonGUI(), and when it's deleted, it calls shutdownJuce_NonGUI(), which lets you easily make sure that these functions are matched correctly. This class is particularly handy to use at the beginning of a console app's main() function, because it'll take care of shutting down whenever you return from the main() call. @see ScopedJuceInitialiser_GUI */ class ScopedJuceInitialiser_NonGUI { public: /** The constructor simply calls initialiseJuce_NonGUI(). */ ScopedJuceInitialiser_NonGUI() { initialiseJuce_NonGUI(); } /** The destructor simply calls shutdownJuce_NonGUI(). */ ~ScopedJuceInitialiser_NonGUI() { shutdownJuce_NonGUI(); } }; /** A utility object that helps you initialise and shutdown Juce correctly using an RAII pattern. When an instance of this class is created, it calls initialiseJuce_GUI(), and when it's deleted, it calls shutdownJuce_GUI(), which lets you easily make sure that these functions are matched correctly. This class is particularly handy to use at the beginning of a console app's main() function, because it'll take care of shutting down whenever you return from the main() call. @see ScopedJuceInitialiser_NonGUI */ class ScopedJuceInitialiser_GUI { public: /** The constructor simply calls initialiseJuce_GUI(). */ ScopedJuceInitialiser_GUI() { initialiseJuce_GUI(); } /** The destructor simply calls shutdownJuce_GUI(). */ ~ScopedJuceInitialiser_GUI() { shutdownJuce_GUI(); } }; /* To start a JUCE app, use this macro: START_JUCE_APPLICATION (AppSubClass) where AppSubClass is the name of a class derived from JUCEApplication. See the JUCEApplication class documentation (juce_Application.h) for more details. */ #if defined (JUCE_GCC) || defined (__MWERKS__) #define START_JUCE_APPLICATION(AppClass) \ static JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication() { return new AppClass(); } \ int main (int argc, char* argv[]) \ { \ JUCE_NAMESPACE::JUCEApplication::createInstance = &juce_CreateApplication; \ return JUCE_NAMESPACE::JUCEApplication::main (argc, (const char**) argv); \ } #elif JUCE_WINDOWS #ifdef _CONSOLE #define START_JUCE_APPLICATION(AppClass) \ static JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication() { return new AppClass(); } \ int main (int, char* argv[]) \ { \ JUCE_NAMESPACE::JUCEApplication::createInstance = &juce_CreateApplication; \ return JUCE_NAMESPACE::JUCEApplication::main (JUCE_NAMESPACE::PlatformUtilities::getCurrentCommandLineParams()); \ } #elif ! defined (_AFXDLL) #ifdef _WINDOWS_ #define START_JUCE_APPLICATION(AppClass) \ static JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication() { return new AppClass(); } \ int WINAPI WinMain (HINSTANCE, HINSTANCE, LPSTR, int) \ { \ JUCE_NAMESPACE::JUCEApplication::createInstance = &juce_CreateApplication; \ return JUCE_NAMESPACE::JUCEApplication::main (JUCE_NAMESPACE::PlatformUtilities::getCurrentCommandLineParams()); \ } #else #define START_JUCE_APPLICATION(AppClass) \ static JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication() { return new AppClass(); } \ int __stdcall WinMain (int, int, const char*, int) \ { \ JUCE_NAMESPACE::JUCEApplication::createInstance = &juce_CreateApplication; \ return JUCE_NAMESPACE::JUCEApplication::main (JUCE_NAMESPACE::PlatformUtilities::getCurrentCommandLineParams()); \ } #endif #endif #endif #endif // __JUCE_INITIALISATION_JUCEHEADER__ /*** End of inlined file: juce_Initialisation.h ***/ #endif #ifndef __JUCE_LOGGER_JUCEHEADER__ #endif #ifndef __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ /*** Start of inlined file: juce_PerformanceCounter.h ***/ #ifndef __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ #define __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ /** A timer for measuring performance of code and dumping the results to a file. e.g. @code PerformanceCounter pc ("fish", 50, "/temp/myfishlog.txt"); for (;;) { pc.start(); doSomethingFishy(); pc.stop(); } @endcode In this example, the time of each period between calling start/stop will be measured and averaged over 50 runs, and the results printed to a file every 50 times round the loop. */ class JUCE_API PerformanceCounter { public: /** Creates a PerformanceCounter object. @param counterName the name used when printing out the statistics @param runsPerPrintout the number of start/stop iterations before calling printStatistics() @param loggingFile a file to dump the results to - if this is File::nonexistent, the results are just written to the debugger output */ PerformanceCounter (const String& counterName, int runsPerPrintout = 100, const File& loggingFile = File::nonexistent); /** Destructor. */ ~PerformanceCounter(); /** Starts timing. @see stop */ void start(); /** Stops timing and prints out the results. The number of iterations before doing a printout of the results is set in the constructor. @see start */ void stop(); /** Dumps the current metrics to the debugger output and to a file. As well as using Logger::outputDebugString to print the results, this will write then to the file specified in the constructor (if this was valid). */ void printStatistics(); private: String name; int numRuns, runsPerPrint; double totalTime; int64 started; File outputFile; }; #endif // __JUCE_PERFORMANCECOUNTER_JUCEHEADER__ /*** End of inlined file: juce_PerformanceCounter.h ***/ #endif #ifndef __JUCE_PLATFORMDEFS_JUCEHEADER__ #endif #ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ /*** Start of inlined file: juce_PlatformUtilities.h ***/ #ifndef __JUCE_PLATFORMUTILITIES_JUCEHEADER__ #define __JUCE_PLATFORMUTILITIES_JUCEHEADER__ /** A collection of miscellaneous platform-specific utilities. */ class JUCE_API PlatformUtilities { public: /** Plays the operating system's default alert 'beep' sound. */ static void beep(); /** Tries to launch the system's default reader for a given file or URL. */ static bool openDocument (const String& documentURL, const String& parameters); /** Tries to launch the system's default email app to let the user create an email. */ static bool launchEmailWithAttachments (const String& targetEmailAddress, const String& emailSubject, const String& bodyText, const StringArray& filesToAttach); #if JUCE_MAC || JUCE_IOS || DOXYGEN /** MAC ONLY - Turns a Core CF String into a juce one. */ static const String cfStringToJuceString (CFStringRef cfString); /** MAC ONLY - Turns a juce string into a Core CF one. */ static CFStringRef juceStringToCFString (const String& s); /** MAC ONLY - Turns a file path into an FSRef, returning true if it succeeds. */ static bool makeFSRefFromPath (FSRef* destFSRef, const String& path); /** MAC ONLY - Turns an FSRef into a juce string path. */ static const String makePathFromFSRef (FSRef* file); /** MAC ONLY - Converts any decomposed unicode characters in a string into their precomposed equivalents. */ static const String convertToPrecomposedUnicode (const String& s); /** MAC ONLY - Gets the type of a file from the file's resources. */ static OSType getTypeOfFile (const String& filename); /** MAC ONLY - Returns true if this file is actually a bundle. */ static bool isBundle (const String& filename); /** MAC ONLY - Adds an item to the dock */ static void addItemToDock (const File& file); /** MAC ONLY - Returns the current OS version number. E.g. if it's running on 10.4, this will be 4, 10.5 will return 5, etc. */ static int getOSXMinorVersionNumber(); #endif #if JUCE_WINDOWS || DOXYGEN // Some registry helper functions: /** WIN32 ONLY - Returns a string from the registry. The path is a string for the entire path of a value in the registry, e.g. "HKEY_CURRENT_USER\Software\foo\bar" */ static const String getRegistryValue (const String& regValuePath, const String& defaultValue = String::empty); /** WIN32 ONLY - Sets a registry value as a string. This will take care of creating any groups needed to get to the given registry value. */ static void setRegistryValue (const String& regValuePath, const String& value); /** WIN32 ONLY - Returns true if the given value exists in the registry. */ static bool registryValueExists (const String& regValuePath); /** WIN32 ONLY - Deletes a registry value. */ static void deleteRegistryValue (const String& regValuePath); /** WIN32 ONLY - Deletes a registry key (which is registry-talk for 'folder'). */ static void deleteRegistryKey (const String& regKeyPath); /** WIN32 ONLY - Creates a file association in the registry. This lets you set the exe that should be launched by a given file extension. @param fileExtension the file extension to associate, including the initial dot, e.g. ".txt" @param symbolicDescription a space-free short token to identify the file type @param fullDescription a human-readable description of the file type @param targetExecutable the executable that should be launched @param iconResourceNumber the icon that gets displayed for the file type will be found by looking up this resource number in the executable. Pass 0 here to not use an icon */ static void registerFileAssociation (const String& fileExtension, const String& symbolicDescription, const String& fullDescription, const File& targetExecutable, int iconResourceNumber); /** WIN32 ONLY - This returns the HINSTANCE of the current module. In a normal Juce application this will be set to the module handle of the application executable. If you're writing a DLL using Juce and plan to use any Juce messaging or windows, you'll need to make sure you use the setCurrentModuleInstanceHandle() to set the correct module handle in your DllMain() function, because the win32 system relies on the correct instance handle when opening windows. */ static void* JUCE_CALLTYPE getCurrentModuleInstanceHandle() throw(); /** WIN32 ONLY - Sets a new module handle to be used by the library. @see getCurrentModuleInstanceHandle() */ static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) throw(); /** WIN32 ONLY - Gets the command-line params as a string. This is needed to avoid unicode problems with the argc type params. */ static const String JUCE_CALLTYPE getCurrentCommandLineParams(); #endif /** Clears the floating point unit's flags. Only has an effect under win32, currently. */ static void fpuReset(); #if JUCE_LINUX || JUCE_WINDOWS /** Loads a dynamically-linked library into the process's address space. @param pathOrFilename the platform-dependent name and search path @returns a handle which can be used by getProcedureEntryPoint(), or zero if it fails. @see freeDynamicLibrary, getProcedureEntryPoint */ static void* loadDynamicLibrary (const String& pathOrFilename); /** Frees a dynamically-linked library. @param libraryHandle a handle created by loadDynamicLibrary @see loadDynamicLibrary, getProcedureEntryPoint */ static void freeDynamicLibrary (void* libraryHandle); /** Finds a procedure call in a dynamically-linked library. @param libraryHandle a library handle returned by loadDynamicLibrary @param procedureName the name of the procedure call to try to load @returns a pointer to the function if found, or 0 if it fails @see loadDynamicLibrary */ static void* getProcedureEntryPoint (void* libraryHandle, const String& procedureName); #endif private: PlatformUtilities(); JUCE_DECLARE_NON_COPYABLE (PlatformUtilities); }; #if JUCE_MAC || JUCE_IOS /** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII. */ class ScopedAutoReleasePool { public: ScopedAutoReleasePool(); ~ScopedAutoReleasePool(); private: void* pool; JUCE_DECLARE_NON_COPYABLE (ScopedAutoReleasePool); }; #define JUCE_AUTORELEASEPOOL const JUCE_NAMESPACE::ScopedAutoReleasePool pool; #else #define JUCE_AUTORELEASEPOOL #endif #if JUCE_LINUX /** A handy class that uses XLockDisplay and XUnlockDisplay to lock the X server using an RAII approach. */ class ScopedXLock { public: /** Creating a ScopedXLock object locks the X display. This uses XLockDisplay() to grab the display that Juce is using. */ ScopedXLock(); /** Deleting a ScopedXLock object unlocks the X display. This calls XUnlockDisplay() to release the lock. */ ~ScopedXLock(); }; #endif #if JUCE_MAC /** A wrapper class for picking up events from an Apple IR remote control device. To use it, just create a subclass of this class, implementing the buttonPressed() callback, then call start() and stop() to start or stop receiving events. */ class JUCE_API AppleRemoteDevice { public: AppleRemoteDevice(); virtual ~AppleRemoteDevice(); /** The set of buttons that may be pressed. @see buttonPressed */ enum ButtonType { menuButton = 0, /**< The menu button (if it's held for a short time). */ playButton, /**< The play button. */ plusButton, /**< The plus or volume-up button. */ minusButton, /**< The minus or volume-down button. */ rightButton, /**< The right button (if it's held for a short time). */ leftButton, /**< The left button (if it's held for a short time). */ rightButton_Long, /**< The right button (if it's held for a long time). */ leftButton_Long, /**< The menu button (if it's held for a long time). */ menuButton_Long, /**< The menu button (if it's held for a long time). */ playButtonSleepMode, switched }; /** Override this method to receive the callback about a button press. The callback will happen on the application's message thread. Some buttons trigger matching up and down events, in which the isDown parameter will be true and then false. Others only send a single event when the button is pressed. */ virtual void buttonPressed (ButtonType buttonId, bool isDown) = 0; /** Starts the device running and responding to events. Returns true if it managed to open the device. @param inExclusiveMode if true, the remote will be grabbed exclusively for this app, and will not be available to any other part of the system. If false, it will be shared with other apps. @see stop */ bool start (bool inExclusiveMode); /** Stops the device running. @see start */ void stop(); /** Returns true if the device has been started successfully. */ bool isActive() const; /** Returns the ID number of the remote, if it has sent one. */ int getRemoteId() const { return remoteId; } /** @internal */ void handleCallbackInternal(); private: void* device; void* queue; int remoteId; bool open (bool openInExclusiveMode); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AppleRemoteDevice); }; #endif #endif // __JUCE_PLATFORMUTILITIES_JUCEHEADER__ /*** End of inlined file: juce_PlatformUtilities.h ***/ #endif #ifndef __JUCE_RELATIVETIME_JUCEHEADER__ #endif #ifndef __JUCE_SINGLETON_JUCEHEADER__ /*** Start of inlined file: juce_Singleton.h ***/ #ifndef __JUCE_SINGLETON_JUCEHEADER__ #define __JUCE_SINGLETON_JUCEHEADER__ /*** Start of inlined file: juce_ScopedLock.h ***/ #ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ #define __JUCE_SCOPEDLOCK_JUCEHEADER__ /** Automatically locks and unlocks a CriticalSection object. Use one of these as a local variable to control access to a CriticalSection. e.g. @code CriticalSection myCriticalSection; for (;;) { const ScopedLock myScopedLock (myCriticalSection); // myCriticalSection is now locked ...do some stuff... // myCriticalSection gets unlocked here. } @endcode @see CriticalSection, ScopedUnlock */ class JUCE_API ScopedLock { public: /** Creates a ScopedLock. As soon as it is created, this will lock the CriticalSection, and when the ScopedLock object is deleted, the CriticalSection will be unlocked. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! Best just to use it as a local stack object, rather than creating one with the new() operator. */ inline explicit ScopedLock (const CriticalSection& lock) throw() : lock_ (lock) { lock.enter(); } /** Destructor. The CriticalSection will be unlocked when the destructor is called. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ inline ~ScopedLock() throw() { lock_.exit(); } private: const CriticalSection& lock_; JUCE_DECLARE_NON_COPYABLE (ScopedLock); }; /** Automatically unlocks and re-locks a CriticalSection object. This is the reverse of a ScopedLock object - instead of locking the critical section for the lifetime of this object, it unlocks it. Make sure you don't try to unlock critical sections that aren't actually locked! e.g. @code CriticalSection myCriticalSection; for (;;) { const ScopedLock myScopedLock (myCriticalSection); // myCriticalSection is now locked ... do some stuff with it locked .. while (xyz) { ... do some stuff with it locked .. const ScopedUnlock unlocker (myCriticalSection); // myCriticalSection is now unlocked for the remainder of this block, // and re-locked at the end. ...do some stuff with it unlocked ... } // myCriticalSection gets unlocked here. } @endcode @see CriticalSection, ScopedLock */ class ScopedUnlock { public: /** Creates a ScopedUnlock. As soon as it is created, this will unlock the CriticalSection, and when the ScopedLock object is deleted, the CriticalSection will be re-locked. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! Best just to use it as a local stack object, rather than creating one with the new() operator. */ inline explicit ScopedUnlock (const CriticalSection& lock) throw() : lock_ (lock) { lock.exit(); } /** Destructor. The CriticalSection will be unlocked when the destructor is called. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ inline ~ScopedUnlock() throw() { lock_.enter(); } private: const CriticalSection& lock_; JUCE_DECLARE_NON_COPYABLE (ScopedUnlock); }; #endif // __JUCE_SCOPEDLOCK_JUCEHEADER__ /*** End of inlined file: juce_ScopedLock.h ***/ /** Macro to declare member variables and methods for a singleton class. To use this, add the line juce_DeclareSingleton (MyClass, doNotRecreateAfterDeletion) to the class's definition. Then put a macro juce_ImplementSingleton (MyClass) along with the class's implementation code. It's also a very good idea to also add the call clearSingletonInstance() in your class's destructor, in case it is deleted by other means than deleteInstance() Clients can then call the static method MyClass::getInstance() to get a pointer to the singleton, or MyClass::getInstanceWithoutCreating() which will return 0 if no instance currently exists. e.g. @code class MySingleton { public: MySingleton() { } ~MySingleton() { // this ensures that no dangling pointers are left when the // singleton is deleted. clearSingletonInstance(); } juce_DeclareSingleton (MySingleton, false) }; juce_ImplementSingleton (MySingleton) // example of usage: MySingleton* m = MySingleton::getInstance(); // creates the singleton if there isn't already one. ... MySingleton::deleteInstance(); // safely deletes the singleton (if it's been created). @endcode If doNotRecreateAfterDeletion = true, it won't allow the object to be created more than once during the process's lifetime - i.e. after you've created and deleted the object, getInstance() will refuse to create another one. This can be useful to stop objects being accidentally re-created during your app's shutdown code. If you know that your object will only be created and deleted by a single thread, you can use the slightly more efficient juce_DeclareSingleton_SingleThreaded() macro instead of this one. @see juce_ImplementSingleton, juce_DeclareSingleton_SingleThreaded */ #define juce_DeclareSingleton(classname, doNotRecreateAfterDeletion) \ \ static classname* _singletonInstance; \ static JUCE_NAMESPACE::CriticalSection _singletonLock; \ \ static classname* JUCE_CALLTYPE getInstance() \ { \ if (_singletonInstance == 0) \ {\ const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \ \ if (_singletonInstance == 0) \ { \ static bool alreadyInside = false; \ static bool createdOnceAlready = false; \ \ const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \ jassert (! problem); \ if (! problem) \ { \ createdOnceAlready = true; \ alreadyInside = true; \ classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \ alreadyInside = false; \ \ _singletonInstance = newObject; \ } \ } \ } \ \ return _singletonInstance; \ } \ \ static inline classname* JUCE_CALLTYPE getInstanceWithoutCreating() throw() \ { \ return _singletonInstance; \ } \ \ static void JUCE_CALLTYPE deleteInstance() \ { \ const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \ if (_singletonInstance != 0) \ { \ classname* const old = _singletonInstance; \ _singletonInstance = 0; \ delete old; \ } \ } \ \ void clearSingletonInstance() throw() \ { \ if (_singletonInstance == this) \ _singletonInstance = 0; \ } /** This is a counterpart to the juce_DeclareSingleton macro. After adding the juce_DeclareSingleton to the class definition, this macro has to be used in the cpp file. */ #define juce_ImplementSingleton(classname) \ \ classname* classname::_singletonInstance = 0; \ JUCE_NAMESPACE::CriticalSection classname::_singletonLock; /** Macro to declare member variables and methods for a singleton class. This is exactly the same as juce_DeclareSingleton, but doesn't use a critical section to make access to it thread-safe. If you know that your object will only ever be created or deleted by a single thread, then this is a more efficient version to use. If doNotRecreateAfterDeletion = true, it won't allow the object to be created more than once during the process's lifetime - i.e. after you've created and deleted the object, getInstance() will refuse to create another one. This can be useful to stop objects being accidentally re-created during your app's shutdown code. See the documentation for juce_DeclareSingleton for more information about how to use it, the only difference being that you have to use juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton. @see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton, juce_DeclareSingleton_SingleThreaded_Minimal */ #define juce_DeclareSingleton_SingleThreaded(classname, doNotRecreateAfterDeletion) \ \ static classname* _singletonInstance; \ \ static classname* getInstance() \ { \ if (_singletonInstance == 0) \ { \ static bool alreadyInside = false; \ static bool createdOnceAlready = false; \ \ const bool problem = alreadyInside || ((doNotRecreateAfterDeletion) && createdOnceAlready); \ jassert (! problem); \ if (! problem) \ { \ createdOnceAlready = true; \ alreadyInside = true; \ classname* newObject = new classname(); /* (use a stack variable to avoid setting the newObject value before the class has finished its constructor) */ \ alreadyInside = false; \ \ _singletonInstance = newObject; \ } \ } \ \ return _singletonInstance; \ } \ \ static inline classname* getInstanceWithoutCreating() throw() \ { \ return _singletonInstance; \ } \ \ static void deleteInstance() \ { \ if (_singletonInstance != 0) \ { \ classname* const old = _singletonInstance; \ _singletonInstance = 0; \ delete old; \ } \ } \ \ void clearSingletonInstance() throw() \ { \ if (_singletonInstance == this) \ _singletonInstance = 0; \ } /** Macro to declare member variables and methods for a singleton class. This is like juce_DeclareSingleton_SingleThreaded, but doesn't do any checking for recursion or repeated instantiation. It's intended for use as a lightweight version of a singleton, where you're using it in very straightforward circumstances and don't need the extra checking. Juce use the normal juce_ImplementSingleton_SingleThreaded as the counterpart to this declaration, as you would with juce_DeclareSingleton_SingleThreaded. See the documentation for juce_DeclareSingleton for more information about how to use it, the only difference being that you have to use juce_ImplementSingleton_SingleThreaded instead of juce_ImplementSingleton. @see juce_ImplementSingleton_SingleThreaded, juce_DeclareSingleton */ #define juce_DeclareSingleton_SingleThreaded_Minimal(classname) \ \ static classname* _singletonInstance; \ \ static classname* getInstance() \ { \ if (_singletonInstance == 0) \ _singletonInstance = new classname(); \ \ return _singletonInstance; \ } \ \ static inline classname* getInstanceWithoutCreating() throw() \ { \ return _singletonInstance; \ } \ \ static void deleteInstance() \ { \ if (_singletonInstance != 0) \ { \ classname* const old = _singletonInstance; \ _singletonInstance = 0; \ delete old; \ } \ } \ \ void clearSingletonInstance() throw() \ { \ if (_singletonInstance == this) \ _singletonInstance = 0; \ } /** This is a counterpart to the juce_DeclareSingleton_SingleThreaded macro. After adding juce_DeclareSingleton_SingleThreaded or juce_DeclareSingleton_SingleThreaded_Minimal to the class definition, this macro has to be used somewhere in the cpp file. */ #define juce_ImplementSingleton_SingleThreaded(classname) \ \ classname* classname::_singletonInstance = 0; #endif // __JUCE_SINGLETON_JUCEHEADER__ /*** End of inlined file: juce_Singleton.h ***/ #endif #ifndef __JUCE_STANDARDHEADER_JUCEHEADER__ #endif #ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ /*** Start of inlined file: juce_SystemStats.h ***/ #ifndef __JUCE_SYSTEMSTATS_JUCEHEADER__ #define __JUCE_SYSTEMSTATS_JUCEHEADER__ /** Contains methods for finding out about the current hardware and OS configuration. */ class JUCE_API SystemStats { public: /** Returns the current version of JUCE, (just in case you didn't already know at compile-time.) See also the JUCE_VERSION, JUCE_MAJOR_VERSION and JUCE_MINOR_VERSION macros. */ static const String getJUCEVersion(); /** The set of possible results of the getOperatingSystemType() method. */ enum OperatingSystemType { UnknownOS = 0, MacOSX = 0x1000, Linux = 0x2000, Win95 = 0x4001, Win98 = 0x4002, WinNT351 = 0x4103, WinNT40 = 0x4104, Win2000 = 0x4105, WinXP = 0x4106, WinVista = 0x4107, Windows7 = 0x4108, Windows = 0x4000, /**< To test whether any version of Windows is running, you can use the expression ((getOperatingSystemType() & Windows) != 0). */ WindowsNT = 0x0100, /**< To test whether the platform is Windows NT or later (i.e. not Win95 or 98), you can use the expression ((getOperatingSystemType() & WindowsNT) != 0). */ }; /** Returns the type of operating system we're running on. @returns one of the values from the OperatingSystemType enum. @see getOperatingSystemName */ static OperatingSystemType getOperatingSystemType(); /** Returns the name of the type of operating system we're running on. @returns a string describing the OS type. @see getOperatingSystemType */ static const String getOperatingSystemName(); /** Returns true if the OS is 64-bit, or false for a 32-bit OS. */ static bool isOperatingSystem64Bit(); /** Returns the current user's name, if available. @see getFullUserName() */ static const String getLogonName(); /** Returns the current user's full name, if available. On some OSes, this may just return the same value as getLogonName(). @see getLogonName() */ static const String getFullUserName(); // CPU and memory information.. /** Returns the approximate CPU speed. @returns the speed in megahertz, e.g. 1500, 2500, 32000 (depending on what year you're reading this...) */ static int getCpuSpeedInMegaherz(); /** Returns a string to indicate the CPU vendor. Might not be known on some systems. */ static const String getCpuVendor(); /** Checks whether Intel MMX instructions are available. */ static bool hasMMX() throw() { return cpuFlags.hasMMX; } /** Checks whether Intel SSE instructions are available. */ static bool hasSSE() throw() { return cpuFlags.hasSSE; } /** Checks whether Intel SSE2 instructions are available. */ static bool hasSSE2() throw() { return cpuFlags.hasSSE2; } /** Checks whether AMD 3DNOW instructions are available. */ static bool has3DNow() throw() { return cpuFlags.has3DNow; } /** Returns the number of CPUs. */ static int getNumCpus() throw() { return cpuFlags.numCpus; } /** Finds out how much RAM is in the machine. @returns the approximate number of megabytes of memory, or zero if something goes wrong when finding out. */ static int getMemorySizeInMegabytes(); /** Returns the system page-size. This is only used by programmers with beards. */ static int getPageSize(); // not-for-public-use platform-specific method gets called at startup to initialise things. static void initialiseStats(); private: struct CPUFlags { int numCpus; bool hasMMX : 1; bool hasSSE : 1; bool hasSSE2 : 1; bool has3DNow : 1; }; static CPUFlags cpuFlags; SystemStats(); JUCE_DECLARE_NON_COPYABLE (SystemStats); }; #endif // __JUCE_SYSTEMSTATS_JUCEHEADER__ /*** End of inlined file: juce_SystemStats.h ***/ #endif #ifndef __JUCE_TARGETPLATFORM_JUCEHEADER__ #endif #ifndef __JUCE_TIME_JUCEHEADER__ #endif #ifndef __JUCE_UUID_JUCEHEADER__ /*** Start of inlined file: juce_Uuid.h ***/ #ifndef __JUCE_UUID_JUCEHEADER__ #define __JUCE_UUID_JUCEHEADER__ /** A universally unique 128-bit identifier. This class generates very random unique numbers based on the system time and MAC addresses if any are available. It's extremely unlikely that two identical UUIDs would ever be created by chance. The class includes methods for saving the ID as a string or as raw binary data. */ class JUCE_API Uuid { public: /** Creates a new unique ID. */ Uuid(); /** Destructor. */ ~Uuid() throw(); /** Creates a copy of another UUID. */ Uuid (const Uuid& other); /** Copies another UUID. */ Uuid& operator= (const Uuid& other); /** Returns true if the ID is zero. */ bool isNull() const throw(); /** Compares two UUIDs. */ bool operator== (const Uuid& other) const; /** Compares two UUIDs. */ bool operator!= (const Uuid& other) const; /** Returns a stringified version of this UUID. A Uuid object can later be reconstructed from this string using operator= or the constructor that takes a string parameter. @returns a 32 character hex string. */ const String toString() const; /** Creates an ID from an encoded string version. @see toString */ Uuid (const String& uuidString); /** Copies from a stringified UUID. The string passed in should be one that was created with the toString() method. */ Uuid& operator= (const String& uuidString); /** Returns a pointer to the internal binary representation of the ID. This is an array of 16 bytes. To reconstruct a Uuid from its data, use the constructor or operator= method that takes an array of uint8s. */ const uint8* getRawData() const throw() { return value.asBytes; } /** Creates a UUID from a 16-byte array. @see getRawData */ Uuid (const uint8* rawData); /** Sets this UUID from 16-bytes of raw data. */ Uuid& operator= (const uint8* rawData); private: #ifndef DOXYGEN union { uint8 asBytes [16]; int asInt[4]; int64 asInt64[2]; } value; #endif JUCE_LEAK_DETECTOR (Uuid); }; #endif // __JUCE_UUID_JUCEHEADER__ /*** End of inlined file: juce_Uuid.h ***/ #endif #ifndef __JUCE_BLOWFISH_JUCEHEADER__ /*** Start of inlined file: juce_BlowFish.h ***/ #ifndef __JUCE_BLOWFISH_JUCEHEADER__ #define __JUCE_BLOWFISH_JUCEHEADER__ /** BlowFish encryption class. */ class JUCE_API BlowFish { public: /** Creates an object that can encode/decode based on the specified key. The key data can be up to 72 bytes long. */ BlowFish (const void* keyData, int keyBytes); /** Creates a copy of another blowfish object. */ BlowFish (const BlowFish& other); /** Copies another blowfish object. */ BlowFish& operator= (const BlowFish& other); /** Destructor. */ ~BlowFish(); /** Encrypts a pair of 32-bit integers. */ void encrypt (uint32& data1, uint32& data2) const throw(); /** Decrypts a pair of 32-bit integers. */ void decrypt (uint32& data1, uint32& data2) const throw(); private: uint32 p[18]; HeapBlock s[4]; uint32 F (uint32 x) const throw(); JUCE_LEAK_DETECTOR (BlowFish); }; #endif // __JUCE_BLOWFISH_JUCEHEADER__ /*** End of inlined file: juce_BlowFish.h ***/ #endif #ifndef __JUCE_MD5_JUCEHEADER__ /*** Start of inlined file: juce_MD5.h ***/ #ifndef __JUCE_MD5_JUCEHEADER__ #define __JUCE_MD5_JUCEHEADER__ /** MD5 checksum class. Create one of these with a block of source data or a string, and it calculates the MD5 checksum of that data. You can then retrieve this checksum as a 16-byte block, or as a hex string. */ class JUCE_API MD5 { public: /** Creates a null MD5 object. */ MD5(); /** Creates a copy of another MD5. */ MD5 (const MD5& other); /** Copies another MD5. */ MD5& operator= (const MD5& other); /** Creates a checksum for a block of binary data. */ explicit MD5 (const MemoryBlock& data); /** Creates a checksum for a block of binary data. */ MD5 (const void* data, size_t numBytes); /** Creates a checksum for a string. Note that this operates on the string as a block of unicode characters, so the result you get will differ from the value you'd get if the string was treated as a block of utf8 or ascii. Bear this in mind if you're comparing the result of this method with a checksum created by a different framework, which may have used a different encoding. */ explicit MD5 (const String& text); /** Creates a checksum for the input from a stream. This will read up to the given number of bytes from the stream, and produce the checksum of that. If the number of bytes to read is negative, it'll read until the stream is exhausted. */ MD5 (InputStream& input, int64 numBytesToRead = -1); /** Creates a checksum for a file. */ explicit MD5 (const File& file); /** Destructor. */ ~MD5(); /** Returns the checksum as a 16-byte block of data. */ const MemoryBlock getRawChecksumData() const; /** Returns the checksum as a 32-digit hex string. */ const String toHexString() const; /** Compares this to another MD5. */ bool operator== (const MD5& other) const; /** Compares this to another MD5. */ bool operator!= (const MD5& other) const; private: uint8 result [16]; struct ProcessContext { uint8 buffer [64]; uint32 state [4]; uint32 count [2]; ProcessContext(); void processBlock (const void* data, size_t dataSize); void transform (const void* buffer); void finish (void* result); }; void processStream (InputStream& input, int64 numBytesToRead); JUCE_LEAK_DETECTOR (MD5); }; #endif // __JUCE_MD5_JUCEHEADER__ /*** End of inlined file: juce_MD5.h ***/ #endif #ifndef __JUCE_PRIMES_JUCEHEADER__ /*** Start of inlined file: juce_Primes.h ***/ #ifndef __JUCE_PRIMES_JUCEHEADER__ #define __JUCE_PRIMES_JUCEHEADER__ /*** Start of inlined file: juce_BigInteger.h ***/ #ifndef __JUCE_BIGINTEGER_JUCEHEADER__ #define __JUCE_BIGINTEGER_JUCEHEADER__ class MemoryBlock; /** An arbitrarily large integer class. A BigInteger can be used in a similar way to a normal integer, but has no size limit (except for memory and performance constraints). Negative values are possible, but the value isn't stored as 2s-complement, so be careful if you use negative values and look at the values of individual bits. */ class JUCE_API BigInteger { public: /** Creates an empty BigInteger */ BigInteger(); /** Creates a BigInteger containing an integer value in its low bits. The low 32 bits of the number are initialised with this value. */ BigInteger (uint32 value); /** Creates a BigInteger containing an integer value in its low bits. The low 32 bits of the number are initialised with the absolute value passed in, and its sign is set to reflect the sign of the number. */ BigInteger (int32 value); /** Creates a BigInteger containing an integer value in its low bits. The low 64 bits of the number are initialised with the absolute value passed in, and its sign is set to reflect the sign of the number. */ BigInteger (int64 value); /** Creates a copy of another BigInteger. */ BigInteger (const BigInteger& other); /** Destructor. */ ~BigInteger(); /** Copies another BigInteger onto this one. */ BigInteger& operator= (const BigInteger& other); /** Swaps the internal contents of this with another object. */ void swapWith (BigInteger& other) throw(); /** Returns the value of a specified bit in the number. If the index is out-of-range, the result will be false. */ bool operator[] (int bit) const throw(); /** Returns true if no bits are set. */ bool isZero() const throw(); /** Returns true if the value is 1. */ bool isOne() const throw(); /** Attempts to get the lowest bits of the value as an integer. If the value is bigger than the integer limits, this will return only the lower bits. */ int toInteger() const throw(); /** Resets the value to 0. */ void clear(); /** Clears a particular bit in the number. */ void clearBit (int bitNumber) throw(); /** Sets a specified bit to 1. */ void setBit (int bitNumber); /** Sets or clears a specified bit. */ void setBit (int bitNumber, bool shouldBeSet); /** Sets a range of bits to be either on or off. @param startBit the first bit to change @param numBits the number of bits to change @param shouldBeSet whether to turn these bits on or off */ void setRange (int startBit, int numBits, bool shouldBeSet); /** Inserts a bit an a given position, shifting up any bits above it. */ void insertBit (int bitNumber, bool shouldBeSet); /** Returns a range of bits as a new BigInteger. e.g. getBitRangeAsInt (0, 64) would return the lowest 64 bits. @see getBitRangeAsInt */ const BigInteger getBitRange (int startBit, int numBits) const; /** Returns a range of bits as an integer value. e.g. getBitRangeAsInt (0, 32) would return the lowest 32 bits. Asking for more than 32 bits isn't allowed (obviously) - for that, use getBitRange(). */ int getBitRangeAsInt (int startBit, int numBits) const throw(); /** Sets a range of bits to an integer value. Copies the given integer onto a range of bits, starting at startBit, and using up to numBits of the available bits. */ void setBitRangeAsInt (int startBit, int numBits, uint32 valueToSet); /** Shifts a section of bits left or right. @param howManyBitsLeft how far to move the bits (+ve numbers shift it left, -ve numbers shift it right). @param startBit the first bit to affect - if this is > 0, only bits above that index will be affected. */ void shiftBits (int howManyBitsLeft, int startBit); /** Returns the total number of set bits in the value. */ int countNumberOfSetBits() const throw(); /** Looks for the index of the next set bit after a given starting point. This searches from startIndex (inclusive) upwards for the first set bit, and returns its index. If no set bits are found, it returns -1. */ int findNextSetBit (int startIndex = 0) const throw(); /** Looks for the index of the next clear bit after a given starting point. This searches from startIndex (inclusive) upwards for the first clear bit, and returns its index. */ int findNextClearBit (int startIndex = 0) const throw(); /** Returns the index of the highest set bit in the number. If the value is zero, this will return -1. */ int getHighestBit() const throw(); // All the standard arithmetic ops... BigInteger& operator+= (const BigInteger& other); BigInteger& operator-= (const BigInteger& other); BigInteger& operator*= (const BigInteger& other); BigInteger& operator/= (const BigInteger& other); BigInteger& operator|= (const BigInteger& other); BigInteger& operator&= (const BigInteger& other); BigInteger& operator^= (const BigInteger& other); BigInteger& operator%= (const BigInteger& other); BigInteger& operator<<= (int numBitsToShift); BigInteger& operator>>= (int numBitsToShift); BigInteger& operator++(); BigInteger& operator--(); const BigInteger operator++ (int); const BigInteger operator-- (int); const BigInteger operator-() const; const BigInteger operator+ (const BigInteger& other) const; const BigInteger operator- (const BigInteger& other) const; const BigInteger operator* (const BigInteger& other) const; const BigInteger operator/ (const BigInteger& other) const; const BigInteger operator| (const BigInteger& other) const; const BigInteger operator& (const BigInteger& other) const; const BigInteger operator^ (const BigInteger& other) const; const BigInteger operator% (const BigInteger& other) const; const BigInteger operator<< (int numBitsToShift) const; const BigInteger operator>> (int numBitsToShift) const; bool operator== (const BigInteger& other) const throw(); bool operator!= (const BigInteger& other) const throw(); bool operator< (const BigInteger& other) const throw(); bool operator<= (const BigInteger& other) const throw(); bool operator> (const BigInteger& other) const throw(); bool operator>= (const BigInteger& other) const throw(); /** Does a signed comparison of two BigIntegers. Return values are: - 0 if the numbers are the same - < 0 if this number is smaller than the other - > 0 if this number is bigger than the other */ int compare (const BigInteger& other) const throw(); /** Compares the magnitudes of two BigIntegers, ignoring their signs. Return values are: - 0 if the numbers are the same - < 0 if this number is smaller than the other - > 0 if this number is bigger than the other */ int compareAbsolute (const BigInteger& other) const throw(); /** Divides this value by another one and returns the remainder. This number is divided by other, leaving the quotient in this number, with the remainder being copied to the other BigInteger passed in. */ void divideBy (const BigInteger& divisor, BigInteger& remainder); /** Returns the largest value that will divide both this value and the one passed-in. */ const BigInteger findGreatestCommonDivisor (BigInteger other) const; /** Performs a combined exponent and modulo operation. This BigInteger's value becomes (this ^ exponent) % modulus. */ void exponentModulo (const BigInteger& exponent, const BigInteger& modulus); /** Performs an inverse modulo on the value. i.e. the result is (this ^ -1) mod (modulus). */ void inverseModulo (const BigInteger& modulus); /** Returns true if the value is less than zero. @see setNegative, negate */ bool isNegative() const throw(); /** Changes the sign of the number to be positive or negative. @see isNegative, negate */ void setNegative (bool shouldBeNegative) throw(); /** Inverts the sign of the number. @see isNegative, setNegative */ void negate() throw(); /** Converts the number to a string. Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex). If minimumNumCharacters is greater than 0, the returned string will be padded with leading zeros to reach at least that length. */ const String toString (int base, int minimumNumCharacters = 1) const; /** Reads the numeric value from a string. Specify a base such as 2 (binary), 8 (octal), 10 (decimal), 16 (hex). Any invalid characters will be ignored. */ void parseString (const String& text, int base); /** Turns the number into a block of binary data. The data is arranged as little-endian, so the first byte of data is the low 8 bits of the number, and so on. @see loadFromMemoryBlock */ const MemoryBlock toMemoryBlock() const; /** Converts a block of raw data into a number. The data is arranged as little-endian, so the first byte of data is the low 8 bits of the number, and so on. @see toMemoryBlock */ void loadFromMemoryBlock (const MemoryBlock& data); private: HeapBlock values; int numValues, highestBit; bool negative; void ensureSize (int numVals); static const BigInteger simpleGCD (BigInteger* m, BigInteger* n); static inline int bitToIndex (const int bit) throw() { return bit >> 5; } static inline uint32 bitToMask (const int bit) throw() { return 1 << (bit & 31); } JUCE_LEAK_DETECTOR (BigInteger); }; /** Writes a BigInteger to an OutputStream as a UTF8 decimal string. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const BigInteger& value); #ifndef DOXYGEN // For backwards compatibility, BitArray is defined as an alias for BigInteger. typedef BigInteger BitArray; #endif #endif // __JUCE_BIGINTEGER_JUCEHEADER__ /*** End of inlined file: juce_BigInteger.h ***/ /** Prime number creation class. This class contains static methods for generating and testing prime numbers. @see BigInteger */ class JUCE_API Primes { public: /** Creates a random prime number with a given bit-length. The certainty parameter specifies how many iterations to use when testing for primality. A safe value might be anything over about 20-30. The randomSeeds parameter lets you optionally pass it a set of values with which to seed the random number generation, improving the security of the keys generated. */ static const BigInteger createProbablePrime (int bitLength, int certainty, const int* randomSeeds = 0, int numRandomSeeds = 0); /** Tests a number to see if it's prime. This isn't a bulletproof test, it uses a Miller-Rabin test to determine whether the number is prime. The certainty parameter specifies how many iterations to use when testing - a safe value might be anything over about 20-30. */ static bool isProbablyPrime (const BigInteger& number, int certainty); private: Primes(); JUCE_DECLARE_NON_COPYABLE (Primes); }; #endif // __JUCE_PRIMES_JUCEHEADER__ /*** End of inlined file: juce_Primes.h ***/ #endif #ifndef __JUCE_RSAKEY_JUCEHEADER__ /*** Start of inlined file: juce_RSAKey.h ***/ #ifndef __JUCE_RSAKEY_JUCEHEADER__ #define __JUCE_RSAKEY_JUCEHEADER__ /** RSA public/private key-pair encryption class. An object of this type makes up one half of a public/private RSA key pair. Use the createKeyPair() method to create a matching pair for encoding/decoding. */ class JUCE_API RSAKey { public: /** Creates a null key object. Initialise a pair of objects for use with the createKeyPair() method. */ RSAKey(); /** Loads a key from an encoded string representation. This reloads a key from a string created by the toString() method. */ explicit RSAKey (const String& stringRepresentation); /** Destructor. */ ~RSAKey(); bool operator== (const RSAKey& other) const throw(); bool operator!= (const RSAKey& other) const throw(); /** Turns the key into a string representation. This can be reloaded using the constructor that takes a string. */ const String toString() const; /** Encodes or decodes a value. Call this on the public key object to encode some data, then use the matching private key object to decode it. Returns false if the operation couldn't be completed, e.g. if this key hasn't been initialised correctly. NOTE: This method dumbly applies this key to this data. If you encode some data and then try to decode it with a key that doesn't match, this method will still happily do its job and return true, but the result won't be what you were expecting. It's your responsibility to check that the result is what you wanted. */ bool applyToValue (BigInteger& value) const; /** Creates a public/private key-pair. Each key will perform one-way encryption that can only be reversed by using the other key. The numBits parameter specifies the size of key, e.g. 128, 256, 512 bit. Bigger sizes are more secure, but this method will take longer to execute. The randomSeeds parameter lets you optionally pass it a set of values with which to seed the random number generation, improving the security of the keys generated. If you supply these, make sure you provide more than 2 values, and the more your provide, the better the security. */ static void createKeyPair (RSAKey& publicKey, RSAKey& privateKey, int numBits, const int* randomSeeds = 0, int numRandomSeeds = 0); protected: BigInteger part1, part2; private: static const BigInteger findBestCommonDivisor (const BigInteger& p, const BigInteger& q); JUCE_LEAK_DETECTOR (RSAKey); }; #endif // __JUCE_RSAKEY_JUCEHEADER__ /*** End of inlined file: juce_RSAKey.h ***/ #endif #ifndef __JUCE_DIRECTORYITERATOR_JUCEHEADER__ /*** Start of inlined file: juce_DirectoryIterator.h ***/ #ifndef __JUCE_DIRECTORYITERATOR_JUCEHEADER__ #define __JUCE_DIRECTORYITERATOR_JUCEHEADER__ /** Searches through a the files in a directory, returning each file that is found. A DirectoryIterator will search through a directory and its subdirectories using a wildcard filepattern match. If you may be finding a large number of files, this is better than using File::findChildFiles() because it doesn't block while it finds them all, and this is more memory-efficient. It can also guess how far it's got using a wildly inaccurate algorithm. */ class JUCE_API DirectoryIterator { public: /** Creates a DirectoryIterator for a given directory. After creating one of these, call its next() method to get the first file - e.g. @code DirectoryIterator iter (File ("/animals/mooses"), true, "*.moose"); while (iter.next()) { File theFileItFound (iter.getFile()); ... etc } @endcode @param directory the directory to search in @param isRecursive whether all the subdirectories should also be searched @param wildCard the file pattern to match @param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to look for files, directories, or both. */ DirectoryIterator (const File& directory, bool isRecursive, const String& wildCard = "*", int whatToLookFor = File::findFiles); /** Destructor. */ ~DirectoryIterator(); /** Moves the iterator along to the next file. @returns true if a file was found (you can then use getFile() to see what it was) - or false if there are no more matching files. */ bool next(); /** Moves the iterator along to the next file, and returns various properties of that file. If you need to find out details about the file, it's more efficient to call this method than to call the normal next() method and then find out the details afterwards. All the parameters are optional, so pass null pointers for any items that you're not interested in. @returns true if a file was found (you can then use getFile() to see what it was) - or false if there are no more matching files. If it returns false, then none of the parameters will be filled-in. */ bool next (bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly); /** Returns the file that the iterator is currently pointing at. The result of this call is only valid after a call to next() has returned true. */ const File getFile() const; /** Returns a guess of how far through the search the iterator has got. @returns a value 0.0 to 1.0 to show the progress, although this won't be very accurate. */ float getEstimatedProgress() const; private: class NativeIterator { public: NativeIterator (const File& directory, const String& wildCard); ~NativeIterator(); bool next (String& filenameFound, bool* isDirectory, bool* isHidden, int64* fileSize, Time* modTime, Time* creationTime, bool* isReadOnly); class Pimpl; private: friend class DirectoryIterator; friend class ScopedPointer; ScopedPointer pimpl; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeIterator); }; friend class ScopedPointer; NativeIterator fileFinder; String wildCard, path; int index; mutable int totalNumFiles; const int whatToLookFor; const bool isRecursive; bool hasBeenAdvanced; ScopedPointer subIterator; File currentFile; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryIterator); }; #endif // __JUCE_DIRECTORYITERATOR_JUCEHEADER__ /*** End of inlined file: juce_DirectoryIterator.h ***/ #endif #ifndef __JUCE_FILE_JUCEHEADER__ #endif #ifndef __JUCE_FILEINPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_FileInputStream.h ***/ #ifndef __JUCE_FILEINPUTSTREAM_JUCEHEADER__ #define __JUCE_FILEINPUTSTREAM_JUCEHEADER__ /** An input stream that reads from a local file. @see InputStream, FileOutputStream, File::createInputStream */ class JUCE_API FileInputStream : public InputStream { public: /** Creates a FileInputStream. @param fileToRead the file to read from - if the file can't be accessed for some reason, then the stream will just contain no data */ explicit FileInputStream (const File& fileToRead); /** Destructor. */ ~FileInputStream(); const File& getFile() const throw() { return file; } int64 getTotalLength(); int read (void* destBuffer, int maxBytesToRead); bool isExhausted(); int64 getPosition(); bool setPosition (int64 pos); private: File file; void* fileHandle; int64 currentPosition, totalSize; bool needToSeek; void openHandle(); void closeHandle(); size_t readInternal (void* buffer, size_t numBytes); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputStream); }; #endif // __JUCE_FILEINPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_FileInputStream.h ***/ #endif #ifndef __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_FileOutputStream.h ***/ #ifndef __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ #define __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ /** An output stream that writes into a local file. @see OutputStream, FileInputStream, File::createOutputStream */ class JUCE_API FileOutputStream : public OutputStream { public: /** Creates a FileOutputStream. If the file doesn't exist, it will first be created. If the file can't be created or opened, the failedToOpen() method will return true. If the file already exists when opened, the stream's write-postion will be set to the end of the file. To overwrite an existing file, use File::deleteFile() before opening the stream, or use setPosition(0) 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 */ FileOutputStream (const File& fileToWriteTo, int bufferSizeToUse = 16384); /** Destructor. */ ~FileOutputStream(); /** Returns the file that this stream is writing to. */ const File& getFile() const { return file; } /** Returns true if the stream couldn't be opened for some reason. */ bool failedToOpen() const { return fileHandle == 0; } void flush(); int64 getPosition(); bool setPosition (int64 pos); bool write (const void* data, int numBytes); private: File file; void* fileHandle; int64 currentPosition; int bufferSize, bytesInBuffer; HeapBlock buffer; void openHandle(); void closeHandle(); void flushInternal(); int64 setPositionInternal (int64 newPosition); int writeInternal (const void* data, int numBytes); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileOutputStream); }; #endif // __JUCE_FILEOUTPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_FileOutputStream.h ***/ #endif #ifndef __JUCE_FILESEARCHPATH_JUCEHEADER__ /*** Start of inlined file: juce_FileSearchPath.h ***/ #ifndef __JUCE_FILESEARCHPATH_JUCEHEADER__ #define __JUCE_FILESEARCHPATH_JUCEHEADER__ /** Encapsulates a set of folders that make up a search path. @see File */ class JUCE_API FileSearchPath { public: /** Creates an empty search path. */ FileSearchPath(); /** Creates a search path from a string of pathnames. The path can be semicolon- or comma-separated, e.g. "/foo/bar;/foo/moose;/fish/moose" The separate folders are tokenised and added to the search path. */ FileSearchPath (const String& path); /** Creates a copy of another search path. */ FileSearchPath (const FileSearchPath& other); /** Destructor. */ ~FileSearchPath(); /** Uses a string containing a list of pathnames to re-initialise this list. This search path is cleared and the semicolon- or comma-separated folders in this string are added instead. e.g. "/foo/bar;/foo/moose;/fish/moose" */ FileSearchPath& operator= (const String& path); /** Returns the number of folders in this search path. @see operator[] */ int getNumPaths() const; /** Returns one of the folders in this search path. The file returned isn't guaranteed to actually be a valid directory. @see getNumPaths */ const File operator[] (int index) const; /** Returns the search path as a semicolon-separated list of directories. */ const String toString() const; /** Adds a new directory to the search path. The new directory is added to the end of the list if the insertIndex parameter is less than zero, otherwise it is inserted at the given index. */ void add (const File& directoryToAdd, int insertIndex = -1); /** Adds a new directory to the search path if it's not already in there. */ void addIfNotAlreadyThere (const File& directoryToAdd); /** Removes a directory from the search path. */ void remove (int indexToRemove); /** Merges another search path into this one. This will remove any duplicate directories. */ void addPath (const FileSearchPath& other); /** Removes any directories that are actually subdirectories of one of the other directories in the search path. If the search is intended to be recursive, there's no point having nested folders in the search path, because they'll just get searched twice and you'll get duplicate results. e.g. if the path is "c:\abc\de;c:\abc", this method will simplify it to "c:\abc" */ void removeRedundantPaths(); /** Removes any directories that don't actually exist. */ void removeNonExistentPaths(); /** Searches the path for a wildcard. This will search all the directories in the search path in order, adding any matching files to the results array. @param results an array to append the results to @param whatToLookFor a value from the File::TypesOfFileToFind enum, specifying whether to return files, directories, or both. @param searchRecursively whether to recursively search the subdirectories too @param wildCardPattern a pattern to match against the filenames @returns the number of files added to the array @see File::findChildFiles */ int findChildFiles (Array& results, int whatToLookFor, bool searchRecursively, const String& wildCardPattern = "*") const; /** Finds out whether a file is inside one of the path's directories. This will return true if the specified file is a child of one of the directories specified by this path. Note that this doesn't actually do any searching or check that the files exist - it just looks at the pathnames to work out whether the file would be inside a directory. @param fileToCheck the file to look for @param checkRecursively if true, then this will return true if the file is inside a subfolder of one of the path's directories (at any depth). If false it will only return true if the file is actually a direct child of one of the directories. @see File::isAChildOf */ bool isFileInPath (const File& fileToCheck, bool checkRecursively) const; private: StringArray directories; void init (const String& path); JUCE_LEAK_DETECTOR (FileSearchPath); }; #endif // __JUCE_FILESEARCHPATH_JUCEHEADER__ /*** End of inlined file: juce_FileSearchPath.h ***/ #endif #ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ /*** Start of inlined file: juce_NamedPipe.h ***/ #ifndef __JUCE_NAMEDPIPE_JUCEHEADER__ #define __JUCE_NAMEDPIPE_JUCEHEADER__ /** A cross-process pipe that can have data written to and read from it. Two or more processes can use these for inter-process communication. @see InterprocessConnection */ class JUCE_API NamedPipe { public: /** Creates a NamedPipe. */ NamedPipe(); /** Destructor. */ ~NamedPipe(); /** Tries to open a pipe that already exists. Returns true if it succeeds. */ bool openExisting (const String& pipeName); /** Tries to create a new pipe. Returns true if it succeeds. */ bool createNewPipe (const String& pipeName); /** Closes the pipe, if it's open. */ void close(); /** True if the pipe is currently open. */ bool isOpen() const; /** Returns the last name that was used to try to open this pipe. */ const String getName() const; /** Reads data from the pipe. This will block until another thread has written enough data into the pipe to fill the number of bytes specified, or until another thread calls the cancelPendingReads() method. If the operation fails, it returns -1, otherwise, it will return the number of bytes read. If timeOutMilliseconds is less than zero, it will wait indefinitely, otherwise this is a maximum timeout for reading from the pipe. */ int read (void* destBuffer, int maxBytesToRead, int timeOutMilliseconds = 5000); /** Writes some data to the pipe. If the operation fails, it returns -1, otherwise, it will return the number of bytes written. */ int write (const void* sourceBuffer, int numBytesToWrite, int timeOutMilliseconds = 2000); /** If any threads are currently blocked on a read operation, this tells them to abort. */ void cancelPendingReads(); private: void* internal; String currentPipeName; CriticalSection lock; bool openInternal (const String& pipeName, const bool createPipe); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NamedPipe); }; #endif // __JUCE_NAMEDPIPE_JUCEHEADER__ /*** End of inlined file: juce_NamedPipe.h ***/ #endif #ifndef __JUCE_TEMPORARYFILE_JUCEHEADER__ /*** Start of inlined file: juce_TemporaryFile.h ***/ #ifndef __JUCE_TEMPORARYFILE_JUCEHEADER__ #define __JUCE_TEMPORARYFILE_JUCEHEADER__ /** Manages a temporary file, which will be deleted when this object is deleted. This object is intended to be used as a stack based object, using its scope to make sure the temporary file isn't left lying around. For example: @code { File myTargetFile ("~/myfile.txt"); // this will choose a file called something like "~/myfile_temp239348.txt" // which definitely doesn't exist at the time the constructor is called. TemporaryFile temp (myTargetFile); // create a stream to the temporary file, and write some data to it... ScopedPointer out (temp.getFile().createOutputStream()); if (out != 0) { out->write ( ...etc ) out->flush(); out = 0; // (deletes the stream) // ..now we've finished writing, this will rename the temp file to // make it replace the target file we specified above. bool succeeded = temp.overwriteTargetFileWithTemporary(); } // ..and even if something went wrong and our overwrite failed, // as the TemporaryFile object goes out of scope here, it'll make sure // that the temp file gets deleted. } @endcode @see File, FileOutputStream */ class JUCE_API TemporaryFile { public: enum OptionFlags { useHiddenFile = 1, /**< Indicates that the temporary file should be hidden - i.e. its name should start with a dot. */ putNumbersInBrackets = 2 /**< Indicates that when numbers are appended to make sure the file is unique, they should go in brackets rather than just being appended (see File::getNonexistentSibling() )*/ }; /** Creates a randomly-named temporary file in the default temp directory. @param suffix a file suffix to use for the file @param optionFlags a combination of the values listed in the OptionFlags enum The file will not be created until you write to it. And remember that when this object is deleted, the file will also be deleted! */ TemporaryFile (const String& suffix = String::empty, int optionFlags = 0); /** Creates a temporary file in the same directory as a specified file. This is useful if you have a file that you want to overwrite, but don't want to harm the original file if the write operation fails. You can use this to create a temporary file next to the target file, then write to the temporary file, and finally use overwriteTargetFileWithTemporary() to replace the target file with the one you've just written. This class won't create any files until you actually write to them. And remember that when this object is deleted, the temporary file will also be deleted! @param targetFile the file that you intend to overwrite - the temporary file will be created in the same directory as this @param optionFlags a combination of the values listed in the OptionFlags enum */ TemporaryFile (const File& targetFile, int optionFlags = 0); /** Destructor. When this object is deleted it will make sure that its temporary file is also deleted! If the operation fails, it'll throw an assertion in debug mode. */ ~TemporaryFile(); /** Returns the temporary file. */ const File getFile() const { return temporaryFile; } /** Returns the target file that was specified in the constructor. */ const File getTargetFile() const { return targetFile; } /** Tries to move the temporary file to overwrite the target file that was specified in the constructor. If you used the constructor that specified a target file, this will attempt to replace that file with the temporary one. Before calling this, make sure: - that you've actually written to the temporary file - that you've closed any open streams that you were using to write to it - and that you don't have any streams open to the target file, which would prevent it being overwritten If the file move succeeds, this returns false, and the temporary file will have disappeared. If it fails, the temporary file will probably still exist, but will be deleted when this object is destroyed. */ bool overwriteTargetFileWithTemporary() const; /** Attempts to delete the temporary file, if it exists. @returns true if the file is successfully deleted (or if it didn't exist). */ bool deleteTemporaryFile() const; private: File temporaryFile, targetFile; void createTempFile (const File& parentDirectory, String name, const String& suffix, int optionFlags); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TemporaryFile); }; #endif // __JUCE_TEMPORARYFILE_JUCEHEADER__ /*** End of inlined file: juce_TemporaryFile.h ***/ #endif #ifndef __JUCE_ZIPFILE_JUCEHEADER__ /*** Start of inlined file: juce_ZipFile.h ***/ #ifndef __JUCE_ZIPFILE_JUCEHEADER__ #define __JUCE_ZIPFILE_JUCEHEADER__ /*** Start of inlined file: juce_InputSource.h ***/ #ifndef __JUCE_INPUTSOURCE_JUCEHEADER__ #define __JUCE_INPUTSOURCE_JUCEHEADER__ /** A lightweight object that can create a stream to read some kind of resource. This may be used to refer to a file, or some other kind of source, allowing a caller to create an input stream that can read from it when required. @see FileInputSource */ class JUCE_API InputSource { public: InputSource() throw() {} /** Destructor. */ virtual ~InputSource() {} /** Returns a new InputStream to read this item. @returns an inputstream that the caller will delete, or 0 if the filename isn't found. */ virtual InputStream* createInputStream() = 0; /** Returns a new InputStream to read an item, relative. @param relatedItemPath the relative pathname of the resource that is required @returns an inputstream that the caller will delete, or 0 if the item isn't found. */ virtual InputStream* createInputStreamFor (const String& relatedItemPath) = 0; /** Returns a hash code that uniquely represents this item. */ virtual int64 hashCode() const = 0; private: JUCE_LEAK_DETECTOR (InputSource); }; #endif // __JUCE_INPUTSOURCE_JUCEHEADER__ /*** End of inlined file: juce_InputSource.h ***/ /** Decodes a ZIP file from a stream. This can enumerate the items in a ZIP file and can create suitable stream objects to read each one. */ class JUCE_API ZipFile { public: /** Creates a ZipFile for a given stream. @param inputStream the stream to read from @param deleteStreamWhenDestroyed if set to true, the object passed-in will be deleted when this ZipFile object is deleted */ ZipFile (InputStream* inputStream, bool deleteStreamWhenDestroyed); /** Creates a ZipFile based for a file. */ ZipFile (const File& file); /** Creates a ZipFile for an input source. The inputSource object will be owned by the zip file, which will delete it later when not needed. */ ZipFile (InputSource* inputSource); /** Destructor. */ ~ZipFile(); /** Contains information about one of the entries in a ZipFile. @see ZipFile::getEntry */ struct ZipEntry { /** The name of the file, which may also include a partial pathname. */ String filename; /** The file's original size. */ unsigned int uncompressedSize; /** The last time the file was modified. */ Time fileTime; }; /** Returns the number of items in the zip file. */ int getNumEntries() const throw(); /** Returns a structure that describes one of the entries in the zip file. This may return zero if the index is out of range. @see ZipFile::ZipEntry */ const ZipEntry* getEntry (int index) const throw(); /** Returns the index of the first entry with a given filename. This uses a case-sensitive comparison to look for a filename in the list of entries. It might return -1 if no match is found. @see ZipFile::ZipEntry */ int getIndexOfFileName (const String& fileName) const throw(); /** Returns a structure that describes one of the entries in the zip file. This uses a case-sensitive comparison to look for a filename in the list of entries. It might return 0 if no match is found. @see ZipFile::ZipEntry */ const ZipEntry* getEntry (const String& fileName) const throw(); /** Sorts the list of entries, based on the filename. */ void sortEntriesByFilename(); /** Creates a stream that can read from one of the zip file's entries. The stream that is returned must be deleted by the caller (and zero might be returned if a stream can't be opened for some reason). The stream must not be used after the ZipFile object that created has been deleted. */ InputStream* createStreamForEntry (int index); /** Creates a stream that can read from one of the zip file's entries. The stream that is returned must be deleted by the caller (and zero might be returned if a stream can't be opened for some reason). The stream must not be used after the ZipFile object that created has been deleted. */ InputStream* createStreamForEntry (ZipEntry& entry); /** Uncompresses all of the files in the zip file. This will expand all the entries into a target directory. The relative paths of the entries are used. @param targetDirectory the root folder to uncompress to @param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones @returns true if all the files are successfully unzipped */ bool uncompressTo (const File& targetDirectory, bool shouldOverwriteFiles = true); /** 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 determine which subfolder of the target should contain the new file. @param index the index of the entry to uncompress @param targetDirectory the root folder to uncompress into @param shouldOverwriteFiles whether to overwrite existing files with similarly-named ones @returns true if the files is successfully unzipped */ bool uncompressEntry (int index, const File& targetDirectory, bool shouldOverwriteFiles = true); private: class ZipInputStream; class ZipFilenameComparator; class ZipEntryInfo; friend class ZipInputStream; friend class ZipFilenameComparator; friend class ZipEntryInfo; OwnedArray entries; CriticalSection lock; InputStream* inputStream; ScopedPointer streamToDelete; ScopedPointer inputSource; #if JUCE_DEBUG int numOpenStreams; #endif void init(); int findEndOfZipEntryTable (InputStream& input, int& numEntries); static int compareElements (const ZipEntryInfo* first, const ZipEntryInfo* second); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ZipFile); }; #endif // __JUCE_ZIPFILE_JUCEHEADER__ /*** End of inlined file: juce_ZipFile.h ***/ #endif #ifndef __JUCE_MACADDRESS_JUCEHEADER__ /*** Start of inlined file: juce_MACAddress.h ***/ #ifndef __JUCE_MACADDRESS_JUCEHEADER__ #define __JUCE_MACADDRESS_JUCEHEADER__ /** A wrapper for a streaming (TCP) socket. This allows low-level use of sockets; for an easier-to-use messaging layer on top of sockets, you could also try the InterprocessConnection class. @see DatagramSocket, InterprocessConnection, InterprocessConnectionServer */ class JUCE_API MACAddress { public: /** Populates a list of the MAC addresses of all the available network cards. */ static void findAllAddresses (Array& results); /** Creates a null address (00-00-00-00-00-00). */ MACAddress(); /** Creates a copy of another address. */ MACAddress (const MACAddress& other); /** Creates a copy of another address. */ MACAddress& operator= (const MACAddress& other); /** Creates an address from 6 bytes. */ explicit MACAddress (const uint8 bytes[6]); /** Returns a pointer to the 6 bytes that make up this address. */ const uint8* getBytes() const throw() { return asBytes; } /** Returns a dash-separated string in the form "11-22-33-44-55-66" */ const String toString() const; /** Returns the address in the lower 6 bytes of an int64. This uses a little-endian arrangement, with the first byte of the address being stored in the least-significant byte of the result value. */ int64 toInt64() const throw(); /** Returns true if this address is null (00-00-00-00-00-00). */ bool isNull() const throw(); bool operator== (const MACAddress& other) const throw(); bool operator!= (const MACAddress& other) const throw(); private: #ifndef DOXYGEN union { uint64 asInt64; uint8 asBytes[6]; }; #endif }; #endif // __JUCE_MACADDRESS_JUCEHEADER__ /*** End of inlined file: juce_MACAddress.h ***/ #endif #ifndef __JUCE_SOCKET_JUCEHEADER__ /*** Start of inlined file: juce_Socket.h ***/ #ifndef __JUCE_SOCKET_JUCEHEADER__ #define __JUCE_SOCKET_JUCEHEADER__ /** A wrapper for a streaming (TCP) socket. This allows low-level use of sockets; for an easier-to-use messaging layer on top of sockets, you could also try the InterprocessConnection class. @see DatagramSocket, InterprocessConnection, InterprocessConnectionServer */ class JUCE_API StreamingSocket { public: /** Creates an uninitialised socket. To connect it, use the connect() method, after which you can read() or write() to it. To wait for other sockets to connect to this one, the createListener() method enters "listener" mode, and can be used to spawn new sockets for each connection that comes along. */ StreamingSocket(); /** Destructor. */ ~StreamingSocket(); /** Binds the socket to the specified local port. @returns true on success; false may indicate that another socket is already bound on the same port */ bool bindToPort (int localPortNumber); /** Tries to connect the socket to hostname:port. If timeOutMillisecs is 0, then this method will block until the operating system rejects the connection (which could take a long time). @returns true if it succeeds. @see isConnected */ bool connect (const String& remoteHostname, int remotePortNumber, int timeOutMillisecs = 3000); /** True if the socket is currently connected. */ bool isConnected() const throw() { return connected; } /** Closes the connection. */ void close(); /** Returns the name of the currently connected host. */ const String& getHostName() const throw() { return hostName; } /** Returns the port number that's currently open. */ int getPort() const throw() { return portNumber; } /** True if the socket is connected to this machine rather than over the network. */ bool isLocal() const throw(); /** Waits until the socket is ready for reading or writing. If readyForReading is true, it will wait until the socket is ready for reading; if false, it will wait until it's ready for writing. If the timeout is < 0, it will wait forever, or else will give up after the specified time. If the socket is ready on return, this returns 1. If it times-out before the socket becomes ready, it returns 0. If an error occurs, it returns -1. */ int waitUntilReady (bool readyForReading, int timeoutMsecs) const; /** Reads bytes from the socket. If blockUntilSpecifiedAmountHasArrived is true, the method will block until maxBytesToRead bytes have been read, (or until an error occurs). If this flag is false, the method will return as much data as is currently available without blocking. @returns the number of bytes read, or -1 if there was an error. @see waitUntilReady */ int read (void* destBuffer, int maxBytesToRead, bool blockUntilSpecifiedAmountHasArrived); /** Writes bytes to the socket from a buffer. Note that this method will block unless you have checked the socket is ready for writing before calling it (see the waitUntilReady() method). @returns the number of bytes written, or -1 if there was an error. */ int write (const void* sourceBuffer, int numBytesToWrite); /** Puts this socket into "listener" mode. When in this mode, your thread can call waitForNextConnection() repeatedly, which will spawn new sockets for each new connection, so that these can be handled in parallel by other threads. @param portNumber the port number to listen on @param localHostName the interface address to listen on - pass an empty string to listen on all addresses @returns true if it manages to open the socket successfully. @see waitForNextConnection */ bool createListener (int portNumber, const String& localHostName = String::empty); /** When in "listener" mode, this waits for a connection and spawns it as a new socket. The object that gets returned will be owned by the caller. This method can only be called after using createListener(). @see createListener */ StreamingSocket* waitForNextConnection() const; private: String hostName; int volatile portNumber, handle; bool connected, isListener; StreamingSocket (const String& hostname, int portNumber, int handle); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StreamingSocket); }; /** A wrapper for a datagram (UDP) socket. This allows low-level use of sockets; for an easier-to-use messaging layer on top of sockets, you could also try the InterprocessConnection class. @see StreamingSocket, InterprocessConnection, InterprocessConnectionServer */ class JUCE_API DatagramSocket { public: /** Creates an (uninitialised) datagram socket. The localPortNumber is the port on which to bind this socket. If this value is 0, the port number is assigned by the operating system. To use the socket for sending, call the connect() method. This will not immediately make a connection, but will save the destination you've provided. After this, you can call read() or write(). If enableBroadcasting is true, the socket will be allowed to send broadcast messages (may require extra privileges on linux) To wait for other sockets to connect to this one, call waitForNextConnection(). */ DatagramSocket (int localPortNumber, bool enableBroadcasting = false); /** Destructor. */ ~DatagramSocket(); /** Binds the socket to the specified local port. @returns true on success; false may indicate that another socket is already bound on the same port */ bool bindToPort (int localPortNumber); /** Tries to connect the socket to hostname:port. If timeOutMillisecs is 0, then this method will block until the operating system rejects the connection (which could take a long time). @returns true if it succeeds. @see isConnected */ bool connect (const String& remoteHostname, int remotePortNumber, int timeOutMillisecs = 3000); /** True if the socket is currently connected. */ bool isConnected() const throw() { return connected; } /** Closes the connection. */ void close(); /** Returns the name of the currently connected host. */ const String& getHostName() const throw() { return hostName; } /** Returns the port number that's currently open. */ int getPort() const throw() { return portNumber; } /** True if the socket is connected to this machine rather than over the network. */ bool isLocal() const throw(); /** Waits until the socket is ready for reading or writing. If readyForReading is true, it will wait until the socket is ready for reading; if false, it will wait until it's ready for writing. If the timeout is < 0, it will wait forever, or else will give up after the specified time. If the socket is ready on return, this returns 1. If it times-out before the socket becomes ready, it returns 0. If an error occurs, it returns -1. */ int waitUntilReady (bool readyForReading, int timeoutMsecs) const; /** Reads bytes from the socket. If blockUntilSpecifiedAmountHasArrived is true, the method will block until maxBytesToRead bytes have been read, (or until an error occurs). If this flag is false, the method will return as much data as is currently available without blocking. @returns the number of bytes read, or -1 if there was an error. @see waitUntilReady */ int read (void* destBuffer, int maxBytesToRead, bool blockUntilSpecifiedAmountHasArrived); /** Writes bytes to the socket from a buffer. Note that this method will block unless you have checked the socket is ready for writing before calling it (see the waitUntilReady() method). @returns the number of bytes written, or -1 if there was an error. */ int write (const void* sourceBuffer, int numBytesToWrite); /** This waits for incoming data to be sent, and returns a socket that can be used to read it. The object that gets returned is owned by the caller, and can't be used for sending, but can be used to read the data. */ DatagramSocket* waitForNextConnection() const; private: String hostName; int volatile portNumber, handle; bool connected, allowBroadcast; void* serverAddress; DatagramSocket (const String& hostname, int portNumber, int handle, int localPortNumber); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DatagramSocket); }; #endif // __JUCE_SOCKET_JUCEHEADER__ /*** End of inlined file: juce_Socket.h ***/ #endif #ifndef __JUCE_URL_JUCEHEADER__ /*** Start of inlined file: juce_URL.h ***/ #ifndef __JUCE_URL_JUCEHEADER__ #define __JUCE_URL_JUCEHEADER__ /** Represents a URL and has a bunch of useful functions to manipulate it. This class can be used to launch URLs in browsers, and also to create InputStreams that can read from remote http or ftp sources. */ class JUCE_API URL { public: /** Creates an empty URL. */ URL(); /** Creates a URL from a string. */ URL (const String& url); /** Creates a copy of another URL. */ URL (const URL& other); /** Destructor. */ ~URL(); /** Copies this URL from another one. */ URL& operator= (const URL& other); /** Returns a string version of the URL. If includeGetParameters is true and any parameters have been set with the withParameter() method, then the string will have these appended on the end and url-encoded. */ const String toString (bool includeGetParameters) const; /** True if it seems to be valid. */ bool isWellFormed() const; /** Returns just the domain part of the URL. E.g. for "http://www.xyz.com/foobar", this will return "www.xyz.com". */ const String getDomain() const; /** Returns the path part of the URL. E.g. for "http://www.xyz.com/foo/bar?x=1", this will return "foo/bar". */ const String getSubPath() const; /** Returns the scheme of the URL. E.g. for "http://www.xyz.com/foobar", this will return "http". (It won't include the colon). */ const String getScheme() const; /** Returns a new version of this URL that uses a different sub-path. E.g. if the URL is "http://www.xyz.com/foo?x=1" and you call this with "bar", it'll return "http://www.xyz.com/bar?x=1". */ const URL withNewSubPath (const String& newPath) const; /** Returns a copy of this URL, with a GET or POST parameter added to the end. Any control characters in the value will be encoded. e.g. calling "withParameter ("amount", "some fish") for the url "www.fish.com" would produce a new url whose toString(true) method would return "www.fish.com?amount=some+fish". */ const URL withParameter (const String& parameterName, const String& parameterValue) const; /** Returns a copy of this URl, with a file-upload type parameter added to it. When performing a POST where one of your parameters is a binary file, this lets you specify the file. Note that the filename is stored, but the file itself won't actually be read until this URL is later used to create a network input stream. */ const URL withFileToUpload (const String& parameterName, const File& fileToUpload, const String& mimeType) const; /** Returns a set of all the parameters encoded into the url. E.g. for the url "www.fish.com?type=haddock&amount=some+fish", this array would contain two pairs: "type" => "haddock" and "amount" => "some fish". The values returned will have been cleaned up to remove any escape characters. @see getNamedParameter, withParameter */ const StringPairArray& getParameters() const; /** Returns the set of files that should be uploaded as part of a POST operation. This is the set of files that were added to the URL with the withFileToUpload() method. */ const StringPairArray& getFilesToUpload() const; /** Returns the set of mime types associated with each of the upload files. */ const StringPairArray& getMimeTypesOfUploadFiles() const; /** Returns a copy of this URL, with a block of data to send as the POST data. If you're setting the POST data, be careful not to have any parameters set as well, otherwise it'll all get thrown in together, and might not have the desired effect. If the URL already contains some POST data, this will replace it, rather than being appended to it. This data will only be used if you specify a post operation when you call createInputStream(). */ const URL withPOSTData (const String& postData) const; /** Returns the data that was set using withPOSTData(). */ const String getPostData() const { return postData; } /** Tries to launch the system's default browser to open the URL. Returns true if this seems to have worked. */ bool launchInDefaultBrowser() const; /** Takes a guess as to whether a string might be a valid website address. This isn't foolproof! */ static bool isProbablyAWebsiteURL (const String& possibleURL); /** Takes a guess as to whether a string might be a valid email address. This isn't foolproof! */ static bool isProbablyAnEmailAddress (const String& possibleEmailAddress); /** This callback function can be used by the createInputStream() method. It allows your app to receive progress updates during a lengthy POST operation. If you want to continue the operation, this should return true, or false to abort. */ typedef bool (OpenStreamProgressCallback) (void* context, int bytesSent, int totalBytes); /** Attempts to open a stream that can read from this URL. @param usePostCommand if true, it will try to do use a http 'POST' to pass the paramters, otherwise it'll encode them into the URL and do a 'GET'. @param progressCallback if this is non-zero, it lets you supply a callback function to keep track of the operation's progress. This can be useful for lengthy POST operations, so that you can provide user feedback. @param progressCallbackContext if a callback is specified, this value will be passed to the function @param extraHeaders if not empty, this string is appended onto the headers that are used for the request. It must therefore be a valid set of HTML header directives, separated by newlines. @param connectionTimeOutMs if 0, this will use whatever default setting the OS chooses. If a negative number, it will be infinite. Otherwise it specifies a time in milliseconds. @param responseHeaders if this is non-zero, all the (key, value) pairs received as headers in the response will be stored in this array @returns an input stream that the caller must delete, or a null pointer if there was an error trying to open it. */ InputStream* createInputStream (bool usePostCommand, OpenStreamProgressCallback* progressCallback = 0, void* progressCallbackContext = 0, const String& extraHeaders = String::empty, int connectionTimeOutMs = 0, StringPairArray* responseHeaders = 0) const; /** Tries to download the entire contents of this URL into a binary data block. If it succeeds, this will return true and append the data it read onto the end of the memory block. @param destData the memory block to append the new data to @param usePostCommand whether to use a POST command to get the data (uses a GET command if this is false) @see readEntireTextStream, readEntireXmlStream */ bool readEntireBinaryStream (MemoryBlock& destData, bool usePostCommand = false) const; /** Tries to download the entire contents of this URL as a string. If it fails, this will return an empty string, otherwise it will return the contents of the downloaded file. If you need to distinguish between a read operation that fails and one that returns an empty string, you'll need to use a different method, such as readEntireBinaryStream(). @param usePostCommand whether to use a POST command to get the data (uses a GET command if this is false) @see readEntireBinaryStream, readEntireXmlStream */ const String readEntireTextStream (bool usePostCommand = false) const; /** Tries to download the entire contents of this URL and parse it as XML. If it fails, or if the text that it reads can't be parsed as XML, this will return 0. When it returns a valid XmlElement object, the caller is responsibile for deleting this object when no longer needed. @param usePostCommand whether to use a POST command to get the data (uses a GET command if this is false) @see readEntireBinaryStream, readEntireTextStream */ XmlElement* readEntireXmlStream (bool usePostCommand = false) const; /** Adds escape sequences to a string to encode any characters that aren't legal in a URL. E.g. any spaces will be replaced with "%20". This is the opposite of removeEscapeChars(). If isParameter is true, it means that the string is going to be used as a parameter, so it also encodes '$' and ',' (which would otherwise be legal in a URL. @see removeEscapeChars */ static const String addEscapeChars (const String& stringToAddEscapeCharsTo, bool isParameter); /** Replaces any escape character sequences in a string with their original character codes. E.g. any instances of "%20" will be replaced by a space. This is the opposite of addEscapeChars(). @see addEscapeChars */ static const String removeEscapeChars (const String& stringToRemoveEscapeCharsFrom); private: String url, postData; StringPairArray parameters, filesToUpload, mimeTypes; static InputStream* createNativeStream (const String& address, bool isPost, const MemoryBlock& postData, OpenStreamProgressCallback* progressCallback, void* progressCallbackContext, const String& headers, const int timeOutMs, StringPairArray* responseHeaders); JUCE_LEAK_DETECTOR (URL); }; #endif // __JUCE_URL_JUCEHEADER__ /*** End of inlined file: juce_URL.h ***/ #endif #ifndef __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_BufferedInputStream.h ***/ #ifndef __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ #define __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ /** Wraps another input stream, and reads from it using an intermediate buffer If you're using an input stream such as a file input stream, and making lots of small read accesses to it, it's probably sensible to wrap it in one of these, so that the source stream gets accessed in larger chunk sizes, meaning less work for the underlying stream. */ class JUCE_API BufferedInputStream : public InputStream { public: /** Creates a BufferedInputStream from an input source. @param sourceStream the source stream to read from @param bufferSize the size of reservoir to use to buffer the source @param deleteSourceWhenDestroyed whether the sourceStream that is passed in should be deleted by this object when it is itself deleted. */ BufferedInputStream (InputStream* sourceStream, int bufferSize, bool deleteSourceWhenDestroyed); /** Creates a BufferedInputStream from an input source. @param sourceStream the source stream to read from - the source stream must not be deleted until this object has been destroyed. @param bufferSize the size of reservoir to use to buffer the source */ BufferedInputStream (InputStream& sourceStream, int bufferSize); /** Destructor. This may also delete the source stream, if that option was chosen when the buffered stream was created. */ ~BufferedInputStream(); int64 getTotalLength(); int64 getPosition(); bool setPosition (int64 newPosition); int read (void* destBuffer, int maxBytesToRead); const String readString(); bool isExhausted(); private: InputStream* const source; ScopedPointer sourceToDelete; int bufferSize; int64 position, lastReadPos, bufferStart, bufferOverlap; HeapBlock buffer; void ensureBuffered(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BufferedInputStream); }; #endif // __JUCE_BUFFEREDINPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_BufferedInputStream.h ***/ #endif #ifndef __JUCE_FILEINPUTSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_FileInputSource.h ***/ #ifndef __JUCE_FILEINPUTSOURCE_JUCEHEADER__ #define __JUCE_FILEINPUTSOURCE_JUCEHEADER__ /** A type of InputSource that represents a normal file. @see InputSource */ class JUCE_API FileInputSource : public InputSource { public: FileInputSource (const File& file, bool useFileTimeInHashGeneration = false); ~FileInputSource(); InputStream* createInputStream(); InputStream* createInputStreamFor (const String& relatedItemPath); int64 hashCode() const; private: const File file; bool useFileTimeInHashGeneration; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileInputSource); }; #endif // __JUCE_FILEINPUTSOURCE_JUCEHEADER__ /*** End of inlined file: juce_FileInputSource.h ***/ #endif #ifndef __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_GZIPCompressorOutputStream.h ***/ #ifndef __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ #define __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ /** A stream which uses zlib to compress the data written into it. @see GZIPDecompressorInputStream */ class JUCE_API GZIPCompressorOutputStream : public OutputStream { public: /** Creates a compression stream. @param destStream the stream into which the compressed data should be written @param compressionLevel how much to compress the data, between 1 and 9, where 1 is the fastest/lowest compression, and 9 is the slowest/highest compression. Any value outside this range indicates that a default compression level should be used. @param deleteDestStreamWhenDestroyed whether or not to delete the destStream object when this stream is destroyed @param windowBits this is used internally to change the window size used by zlib - leave it as 0 unless you specifically need to set its value for some reason */ GZIPCompressorOutputStream (OutputStream* destStream, int compressionLevel = 0, bool deleteDestStreamWhenDestroyed = false, int windowBits = 0); /** Destructor. */ ~GZIPCompressorOutputStream(); void flush(); int64 getPosition(); bool setPosition (int64 newPosition); bool write (const void* destBuffer, int howMany); /** These are preset values that can be used for the constructor's windowBits paramter. For more info about this, see the zlib documentation for its windowBits parameter. */ enum WindowBitsValues { windowBitsRaw = -15, windowBitsGZIP = 15 + 16 }; private: OutputStream* const destStream; ScopedPointer streamToDelete; HeapBlock buffer; class GZIPCompressorHelper; friend class ScopedPointer ; ScopedPointer helper; bool doNextBlock(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPCompressorOutputStream); }; #endif // __JUCE_GZIPCOMPRESSOROUTPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_GZIPCompressorOutputStream.h ***/ #endif #ifndef __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_GZIPDecompressorInputStream.h ***/ #ifndef __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ #define __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ /** This stream will decompress a source-stream using zlib. Tip: if you're reading lots of small items from one of these streams, you can increase the performance enormously by passing it through a BufferedInputStream, so that it has to read larger blocks less often. @see GZIPCompressorOutputStream */ class JUCE_API GZIPDecompressorInputStream : public InputStream { public: /** Creates a decompressor stream. @param sourceStream the stream to read from @param deleteSourceWhenDestroyed whether or not to delete the source stream when this object is destroyed @param noWrap this is used internally by the ZipFile class and should be ignored by user applications @param uncompressedStreamLength if the creator knows the length that the uncompressed stream will be, then it can supply this value, which will be returned by getTotalLength() */ GZIPDecompressorInputStream (InputStream* sourceStream, bool deleteSourceWhenDestroyed, bool noWrap = false, int64 uncompressedStreamLength = -1); /** Creates a decompressor stream. @param sourceStream the stream to read from - the source stream must not be deleted until this object has been destroyed */ GZIPDecompressorInputStream (InputStream& sourceStream); /** Destructor. */ ~GZIPDecompressorInputStream(); int64 getPosition(); bool setPosition (int64 pos); int64 getTotalLength(); bool isExhausted(); int read (void* destBuffer, int maxBytesToRead); private: InputStream* const sourceStream; ScopedPointer streamToDelete; const int64 uncompressedStreamLength; const bool noWrap; bool isEof; int activeBufferSize; int64 originalSourcePos, currentPos; HeapBlock buffer; class GZIPDecompressHelper; friend class ScopedPointer ; ScopedPointer helper; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GZIPDecompressorInputStream); }; #endif // __JUCE_GZIPDECOMPRESSORINPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_GZIPDecompressorInputStream.h ***/ #endif #ifndef __JUCE_INPUTSOURCE_JUCEHEADER__ #endif #ifndef __JUCE_INPUTSTREAM_JUCEHEADER__ #endif #ifndef __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_MemoryInputStream.h ***/ #ifndef __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ #define __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ /** Allows a block of data and to be accessed as a stream. This can either be used to refer to a shared block of memory, or can make its own internal copy of the data when the MemoryInputStream is created. */ class JUCE_API MemoryInputStream : public InputStream { public: /** Creates a MemoryInputStream. @param sourceData the block of data to use as the stream's source @param sourceDataSize the number of bytes in the source data block @param keepInternalCopyOfData if false, the stream will just keep a pointer to the source data, so this data shouldn't be changed for the lifetime of the stream; if this parameter is true, the stream will make its own copy of the data and use that. */ MemoryInputStream (const void* sourceData, size_t sourceDataSize, bool keepInternalCopyOfData); /** Creates a MemoryInputStream. @param data a block of data to use as the stream's source @param keepInternalCopyOfData if false, the stream will just keep a reference to the source data, so this data shouldn't be changed for the lifetime of the stream; if this parameter is true, the stream will make its own copy of the data and use that. */ MemoryInputStream (const MemoryBlock& data, bool keepInternalCopyOfData); /** Destructor. */ ~MemoryInputStream(); int64 getPosition(); bool setPosition (int64 pos); int64 getTotalLength(); bool isExhausted(); int read (void* destBuffer, int maxBytesToRead); private: const char* data; size_t dataSize, position; MemoryBlock internalCopy; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryInputStream); }; #endif // __JUCE_MEMORYINPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_MemoryInputStream.h ***/ #endif #ifndef __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_MemoryOutputStream.h ***/ #ifndef __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ #define __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ /** Writes data to an internal memory buffer, which grows as required. The data that was written into the stream can then be accessed later as a contiguous block of memory. */ class JUCE_API MemoryOutputStream : public OutputStream { public: /** Creates an empty memory stream ready for writing into. @param initialSize the intial amount of capacity to allocate for writing into */ MemoryOutputStream (size_t initialSize = 256); /** Creates a memory stream for writing into into a pre-existing MemoryBlock object. Note that the destination block will always be larger than the amount of data that has been written to the stream, because the MemoryOutputStream keeps some spare capactity at its end. To trim the block's size down to fit the actual data, call flush(), or delete the MemoryOutputStream. @param memoryBlockToWriteTo the block into which new data will be written. @param appendToExistingBlockContent if this is true, the contents of the block will be kept, and new data will be appended to it. If false, the block will be cleared before use */ MemoryOutputStream (MemoryBlock& memoryBlockToWriteTo, bool appendToExistingBlockContent); /** Destructor. This will free any data that was written to it. */ ~MemoryOutputStream(); /** Returns a pointer to the data that has been written to the stream. @see getDataSize */ const void* getData() const throw(); /** Returns the number of bytes of data that have been written to the stream. @see getData */ size_t getDataSize() const throw() { return size; } /** Resets the stream, clearing any data that has been written to it so far. */ void reset() throw(); /** Increases the internal storage capacity to be able to contain at least the specified amount of data without needing to be resized. */ void preallocate (size_t bytesToPreallocate); /** Returns a String created from the (UTF8) data that has been written to the stream. */ const String toUTF8() const; /** Attempts to detect the encoding of the data and convert it to a string. @see String::createStringFromData */ const String toString() const; /** If the stream is writing to a user-supplied MemoryBlock, this will trim any excess capacity off the block, so that its length matches the amount of actual data that has been written so far. */ void flush(); bool write (const void* buffer, int howMany); int64 getPosition() { return position; } bool setPosition (int64 newPosition); int writeFromInputStream (InputStream& source, int64 maxNumBytesToWrite); private: MemoryBlock& data; MemoryBlock internalBlock; size_t position, size; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryOutputStream); }; /** Copies all the data that has been written to a MemoryOutputStream into another stream. */ OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const MemoryOutputStream& streamToRead); #endif // __JUCE_MEMORYOUTPUTSTREAM_JUCEHEADER__ /*** End of inlined file: juce_MemoryOutputStream.h ***/ #endif #ifndef __JUCE_OUTPUTSTREAM_JUCEHEADER__ #endif #ifndef __JUCE_SUBREGIONSTREAM_JUCEHEADER__ /*** Start of inlined file: juce_SubregionStream.h ***/ #ifndef __JUCE_SUBREGIONSTREAM_JUCEHEADER__ #define __JUCE_SUBREGIONSTREAM_JUCEHEADER__ /** Wraps another input stream, and reads from a specific part of it. This lets you take a subsection of a stream and present it as an entire stream in its own right. */ class JUCE_API SubregionStream : public InputStream { public: /** Creates a SubregionStream from an input source. @param sourceStream the source stream to read from @param startPositionInSourceStream this is the position in the source stream that corresponds to position 0 in this stream @param lengthOfSourceStream this specifies the maximum number of bytes from the source stream that will be passed through by this stream. When the position of this stream exceeds lengthOfSourceStream, it will cause an end-of-stream. If the length passed in here is greater than the length of the source stream (as returned by getTotalLength()), then the smaller value will be used. Passing a negative value for this parameter means it will keep reading until the source's end-of-stream. @param deleteSourceWhenDestroyed whether the sourceStream that is passed in should be deleted by this object when it is itself deleted. */ SubregionStream (InputStream* sourceStream, int64 startPositionInSourceStream, int64 lengthOfSourceStream, bool deleteSourceWhenDestroyed); /** Destructor. This may also delete the source stream, if that option was chosen when the buffered stream was created. */ ~SubregionStream(); int64 getTotalLength(); int64 getPosition(); bool setPosition (int64 newPosition); int read (void* destBuffer, int maxBytesToRead); bool isExhausted(); private: InputStream* const source; ScopedPointer sourceToDelete; const int64 startPositionInSourceStream, lengthOfSourceStream; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SubregionStream); }; #endif // __JUCE_SUBREGIONSTREAM_JUCEHEADER__ /*** End of inlined file: juce_SubregionStream.h ***/ #endif #ifndef __JUCE_BIGINTEGER_JUCEHEADER__ #endif #ifndef __JUCE_EXPRESSION_JUCEHEADER__ /*** Start of inlined file: juce_Expression.h ***/ #ifndef __JUCE_EXPRESSION_JUCEHEADER__ #define __JUCE_EXPRESSION_JUCEHEADER__ /** A class for dynamically evaluating simple numeric expressions. This class can parse a simple C-style string expression involving floating point numbers, named symbols and functions. The basic arithmetic operations of +, -, *, / are supported, as well as parentheses, and any alphanumeric identifiers are assumed to be named symbols which will be resolved when the expression is evaluated. Expressions which use identifiers and functions require a subclass of Expression::EvaluationContext to be supplied when evaluating them, and this object is expected to be able to resolve the symbol names and perform the functions that are used. */ class JUCE_API Expression { public: /** Creates a simple expression with a value of 0. */ Expression(); /** Destructor. */ ~Expression(); /** Creates a simple expression with a specified constant value. */ explicit Expression (double constant); /** Creates a copy of an expression. */ Expression (const Expression& other); /** Copies another expression. */ Expression& operator= (const Expression& other); /** Creates an expression by parsing a string. If there's a syntax error in the string, this will throw a ParseError exception. @throws ParseError */ explicit Expression (const String& stringToParse); /** Returns a string version of the expression. */ const String toString() const; /** Returns an expression which is an addtion operation of two existing expressions. */ const Expression operator+ (const Expression& other) const; /** Returns an expression which is a subtraction operation of two existing expressions. */ const Expression operator- (const Expression& other) const; /** Returns an expression which is a multiplication operation of two existing expressions. */ const Expression operator* (const Expression& other) const; /** Returns an expression which is a division operation of two existing expressions. */ const Expression operator/ (const Expression& other) const; /** Returns an expression which performs a negation operation on an existing expression. */ const Expression operator-() const; /** Returns an Expression which is an identifier reference. */ static const Expression symbol (const String& symbol); /** Returns an Expression which is a function call. */ static const Expression function (const String& functionName, const Array& parameters); /** Returns an Expression which parses a string from a specified character index. The index value is incremented so that on return, it indicates the character that follows the end of the expression that was parsed. If there's a syntax error in the string, this will throw a ParseError exception. @throws ParseError */ static const Expression parse (const String& stringToParse, int& textIndexToStartFrom); /** When evaluating an Expression object, this class is used to resolve symbols and perform functions that the expression uses. */ class JUCE_API EvaluationContext { public: EvaluationContext(); virtual ~EvaluationContext(); /** Returns the value of a symbol. If the symbol is unknown, this can throw an Expression::EvaluationError exception. The member value is set to the part of the symbol that followed the dot, if there is one, e.g. for "foo.bar", symbol = "foo" and member = "bar". @throws Expression::EvaluationError */ virtual const Expression getSymbolValue (const String& symbol, const String& member) const; /** Executes a named function. If the function name is unknown, this can throw an Expression::EvaluationError exception. @throws Expression::EvaluationError */ virtual double evaluateFunction (const String& functionName, const double* parameters, int numParams) const; }; /** Evaluates this expression, without using an EvaluationContext. Without an EvaluationContext, no symbols can be used, and only basic functions such as sin, cos, tan, min, max are available. @throws Expression::EvaluationError */ double evaluate() const; /** Evaluates this expression, providing a context that should be able to evaluate any symbols or functions that it uses. @throws Expression::EvaluationError */ double evaluate (const EvaluationContext& context) const; /** Attempts to return an expression which is a copy of this one, but with a constant adjusted to make the expression resolve to a target value. E.g. if the expression is "x + 10" and x is 5, then asking for a target value of 8 will return the expression "x + 3". Obviously some expressions can't be reversed in this way, in which case they might just be adjusted by adding a constant to them. @throws Expression::EvaluationError */ const Expression adjustedToGiveNewResult (double targetValue, const EvaluationContext& context) const; /** Returns a copy of this expression in which all instances of a given symbol have been renamed. */ const Expression withRenamedSymbol (const String& oldSymbol, const String& newSymbol) const; /** Returns true if this expression makes use of the specified symbol. If a suitable context is supplied, the search will dereference and recursively check all symbols, so that it can be determined whether this expression relies on the given symbol at any level in its evaluation. If the context parameter is null, this just checks whether the expression contains any direct references to the symbol. @throws Expression::EvaluationError */ bool referencesSymbol (const String& symbol, const EvaluationContext* context) const; /** Returns true if this expression contains any symbols. */ bool usesAnySymbols() const; /** An exception that can be thrown by Expression::parse(). */ class ParseError : public std::exception { public: ParseError (const String& message); String description; }; /** An exception that can be thrown by Expression::evaluate(). */ class EvaluationError : public std::exception { public: EvaluationError (const String& message); EvaluationError (const String& symbolName, const String& memberName); String description; }; /** Expression type. @see Expression::getType() */ enum Type { constantType, functionType, operatorType, symbolType }; /** Returns the type of this expression. */ Type getType() const throw(); /** If this expression is a symbol, this returns its full name. */ const String getSymbol() const; /** For a symbol that contains a dot, this returns the two */ void getSymbolParts (String& objectName, String& memberName) const; /** If this expression is a function, this returns its name. */ const String getFunction() const; /** If this expression is an operator, this returns its name. E.g. "+", "-", "*", "/", etc. */ const String getOperator() const; /** Returns the number of inputs to this expression. @see getInput */ int getNumInputs() const; /** Retrieves one of the inputs to this expression. @see getNumInputs */ const Expression getInput (int index) const; private: class Helpers; friend class Helpers; class Term : public ReferenceCountedObject { public: Term() {} virtual ~Term() {} virtual Term* clone() const = 0; virtual double evaluate (const EvaluationContext&, int recursionDepth) const = 0; virtual int getNumInputs() const = 0; virtual Term* getInput (int index) const = 0; virtual int getInputIndexFor (const Term* possibleInput) const; virtual const String toString() const = 0; virtual int getOperatorPrecedence() const; virtual bool referencesSymbol (const String& symbol, const EvaluationContext*, int recursionDepth) const; virtual const ReferenceCountedObjectPtr createTermToEvaluateInput (const EvaluationContext&, const Term* inputTerm, double overallTarget, Term* topLevelTerm) const; virtual const ReferenceCountedObjectPtr negated(); virtual Type getType() const throw() = 0; virtual void getSymbolParts (String& objectName, String& memberName) const; virtual const String getFunctionName() const; private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Term); }; friend class ScopedPointer; ReferenceCountedObjectPtr term; explicit Expression (Term* term); }; #endif // __JUCE_EXPRESSION_JUCEHEADER__ /*** End of inlined file: juce_Expression.h ***/ #endif #ifndef __JUCE_MATHSFUNCTIONS_JUCEHEADER__ #endif #ifndef __JUCE_RANDOM_JUCEHEADER__ /*** Start of inlined file: juce_Random.h ***/ #ifndef __JUCE_RANDOM_JUCEHEADER__ #define __JUCE_RANDOM_JUCEHEADER__ /** A simple pseudo-random number generator. */ class JUCE_API Random { public: /** Creates a Random object based on a seed value. For a given seed value, the subsequent numbers generated by this object will be predictable, so a good idea is to set this value based on the time, e.g. new Random (Time::currentTimeMillis()) */ explicit Random (int64 seedValue) throw(); /** Destructor. */ ~Random() throw(); /** Returns the next random 32 bit integer. @returns a random integer from the full range 0x80000000 to 0x7fffffff */ int nextInt() throw(); /** Returns the next random number, limited to a given range. @returns a random integer between 0 (inclusive) and maxValue (exclusive). */ int nextInt (int maxValue) throw(); /** Returns the next 64-bit random number. @returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff */ int64 nextInt64() throw(); /** Returns the next random floating-point number. @returns a random value in the range 0 to 1.0 */ float nextFloat() throw(); /** Returns the next random floating-point number. @returns a random value in the range 0 to 1.0 */ double nextDouble() throw(); /** Returns the next random boolean value. */ bool nextBool() throw(); /** Returns a BigInteger containing a random number. @returns a random value in the range 0 to (maximumValue - 1). */ const BigInteger nextLargeNumber (const BigInteger& maximumValue); /** Sets a range of bits in a BigInteger to random values. */ void fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits); /** To avoid the overhead of having to create a new Random object whenever you need a number, this is a shared application-wide object that can be used. It's not thread-safe though, so threads should use their own Random object. */ static Random& getSystemRandom() throw(); /** Resets this Random object to a given seed value. */ void setSeed (int64 newSeed) throw(); /** Merges this object's seed with another value. This sets the seed to be a value created by combining the current seed and this new value. */ void combineSeed (int64 seedValue) throw(); /** Reseeds this generator using a value generated from various semi-random system properties like the current time, etc. Because this function convolves the time with the last seed value, calling it repeatedly will increase the randomness of the final result. */ void setSeedRandomly(); private: int64 seed; JUCE_LEAK_DETECTOR (Random); }; #endif // __JUCE_RANDOM_JUCEHEADER__ /*** End of inlined file: juce_Random.h ***/ #endif #ifndef __JUCE_RANGE_JUCEHEADER__ #endif #ifndef __JUCE_ATOMIC_JUCEHEADER__ #endif #ifndef __JUCE_BYTEORDER_JUCEHEADER__ #endif #ifndef __JUCE_HEAPBLOCK_JUCEHEADER__ #endif #ifndef __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__ #endif #ifndef __JUCE_MEMORY_JUCEHEADER__ #endif #ifndef __JUCE_MEMORYBLOCK_JUCEHEADER__ #endif #ifndef __JUCE_REFERENCECOUNTEDOBJECT_JUCEHEADER__ #endif #ifndef __JUCE_SCOPEDPOINTER_JUCEHEADER__ #endif #ifndef __JUCE_WEAKREFERENCE_JUCEHEADER__ /*** Start of inlined file: juce_WeakReference.h ***/ #ifndef __JUCE_WEAKREFERENCE_JUCEHEADER__ #define __JUCE_WEAKREFERENCE_JUCEHEADER__ /** This class acts as a pointer which will automatically become null if the object to which it points is deleted. To accomplish this, the source object needs to cooperate by performing a couple of simple tasks. It must provide a getWeakReference() method and embed a WeakReference::Master object, which stores a shared pointer object. It must also clear this master pointer when it's getting deleted. E.g. @code class MyObject { public: MyObject() { // If you're planning on using your WeakReferences in a multi-threaded situation, you may choose // to call getWeakReference() here in the constructor, which will pre-initialise it, avoiding an // (extremely unlikely) race condition that could occur if multiple threads overlap while making // the first call to getWeakReference(). } ~MyObject() { // This will zero all the references - you need to call this in your destructor. masterReference.clear(); } // Your object must provide a method that looks pretty much identical to this (except // for the templated class name, of course). const WeakReference::SharedRef& getWeakReference() { return masterReference (this); } private: // You need to embed one of these inside your object. It can be private. WeakReference::Master masterReference; }; // Here's an example of using a pointer.. MyObject* n = new MyObject(); WeakReference myObjectRef = n; MyObject* pointer1 = myObjectRef; // returns a valid pointer to 'n' delete n; MyObject* pointer2 = myObjectRef; // returns a null pointer @endcode @see WeakReference::Master */ template class WeakReference { public: /** Creates a null SafePointer. */ WeakReference() throw() {} /** Creates a WeakReference that points at the given object. */ WeakReference (ObjectType* const object) : holder (object != 0 ? object->getWeakReference() : 0) {} /** Creates a copy of another WeakReference. */ WeakReference (const WeakReference& other) throw() : holder (other.holder) {} /** Copies another pointer to this one. */ WeakReference& operator= (const WeakReference& other) { holder = other.holder; return *this; } /** Copies another pointer to this one. */ WeakReference& operator= (ObjectType* const newObject) { holder = newObject != 0 ? newObject->getWeakReference() : 0; return *this; } /** Returns the object that this pointer refers to, or null if the object no longer exists. */ ObjectType* get() const throw() { return holder != 0 ? holder->get() : 0; } /** Returns the object that this pointer refers to, or null if the object no longer exists. */ operator ObjectType*() const throw() { return get(); } /** Returns the object that this pointer refers to, or null if the object no longer exists. */ ObjectType* operator->() throw() { return get(); } /** Returns the object that this pointer refers to, or null if the object no longer exists. */ const ObjectType* operator->() const throw() { return get(); } /** This returns true if this reference has been pointing at an object, but that object has since been deleted. If this reference was only ever pointing at a null pointer, this will return false. Using operator=() to make this refer to a different object will reset this flag to match the status of the reference from which you're copying. */ bool wasObjectDeleted() const throw() { return holder != 0 && holder->get() == 0; } bool operator== (ObjectType* const object) const throw() { return get() == object; } bool operator!= (ObjectType* const object) const throw() { return get() != object; } /** This class is used internally by the WeakReference class - don't use it directly in your code! @see WeakReference */ class SharedPointer : public ReferenceCountedObject { public: explicit SharedPointer (ObjectType* const owner_) throw() : owner (owner_) {} inline ObjectType* get() const throw() { return owner; } void clearPointer() throw() { owner = 0; } private: ObjectType* volatile owner; JUCE_DECLARE_NON_COPYABLE (SharedPointer); }; typedef ReferenceCountedObjectPtr SharedRef; /** This class is embedded inside an object to which you want to attach WeakReference pointers. See the WeakReference class notes for an example of how to use this class. @see WeakReference */ class Master { public: Master() throw() {} ~Master() { // You must remember to call clear() in your source object's destructor! See the notes // for the WeakReference class for an example of how to do this. jassert (sharedPointer == 0 || sharedPointer->get() == 0); } /** The first call to this method will create an internal object that is shared by all weak references to the object. You need to call this from your main object's getWeakReference() method - see the WeakReference class notes for an example. */ const SharedRef& operator() (ObjectType* const object) { if (sharedPointer == 0) { sharedPointer = new SharedPointer (object); } else { // You're trying to create a weak reference to an object that has already been deleted!! jassert (sharedPointer->get() != 0); } return sharedPointer; } /** The object that owns this master pointer should call this before it gets destroyed, to zero all the references to this object that may be out there. See the WeakReference class notes for an example of how to do this. */ void clear() { if (sharedPointer != 0) sharedPointer->clearPointer(); } private: SharedRef sharedPointer; JUCE_DECLARE_NON_COPYABLE (Master); }; private: SharedRef holder; }; #endif // __JUCE_WEAKREFERENCE_JUCEHEADER__ /*** End of inlined file: juce_WeakReference.h ***/ #endif #ifndef __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__ #endif #ifndef __JUCE_IDENTIFIER_JUCEHEADER__ #endif #ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ /*** Start of inlined file: juce_LocalisedStrings.h ***/ #ifndef __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ #define __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ /** Used in the same way as the T(text) macro, this will attempt to translate a string into a localised version using the LocalisedStrings class. @see LocalisedStrings */ #define TRANS(stringLiteral) \ LocalisedStrings::translateWithCurrentMappings (stringLiteral) /** Used to convert strings to localised foreign-language versions. This is basically a look-up table of strings and their translated equivalents. It can be loaded from a text file, so that you can supply a set of localised versions of strings that you use in your app. To use it in your code, simply call the translate() method on each string that might have foreign versions, and if none is found, the method will just return the original string. The translation file should start with some lines specifying a description of the language it contains, and also a list of ISO country codes where it might be appropriate to use the file. After that, each line of the file should contain a pair of quoted strings with an '=' sign. E.g. for a french translation, the file might be: @code language: French countries: fr be mc ch lu "hello" = "bonjour" "goodbye" = "au revoir" @endcode If the strings need to contain a quote character, they can use '\"' instead, and if the first non-whitespace character on a line isn't a quote, then it's ignored, (you can use this to add comments). Note that this is a singleton class, so don't create or destroy the object directly. There's also a TRANS(text) macro defined to make it easy to use the this. E.g. @code printSomething (TRANS("hello")); @endcode This macro is used in the Juce classes themselves, so your application has a chance to intercept and translate any internal Juce text strings that might be shown. (You can easily get a list of all the messages by searching for the TRANS() macro in the Juce source code). */ class JUCE_API LocalisedStrings { public: /** Creates a set of translations from the text of a translation file. When you create one of these, you can call setCurrentMappings() to make it the set of mappings that the system's using. */ LocalisedStrings (const String& fileContents); /** Creates a set of translations from a file. When you create one of these, you can call setCurrentMappings() to make it the set of mappings that the system's using. */ LocalisedStrings (const File& fileToLoad); /** Destructor. */ ~LocalisedStrings(); /** Selects the current set of mappings to be used by the system. The object you pass in will be automatically deleted when no longer needed, so don't keep a pointer to it. You can also pass in zero to remove the current mappings. See also the TRANS() macro, which uses the current set to do its translation. @see translateWithCurrentMappings */ static void setCurrentMappings (LocalisedStrings* newTranslations); /** Returns the currently selected set of mappings. This is the object that was last passed to setCurrentMappings(). It may be 0 if none has been created. */ static LocalisedStrings* getCurrentMappings(); /** Tries to translate a string using the currently selected set of mappings. If no mapping has been set, or if the mapping doesn't contain a translation for the string, this will just return the original string. See also the TRANS() macro, which uses this method to do its translation. @see setCurrentMappings, getCurrentMappings */ static const String translateWithCurrentMappings (const String& text); /** Tries to translate a string using the currently selected set of mappings. If no mapping has been set, or if the mapping doesn't contain a translation for the string, this will just return the original string. See also the TRANS() macro, which uses this method to do its translation. @see setCurrentMappings, getCurrentMappings */ static const String translateWithCurrentMappings (const char* text); /** Attempts to look up a string and return its localised version. If the string isn't found in the list, the original string will be returned. */ const String translate (const String& text) const; /** Returns the name of the language specified in the translation file. This is specified in the file using a line starting with "language:", e.g. @code language: german @endcode */ const String getLanguageName() const { return languageName; } /** Returns the list of suitable country codes listed in the translation file. These is specified in the file using a line starting with "countries:", e.g. @code countries: fr be mc ch lu @endcode The country codes are supposed to be 2-character ISO complient codes. */ const StringArray getCountryCodes() const { return countryCodes; } /** Indicates whether to use a case-insensitive search when looking up a string. This defaults to true. */ void setIgnoresCase (bool shouldIgnoreCase); private: String languageName; StringArray countryCodes; StringPairArray translations; void loadFromText (const String& fileContents); JUCE_LEAK_DETECTOR (LocalisedStrings); }; #endif // __JUCE_LOCALISEDSTRINGS_JUCEHEADER__ /*** End of inlined file: juce_LocalisedStrings.h ***/ #endif #ifndef __JUCE_NEWLINE_JUCEHEADER__ #endif #ifndef __JUCE_STRING_JUCEHEADER__ #endif #ifndef __JUCE_STRINGARRAY_JUCEHEADER__ #endif #ifndef __JUCE_STRINGPAIRARRAY_JUCEHEADER__ #endif #ifndef __JUCE_STRINGPOOL_JUCEHEADER__ #endif #ifndef __JUCE_XMLDOCUMENT_JUCEHEADER__ /*** Start of inlined file: juce_XmlDocument.h ***/ #ifndef __JUCE_XMLDOCUMENT_JUCEHEADER__ #define __JUCE_XMLDOCUMENT_JUCEHEADER__ /** Parses a text-based XML document and creates an XmlElement object from it. The parser will parse DTDs to load external entities but won't check the document for validity against the DTD. e.g. @code XmlDocument myDocument (File ("myfile.xml")); XmlElement* mainElement = myDocument.getDocumentElement(); if (mainElement == 0) { String error = myDocument.getLastParseError(); } else { ..use the element } @endcode Or you can use the static helper methods for quick parsing.. @code XmlElement* xml = XmlDocument::parse (myXmlFile); if (xml != 0 && xml->hasTagName ("foobar")) { ...etc @endcode @see XmlElement */ class JUCE_API XmlDocument { public: /** Creates an XmlDocument from the xml text. The text doesn't actually get parsed until the getDocumentElement() method is called. */ XmlDocument (const String& documentText); /** Creates an XmlDocument from a file. The text doesn't actually get parsed until the getDocumentElement() method is called. */ XmlDocument (const File& file); /** Destructor. */ ~XmlDocument(); /** Creates an XmlElement object to represent the main document node. This method will do the actual parsing of the text, and if there's a parse error, it may returns 0 (and you can find out the error using the getLastParseError() method). See also the parse() methods, which provide a shorthand way to quickly parse a file or string. @param onlyReadOuterDocumentElement if true, the parser will only read the first section of the file, and will only return the outer document element - this allows quick checking of large files to see if they contain the correct type of tag, without having to parse the entire file @returns a new XmlElement which the caller will need to delete, or null if there was an error. @see getLastParseError */ XmlElement* getDocumentElement (bool onlyReadOuterDocumentElement = false); /** Returns the parsing error that occurred the last time getDocumentElement was called. @returns the error, or an empty string if there was no error. */ const String& getLastParseError() const throw(); /** Sets an input source object to use for parsing documents that reference external entities. If the document has been created from a file, this probably won't be needed, but if you're parsing some text and there might be a DTD that references external files, you may need to create a custom input source that can retrieve the other files it needs. The object that is passed-in will be deleted automatically when no longer needed. @see InputSource */ void setInputSource (InputSource* newSource) throw(); /** Sets a flag to change the treatment of empty text elements. If this is true (the default state), then any text elements that contain only whitespace characters will be ingored during parsing. If you need to catch whitespace-only text, then you should set this to false before calling the getDocumentElement() method. */ void setEmptyTextElementsIgnored (bool shouldBeIgnored) throw(); /** A handy static method that parses a file. This is a shortcut for creating an XmlDocument object and calling getDocumentElement() on it. @returns a new XmlElement which the caller will need to delete, or null if there was an error. */ static XmlElement* parse (const File& file); /** A handy static method that parses some XML data. This is a shortcut for creating an XmlDocument object and calling getDocumentElement() on it. @returns a new XmlElement which the caller will need to delete, or null if there was an error. */ static XmlElement* parse (const String& xmlData); private: String originalText; const juce_wchar* input; bool outOfData, errorOccurred; String lastError, dtdText; StringArray tokenisedDTD; bool needToLoadDTD, ignoreEmptyTextElements; ScopedPointer inputSource; void setLastError (const String& desc, bool carryOn); void skipHeader(); void skipNextWhiteSpace(); juce_wchar readNextChar() throw(); XmlElement* readNextElement (bool alsoParseSubElements); void readChildElements (XmlElement* parent); int findNextTokenLength() throw(); void readQuotedString (String& result); void readEntity (String& result); const String getFileContents (const String& filename) const; const String expandEntity (const String& entity); const String expandExternalEntity (const String& entity); const String getParameterEntity (const String& entity); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XmlDocument); }; #endif // __JUCE_XMLDOCUMENT_JUCEHEADER__ /*** End of inlined file: juce_XmlDocument.h ***/ #endif #ifndef __JUCE_XMLELEMENT_JUCEHEADER__ #endif #ifndef __JUCE_CRITICALSECTION_JUCEHEADER__ #endif #ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ /*** Start of inlined file: juce_InterProcessLock.h ***/ #ifndef __JUCE_INTERPROCESSLOCK_JUCEHEADER__ #define __JUCE_INTERPROCESSLOCK_JUCEHEADER__ /** Acts as a critical section which processes can use to block each other. @see CriticalSection */ class JUCE_API InterProcessLock { public: /** Creates a lock object. @param name a name that processes will use to identify this lock object */ explicit InterProcessLock (const String& name); /** Destructor. This will also release the lock if it's currently held by this process. */ ~InterProcessLock(); /** Attempts to lock the critical section. @param timeOutMillisecs how many milliseconds to wait if the lock is already held by another process - a value of 0 will return immediately, negative values will wait forever @returns true if the lock could be gained within the timeout period, or false if the timeout expired. */ bool enter (int timeOutMillisecs = -1); /** Releases the lock if it's currently held by this process. */ void exit(); /** Automatically locks and unlocks an InterProcessLock object. This works like a ScopedLock, but using an InterprocessLock rather than a CriticalSection. @see ScopedLock */ class ScopedLockType { public: /** Creates a scoped lock. As soon as it is created, this will lock the InterProcessLock, and when the ScopedLockType object is deleted, the InterProcessLock will be unlocked. Note that since an InterprocessLock can fail due to errors, you should check isLocked() to make sure that the lock was successful before using it. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! Best just to use it as a local stack object, rather than creating one with the new() operator. */ explicit ScopedLockType (InterProcessLock& lock) : lock_ (lock) { lockWasSuccessful = lock.enter(); } /** Destructor. The InterProcessLock will be unlocked when the destructor is called. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ inline ~ScopedLockType() { lock_.exit(); } /** Returns true if the InterProcessLock was successfully locked. */ bool isLocked() const throw() { return lockWasSuccessful; } private: InterProcessLock& lock_; bool lockWasSuccessful; JUCE_DECLARE_NON_COPYABLE (ScopedLockType); }; private: class Pimpl; friend class ScopedPointer ; ScopedPointer pimpl; CriticalSection lock; String name; JUCE_DECLARE_NON_COPYABLE (InterProcessLock); }; #endif // __JUCE_INTERPROCESSLOCK_JUCEHEADER__ /*** End of inlined file: juce_InterProcessLock.h ***/ #endif #ifndef __JUCE_PROCESS_JUCEHEADER__ /*** Start of inlined file: juce_Process.h ***/ #ifndef __JUCE_PROCESS_JUCEHEADER__ #define __JUCE_PROCESS_JUCEHEADER__ /** Represents the current executable's process. This contains methods for controlling the current application at the process-level. @see Thread, JUCEApplication */ class JUCE_API Process { public: enum ProcessPriority { LowPriority = 0, NormalPriority = 1, HighPriority = 2, RealtimePriority = 3 }; /** Changes the current process's priority. @param priority the process priority, where 0=low, 1=normal, 2=high, 3=realtime */ static void setPriority (const ProcessPriority priority); /** Kills the current process immediately. This is an emergency process terminator that kills the application immediately - it's intended only for use only when something goes horribly wrong. @see JUCEApplication::quit */ static void terminate(); /** Returns true if this application process is the one that the user is currently using. */ static bool isForegroundProcess(); /** Raises the current process's privilege level. Does nothing if this isn't supported by the current OS, or if process privilege level is fixed. */ static void raisePrivilege(); /** Lowers the current process's privilege level. Does nothing if this isn't supported by the current OS, or if process privilege level is fixed. */ static void lowerPrivilege(); /** Returns true if this process is being hosted by a debugger. */ static bool JUCE_CALLTYPE isRunningUnderDebugger(); private: Process(); JUCE_DECLARE_NON_COPYABLE (Process); }; #endif // __JUCE_PROCESS_JUCEHEADER__ /*** End of inlined file: juce_Process.h ***/ #endif #ifndef __JUCE_READWRITELOCK_JUCEHEADER__ /*** Start of inlined file: juce_ReadWriteLock.h ***/ #ifndef __JUCE_READWRITELOCK_JUCEHEADER__ #define __JUCE_READWRITELOCK_JUCEHEADER__ /*** Start of inlined file: juce_WaitableEvent.h ***/ #ifndef __JUCE_WAITABLEEVENT_JUCEHEADER__ #define __JUCE_WAITABLEEVENT_JUCEHEADER__ /** Allows threads to wait for events triggered by other threads. A thread can call wait() on a WaitableObject, and this will suspend the calling thread until another thread wakes it up by calling the signal() method. */ class JUCE_API WaitableEvent { public: /** Creates a WaitableEvent object. @param manualReset If this is false, the event will be reset automatically when the wait() method is called. If manualReset is true, then once the event is signalled, the only way to reset it will be by calling the reset() method. */ WaitableEvent (bool manualReset = false) throw(); /** Destructor. If other threads are waiting on this object when it gets deleted, this can cause nasty errors, so be careful! */ ~WaitableEvent() throw(); /** Suspends the calling thread until the event has been signalled. This will wait until the object's signal() method is called by another thread, or until the timeout expires. After the event has been signalled, this method will return true and if manualReset was set to false in the WaitableEvent's constructor, then the event will be reset. @param timeOutMilliseconds the maximum time to wait, in milliseconds. A negative value will cause it to wait forever. @returns true if the object has been signalled, false if the timeout expires first. @see signal, reset */ bool wait (int timeOutMilliseconds = -1) const throw(); /** Wakes up any threads that are currently waiting on this object. If signal() is called when nothing is waiting, the next thread to call wait() will return immediately and reset the signal. @see wait, reset */ void signal() const throw(); /** Resets the event to an unsignalled state. If it's not already signalled, this does nothing. */ void reset() const throw(); private: void* internal; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WaitableEvent); }; #endif // __JUCE_WAITABLEEVENT_JUCEHEADER__ /*** End of inlined file: juce_WaitableEvent.h ***/ /*** Start of inlined file: juce_Thread.h ***/ #ifndef __JUCE_THREAD_JUCEHEADER__ #define __JUCE_THREAD_JUCEHEADER__ /** Encapsulates a thread. Subclasses derive from Thread and implement the run() method, in which they do their business. The thread can then be started with the startThread() method and controlled with various other methods. This class also contains some thread-related static methods, such as sleep(), yield(), getCurrentThreadId() etc. @see CriticalSection, WaitableEvent, Process, ThreadWithProgressWindow, MessageManagerLock */ class JUCE_API Thread { public: /** Creates a thread. When first created, the thread is not running. Use the startThread() method to start it. */ explicit Thread (const String& threadName); /** Destructor. Deleting a Thread object that is running will only give the thread a brief opportunity to stop itself cleanly, so it's recommended that you should always call stopThread() with a decent timeout before deleting, to avoid the thread being forcibly killed (which is a Bad Thing). */ virtual ~Thread(); /** Must be implemented to perform the thread's actual code. Remember that the thread must regularly check the threadShouldExit() method whilst running, and if this returns true it should return from the run() method as soon as possible to avoid being forcibly killed. @see threadShouldExit, startThread */ virtual void run() = 0; // Thread control functions.. /** Starts the thread running. This will start the thread's run() method. (if it's already started, startThread() won't do anything). @see stopThread */ void startThread(); /** Starts the thread with a given priority. Launches the thread with a given priority, where 0 = lowest, 10 = highest. If the thread is already running, its priority will be changed. @see startThread, setPriority */ void startThread (int priority); /** Attempts to stop the thread running. This method will cause the threadShouldExit() method to return true and call notify() in case the thread is currently waiting. Hopefully the thread will then respond to this by exiting cleanly, and the stopThread method will wait for a given time-period for this to happen. If the thread is stuck and fails to respond after the time-out, it gets forcibly killed, which is a very bad thing to happen, as it could still be holding locks, etc. which are needed by other parts of your program. @param timeOutMilliseconds The number of milliseconds to wait for the thread to finish before killing it by force. A negative value in here will wait forever. @see signalThreadShouldExit, threadShouldExit, waitForThreadToExit, isThreadRunning */ void stopThread (int timeOutMilliseconds); /** Returns true if the thread is currently active */ bool isThreadRunning() const; /** Sets a flag to tell the thread it should stop. Calling this means that the threadShouldExit() method will then return true. The thread should be regularly checking this to see whether it should exit. If your thread makes use of wait(), you might want to call notify() after calling this method, to interrupt any waits that might be in progress, and allow it to reach a point where it can exit. @see threadShouldExit @see waitForThreadToExit */ void signalThreadShouldExit(); /** Checks whether the thread has been told to stop running. Threads need to check this regularly, and if it returns true, they should return from their run() method at the first possible opportunity. @see signalThreadShouldExit */ inline bool threadShouldExit() const { return threadShouldExit_; } /** Waits for the thread to stop. This will waits until isThreadRunning() is false or until a timeout expires. @param timeOutMilliseconds the time to wait, in milliseconds. If this value is less than zero, it will wait forever. @returns true if the thread exits, or false if the timeout expires first. */ bool waitForThreadToExit (int timeOutMilliseconds) const; /** Changes the thread's priority. May return false if for some reason the priority can't be changed. @param priority the new priority, in the range 0 (lowest) to 10 (highest). A priority of 5 is normal. */ bool setPriority (int priority); /** Changes the priority of the caller thread. Similar to setPriority(), but this static method acts on the caller thread. May return false if for some reason the priority can't be changed. @see setPriority */ static bool setCurrentThreadPriority (int priority); /** Sets the affinity mask for the thread. This will only have an effect next time the thread is started - i.e. if the thread is already running when called, it'll have no effect. @see setCurrentThreadAffinityMask */ void setAffinityMask (uint32 affinityMask); /** Changes the affinity mask for the caller thread. This will change the affinity mask for the thread that calls this static method. @see setAffinityMask */ static void setCurrentThreadAffinityMask (uint32 affinityMask); // this can be called from any thread that needs to pause.. static void JUCE_CALLTYPE sleep (int milliseconds); /** Yields the calling thread's current time-slot. */ static void JUCE_CALLTYPE yield(); /** Makes the thread wait for a notification. This puts the thread to sleep until either the timeout period expires, or another thread calls the notify() method to wake it up. A negative time-out value means that the method will wait indefinitely. @returns true if the event has been signalled, false if the timeout expires. */ bool wait (int timeOutMilliseconds) const; /** Wakes up the thread. If the thread has called the wait() method, this will wake it up. @see wait */ void notify() const; /** A value type used for thread IDs. @see getCurrentThreadId(), getThreadId() */ typedef void* ThreadID; /** Returns an id that identifies the caller thread. To find the ID of a particular thread object, use getThreadId(). @returns a unique identifier that identifies the calling thread. @see getThreadId */ static ThreadID getCurrentThreadId(); /** Finds the thread object that is currently running. Note that the main UI thread (or other non-Juce threads) don't have a Thread object associated with them, so this will return 0. */ static Thread* getCurrentThread(); /** Returns the ID of this thread. That means the ID of this thread object - not of the thread that's calling the method. This can change when the thread is started and stopped, and will be invalid if the thread's not actually running. @see getCurrentThreadId */ ThreadID getThreadId() const throw() { return threadId_; } /** Returns the name of the thread. This is the name that gets set in the constructor. */ const String getThreadName() const { return threadName_; } /** Returns the number of currently-running threads. @returns the number of Thread objects known to be currently running. @see stopAllThreads */ static int getNumRunningThreads(); /** Tries to stop all currently-running threads. This will attempt to stop all the threads known to be running at the moment. */ static void stopAllThreads (int timeoutInMillisecs); private: const String threadName_; void* volatile threadHandle_; ThreadID threadId_; CriticalSection startStopLock; WaitableEvent startSuspensionEvent_, defaultEvent_; int threadPriority_; uint32 affinityMask_; bool volatile threadShouldExit_; #ifndef DOXYGEN friend class MessageManager; friend void JUCE_API juce_threadEntryPoint (void*); #endif void launchThread(); void closeThreadHandle(); void killThread(); void threadEntryPoint(); static void setCurrentThreadName (const String& name); static bool setThreadPriority (void* handle, int priority); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Thread); }; #endif // __JUCE_THREAD_JUCEHEADER__ /*** End of inlined file: juce_Thread.h ***/ /** A critical section that allows multiple simultaneous readers. Features of this type of lock are: - Multiple readers can hold the lock at the same time, but only one writer can hold it at once. - Writers trying to gain the lock will be blocked until all readers and writers have released it - Readers trying to gain the lock while a writer is waiting to acquire it will be blocked until the writer has obtained and released it - If a thread already has a read lock and tries to obtain a write lock, it will succeed if there are no other readers - If a thread already has the write lock and tries to obtain a read lock, this will succeed. - Recursive locking is supported. @see ScopedReadLock, ScopedWriteLock, CriticalSection */ class JUCE_API ReadWriteLock { public: /** Creates a ReadWriteLock object. */ ReadWriteLock() throw(); /** Destructor. If the object is deleted whilst locked, any subsequent behaviour is unpredictable. */ ~ReadWriteLock() throw(); /** Locks this object for reading. Multiple threads can simulaneously lock the object for reading, but if another thread has it locked for writing, then this will block until it releases the lock. @see exitRead, ScopedReadLock */ void enterRead() const throw(); /** Releases the read-lock. If the caller thread hasn't got the lock, this can have unpredictable results. If the enterRead() method has been called multiple times by the thread, each call must be matched by a call to exitRead() before other threads will be allowed to take over the lock. @see enterRead, ScopedReadLock */ void exitRead() const throw(); /** Locks this object for writing. This will block until any other threads that have it locked for reading or writing have released their lock. @see exitWrite, ScopedWriteLock */ void enterWrite() const throw(); /** Tries to lock this object for writing. This is like enterWrite(), but doesn't block - it returns true if it manages to obtain the lock. @see enterWrite */ bool tryEnterWrite() const throw(); /** Releases the write-lock. If the caller thread hasn't got the lock, this can have unpredictable results. If the enterWrite() method has been called multiple times by the thread, each call must be matched by a call to exit() before other threads will be allowed to take over the lock. @see enterWrite, ScopedWriteLock */ void exitWrite() const throw(); private: CriticalSection accessLock; WaitableEvent waitEvent; mutable int numWaitingWriters, numWriters; mutable Thread::ThreadID writerThreadId; mutable Array readerThreads; JUCE_DECLARE_NON_COPYABLE (ReadWriteLock); }; #endif // __JUCE_READWRITELOCK_JUCEHEADER__ /*** End of inlined file: juce_ReadWriteLock.h ***/ #endif #ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__ #endif #ifndef __JUCE_SCOPEDREADLOCK_JUCEHEADER__ /*** Start of inlined file: juce_ScopedReadLock.h ***/ #ifndef __JUCE_SCOPEDREADLOCK_JUCEHEADER__ #define __JUCE_SCOPEDREADLOCK_JUCEHEADER__ /** Automatically locks and unlocks a ReadWriteLock object. Use one of these as a local variable to control access to a ReadWriteLock. e.g. @code ReadWriteLock myLock; for (;;) { const ScopedReadLock myScopedLock (myLock); // myLock is now locked ...do some stuff... // myLock gets unlocked here. } @endcode @see ReadWriteLock, ScopedWriteLock */ class JUCE_API ScopedReadLock { public: /** Creates a ScopedReadLock. As soon as it is created, this will call ReadWriteLock::enterRead(), and when the ScopedReadLock object is deleted, the ReadWriteLock will be unlocked. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! Best just to use it as a local stack object, rather than creating one with the new() operator. */ inline explicit ScopedReadLock (const ReadWriteLock& lock) throw() : lock_ (lock) { lock.enterRead(); } /** Destructor. The ReadWriteLock's exitRead() method will be called when the destructor is called. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ inline ~ScopedReadLock() throw() { lock_.exitRead(); } private: const ReadWriteLock& lock_; JUCE_DECLARE_NON_COPYABLE (ScopedReadLock); }; #endif // __JUCE_SCOPEDREADLOCK_JUCEHEADER__ /*** End of inlined file: juce_ScopedReadLock.h ***/ #endif #ifndef __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ /*** Start of inlined file: juce_ScopedTryLock.h ***/ #ifndef __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ #define __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ /** Automatically tries to lock and unlock a CriticalSection object. Use one of these as a local variable to control access to a CriticalSection. e.g. @code CriticalSection myCriticalSection; for (;;) { const ScopedTryLock myScopedTryLock (myCriticalSection); // Unlike using a ScopedLock, this may fail to actually get the lock, so you // should test this with the isLocked() method before doing your thread-unsafe // action.. if (myScopedTryLock.isLocked()) { ...do some stuff... } else { ..our attempt at locking failed because another thread had already locked it.. } // myCriticalSection gets unlocked here (if it was locked) } @endcode @see CriticalSection::tryEnter, ScopedLock, ScopedUnlock, ScopedReadLock */ class JUCE_API ScopedTryLock { public: /** Creates a ScopedTryLock. As soon as it is created, this will try to lock the CriticalSection, and when the ScopedTryLock object is deleted, the CriticalSection will be unlocked if the lock was successful. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! Best just to use it as a local stack object, rather than creating one with the new() operator. */ inline explicit ScopedTryLock (const CriticalSection& lock) throw() : lock_ (lock), lockWasSuccessful (lock.tryEnter()) {} /** Destructor. The CriticalSection will be unlocked (if locked) when the destructor is called. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ inline ~ScopedTryLock() throw() { if (lockWasSuccessful) lock_.exit(); } /** Returns true if the CriticalSection was successfully locked. */ bool isLocked() const throw() { return lockWasSuccessful; } private: const CriticalSection& lock_; const bool lockWasSuccessful; JUCE_DECLARE_NON_COPYABLE (ScopedTryLock); }; #endif // __JUCE_SCOPEDTRYLOCK_JUCEHEADER__ /*** End of inlined file: juce_ScopedTryLock.h ***/ #endif #ifndef __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ /*** Start of inlined file: juce_ScopedWriteLock.h ***/ #ifndef __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ #define __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ /** Automatically locks and unlocks a ReadWriteLock object. Use one of these as a local variable to control access to a ReadWriteLock. e.g. @code ReadWriteLock myLock; for (;;) { const ScopedWriteLock myScopedLock (myLock); // myLock is now locked ...do some stuff... // myLock gets unlocked here. } @endcode @see ReadWriteLock, ScopedReadLock */ class JUCE_API ScopedWriteLock { public: /** Creates a ScopedWriteLock. As soon as it is created, this will call ReadWriteLock::enterWrite(), and when the ScopedWriteLock object is deleted, the ReadWriteLock will be unlocked. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! Best just to use it as a local stack object, rather than creating one with the new() operator. */ inline explicit ScopedWriteLock (const ReadWriteLock& lock) throw() : lock_ (lock) { lock.enterWrite(); } /** Destructor. The ReadWriteLock's exitWrite() method will be called when the destructor is called. Make sure this object is created and deleted by the same thread, otherwise there are no guarantees what will happen! */ inline ~ScopedWriteLock() throw() { lock_.exitWrite(); } private: const ReadWriteLock& lock_; JUCE_DECLARE_NON_COPYABLE (ScopedWriteLock); }; #endif // __JUCE_SCOPEDWRITELOCK_JUCEHEADER__ /*** End of inlined file: juce_ScopedWriteLock.h ***/ #endif #ifndef __JUCE_THREAD_JUCEHEADER__ #endif #ifndef __JUCE_THREADPOOL_JUCEHEADER__ /*** Start of inlined file: juce_ThreadPool.h ***/ #ifndef __JUCE_THREADPOOL_JUCEHEADER__ #define __JUCE_THREADPOOL_JUCEHEADER__ class ThreadPool; class ThreadPoolThread; /** A task that is executed by a ThreadPool object. A ThreadPool keeps a list of ThreadPoolJob objects which are executed by its threads. The runJob() method needs to be implemented to do the task, and if the code that does the work takes a significant time to run, it must keep checking the shouldExit() method to see if something is trying to interrupt the job. If shouldExit() returns true, the runJob() method must return immediately. @see ThreadPool, Thread */ class JUCE_API ThreadPoolJob { public: /** Creates a thread pool job object. After creating your job, add it to a thread pool with ThreadPool::addJob(). */ explicit ThreadPoolJob (const String& name); /** Destructor. */ virtual ~ThreadPoolJob(); /** Returns the name of this job. @see setJobName */ const String getJobName() const; /** Changes the job's name. @see getJobName */ void setJobName (const String& newName); /** These are the values that can be returned by the runJob() method. */ enum JobStatus { jobHasFinished = 0, /**< indicates that the job has finished and can be removed from the pool. */ jobHasFinishedAndShouldBeDeleted, /**< indicates that the job has finished and that it should be automatically deleted by the pool. */ jobNeedsRunningAgain /**< indicates that the job would like to be called again when a thread is free. */ }; /** Peforms the actual work that this job needs to do. Your subclass must implement this method, in which is does its work. If the code in this method takes a significant time to run, it must repeatedly check the shouldExit() method to see if something is trying to interrupt the job. If shouldExit() ever returns true, the runJob() method must return immediately. If this method returns jobHasFinished, then the job will be removed from the pool immediately. If it returns jobNeedsRunningAgain, then the job will be left in the pool and will get a chance to run again as soon as a thread is free. @see shouldExit() */ virtual JobStatus runJob() = 0; /** Returns true if this job is currently running its runJob() method. */ bool isRunning() const { return isActive; } /** Returns true if something is trying to interrupt this job and make it stop. Your runJob() method must call this whenever it gets a chance, and if it ever returns true, the runJob() method must return immediately. @see signalJobShouldExit() */ bool shouldExit() const { return shouldStop; } /** Calling this will cause the shouldExit() method to return true, and the job should (if it's been implemented correctly) stop as soon as possible. @see shouldExit() */ void signalJobShouldExit(); private: friend class ThreadPool; friend class ThreadPoolThread; String jobName; ThreadPool* pool; bool shouldStop, isActive, shouldBeDeleted; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPoolJob); }; /** A set of threads that will run a list of jobs. When a ThreadPoolJob object is added to the ThreadPool's list, its run() method will be called by the next pooled thread that becomes free. @see ThreadPoolJob, Thread */ class JUCE_API ThreadPool { public: /** Creates a thread pool. Once you've created a pool, you can give it some things to do with the addJob() method. @param numberOfThreads the maximum number of actual threads to run. @param startThreadsOnlyWhenNeeded if this is true, then no threads will be started until there are some jobs to run. If false, then all the threads will be fired-up immediately so that they're ready for action @param stopThreadsWhenNotUsedTimeoutMs if this timeout is > 0, then if any threads have been inactive for this length of time, they will automatically be stopped until more jobs come along and they're needed */ ThreadPool (int numberOfThreads, bool startThreadsOnlyWhenNeeded = true, int stopThreadsWhenNotUsedTimeoutMs = 5000); /** Destructor. This will attempt to remove all the jobs before deleting, but if you want to specify a timeout, you should call removeAllJobs() explicitly before deleting the pool. */ ~ThreadPool(); /** A callback class used when you need to select which ThreadPoolJob objects are suitable for some kind of operation. @see ThreadPool::removeAllJobs */ class JUCE_API JobSelector { public: virtual ~JobSelector() {} /** Should return true if the specified thread matches your criteria for whatever operation that this object is being used for. Any implementation of this method must be extremely fast and thread-safe! */ virtual bool isJobSuitable (ThreadPoolJob* job) = 0; }; /** Adds a job to the queue. Once a job has been added, then the next time a thread is free, it will run the job's ThreadPoolJob::runJob() method. Depending on the return value of the runJob() method, the pool will either remove the job from the pool or add it to the back of the queue to be run again. */ void addJob (ThreadPoolJob* job); /** Tries to remove a job from the pool. If the job isn't yet running, this will simply remove it. If it is running, it will wait for it to finish. If the timeout period expires before the job finishes running, then the job will be left in the pool and this will return false. It returns true if the job is sucessfully stopped and removed. @param job the job to remove @param interruptIfRunning if true, then if the job is currently busy, its ThreadPoolJob::signalJobShouldExit() method will be called to try to interrupt it. If false, then if the job will be allowed to run until it stops normally (or the timeout expires) @param timeOutMilliseconds the length of time this method should wait for the job to finish before giving up and returning false */ bool removeJob (ThreadPoolJob* job, bool interruptIfRunning, int timeOutMilliseconds); /** Tries to remove all jobs from the pool. @param interruptRunningJobs if true, then all running jobs will have their ThreadPoolJob::signalJobShouldExit() methods called to try to interrupt them @param timeOutMilliseconds the length of time this method should wait for all the jobs to finish before giving up and returning false @param deleteInactiveJobs if true, any jobs that aren't currently running will be deleted. If false, they will simply be removed from the pool. Jobs that are already running when this method is called can choose whether they should be deleted by returning jobHasFinishedAndShouldBeDeleted from their runJob() method. @param selectedJobsToRemove if this is non-zero, the JobSelector object is asked to decide which jobs should be removed. If it is zero, all jobs are removed @returns true if all jobs are successfully stopped and removed; false if the timeout period expires while waiting for one or more jobs to stop */ bool removeAllJobs (bool interruptRunningJobs, int timeOutMilliseconds, bool deleteInactiveJobs = false, JobSelector* selectedJobsToRemove = 0); /** Returns the number of jobs currently running or queued. */ int getNumJobs() const; /** Returns one of the jobs in the queue. Note that this can be a very volatile list as jobs might be continuously getting shifted around in the list, and this method may return 0 if the index is currently out-of-range. */ ThreadPoolJob* getJob (int index) const; /** Returns true if the given job is currently queued or running. @see isJobRunning() */ bool contains (const ThreadPoolJob* job) const; /** Returns true if the given job is currently being run by a thread. */ bool isJobRunning (const ThreadPoolJob* job) const; /** Waits until a job has finished running and has been removed from the pool. This will wait until the job is no longer in the pool - i.e. until its runJob() method returns ThreadPoolJob::jobHasFinished. If the timeout period expires before the job finishes, this will return false; it returns true if the job has finished successfully. */ bool waitForJobToFinish (const ThreadPoolJob* job, int timeOutMilliseconds) const; /** Returns a list of the names of all the jobs currently running or queued. If onlyReturnActiveJobs is true, only the ones currently running are returned. */ const StringArray getNamesOfAllJobs (bool onlyReturnActiveJobs) const; /** Changes the priority of all the threads. This will call Thread::setPriority() for each thread in the pool. May return false if for some reason the priority can't be changed. */ bool setThreadPriorities (int newPriority); private: const int threadStopTimeout; int priority; class ThreadPoolThread; friend class OwnedArray ; OwnedArray threads; Array jobs; CriticalSection lock; uint32 lastJobEndTime; WaitableEvent jobFinishedSignal; friend class ThreadPoolThread; bool runNextJob(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadPool); }; #endif // __JUCE_THREADPOOL_JUCEHEADER__ /*** End of inlined file: juce_ThreadPool.h ***/ #endif #ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ /*** Start of inlined file: juce_TimeSliceThread.h ***/ #ifndef __JUCE_TIMESLICETHREAD_JUCEHEADER__ #define __JUCE_TIMESLICETHREAD_JUCEHEADER__ /** Used by the TimeSliceThread class. To register your class with a TimeSliceThread, derive from this class and use the TimeSliceThread::addTimeSliceClient() method to add it to the list. Make sure you always call TimeSliceThread::removeTimeSliceClient() before deleting your client! @see TimeSliceThread */ class JUCE_API TimeSliceClient { public: /** Destructor. */ virtual ~TimeSliceClient() {} /** Called back by a TimeSliceThread. When you register this class with it, a TimeSliceThread will repeatedly call this method. The implementation of this method should use its time-slice to do something that's quick - never block for longer than absolutely necessary. @returns Your method should return true if it needs more time, or false if it's not too busy and doesn't need calling back urgently. If all the thread's clients indicate that they're not busy, then it'll save CPU by sleeping for up to half a second in between callbacks. You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method. */ virtual bool useTimeSlice() = 0; }; /** A thread that keeps a list of clients, and calls each one in turn, giving them all a chance to run some sort of short task. @see TimeSliceClient, Thread */ class JUCE_API TimeSliceThread : public Thread { public: /** Creates a TimeSliceThread. When first created, the thread is not running. Use the startThread() method to start it. */ explicit TimeSliceThread (const String& threadName); /** Destructor. Deleting a Thread object that is running will only give the thread a brief opportunity to stop itself cleanly, so it's recommended that you should always call stopThread() with a decent timeout before deleting, to avoid the thread being forcibly killed (which is a Bad Thing). */ ~TimeSliceThread(); /** Adds a client to the list. The client's callbacks will start immediately (possibly before the method has returned). */ void addTimeSliceClient (TimeSliceClient* client); /** Removes a client from the list. This method will make sure that all callbacks to the client have completely finished before the method returns. */ void removeTimeSliceClient (TimeSliceClient* client); /** Returns the number of registered clients. */ int getNumClients() const; /** Returns one of the registered clients. */ TimeSliceClient* getClient (int index) const; /** @internal */ void run(); private: CriticalSection callbackLock, listLock; Array clients; int index; TimeSliceClient* clientBeingCalled; bool clientsChanged; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TimeSliceThread); }; #endif // __JUCE_TIMESLICETHREAD_JUCEHEADER__ /*** End of inlined file: juce_TimeSliceThread.h ***/ #endif #ifndef __JUCE_WAITABLEEVENT_JUCEHEADER__ #endif #endif /*** End of inlined file: juce_core_includes.h ***/ // if you're compiling a command-line app, you might want to just include the core headers, // so you can set this macro before including juce.h #if ! JUCE_ONLY_BUILD_CORE_LIBRARY /*** Start of inlined file: juce_app_includes.h ***/ #ifndef __JUCE_JUCE_APP_INCLUDES_INCLUDEFILES__ #define __JUCE_JUCE_APP_INCLUDES_INCLUDEFILES__ #ifndef __JUCE_APPLICATION_JUCEHEADER__ /*** Start of inlined file: juce_Application.h ***/ #ifndef __JUCE_APPLICATION_JUCEHEADER__ #define __JUCE_APPLICATION_JUCEHEADER__ /*** Start of inlined file: juce_ApplicationCommandTarget.h ***/ #ifndef __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ #define __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ /*** Start of inlined file: juce_Component.h ***/ #ifndef __JUCE_COMPONENT_JUCEHEADER__ #define __JUCE_COMPONENT_JUCEHEADER__ /*** Start of inlined file: juce_MouseCursor.h ***/ #ifndef __JUCE_MOUSECURSOR_JUCEHEADER__ #define __JUCE_MOUSECURSOR_JUCEHEADER__ class Image; class ComponentPeer; class Component; /** Represents a mouse cursor image. This object can either be used to represent one of the standard mouse cursor shapes, or a custom one generated from an image. */ class JUCE_API MouseCursor { public: /** The set of available standard mouse cursors. */ enum StandardCursorType { NoCursor = 0, /**< An invisible cursor. */ NormalCursor, /**< The stardard arrow cursor. */ WaitCursor, /**< The normal hourglass or spinning-beachball 'busy' cursor. */ IBeamCursor, /**< A vertical I-beam for positioning within text. */ CrosshairCursor, /**< A pair of crosshairs. */ CopyingCursor, /**< The normal arrow cursor, but with a "+" on it to indicate that you're dragging a copy of something. */ PointingHandCursor, /**< A hand with a pointing finger, for clicking on web-links. */ DraggingHandCursor, /**< An open flat hand for dragging heavy objects around. */ LeftRightResizeCursor, /**< An arrow pointing left and right. */ UpDownResizeCursor, /**< an arrow pointing up and down. */ UpDownLeftRightResizeCursor, /**< An arrow pointing up, down, left and right. */ TopEdgeResizeCursor, /**< A platform-specific cursor for resizing the top-edge of a window. */ BottomEdgeResizeCursor, /**< A platform-specific cursor for resizing the bottom-edge of a window. */ LeftEdgeResizeCursor, /**< A platform-specific cursor for resizing the left-edge of a window. */ RightEdgeResizeCursor, /**< A platform-specific cursor for resizing the right-edge of a window. */ TopLeftCornerResizeCursor, /**< A platform-specific cursor for resizing the top-left-corner of a window. */ TopRightCornerResizeCursor, /**< A platform-specific cursor for resizing the top-right-corner of a window. */ BottomLeftCornerResizeCursor, /**< A platform-specific cursor for resizing the bottom-left-corner of a window. */ BottomRightCornerResizeCursor /**< A platform-specific cursor for resizing the bottom-right-corner of a window. */ }; /** Creates the standard arrow cursor. */ MouseCursor(); /** Creates one of the standard mouse cursor */ MouseCursor (StandardCursorType type); /** Creates a custom cursor from an image. @param image the image to use for the cursor - if this is bigger than the system can manage, it might get scaled down first, and might also have to be turned to black-and-white if it can't do colour cursors. @param hotSpotX the x position of the cursor's hotspot within the image @param hotSpotY the y position of the cursor's hotspot within the image */ MouseCursor (const Image& image, int hotSpotX, int hotSpotY); /** Creates a copy of another cursor object. */ MouseCursor (const MouseCursor& other); /** Copies this cursor from another object. */ MouseCursor& operator= (const MouseCursor& other); /** Destructor. */ ~MouseCursor(); /** Checks whether two mouse cursors are the same. For custom cursors, two cursors created from the same image won't be recognised as the same, only MouseCursor objects that have been copied from the same object. */ bool operator== (const MouseCursor& other) const throw(); /** Checks whether two mouse cursors are the same. For custom cursors, two cursors created from the same image won't be recognised as the same, only MouseCursor objects that have been copied from the same object. */ bool operator!= (const MouseCursor& other) const throw(); /** Makes the system show its default 'busy' cursor. This will turn the system cursor to an hourglass or spinning beachball until the next time the mouse is moved, or hideWaitCursor() is called. This is handy if the message loop is about to block for a couple of seconds while busy and you want to give the user feedback about this. @see MessageManager::setTimeBeforeShowingWaitCursor */ static void showWaitCursor(); /** If showWaitCursor has been called, this will return the mouse to its normal state. This will look at what component is under the mouse, and update the cursor to be the correct one for that component. @see showWaitCursor */ static void hideWaitCursor(); private: class SharedCursorHandle; friend class SharedCursorHandle; SharedCursorHandle* cursorHandle; friend class MouseInputSourceInternal; void showInWindow (ComponentPeer* window) const; void showInAllWindows() const; void* getHandle() const throw(); static void* createMouseCursorFromImage (const Image& image, int hotspotX, int hotspotY); static void* createStandardMouseCursor (MouseCursor::StandardCursorType type); static void deleteMouseCursor (void* cursorHandle, bool isStandard); JUCE_LEAK_DETECTOR (MouseCursor); }; #endif // __JUCE_MOUSECURSOR_JUCEHEADER__ /*** End of inlined file: juce_MouseCursor.h ***/ /*** Start of inlined file: juce_MouseListener.h ***/ #ifndef __JUCE_MOUSELISTENER_JUCEHEADER__ #define __JUCE_MOUSELISTENER_JUCEHEADER__ class MouseEvent; /** A MouseListener can be registered with a component to receive callbacks about mouse events that happen to that component. @see Component::addMouseListener, Component::removeMouseListener */ class JUCE_API MouseListener { public: /** Destructor. */ virtual ~MouseListener() {} /** Called when the mouse moves inside a component. If the mouse button isn't pressed and the mouse moves over a component, this will be called to let the component react to this. A component will always get a mouseEnter callback before a mouseMove. @param e details about the position and status of the mouse event, including the source component in which it occurred @see mouseEnter, mouseExit, mouseDrag, contains */ virtual void mouseMove (const MouseEvent& e); /** Called when the mouse first enters a component. If the mouse button isn't pressed and the mouse moves into a component, this will be called to let the component react to this. When the mouse button is pressed and held down while being moved in or out of a component, no mouseEnter or mouseExit callbacks are made - only mouseDrag messages are sent to the component that the mouse was originally clicked on, until the button is released. @param e details about the position and status of the mouse event, including the source component in which it occurred @see mouseExit, mouseDrag, mouseMove, contains */ virtual void mouseEnter (const MouseEvent& e); /** Called when the mouse moves out of a component. This will be called when the mouse moves off the edge of this component. If the mouse button was pressed, and it was then dragged off the edge of the component and released, then this callback will happen when the button is released, after the mouseUp callback. @param e details about the position and status of the mouse event, including the source component in which it occurred @see mouseEnter, mouseDrag, mouseMove, contains */ virtual void mouseExit (const MouseEvent& e); /** Called when a mouse button is pressed. The MouseEvent object passed in contains lots of methods for finding out which button was pressed, as well as which modifier keys (e.g. shift, ctrl) were held down at the time. Once a button is held down, the mouseDrag method will be called when the mouse moves, until the button is released. @param e details about the position and status of the mouse event, including the source component in which it occurred @see mouseUp, mouseDrag, mouseDoubleClick, contains */ virtual void mouseDown (const MouseEvent& e); /** Called when the mouse is moved while a button is held down. When a mouse button is pressed inside a component, that component receives mouseDrag callbacks each time the mouse moves, even if the mouse strays outside the component's bounds. @param e details about the position and status of the mouse event, including the source component in which it occurred @see mouseDown, mouseUp, mouseMove, contains, setDragRepeatInterval */ virtual void mouseDrag (const MouseEvent& e); /** Called when a mouse button is released. A mouseUp callback is sent to the component in which a button was pressed even if the mouse is actually over a different component when the button is released. The MouseEvent object passed in contains lots of methods for finding out which buttons were down just before they were released. @param e details about the position and status of the mouse event, including the source component in which it occurred @see mouseDown, mouseDrag, mouseDoubleClick, contains */ virtual void mouseUp (const MouseEvent& e); /** Called when a mouse button has been double-clicked on a component. The MouseEvent object passed in contains lots of methods for finding out which button was pressed, as well as which modifier keys (e.g. shift, ctrl) were held down at the time. @param e details about the position and status of the mouse event, including the source component in which it occurred @see mouseDown, mouseUp */ virtual void mouseDoubleClick (const MouseEvent& e); /** Called when the mouse-wheel is moved. This callback is sent to the component that the mouse is over when the wheel is moved. If not overridden, the component will forward this message to its parent, so that parent components can collect mouse-wheel messages that happen to child components which aren't interested in them. @param e details about the position and status of the mouse event, including the source component in which it occurred @param wheelIncrementX the speed and direction of the horizontal scroll-wheel - a positive value means the wheel has been pushed to the right, negative means it was pushed to the left @param wheelIncrementY the speed and direction of the vertical scroll-wheel - a positive value means the wheel has been pushed upwards, negative means it was pushed downwards */ virtual void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); }; #endif // __JUCE_MOUSELISTENER_JUCEHEADER__ /*** End of inlined file: juce_MouseListener.h ***/ /*** Start of inlined file: juce_MouseEvent.h ***/ #ifndef __JUCE_MOUSEEVENT_JUCEHEADER__ #define __JUCE_MOUSEEVENT_JUCEHEADER__ class Component; class MouseInputSource; /*** Start of inlined file: juce_ModifierKeys.h ***/ #ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__ #define __JUCE_MODIFIERKEYS_JUCEHEADER__ /** Represents the state of the mouse buttons and modifier keys. This is used both by mouse events and by KeyPress objects to describe the state of keys such as shift, control, alt, etc. @see KeyPress, MouseEvent::mods */ class JUCE_API ModifierKeys { public: /** Creates a ModifierKeys object from a raw set of flags. @param flags to represent the keys that are down @see shiftModifier, ctrlModifier, altModifier, leftButtonModifier, rightButtonModifier, commandModifier, popupMenuClickModifier */ ModifierKeys (int flags = 0) throw(); /** Creates a copy of another object. */ ModifierKeys (const ModifierKeys& other) throw(); /** Copies this object from another one. */ ModifierKeys& operator= (const ModifierKeys& other) throw(); /** Checks whether the 'command' key flag is set (or 'ctrl' on Windows/Linux). This is a platform-agnostic way of checking for the operating system's preferred command-key modifier - so on the Mac it tests for the Apple key, on Windows/Linux, it's actually checking for the CTRL key. */ inline bool isCommandDown() const throw() { return (flags & commandModifier) != 0; } /** Checks whether the user is trying to launch a pop-up menu. This checks for platform-specific modifiers that might indicate that the user is following the operating system's normal method of showing a pop-up menu. So on Windows/Linux, this method is really testing for a right-click. On the Mac, it tests for either the CTRL key being down, or a right-click. */ inline bool isPopupMenu() const throw() { return (flags & popupMenuClickModifier) != 0; } /** Checks whether the flag is set for the left mouse-button. */ inline bool isLeftButtonDown() const throw() { return (flags & leftButtonModifier) != 0; } /** Checks whether the flag is set for the right mouse-button. Note that for detecting popup-menu clicks, you should be using isPopupMenu() instead, as this is platform-independent (and makes your code more explanatory too). */ inline bool isRightButtonDown() const throw() { return (flags & rightButtonModifier) != 0; } inline bool isMiddleButtonDown() const throw() { return (flags & middleButtonModifier) != 0; } /** Tests for any of the mouse-button flags. */ inline bool isAnyMouseButtonDown() const throw() { return (flags & allMouseButtonModifiers) != 0; } /** Tests for any of the modifier key flags. */ inline bool isAnyModifierKeyDown() const throw() { return (flags & (shiftModifier | ctrlModifier | altModifier | commandModifier)) != 0; } /** Checks whether the shift key's flag is set. */ inline bool isShiftDown() const throw() { return (flags & shiftModifier) != 0; } /** Checks whether the CTRL key's flag is set. Remember that it's better to use the platform-agnostic routines to test for command-key and popup-menu modifiers. @see isCommandDown, isPopupMenu */ inline bool isCtrlDown() const throw() { return (flags & ctrlModifier) != 0; } /** Checks whether the shift key's flag is set. */ inline bool isAltDown() const throw() { return (flags & altModifier) != 0; } /** Flags that represent the different keys. */ enum Flags { /** Shift key flag. */ shiftModifier = 1, /** CTRL key flag. */ ctrlModifier = 2, /** ALT key flag. */ altModifier = 4, /** Left mouse button flag. */ leftButtonModifier = 16, /** Right mouse button flag. */ rightButtonModifier = 32, /** Middle mouse button flag. */ middleButtonModifier = 64, #if JUCE_MAC /** Command key flag - on windows this is the same as the CTRL key flag. */ commandModifier = 8, /** Popup menu flag - on windows this is the same as rightButtonModifier, on the Mac it's the same as (rightButtonModifier | ctrlModifier). */ popupMenuClickModifier = rightButtonModifier | ctrlModifier, #else /** Command key flag - on windows this is the same as the CTRL key flag. */ commandModifier = ctrlModifier, /** Popup menu flag - on windows this is the same as rightButtonModifier, on the Mac it's the same as (rightButtonModifier | ctrlModifier). */ popupMenuClickModifier = rightButtonModifier, #endif /** Represents a combination of all the shift, alt, ctrl and command key modifiers. */ allKeyboardModifiers = shiftModifier | ctrlModifier | altModifier | commandModifier, /** Represents a combination of all the mouse buttons at once. */ allMouseButtonModifiers = leftButtonModifier | rightButtonModifier | middleButtonModifier, }; /** Returns a copy of only the mouse-button flags */ const ModifierKeys withOnlyMouseButtons() const throw() { return ModifierKeys (flags & allMouseButtonModifiers); } /** Returns a copy of only the non-mouse flags */ const ModifierKeys withoutMouseButtons() const throw() { return ModifierKeys (flags & ~allMouseButtonModifiers); } bool operator== (const ModifierKeys& other) const throw() { return flags == other.flags; } bool operator!= (const ModifierKeys& other) const throw() { return flags != other.flags; } /** Returns the raw flags for direct testing. */ inline int getRawFlags() const throw() { return flags; } inline const ModifierKeys withoutFlags (int rawFlagsToClear) const throw() { return ModifierKeys (flags & ~rawFlagsToClear); } inline const ModifierKeys withFlags (int rawFlagsToSet) const throw() { return ModifierKeys (flags | rawFlagsToSet); } /** Tests a combination of flags and returns true if any of them are set. */ inline bool testFlags (const int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } /** Returns the total number of mouse buttons that are down. */ int getNumMouseButtonsDown() const throw(); /** Creates a ModifierKeys object to represent the last-known state of the keyboard and mouse buttons. @see getCurrentModifiersRealtime */ static const ModifierKeys getCurrentModifiers() throw(); /** Creates a ModifierKeys object to represent the current state of the keyboard and mouse buttons. This isn't often needed and isn't recommended, but will actively check all the mouse and key states rather than just returning their last-known state like getCurrentModifiers() does. This is only needed in special circumstances for up-to-date modifier information at times when the app's event loop isn't running normally. Another reason to avoid this method is that it's not stateless, and calling it may update the value returned by getCurrentModifiers(), which could cause subtle changes in the behaviour of some components. */ static const ModifierKeys getCurrentModifiersRealtime() throw(); private: int flags; static ModifierKeys currentModifiers; friend class ComponentPeer; friend class MouseInputSource; friend class MouseInputSourceInternal; static void updateCurrentModifiers() throw(); }; #endif // __JUCE_MODIFIERKEYS_JUCEHEADER__ /*** End of inlined file: juce_ModifierKeys.h ***/ /*** Start of inlined file: juce_Point.h ***/ #ifndef __JUCE_POINT_JUCEHEADER__ #define __JUCE_POINT_JUCEHEADER__ /*** Start of inlined file: juce_AffineTransform.h ***/ #ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__ #define __JUCE_AFFINETRANSFORM_JUCEHEADER__ /** Represents a 2D affine-transformation matrix. An affine transformation is a transformation such as a rotation, scale, shear, resize or translation. These are used for various 2D transformation tasks, e.g. with Path objects. @see Path, Point, Line */ class JUCE_API AffineTransform { public: /** Creates an identity transform. */ AffineTransform() throw(); /** Creates a copy of another transform. */ AffineTransform (const AffineTransform& other) throw(); /** Creates a transform from a set of raw matrix values. The resulting matrix is: (mat00 mat01 mat02) (mat10 mat11 mat12) ( 0 0 1 ) */ AffineTransform (float mat00, float mat01, float mat02, float mat10, float mat11, float mat12) throw(); /** Copies from another AffineTransform object */ AffineTransform& operator= (const AffineTransform& other) throw(); /** Compares two transforms. */ bool operator== (const AffineTransform& other) const throw(); /** Compares two transforms. */ bool operator!= (const AffineTransform& other) const throw(); /** A ready-to-use identity transform, which you can use to append other transformations to. e.g. @code AffineTransform myTransform = AffineTransform::identity.rotated (.5f) .scaled (2.0f); @endcode */ static const AffineTransform identity; /** Transforms a 2D co-ordinate using this matrix. */ template void transformPoint (ValueType& x, ValueType& y) const throw() { const ValueType oldX = x; x = static_cast (mat00 * oldX + mat01 * y + mat02); y = static_cast (mat10 * oldX + mat11 * y + mat12); } /** Transforms two 2D co-ordinates using this matrix. This is just a shortcut for calling transformPoint() on each of these pairs of coordinates in turn. (And putting all the calculations into one function hopefully also gives the compiler a bit more scope for pipelining it). */ template void transformPoints (ValueType& x1, ValueType& y1, ValueType& x2, ValueType& y2) const throw() { const ValueType oldX1 = x1, oldX2 = x2; x1 = static_cast (mat00 * oldX1 + mat01 * y1 + mat02); y1 = static_cast (mat10 * oldX1 + mat11 * y1 + mat12); x2 = static_cast (mat00 * oldX2 + mat01 * y2 + mat02); y2 = static_cast (mat10 * oldX2 + mat11 * y2 + mat12); } /** Transforms three 2D co-ordinates using this matrix. This is just a shortcut for calling transformPoint() on each of these pairs of coordinates in turn. (And putting all the calculations into one function hopefully also gives the compiler a bit more scope for pipelining it). */ template void transformPoints (ValueType& x1, ValueType& y1, ValueType& x2, ValueType& y2, ValueType& x3, ValueType& y3) const throw() { const ValueType oldX1 = x1, oldX2 = x2, oldX3 = x3; x1 = static_cast (mat00 * oldX1 + mat01 * y1 + mat02); y1 = static_cast (mat10 * oldX1 + mat11 * y1 + mat12); x2 = static_cast (mat00 * oldX2 + mat01 * y2 + mat02); y2 = static_cast (mat10 * oldX2 + mat11 * y2 + mat12); x3 = static_cast (mat00 * oldX3 + mat01 * y3 + mat02); y3 = static_cast (mat10 * oldX3 + mat11 * y3 + mat12); } /** Returns a new transform which is the same as this one followed by a translation. */ const AffineTransform translated (float deltaX, float deltaY) const throw(); /** Returns a new transform which is a translation. */ static const AffineTransform translation (float deltaX, float deltaY) throw(); /** Returns a transform which is the same as this one followed by a rotation. The rotation is specified by a number of radians to rotate clockwise, centred around the origin (0, 0). */ const AffineTransform rotated (float angleInRadians) const throw(); /** Returns a transform which is the same as this one followed by a rotation about a given point. The rotation is specified by a number of radians to rotate clockwise, centred around the co-ordinates passed in. */ const AffineTransform rotated (float angleInRadians, float pivotX, float pivotY) const throw(); /** Returns a new transform which is a rotation about (0, 0). */ static const AffineTransform rotation (float angleInRadians) throw(); /** Returns a new transform which is a rotation about a given point. */ static const AffineTransform rotation (float angleInRadians, float pivotX, float pivotY) throw(); /** Returns a transform which is the same as this one followed by a re-scaling. The scaling is centred around the origin (0, 0). */ const AffineTransform scaled (float factorX, float factorY) const throw(); /** Returns a transform which is the same as this one followed by a re-scaling. The scaling is centred around the origin provided. */ const AffineTransform scaled (float factorX, float factorY, float pivotX, float pivotY) const throw(); /** Returns a new transform which is a re-scale about the origin. */ static const AffineTransform scale (float factorX, float factorY) throw(); /** Returns a new transform which is a re-scale centred around the point provided. */ static const AffineTransform scale (float factorX, float factorY, float pivotX, float pivotY) throw(); /** Returns a transform which is the same as this one followed by a shear. The shear is centred around the origin (0, 0). */ const AffineTransform sheared (float shearX, float shearY) const throw(); /** Returns a shear transform, centred around the origin (0, 0). */ static const AffineTransform shear (float shearX, float shearY) throw(); /** Returns a matrix which is the inverse operation of this one. Some matrices don't have an inverse - in this case, the method will just return an identity transform. */ const AffineTransform inverted() const throw(); /** Returns the transform that will map three known points onto three coordinates that are supplied. This returns the transform that will transform (0, 0) into (x00, y00), (1, 0) to (x10, y10), and (0, 1) to (x01, y01). */ static const AffineTransform fromTargetPoints (float x00, float y00, float x10, float y10, float x01, float y01) throw(); /** Returns the transform that will map three specified points onto three target points. */ static const AffineTransform fromTargetPoints (float sourceX1, float sourceY1, float targetX1, float targetY1, float sourceX2, float sourceY2, float targetX2, float targetY2, float sourceX3, float sourceY3, float targetX3, float targetY3) throw(); /** Returns the result of concatenating another transformation after this one. */ const AffineTransform followedBy (const AffineTransform& other) const throw(); /** Returns true if this transform has no effect on points. */ bool isIdentity() const throw(); /** Returns true if this transform maps to a singularity - i.e. if it has no inverse. */ bool isSingularity() const throw(); /** Returns true if the transform only translates, and doesn't scale or rotate the points. */ bool isOnlyTranslation() const throw(); /** If this transform is only a translation, this returns the X offset. @see isOnlyTranslation */ float getTranslationX() const throw() { return mat02; } /** If this transform is only a translation, this returns the X offset. @see isOnlyTranslation */ float getTranslationY() const throw() { return mat12; } /** Returns the approximate scale factor by which lengths will be transformed. Obviously a length may be scaled by entirely different amounts depending on its direction, so this is only appropriate as a rough guide. */ float getScaleFactor() const throw(); /* The transform matrix is: (mat00 mat01 mat02) (mat10 mat11 mat12) ( 0 0 1 ) */ float mat00, mat01, mat02; float mat10, mat11, mat12; private: JUCE_LEAK_DETECTOR (AffineTransform); }; #endif // __JUCE_AFFINETRANSFORM_JUCEHEADER__ /*** End of inlined file: juce_AffineTransform.h ***/ /** A pair of (x, y) co-ordinates. The ValueType template should be a primitive type such as int, float, double, rather than a class. @see Line, Path, AffineTransform */ template class Point { public: /** Creates a point with co-ordinates (0, 0). */ Point() throw() : x (0), y (0) {} /** Creates a copy of another point. */ Point (const Point& other) throw() : x (other.x), y (other.y) {} /** Creates a point from an (x, y) position. */ Point (const ValueType initialX, const ValueType initialY) throw() : x (initialX), y (initialY) {} /** Destructor. */ ~Point() throw() {} /** Copies this point from another one. */ Point& operator= (const Point& other) throw() { x = other.x; y = other.y; return *this; } inline bool operator== (const Point& other) const throw() { return x == other.x && y == other.y; } inline bool operator!= (const Point& other) const throw() { return x != other.x || y != other.y; } /** Returns true if the point is (0, 0). */ bool isOrigin() const throw() { return x == ValueType() && y == ValueType(); } /** Returns the point's x co-ordinate. */ inline ValueType getX() const throw() { return x; } /** Returns the point's y co-ordinate. */ inline ValueType getY() const throw() { return y; } /** Sets the point's x co-ordinate. */ inline void setX (const ValueType newX) throw() { x = newX; } /** Sets the point's y co-ordinate. */ inline void setY (const ValueType newY) throw() { y = newY; } /** Returns a point which has the same Y position as this one, but a new X. */ const Point withX (const ValueType newX) const throw() { return Point (newX, y); } /** Returns a point which has the same X position as this one, but a new Y. */ const Point withY (const ValueType newY) const throw() { return Point (x, newY); } /** Changes the point's x and y co-ordinates. */ void setXY (const ValueType newX, const ValueType newY) throw() { x = newX; y = newY; } /** Adds a pair of co-ordinates to this value. */ void addXY (const ValueType xToAdd, const ValueType yToAdd) throw() { x += xToAdd; y += yToAdd; } /** Returns a point with a given offset from this one. */ const Point translated (const ValueType xDelta, const ValueType yDelta) const throw() { return Point (x + xDelta, y + yDelta); } /** Adds two points together. */ const Point operator+ (const Point& other) const throw() { return Point (x + other.x, y + other.y); } /** Adds another point's co-ordinates to this one. */ Point& operator+= (const Point& other) throw() { x += other.x; y += other.y; return *this; } /** Subtracts one points from another. */ const Point operator- (const Point& other) const throw() { return Point (x - other.x, y - other.y); } /** Subtracts another point's co-ordinates to this one. */ Point& operator-= (const Point& other) throw() { x -= other.x; y -= other.y; return *this; } /** Returns a point whose coordinates are multiplied by a given value. */ const Point operator* (const ValueType multiplier) const throw() { return Point (x * multiplier, y * multiplier); } /** Multiplies the point's co-ordinates by a value. */ Point& operator*= (const ValueType multiplier) throw() { x *= multiplier; y *= multiplier; return *this; } /** Returns a point whose coordinates are divided by a given value. */ const Point operator/ (const ValueType divisor) const throw() { return Point (x / divisor, y / divisor); } /** Divides the point's co-ordinates by a value. */ Point& operator/= (const ValueType divisor) throw() { x /= divisor; y /= divisor; return *this; } /** Returns the inverse of this point. */ const Point operator-() const throw() { return Point (-x, -y); } /** Returns the straight-line distance between this point and another one. */ ValueType getDistanceFromOrigin() const throw() { return juce_hypot (x, y); } /** Returns the straight-line distance between this point and another one. */ ValueType getDistanceFrom (const Point& other) const throw() { return juce_hypot (x - other.x, y - other.y); } /** Returns the angle from this point to another one. The return value is the number of radians clockwise from the 3 o'clock direction, where this point is the centre and the other point is on the circumference. */ ValueType getAngleToPoint (const Point& other) const throw() { return (ValueType) std::atan2 (other.x - x, other.y - y); } /** Taking this point to be the centre of a circle, this returns a point on its circumference. @param radius the radius of the circle. @param angle the angle of the point, in radians clockwise from the 12 o'clock position. */ const Point getPointOnCircumference (const float radius, const float angle) const throw() { return Point (x + radius * std::sin (angle), y - radius * std::cos (angle)); } /** Taking this point to be the centre of an ellipse, this returns a point on its circumference. @param radiusX the horizontal radius of the circle. @param radiusY the vertical radius of the circle. @param angle the angle of the point, in radians clockwise from the 12 o'clock position. */ const Point getPointOnCircumference (const float radiusX, const float radiusY, const float angle) const throw() { return Point (x + radiusX * std::sin (angle), y - radiusY * std::cos (angle)); } /** Uses a transform to change the point's co-ordinates. This will only compile if ValueType = float! @see AffineTransform::transformPoint */ void applyTransform (const AffineTransform& transform) throw() { transform.transformPoint (x, y); } /** Returns the position of this point, if it is transformed by a given AffineTransform. */ const Point transformedBy (const AffineTransform& transform) const throw() { return Point (transform.mat00 * x + transform.mat01 * y + transform.mat02, transform.mat10 * x + transform.mat11 * y + transform.mat12); } /** Casts this point to a Point object. */ const Point toFloat() const throw() { return Point (static_cast (x), static_cast (y)); } /** Casts this point to a Point object. */ const Point toInt() const throw() { return Point (static_cast (x), static_cast (y)); } /** Returns the point as a string in the form "x, y". */ const String toString() const { return String (x) + ", " + String (y); } private: ValueType x, y; }; #endif // __JUCE_POINT_JUCEHEADER__ /*** End of inlined file: juce_Point.h ***/ /** Contains position and status information about a mouse event. @see MouseListener, Component::mouseMove, Component::mouseEnter, Component::mouseExit, Component::mouseDown, Component::mouseUp, Component::mouseDrag */ class JUCE_API MouseEvent { public: /** Creates a MouseEvent. Normally an application will never need to use this. @param source the source that's invoking the event @param position the position of the mouse, relative to the component that is passed-in @param modifiers the key modifiers at the time of the event @param eventComponent the component that the mouse event applies to @param originator the component that originally received the event @param eventTime the time the event happened @param mouseDownPos the position of the corresponding mouse-down event (relative to the component that is passed-in). If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be the same as the current mouse-x position. @param mouseDownTime the time at which the corresponding mouse-down event happened If there isn't a corresponding mouse-down (e.g. for a mouse-move), this will just be the same as the current mouse-event time. @param numberOfClicks how many clicks, e.g. a double-click event will be 2, a triple-click will be 3, etc @param mouseWasDragged whether the mouse has been dragged significantly since the previous mouse-down */ MouseEvent (MouseInputSource& source, const Point& position, const ModifierKeys& modifiers, Component* eventComponent, Component* originator, const Time& eventTime, const Point mouseDownPos, const Time& mouseDownTime, int numberOfClicks, bool mouseWasDragged) throw(); /** Destructor. */ ~MouseEvent() throw(); /** The x-position of the mouse when the event occurred. This value is relative to the top-left of the component to which the event applies (as indicated by the MouseEvent::eventComponent field). */ const int x; /** The y-position of the mouse when the event occurred. This value is relative to the top-left of the component to which the event applies (as indicated by the MouseEvent::eventComponent field). */ const int y; /** The key modifiers associated with the event. This will let you find out which mouse buttons were down, as well as which modifier keys were held down. When used for mouse-up events, this will indicate the state of the mouse buttons just before they were released, so that you can tell which button they let go of. */ const ModifierKeys mods; /** The component that this event applies to. This is usually the component that the mouse was over at the time, but for mouse-drag events the mouse could actually be over a different component and the events are still sent to the component that the button was originally pressed on. The x and y member variables are relative to this component's position. If you use getEventRelativeTo() to retarget this object to be relative to a different component, this pointer will be updated, but originalComponent remains unchanged. @see originalComponent */ Component* const eventComponent; /** The component that the event first occurred on. If you use getEventRelativeTo() to retarget this object to be relative to a different component, this value remains unchanged to indicate the first component that received it. @see eventComponent */ Component* const originalComponent; /** The time that this mouse-event occurred. */ const Time eventTime; /** The source device that generated this event. */ MouseInputSource& source; /** Returns the x co-ordinate of the last place that a mouse was pressed. The co-ordinate is relative to the component specified in MouseEvent::component. @see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked */ int getMouseDownX() const throw(); /** Returns the y co-ordinate of the last place that a mouse was pressed. The co-ordinate is relative to the component specified in MouseEvent::component. @see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked */ int getMouseDownY() const throw(); /** Returns the co-ordinates of the last place that a mouse was pressed. The co-ordinates are relative to the component specified in MouseEvent::component. @see getDistanceFromDragStart, getDistanceFromDragStartX, mouseWasClicked */ const Point getMouseDownPosition() const throw(); /** Returns the straight-line distance between where the mouse is now and where it was the last time the button was pressed. This is quite handy for things like deciding whether the user has moved far enough for it to be considered a drag operation. @see getDistanceFromDragStartX */ int getDistanceFromDragStart() const throw(); /** Returns the difference between the mouse's current x postion and where it was when the button was last pressed. @see getDistanceFromDragStart */ int getDistanceFromDragStartX() const throw(); /** Returns the difference between the mouse's current y postion and where it was when the button was last pressed. @see getDistanceFromDragStart */ int getDistanceFromDragStartY() const throw(); /** Returns the difference between the mouse's current postion and where it was when the button was last pressed. @see getDistanceFromDragStart */ const Point getOffsetFromDragStart() const throw(); /** Returns true if the mouse has just been clicked. Used in either your mouseUp() or mouseDrag() methods, this will tell you whether the user has dragged the mouse more than a few pixels from the place where the mouse-down occurred. Once they have dragged it far enough for this method to return false, it will continue to return false until the mouse-up, even if they move the mouse back to the same position where they originally pressed it. This means that it's very handy for objects that can either be clicked on or dragged, as you can use it in the mouseDrag() callback to ignore any small movements they might make while clicking. @returns true if the mouse wasn't dragged by more than a few pixels between the last time the button was pressed and released. */ bool mouseWasClicked() const throw(); /** For a click event, the number of times the mouse was clicked in succession. So for example a double-click event will return 2, a triple-click 3, etc. */ int getNumberOfClicks() const throw() { return numberOfClicks; } /** Returns the time that the mouse button has been held down for. If called from a mouseDrag or mouseUp callback, this will return the number of milliseconds since the corresponding mouseDown event occurred. If called in other contexts, e.g. a mouseMove, then the returned value may be 0 or an undefined value. */ int getLengthOfMousePress() const throw(); /** The position of the mouse when the event occurred. This position is relative to the top-left of the component to which the event applies (as indicated by the MouseEvent::eventComponent field). */ const Point getPosition() const throw(); /** Returns the mouse x position of this event, in global screen co-ordinates. The co-ordinates are relative to the top-left of the main monitor. @see getScreenPosition */ int getScreenX() const; /** Returns the mouse y position of this event, in global screen co-ordinates. The co-ordinates are relative to the top-left of the main monitor. @see getScreenPosition */ int getScreenY() const; /** Returns the mouse position of this event, in global screen co-ordinates. The co-ordinates are relative to the top-left of the main monitor. @see getMouseDownScreenPosition */ const Point getScreenPosition() const; /** Returns the x co-ordinate at which the mouse button was last pressed. The co-ordinates are relative to the top-left of the main monitor. @see getMouseDownScreenPosition */ int getMouseDownScreenX() const; /** Returns the y co-ordinate at which the mouse button was last pressed. The co-ordinates are relative to the top-left of the main monitor. @see getMouseDownScreenPosition */ int getMouseDownScreenY() const; /** Returns the co-ordinates at which the mouse button was last pressed. The co-ordinates are relative to the top-left of the main monitor. @see getScreenPosition */ const Point getMouseDownScreenPosition() const; /** Creates a version of this event that is relative to a different component. The x and y positions of the event that is returned will have been adjusted to be relative to the new component. */ const MouseEvent getEventRelativeTo (Component* otherComponent) const throw(); /** Creates a copy of this event with a different position. All other members of the event object are the same, but the x and y are replaced with these new values. */ const MouseEvent withNewPosition (const Point& newPosition) const throw(); /** Changes the application-wide setting for the double-click time limit. This is the maximum length of time between mouse-clicks for it to be considered a double-click. It's used by the Component class. @see getDoubleClickTimeout, MouseListener::mouseDoubleClick */ static void setDoubleClickTimeout (int timeOutMilliseconds) throw(); /** Returns the application-wide setting for the double-click time limit. This is the maximum length of time between mouse-clicks for it to be considered a double-click. It's used by the Component class. @see setDoubleClickTimeout, MouseListener::mouseDoubleClick */ static int getDoubleClickTimeout() throw(); private: const Point mouseDownPos; const Time mouseDownTime; const int numberOfClicks; const bool wasMovedSinceMouseDown; static int doubleClickTimeOutMs; MouseEvent& operator= (const MouseEvent&); JUCE_LEAK_DETECTOR (MouseEvent); }; #endif // __JUCE_MOUSEEVENT_JUCEHEADER__ /*** End of inlined file: juce_MouseEvent.h ***/ /*** Start of inlined file: juce_ComponentListener.h ***/ #ifndef __JUCE_COMPONENTLISTENER_JUCEHEADER__ #define __JUCE_COMPONENTLISTENER_JUCEHEADER__ class Component; /** Gets informed about changes to a component's hierarchy or position. To monitor a component for changes, register a subclass of ComponentListener with the component using Component::addComponentListener(). Be sure to deregister listeners before you delete them! @see Component::addComponentListener, Component::removeComponentListener */ class JUCE_API ComponentListener { public: /** Destructor. */ virtual ~ComponentListener() {} /** Called when the component's position or size changes. @param component the component that was moved or resized @param wasMoved true if the component's top-left corner has just moved @param wasResized true if the component's width or height has just changed @see Component::setBounds, Component::resized, Component::moved */ virtual void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); /** Called when the component is brought to the top of the z-order. @param component the component that was moved @see Component::toFront, Component::broughtToFront */ virtual void componentBroughtToFront (Component& component); /** Called when the component is made visible or invisible. @param component the component that changed @see Component::setVisible */ virtual void componentVisibilityChanged (Component& component); /** Called when the component has children added or removed. @param component the component whose children were changed @see Component::childrenChanged, Component::addChildComponent, Component::removeChildComponent */ virtual void componentChildrenChanged (Component& component); /** Called to indicate that the component's parents have changed. When a component is added or removed from its parent, all of its children will produce this notification (recursively - so all children of its children will also be called as well). @param component the component that this listener is registered with @see Component::parentHierarchyChanged */ virtual void componentParentHierarchyChanged (Component& component); /** Called when the component's name is changed. @see Component::setName, Component::getName */ virtual void componentNameChanged (Component& component); /** Called when the component is in the process of being deleted. This callback is made from inside the destructor, so be very, very cautious about what you do in here. In particular, bear in mind that it's the Component base class's destructor that calls this - so if the object that's being deleted is a subclass of Component, then the subclass layers of the object will already have been destructed when it gets to this point! */ virtual void componentBeingDeleted (Component& component); }; #endif // __JUCE_COMPONENTLISTENER_JUCEHEADER__ /*** End of inlined file: juce_ComponentListener.h ***/ /*** Start of inlined file: juce_KeyListener.h ***/ #ifndef __JUCE_KEYLISTENER_JUCEHEADER__ #define __JUCE_KEYLISTENER_JUCEHEADER__ /*** Start of inlined file: juce_KeyPress.h ***/ #ifndef __JUCE_KEYPRESS_JUCEHEADER__ #define __JUCE_KEYPRESS_JUCEHEADER__ /** Represents a key press, including any modifier keys that are needed. E.g. a KeyPress might represent CTRL+C, SHIFT+ALT+H, Spacebar, Escape, etc. @see Component, KeyListener, Button::addShortcut, KeyPressMappingManager */ class JUCE_API KeyPress { public: /** Creates an (invalid) KeyPress. @see isValid */ KeyPress() throw(); /** Creates a KeyPress for a key and some modifiers. e.g. CTRL+C would be: KeyPress ('c', ModifierKeys::ctrlModifier) SHIFT+Escape would be: KeyPress (KeyPress::escapeKey, ModifierKeys::shiftModifier) @param keyCode a code that represents the key - this value must be one of special constants listed in this class, or an 8-bit character code such as a letter (case is ignored), digit or a simple key like "," or ".". Note that this isn't the same as the textCharacter parameter, so for example a keyCode of 'a' and a shift-key modifier should have a textCharacter value of 'A'. @param modifiers the modifiers to associate with the keystroke @param textCharacter the character that would be printed if someone typed this keypress into a text editor. This value may be null if the keypress is a non-printing character @see getKeyCode, isKeyCode, getModifiers */ KeyPress (int keyCode, const ModifierKeys& modifiers, juce_wchar textCharacter) throw(); /** Creates a keypress with a keyCode but no modifiers or text character. */ KeyPress (int keyCode) throw(); /** Creates a copy of another KeyPress. */ KeyPress (const KeyPress& other) throw(); /** Copies this KeyPress from another one. */ KeyPress& operator= (const KeyPress& other) throw(); /** Compares two KeyPress objects. */ bool operator== (const KeyPress& other) const throw(); /** Compares two KeyPress objects. */ bool operator!= (const KeyPress& other) const throw(); /** Returns true if this is a valid KeyPress. A null keypress can be created by the default constructor, in case it's needed. */ bool isValid() const throw() { return keyCode != 0; } /** Returns the key code itself. This will either be one of the special constants defined in this class, or an 8-bit character code. */ int getKeyCode() const throw() { return keyCode; } /** Returns the key modifiers. @see ModifierKeys */ const ModifierKeys getModifiers() const throw() { return mods; } /** Returns the character that is associated with this keypress. This is the character that you'd expect to see printed if you press this keypress in a text editor or similar component. */ juce_wchar getTextCharacter() const throw() { return textCharacter; } /** Checks whether the KeyPress's key is the same as the one provided, without checking the modifiers. The values for key codes can either be one of the special constants defined in this class, or an 8-bit character code. @see getKeyCode */ bool isKeyCode (int keyCodeToCompare) const throw() { return keyCode == keyCodeToCompare; } /** Converts a textual key description to a KeyPress. This attempts to decode a textual version of a keypress, e.g. "CTRL + C" or "SPACE". This isn't designed to cope with any kind of input, but should be given the strings that are created by the getTextDescription() method. If the string can't be parsed, the object returned will be invalid. @see getTextDescription */ static const KeyPress createFromDescription (const String& textVersion); /** Creates a textual description of the key combination. e.g. "CTRL + C" or "DELETE". To store a keypress in a file, use this method, along with createFromDescription() to retrieve it later. */ const String getTextDescription() const; /** Checks whether the user is currently holding down the keys that make up this KeyPress. Note that this will return false if any extra modifier keys are down - e.g. if the keypress is CTRL+X and the user is actually holding CTRL+ALT+x then it will be false. */ bool isCurrentlyDown() const; /** Checks whether a particular key is held down, irrespective of modifiers. The values for key codes can either be one of the special constants defined in this class, or an 8-bit character code. */ static bool isKeyCurrentlyDown (int keyCode); // Key codes // // Note that the actual values of these are platform-specific and may change // without warning, so don't store them anywhere as constants. For persisting/retrieving // KeyPress objects, use getTextDescription() and createFromDescription() instead. // static const int spaceKey; /**< key-code for the space bar */ static const int escapeKey; /**< key-code for the escape key */ static const int returnKey; /**< key-code for the return key*/ static const int tabKey; /**< key-code for the tab key*/ static const int deleteKey; /**< key-code for the delete key (not backspace) */ static const int backspaceKey; /**< key-code for the backspace key */ static const int insertKey; /**< key-code for the insert key */ static const int upKey; /**< key-code for the cursor-up key */ static const int downKey; /**< key-code for the cursor-down key */ static const int leftKey; /**< key-code for the cursor-left key */ static const int rightKey; /**< key-code for the cursor-right key */ static const int pageUpKey; /**< key-code for the page-up key */ static const int pageDownKey; /**< key-code for the page-down key */ static const int homeKey; /**< key-code for the home key */ static const int endKey; /**< key-code for the end key */ static const int F1Key; /**< key-code for the F1 key */ static const int F2Key; /**< key-code for the F2 key */ static const int F3Key; /**< key-code for the F3 key */ static const int F4Key; /**< key-code for the F4 key */ static const int F5Key; /**< key-code for the F5 key */ static const int F6Key; /**< key-code for the F6 key */ static const int F7Key; /**< key-code for the F7 key */ static const int F8Key; /**< key-code for the F8 key */ static const int F9Key; /**< key-code for the F9 key */ static const int F10Key; /**< key-code for the F10 key */ static const int F11Key; /**< key-code for the F11 key */ static const int F12Key; /**< key-code for the F12 key */ static const int F13Key; /**< key-code for the F13 key */ static const int F14Key; /**< key-code for the F14 key */ static const int F15Key; /**< key-code for the F15 key */ static const int F16Key; /**< key-code for the F16 key */ static const int numberPad0; /**< key-code for the 0 on the numeric keypad. */ static const int numberPad1; /**< key-code for the 1 on the numeric keypad. */ static const int numberPad2; /**< key-code for the 2 on the numeric keypad. */ static const int numberPad3; /**< key-code for the 3 on the numeric keypad. */ static const int numberPad4; /**< key-code for the 4 on the numeric keypad. */ static const int numberPad5; /**< key-code for the 5 on the numeric keypad. */ static const int numberPad6; /**< key-code for the 6 on the numeric keypad. */ static const int numberPad7; /**< key-code for the 7 on the numeric keypad. */ static const int numberPad8; /**< key-code for the 8 on the numeric keypad. */ static const int numberPad9; /**< key-code for the 9 on the numeric keypad. */ static const int numberPadAdd; /**< key-code for the add sign on the numeric keypad. */ static const int numberPadSubtract; /**< key-code for the subtract sign on the numeric keypad. */ static const int numberPadMultiply; /**< key-code for the multiply sign on the numeric keypad. */ static const int numberPadDivide; /**< key-code for the divide sign on the numeric keypad. */ static const int numberPadSeparator; /**< key-code for the comma on the numeric keypad. */ static const int numberPadDecimalPoint; /**< key-code for the decimal point sign on the numeric keypad. */ static const int numberPadEquals; /**< key-code for the equals key on the numeric keypad. */ static const int numberPadDelete; /**< key-code for the delete key on the numeric keypad. */ static const int playKey; /**< key-code for a multimedia 'play' key, (not all keyboards will have one) */ static const int stopKey; /**< key-code for a multimedia 'stop' key, (not all keyboards will have one) */ static const int fastForwardKey; /**< key-code for a multimedia 'fast-forward' key, (not all keyboards will have one) */ static const int rewindKey; /**< key-code for a multimedia 'rewind' key, (not all keyboards will have one) */ private: int keyCode; ModifierKeys mods; juce_wchar textCharacter; JUCE_LEAK_DETECTOR (KeyPress); }; #endif // __JUCE_KEYPRESS_JUCEHEADER__ /*** End of inlined file: juce_KeyPress.h ***/ class Component; /** Receives callbacks when keys are pressed. You can add a key listener to a component to be informed when that component gets key events. See the Component::addListener method for more details. @see KeyPress, Component::addKeyListener, KeyPressMappingManager */ class JUCE_API KeyListener { public: /** Destructor. */ virtual ~KeyListener() {} /** Called to indicate that a key has been pressed. If your implementation returns true, then the key event is considered to have been consumed, and will not be passed on to any other components. If it returns false, then the key will be passed to other components that might want to use it. @param key the keystroke, including modifier keys @param originatingComponent the component that received the key event @see keyStateChanged, Component::keyPressed */ virtual bool keyPressed (const KeyPress& key, Component* originatingComponent) = 0; /** Called when any key is pressed or released. When this is called, classes that might be interested in the state of one or more keys can use KeyPress::isKeyCurrentlyDown() to check whether their key has changed. If your implementation returns true, then the key event is considered to have been consumed, and will not be passed on to any other components. If it returns false, then the key will be passed to other components that might want to use it. @param originatingComponent the component that received the key event @param isKeyDown true if a key is being pressed, false if one is being released @see KeyPress, Component::keyStateChanged */ virtual bool keyStateChanged (bool isKeyDown, Component* originatingComponent); }; #endif // __JUCE_KEYLISTENER_JUCEHEADER__ /*** End of inlined file: juce_KeyListener.h ***/ /*** Start of inlined file: juce_KeyboardFocusTraverser.h ***/ #ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ #define __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ class Component; /** Controls the order in which focus moves between components. The default algorithm used by this class to work out the order of traversal is as follows: - if two components both have an explicit focus order specified, then the one with the lowest number comes first (see the Component::setExplicitFocusOrder() method). - any component with an explicit focus order greater than 0 comes before ones that don't have an order specified. - any unspecified components are traversed in a left-to-right, then top-to-bottom order. If you need traversal in a more customised way, you can create a subclass of KeyboardFocusTraverser that uses your own algorithm, and use Component::createFocusTraverser() to create it. @see Component::setExplicitFocusOrder, Component::createFocusTraverser */ class JUCE_API KeyboardFocusTraverser { public: KeyboardFocusTraverser(); /** Destructor. */ virtual ~KeyboardFocusTraverser(); /** Returns the component that should be given focus after the specified one when moving "forwards". The default implementation will return the next component which is to the right of or below this one. This may return 0 if there's no suitable candidate. */ virtual Component* getNextComponent (Component* current); /** Returns the component that should be given focus after the specified one when moving "backwards". The default implementation will return the next component which is to the left of or above this one. This may return 0 if there's no suitable candidate. */ virtual Component* getPreviousComponent (Component* current); /** Returns the component that should receive focus be default within the given parent component. The default implementation will just return the foremost child component that wants focus. This may return 0 if there's no suitable candidate. */ virtual Component* getDefaultComponent (Component* parentComponent); }; #endif // __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__ /*** End of inlined file: juce_KeyboardFocusTraverser.h ***/ /*** Start of inlined file: juce_ImageEffectFilter.h ***/ #ifndef __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ #define __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ /*** Start of inlined file: juce_Graphics.h ***/ #ifndef __JUCE_GRAPHICS_JUCEHEADER__ #define __JUCE_GRAPHICS_JUCEHEADER__ /*** Start of inlined file: juce_Font.h ***/ #ifndef __JUCE_FONT_JUCEHEADER__ #define __JUCE_FONT_JUCEHEADER__ /*** Start of inlined file: juce_Typeface.h ***/ #ifndef __JUCE_TYPEFACE_JUCEHEADER__ #define __JUCE_TYPEFACE_JUCEHEADER__ /*** Start of inlined file: juce_Path.h ***/ #ifndef __JUCE_PATH_JUCEHEADER__ #define __JUCE_PATH_JUCEHEADER__ /*** Start of inlined file: juce_Line.h ***/ #ifndef __JUCE_LINE_JUCEHEADER__ #define __JUCE_LINE_JUCEHEADER__ /** Represents a line. This class contains a bunch of useful methods for various geometric tasks. The ValueType template parameter should be a primitive type - float or double are what it's designed for. Integer types will work in a basic way, but some methods that perform mathematical operations may not compile, or they may not produce sensible results. @see Point, Rectangle, Path, Graphics::drawLine */ template class Line { public: /** Creates a line, using (0, 0) as its start and end points. */ Line() throw() {} /** Creates a copy of another line. */ Line (const Line& other) throw() : start (other.start), end (other.end) { } /** Creates a line based on the co-ordinates of its start and end points. */ Line (ValueType startX, ValueType startY, ValueType endX, ValueType endY) throw() : start (startX, startY), end (endX, endY) { } /** Creates a line from its start and end points. */ Line (const Point& startPoint, const Point& endPoint) throw() : start (startPoint), end (endPoint) { } /** Copies a line from another one. */ Line& operator= (const Line& other) throw() { start = other.start; end = other.end; return *this; } /** Destructor. */ ~Line() throw() {} /** Returns the x co-ordinate of the line's start point. */ inline ValueType getStartX() const throw() { return start.getX(); } /** Returns the y co-ordinate of the line's start point. */ inline ValueType getStartY() const throw() { return start.getY(); } /** Returns the x co-ordinate of the line's end point. */ inline ValueType getEndX() const throw() { return end.getX(); } /** Returns the y co-ordinate of the line's end point. */ inline ValueType getEndY() const throw() { return end.getY(); } /** Returns the line's start point. */ inline const Point& getStart() const throw() { return start; } /** Returns the line's end point. */ inline const Point& getEnd() const throw() { return end; } /** Changes this line's start point */ void setStart (ValueType newStartX, ValueType newStartY) throw() { start.setXY (newStartX, newStartY); } /** Changes this line's end point */ void setEnd (ValueType newEndX, ValueType newEndY) throw() { end.setXY (newEndX, newEndY); } /** Changes this line's start point */ void setStart (const Point& newStart) throw() { start = newStart; } /** Changes this line's end point */ void setEnd (const Point& newEnd) throw() { end = newEnd; } /** Returns a line that is the same as this one, but with the start and end reversed, */ const Line reversed() const throw() { return Line (end, start); } /** Applies an affine transform to the line's start and end points. */ void applyTransform (const AffineTransform& transform) throw() { start.applyTransform (transform); end.applyTransform (transform); } /** Returns the length of the line. */ ValueType getLength() const throw() { return start.getDistanceFrom (end); } /** Returns true if the line's start and end x co-ordinates are the same. */ bool isVertical() const throw() { return start.getX() == end.getX(); } /** Returns true if the line's start and end y co-ordinates are the same. */ bool isHorizontal() const throw() { return start.getY() == end.getY(); } /** Returns the line's angle. This value is the number of radians clockwise from the 3 o'clock direction, where the line's start point is considered to be at the centre. */ ValueType getAngle() const throw() { return start.getAngleToPoint (end); } /** Compares two lines. */ bool operator== (const Line& other) const throw() { return start == other.start && end == other.end; } /** Compares two lines. */ bool operator!= (const Line& other) const throw() { return start != other.start || end != other.end; } /** Finds the intersection between two lines. @param line the other line @param intersection the position of the point where the lines meet (or where they would meet if they were infinitely long) the intersection (if the lines intersect). If the lines are parallel, this will just be set to the position of one of the line's endpoints. @returns true if the line segments intersect; false if they dont. Even if they don't intersect, the intersection co-ordinates returned will still be valid */ bool intersects (const Line& line, Point& intersection) const throw() { return findIntersection (start, end, line.start, line.end, intersection); } /** Finds the intersection between two lines. @param line the line to intersect with @returns the point at which the lines intersect, even if this lies beyond the end of the lines */ const Point getIntersection (const Line& line) const throw() { Point p; findIntersection (start, end, line.start, line.end, p); return p; } /** Returns the location of the point which is a given distance along this line. @param distanceFromStart the distance to move along the line from its start point. This value can be negative or longer than the line itself @see getPointAlongLineProportionally */ const Point getPointAlongLine (ValueType distanceFromStart) const throw() { return start + (end - start) * (distanceFromStart / getLength()); } /** Returns a point which is a certain distance along and to the side of this line. This effectively moves a given distance along the line, then another distance perpendicularly to this, and returns the resulting position. @param distanceFromStart the distance to move along the line from its start point. This value can be negative or longer than the line itself @param perpendicularDistance how far to move sideways from the line. If you're looking along the line from its start towards its end, then a positive value here will move to the right, negative value move to the left. */ const Point getPointAlongLine (ValueType distanceFromStart, ValueType perpendicularDistance) const throw() { const Point delta (end - start); const double length = juce_hypot ((double) delta.getX(), (double) delta.getY()); if (length == 0) return start; return Point (start.getX() + (ValueType) ((delta.getX() * distanceFromStart - delta.getY() * perpendicularDistance) / length), start.getY() + (ValueType) ((delta.getY() * distanceFromStart + delta.getX() * perpendicularDistance) / length)); } /** Returns the location of the point which is a given distance along this line proportional to the line's length. @param proportionOfLength the distance to move along the line from its start point, in multiples of the line's length. So a value of 0.0 will return the line's start point and a value of 1.0 will return its end point. (This value can be negative or greater than 1.0). @see getPointAlongLine */ const Point getPointAlongLineProportionally (ValueType proportionOfLength) const throw() { return start + (end - start) * proportionOfLength; } /** Returns the smallest distance between this line segment and a given point. So if the point is close to the line, this will return the perpendicular distance from the line; if the point is a long way beyond one of the line's end-point's, it'll return the straight-line distance to the nearest end-point. pointOnLine receives the position of the point that is found. @returns the point's distance from the line @see getPositionAlongLineOfNearestPoint */ ValueType getDistanceFromPoint (const Point& targetPoint, Point& pointOnLine) const throw() { const Point delta (end - start); const double length = delta.getX() * delta.getX() + delta.getY() * delta.getY(); if (length > 0) { const double prop = ((targetPoint.getX() - start.getX()) * delta.getX() + (targetPoint.getY() - start.getY()) * delta.getY()) / length; if (prop >= 0 && prop <= 1.0) { pointOnLine = start + delta * (ValueType) prop; return targetPoint.getDistanceFrom (pointOnLine); } } const float fromStart = targetPoint.getDistanceFrom (start); const float fromEnd = targetPoint.getDistanceFrom (end); if (fromStart < fromEnd) { pointOnLine = start; return fromStart; } else { pointOnLine = end; return fromEnd; } } /** Finds the point on this line which is nearest to a given point, and returns its position as a proportional position along the line. @returns a value 0 to 1.0 which is the distance along this line from the line's start to the point which is nearest to the point passed-in. To turn this number into a position, use getPointAlongLineProportionally(). @see getDistanceFromPoint, getPointAlongLineProportionally */ ValueType findNearestProportionalPositionTo (const Point& point) const throw() { const Point delta (end - start); const double length = delta.getX() * delta.getX() + delta.getY() * delta.getY(); return length <= 0 ? 0 : jlimit ((ValueType) 0, (ValueType) 1, (ValueType) (((point.getX() - start.getX()) * delta.getX() + (point.getY() - start.getY()) * delta.getY()) / length)); } /** Finds the point on this line which is nearest to a given point. @see getDistanceFromPoint, findNearestProportionalPositionTo */ const Point findNearestPointTo (const Point& point) const throw() { return getPointAlongLineProportionally (findNearestProportionalPositionTo (point)); } /** Returns true if the given point lies above this line. The return value is true if the point's y coordinate is less than the y coordinate of this line at the given x (assuming the line extends infinitely in both directions). */ bool isPointAbove (const Point& point) const throw() { return start.getX() != end.getX() && point.getY() < ((end.getY() - start.getY()) * (point.getX() - start.getX())) / (end.getX() - start.getX()) + start.getY(); } /** Returns a shortened copy of this line. This will chop off part of the start of this line by a certain amount, (leaving the end-point the same), and return the new line. */ const Line withShortenedStart (ValueType distanceToShortenBy) const throw() { return Line (getPointAlongLine (jmin (distanceToShortenBy, getLength())), end); } /** Returns a shortened copy of this line. This will chop off part of the end of this line by a certain amount, (leaving the start-point the same), and return the new line. */ const Line withShortenedEnd (ValueType distanceToShortenBy) const throw() { const ValueType length = getLength(); return Line (start, getPointAlongLine (length - jmin (distanceToShortenBy, length))); } private: Point start, end; static bool findIntersection (const Point& p1, const Point& p2, const Point& p3, const Point& p4, Point& intersection) throw() { if (p2 == p3) { intersection = p2; return true; } const Point d1 (p2 - p1); const Point d2 (p4 - p3); const ValueType divisor = d1.getX() * d2.getY() - d2.getX() * d1.getY(); if (divisor == 0) { if (! (d1.isOrigin() || d2.isOrigin())) { if (d1.getY() == 0 && d2.getY() != 0) { const ValueType along = (p1.getY() - p3.getY()) / d2.getY(); intersection = p1.withX (p3.getX() + along * d2.getX()); return along >= 0 && along <= (ValueType) 1; } else if (d2.getY() == 0 && d1.getY() != 0) { const ValueType along = (p3.getY() - p1.getY()) / d1.getY(); intersection = p3.withX (p1.getX() + along * d1.getX()); return along >= 0 && along <= (ValueType) 1; } else if (d1.getX() == 0 && d2.getX() != 0) { const ValueType along = (p1.getX() - p3.getX()) / d2.getX(); intersection = p1.withY (p3.getY() + along * d2.getY()); return along >= 0 && along <= (ValueType) 1; } else if (d2.getX() == 0 && d1.getX() != 0) { const ValueType along = (p3.getX() - p1.getX()) / d1.getX(); intersection = p3.withY (p1.getY() + along * d1.getY()); return along >= 0 && along <= (ValueType) 1; } } intersection = (p2 + p3) / (ValueType) 2; return false; } const ValueType along1 = ((p1.getY() - p3.getY()) * d2.getX() - (p1.getX() - p3.getX()) * d2.getY()) / divisor; intersection = p1 + d1 * along1; if (along1 < 0 || along1 > (ValueType) 1) return false; const ValueType along2 = ((p1.getY() - p3.getY()) * d1.getX() - (p1.getX() - p3.getX()) * d1.getY()) / divisor; return along2 >= 0 && along2 <= (ValueType) 1; } }; #endif // __JUCE_LINE_JUCEHEADER__ /*** End of inlined file: juce_Line.h ***/ /*** Start of inlined file: juce_Rectangle.h ***/ #ifndef __JUCE_RECTANGLE_JUCEHEADER__ #define __JUCE_RECTANGLE_JUCEHEADER__ class RectangleList; /** Manages a rectangle and allows geometric operations to be performed on it. @see RectangleList, Path, Line, Point */ template class Rectangle { public: /** Creates a rectangle of zero size. The default co-ordinates will be (0, 0, 0, 0). */ Rectangle() throw() : x (0), y (0), w (0), h (0) { } /** Creates a copy of another rectangle. */ Rectangle (const Rectangle& other) throw() : x (other.x), y (other.y), w (other.w), h (other.h) { } /** Creates a rectangle with a given position and size. */ Rectangle (const ValueType initialX, const ValueType initialY, const ValueType width, const ValueType height) throw() : x (initialX), y (initialY), w (width), h (height) { } /** Creates a rectangle with a given size, and a position of (0, 0). */ Rectangle (const ValueType width, const ValueType height) throw() : x (0), y (0), w (width), h (height) { } /** Creates a Rectangle from the positions of two opposite corners. */ Rectangle (const Point& corner1, const Point& corner2) throw() : x (jmin (corner1.getX(), corner2.getX())), y (jmin (corner1.getY(), corner2.getY())), w (corner1.getX() - corner2.getX()), h (corner1.getY() - corner2.getY()) { if (w < 0) w = -w; if (h < 0) h = -h; } /** Creates a Rectangle from a set of left, right, top, bottom coordinates. The right and bottom values must be larger than the left and top ones, or the resulting rectangle will have a negative size. */ static const Rectangle leftTopRightBottom (const ValueType left, const ValueType top, const ValueType right, const ValueType bottom) throw() { return Rectangle (left, top, right - left, bottom - top); } Rectangle& operator= (const Rectangle& other) throw() { x = other.x; y = other.y; w = other.w; h = other.h; return *this; } /** Destructor. */ ~Rectangle() throw() {} /** Returns true if the rectangle's width and height are both zero or less */ bool isEmpty() const throw() { return w <= 0 || h <= 0; } /** Returns the x co-ordinate of the rectangle's left-hand-side. */ inline ValueType getX() const throw() { return x; } /** Returns the y co-ordinate of the rectangle's top edge. */ inline ValueType getY() const throw() { return y; } /** Returns the width of the rectangle. */ inline ValueType getWidth() const throw() { return w; } /** Returns the height of the rectangle. */ inline ValueType getHeight() const throw() { return h; } /** Returns the x co-ordinate of the rectangle's right-hand-side. */ inline ValueType getRight() const throw() { return x + w; } /** Returns the y co-ordinate of the rectangle's bottom edge. */ inline ValueType getBottom() const throw() { return y + h; } /** Returns the x co-ordinate of the rectangle's centre. */ ValueType getCentreX() const throw() { return x + w / (ValueType) 2; } /** Returns the y co-ordinate of the rectangle's centre. */ ValueType getCentreY() const throw() { return y + h / (ValueType) 2; } /** Returns the centre point of the rectangle. */ const Point getCentre() const throw() { return Point (x + w / (ValueType) 2, y + h / (ValueType) 2); } /** Returns the aspect ratio of the rectangle's width / height. If widthOverHeight is true, it returns width / height; if widthOverHeight is false, it returns height / width. */ ValueType getAspectRatio (const bool widthOverHeight = true) const throw() { return widthOverHeight ? w / h : h / w; } /** Returns the rectangle's top-left position as a Point. */ const Point getPosition() const throw() { return Point (x, y); } /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ void setPosition (const Point& newPos) throw() { x = newPos.getX(); y = newPos.getY(); } /** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */ void setPosition (const ValueType newX, const ValueType newY) throw() { x = newX; y = newY; } /** Returns a rectangle with the same size as this one, but a new position. */ const Rectangle withPosition (const ValueType newX, const ValueType newY) const throw() { return Rectangle (newX, newY, w, h); } /** Returns a rectangle with the same size as this one, but a new position. */ const Rectangle withPosition (const Point& newPos) const throw() { return Rectangle (newPos.getX(), newPos.getY(), w, h); } /** Returns the rectangle's top-left position as a Point. */ const Point getTopLeft() const throw() { return getPosition(); } /** Returns the rectangle's top-right position as a Point. */ const Point getTopRight() const throw() { return Point (x + w, y); } /** Returns the rectangle's bottom-left position as a Point. */ const Point getBottomLeft() const throw() { return Point (x, y + h); } /** Returns the rectangle's bottom-right position as a Point. */ const Point getBottomRight() const throw() { return Point (x + w, y + h); } /** Changes the rectangle's size, leaving the position of its top-left corner unchanged. */ void setSize (const ValueType newWidth, const ValueType newHeight) throw() { w = newWidth; h = newHeight; } /** Returns a rectangle with the same position as this one, but a new size. */ const Rectangle withSize (const ValueType newWidth, const ValueType newHeight) const throw() { return Rectangle (x, y, newWidth, newHeight); } /** Changes all the rectangle's co-ordinates. */ void setBounds (const ValueType newX, const ValueType newY, const ValueType newWidth, const ValueType newHeight) throw() { x = newX; y = newY; w = newWidth; h = newHeight; } /** Changes the rectangle's X coordinate */ void setX (const ValueType newX) throw() { x = newX; } /** Changes the rectangle's Y coordinate */ void setY (const ValueType newY) throw() { y = newY; } /** Changes the rectangle's width */ void setWidth (const ValueType newWidth) throw() { w = newWidth; } /** Changes the rectangle's height */ void setHeight (const ValueType newHeight) throw() { h = newHeight; } /** Returns a rectangle which has the same size and y-position as this one, but with a different x-position. */ const Rectangle withX (const ValueType newX) const throw() { return Rectangle (newX, y, w, h); } /** Returns a rectangle which has the same size and x-position as this one, but with a different y-position. */ const Rectangle withY (const ValueType newY) const throw() { return Rectangle (x, newY, w, h); } /** Returns a rectangle which has the same position and height as this one, but with a different width. */ const Rectangle withWidth (const ValueType newWidth) const throw() { return Rectangle (x, y, newWidth, h); } /** Returns a rectangle which has the same position and width as this one, but with a different height. */ const Rectangle withHeight (const ValueType newHeight) const throw() { return Rectangle (x, y, w, newHeight); } /** Moves the x position, adjusting the width so that the right-hand edge remains in the same place. If the x is moved to be on the right of the current right-hand edge, the width will be set to zero. @see withLeft */ void setLeft (const ValueType newLeft) throw() { w = jmax (ValueType(), x + w - newLeft); x = newLeft; } /** Returns a new rectangle with a different x position, but the same right-hand edge as this one. If the new x is beyond the right of the current right-hand edge, the width will be set to zero. @see setLeft */ const Rectangle withLeft (const ValueType newLeft) const throw() { return Rectangle (newLeft, y, jmax (ValueType(), x + w - newLeft), h); } /** Moves the y position, adjusting the height so that the bottom edge remains in the same place. If the y is moved to be below the current bottom edge, the height will be set to zero. @see withTop */ void setTop (const ValueType newTop) throw() { h = jmax (ValueType(), y + h - newTop); y = newTop; } /** Returns a new rectangle with a different y position, but the same bottom edge as this one. If the new y is beyond the bottom of the current rectangle, the height will be set to zero. @see setTop */ const Rectangle withTop (const ValueType newTop) const throw() { return Rectangle (x, newTop, w, jmax (ValueType(), y + h - newTop)); } /** Adjusts the width so that the right-hand edge of the rectangle has this new value. If the new right is below the current X value, the X will be pushed down to match it. @see getRight, withRight */ void setRight (const ValueType newRight) throw() { x = jmin (x, newRight); w = newRight - x; } /** Returns a new rectangle with a different right-hand edge position, but the same left-hand edge as this one. If the new right edge is below the current left-hand edge, the width will be set to zero. @see setRight */ const Rectangle withRight (const ValueType newRight) const throw() { return Rectangle (jmin (x, newRight), y, jmax (ValueType(), newRight - x), h); } /** Adjusts the height so that the bottom edge of the rectangle has this new value. If the new bottom is lower than the current Y value, the Y will be pushed down to match it. @see getBottom, withBottom */ void setBottom (const ValueType newBottom) throw() { y = jmin (y, newBottom); h = newBottom - y; } /** Returns a new rectangle with a different bottom edge position, but the same top edge as this one. If the new y is beyond the bottom of the current rectangle, the height will be set to zero. @see setBottom */ const Rectangle withBottom (const ValueType newBottom) const throw() { return Rectangle (x, jmin (y, newBottom), w, jmax (ValueType(), newBottom - y)); } /** Moves the rectangle's position by adding amount to its x and y co-ordinates. */ void translate (const ValueType deltaX, const ValueType deltaY) throw() { x += deltaX; y += deltaY; } /** Returns a rectangle which is the same as this one moved by a given amount. */ const Rectangle translated (const ValueType deltaX, const ValueType deltaY) const throw() { return Rectangle (x + deltaX, y + deltaY, w, h); } /** Returns a rectangle which is the same as this one moved by a given amount. */ const Rectangle operator+ (const Point& deltaPosition) const throw() { return Rectangle (x + deltaPosition.getX(), y + deltaPosition.getY(), w, h); } /** Moves this rectangle by a given amount. */ Rectangle& operator+= (const Point& deltaPosition) throw() { x += deltaPosition.getX(); y += deltaPosition.getY(); return *this; } /** Returns a rectangle which is the same as this one moved by a given amount. */ const Rectangle operator- (const Point& deltaPosition) const throw() { return Rectangle (x - deltaPosition.getX(), y - deltaPosition.getY(), w, h); } /** Moves this rectangle by a given amount. */ Rectangle& operator-= (const Point& deltaPosition) throw() { x -= deltaPosition.getX(); y -= deltaPosition.getY(); return *this; } /** Expands the rectangle by a given amount. Effectively, its new size is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). @see expanded, reduce, reduced */ void expand (const ValueType deltaX, const ValueType deltaY) throw() { const ValueType nw = jmax (ValueType(), w + deltaX * 2); const ValueType nh = jmax (ValueType(), h + deltaY * 2); setBounds (x - deltaX, y - deltaY, nw, nh); } /** Returns a rectangle that is larger than this one by a given amount. Effectively, the rectangle returned is (x - deltaX, y - deltaY, w + deltaX * 2, h + deltaY * 2). @see expand, reduce, reduced */ const Rectangle expanded (const ValueType deltaX, const ValueType deltaY) const throw() { const ValueType nw = jmax (ValueType(), w + deltaX * 2); const ValueType nh = jmax (ValueType(), h + deltaY * 2); return Rectangle (x - deltaX, y - deltaY, nw, nh); } /** Shrinks the rectangle by a given amount. Effectively, its new size is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). @see reduced, expand, expanded */ void reduce (const ValueType deltaX, const ValueType deltaY) throw() { expand (-deltaX, -deltaY); } /** Returns a rectangle that is smaller than this one by a given amount. Effectively, the rectangle returned is (x + deltaX, y + deltaY, w - deltaX * 2, h - deltaY * 2). @see reduce, expand, expanded */ const Rectangle reduced (const ValueType deltaX, const ValueType deltaY) const throw() { return expanded (-deltaX, -deltaY); } /** Removes a strip from the top of this rectangle, reducing this rectangle by the specified amount and returning the section that was removed. E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will return (100, 100, 300, 50) and leave this rectangle as (100, 150, 300, 250). If amountToRemove is greater than the height of this rectangle, it'll be clipped to that value. */ const Rectangle removeFromTop (const ValueType amountToRemove) throw() { const Rectangle r (x, y, w, jmin (amountToRemove, h)); y += r.h; h -= r.h; return r; } /** Removes a strip from the left-hand edge of this rectangle, reducing this rectangle by the specified amount and returning the section that was removed. E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will return (100, 100, 50, 300) and leave this rectangle as (150, 100, 250, 300). If amountToRemove is greater than the width of this rectangle, it'll be clipped to that value. */ const Rectangle removeFromLeft (const ValueType amountToRemove) throw() { const Rectangle r (x, y, jmin (amountToRemove, w), h); x += r.w; w -= r.w; return r; } /** Removes a strip from the right-hand edge of this rectangle, reducing this rectangle by the specified amount and returning the section that was removed. E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will return (250, 100, 50, 300) and leave this rectangle as (100, 100, 250, 300). If amountToRemove is greater than the width of this rectangle, it'll be clipped to that value. */ const Rectangle removeFromRight (ValueType amountToRemove) throw() { amountToRemove = jmin (amountToRemove, w); const Rectangle r (x + w - amountToRemove, y, amountToRemove, h); w -= amountToRemove; return r; } /** Removes a strip from the bottom of this rectangle, reducing this rectangle by the specified amount and returning the section that was removed. E.g. if this rectangle is (100, 100, 300, 300) and amountToRemove is 50, this will return (100, 250, 300, 50) and leave this rectangle as (100, 100, 300, 250). If amountToRemove is greater than the height of this rectangle, it'll be clipped to that value. */ const Rectangle removeFromBottom (ValueType amountToRemove) throw() { amountToRemove = jmin (amountToRemove, h); const Rectangle r (x, y + h - amountToRemove, w, amountToRemove); h -= amountToRemove; return r; } /** Returns true if the two rectangles are identical. */ bool operator== (const Rectangle& other) const throw() { return x == other.x && y == other.y && w == other.w && h == other.h; } /** Returns true if the two rectangles are not identical. */ bool operator!= (const Rectangle& other) const throw() { return x != other.x || y != other.y || w != other.w || h != other.h; } /** Returns true if this co-ordinate is inside the rectangle. */ bool contains (const ValueType xCoord, const ValueType yCoord) const throw() { return xCoord >= x && yCoord >= y && xCoord < x + w && yCoord < y + h; } /** Returns true if this co-ordinate is inside the rectangle. */ bool contains (const Point& point) const throw() { return point.getX() >= x && point.getY() >= y && point.getX() < x + w && point.getY() < y + h; } /** Returns true if this other rectangle is completely inside this one. */ bool contains (const Rectangle& other) const throw() { return x <= other.x && y <= other.y && x + w >= other.x + other.w && y + h >= other.y + other.h; } /** Returns the nearest point to the specified point that lies within this rectangle. */ const Point getConstrainedPoint (const Point& point) const throw() { return Point (jlimit (x, x + w, point.getX()), jlimit (y, y + h, point.getY())); } /** Returns true if any part of another rectangle overlaps this one. */ bool intersects (const Rectangle& other) const throw() { return x + w > other.x && y + h > other.y && x < other.x + other.w && y < other.y + other.h && w > ValueType() && h > ValueType(); } /** Returns the region that is the overlap between this and another rectangle. If the two rectangles don't overlap, the rectangle returned will be empty. */ const Rectangle getIntersection (const Rectangle& other) const throw() { const ValueType nx = jmax (x, other.x); const ValueType ny = jmax (y, other.y); const ValueType nw = jmin (x + w, other.x + other.w) - nx; const ValueType nh = jmin (y + h, other.y + other.h) - ny; if (nw >= ValueType() && nh >= ValueType()) return Rectangle (nx, ny, nw, nh); return Rectangle(); } /** Clips a rectangle so that it lies only within this one. This is a non-static version of intersectRectangles(). Returns false if the two regions didn't overlap. */ bool intersectRectangle (ValueType& otherX, ValueType& otherY, ValueType& otherW, ValueType& otherH) const throw() { const int maxX = jmax (otherX, x); otherW = jmin (otherX + otherW, x + w) - maxX; if (otherW > 0) { const int maxY = jmax (otherY, y); otherH = jmin (otherY + otherH, y + h) - maxY; if (otherH > 0) { otherX = maxX; otherY = maxY; return true; } } return false; } /** Returns the smallest rectangle that contains both this one and the one passed-in. If either this or the other rectangle are empty, they will not be counted as part of the resulting region. */ const Rectangle getUnion (const Rectangle& other) const throw() { if (other.isEmpty()) return *this; if (isEmpty()) return other; const ValueType newX = jmin (x, other.x); const ValueType newY = jmin (y, other.y); return Rectangle (newX, newY, jmax (x + w, other.x + other.w) - newX, jmax (y + h, other.y + other.h) - newY); } /** If this rectangle merged with another one results in a simple rectangle, this will set this rectangle to the result, and return true. Returns false and does nothing to this rectangle if the two rectangles don't overlap, or if they form a complex region. */ bool enlargeIfAdjacent (const Rectangle& other) throw() { if (x == other.x && getRight() == other.getRight() && (other.getBottom() >= y && other.y <= getBottom())) { const ValueType newY = jmin (y, other.y); h = jmax (getBottom(), other.getBottom()) - newY; y = newY; return true; } else if (y == other.y && getBottom() == other.getBottom() && (other.getRight() >= x && other.x <= getRight())) { const ValueType newX = jmin (x, other.x); w = jmax (getRight(), other.getRight()) - newX; x = newX; return true; } return false; } /** If after removing another rectangle from this one the result is a simple rectangle, this will set this object's bounds to be the result, and return true. Returns false and does nothing to this rectangle if the two rectangles don't overlap, or if removing the other one would form a complex region. */ bool reduceIfPartlyContainedIn (const Rectangle& other) throw() { int inside = 0; const int otherR = other.getRight(); if (x >= other.x && x < otherR) inside = 1; const int otherB = other.getBottom(); if (y >= other.y && y < otherB) inside |= 2; const int r = x + w; if (r >= other.x && r < otherR) inside |= 4; const int b = y + h; if (b >= other.y && b < otherB) inside |= 8; switch (inside) { case 1 + 2 + 8: w = r - otherR; x = otherR; return true; case 1 + 2 + 4: h = b - otherB; y = otherB; return true; case 2 + 4 + 8: w = other.x - x; return true; case 1 + 4 + 8: h = other.y - y; return true; } return false; } /** Returns the smallest rectangle that can contain the shape created by applying a transform to this rectangle. This should only be used on floating point rectangles. */ const Rectangle transformed (const AffineTransform& transform) const throw() { float x1 = x, y1 = y; float x2 = x + w, y2 = y; float x3 = x, y3 = y + h; float x4 = x2, y4 = y3; transform.transformPoints (x1, y1, x2, y2); transform.transformPoints (x3, y3, x4, y4); const float rx = jmin (x1, x2, x3, x4); const float ry = jmin (y1, y2, y3, y4); return Rectangle (rx, ry, jmax (x1, x2, x3, x4) - rx, jmax (y1, y2, y3, y4) - ry); } /** Returns the smallest integer-aligned rectangle that completely contains this one. This is only relevent for floating-point rectangles, of course. @see toFloat() */ const Rectangle getSmallestIntegerContainer() const throw() { const int x1 = (int) std::floor (static_cast (x)); const int y1 = (int) std::floor (static_cast (y)); const int x2 = (int) std::ceil (static_cast (x + w)); const int y2 = (int) std::ceil (static_cast (y + h)); return Rectangle (x1, y1, x2 - x1, y2 - y1); } /** Returns the smallest Rectangle that can contain a set of points. */ static const Rectangle findAreaContainingPoints (const Point* const points, const int numPoints) throw() { if (numPoints == 0) return Rectangle(); ValueType minX (points[0].getX()); ValueType maxX (minX); ValueType minY (points[0].getY()); ValueType maxY (minY); for (int i = 1; i < numPoints; ++i) { minX = jmin (minX, points[i].getX()); maxX = jmax (maxX, points[i].getX()); minY = jmin (minY, points[i].getY()); maxY = jmax (maxY, points[i].getY()); } return Rectangle (minX, minY, maxX - minX, maxY - minY); } /** Casts this rectangle to a Rectangle. Obviously this is mainly useful for rectangles that use integer types. @see getSmallestIntegerContainer */ const Rectangle toFloat() const throw() { return Rectangle (static_cast (x), static_cast (y), static_cast (w), static_cast (h)); } /** Static utility to intersect two sets of rectangular co-ordinates. Returns false if the two regions didn't overlap. @see intersectRectangle */ static bool intersectRectangles (ValueType& x1, ValueType& y1, ValueType& w1, ValueType& h1, const ValueType x2, const ValueType y2, const ValueType w2, const ValueType h2) throw() { const ValueType x = jmax (x1, x2); w1 = jmin (x1 + w1, x2 + w2) - x; if (w1 > 0) { const ValueType y = jmax (y1, y2); h1 = jmin (y1 + h1, y2 + h2) - y; if (h1 > 0) { x1 = x; y1 = y; return true; } } return false; } /** Creates a string describing this rectangle. The string will be of the form "x y width height", e.g. "100 100 400 200". Coupled with the fromString() method, this is very handy for things like storing rectangles (particularly component positions) in XML attributes. @see fromString */ const String toString() const { String s; s.preallocateStorage (16); s << x << ' ' << y << ' ' << w << ' ' << h; return s; } /** Parses a string containing a rectangle's details. The string should contain 4 integer tokens, in the form "x y width height". They can be comma or whitespace separated. This method is intended to go with the toString() method, to form an easy way of saving/loading rectangles as strings. @see toString */ static const Rectangle fromString (const String& stringVersion) { StringArray toks; toks.addTokens (stringVersion.trim(), ",; \t\r\n", String::empty); return Rectangle (toks[0].trim().getIntValue(), toks[1].trim().getIntValue(), toks[2].trim().getIntValue(), toks[3].trim().getIntValue()); } private: friend class RectangleList; ValueType x, y, w, h; }; #endif // __JUCE_RECTANGLE_JUCEHEADER__ /*** End of inlined file: juce_Rectangle.h ***/ /*** Start of inlined file: juce_Justification.h ***/ #ifndef __JUCE_JUSTIFICATION_JUCEHEADER__ #define __JUCE_JUSTIFICATION_JUCEHEADER__ /** Represents a type of justification to be used when positioning graphical items. e.g. it indicates whether something should be placed top-left, top-right, centred, etc. It is used in various places wherever this kind of information is needed. */ class JUCE_API Justification { public: /** Creates a Justification object using a combination of flags. */ inline Justification (int flags_) throw() : flags (flags_) {} /** Creates a copy of another Justification object. */ Justification (const Justification& other) throw(); /** Copies another Justification object. */ Justification& operator= (const Justification& other) throw(); bool operator== (const Justification& other) const throw() { return flags == other.flags; } bool operator!= (const Justification& other) const throw() { return flags != other.flags; } /** Returns the raw flags that are set for this Justification object. */ inline int getFlags() const throw() { return flags; } /** Tests a set of flags for this object. @returns true if any of the flags passed in are set on this object. */ inline bool testFlags (int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } /** Returns just the flags from this object that deal with vertical layout. */ int getOnlyVerticalFlags() const throw(); /** Returns just the flags from this object that deal with horizontal layout. */ int getOnlyHorizontalFlags() const throw(); /** Adjusts the position of a rectangle to fit it into a space. The (x, y) position of the rectangle will be updated to position it inside the given space according to the justification flags. */ template void applyToRectangle (ValueType& x, ValueType& y, ValueType w, ValueType h, ValueType spaceX, ValueType spaceY, ValueType spaceW, ValueType spaceH) const throw() { x = spaceX; if ((flags & horizontallyCentred) != 0) x += (spaceW - w) / (ValueType) 2; else if ((flags & right) != 0) x += spaceW - w; y = spaceY; if ((flags & verticallyCentred) != 0) y += (spaceH - h) / (ValueType) 2; else if ((flags & bottom) != 0) y += spaceH - h; } /** Returns the new position of a rectangle that has been justified to fit within a given space. */ template const Rectangle appliedToRectangle (const Rectangle& areaToAdjust, const Rectangle& targetSpace) const throw() { ValueType x = areaToAdjust.getX(), y = areaToAdjust.getY(); applyToRectangle (x, y, areaToAdjust.getWidth(), areaToAdjust.getHeight(), targetSpace.getX(), targetSpace.getY(), targetSpace.getWidth(), targetSpace.getHeight()); return areaToAdjust.withPosition (x, y); } /** Flag values that can be combined and used in the constructor. */ enum { /** Indicates that the item should be aligned against the left edge of the available space. */ left = 1, /** Indicates that the item should be aligned against the right edge of the available space. */ right = 2, /** Indicates that the item should be placed in the centre between the left and right sides of the available space. */ horizontallyCentred = 4, /** Indicates that the item should be aligned against the top edge of the available space. */ top = 8, /** Indicates that the item should be aligned against the bottom edge of the available space. */ bottom = 16, /** Indicates that the item should be placed in the centre between the top and bottom sides of the available space. */ verticallyCentred = 32, /** Indicates that lines of text should be spread out to fill the maximum width available, so that both margins are aligned vertically. */ horizontallyJustified = 64, /** Indicates that the item should be centred vertically and horizontally. This is equivalent to (horizontallyCentred | verticallyCentred) */ centred = 36, /** Indicates that the item should be centred vertically but placed on the left hand side. This is equivalent to (left | verticallyCentred) */ centredLeft = 33, /** Indicates that the item should be centred vertically but placed on the right hand side. This is equivalent to (right | verticallyCentred) */ centredRight = 34, /** Indicates that the item should be centred horizontally and placed at the top. This is equivalent to (horizontallyCentred | top) */ centredTop = 12, /** Indicates that the item should be centred horizontally and placed at the bottom. This is equivalent to (horizontallyCentred | bottom) */ centredBottom = 20, /** Indicates that the item should be placed in the top-left corner. This is equivalent to (left | top) */ topLeft = 9, /** Indicates that the item should be placed in the top-right corner. This is equivalent to (right | top) */ topRight = 10, /** Indicates that the item should be placed in the bottom-left corner. This is equivalent to (left | bottom) */ bottomLeft = 17, /** Indicates that the item should be placed in the bottom-left corner. This is equivalent to (right | bottom) */ bottomRight = 18 }; private: int flags; }; #endif // __JUCE_JUSTIFICATION_JUCEHEADER__ /*** End of inlined file: juce_Justification.h ***/ class Image; /** A path is a sequence of lines and curves that may either form a closed shape or be open-ended. To use a path, you can create an empty one, then add lines and curves to it to create shapes, then it can be rendered by a Graphics context or used for geometric operations. e.g. @code Path myPath; myPath.startNewSubPath (10.0f, 10.0f); // move the current position to (10, 10) myPath.lineTo (100.0f, 200.0f); // draw a line from here to (100, 200) myPath.quadraticTo (0.0f, 150.0f, 5.0f, 50.0f); // draw a curve that ends at (5, 50) myPath.closeSubPath(); // close the subpath with a line back to (10, 10) // add an ellipse as well, which will form a second sub-path within the path.. myPath.addEllipse (50.0f, 50.0f, 40.0f, 30.0f); // double the width of the whole thing.. myPath.applyTransform (AffineTransform::scale (2.0f, 1.0f)); // and draw it to a graphics context with a 5-pixel thick outline. g.strokePath (myPath, PathStrokeType (5.0f)); @endcode A path object can actually contain multiple sub-paths, which may themselves be open or closed. @see PathFlatteningIterator, PathStrokeType, Graphics */ class JUCE_API Path { public: /** Creates an empty path. */ Path(); /** Creates a copy of another path. */ Path (const Path& other); /** Destructor. */ ~Path(); /** Copies this path from another one. */ Path& operator= (const Path& other); bool operator== (const Path& other) const throw(); bool operator!= (const Path& other) const throw(); /** Returns true if the path doesn't contain any lines or curves. */ bool isEmpty() const throw(); /** Returns the smallest rectangle that contains all points within the path. */ const Rectangle getBounds() const throw(); /** Returns the smallest rectangle that contains all points within the path after it's been transformed with the given tranasform matrix. */ const Rectangle getBoundsTransformed (const AffineTransform& transform) const throw(); /** Checks whether a point lies within the path. This is only relevent for closed paths (see closeSubPath()), and may produce false results if used on a path which has open sub-paths. The path's winding rule is taken into account by this method. The tolerance parameter is the maximum error allowed when flattening the path, so this method could return a false positive when your point is up to this distance outside the path's boundary. @see closeSubPath, setUsingNonZeroWinding */ bool contains (float x, float y, float tolerance = 1.0f) const; /** Checks whether a point lies within the path. This is only relevent for closed paths (see closeSubPath()), and may produce false results if used on a path which has open sub-paths. The path's winding rule is taken into account by this method. The tolerance parameter is the maximum error allowed when flattening the path, so this method could return a false positive when your point is up to this distance outside the path's boundary. @see closeSubPath, setUsingNonZeroWinding */ bool contains (const Point& point, float tolerance = 1.0f) const; /** Checks whether a line crosses the path. This will return positive if the line crosses any of the paths constituent lines or curves. It doesn't take into account whether the line is inside or outside the path, or whether the path is open or closed. The tolerance parameter is the maximum error allowed when flattening the path, so this method could return a false positive when your point is up to this distance outside the path's boundary. */ bool intersectsLine (const Line& line, float tolerance = 1.0f); /** Cuts off parts of a line to keep the parts that are either inside or outside this path. Note that this isn't smart enough to cope with situations where the line would need to be cut into multiple pieces to correctly clip against a re-entrant shape. @param line the line to clip @param keepSectionOutsidePath if true, it's the section outside the path that will be kept; if false its the section inside the path */ const Line getClippedLine (const Line& line, bool keepSectionOutsidePath) const; /** Returns the length of the path. @see getPointAlongPath */ float getLength (const AffineTransform& transform = AffineTransform::identity) const; /** Returns a point that is the specified distance along the path. If the distance is greater than the total length of the path, this will return the end point. @see getLength */ const Point getPointAlongPath (float distanceFromStart, const AffineTransform& transform = AffineTransform::identity) const; /** Finds the point along the path which is nearest to a given position. This sets pointOnPath to the nearest point, and returns the distance of this point from the start of the path. */ float getNearestPoint (const Point& targetPoint, Point& pointOnPath, const AffineTransform& transform = AffineTransform::identity) const; /** Removes all lines and curves, resetting the path completely. */ void clear() throw(); /** Begins a new subpath with a given starting position. This will move the path's current position to the co-ordinates passed in and make it ready to draw lines or curves starting from this position. After adding whatever lines and curves are needed, you can either close the current sub-path using closeSubPath() or call startNewSubPath() to move to a new sub-path, leaving the old one open-ended. @see lineTo, quadraticTo, cubicTo, closeSubPath */ void startNewSubPath (float startX, float startY); /** Begins a new subpath with a given starting position. This will move the path's current position to the co-ordinates passed in and make it ready to draw lines or curves starting from this position. After adding whatever lines and curves are needed, you can either close the current sub-path using closeSubPath() or call startNewSubPath() to move to a new sub-path, leaving the old one open-ended. @see lineTo, quadraticTo, cubicTo, closeSubPath */ void startNewSubPath (const Point& start); /** Closes a the current sub-path with a line back to its start-point. When creating a closed shape such as a triangle, don't use 3 lineTo() calls - instead use two lineTo() calls, followed by a closeSubPath() to join the final point back to the start. This ensures that closes shapes are recognised as such, and this is important for tasks like drawing strokes, which needs to know whether to draw end-caps or not. @see startNewSubPath, lineTo, quadraticTo, cubicTo, closeSubPath */ void closeSubPath(); /** Adds a line from the shape's last position to a new end-point. This will connect the end-point of the last line or curve that was added to a new point, using a straight line. See the class description for an example of how to add lines and curves to a path. @see startNewSubPath, quadraticTo, cubicTo, closeSubPath */ void lineTo (float endX, float endY); /** Adds a line from the shape's last position to a new end-point. This will connect the end-point of the last line or curve that was added to a new point, using a straight line. See the class description for an example of how to add lines and curves to a path. @see startNewSubPath, quadraticTo, cubicTo, closeSubPath */ void lineTo (const Point& end); /** Adds a quadratic bezier curve from the shape's last position to a new position. This will connect the end-point of the last line or curve that was added to a new point, using a quadratic spline with one control-point. See the class description for an example of how to add lines and curves to a path. @see startNewSubPath, lineTo, cubicTo, closeSubPath */ void quadraticTo (float controlPointX, float controlPointY, float endPointX, float endPointY); /** Adds a quadratic bezier curve from the shape's last position to a new position. This will connect the end-point of the last line or curve that was added to a new point, using a quadratic spline with one control-point. See the class description for an example of how to add lines and curves to a path. @see startNewSubPath, lineTo, cubicTo, closeSubPath */ void quadraticTo (const Point& controlPoint, const Point& endPoint); /** Adds a cubic bezier curve from the shape's last position to a new position. This will connect the end-point of the last line or curve that was added to a new point, using a cubic spline with two control-points. See the class description for an example of how to add lines and curves to a path. @see startNewSubPath, lineTo, quadraticTo, closeSubPath */ void cubicTo (float controlPoint1X, float controlPoint1Y, float controlPoint2X, float controlPoint2Y, float endPointX, float endPointY); /** Adds a cubic bezier curve from the shape's last position to a new position. This will connect the end-point of the last line or curve that was added to a new point, using a cubic spline with two control-points. See the class description for an example of how to add lines and curves to a path. @see startNewSubPath, lineTo, quadraticTo, closeSubPath */ void cubicTo (const Point& controlPoint1, const Point& controlPoint2, const Point& endPoint); /** Returns the last point that was added to the path by one of the drawing methods. */ const Point getCurrentPosition() const; /** Adds a rectangle to the path. The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRoundedRectangle, addTriangle */ void addRectangle (float x, float y, float width, float height); /** Adds a rectangle to the path. The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRoundedRectangle, addTriangle */ template void addRectangle (const Rectangle& rectangle) { addRectangle (static_cast (rectangle.getX()), static_cast (rectangle.getY()), static_cast (rectangle.getWidth()), static_cast (rectangle.getHeight())); } /** Adds a rectangle with rounded corners to the path. The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRectangle, addTriangle */ void addRoundedRectangle (float x, float y, float width, float height, float cornerSize); /** Adds a rectangle with rounded corners to the path. The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRectangle, addTriangle */ void addRoundedRectangle (float x, float y, float width, float height, float cornerSizeX, float cornerSizeY); /** Adds a rectangle with rounded corners to the path. The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRectangle, addTriangle */ template void addRoundedRectangle (const Rectangle& rectangle, float cornerSizeX, float cornerSizeY) { addRoundedRectangle (static_cast (rectangle.getX()), static_cast (rectangle.getY()), static_cast (rectangle.getWidth()), static_cast (rectangle.getHeight()), cornerSizeX, cornerSizeY); } /** Adds a rectangle with rounded corners to the path. The rectangle is added as a new sub-path. (Any currently open paths will be left open). @see addRectangle, addTriangle */ template void addRoundedRectangle (const Rectangle& rectangle, float cornerSize) { addRoundedRectangle (rectangle, cornerSize, cornerSize); } /** Adds a triangle to the path. The triangle is added as a new closed sub-path. (Any currently open paths will be left open). Note that whether the vertices are specified in clockwise or anticlockwise order will affect how the triangle is filled when it overlaps other shapes (the winding order setting will affect this of course). */ void addTriangle (float x1, float y1, float x2, float y2, float x3, float y3); /** Adds a quadrilateral to the path. The quad is added as a new closed sub-path. (Any currently open paths will be left open). Note that whether the vertices are specified in clockwise or anticlockwise order will affect how the quad is filled when it overlaps other shapes (the winding order setting will affect this of course). */ void addQuadrilateral (float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4); /** Adds an ellipse to the path. The shape is added as a new sub-path. (Any currently open paths will be left open). @see addArc */ void addEllipse (float x, float y, float width, float height); /** Adds an elliptical arc to the current path. Note that when specifying the start and end angles, the curve will be drawn either clockwise or anti-clockwise according to whether the end angle is greater than the start. This means that sometimes you may need to use values greater than 2*Pi for the end angle. @param x the left-hand edge of the rectangle in which the elliptical outline fits @param y the top edge of the rectangle in which the elliptical outline fits @param width the width of the rectangle in which the elliptical outline fits @param height the height of the rectangle in which the elliptical outline fits @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the top-centre of the ellipse) @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, it will be added to the current sub-path, continuing from the current postition @see addCentredArc, arcTo, addPieSegment, addEllipse */ void addArc (float x, float y, float width, float height, float fromRadians, float toRadians, bool startAsNewSubPath = false); /** Adds an arc which is centred at a given point, and can have a rotation specified. Note that when specifying the start and end angles, the curve will be drawn either clockwise or anti-clockwise according to whether the end angle is greater than the start. This means that sometimes you may need to use values greater than 2*Pi for the end angle. @param centreX the centre x of the ellipse @param centreY the centre y of the ellipse @param radiusX the horizontal radius of the ellipse @param radiusY the vertical radius of the ellipse @param rotationOfEllipse an angle by which the whole ellipse should be rotated about its centre, in radians (clockwise) @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the top-centre of the ellipse) @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the top-centre of the ellipse). This angle can be greater than 2*Pi, so for example to draw a curve clockwise from the 9 o'clock position to the 3 o'clock position via 12 o'clock, you'd use 1.5*Pi and 2.5*Pi as the start and finish points. @param startAsNewSubPath if true, the arc will begin a new subpath from its starting point; if false, it will be added to the current sub-path, continuing from the current postition @see addArc, arcTo */ void addCentredArc (float centreX, float centreY, float radiusX, float radiusY, float rotationOfEllipse, float fromRadians, float toRadians, bool startAsNewSubPath = false); /** Adds a "pie-chart" shape to the path. The shape is added as a new sub-path. (Any currently open paths will be left open). Note that when specifying the start and end angles, the curve will be drawn either clockwise or anti-clockwise according to whether the end angle is greater than the start. This means that sometimes you may need to use values greater than 2*Pi for the end angle. @param x the left-hand edge of the rectangle in which the elliptical outline fits @param y the top edge of the rectangle in which the elliptical outline fits @param width the width of the rectangle in which the elliptical outline fits @param height the height of the rectangle in which the elliptical outline fits @param fromRadians the angle (clockwise) in radians at which to start the arc segment (where 0 is the top-centre of the ellipse) @param toRadians the angle (clockwise) in radians at which to end the arc segment (where 0 is the top-centre of the ellipse) @param innerCircleProportionalSize if this is > 0, then the pie will be drawn as a curved band around a hollow ellipse at its centre, where this value indicates the inner ellipse's size with respect to the outer one. @see addArc */ void addPieSegment (float x, float y, float width, float height, float fromRadians, float toRadians, float innerCircleProportionalSize); /** Adds a line with a specified thickness. The line is added as a new closed sub-path. (Any currently open paths will be left open). @see addArrow */ void addLineSegment (const Line& line, float lineThickness); /** Adds a line with an arrowhead on the end. The arrow is added as a new closed sub-path. (Any currently open paths will be left open). @see PathStrokeType::createStrokeWithArrowheads */ void addArrow (const Line& line, float lineThickness, float arrowheadWidth, float arrowheadLength); /** Adds a polygon shape to the path. @see addStar */ void addPolygon (const Point& centre, int numberOfSides, float radius, float startAngle = 0.0f); /** Adds a star shape to the path. @see addPolygon */ void addStar (const Point& centre, int numberOfPoints, float innerRadius, float outerRadius, float startAngle = 0.0f); /** Adds a speech-bubble shape to the path. @param bodyX the left of the main body area of the bubble @param bodyY the top of the main body area of the bubble @param bodyW the width of the main body area of the bubble @param bodyH the height of the main body area of the bubble @param cornerSize the amount by which to round off the corners of the main body rectangle @param arrowTipX the x position that the tip of the arrow should connect to @param arrowTipY the y position that the tip of the arrow should connect to @param whichSide the side to connect the arrow to: 0 = top, 1 = left, 2 = bottom, 3 = right @param arrowPositionAlongEdgeProportional how far along the edge of the main rectangle the arrow's base should be - this is a proportional distance between 0 and 1.0 @param arrowWidth how wide the base of the arrow should be where it joins the main rectangle */ void addBubble (float bodyX, float bodyY, float bodyW, float bodyH, float cornerSize, float arrowTipX, float arrowTipY, int whichSide, float arrowPositionAlongEdgeProportional, float arrowWidth); /** Adds another path to this one. The new path is added as a new sub-path. (Any currently open paths in this path will be left open). @param pathToAppend the path to add */ void addPath (const Path& pathToAppend); /** Adds another path to this one, transforming it on the way in. The new path is added as a new sub-path, its points being transformed by the given matrix before being added. @param pathToAppend the path to add @param transformToApply an optional transform to apply to the incoming vertices */ void addPath (const Path& pathToAppend, const AffineTransform& transformToApply); /** Swaps the contents of this path with another one. The internal data of the two paths is swapped over, so this is much faster than copying it to a temp variable and back. */ void swapWithPath (Path& other) throw(); /** Applies a 2D transform to all the vertices in the path. @see AffineTransform, scaleToFit, getTransformToScaleToFit */ void applyTransform (const AffineTransform& transform) throw(); /** Rescales this path to make it fit neatly into a given space. This is effectively a quick way of calling applyTransform (getTransformToScaleToFit (x, y, w, h, preserveProportions)) @param x the x position of the rectangle to fit the path inside @param y the y position of the rectangle to fit the path inside @param width the width of the rectangle to fit the path inside @param height the height of the rectangle to fit the path inside @param preserveProportions if true, it will fit the path into the space without altering its horizontal/vertical scale ratio; if false, it will distort the path to fill the specified ratio both horizontally and vertically @see applyTransform, getTransformToScaleToFit */ void scaleToFit (float x, float y, float width, float height, bool preserveProportions) throw(); /** Returns a transform that can be used to rescale the path to fit into a given space. @param x the x position of the rectangle to fit the path inside @param y the y position of the rectangle to fit the path inside @param width the width of the rectangle to fit the path inside @param height the height of the rectangle to fit the path inside @param preserveProportions if true, it will fit the path into the space without altering its horizontal/vertical scale ratio; if false, it will distort the path to fill the specified ratio both horizontally and vertically @param justificationType if the proportions are preseved, the resultant path may be smaller than the available rectangle, so this describes how it should be positioned within the space. @returns an appropriate transformation @see applyTransform, scaleToFit */ const AffineTransform getTransformToScaleToFit (float x, float y, float width, float height, bool preserveProportions, const Justification& justificationType = Justification::centred) const; /** Creates a version of this path where all sharp corners have been replaced by curves. Wherever two lines meet at an angle, this will replace the corner with a curve of the given radius. */ const Path createPathWithRoundedCorners (float cornerRadius) const; /** Changes the winding-rule to be used when filling the path. If set to true (which is the default), then the path uses a non-zero-winding rule to determine which points are inside the path. If set to false, it uses an alternate-winding rule. The winding-rule comes into play when areas of the shape overlap other areas, and determines whether the overlapping regions are considered to be inside or outside. Changing this value just sets a flag - it doesn't affect the contents of the path. @see isUsingNonZeroWinding */ void setUsingNonZeroWinding (bool isNonZeroWinding) throw(); /** Returns the flag that indicates whether the path should use a non-zero winding rule. The default for a new path is true. @see setUsingNonZeroWinding */ bool isUsingNonZeroWinding() const { return useNonZeroWinding; } /** Iterates the lines and curves that a path contains. @see Path, PathFlatteningIterator */ class JUCE_API Iterator { public: Iterator (const Path& path); ~Iterator(); /** Moves onto the next element in the path. If this returns false, there are no more elements. If it returns true, the elementType variable will be set to the type of the current element, and some of the x and y variables will be filled in with values. */ bool next(); enum PathElementType { startNewSubPath, /**< For this type, x1 and y1 will be set to indicate the first point in the subpath. */ lineTo, /**< For this type, x1 and y1 indicate the end point of the line. */ quadraticTo, /**< For this type, x1, y1, x2, y2 indicate the control point and endpoint of a quadratic curve. */ cubicTo, /**< For this type, x1, y1, x2, y2, x3, y3 indicate the two control points and the endpoint of a cubic curve. */ closePath /**< Indicates that the sub-path is being closed. None of the x or y values are valid in this case. */ }; PathElementType elementType; float x1, y1, x2, y2, x3, y3; private: const Path& path; size_t index; JUCE_DECLARE_NON_COPYABLE (Iterator); }; /** Loads a stored path from a data stream. The data in the stream must have been written using writePathToStream(). Note that this will append the stored path to whatever is currently in this path, so you might need to call clear() beforehand. @see loadPathFromData, writePathToStream */ void loadPathFromStream (InputStream& source); /** Loads a stored path from a block of data. This is similar to loadPathFromStream(), but just reads from a block of data. Useful if you're including stored shapes in your code as a block of static data. @see loadPathFromStream, writePathToStream */ void loadPathFromData (const void* data, int numberOfBytes); /** Stores the path by writing it out to a stream. After writing out a path, you can reload it using loadPathFromStream(). @see loadPathFromStream, loadPathFromData */ void writePathToStream (OutputStream& destination) const; /** Creates a string containing a textual representation of this path. @see restoreFromString */ const String toString() const; /** Restores this path from a string that was created with the toString() method. @see toString() */ void restoreFromString (const String& stringVersion); private: friend class PathFlatteningIterator; friend class Path::Iterator; ArrayAllocationBase data; size_t numElements; float pathXMin, pathXMax, pathYMin, pathYMax; bool useNonZeroWinding; static const float lineMarker; static const float moveMarker; static const float quadMarker; static const float cubicMarker; static const float closeSubPathMarker; JUCE_LEAK_DETECTOR (Path); }; #endif // __JUCE_PATH_JUCEHEADER__ /*** End of inlined file: juce_Path.h ***/ class Font; /** A typeface represents a size-independent font. This base class is abstract, but calling createSystemTypefaceFor() will return a platform-specific subclass that can be used. The CustomTypeface subclass allow you to build your own typeface, and to load and save it in the Juce typeface format. Normally you should never need to deal directly with Typeface objects - the Font class does everything you typically need for rendering text. @see CustomTypeface, Font */ class JUCE_API Typeface : public ReferenceCountedObject { public: /** A handy typedef for a pointer to a typeface. */ typedef ReferenceCountedObjectPtr Ptr; /** Returns the name of the typeface. @see Font::getTypefaceName */ const String getName() const throw() { return name; } /** Creates a new system typeface. */ static const Ptr createSystemTypefaceFor (const Font& font); /** Destructor. */ virtual ~Typeface(); /** Returns true if this typeface can be used to render the specified font. When called, the font will already have been checked to make sure that its name and style flags match the typeface. */ virtual bool isSuitableForFont (const Font&) const { return true; } /** Returns the ascent of the font, as a proportion of its height. The height is considered to always be normalised as 1.0, so this will be a value less that 1.0, indicating the proportion of the font that lies above its baseline. */ virtual float getAscent() const = 0; /** Returns the descent of the font, as a proportion of its height. The height is considered to always be normalised as 1.0, so this will be a value less that 1.0, indicating the proportion of the font that lies below its baseline. */ virtual float getDescent() const = 0; /** Measures the width of a line of text. The distance returned is based on the font having an normalised height of 1.0. You should never need to call this directly! Use Font::getStringWidth() instead! */ virtual float getStringWidth (const String& text) = 0; /** Converts a line of text into its glyph numbers and their positions. The distances returned are based on the font having an normalised height of 1.0. You should never need to call this directly! Use Font::getGlyphPositions() instead! */ virtual void getGlyphPositions (const String& text, Array & glyphs, Array& xOffsets) = 0; /** Returns the outline for a glyph. The path returned will be normalised to a font height of 1.0. */ virtual bool getOutlineForGlyph (int glyphNumber, Path& path) = 0; /** Returns true if the typeface uses hinting. */ virtual bool isHinted() const { return false; } /** Changes the number of fonts that are cached in memory. */ static void setTypefaceCacheSize (int numFontsToCache); protected: String name; bool isFallbackFont; explicit Typeface (const String& name) throw(); static const Ptr getFallbackTypeface(); private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Typeface); }; /** A typeface that can be populated with custom glyphs. You can create a CustomTypeface if you need one that contains your own glyphs, or if you need to load a typeface from a Juce-formatted binary stream. If you want to create a copy of a native face, you can use addGlyphsFromOtherTypeface() to copy glyphs into this face. @see Typeface, Font */ class JUCE_API CustomTypeface : public Typeface { public: /** Creates a new, empty typeface. */ CustomTypeface(); /** Loads a typeface from a previously saved stream. The stream must have been created by writeToStream(). @see writeToStream */ explicit CustomTypeface (InputStream& serialisedTypefaceStream); /** Destructor. */ ~CustomTypeface(); /** Resets this typeface, deleting all its glyphs and settings. */ void clear(); /** Sets the vital statistics for the typeface. @param name the typeface's name @param ascent the ascent - this is normalised to a height of 1.0 and this is the value that will be returned by Typeface::getAscent(). The descent is assumed to be (1.0 - ascent) @param isBold should be true if the typeface is bold @param isItalic should be true if the typeface is italic @param defaultCharacter the character to be used as a replacement if there's no glyph available for the character that's being drawn */ void setCharacteristics (const String& name, float ascent, bool isBold, bool isItalic, juce_wchar defaultCharacter) throw(); /** Adds a glyph to the typeface. The path that is passed in is normalised so that the font height is 1.0, and its origin is the anchor point of the character on its baseline. The width is the nominal width of the character, and any extra kerning values that are specified will be added to this width. */ void addGlyph (juce_wchar character, const Path& path, float width) throw(); /** Specifies an extra kerning amount to be used between a pair of characters. The amount will be added to the nominal width of the first character when laying out a string. */ void addKerningPair (juce_wchar char1, juce_wchar char2, float extraAmount) throw(); /** Adds a range of glyphs from another typeface. This will attempt to pull in the paths and kerning information from another typeface and add it to this one. */ void addGlyphsFromOtherTypeface (Typeface& typefaceToCopy, juce_wchar characterStartIndex, int numCharacters) throw(); /** Saves this typeface as a Juce-formatted font file. A CustomTypeface can be created to reload the data that is written - see the CustomTypeface constructor. */ bool writeToStream (OutputStream& outputStream); // The following methods implement the basic Typeface behaviour. float getAscent() const; float getDescent() const; float getStringWidth (const String& text); void getGlyphPositions (const String& text, Array & glyphs, Array& xOffsets); bool getOutlineForGlyph (int glyphNumber, Path& path); int getGlyphForCharacter (juce_wchar character); protected: juce_wchar defaultCharacter; float ascent; bool isBold, isItalic; /** If a subclass overrides this, it can load glyphs into the font on-demand. When methods such as getGlyphPositions() or getOutlineForGlyph() are asked for a particular character and there's no corresponding glyph, they'll call this method so that a subclass can try to add that glyph, returning true if it manages to do so. */ virtual bool loadGlyphIfPossible (juce_wchar characterNeeded); private: class GlyphInfo; friend class OwnedArray; OwnedArray glyphs; short lookupTable [128]; GlyphInfo* findGlyph (const juce_wchar character, bool loadIfNeeded) throw(); GlyphInfo* findGlyphSubstituting (juce_wchar character) throw(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomTypeface); }; #endif // __JUCE_TYPEFACE_JUCEHEADER__ /*** End of inlined file: juce_Typeface.h ***/ class LowLevelGraphicsContext; /** Represents a particular font, including its size, style, etc. Apart from the typeface to be used, a Font object also dictates whether the font is bold, italic, underlined, how big it is, and its kerning and horizontal scale factor. @see Typeface */ class JUCE_API Font { public: /** A combination of these values is used by the constructor to specify the style of font to use. */ enum FontStyleFlags { plain = 0, /**< indicates a plain, non-bold, non-italic version of the font. @see setStyleFlags */ bold = 1, /**< boldens the font. @see setStyleFlags */ italic = 2, /**< finds an italic version of the font. @see setStyleFlags */ underlined = 4 /**< underlines the font. @see setStyleFlags */ }; /** Creates a sans-serif font in a given size. @param fontHeight the height in pixels (can be fractional) @param styleFlags the style to use - this can be a combination of the Font::bold, Font::italic and Font::underlined, or just Font::plain for the normal style. @see FontStyleFlags, getDefaultSansSerifFontName */ Font (float fontHeight, int styleFlags = plain); /** Creates a font with a given typeface and parameters. @param typefaceName the name of the typeface to use @param fontHeight the height in pixels (can be fractional) @param styleFlags the style to use - this can be a combination of the Font::bold, Font::italic and Font::underlined, or just Font::plain for the normal style. @see FontStyleFlags, getDefaultSansSerifFontName */ Font (const String& typefaceName, float fontHeight, int styleFlags); /** Creates a copy of another Font object. */ Font (const Font& other) throw(); /** Creates a font for a typeface. */ Font (const Typeface::Ptr& typeface); /** Creates a basic sans-serif font at a default height. You should use one of the other constructors for creating a font that you're planning on drawing with - this constructor is here to help initialise objects before changing the font's settings later. */ Font(); /** Copies this font from another one. */ Font& operator= (const Font& other) throw(); bool operator== (const Font& other) const throw(); bool operator!= (const Font& other) const throw(); /** Destructor. */ ~Font() throw(); /** Changes the name of the typeface family. e.g. "Arial", "Courier", etc. This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font names, but are generic names that are used to represent the various default fonts. If you need to know the exact typeface name being used, you can call Font::getTypeface()->getTypefaceName(), which will give you the platform-specific name. If a suitable font isn't found on the machine, it'll just use a default instead. */ void setTypefaceName (const String& faceName); /** Returns the name of the typeface family that this font uses. e.g. "Arial", "Courier", etc. This may also be set to Font::getDefaultSansSerifFontName(), Font::getDefaultSerifFontName(), or Font::getDefaultMonospacedFontName(), which are not actual platform-specific font names, but are generic names that are used to represent the various default fonts. If you need to know the exact typeface name being used, you can call Font::getTypeface()->getTypefaceName(), which will give you the platform-specific name. */ const String& getTypefaceName() const throw() { return font->typefaceName; } /** Returns a typeface name that represents the default sans-serif font. This is also the typeface that will be used when a font is created without specifying any typeface details. Note that this method just returns a generic placeholder string that means "the default sans-serif font" - it's not the actual name of this font. To get the actual name, use getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). @see setTypefaceName, getDefaultSerifFontName, getDefaultMonospacedFontName */ static const String getDefaultSansSerifFontName(); /** Returns a typeface name that represents the default sans-serif font. Note that this method just returns a generic placeholder string that means "the default serif font" - it's not the actual name of this font. To get the actual name, use getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). @see setTypefaceName, getDefaultSansSerifFontName, getDefaultMonospacedFontName */ static const String getDefaultSerifFontName(); /** Returns a typeface name that represents the default sans-serif font. Note that this method just returns a generic placeholder string that means "the default monospaced font" - it's not the actual name of this font. To get the actual name, use getPlatformDefaultFontNames() or LookAndFeel::getTypefaceForFont(). @see setTypefaceName, getDefaultSansSerifFontName, getDefaultSerifFontName */ static const String getDefaultMonospacedFontName(); /** Returns the typeface names of the default fonts on the current platform. */ static void getPlatformDefaultFontNames (String& defaultSans, String& defaultSerif, String& defaultFixed, String& defaultFallback); /** Returns the total height of this font. This is the maximum height, from the top of the ascent to the bottom of the descenders. @see setHeight, setHeightWithoutChangingWidth, getAscent */ float getHeight() const throw() { return font->height; } /** Changes the font's height. @see getHeight, setHeightWithoutChangingWidth */ void setHeight (float newHeight); /** Changes the font's height without changing its width. This alters the horizontal scale to compensate for the change in height. */ void setHeightWithoutChangingWidth (float newHeight); /** Returns the height of the font above its baseline. This is the maximum height from the baseline to the top. @see getHeight, getDescent */ float getAscent() const; /** Returns the amount that the font descends below its baseline. This is calculated as (getHeight() - getAscent()). @see getAscent, getHeight */ float getDescent() const; /** Returns the font's style flags. This will return a bitwise-or'ed combination of values from the FontStyleFlags enum, to describe whether the font is bold, italic, etc. @see FontStyleFlags */ int getStyleFlags() const throw() { return font->styleFlags; } /** Changes the font's style. @param newFlags a bitwise-or'ed combination of values from the FontStyleFlags enum, to set the font's properties @see FontStyleFlags */ void setStyleFlags (int newFlags); /** Makes the font bold or non-bold. */ void setBold (bool shouldBeBold); /** Returns a copy of this font with the bold attribute set. */ const Font boldened() const; /** Returns true if the font is bold. */ bool isBold() const throw(); /** Makes the font italic or non-italic. */ void setItalic (bool shouldBeItalic); /** Returns a copy of this font with the italic attribute set. */ const Font italicised() const; /** Returns true if the font is italic. */ bool isItalic() const throw(); /** Makes the font underlined or non-underlined. */ void setUnderline (bool shouldBeUnderlined); /** Returns true if the font is underlined. */ bool isUnderlined() const throw(); /** Changes the font's horizontal scale factor. @param scaleFactor a value of 1.0 is the normal scale, less than this will be narrower, greater than 1.0 will be stretched out. */ void setHorizontalScale (float scaleFactor); /** Returns the font's horizontal scale. A value of 1.0 is the normal scale, less than this will be narrower, greater than 1.0 will be stretched out. @see setHorizontalScale */ float getHorizontalScale() const throw() { return font->horizontalScale; } /** Changes the font's kerning. @param extraKerning a multiple of the font's height that will be added to space between the characters. So a value of zero is normal spacing, positive values spread the letters out, negative values make them closer together. */ void setExtraKerningFactor (float extraKerning); /** Returns the font's kerning. This is the extra space added between adjacent characters, as a proportion of the font's height. A value of zero is normal spacing, positive values will spread the letters out more, and negative values make them closer together. */ float getExtraKerningFactor() const throw() { return font->kerning; } /** Changes all the font's characteristics with one call. */ void setSizeAndStyle (float newHeight, int newStyleFlags, float newHorizontalScale, float newKerningAmount); /** Returns the total width of a string as it would be drawn using this font. For a more accurate floating-point result, use getStringWidthFloat(). */ int getStringWidth (const String& text) const; /** Returns the total width of a string as it would be drawn using this font. @see getStringWidth */ float getStringWidthFloat (const String& text) const; /** Returns the series of glyph numbers and their x offsets needed to represent a string. An extra x offset is added at the end of the run, to indicate where the right hand edge of the last character is. */ void getGlyphPositions (const String& text, Array & glyphs, Array & xOffsets) const; /** Returns the typeface used by this font. Note that the object returned may go out of scope if this font is deleted or has its style changed. */ Typeface* getTypeface() const; /** Creates an array of Font objects to represent all the fonts on the system. If you just need the names of the typefaces, you can also use findAllTypefaceNames() instead. @param results the array to which new Font objects will be added. */ static void findFonts (Array& results); /** Returns a list of all the available typeface names. The names returned can be passed into setTypefaceName(). You can use this instead of findFonts() if you only need their names, and not font objects. */ static const StringArray findAllTypefaceNames(); /** Returns the name of the typeface to be used for rendering glyphs that aren't found in the requested typeface. */ static const String getFallbackFontName(); /** Sets the (platform-specific) name of the typeface to use to find glyphs that aren't available in whatever font you're trying to use. */ static void setFallbackFontName (const String& name); /** Creates a string to describe this font. The string will contain information to describe the font's typeface, size, and style. To recreate the font from this string, use fromString(). */ const String toString() const; /** Recreates a font from its stringified encoding. This method takes a string that was created by toString(), and recreates the original font. */ static const Font fromString (const String& fontDescription); private: friend class FontGlyphAlphaMap; friend class TypefaceCache; class SharedFontInternal : public ReferenceCountedObject { public: SharedFontInternal (float height, int styleFlags) throw(); SharedFontInternal (const String& typefaceName, float height, int styleFlags) throw(); SharedFontInternal (const Typeface::Ptr& typeface) throw(); SharedFontInternal (const SharedFontInternal& other) throw(); bool operator== (const SharedFontInternal&) const throw(); String typefaceName; float height, horizontalScale, kerning, ascent; int styleFlags; Typeface::Ptr typeface; }; ReferenceCountedObjectPtr font; void dupeInternalIfShared(); JUCE_LEAK_DETECTOR (Font); }; #endif // __JUCE_FONT_JUCEHEADER__ /*** End of inlined file: juce_Font.h ***/ /*** Start of inlined file: juce_PathStrokeType.h ***/ #ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__ #define __JUCE_PATHSTROKETYPE_JUCEHEADER__ /** Describes a type of stroke used to render a solid outline along a path. A PathStrokeType object can be used directly to create the shape of an outline around a path, and is used by Graphics::strokePath to specify the type of stroke to draw. @see Path, Graphics::strokePath */ class JUCE_API PathStrokeType { public: /** The type of shape to use for the corners between two adjacent line segments. */ enum JointStyle { mitered, /**< Indicates that corners should be drawn with sharp joints. Note that for angles that curve back on themselves, drawing a mitre could require extending the point too far away from the path, so a mitre limit is imposed and any corners that exceed it are drawn as bevelled instead. */ curved, /**< Indicates that corners should be drawn as rounded-off. */ beveled /**< Indicates that corners should be drawn with a line flattening their outside edge. */ }; /** The type shape to use for the ends of lines. */ enum EndCapStyle { butt, /**< Ends of lines are flat and don't extend beyond the end point. */ square, /**< Ends of lines are flat, but stick out beyond the end point for half the thickness of the stroke. */ rounded /**< Ends of lines are rounded-off with a circular shape. */ }; /** Creates a stroke type. @param strokeThickness the width of the line to use @param jointStyle the type of joints to use for corners @param endStyle the type of end-caps to use for the ends of open paths. */ PathStrokeType (float strokeThickness, JointStyle jointStyle = mitered, EndCapStyle endStyle = butt) throw(); /** Createes a copy of another stroke type. */ PathStrokeType (const PathStrokeType& other) throw(); /** Copies another stroke onto this one. */ PathStrokeType& operator= (const PathStrokeType& other) throw(); /** Destructor. */ ~PathStrokeType() throw(); /** Applies this stroke type to a path and returns the resultant stroke as another Path. @param destPath the resultant stroked outline shape will be copied into this path. Note that it's ok for the source and destination Paths to be the same object, so you can easily turn a path into a stroked version of itself. @param sourcePath the path to use as the source @param transform an optional transform to apply to the points from the source path as they are being used @param extraAccuracy if this is greater than 1.0, it will subdivide the path to a higher resolution, which improves the quality if you'll later want to enlarge the stroked path. So for example, if you're planning on drawing the stroke at 3x the size that you're creating it, you should set this to 3. @see createDashedStroke */ void createStrokedPath (Path& destPath, const Path& sourcePath, const AffineTransform& transform = AffineTransform::identity, float extraAccuracy = 1.0f) const; /** Applies this stroke type to a path, creating a dashed line. This is similar to createStrokedPath, but uses the array passed in to break the stroke up into a series of dashes. @param destPath the resultant stroked outline shape will be copied into this path. Note that it's ok for the source and destination Paths to be the same object, so you can easily turn a path into a stroked version of itself. @param sourcePath the path to use as the source @param dashLengths An array of alternating on/off lengths. E.g. { 2, 3, 4, 5 } will create a line of length 2, then skip a length of 3, then add a line of length 4, skip 5, and keep repeating this pattern. @param numDashLengths The number of lengths in the dashLengths array. This should really be an even number, otherwise the pattern will get out of step as it repeats. @param transform an optional transform to apply to the points from the source path as they are being used @param extraAccuracy if this is greater than 1.0, it will subdivide the path to a higher resolution, which improves the quality if you'll later want to enlarge the stroked path. So for example, if you're planning on drawing the stroke at 3x the size that you're creating it, you should set this to 3. */ void createDashedStroke (Path& destPath, const Path& sourcePath, const float* dashLengths, int numDashLengths, const AffineTransform& transform = AffineTransform::identity, float extraAccuracy = 1.0f) const; /** Applies this stroke type to a path and returns the resultant stroke as another Path. @param destPath the resultant stroked outline shape will be copied into this path. Note that it's ok for the source and destination Paths to be the same object, so you can easily turn a path into a stroked version of itself. @param sourcePath the path to use as the source @param arrowheadStartWidth the width of the arrowhead at the start of the path @param arrowheadStartLength the length of the arrowhead at the start of the path @param arrowheadEndWidth the width of the arrowhead at the end of the path @param arrowheadEndLength the length of the arrowhead at the end of the path @param transform an optional transform to apply to the points from the source path as they are being used @param extraAccuracy if this is greater than 1.0, it will subdivide the path to a higher resolution, which improves the quality if you'll later want to enlarge the stroked path. So for example, if you're planning on drawing the stroke at 3x the size that you're creating it, you should set this to 3. @see createDashedStroke */ void createStrokeWithArrowheads (Path& destPath, const Path& sourcePath, float arrowheadStartWidth, float arrowheadStartLength, float arrowheadEndWidth, float arrowheadEndLength, const AffineTransform& transform = AffineTransform::identity, float extraAccuracy = 1.0f) const; /** Returns the stroke thickness. */ float getStrokeThickness() const throw() { return thickness; } /** Sets the stroke thickness. */ void setStrokeThickness (float newThickness) throw() { thickness = newThickness; } /** Returns the joint style. */ JointStyle getJointStyle() const throw() { return jointStyle; } /** Sets the joint style. */ void setJointStyle (JointStyle newStyle) throw() { jointStyle = newStyle; } /** Returns the end-cap style. */ EndCapStyle getEndStyle() const throw() { return endStyle; } /** Sets the end-cap style. */ void setEndStyle (EndCapStyle newStyle) throw() { endStyle = newStyle; } /** Compares the stroke thickness, joint and end styles of two stroke types. */ bool operator== (const PathStrokeType& other) const throw(); /** Compares the stroke thickness, joint and end styles of two stroke types. */ bool operator!= (const PathStrokeType& other) const throw(); private: float thickness; JointStyle jointStyle; EndCapStyle endStyle; JUCE_LEAK_DETECTOR (PathStrokeType); }; #endif // __JUCE_PATHSTROKETYPE_JUCEHEADER__ /*** End of inlined file: juce_PathStrokeType.h ***/ /*** Start of inlined file: juce_Colours.h ***/ #ifndef __JUCE_COLOURS_JUCEHEADER__ #define __JUCE_COLOURS_JUCEHEADER__ /*** Start of inlined file: juce_Colour.h ***/ #ifndef __JUCE_COLOUR_JUCEHEADER__ #define __JUCE_COLOUR_JUCEHEADER__ /*** Start of inlined file: juce_PixelFormats.h ***/ #ifndef __JUCE_PIXELFORMATS_JUCEHEADER__ #define __JUCE_PIXELFORMATS_JUCEHEADER__ #ifndef DOXYGEN #if JUCE_MSVC #pragma pack (push, 1) #define PACKED #elif JUCE_GCC #define PACKED __attribute__((packed)) #else #define PACKED #endif #endif class PixelRGB; class PixelAlpha; /** Represents a 32-bit ARGB pixel with premultiplied alpha, and can perform compositing operations with it. This is used internally by the imaging classes. @see PixelRGB */ class JUCE_API PixelARGB { public: /** Creates a pixel without defining its colour. */ PixelARGB() throw() {} ~PixelARGB() throw() {} /** Creates a pixel from a 32-bit argb value. */ PixelARGB (const uint32 argb_) throw() : argb (argb_) { } forcedinline uint32 getARGB() const throw() { return argb; } forcedinline uint32 getRB() const throw() { return 0x00ff00ff & argb; } forcedinline uint32 getAG() const throw() { return 0x00ff00ff & (argb >> 8); } forcedinline uint8 getAlpha() const throw() { return components.a; } forcedinline uint8 getRed() const throw() { return components.r; } forcedinline uint8 getGreen() const throw() { return components.g; } forcedinline uint8 getBlue() const throw() { return components.b; } /** Blends another pixel onto this one. This takes into account the opacity of the pixel being overlaid, and blends it accordingly. */ forcedinline void blend (const PixelARGB& src) throw() { uint32 sargb = src.getARGB(); const uint32 alpha = 0x100 - (sargb >> 24); sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); sargb += 0xff00ff00 & (getAG() * alpha); argb = sargb; } /** Blends another pixel onto this one. This takes into account the opacity of the pixel being overlaid, and blends it accordingly. */ forcedinline void blend (const PixelAlpha& src) throw(); /** Blends another pixel onto this one. This takes into account the opacity of the pixel being overlaid, and blends it accordingly. */ forcedinline void blend (const PixelRGB& src) throw(); /** Blends another pixel onto this one, applying an extra multiplier to its opacity. The opacity of the pixel being overlaid is scaled by the extraAlpha factor before being used, so this can blend semi-transparently from a PixelRGB argument. */ template forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() { ++extraAlpha; uint32 sargb = ((extraAlpha * src.getAG()) & 0xff00ff00) | (((extraAlpha * src.getRB()) >> 8) & 0x00ff00ff); const uint32 alpha = 0x100 - (sargb >> 24); sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); sargb += 0xff00ff00 & (getAG() * alpha); argb = sargb; } /** Blends another pixel with this one, creating a colour that is somewhere between the two, as specified by the amount. */ template forcedinline void tween (const Pixel& src, const uint32 amount) throw() { uint32 drb = getRB(); drb += (((src.getRB() - drb) * amount) >> 8); drb &= 0x00ff00ff; uint32 dag = getAG(); dag += (((src.getAG() - dag) * amount) >> 8); dag &= 0x00ff00ff; dag <<= 8; dag |= drb; argb = dag; } /** Copies another pixel colour over this one. This doesn't blend it - this colour is simply replaced by the other one. */ template forcedinline void set (const Pixel& src) throw() { argb = src.getARGB(); } /** Replaces the colour's alpha value with another one. */ forcedinline void setAlpha (const uint8 newAlpha) throw() { components.a = newAlpha; } /** Multiplies the colour's alpha value with another one. */ forcedinline void multiplyAlpha (int multiplier) throw() { ++multiplier; argb = ((multiplier * getAG()) & 0xff00ff00) | (((multiplier * getRB()) >> 8) & 0x00ff00ff); } forcedinline void multiplyAlpha (const float multiplier) throw() { multiplyAlpha ((int) (multiplier * 256.0f)); } /** Sets the pixel's colour from individual components. */ void setARGB (const uint8 a, const uint8 r, const uint8 g, const uint8 b) throw() { components.b = b; components.g = g; components.r = r; components.a = a; } /** Premultiplies the pixel's RGB values by its alpha. */ forcedinline void premultiply() throw() { const uint32 alpha = components.a; if (alpha < 0xff) { if (alpha == 0) { components.b = 0; components.g = 0; components.r = 0; } else { components.b = (uint8) ((components.b * alpha + 0x7f) >> 8); components.g = (uint8) ((components.g * alpha + 0x7f) >> 8); components.r = (uint8) ((components.r * alpha + 0x7f) >> 8); } } } /** Unpremultiplies the pixel's RGB values. */ forcedinline void unpremultiply() throw() { const uint32 alpha = components.a; if (alpha < 0xff) { if (alpha == 0) { components.b = 0; components.g = 0; components.r = 0; } else { components.b = (uint8) jmin ((uint32) 0xff, (components.b * 0xff) / alpha); components.g = (uint8) jmin ((uint32) 0xff, (components.g * 0xff) / alpha); components.r = (uint8) jmin ((uint32) 0xff, (components.r * 0xff) / alpha); } } } forcedinline void desaturate() throw() { if (components.a < 0xff && components.a > 0) { const int newUnpremultipliedLevel = (0xff * ((int) components.r + (int) components.g + (int) components.b) / (3 * components.a)); components.r = components.g = components.b = (uint8) ((newUnpremultipliedLevel * components.a + 0x7f) >> 8); } else { components.r = components.g = components.b = (uint8) (((int) components.r + (int) components.g + (int) components.b) / 3); } } /** The indexes of the different components in the byte layout of this type of colour. */ #if JUCE_BIG_ENDIAN enum { indexA = 0, indexR = 1, indexG = 2, indexB = 3 }; #else enum { indexA = 3, indexR = 2, indexG = 1, indexB = 0 }; #endif private: union { uint32 argb; struct { #if JUCE_BIG_ENDIAN uint8 a : 8, r : 8, g : 8, b : 8; #else uint8 b, g, r, a; #endif } PACKED components; }; } #ifndef DOXYGEN PACKED #endif ; /** Represents a 24-bit RGB pixel, and can perform compositing operations on it. This is used internally by the imaging classes. @see PixelARGB */ class JUCE_API PixelRGB { public: /** Creates a pixel without defining its colour. */ PixelRGB() throw() {} ~PixelRGB() throw() {} /** Creates a pixel from a 32-bit argb value. (The argb format is that used by PixelARGB) */ PixelRGB (const uint32 argb) throw() { r = (uint8) (argb >> 16); g = (uint8) (argb >> 8); b = (uint8) (argb); } forcedinline uint32 getARGB() const throw() { return 0xff000000 | b | (g << 8) | (r << 16); } forcedinline uint32 getRB() const throw() { return b | (uint32) (r << 16); } forcedinline uint32 getAG() const throw() { return 0xff0000 | g; } forcedinline uint8 getAlpha() const throw() { return 0xff; } forcedinline uint8 getRed() const throw() { return r; } forcedinline uint8 getGreen() const throw() { return g; } forcedinline uint8 getBlue() const throw() { return b; } /** Blends another pixel onto this one. This takes into account the opacity of the pixel being overlaid, and blends it accordingly. */ forcedinline void blend (const PixelARGB& src) throw() { uint32 sargb = src.getARGB(); const uint32 alpha = 0x100 - (sargb >> 24); sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); sargb += 0x0000ff00 & (g * alpha); r = (uint8) (sargb >> 16); g = (uint8) (sargb >> 8); b = (uint8) sargb; } forcedinline void blend (const PixelRGB& src) throw() { set (src); } forcedinline void blend (const PixelAlpha& src) throw(); /** Blends another pixel onto this one, applying an extra multiplier to its opacity. The opacity of the pixel being overlaid is scaled by the extraAlpha factor before being used, so this can blend semi-transparently from a PixelRGB argument. */ template forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() { ++extraAlpha; const uint32 srb = (extraAlpha * src.getRB()) >> 8; const uint32 sag = extraAlpha * src.getAG(); uint32 sargb = (sag & 0xff00ff00) | (srb & 0x00ff00ff); const uint32 alpha = 0x100 - (sargb >> 24); sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); sargb += 0x0000ff00 & (g * alpha); b = (uint8) sargb; g = (uint8) (sargb >> 8); r = (uint8) (sargb >> 16); } /** Blends another pixel with this one, creating a colour that is somewhere between the two, as specified by the amount. */ template forcedinline void tween (const Pixel& src, const uint32 amount) throw() { uint32 drb = getRB(); drb += (((src.getRB() - drb) * amount) >> 8); uint32 dag = getAG(); dag += (((src.getAG() - dag) * amount) >> 8); b = (uint8) drb; g = (uint8) dag; r = (uint8) (drb >> 16); } /** Copies another pixel colour over this one. This doesn't blend it - this colour is simply replaced by the other one. Because PixelRGB has no alpha channel, any alpha value in the source pixel is thrown away. */ template forcedinline void set (const Pixel& src) throw() { b = src.getBlue(); g = src.getGreen(); r = src.getRed(); } /** This method is included for compatibility with the PixelARGB class. */ forcedinline void setAlpha (const uint8) throw() {} /** Multiplies the colour's alpha value with another one. */ forcedinline void multiplyAlpha (int) throw() {} /** Sets the pixel's colour from individual components. */ void setARGB (const uint8, const uint8 r_, const uint8 g_, const uint8 b_) throw() { r = r_; g = g_; b = b_; } /** Premultiplies the pixel's RGB values by its alpha. */ forcedinline void premultiply() throw() {} /** Unpremultiplies the pixel's RGB values. */ forcedinline void unpremultiply() throw() {} forcedinline void desaturate() throw() { r = g = b = (uint8) (((int) r + (int) g + (int) b) / 3); } /** The indexes of the different components in the byte layout of this type of colour. */ #if JUCE_MAC enum { indexR = 0, indexG = 1, indexB = 2 }; #else enum { indexR = 2, indexG = 1, indexB = 0 }; #endif private: #if JUCE_MAC uint8 r, g, b; #else uint8 b, g, r; #endif } #ifndef DOXYGEN PACKED #endif ; forcedinline void PixelARGB::blend (const PixelRGB& src) throw() { set (src); } /** Represents an 8-bit single-channel pixel, and can perform compositing operations on it. This is used internally by the imaging classes. @see PixelARGB, PixelRGB */ class JUCE_API PixelAlpha { public: /** Creates a pixel without defining its colour. */ PixelAlpha() throw() {} ~PixelAlpha() throw() {} /** Creates a pixel from a 32-bit argb value. (The argb format is that used by PixelARGB) */ PixelAlpha (const uint32 argb) throw() { a = (uint8) (argb >> 24); } forcedinline uint32 getARGB() const throw() { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; } forcedinline uint32 getRB() const throw() { return (((uint32) a) << 16) | a; } forcedinline uint32 getAG() const throw() { return (((uint32) a) << 16) | a; } forcedinline uint8 getAlpha() const throw() { return a; } forcedinline uint8 getRed() const throw() { return 0; } forcedinline uint8 getGreen() const throw() { return 0; } forcedinline uint8 getBlue() const throw() { return 0; } /** Blends another pixel onto this one. This takes into account the opacity of the pixel being overlaid, and blends it accordingly. */ template forcedinline void blend (const Pixel& src) throw() { const int srcA = src.getAlpha(); a = (uint8) ((a * (0x100 - srcA) >> 8) + srcA); } /** Blends another pixel onto this one, applying an extra multiplier to its opacity. The opacity of the pixel being overlaid is scaled by the extraAlpha factor before being used, so this can blend semi-transparently from a PixelRGB argument. */ template forcedinline void blend (const Pixel& src, uint32 extraAlpha) throw() { ++extraAlpha; const int srcAlpha = (extraAlpha * src.getAlpha()) >> 8; a = (uint8) ((a * (0x100 - srcAlpha) >> 8) + srcAlpha); } /** Blends another pixel with this one, creating a colour that is somewhere between the two, as specified by the amount. */ template forcedinline void tween (const Pixel& src, const uint32 amount) throw() { a += ((src,getAlpha() - a) * amount) >> 8; } /** Copies another pixel colour over this one. This doesn't blend it - this colour is simply replaced by the other one. */ template forcedinline void set (const Pixel& src) throw() { a = src.getAlpha(); } /** Replaces the colour's alpha value with another one. */ forcedinline void setAlpha (const uint8 newAlpha) throw() { a = newAlpha; } /** Multiplies the colour's alpha value with another one. */ forcedinline void multiplyAlpha (int multiplier) throw() { ++multiplier; a = (uint8) ((a * multiplier) >> 8); } forcedinline void multiplyAlpha (const float multiplier) throw() { a = (uint8) (a * multiplier); } /** Sets the pixel's colour from individual components. */ forcedinline void setARGB (const uint8 a_, const uint8 /*r*/, const uint8 /*g*/, const uint8 /*b*/) throw() { a = a_; } /** Premultiplies the pixel's RGB values by its alpha. */ forcedinline void premultiply() throw() { } /** Unpremultiplies the pixel's RGB values. */ forcedinline void unpremultiply() throw() { } forcedinline void desaturate() throw() { } /** The indexes of the different components in the byte layout of this type of colour. */ enum { indexA = 0 }; private: uint8 a : 8; } #ifndef DOXYGEN PACKED #endif ; forcedinline void PixelRGB::blend (const PixelAlpha& src) throw() { blend (PixelARGB (src.getARGB())); } forcedinline void PixelARGB::blend (const PixelAlpha& src) throw() { uint32 sargb = src.getARGB(); const uint32 alpha = 0x100 - (sargb >> 24); sargb += 0x00ff00ff & ((getRB() * alpha) >> 8); sargb += 0xff00ff00 & (getAG() * alpha); argb = sargb; } #if JUCE_MSVC #pragma pack (pop) #endif #undef PACKED #endif // __JUCE_PIXELFORMATS_JUCEHEADER__ /*** End of inlined file: juce_PixelFormats.h ***/ /** Represents a colour, also including a transparency value. The colour is stored internally as unsigned 8-bit red, green, blue and alpha values. */ class JUCE_API Colour { public: /** Creates a transparent black colour. */ Colour() throw(); /** Creates a copy of another Colour object. */ Colour (const Colour& other) throw(); /** Creates a colour from a 32-bit ARGB value. The format of this number is: ((alpha << 24) | (red << 16) | (green << 8) | blue). All components in the range 0x00 to 0xff. An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. @see getPixelARGB */ explicit Colour (uint32 argb) throw(); /** Creates an opaque colour using 8-bit red, green and blue values */ Colour (uint8 red, uint8 green, uint8 blue) throw(); /** Creates an opaque colour using 8-bit red, green and blue values */ static const Colour fromRGB (uint8 red, uint8 green, uint8 blue) throw(); /** Creates a colour using 8-bit red, green, blue and alpha values. */ Colour (uint8 red, uint8 green, uint8 blue, uint8 alpha) throw(); /** Creates a colour using 8-bit red, green, blue and alpha values. */ static const Colour fromRGBA (uint8 red, uint8 green, uint8 blue, uint8 alpha) throw(); /** Creates a colour from 8-bit red, green, and blue values, and a floating-point alpha. Alpha of 0.0 is transparent, alpha of 1.0f is opaque. Values outside the valid range will be clipped. */ Colour (uint8 red, uint8 green, uint8 blue, float alpha) throw(); /** Creates a colour using 8-bit red, green, blue and float alpha values. */ static const Colour fromRGBAFloat (uint8 red, uint8 green, uint8 blue, float alpha) throw(); /** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha. The floating point values must be between 0.0 and 1.0. An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. Values outside the valid range will be clipped. */ Colour (float hue, float saturation, float brightness, uint8 alpha) throw(); /** Creates a colour using floating point hue, saturation, brightness and alpha values. All values must be between 0.0 and 1.0. Numbers outside the valid range will be clipped. */ Colour (float hue, float saturation, float brightness, float alpha) throw(); /** Creates a colour using floating point hue, saturation and brightness values, and an 8-bit alpha. The floating point values must be between 0.0 and 1.0. An alpha of 0x00 is completely transparent, alpha of 0xff is opaque. Values outside the valid range will be clipped. */ static const Colour fromHSV (float hue, float saturation, float brightness, float alpha) throw(); /** Destructor. */ ~Colour() throw(); /** Copies another Colour object. */ Colour& operator= (const Colour& other) throw(); /** Compares two colours. */ bool operator== (const Colour& other) const throw(); /** Compares two colours. */ bool operator!= (const Colour& other) const throw(); /** Returns the red component of this colour. @returns a value between 0x00 and 0xff. */ uint8 getRed() const throw() { return argb.getRed(); } /** Returns the green component of this colour. @returns a value between 0x00 and 0xff. */ uint8 getGreen() const throw() { return argb.getGreen(); } /** Returns the blue component of this colour. @returns a value between 0x00 and 0xff. */ uint8 getBlue() const throw() { return argb.getBlue(); } /** Returns the red component of this colour as a floating point value. @returns a value between 0.0 and 1.0 */ float getFloatRed() const throw(); /** Returns the green component of this colour as a floating point value. @returns a value between 0.0 and 1.0 */ float getFloatGreen() const throw(); /** Returns the blue component of this colour as a floating point value. @returns a value between 0.0 and 1.0 */ float getFloatBlue() const throw(); /** Returns a premultiplied ARGB pixel object that represents this colour. */ const PixelARGB getPixelARGB() const throw(); /** Returns a 32-bit integer that represents this colour. The format of this number is: ((alpha << 24) | (red << 16) | (green << 16) | blue). */ uint32 getARGB() const throw(); /** Returns the colour's alpha (opacity). Alpha of 0x00 is completely transparent, 0xff is completely opaque. */ uint8 getAlpha() const throw() { return argb.getAlpha(); } /** Returns the colour's alpha (opacity) as a floating point value. Alpha of 0.0 is completely transparent, 1.0 is completely opaque. */ float getFloatAlpha() const throw(); /** Returns true if this colour is completely opaque. Equivalent to (getAlpha() == 0xff). */ bool isOpaque() const throw(); /** Returns true if this colour is completely transparent. Equivalent to (getAlpha() == 0x00). */ bool isTransparent() const throw(); /** Returns a colour that's the same colour as this one, but with a new alpha value. */ const Colour withAlpha (uint8 newAlpha) const throw(); /** Returns a colour that's the same colour as this one, but with a new alpha value. */ const Colour withAlpha (float newAlpha) const throw(); /** Returns a colour that's the same colour as this one, but with a modified alpha value. The new colour's alpha will be this object's alpha multiplied by the value passed-in. */ const Colour withMultipliedAlpha (float alphaMultiplier) const throw(); /** Returns a colour that is the result of alpha-compositing a new colour over this one. If the foreground colour is semi-transparent, it is blended onto this colour accordingly. */ const Colour overlaidWith (const Colour& foregroundColour) const throw(); /** Returns a colour that lies somewhere between this one and another. If amountOfOther is zero, the result is 100% this colour, if amountOfOther is 1.0, the result is 100% of the other colour. */ const Colour interpolatedWith (const Colour& other, float proportionOfOther) const throw(); /** Returns the colour's hue component. The value returned is in the range 0.0 to 1.0 */ float getHue() const throw(); /** Returns the colour's saturation component. The value returned is in the range 0.0 to 1.0 */ float getSaturation() const throw(); /** Returns the colour's brightness component. The value returned is in the range 0.0 to 1.0 */ float getBrightness() const throw(); /** Returns the colour's hue, saturation and brightness components all at once. The values returned are in the range 0.0 to 1.0 */ void getHSB (float& hue, float& saturation, float& brightness) const throw(); /** Returns a copy of this colour with a different hue. */ const Colour withHue (float newHue) const throw(); /** Returns a copy of this colour with a different saturation. */ const Colour withSaturation (float newSaturation) const throw(); /** Returns a copy of this colour with a different brightness. @see brighter, darker, withMultipliedBrightness */ const Colour withBrightness (float newBrightness) const throw(); /** Returns a copy of this colour with it hue rotated. The new colour's hue is ((this->getHue() + amountToRotate) % 1.0) @see brighter, darker, withMultipliedBrightness */ const Colour withRotatedHue (float amountToRotate) const throw(); /** Returns a copy of this colour with its saturation multiplied by the given value. The new colour's saturation is (this->getSaturation() * multiplier) (the result is clipped to legal limits). */ const Colour withMultipliedSaturation (float multiplier) const throw(); /** Returns a copy of this colour with its brightness multiplied by the given value. The new colour's saturation is (this->getBrightness() * multiplier) (the result is clipped to legal limits). */ const Colour withMultipliedBrightness (float amount) const throw(); /** Returns a brighter version of this colour. @param amountBrighter how much brighter to make it - a value from 0 to 1.0 where 0 is unchanged, and higher values make it brighter @see withMultipliedBrightness */ const Colour brighter (float amountBrighter = 0.4f) const throw(); /** Returns a darker version of this colour. @param amountDarker how much darker to make it - a value from 0 to 1.0 where 0 is unchanged, and higher values make it darker @see withMultipliedBrightness */ const Colour darker (float amountDarker = 0.4f) const throw(); /** Returns a colour that will be clearly visible against this colour. The amount parameter indicates how contrasting the new colour should be, so e.g. Colours::black.contrasting (0.1f) will return a colour that's just a little bit lighter; Colours::black.contrasting (1.0f) will return white; Colours::white.contrasting (1.0f) will return black, etc. */ const Colour contrasting (float amount = 1.0f) const throw(); /** Returns a colour that contrasts against two colours. Looks for a colour that contrasts with both of the colours passed-in. Handy for things like choosing a highlight colour in text editors, etc. */ static const Colour contrasting (const Colour& colour1, const Colour& colour2) throw(); /** Returns an opaque shade of grey. @param brightness the level of grey to return - 0 is black, 1.0 is white */ static const Colour greyLevel (float brightness) throw(); /** Returns a stringified version of this colour. The string can be turned back into a colour using the fromString() method. */ const String toString() const; /** Reads the colour from a string that was created with toString(). */ static const Colour fromString (const String& encodedColourString); /** Returns the colour as a hex string in the form RRGGBB or AARRGGBB. */ const String toDisplayString (bool includeAlphaValue) const; private: PixelARGB argb; }; #endif // __JUCE_COLOUR_JUCEHEADER__ /*** End of inlined file: juce_Colour.h ***/ /** Contains a set of predefined named colours (mostly standard HTML colours) @see Colour, Colours::greyLevel */ class Colours { public: static JUCE_API const Colour transparentBlack, /**< ARGB = 0x00000000 */ transparentWhite, /**< ARGB = 0x00ffffff */ black, /**< ARGB = 0xff000000 */ white, /**< ARGB = 0xffffffff */ blue, /**< ARGB = 0xff0000ff */ grey, /**< ARGB = 0xff808080 */ green, /**< ARGB = 0xff008000 */ red, /**< ARGB = 0xffff0000 */ yellow, /**< ARGB = 0xffffff00 */ aliceblue, antiquewhite, aqua, aquamarine, azure, beige, bisque, blanchedalmond, blueviolet, brown, burlywood, cadetblue, chartreuse, chocolate, coral, cornflowerblue, cornsilk, crimson, cyan, darkblue, darkcyan, darkgoldenrod, darkgrey, darkgreen, darkkhaki, darkmagenta, darkolivegreen, darkorange, darkorchid, darkred, darksalmon, darkseagreen, darkslateblue, darkslategrey, darkturquoise, darkviolet, deeppink, deepskyblue, dimgrey, dodgerblue, firebrick, floralwhite, forestgreen, fuchsia, gainsboro, gold, goldenrod, greenyellow, honeydew, hotpink, indianred, indigo, ivory, khaki, lavender, lavenderblush, lemonchiffon, lightblue, lightcoral, lightcyan, lightgoldenrodyellow, lightgreen, lightgrey, lightpink, lightsalmon, lightseagreen, lightskyblue, lightslategrey, lightsteelblue, lightyellow, lime, limegreen, linen, magenta, maroon, mediumaquamarine, mediumblue, mediumorchid, mediumpurple, mediumseagreen, mediumslateblue, mediumspringgreen, mediumturquoise, mediumvioletred, midnightblue, mintcream, mistyrose, navajowhite, navy, oldlace, olive, olivedrab, orange, orangered, orchid, palegoldenrod, palegreen, paleturquoise, palevioletred, papayawhip, peachpuff, peru, pink, plum, powderblue, purple, rosybrown, royalblue, saddlebrown, salmon, sandybrown, seagreen, seashell, sienna, silver, skyblue, slateblue, slategrey, snow, springgreen, steelblue, tan, teal, thistle, tomato, turquoise, violet, wheat, whitesmoke, yellowgreen; /** Attempts to look up a string in the list of known colour names, and return the appropriate colour. A non-case-sensitive search is made of the list of predefined colours, and if a match is found, that colour is returned. If no match is found, the colour passed in as the defaultColour parameter is returned. */ static JUCE_API const Colour findColourForName (const String& colourName, const Colour& defaultColour); private: // this isn't a class you should ever instantiate - it's just here for the // static values in it. Colours(); JUCE_DECLARE_NON_COPYABLE (Colours); }; #endif // __JUCE_COLOURS_JUCEHEADER__ /*** End of inlined file: juce_Colours.h ***/ /*** Start of inlined file: juce_ColourGradient.h ***/ #ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__ #define __JUCE_COLOURGRADIENT_JUCEHEADER__ /** Describes the layout and colours that should be used to paint a colour gradient. @see Graphics::setGradientFill */ class JUCE_API ColourGradient { public: /** Creates a gradient object. (x1, y1) is the location to draw with colour1. Likewise (x2, y2) is where colour2 should be. In between them there's a gradient. If isRadial is true, the colours form a circular gradient with (x1, y1) at its centre. The alpha transparencies of the colours are used, so note that if you blend from transparent to a solid colour, the RGB of the transparent colour will become visible in parts of the gradient. e.g. blending from Colour::transparentBlack to Colours::white will produce a muddy grey colour midway, but Colour::transparentWhite to Colours::white will be white all the way across. @see ColourGradient */ ColourGradient (const Colour& colour1, float x1, float y1, const Colour& colour2, float x2, float y2, bool isRadial); /** Creates an uninitialised gradient. If you use this constructor instead of the other one, be sure to set all the object's public member variables before using it! */ ColourGradient() throw(); /** Destructor */ ~ColourGradient(); /** Removes any colours that have been added. This will also remove any start and end colours, so the gradient won't work. You'll need to add more colours with addColour(). */ void clearColours(); /** Adds a colour at a point along the length of the gradient. This allows the gradient to go through a spectrum of colours, instead of just a start and end colour. @param proportionAlongGradient a value between 0 and 1.0, which is the proportion 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 */ 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(); /** Returns the number of colour-stops that have been added. */ int getNumColours() const throw(); /** Returns the position along the length of the gradient of the colour with this index. The index is from 0 to getNumColours() - 1. The return value will be between 0.0 and 1.0 */ double getColourPosition (int index) const throw(); /** Returns the colour that was added with a given index. 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 (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 colours that it added. */ int createLookupTable (const AffineTransform& transform, HeapBlock & resultLookupTable) const; /** Returns true if all colours are opaque. */ bool isOpaque() const throw(); /** Returns true if all colours are completely transparent. */ bool isInvisible() const throw(); Point point1, point2; /** If true, the gradient should be filled circularly, centred around point1, with point2 defining a point on the circumference. If false, the gradient is linear between the two points. */ bool isRadial; bool operator== (const ColourGradient& other) const throw(); bool operator!= (const ColourGradient& other) const throw(); private: struct ColourPoint { ColourPoint() 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; } double position; Colour colour; }; Array colours; JUCE_LEAK_DETECTOR (ColourGradient); }; #endif // __JUCE_COLOURGRADIENT_JUCEHEADER__ /*** End of inlined file: juce_ColourGradient.h ***/ /*** Start of inlined file: juce_RectanglePlacement.h ***/ #ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ #define __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ /** Defines the method used to postion some kind of rectangular object within a rectangular viewport. Although similar to Justification, this is more specific, and has some extra options. */ class JUCE_API RectanglePlacement { public: /** Creates a RectanglePlacement object using a combination of flags. */ inline RectanglePlacement (int flags_) throw() : flags (flags_) {} /** Creates a copy of another RectanglePlacement object. */ RectanglePlacement (const RectanglePlacement& other) throw(); /** Copies another RectanglePlacement object. */ RectanglePlacement& operator= (const RectanglePlacement& other) throw(); /** Flag values that can be combined and used in the constructor. */ enum { /** Indicates that the source rectangle's left edge should be aligned with the left edge of the target rectangle. */ xLeft = 1, /** Indicates that the source rectangle's right edge should be aligned with the right edge of the target rectangle. */ xRight = 2, /** Indicates that the source should be placed in the centre between the left and right sides of the available space. */ xMid = 4, /** Indicates that the source's top edge should be aligned with the top edge of the destination rectangle. */ yTop = 8, /** Indicates that the source's bottom edge should be aligned with the bottom edge of the destination rectangle. */ yBottom = 16, /** Indicates that the source should be placed in the centre between the top and bottom sides of the available space. */ yMid = 32, /** If this flag is set, then the source rectangle will be resized to completely fill the destination rectangle, and all other flags are ignored. */ stretchToFit = 64, /** If this flag is set, then the source rectangle will be resized so that it is the minimum size to completely fill the destination rectangle, without changing its aspect ratio. This means that some of the source rectangle may fall outside the destination. If this flag is not set, the source will be given the maximum size at which none of it falls outside the destination rectangle. */ fillDestination = 128, /** Indicates that the source rectangle can be reduced in size if required, but should never be made larger than its original size. */ onlyReduceInSize = 256, /** Indicates that the source rectangle can be enlarged if required, but should never be made smaller than its original size. */ onlyIncreaseInSize = 512, /** Indicates that the source rectangle's size should be left unchanged. */ doNotResize = (onlyIncreaseInSize | onlyReduceInSize), /** A shorthand value that is equivalent to (xMid | yMid). */ centred = 4 + 32 }; /** Returns the raw flags that are set for this object. */ inline int getFlags() const throw() { return flags; } /** Tests a set of flags for this object. @returns true if any of the flags passed in are set on this object. */ inline bool testFlags (int flagsToTest) const throw() { return (flags & flagsToTest) != 0; } /** Adjusts the position and size of a rectangle to fit it into a space. The source rectangle co-ordinates will be adjusted so that they fit into the destination rectangle based on this object's flags. */ void applyTo (double& sourceX, double& sourceY, double& sourceW, double& sourceH, double destinationX, double destinationY, double destinationW, double destinationH) const throw(); /** Returns the transform that should be applied to these source co-ordinates to fit them into the destination rectangle using the current flags. */ template const Rectangle appliedTo (const Rectangle& source, const Rectangle& destination) const throw() { double x = source.getX(), y = source.getY(), w = source.getWidth(), h = source.getHeight(); applyTo (x, y, w, h, static_cast (destination.getX()), static_cast (destination.getY()), static_cast (destination.getWidth()), static_cast (destination.getHeight())); return Rectangle (static_cast (x), static_cast (y), static_cast (w), static_cast (h)); } /** Returns the transform that should be applied to these source co-ordinates to fit them into the destination rectangle using the current flags. */ const AffineTransform getTransformToFit (const Rectangle& source, const Rectangle& destination) const throw(); private: int flags; }; #endif // __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__ /*** End of inlined file: juce_RectanglePlacement.h ***/ class LowLevelGraphicsContext; class Image; class FillType; class RectangleList; /** A graphics context, used for drawing a component or image. When a Component needs painting, a Graphics context is passed to its Component::paint() method, and this you then call methods within this object to actually draw the component's content. A Graphics can also be created from an image, to allow drawing directly onto that image. @see Component::paint */ class JUCE_API Graphics { public: /** Creates a Graphics object to draw directly onto the given image. The graphics object that is created will be set up to draw onto the image, with the context's clipping area being the entire size of the image, and its origin being the image's origin. To draw into a subsection of an image, use the reduceClipRegion() and setOrigin() methods. Obviously you shouldn't delete the image before this context is deleted. */ explicit Graphics (const Image& imageToDrawOnto); /** Destructor. */ ~Graphics(); /** Changes the current drawing colour. This sets the colour that will now be used for drawing operations - it also sets the opacity to that of the colour passed-in. If a brush is being used when this method is called, the brush will be deselected, and any subsequent drawing will be done with a solid colour brush instead. @see setOpacity */ void setColour (const Colour& newColour); /** Changes the opacity to use with the current colour. If a solid colour is being used for drawing, this changes its opacity to this new value (i.e. it doesn't multiply the colour's opacity by this amount). If a gradient is being used, this will have no effect on it. A value of 0.0 is completely transparent, 1.0 is completely opaque. */ void setOpacity (float newOpacity); /** Sets the context to use a gradient for its fill pattern. */ void setGradientFill (const ColourGradient& gradient); /** Sets the context to use a tiled image pattern for filling. Make sure that you don't delete this image while it's still being used by this context! */ void setTiledImageFill (const Image& imageToUse, int anchorX, int anchorY, float opacity); /** Changes the current fill settings. @see setColour, setGradientFill, setTiledImageFill */ void setFillType (const FillType& newFill); /** Changes the font to use for subsequent text-drawing functions. Note there's also a setFont (float, int) method to quickly change the size and style of the current font. @see drawSingleLineText, drawMultiLineText, drawTextAsPath, drawText, drawFittedText */ void setFont (const Font& newFont); /** Changes the size and style of the currently-selected font. This is a convenient shortcut that changes the context's current font to a different size or style. The typeface won't be changed. @see Font */ void setFont (float newFontHeight, int fontStyleFlags = Font::plain); /** Returns the currently selected font. */ const Font getCurrentFont() const; /** Draws a one-line text string. This will use the current colour (or brush) to fill the text. The font is the last one specified by setFont(). @param text the string to draw @param startX the position to draw the left-hand edge of the text @param baselineY the position of the text's baseline @see drawMultiLineText, drawText, drawFittedText, GlyphArrangement::addLineOfText */ void drawSingleLineText (const String& text, int startX, int baselineY) const; /** Draws text across multiple lines. This will break the text onto a new line where there's a new-line or carriage-return character, or at a word-boundary when the text becomes wider than the size specified by the maximumLineWidth parameter. @see setFont, drawSingleLineText, drawFittedText, GlyphArrangement::addJustifiedText */ void drawMultiLineText (const String& text, int startX, int baselineY, int maximumLineWidth) const; /** Renders a string of text as a vector path. This allows a string to be transformed with an arbitrary AffineTransform and rendered using the current colour/brush. It's much slower than the normal text methods but more accurate. @see setFont */ void drawTextAsPath (const String& text, const AffineTransform& transform) const; /** Draws a line of text within a specified rectangle. The text will be positioned within the rectangle based on the justification flags passed-in. If the string is too long to fit inside the rectangle, it will either be truncated or will have ellipsis added to its end (if the useEllipsesIfTooBig flag is true). @see drawSingleLineText, drawFittedText, drawMultiLineText, GlyphArrangement::addJustifiedText */ void drawText (const String& text, int x, int y, int width, int height, const Justification& justificationType, bool useEllipsesIfTooBig) const; /** Tries to draw a text string inside a given space. This does its best to make the given text readable within the specified rectangle, so it useful for labelling things. If the text is too big, it'll be squashed horizontally or broken over multiple lines if the maximumLinesToUse value allows this. If the text just won't fit into the space, it'll cram as much as possible in there, and put some ellipsis at the end to show that it's been truncated. A Justification parameter lets you specify how the text is laid out within the rectangle, both horizontally and vertically. The minimumHorizontalScale parameter specifies how much the text can be squashed horizontally to try to squeeze it into the space. If you don't want any horizontal scaling to occur, you can set this value to 1.0f. @see GlyphArrangement::addFittedText */ void drawFittedText (const String& text, int x, int y, int width, int height, const Justification& justificationFlags, int maximumNumberOfLines, float minimumHorizontalScale = 0.7f) const; /** Fills the context's entire clip region with the current colour or brush. (See also the fillAll (const Colour&) method which is a quick way of filling it with a given colour). */ void fillAll() const; /** Fills the context's entire clip region with a given colour. This leaves the context's current colour and brush unchanged, it just uses the specified colour temporarily. */ void fillAll (const Colour& colourToUse) const; /** Fills a rectangle with the current colour or brush. @see drawRect, fillRoundedRectangle */ void fillRect (int x, int y, int width, int height) const; /** Fills a rectangle with the current colour or brush. */ void fillRect (const Rectangle& rectangle) const; /** Fills a rectangle with the current colour or brush. This uses sub-pixel positioning so is slower than the fillRect method which takes integer co-ordinates. */ void fillRect (float x, float y, float width, float height) const; /** Uses the current colour or brush to fill a rectangle with rounded corners. @see drawRoundedRectangle, Path::addRoundedRectangle */ void fillRoundedRectangle (float x, float y, float width, float height, float cornerSize) const; /** Uses the current colour or brush to fill a rectangle with rounded corners. @see drawRoundedRectangle, Path::addRoundedRectangle */ void fillRoundedRectangle (const Rectangle& rectangle, float cornerSize) const; /** Fills a rectangle with a checkerboard pattern, alternating between two colours. */ void fillCheckerBoard (const Rectangle& area, int checkWidth, int checkHeight, const Colour& colour1, const Colour& colour2) const; /** Draws four lines to form a rectangular outline, using the current colour or brush. The lines are drawn inside the given rectangle, and greater line thicknesses extend inwards. @see fillRect */ void drawRect (int x, int y, int width, int height, int lineThickness = 1) const; /** Draws four lines to form a rectangular outline, using the current colour or brush. The lines are drawn inside the given rectangle, and greater line thicknesses extend inwards. @see fillRect */ void drawRect (float x, float y, float width, float height, float lineThickness = 1.0f) const; /** Draws four lines to form a rectangular outline, using the current colour or brush. The lines are drawn inside the given rectangle, and greater line thicknesses extend inwards. @see fillRect */ void drawRect (const Rectangle& rectangle, int lineThickness = 1) const; /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. @see fillRoundedRectangle, Path::addRoundedRectangle */ void drawRoundedRectangle (float x, float y, float width, float height, float cornerSize, float lineThickness) const; /** Uses the current colour or brush to draw the outline of a rectangle with rounded corners. @see fillRoundedRectangle, Path::addRoundedRectangle */ void drawRoundedRectangle (const Rectangle& rectangle, float cornerSize, float lineThickness) const; /** Draws a 3D raised (or indented) bevel using two colours. The bevel is drawn inside the given rectangle, and greater bevel thicknesses extend inwards. The top-left colour is used for the top- and left-hand edges of the bevel; the bottom-right colour is used for the bottom- and right-hand edges. If useGradient is true, then the bevel fades out to make it look more curved and less angular. If sharpEdgeOnOutside is true, the outside of the bevel is sharp, and it fades towards the centre; if sharpEdgeOnOutside is false, then the centre edges are sharp and it fades towards the outside. */ void drawBevel (int x, int y, int width, int height, int bevelThickness, const Colour& topLeftColour = Colours::white, const Colour& bottomRightColour = Colours::black, bool useGradient = true, bool sharpEdgeOnOutside = true) const; /** Draws a pixel using the current colour or brush. */ void setPixel (int x, int y) const; /** Fills an ellipse with the current colour or brush. The ellipse is drawn to fit inside the given rectangle. @see drawEllipse, Path::addEllipse */ void fillEllipse (float x, float y, float width, float height) const; /** Draws an elliptical stroke using the current colour or brush. @see fillEllipse, Path::addEllipse */ void drawEllipse (float x, float y, float width, float height, float lineThickness) const; /** Draws a line between two points. The line is 1 pixel wide and drawn with the current colour or brush. */ void drawLine (float startX, float startY, float endX, float endY) const; /** Draws a line between two points with a given thickness. @see Path::addLineSegment */ void drawLine (float startX, float startY, float endX, float endY, float lineThickness) const; /** Draws a line between two points. The line is 1 pixel wide and drawn with the current colour or brush. */ void drawLine (const Line& line) const; /** Draws a line between two points with a given thickness. @see Path::addLineSegment */ void drawLine (const Line& line, float lineThickness) const; /** Draws a dashed line using a custom set of dash-lengths. @param startX the line's start x co-ordinate @param startY the line's start y co-ordinate @param endX the line's end x co-ordinate @param endY the line's end y co-ordinate @param dashLengths a series of lengths to specify the on/off lengths - e.g. { 4, 5, 6, 7 } will draw a line of 4 pixels, skip 5 pixels, draw 6 pixels, skip 7 pixels, and then repeat. @param numDashLengths the number of elements in the array (this must be an even number). @param lineThickness the thickness of the line to draw @see PathStrokeType::createDashedStroke */ void drawDashedLine (float startX, float startY, float endX, float endY, const float* dashLengths, int numDashLengths, float lineThickness = 1.0f) const; /** Draws a vertical line of pixels at a given x position. The x position is an integer, but the top and bottom of the line can be sub-pixel positions, and these will be anti-aliased if necessary. */ void drawVerticalLine (int x, float top, float bottom) const; /** Draws a horizontal line of pixels at a given y position. The y position is an integer, but the left and right ends of the line can be sub-pixel positions, and these will be anti-aliased if necessary. */ void drawHorizontalLine (int y, float left, float right) const; /** Fills a path using the currently selected colour or brush. */ void fillPath (const Path& path, const AffineTransform& transform = AffineTransform::identity) const; /** Draws a path's outline using the currently selected colour or brush. */ void strokePath (const Path& path, const PathStrokeType& strokeType, const AffineTransform& transform = AffineTransform::identity) const; /** Draws a line with an arrowhead at its end. @param line the line to draw @param lineThickness the thickness of the line @param arrowheadWidth the width of the arrow head (perpendicular to the line) @param arrowheadLength the length of the arrow head (along the length of the line) */ void drawArrow (const Line& line, float lineThickness, float arrowheadWidth, float arrowheadLength) const; /** Types of rendering quality that can be specified when drawing images. @see blendImage, Graphics::setImageResamplingQuality */ enum ResamplingQuality { lowResamplingQuality = 0, /**< Just uses a nearest-neighbour algorithm for resampling. */ mediumResamplingQuality = 1, /**< Uses bilinear interpolation for upsampling and area-averaging for downsampling. */ highResamplingQuality = 2 /**< Uses bicubic interpolation for upsampling and area-averaging for downsampling. */ }; /** Changes the quality that will be used when resampling images. By default a Graphics object will be set to mediumRenderingQuality. @see Graphics::drawImage, Graphics::drawImageTransformed, Graphics::drawImageWithin */ void setImageResamplingQuality (const ResamplingQuality newQuality); /** Draws an image. This will draw the whole of an image, positioning its top-left corner at the given co-ordinates, and keeping its size the same. This is the simplest image drawing method - the others give more control over the scaling and clipping of the images. Images are composited using the context's current opacity, so if you don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) (or setColour() with an opaque colour) before drawing images. */ void drawImageAt (const Image& imageToDraw, int topLeftX, int topLeftY, bool fillAlphaChannelWithCurrentBrush = false) const; /** Draws part of an image, rescaling it to fit in a given target region. The specified area of the source image is rescaled and drawn to fill the specifed destination rectangle. Images are composited using the context's current opacity, so if you don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) (or setColour() with an opaque colour) before drawing images. @param imageToDraw the image to overlay @param destX the left of the destination rectangle @param destY the top of the destination rectangle @param destWidth the width of the destination rectangle @param destHeight the height of the destination rectangle @param sourceX the left of the rectangle to copy from the source image @param sourceY the top of the rectangle to copy from the source image @param sourceWidth the width of the rectangle to copy from the source image @param sourceHeight the height of the rectangle to copy from the source image @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the source image's pixels, the source image's alpha channel is used as a mask with which to fill the destination using the current colour or brush. (If the source is has no alpha channel, then it will just fill the target with a solid rectangle) @see setImageResamplingQuality, drawImageAt, drawImageWithin, fillAlphaMap */ void drawImage (const Image& imageToDraw, int destX, int destY, int destWidth, int destHeight, int sourceX, int sourceY, int sourceWidth, int sourceHeight, bool fillAlphaChannelWithCurrentBrush = false) const; /** Draws an image, having applied an affine transform to it. This lets you throw the image around in some wacky ways, rotate it, shear, scale it, etc. Images are composited using the context's current opacity, so if you don't want it to be drawn semi-transparently, be sure to call setOpacity (1.0f) (or setColour() with an opaque colour) before drawing images. If fillAlphaChannelWithCurrentBrush is set to true, then the image's RGB channels are ignored and it is filled with the current brush, masked by its alpha channel. If you want to render only a subsection of an image, use Image::getClippedImage() to create the section that you need. @see setImageResamplingQuality, drawImage */ void drawImageTransformed (const Image& imageToDraw, const AffineTransform& transform, bool fillAlphaChannelWithCurrentBrush = false) const; /** Draws an image to fit within a designated rectangle. If the image is too big or too small for the space, it will be rescaled to fit as nicely as it can do without affecting its aspect ratio. It will then be placed within the target rectangle according to the justification flags specified. @param imageToDraw the source image to draw @param destX top-left of the target rectangle to fit it into @param destY top-left of the target rectangle to fit it into @param destWidth size of the target rectangle to fit the image into @param destHeight size of the target rectangle to fit the image into @param placementWithinTarget this specifies how the image should be positioned within the target rectangle - see the RectanglePlacement class for more details about this. @param fillAlphaChannelWithCurrentBrush if true, then instead of drawing the image, just its alpha channel will be used as a mask with which to draw with the current brush or colour. This is similar to fillAlphaMap(), and see also drawImage() @see setImageResamplingQuality, drawImage, drawImageTransformed, drawImageAt, RectanglePlacement */ void drawImageWithin (const Image& imageToDraw, int destX, int destY, int destWidth, int destHeight, const RectanglePlacement& placementWithinTarget, bool fillAlphaChannelWithCurrentBrush = false) const; /** Returns the position of the bounding box for the current clipping region. @see getClipRegion, clipRegionIntersects */ const Rectangle getClipBounds() const; /** Checks whether a rectangle overlaps the context's clipping region. If this returns false, no part of the given area can be drawn onto, so this method can be used to optimise a component's paint() method, by letting it avoid drawing complex objects that aren't within the region being repainted. */ bool clipRegionIntersects (const Rectangle& area) const; /** Intersects the current clipping region with another region. @returns true if the resulting clipping region is non-zero in size @see setOrigin, clipRegionIntersects */ bool reduceClipRegion (int x, int y, int width, int height); /** Intersects the current clipping region with another region. @returns true if the resulting clipping region is non-zero in size @see setOrigin, clipRegionIntersects */ bool reduceClipRegion (const Rectangle& area); /** Intersects the current clipping region with a rectangle list region. @returns true if the resulting clipping region is non-zero in size @see setOrigin, clipRegionIntersects */ bool reduceClipRegion (const RectangleList& clipRegion); /** Intersects the current clipping region with a path. @returns true if the resulting clipping region is non-zero in size @see reduceClipRegion */ bool reduceClipRegion (const Path& path, const AffineTransform& transform = AffineTransform::identity); /** Intersects the current clipping region with an image's alpha-channel. The current clipping path is intersected with the area covered by this image's alpha-channel, after the image has been transformed by the specified matrix. @param image the image whose alpha-channel should be used. If the image doesn't have an alpha-channel, it is treated as entirely opaque. @param transform a matrix to apply to the image @returns true if the resulting clipping region is non-zero in size @see reduceClipRegion */ bool reduceClipRegion (const Image& image, const AffineTransform& transform); /** Excludes a rectangle to stop it being drawn into. */ void excludeClipRegion (const Rectangle& rectangleToExclude); /** Returns true if no drawing can be done because the clip region is zero. */ bool isClipEmpty() const; /** Saves the current graphics state on an internal stack. To restore the state, use restoreState(). @see ScopedSaveState */ void saveState(); /** Restores a graphics state that was previously saved with saveState(). @see ScopedSaveState */ void restoreState(); /** Uses RAII to save and restore the state of a graphics context. On construction, this calls Graphics::saveState(), and on destruction it calls Graphics::restoreState() on the Graphics object that you supply. */ class ScopedSaveState { public: ScopedSaveState (Graphics& g); ~ScopedSaveState(); private: Graphics& context; JUCE_DECLARE_NON_COPYABLE (ScopedSaveState); }; /** Begins rendering to an off-screen bitmap which will later be flattened onto the current context with the given opacity. The context uses an internal stack of temporary image layers to do this. When you've finished drawing to the layer, call endTransparencyLayer() to complete the operation and composite the finished layer. Every call to beginTransparencyLayer() MUST be matched by a corresponding call to endTransparencyLayer()! This call also saves the current state, and endTransparencyLayer() restores it. */ void beginTransparencyLayer (float layerOpacity); /** Completes a drawing operation to a temporary semi-transparent buffer. See beginTransparencyLayer() for more details. */ void endTransparencyLayer(); /** Moves the position of the context's origin. This changes the position that the context considers to be (0, 0) to the specified position. So if you call setOrigin (100, 100), then the position that was previously referred to as (100, 100) will subsequently be considered to be (0, 0). @see reduceClipRegion, addTransform */ void setOrigin (int newOriginX, int newOriginY); /** Adds a transformation which will be performed on all the graphics operations that the context subsequently performs. After calling this, all the coordinates that are passed into the context will be transformed by this matrix. @see setOrigin */ void addTransform (const AffineTransform& transform); /** Resets the current colour, brush, and font to default settings. */ void resetToDefaultState(); /** Returns true if this context is drawing to a vector-based device, such as a printer. */ bool isVectorDevice() const; /** Create a graphics that uses a given low-level renderer. For internal use only. NB. The context will NOT be deleted by this object when it is deleted. */ Graphics (LowLevelGraphicsContext* internalContext) throw(); /** @internal */ LowLevelGraphicsContext* getInternalContext() const throw() { return context; } private: LowLevelGraphicsContext* const context; ScopedPointer contextToDelete; bool saveStatePending; void saveStateIfPending(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Graphics); }; #endif // __JUCE_GRAPHICS_JUCEHEADER__ /*** End of inlined file: juce_Graphics.h ***/ /** A graphical effect filter that can be applied to components. An ImageEffectFilter can be applied to the image that a component paints before it hits the screen. This is used for adding effects like shadows, blurs, etc. @see Component::setComponentEffect */ class JUCE_API ImageEffectFilter { public: /** Overridden to render the effect. The implementation of this method must use the image that is passed in as its source, and should render its output to the graphics context passed in. @param sourceImage the image that the source component has just rendered with its paint() method. The image may or may not have an alpha channel, depending on whether the component is opaque. @param destContext the graphics context to use to draw the resultant image. @param alpha the alpha with which to draw the resultant image to the target context */ virtual void applyEffect (Image& sourceImage, Graphics& destContext, float alpha) = 0; /** Destructor. */ virtual ~ImageEffectFilter() {} }; #endif // __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__ /*** End of inlined file: juce_ImageEffectFilter.h ***/ /*** Start of inlined file: juce_Image.h ***/ #ifndef __JUCE_IMAGE_JUCEHEADER__ #define __JUCE_IMAGE_JUCEHEADER__ /** Holds a fixed-size bitmap. The image is stored in either 24-bit RGB or 32-bit premultiplied-ARGB format. To draw into an image, create a Graphics object for it. e.g. @code // create a transparent 500x500 image.. Image myImage (Image::RGB, 500, 500, true); Graphics g (myImage); g.setColour (Colours::red); g.fillEllipse (20, 20, 300, 200); // draws a red ellipse in our image. @endcode Other useful ways to create an image are with the ImageCache class, or the ImageFileFormat, which provides a way to load common image files. @see Graphics, ImageFileFormat, ImageCache, ImageConvolutionKernel */ class JUCE_API Image { public: /** */ enum PixelFormat { UnknownFormat, RGB, /**<< each pixel is a 3-byte packed RGB colour value. For byte order, see the PixelRGB class. */ ARGB, /**<< each pixel is a 4-byte ARGB premultiplied colour value. For byte order, see the PixelARGB class. */ SingleChannel /**<< each pixel is a 1-byte alpha channel value. */ }; /** */ enum ImageType { SoftwareImage = 0, NativeImage }; /** Creates a null image. */ Image(); /** Creates an image with a specified size and format. @param format the number of colour channels in the image @param imageWidth the desired width of the image, in pixels - this value must be greater than zero (otherwise a width of 1 will be used) @param imageHeight the desired width of the image, in pixels - this value must be greater than zero (otherwise a height of 1 will be used) @param clearImage if true, the image will initially be cleared to black (if it's RGB) or transparent black (if it's ARGB). If false, the image may contain junk initially, so you need to make sure you overwrite it thoroughly. @param type the type of image - this lets you specify whether you want a purely memory-based image, or one that may be managed by the OS if possible. */ Image (PixelFormat format, int imageWidth, int imageHeight, bool clearImage, ImageType type = NativeImage); /** Creates a shared reference to another image. This won't create a duplicate of the image - when Image objects are copied, they simply point to the same shared image data. To make sure that an Image object has its own unique, unshared internal data, call duplicateIfShared(). */ Image (const Image& other); /** Makes this image refer to the same underlying image as another object. This won't create a duplicate of the image - when Image objects are copied, they simply point to the same shared image data. To make sure that an Image object has its own unique, unshared internal data, call duplicateIfShared(). */ Image& operator= (const Image&); /** Destructor. */ ~Image(); /** Returns true if the two images are referring to the same internal, shared image. */ bool operator== (const Image& other) const throw() { return image == other.image; } /** Returns true if the two images are not referring to the same internal, shared image. */ bool operator!= (const Image& other) const throw() { return image != other.image; } /** Returns true if this image isn't null. If you create an Image with the default constructor, it has no size or content, and is null until you reassign it to an Image which contains some actual data. The isNull() method is the opposite of isValid(). @see isNull */ inline bool isValid() const throw() { return image != 0; } /** Returns true if this image is not valid. If you create an Image with the default constructor, it has no size or content, and is null until you reassign it to an Image which contains some actual data. The isNull() method is the opposite of isValid(). @see isValid */ inline bool isNull() const throw() { return image == 0; } /** A null Image object that can be used when you need to return an invalid image. This object is the equivalient to an Image created with the default constructor. */ static const Image null; /** Returns the image's width (in pixels). */ int getWidth() const throw() { return image == 0 ? 0 : image->width; } /** Returns the image's height (in pixels). */ int getHeight() const throw() { return image == 0 ? 0 : image->height; } /** Returns a rectangle with the same size as this image. The rectangle's origin is always (0, 0). */ const Rectangle getBounds() const throw() { return image == 0 ? Rectangle() : Rectangle (image->width, image->height); } /** Returns the image's pixel format. */ PixelFormat getFormat() const throw() { return image == 0 ? UnknownFormat : image->format; } /** True if the image's format is ARGB. */ bool isARGB() const throw() { return getFormat() == ARGB; } /** True if the image's format is RGB. */ bool isRGB() const throw() { return getFormat() == RGB; } /** True if the image's format is a single-channel alpha map. */ bool isSingleChannel() const throw() { return getFormat() == SingleChannel; } /** True if the image contains an alpha-channel. */ bool hasAlphaChannel() const throw() { return getFormat() != RGB; } /** Clears a section of the image with a given colour. This won't do any alpha-blending - it just sets all pixels in the image to the given colour (which may be non-opaque if the image has an alpha channel). */ void clear (const Rectangle& area, const Colour& colourToClearTo = Colour (0x00000000)); /** Returns a rescaled version of this image. A new image is returned which is a copy of this one, rescaled to the given size. Note that if the new size is identical to the existing image, this will just return a reference to the original image, and won't actually create a duplicate. */ const Image rescaled (int newWidth, int newHeight, Graphics::ResamplingQuality quality = Graphics::mediumResamplingQuality) const; /** Returns a version of this image with a different image format. A new image is returned which has been converted to the specified format. Note that if the new format is no different to the current one, this will just return a reference to the original image, and won't actually create a copy. */ const Image convertedToFormat (PixelFormat newFormat) const; /** Makes sure that no other Image objects share the same underlying data as this one. If no other Image objects refer to the same shared data as this one, this method has no effect. But if there are other references to the data, this will create a new copy of the data internally. Call this if you want to draw onto the image, but want to make sure that this doesn't affect any other code that may be sharing the same data. @see getReferenceCount */ void duplicateIfShared(); /** Returns an image which refers to a subsection of this image. This will not make a copy of the original - the new image will keep a reference to it, so that if the original image is changed, the contents of the subsection will also change. Likewise if you draw into the subimage, you'll also be drawing onto that area of the original image. Note that if you use operator= to make the original Image object refer to something else, the subsection image won't pick up this change, it'll remain pointing at the original. The area passed-in will be clipped to the bounds of this image, so this may return a smaller image than the area you asked for, or even a null image if the area was out-of-bounds. */ const Image getClippedImage (const Rectangle& area) const; /** Returns the colour of one of the pixels in the image. If the co-ordinates given are beyond the image's boundaries, this will return Colours::transparentBlack. @see setPixelAt, Image::BitmapData::getPixelColour */ const Colour getPixelAt (int x, int y) const; /** Sets the colour of one of the image's pixels. If the co-ordinates are beyond the image's boundaries, then nothing will happen. Note that this won't do any alpha-blending, it'll just replace the existing pixel with the given one. The colour's opacity will be ignored if this image doesn't have an alpha-channel. @see getPixelAt, Image::BitmapData::setPixelColour */ void setPixelAt (int x, int y, const Colour& colour); /** Changes the opacity of a pixel. This only has an effect if the image has an alpha channel and if the given co-ordinates are inside the image's boundary. The multiplier must be in the range 0 to 1.0, and the current alpha at the given co-ordinates will be multiplied by this value. @see setPixelAt */ void multiplyAlphaAt (int x, int y, float multiplier); /** Changes the overall opacity of the image. This will multiply the alpha value of each pixel in the image by the given amount (limiting the resulting alpha values between 0 and 255). This allows you to make an image more or less transparent. If the image doesn't have an alpha channel, this won't have any effect. */ void multiplyAllAlphas (float amountToMultiplyBy); /** Changes all the colours to be shades of grey, based on their current luminosity. */ void desaturate(); /** Retrieves a section of an image as raw pixel data, so it can be read or written to. You should only use this class as a last resort - messing about with the internals of an image is only recommended for people who really know what they're doing! A BitmapData object should be used as a temporary, stack-based object. Don't keep one hanging around while the image is being used elsewhere. Depending on the way the image class is implemented, this may create a temporary buffer which is copied back to the image when the object is deleted, or it may just get a pointer directly into the image's raw data. You can use the stride and data values in this class directly, but don't alter them! The actual format of the pixel data depends on the image's format - see Image::getFormat(), and the PixelRGB, PixelARGB and PixelAlpha classes for more info. */ class BitmapData { public: BitmapData (Image& image, int x, int y, int w, int h, bool needsToBeWritable); BitmapData (const Image& image, int x, int y, int w, int h); BitmapData (const Image& image, bool needsToBeWritable); ~BitmapData(); /** Returns a pointer to the start of a line in the image. The co-ordinate you provide here isn't checked, so it's the caller's responsibility to make sure it's not out-of-range. */ inline uint8* getLinePointer (int y) const throw() { return data + y * lineStride; } /** Returns a pointer to a pixel in the image. The co-ordinates you give here are not checked, so it's the caller's responsibility to make sure they're not out-of-range. */ inline uint8* getPixelPointer (int x, int y) const throw() { return data + y * lineStride + x * pixelStride; } /** Returns the colour of a given pixel. For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's repsonsibility to make sure they're within the image's size. */ const Colour getPixelColour (int x, int y) const throw(); /** Sets the colour of a given pixel. For performance reasons, this won't do any bounds-checking on the coordinates, so it's the caller's repsonsibility to make sure they're within the image's size. */ void setPixelColour (int x, int y, const Colour& colour) const throw(); uint8* data; const PixelFormat pixelFormat; int lineStride, pixelStride, width, height; private: JUCE_DECLARE_NON_COPYABLE (BitmapData); }; /** Copies some pixel values to a rectangle of the image. The format of the pixel data must match that of the image itself, and the rectangle supplied must be within the image's bounds. */ void setPixelData (int destX, int destY, int destW, int destH, const uint8* sourcePixelData, int sourceLineStride); /** Copies a section of the image to somewhere else within itself. */ void moveImageSection (int destX, int destY, int sourceX, int sourceY, int width, int height); /** Creates a RectangleList containing rectangles for all non-transparent pixels of the image. @param result the list that will have the area added to it @param alphaThreshold for a semi-transparent image, any pixels whose alpha is above this level will be considered opaque */ void createSolidAreaMask (RectangleList& result, float alphaThreshold = 0.5f) const; /** Returns a NamedValueSet that is attached to the image and which can be used for associating custom values with it. If this is a null image, this will return a null pointer. */ NamedValueSet* getProperties() const; /** Creates a context suitable for drawing onto this image. Don't call this method directly! It's used internally by the Graphics class. */ LowLevelGraphicsContext* createLowLevelContext() const; /** Returns the number of Image objects which are currently referring to the same internal shared image data. @see duplicateIfShared */ int getReferenceCount() const throw() { return image == 0 ? 0 : image->getReferenceCount(); } /** This is a base class for task-specific types of image. Don't use this class directly! It's used internally by the Image class. */ class SharedImage : public ReferenceCountedObject { public: SharedImage (PixelFormat format, int width, int height); ~SharedImage(); virtual LowLevelGraphicsContext* createLowLevelContext() = 0; virtual SharedImage* clone() = 0; virtual ImageType getType() const = 0; static SharedImage* createNativeImage (PixelFormat format, int width, int height, bool clearImage); static SharedImage* createSoftwareImage (PixelFormat format, int width, int height, bool clearImage); const PixelFormat getPixelFormat() const throw() { return format; } int getWidth() const throw() { return width; } int getHeight() const throw() { return height; } int getPixelStride() const throw() { return pixelStride; } int getLineStride() const throw() { return lineStride; } uint8* getPixelData (int x, int y) const throw(); protected: friend class Image; friend class BitmapData; const PixelFormat format; const int width, height; int pixelStride, lineStride; uint8* imageData; NamedValueSet userData; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedImage); }; /** @internal */ SharedImage* getSharedImage() const throw() { return image; } /** @internal */ explicit Image (SharedImage* instance); private: friend class SharedImage; friend class BitmapData; ReferenceCountedObjectPtr image; JUCE_LEAK_DETECTOR (Image); }; #endif // __JUCE_IMAGE_JUCEHEADER__ /*** End of inlined file: juce_Image.h ***/ /*** Start of inlined file: juce_RectangleList.h ***/ #ifndef __JUCE_RECTANGLELIST_JUCEHEADER__ #define __JUCE_RECTANGLELIST_JUCEHEADER__ /** Maintains a set of rectangles as a complex region. This class allows a set of rectangles to be treated as a solid shape, and can add and remove rectangular sections of it, and simplify overlapping or adjacent rectangles. @see Rectangle */ class JUCE_API RectangleList { public: /** Creates an empty RectangleList */ RectangleList() throw(); /** Creates a copy of another list */ RectangleList (const RectangleList& other); /** Creates a list containing just one rectangle. */ RectangleList (const Rectangle& rect); /** Copies this list from another one. */ RectangleList& operator= (const RectangleList& other); /** Destructor. */ ~RectangleList(); /** Returns true if the region is empty. */ bool isEmpty() const throw(); /** Returns the number of rectangles in the list. */ int getNumRectangles() const throw() { return rects.size(); } /** Returns one of the rectangles at a particular index. @returns the rectangle at the index, or an empty rectangle if the index is out-of-range. */ const Rectangle getRectangle (int index) const throw(); /** Removes all rectangles to leave an empty region. */ void clear(); /** Merges a new rectangle into the list. The rectangle being added will first be clipped to remove any parts of it that overlap existing rectangles in the list. */ void add (int x, int y, int width, int height); /** Merges a new rectangle into the list. The rectangle being added will first be clipped to remove any parts of it that overlap existing rectangles in the list, and adjacent rectangles will be merged into it. */ void add (const Rectangle& rect); /** Dumbly adds a rectangle to the list without checking for overlaps. This simply adds the rectangle to the end, it doesn't merge it or remove any overlapping bits. */ void addWithoutMerging (const Rectangle& rect); /** Merges another rectangle list into this one. Any overlaps between the two lists will be clipped, so that the result is the union of both lists. */ void add (const RectangleList& other); /** Removes a rectangular region from the list. Any rectangles in the list which overlap this will be clipped and subdivided if necessary. */ void subtract (const Rectangle& rect); /** Removes all areas in another RectangleList from this one. Any rectangles in the list which overlap this will be clipped and subdivided if necessary. @returns true if the resulting list is non-empty. */ bool subtract (const RectangleList& otherList); /** Removes any areas of the region that lie outside a given rectangle. Any rectangles in the list which overlap this will be clipped and subdivided if necessary. Returns true if the resulting region is not empty, false if it is empty. @see getIntersectionWith */ bool clipTo (const Rectangle& rect); /** Removes any areas of the region that lie outside a given rectangle list. Any rectangles in this object which overlap the specified list will be clipped and subdivided if necessary. Returns true if the resulting region is not empty, false if it is empty. @see getIntersectionWith */ bool clipTo (const RectangleList& other); /** Creates a region which is the result of clipping this one to a given rectangle. Unlike the other clipTo method, this one doesn't affect this object - it puts the resulting region into the list whose reference is passed-in. Returns true if the resulting region is not empty, false if it is empty. @see clipTo */ bool getIntersectionWith (const Rectangle& rect, RectangleList& destRegion) const; /** Swaps the contents of this and another list. This swaps their internal pointers, so is hugely faster than using copy-by-value to swap them. */ void swapWith (RectangleList& otherList) throw(); /** Checks whether the region contains a given point. @returns true if the point lies within one of the rectangles in the list */ bool containsPoint (int x, int y) const throw(); /** Checks whether the region contains the whole of a given rectangle. @returns true all parts of the rectangle passed in lie within the region defined by this object @see intersectsRectangle, containsPoint */ bool containsRectangle (const Rectangle& rectangleToCheck) const; /** Checks whether the region contains any part of a given rectangle. @returns true if any part of the rectangle passed in lies within the region defined by this object @see containsRectangle */ bool intersectsRectangle (const Rectangle& rectangleToCheck) const throw(); /** Checks whether this region intersects any part of another one. @see intersectsRectangle */ bool intersects (const RectangleList& other) const throw(); /** Returns the smallest rectangle that can enclose the whole of this region. */ const Rectangle getBounds() const throw(); /** Optimises the list into a minimum number of constituent rectangles. This will try to combine any adjacent rectangles into larger ones where possible, to simplify lists that might have been fragmented by repeated add/subtract calls. */ void consolidate(); /** Adds an x and y value to all the co-ordinates. */ void offsetAll (int dx, int dy) throw(); /** Creates a Path object to represent this region. */ const Path toPath() const; /** An iterator for accessing all the rectangles in a RectangleList. */ class Iterator { public: Iterator (const RectangleList& list) throw(); ~Iterator(); /** Advances to the next rectangle, and returns true if it's not finished. Call this before using getRectangle() to find the rectangle that was returned. */ bool next() throw(); /** Returns the current rectangle. */ const Rectangle* getRectangle() const throw() { return current; } private: const Rectangle* current; const RectangleList& owner; int index; JUCE_DECLARE_NON_COPYABLE (Iterator); }; private: friend class Iterator; Array > rects; JUCE_LEAK_DETECTOR (RectangleList); }; #endif // __JUCE_RECTANGLELIST_JUCEHEADER__ /*** End of inlined file: juce_RectangleList.h ***/ /*** Start of inlined file: juce_BorderSize.h ***/ #ifndef __JUCE_BORDERSIZE_JUCEHEADER__ #define __JUCE_BORDERSIZE_JUCEHEADER__ /** Specifies a set of gaps to be left around the sides of a rectangle. This is basically the size of the spaces at the top, bottom, left and right of a rectangle. It's used by various component classes to specify borders. @see Rectangle */ class JUCE_API BorderSize { public: /** Creates a null border. All sizes are left as 0. */ BorderSize() throw(); /** Creates a copy of another border. */ BorderSize (const BorderSize& other) throw(); /** Creates a border with the given gaps. */ BorderSize (int topGap, int leftGap, int bottomGap, int rightGap) throw(); /** Creates a border with the given gap on all sides. */ explicit BorderSize (int allGaps) throw(); /** Destructor. */ ~BorderSize() throw(); /** Returns the gap that should be left at the top of the region. */ int getTop() const throw() { return top; } /** Returns the gap that should be left at the top of the region. */ int getLeft() const throw() { return left; } /** Returns the gap that should be left at the top of the region. */ int getBottom() const throw() { return bottom; } /** Returns the gap that should be left at the top of the region. */ int getRight() const throw() { return right; } /** Returns the sum of the top and bottom gaps. */ int getTopAndBottom() const throw() { return top + bottom; } /** Returns the sum of the left and right gaps. */ int getLeftAndRight() const throw() { return left + right; } /** Returns true if this border has no thickness along any edge. */ bool isEmpty() const throw() { return left + right + top + bottom == 0; } /** Changes the top gap. */ void setTop (int newTopGap) throw(); /** Changes the left gap. */ void setLeft (int newLeftGap) throw(); /** Changes the bottom gap. */ void setBottom (int newBottomGap) throw(); /** Changes the right gap. */ void setRight (int newRightGap) throw(); /** Returns a rectangle with these borders removed from it. */ const Rectangle subtractedFrom (const Rectangle& original) const throw(); /** Removes this border from a given rectangle. */ void subtractFrom (Rectangle& rectangle) const throw(); /** Returns a rectangle with these borders added around it. */ const Rectangle addedTo (const Rectangle& original) const throw(); /** Adds this border around a given rectangle. */ void addTo (Rectangle& original) const throw(); bool operator== (const BorderSize& other) const throw(); bool operator!= (const BorderSize& other) const throw(); private: int top, left, bottom, right; JUCE_LEAK_DETECTOR (BorderSize); }; #endif // __JUCE_BORDERSIZE_JUCEHEADER__ /*** End of inlined file: juce_BorderSize.h ***/ /*** Start of inlined file: juce_ModalComponentManager.h ***/ #ifndef __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__ #define __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__ /*** Start of inlined file: juce_DeletedAtShutdown.h ***/ #ifndef __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ #define __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ /** Classes derived from this will be automatically deleted when the application exits. After JUCEApplication::shutdown() has been called, any objects derived from DeletedAtShutdown which are still in existence will be deleted in the reverse order to that in which they were created. So if you've got a singleton and don't want to have to explicitly delete it, just inherit from this and it'll be taken care of. */ class JUCE_API DeletedAtShutdown { protected: /** Creates a DeletedAtShutdown object. */ DeletedAtShutdown(); /** Destructor. It's ok to delete these objects explicitly - it's only the ones left dangling at the end that will be deleted automatically. */ virtual ~DeletedAtShutdown(); public: /** Deletes all extant objects. This shouldn't be used by applications, as it's called automatically in the shutdown code of the JUCEApplication class. */ static void deleteAll(); private: static CriticalSection& getLock(); static Array & getObjects(); JUCE_DECLARE_NON_COPYABLE (DeletedAtShutdown); }; #endif // __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__ /*** End of inlined file: juce_DeletedAtShutdown.h ***/ /** Manages the system's stack of modal components. Normally you'll just use the Component methods to invoke modal states in components, and won't have to deal with this class directly, but this is the singleton object that's used internally to manage the stack. @see Component::enterModalState, Component::exitModalState, Component::isCurrentlyModal, Component::getCurrentlyModalComponent, Component::isCurrentlyBlockedByAnotherModalComponent */ class JUCE_API ModalComponentManager : public AsyncUpdater, public DeletedAtShutdown { public: /** Receives callbacks when a modal component is dismissed. You can register a callback using Component::enterModalState() or ModalComponentManager::attachCallback(). */ class Callback { public: /** */ Callback() {} /** Destructor. */ virtual ~Callback() {} /** Called to indicate that a modal component has been dismissed. You can register a callback using Component::enterModalState() or ModalComponentManager::attachCallback(). The returnValue parameter is the value that was passed to Component::exitModalState() when the component was dismissed. The callback object will be deleted shortly after this method is called. */ virtual void modalStateFinished (int returnValue) = 0; }; /** Returns the number of components currently being shown modally. @see getModalComponent */ int getNumModalComponents() const; /** Returns one of the components being shown modally. An index of 0 is the most recently-shown, topmost component. */ Component* getModalComponent (int index) const; /** Returns true if the specified component is in a modal state. */ bool isModal (Component* component) const; /** Returns true if the specified component is currently the topmost modal component. */ bool isFrontModalComponent (Component* component) const; /** Adds a new callback that will be called when the specified modal component is dismissed. If the component is modal, then when it is dismissed, either by being hidden, or by calling Component::exitModalState(), then the Callback::modalStateFinished() method will be called. Each component can have any number of callbacks associated with it, and this one is added to that list. The object that is passed in will be deleted by the manager when it's no longer needed. If the given component is not currently modal, the callback object is deleted immediately and no action is taken. */ void attachCallback (Component* component, Callback* callback); /** Brings any modal components to the front. */ void bringModalComponentsToFront(); /** Runs the event loop until the currently topmost modal component is dismissed, and returns the exit code for that component. */ int runEventLoopForCurrentComponent(); juce_DeclareSingleton_SingleThreaded_Minimal (ModalComponentManager); protected: /** Creates a ModalComponentManager. You shouldn't ever call the constructor - it's a singleton, so use ModalComponentManager::getInstance() */ ModalComponentManager(); /** Destructor. */ ~ModalComponentManager(); /** @internal */ void handleAsyncUpdate(); private: class ModalItem; class ReturnValueRetriever; friend class Component; friend class OwnedArray ; OwnedArray stack; void startModal (Component* component, Callback* callback); void endModal (Component* component, int returnValue); void endModal (Component* component); JUCE_DECLARE_NON_COPYABLE (ModalComponentManager); }; #endif // __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__ /*** End of inlined file: juce_ModalComponentManager.h ***/ class LookAndFeel; class MouseInputSource; class MouseInputSourceInternal; class ComponentPeer; class MarkerList; class RelativeRectangle; /** The base class for all JUCE user-interface objects. */ class JUCE_API Component : public MouseListener { public: /** Creates a component. To get it to actually appear, you'll also need to: - Either add it to a parent component or use the addToDesktop() method to make it a desktop window - Set its size and position to something sensible - Use setVisible() to make it visible And for it to serve any useful purpose, you'll need to write a subclass of Component or use one of the other types of component from the library. */ Component(); /** Destructor. Note that when a component is deleted, any child components it contains are NOT automatically deleted. It's your responsibilty to manage their lifespan - you may want to use helper methods like deleteAllChildren(), or less haphazard approaches like using ScopedPointers or normal object aggregation to manage them. If the component being deleted is currently the child of another one, then during deletion, it will be removed from its parent, and the parent will receive a childrenChanged() callback. Any ComponentListener objects that have registered with it will also have their ComponentListener::componentBeingDeleted() methods called. */ virtual ~Component(); /** Creates a component, setting its name at the same time. @see getName, setName */ explicit Component (const String& componentName); /** Returns the name of this component. @see setName */ const String& getName() const throw() { return componentName; } /** Sets the name of this component. When the name changes, all registered ComponentListeners will receive a ComponentListener::componentNameChanged() callback. @see getName */ virtual void setName (const String& newName); /** Returns the ID string that was set by setComponentID(). @see setComponentID */ const String& getComponentID() const throw() { return componentID; } /** Sets the component's ID string. You can retrieve the ID using getComponentID(). @see getComponentID */ void setComponentID (const String& newID); /** Makes the component visible or invisible. This method will show or hide the component. Note that components default to being non-visible when first created. Also note that visible components won't be seen unless all their parent components are also visible. This method will call visibilityChanged() and also componentVisibilityChanged() for any component listeners that are interested in this component. @param shouldBeVisible whether to show or hide the component @see isVisible, isShowing, visibilityChanged, ComponentListener::componentVisibilityChanged */ virtual void setVisible (bool shouldBeVisible); /** Tests whether the component is visible or not. this doesn't necessarily tell you whether this comp is actually on the screen because this depends on whether all the parent components are also visible - use isShowing() to find this out. @see isShowing, setVisible */ bool isVisible() const throw() { return flags.visibleFlag; } /** Called when this component's visiblility changes. @see setVisible, isVisible */ virtual void visibilityChanged(); /** Tests whether this component and all its parents are visible. @returns true only if this component and all its parents are visible. @see isVisible */ bool isShowing() const; /** Makes this component appear as a window on the desktop. Note that before calling this, you should make sure that the component's opacity is set correctly using setOpaque(). If the component is non-opaque, the windowing system will try to create a special transparent window for it, which will generally take a lot more CPU to operate (and might not even be possible on some platforms). If the component is inside a parent component at the time this method is called, it will be first be removed from that parent. Likewise if a component on the desktop is subsequently added to another component, it'll be removed from the desktop. @param windowStyleFlags a combination of the flags specified in the ComponentPeer::StyleFlags enum, which define the window's characteristics. @param nativeWindowToAttachTo this allows an OS object to be passed-in as the window in which the juce component should place itself. On Windows, this would be a HWND, a HIViewRef on the Mac. Not necessarily supported on all platforms, and best left as 0 unless you know what you're doing @see removeFromDesktop, isOnDesktop, userTriedToCloseWindow, getPeer, ComponentPeer::setMinimised, ComponentPeer::StyleFlags, ComponentPeer::getStyleFlags, ComponentPeer::setFullScreen */ virtual void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = 0); /** If the component is currently showing on the desktop, this will hide it. You can also use setVisible() to hide a desktop window temporarily, but removeFromDesktop() will free any system resources that are being used up. @see addToDesktop, isOnDesktop */ void removeFromDesktop(); /** Returns true if this component is currently showing on the desktop. @see addToDesktop, removeFromDesktop */ bool isOnDesktop() const throw(); /** Returns the heavyweight window that contains this component. If this component is itself on the desktop, this will return the window object that it is using. Otherwise, it will return the window of its top-level parent component. This may return 0 if there isn't a desktop component. @see addToDesktop, isOnDesktop */ ComponentPeer* getPeer() const; /** For components on the desktop, this is called if the system wants to close the window. This is a signal that either the user or the system wants the window to close. The default implementation of this method will trigger an assertion to warn you that your component should do something about it, but you can override this to ignore the event if you want. */ virtual void userTriedToCloseWindow(); /** Called for a desktop component which has just been minimised or un-minimised. This will only be called for components on the desktop. @see getPeer, ComponentPeer::setMinimised, ComponentPeer::isMinimised */ virtual void minimisationStateChanged (bool isNowMinimised); /** Brings the component to the front of its siblings. If some of the component's siblings have had their 'always-on-top' flag set, then they will still be kept in front of this one (unless of course this one is also 'always-on-top'). @param shouldAlsoGainFocus if true, this will also try to assign keyboard focus to the component (see grabKeyboardFocus() for more details) @see toBack, toBehind, setAlwaysOnTop */ void toFront (bool shouldAlsoGainFocus); /** Changes this component's z-order to be at the back of all its siblings. If the component is set to be 'always-on-top', it will only be moved to the back of the other other 'always-on-top' components. @see toFront, toBehind, setAlwaysOnTop */ void toBack(); /** Changes this component's z-order so that it's just behind another component. @see toFront, toBack */ void toBehind (Component* other); /** Sets whether the component should always be kept at the front of its siblings. @see isAlwaysOnTop */ void setAlwaysOnTop (bool shouldStayOnTop); /** Returns true if this component is set to always stay in front of its siblings. @see setAlwaysOnTop */ bool isAlwaysOnTop() const throw(); /** Returns the x coordinate of the component's left edge. This is a distance in pixels from the left edge of the component's parent. Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to its bounding box. */ inline int getX() const throw() { return bounds.getX(); } /** Returns the y coordinate of the top of this component. This is a distance in pixels from the top edge of the component's parent. Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to its bounding box. */ inline int getY() const throw() { return bounds.getY(); } /** Returns the component's width in pixels. */ inline int getWidth() const throw() { return bounds.getWidth(); } /** Returns the component's height in pixels. */ inline int getHeight() const throw() { return bounds.getHeight(); } /** Returns the x coordinate of the component's right-hand edge. This is a distance in pixels from the left edge of the component's parent. Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to its bounding box. */ int getRight() const throw() { return bounds.getRight(); } /** Returns the component's top-left position as a Point. */ const Point getPosition() const throw() { return bounds.getPosition(); } /** Returns the y coordinate of the bottom edge of this component. This is a distance in pixels from the top edge of the component's parent. Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to its bounding box. */ int getBottom() const throw() { return bounds.getBottom(); } /** Returns this component's bounding box. The rectangle returned is relative to the top-left of the component's parent. Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to its bounding box. */ const Rectangle& getBounds() const throw() { return bounds; } /** Returns the component's bounds, relative to its own origin. This is like getBounds(), but returns the rectangle in local coordinates, In practice, it'll return a rectangle with position (0, 0), and the same size as this component. */ const Rectangle getLocalBounds() const throw(); /** Returns the area of this component's parent which this component covers. The returned area is relative to the parent's coordinate space. If the component has an affine transform specified, then the resulting area will be the smallest rectangle that fully covers the component's transformed bounding box. If this component has no parent, the return value will simply be the same as getBounds(). */ const Rectangle getBoundsInParent() const throw(); /** Returns the region of this component that's not obscured by other, opaque components. The RectangleList that is returned represents the area of this component which isn't covered by opaque child components. If includeSiblings is true, it will also take into account any siblings that may be overlapping the component. */ void getVisibleArea (RectangleList& result, bool includeSiblings) const; /** Returns this component's x coordinate relative the the screen's top-left origin. @see getX, localPointToGlobal */ int getScreenX() const; /** Returns this component's y coordinate relative the the screen's top-left origin. @see getY, localPointToGlobal */ int getScreenY() const; /** Returns the position of this component's top-left corner relative to the screen's top-left. @see getScreenBounds */ const Point getScreenPosition() const; /** Returns the bounds of this component, relative to the screen's top-left. @see getScreenPosition */ const Rectangle getScreenBounds() const; /** Converts a point to be relative to this component's coordinate space. This takes a point relative to a different component, and returns its position relative to this component. If the sourceComponent parameter is null, the source point is assumed to be a global screen coordinate. */ const Point getLocalPoint (const Component* sourceComponent, const Point& pointRelativeToSourceComponent) const; /** Converts a rectangle to be relative to this component's coordinate space. This takes a rectangle that is relative to a different component, and returns its position relative to this component. If the sourceComponent parameter is null, the source rectangle is assumed to be a screen coordinate. If you've used setTransform() to apply one or more transforms to components, then the source rectangle may not actually be rectanglular when converted to the target space, so in that situation this will return the smallest rectangle that fully contains the transformed area. */ const Rectangle getLocalArea (const Component* sourceComponent, const Rectangle& areaRelativeToSourceComponent) const; /** Converts a point relative to this component's top-left into a screen coordinate. @see getLocalPoint, localAreaToGlobal */ const Point localPointToGlobal (const Point& localPoint) const; /** Converts a rectangle from this component's coordinate space to a screen coordinate. If you've used setTransform() to apply one or more transforms to components, then the source rectangle may not actually be rectanglular when converted to the target space, so in that situation this will return the smallest rectangle that fully contains the transformed area. @see getLocalPoint, localPointToGlobal */ const Rectangle localAreaToGlobal (const Rectangle& localArea) const; /** Moves the component to a new position. Changes the component's top-left position (without changing its size). The position is relative to the top-left of the component's parent. If the component actually moves, this method will make a synchronous call to moved(). Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to whatever bounds you set for it. @see setBounds, ComponentListener::componentMovedOrResized */ void setTopLeftPosition (int x, int y); /** Moves the component to a new position. Changes the position of the component's top-right corner (keeping it the same size). The position is relative to the top-left of the component's parent. If the component actually moves, this method will make a synchronous call to moved(). Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to whatever bounds you set for it. */ void setTopRightPosition (int x, int y); /** Changes the size of the component. A synchronous call to resized() will be occur if the size actually changes. Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to whatever bounds you set for it. */ void setSize (int newWidth, int newHeight); /** Changes the component's position and size. The coordinates are relative to the top-left of the component's parent, or relative to the origin of the screen is the component is on the desktop. If this method changes the component's top-left position, it will make a synchronous call to moved(). If it changes the size, it will also make a call to resized(). Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to whatever bounds you set for it. @see setTopLeftPosition, setSize, ComponentListener::componentMovedOrResized */ void setBounds (int x, int y, int width, int height); /** Changes the component's position and size. The coordinates are relative to the top-left of the component's parent, or relative to the origin of the screen is the component is on the desktop. If this method changes the component's top-left position, it will make a synchronous call to moved(). If it changes the size, it will also make a call to resized(). Note that if you've used setTransform() to apply a transform, then the component's bounds will no longer be a direct reflection of the position at which it appears within its parent, as the transform will be applied to whatever bounds you set for it. @see setBounds */ void setBounds (const Rectangle& newBounds); /** Changes the component's position and size. This is similar to the other setBounds() methods, but uses RelativeRectangle::applyToComponent() to set the position, This uses a Component::Positioner to make sure that any dynamic expressions are used in the RelativeRectangle will be automatically re-applied to the component's bounds when the source values change. See RelativeRectangle::applyToComponent() for more details. When using relative expressions, the following symbols are available: - "this.left", "this.right", "this.top", "this.bottom" refer to the position of those edges in this component, so e.g. for a component whose width is always 100, you might set the right edge to the "this.left + 100". - "parent.left", "parent.right", "parent.top", "parent.bottom" refer to the parent component's positions, in its own coordinate space, so "parent.left", "parent.right" are always 0, and "parent.top", "parent.bottom" will actually be the width and height of the parent. So for example to make your component's right-hand edge always 10 pixels away from its parent's right-hand edge, you could set it to "parent.right - 10" - "[id].left", "[id].right", "[id].top", "[id].bottom", where [id] is the identifier of one of this component's siblings. A component's identifier is set with Component::setComponentID(). So for example if you want your component to always be 50 pixels to the right of the one called "xyz", you could set your left edge to be "xyz.right + 50" - The name of a marker that is defined in the parent component. For markers to be used, the parent component must implement its Component::getMarkers() method, and return at least one valid MarkerList. So if you want your component's top edge to be 10 pixels below the marker called "foobar", you'd set it to "foobar + 10". See the Expression class for details about the operators that are supported, but for example if you wanted to make your component remain centred within its parent with a size of 100, 100, you could express it as: @code myComp.setBounds (RelativeBounds ("parent.right / 2 - 50, parent.bottom / 2 - 50, this.left + 100, this.top + 100")); @endcode ..or an alternative way to achieve the same thing: @code myComp.setBounds (RelativeBounds ("this.right - 100, this.bottom - 100, parent.right / 2 + 50, parent.bottom / 2 + 50")); @endcode Or if you wanted a 100x100 component whose top edge is lined up to a marker called "topMarker" and which is positioned 50 pixels to the right of another component called "otherComp", you could write: @code myComp.setBounds (RelativeBounds ("otherComp.right + 50, topMarker, this.left + 100, this.top + 100")); @endcode Be careful not to make your coordinate expressions recursive, though, or exceptions and assertions will be thrown! @see setBounds, RelativeRectangle::applyToComponent(), Expression */ void setBounds (const RelativeRectangle& newBounds); /** Changes the component's position and size in terms of fractions of its parent's size. The values are factors of the parent's size, so for example setBoundsRelative (0.2f, 0.2f, 0.5f, 0.5f) would give it half the width and height of the parent, with its top-left position 20% of the way across and down the parent. @see setBounds */ void setBoundsRelative (float proportionalX, float proportionalY, float proportionalWidth, float proportionalHeight); /** Changes the component's position and size based on the amount of space to leave around it. This will position the component within its parent, leaving the specified number of pixels around each edge. @see setBounds */ void setBoundsInset (const BorderSize& borders); /** Positions the component within a given rectangle, keeping its proportions unchanged. If onlyReduceInSize is false, the component will be resized to fill as much of the rectangle as possible without changing its aspect ratio (the component's current size is used to determine its aspect ratio, so a zero-size component won't work here). If onlyReduceInSize is true, it will only be resized if it's too big to fit inside the rectangle. It will then be positioned within the rectangle according to the justification flags specified. @see setBounds */ void setBoundsToFit (int x, int y, int width, int height, const Justification& justification, bool onlyReduceInSize); /** Changes the position of the component's centre. Leaves the component's size unchanged, but sets the position of its centre relative to its parent's top-left. @see setBounds */ void setCentrePosition (int x, int y); /** Changes the position of the component's centre. Leaves the position unchanged, but positions its centre relative to its parent's size. E.g. setCentreRelative (0.5f, 0.5f) would place it centrally in its parent. */ void setCentreRelative (float x, float y); /** Changes the component's size and centres it within its parent. After changing the size, the component will be moved so that it's centred within its parent. If the component is on the desktop (or has no parent component), then it'll be centred within the main monitor area. */ void centreWithSize (int width, int height); /** Sets a transform matrix to be applied to this component. If you set a transform for a component, the component's position will be warped by it, relative to the component's parent's top-left origin. This means that the values you pass into setBounds() will no longer reflect the actual area within the parent that the component covers, as the bounds will be transformed and the component will probably end up actually appearing somewhere else within its parent. When using transforms you need to be extremely careful when converting coordinates between the coordinate spaces of different components or the screen - you should always use getLocalPoint(), getLocalArea(), etc to do this, and never just manually add a component's position to a point in order to convert it between different components (but I'm sure you would never have done that anyway...). Currently, transforms are not supported for desktop windows, so the transform will be ignored if you put a component on the desktop. To remove a component's transform, simply pass AffineTransform::identity as the parameter to this method. */ void setTransform (const AffineTransform& transform); /** Returns the transform that is currently being applied to this component. For more details about transforms, see setTransform(). @see setTransform */ const AffineTransform getTransform() const; /** Returns true if a non-identity transform is being applied to this component. For more details about transforms, see setTransform(). @see setTransform */ bool isTransformed() const throw(); /** Returns a proportion of the component's width. This is a handy equivalent of (getWidth() * proportion). */ int proportionOfWidth (float proportion) const throw(); /** Returns a proportion of the component's height. This is a handy equivalent of (getHeight() * proportion). */ int proportionOfHeight (float proportion) const throw(); /** Returns the width of the component's parent. If the component has no parent (i.e. if it's on the desktop), this will return the width of the screen. */ int getParentWidth() const throw(); /** Returns the height of the component's parent. If the component has no parent (i.e. if it's on the desktop), this will return the height of the screen. */ int getParentHeight() const throw(); /** Returns the screen coordinates of the monitor that contains this component. If there's only one monitor, this will return its size - if there are multiple monitors, it will return the area of the monitor that contains the component's centre. */ const Rectangle getParentMonitorArea() const; /** Returns the number of child components that this component contains. @see getChildComponent, getIndexOfChildComponent */ int getNumChildComponents() const throw(); /** Returns one of this component's child components, by it index. The component with index 0 is at the back of the z-order, the one at the front will have index (getNumChildComponents() - 1). If the index is out-of-range, this will return a null pointer. @see getNumChildComponents, getIndexOfChildComponent */ Component* getChildComponent (int index) const throw(); /** Returns the index of this component in the list of child components. A value of 0 means it is first in the list (i.e. behind all other components). Higher values are further towards the front. Returns -1 if the component passed-in is not a child of this component. @see getNumChildComponents, getChildComponent, addChildComponent, toFront, toBack, toBehind */ int getIndexOfChildComponent (const Component* child) const throw(); /** Adds a child component to this one. Adding a child component does not mean that the component will own or delete the child - it's your responsibility to delete the component. Note that it's safe to delete a component without first removing it from its parent - doing so will automatically remove it and send out the appropriate notifications before the deletion completes. If the child is already a child of this component, then no action will be taken, and its z-order will be left unchanged. @param child the new component to add. If the component passed-in is already the child of another component, it'll first be removed from it current parent. @param zOrder The index in the child-list at which this component should be inserted. A value of -1 will insert it in front of the others, 0 is the back. @see removeChildComponent, addAndMakeVisible, getChild, ComponentListener::componentChildrenChanged */ void addChildComponent (Component* child, int zOrder = -1); /** Adds a child component to this one, and also makes the child visible if it isn't. Quite a useful function, this is just the same as calling setVisible (true) on the child and then addChildComponent(). See addChildComponent() for more details. */ void addAndMakeVisible (Component* child, int zOrder = -1); /** Removes one of this component's child-components. If the child passed-in isn't actually a child of this component (either because it's invalid or is the child of a different parent), then no action is taken. Note that removing a child will not delete it! But it's ok to delete a component without first removing it - doing so will automatically remove it and send out the appropriate notifications before the deletion completes. @see addChildComponent, ComponentListener::componentChildrenChanged */ void removeChildComponent (Component* childToRemove); /** Removes one of this component's child-components by index. This will return a pointer to the component that was removed, or null if the index was out-of-range. Note that removing a child will not delete it! But it's ok to delete a component without first removing it - doing so will automatically remove it and send out the appropriate notifications before the deletion completes. @see addChildComponent, ComponentListener::componentChildrenChanged */ Component* removeChildComponent (int childIndexToRemove); /** Removes all this component's children. Note that this won't delete them! To do that, use deleteAllChildren() instead. */ void removeAllChildren(); /** Removes all this component's children, and deletes them. @see removeAllChildren */ void deleteAllChildren(); /** Returns the component which this component is inside. If this is the highest-level component or hasn't yet been added to a parent, this will return null. */ Component* getParentComponent() const throw() { return parentComponent; } /** Searches the parent components for a component of a specified class. For example findParentComponentOfClass \() would return the first parent component that can be dynamically cast to a MyComp, or will return 0 if none of the parents are suitable. N.B. The dummy parameter is needed to work around a VC6 compiler bug. */ template TargetClass* findParentComponentOfClass (TargetClass* const dummyParameter = 0) const { (void) dummyParameter; Component* p = parentComponent; while (p != 0) { TargetClass* target = dynamic_cast (p); if (target != 0) return target; p = p->parentComponent; } return 0; } /** Returns the highest-level component which contains this one or its parents. This will search upwards in the parent-hierarchy from this component, until it finds the highest one that doesn't have a parent (i.e. is on the desktop or not yet added to a parent), and will return that. */ Component* getTopLevelComponent() const throw(); /** Checks whether a component is anywhere inside this component or its children. This will recursively check through this component's children to see if the given component is anywhere inside. */ bool isParentOf (const Component* possibleChild) const throw(); /** Called to indicate that the component's parents have changed. When a component is added or removed from its parent, this method will be called on all of its children (recursively - so all children of its children will also be called as well). Subclasses can override this if they need to react to this in some way. @see getParentComponent, isShowing, ComponentListener::componentParentHierarchyChanged */ virtual void parentHierarchyChanged(); /** Subclasses can use this callback to be told when children are added or removed. @see parentHierarchyChanged */ virtual void childrenChanged(); /** Tests whether a given point inside the component. Overriding this method allows you to create components which only intercept mouse-clicks within a user-defined area. This is called to find out whether a particular x, y coordinate is considered to be inside the component or not, and is used by methods such as contains() and getComponentAt() to work out which component the mouse is clicked on. Components with custom shapes will probably want to override it to perform some more complex hit-testing. The default implementation of this method returns either true or false, depending on the value that was set by calling setInterceptsMouseClicks() (true is the default return value). Note that the hit-test region is not related to the opacity with which areas of a component are painted. Applications should never call hitTest() directly - instead use the contains() method, because this will also test for occlusion by the component's parent. Note that for components on the desktop, this method will be ignored, because it's not always possible to implement this behaviour on all platforms. @param x the x coordinate to test, relative to the left hand edge of this component. This value is guaranteed to be greater than or equal to zero, and less than the component's width @param y the y coordinate to test, relative to the top edge of this component. This value is guaranteed to be greater than or equal to zero, and less than the component's height @returns true if the click is considered to be inside the component @see setInterceptsMouseClicks, contains */ virtual bool hitTest (int x, int y); /** Changes the default return value for the hitTest() method. Setting this to false is an easy way to make a component pass its mouse-clicks through to the components behind it. When a component is created, the default setting for this is true. @param allowClicksOnThisComponent if true, hitTest() will always return true; if false, it will return false (or true for child components if allowClicksOnChildComponents is true) @param allowClicksOnChildComponents if this is true and allowClicksOnThisComponent is false, then child components can be clicked on as normal but clicks on this component pass straight through; if this is false and allowClicksOnThisComponent is false, then neither this component nor any child components can be clicked on @see hitTest, getInterceptsMouseClicks */ void setInterceptsMouseClicks (bool allowClicksOnThisComponent, bool allowClicksOnChildComponents) throw(); /** Retrieves the current state of the mouse-click interception flags. On return, the two parameters are set to the state used in the last call to setInterceptsMouseClicks(). @see setInterceptsMouseClicks */ void getInterceptsMouseClicks (bool& allowsClicksOnThisComponent, bool& allowsClicksOnChildComponents) const throw(); /** Returns true if a given point lies within this component or one of its children. Never override this method! Use hitTest to create custom hit regions. @param localPoint the coordinate to test, relative to this component's top-left. @returns true if the point is within the component's hit-test area, but only if that part of the component isn't clipped by its parent component. Note that this won't take into account any overlapping sibling components which might be in the way - for that, see reallyContains() @see hitTest, reallyContains, getComponentAt */ bool contains (const Point& localPoint); /** Returns true if a given point lies in this component, taking any overlapping siblings into account. @param localPoint the coordinate to test, relative to this component's top-left. @param returnTrueIfWithinAChild if the point actually lies within a child of this component, this determines whether that is counted as a hit. @see contains, getComponentAt */ bool reallyContains (const Point& localPoint, bool returnTrueIfWithinAChild); /** Returns the component at a certain point within this one. @param x the x coordinate to test, relative to this component's left edge. @param y the y coordinate to test, relative to this component's top edge. @returns the component that is at this position - which may be 0, this component, or one of its children. Note that overlapping siblings that might actually be in the way are not taken into account by this method - to account for these, instead call getComponentAt on the top-level parent of this component. @see hitTest, contains, reallyContains */ Component* getComponentAt (int x, int y); /** Returns the component at a certain point within this one. @param position the coordinate to test, relative to this component's top-left. @returns the component that is at this position - which may be 0, this component, or one of its children. Note that overlapping siblings that might actually be in the way are not taken into account by this method - to account for these, instead call getComponentAt on the top-level parent of this component. @see hitTest, contains, reallyContains */ Component* getComponentAt (const Point& position); /** Marks the whole component as needing to be redrawn. Calling this will not do any repainting immediately, but will mark the component as 'dirty'. At some point in the near future the operating system will send a paint message, which will redraw all the dirty regions of all components. There's no guarantee about how soon after calling repaint() the redraw will actually happen, and other queued events may be delivered before a redraw is done. If the setBufferedToImage() method has been used to cause this component to use a buffer, the repaint() call will invalidate the component's buffer. To redraw just a subsection of the component rather than the whole thing, use the repaint (int, int, int, int) method. @see paint */ void repaint(); /** Marks a subsection of this component as needing to be redrawn. Calling this will not do any repainting immediately, but will mark the given region of the component as 'dirty'. At some point in the near future the operating system will send a paint message, which will redraw all the dirty regions of all components. There's no guarantee about how soon after calling repaint() the redraw will actually happen, and other queued events may be delivered before a redraw is done. The region that is passed in will be clipped to keep it within the bounds of this component. @see repaint() */ void repaint (int x, int y, int width, int height); /** Marks a subsection of this component as needing to be redrawn. Calling this will not do any repainting immediately, but will mark the given region of the component as 'dirty'. At some point in the near future the operating system will send a paint message, which will redraw all the dirty regions of all components. There's no guarantee about how soon after calling repaint() the redraw will actually happen, and other queued events may be delivered before a redraw is done. The region that is passed in will be clipped to keep it within the bounds of this component. @see repaint() */ void repaint (const Rectangle& area); /** Makes the component use an internal buffer to optimise its redrawing. Setting this flag to true will cause the component to allocate an internal buffer into which it paints itself, so that when asked to redraw itself, it can use this buffer rather than actually calling the paint() method. The buffer is kept until the repaint() method is called directly on this component (or until it is resized), when the image is invalidated and then redrawn the next time the component is painted. Note that only the drawing that happens within the component's paint() method is drawn into the buffer, it's child components are not buffered, and nor is the paintOverChildren() method. @see repaint, paint, createComponentSnapshot */ void setBufferedToImage (bool shouldBeBuffered); /** Generates a snapshot of part of this component. This will return a new Image, the size of the rectangle specified, containing a snapshot of the specified area of the component and all its children. The image may or may not have an alpha-channel, depending on whether the image is opaque or not. If the clipImageToComponentBounds parameter is true and the area is greater than the size of the component, it'll be clipped. If clipImageToComponentBounds is false then parts of the component beyond its bounds can be drawn. @see paintEntireComponent */ const Image createComponentSnapshot (const Rectangle& areaToGrab, bool clipImageToComponentBounds = true); /** Draws this component and all its subcomponents onto the specified graphics context. You should very rarely have to use this method, it's simply there in case you need to draw a component with a custom graphics context for some reason, e.g. for creating a snapshot of the component. It calls paint(), paintOverChildren() and recursively calls paintEntireComponent() on its children in order to render the entire tree. The graphics context may be left in an undefined state after this method returns, so you may need to reset it if you're going to use it again. If ignoreAlphaLevel is false, then the component will be drawn with the opacity level specified by getAlpha(); if ignoreAlphaLevel is true, then this will be ignored and an alpha of 1.0 will be used. */ void paintEntireComponent (Graphics& context, bool ignoreAlphaLevel); /** This allows you to indicate that this component doesn't require its graphics context to be clipped when it is being painted. Most people will never need to use this setting, but in situations where you have a very large number of simple components being rendered, and where they are guaranteed never to do any drawing beyond their own boundaries, setting this to true will reduce the overhead involved in clipping the graphics context that gets passed to the component's paint() callback. If you enable this mode, you'll need to make sure your paint method doesn't call anything like Graphics::fillAll(), and doesn't draw beyond the component's bounds, because that'll produce artifacts. Your component also can't have any child components that may be placed beyond its bounds. */ void setPaintingIsUnclipped (bool shouldPaintWithoutClipping) throw(); /** Adds an effect filter to alter the component's appearance. When a component has an effect filter set, then this is applied to the results of its paint() method. There are a few preset effects, such as a drop-shadow or glow, but they can be user-defined as well. The effect that is passed in will not be deleted by the component - the caller must take care of deleting it. To remove an effect from a component, pass a null pointer in as the parameter. @see ImageEffectFilter, DropShadowEffect, GlowEffect */ void setComponentEffect (ImageEffectFilter* newEffect); /** Returns the current component effect. @see setComponentEffect */ ImageEffectFilter* getComponentEffect() const throw() { return effect; } /** Finds the appropriate look-and-feel to use for this component. If the component hasn't had a look-and-feel explicitly set, this will return the parent's look-and-feel, or just the default one if there's no parent. @see setLookAndFeel, lookAndFeelChanged */ LookAndFeel& getLookAndFeel() const throw(); /** Sets the look and feel to use for this component. This will also change the look and feel for any child components that haven't had their look set explicitly. The object passed in will not be deleted by the component, so it's the caller's responsibility to manage it. It may be used at any time until this component has been deleted. Calling this method will also invoke the sendLookAndFeelChange() method. @see getLookAndFeel, lookAndFeelChanged */ void setLookAndFeel (LookAndFeel* newLookAndFeel); /** Called to let the component react to a change in the look-and-feel setting. When the look-and-feel is changed for a component, this will be called in all its child components, recursively. It can also be triggered manually by the sendLookAndFeelChange() method, in case an application uses a LookAndFeel class that might have changed internally. @see sendLookAndFeelChange, getLookAndFeel */ virtual void lookAndFeelChanged(); /** Calls the lookAndFeelChanged() method in this component and all its children. This will recurse through the children and their children, calling lookAndFeelChanged() on them all. @see lookAndFeelChanged */ void sendLookAndFeelChange(); /** Indicates whether any parts of the component might be transparent. Components that always paint all of their contents with solid colour and thus completely cover any components behind them should use this method to tell the repaint system that they are opaque. This information is used to optimise drawing, because it means that objects underneath opaque windows don't need to be painted. By default, components are considered transparent, unless this is used to make it otherwise. @see isOpaque, getVisibleArea */ void setOpaque (bool shouldBeOpaque); /** Returns true if no parts of this component are transparent. @returns the value that was set by setOpaque, (the default being false) @see setOpaque */ bool isOpaque() const throw(); /** Indicates whether the component should be brought to the front when clicked. Setting this flag to true will cause the component to be brought to the front when the mouse is clicked somewhere inside it or its child components. Note that a top-level desktop window might still be brought to the front by the operating system when it's clicked, depending on how the OS works. By default this is set to false. @see setMouseClickGrabsKeyboardFocus */ void setBroughtToFrontOnMouseClick (bool shouldBeBroughtToFront) throw(); /** Indicates whether the component should be brought to the front when clicked-on. @see setBroughtToFrontOnMouseClick */ bool isBroughtToFrontOnMouseClick() const throw(); // Keyboard focus methods /** Sets a flag to indicate whether this component needs keyboard focus or not. By default components aren't actually interested in gaining the focus, but this method can be used to turn this on. See the grabKeyboardFocus() method for details about the way a component is chosen to receive the focus. @see grabKeyboardFocus, getWantsKeyboardFocus */ void setWantsKeyboardFocus (bool wantsFocus) throw(); /** Returns true if the component is interested in getting keyboard focus. This returns the flag set by setWantsKeyboardFocus(). The default setting is false. @see setWantsKeyboardFocus */ bool getWantsKeyboardFocus() const throw(); /** Chooses whether a click on this component automatically grabs the focus. By default this is set to true, but you might want a component which can be focused, but where you don't want the user to be able to affect it directly by clicking. */ void setMouseClickGrabsKeyboardFocus (bool shouldGrabFocus); /** Returns the last value set with setMouseClickGrabsKeyboardFocus(). See setMouseClickGrabsKeyboardFocus() for more info. */ bool getMouseClickGrabsKeyboardFocus() const throw(); /** Tries to give keyboard focus to this component. When the user clicks on a component or its grabKeyboardFocus() method is called, the following procedure is used to work out which component should get it: - if the component that was clicked on actually wants focus (as indicated by calling getWantsKeyboardFocus), it gets it. - if the component itself doesn't want focus, it will try to pass it on to whichever of its children is the default component, as determined by KeyboardFocusTraverser::getDefaultComponent() - if none of its children want focus at all, it will pass it up to its parent instead, unless it's a top-level component without a parent, in which case it just takes the focus itself. @see setWantsKeyboardFocus, getWantsKeyboardFocus, hasKeyboardFocus, getCurrentlyFocusedComponent, focusGained, focusLost, keyPressed, keyStateChanged */ void grabKeyboardFocus(); /** Returns true if this component currently has the keyboard focus. @param trueIfChildIsFocused if this is true, then the method returns true if either this component or any of its children (recursively) have the focus. If false, the method only returns true if this component has the focus. @see grabKeyboardFocus, setWantsKeyboardFocus, getCurrentlyFocusedComponent, focusGained, focusLost */ bool hasKeyboardFocus (bool trueIfChildIsFocused) const; /** Returns the component that currently has the keyboard focus. @returns the focused component, or null if nothing is focused. */ static Component* JUCE_CALLTYPE getCurrentlyFocusedComponent() throw(); /** Tries to move the keyboard focus to one of this component's siblings. This will try to move focus to either the next or previous component. (This is the method that is used when shifting focus by pressing the tab key). Components for which getWantsKeyboardFocus() returns false are not looked at. @param moveToNext if true, the focus will move forwards; if false, it will move backwards @see grabKeyboardFocus, setFocusContainer, setWantsKeyboardFocus */ void moveKeyboardFocusToSibling (bool moveToNext); /** Creates a KeyboardFocusTraverser object to use to determine the logic by which focus should be passed from this component. The default implementation of this method will return a default KeyboardFocusTraverser if this component is a focus container (as determined by the setFocusContainer() method). If the component isn't a focus container, then it will recursively ask its parents for a KeyboardFocusTraverser. If you overrride this to return a custom KeyboardFocusTraverser, then this component and all its sub-components will use the new object to make their focusing decisions. The method should return a new object, which the caller is required to delete when no longer needed. */ virtual KeyboardFocusTraverser* createFocusTraverser(); /** Returns the focus order of this component, if one has been specified. By default components don't have a focus order - in that case, this will return 0. Lower numbers indicate that the component will be earlier in the focus traversal order. To change the order, call setExplicitFocusOrder(). The focus order may be used by the KeyboardFocusTraverser class as part of its algorithm for deciding the order in which components should be traversed. See the KeyboardFocusTraverser class for more details on this. @see moveKeyboardFocusToSibling, createFocusTraverser, KeyboardFocusTraverser */ int getExplicitFocusOrder() const; /** Sets the index used in determining the order in which focusable components should be traversed. A value of 0 or less is taken to mean that no explicit order is wanted, and that traversal should use other factors, like the component's position. @see getExplicitFocusOrder, moveKeyboardFocusToSibling */ void setExplicitFocusOrder (int newFocusOrderIndex); /** Indicates whether this component is a parent for components that can have their focus traversed. This flag is used by the default implementation of the createFocusTraverser() method, which uses the flag to find the first parent component (of the currently focused one) which wants to be a focus container. So using this method to set the flag to 'true' causes this component to act as the top level within which focus is passed around. @see isFocusContainer, createFocusTraverser, moveKeyboardFocusToSibling */ void setFocusContainer (bool shouldBeFocusContainer) throw(); /** Returns true if this component has been marked as a focus container. See setFocusContainer() for more details. @see setFocusContainer, moveKeyboardFocusToSibling, createFocusTraverser */ bool isFocusContainer() const throw(); /** Returns true if the component (and all its parents) are enabled. Components are enabled by default, and can be disabled with setEnabled(). Exactly what difference this makes to the component depends on the type. E.g. buttons and sliders will choose to draw themselves differently, etc. Note that if one of this component's parents is disabled, this will always return false, even if this component itself is enabled. @see setEnabled, enablementChanged */ bool isEnabled() const throw(); /** Enables or disables this component. Disabling a component will also cause all of its child components to become disabled. Similarly, enabling a component which is inside a disabled parent component won't make any difference until the parent is re-enabled. @see isEnabled, enablementChanged */ void setEnabled (bool shouldBeEnabled); /** Callback to indicate that this component has been enabled or disabled. This can be triggered by one of the component's parent components being enabled or disabled, as well as changes to the component itself. The default implementation of this method does nothing; your class may wish to repaint itself or something when this happens. @see setEnabled, isEnabled */ virtual void enablementChanged(); /** Changes the transparency of this component. When painted, the entire component and all its children will be rendered with this as the overall opacity level, where 0 is completely invisible, and 1.0 is fully opaque (i.e. normal). @see getAlpha */ void setAlpha (float newAlpha); /** Returns the component's current transparancy level. See setAlpha() for more details. */ float getAlpha() const; /** Changes the mouse cursor shape to use when the mouse is over this component. Note that the cursor set by this method can be overridden by the getMouseCursor method. @see MouseCursor */ void setMouseCursor (const MouseCursor& cursorType); /** Returns the mouse cursor shape to use when the mouse is over this component. The default implementation will return the cursor that was set by setCursor() but can be overridden for more specialised purposes, e.g. returning different cursors depending on the mouse position. @see MouseCursor */ virtual const MouseCursor getMouseCursor(); /** Forces the current mouse cursor to be updated. If you're overriding the getMouseCursor() method to control which cursor is displayed, then this will only be checked each time the user moves the mouse. So if you want to force the system to check that the cursor being displayed is up-to-date (even if the mouse is just sitting there), call this method. (If you're changing the cursor using setMouseCursor(), you don't need to bother calling this). */ void updateMouseCursor() const; /** Components can override this method to draw their content. The paint() method gets called when a region of a component needs redrawing, either because the component's repaint() method has been called, or because something has happened on the screen that means a section of a window needs to be redrawn. Any child components will draw themselves over whatever this method draws. If you need to paint over the top of your child components, you can also implement the paintOverChildren() method to do this. If you want to cause a component to redraw itself, this is done asynchronously - calling the repaint() method marks a region of the component as "dirty", and the paint() method will automatically be called sometime later, by the message thread, to paint any bits that need refreshing. In Juce (and almost all modern UI frameworks), you never redraw something synchronously. You should never need to call this method directly - to take a snapshot of the component you could use createComponentSnapshot() or paintEntireComponent(). @param g the graphics context that must be used to do the drawing operations. @see repaint, paintOverChildren, Graphics */ virtual void paint (Graphics& g); /** Components can override this method to draw over the top of their children. For most drawing operations, it's better to use the normal paint() method, but if you need to overlay something on top of the children, this can be used. @see paint, Graphics */ virtual void paintOverChildren (Graphics& g); /** Called when the mouse moves inside this component. If the mouse button isn't pressed and the mouse moves over a component, this will be called to let the component react to this. A component will always get a mouseEnter callback before a mouseMove. @param e details about the position and status of the mouse event @see mouseEnter, mouseExit, mouseDrag, contains */ virtual void mouseMove (const MouseEvent& e); /** Called when the mouse first enters this component. If the mouse button isn't pressed and the mouse moves into a component, this will be called to let the component react to this. When the mouse button is pressed and held down while being moved in or out of a component, no mouseEnter or mouseExit callbacks are made - only mouseDrag messages are sent to the component that the mouse was originally clicked on, until the button is released. If you're writing a component that needs to repaint itself when the mouse enters and exits, it might be quicker to use the setRepaintsOnMouseActivity() method. @param e details about the position and status of the mouse event @see mouseExit, mouseDrag, mouseMove, contains */ virtual void mouseEnter (const MouseEvent& e); /** Called when the mouse moves out of this component. This will be called when the mouse moves off the edge of this component. If the mouse button was pressed, and it was then dragged off the edge of the component and released, then this callback will happen when the button is released, after the mouseUp callback. If you're writing a component that needs to repaint itself when the mouse enters and exits, it might be quicker to use the setRepaintsOnMouseActivity() method. @param e details about the position and status of the mouse event @see mouseEnter, mouseDrag, mouseMove, contains */ virtual void mouseExit (const MouseEvent& e); /** Called when a mouse button is pressed while it's over this component. The MouseEvent object passed in contains lots of methods for finding out which button was pressed, as well as which modifier keys (e.g. shift, ctrl) were held down at the time. Once a button is held down, the mouseDrag method will be called when the mouse moves, until the button is released. @param e details about the position and status of the mouse event @see mouseUp, mouseDrag, mouseDoubleClick, contains */ virtual void mouseDown (const MouseEvent& e); /** Called when the mouse is moved while a button is held down. When a mouse button is pressed inside a component, that component receives mouseDrag callbacks each time the mouse moves, even if the mouse strays outside the component's bounds. If you want to be able to drag things off the edge of a component and have the component scroll when you get to the edges, the beginDragAutoRepeat() method might be useful. @param e details about the position and status of the mouse event @see mouseDown, mouseUp, mouseMove, contains, beginDragAutoRepeat */ virtual void mouseDrag (const MouseEvent& e); /** Called when a mouse button is released. A mouseUp callback is sent to the component in which a button was pressed even if the mouse is actually over a different component when the button is released. The MouseEvent object passed in contains lots of methods for finding out which buttons were down just before they were released. @param e details about the position and status of the mouse event @see mouseDown, mouseDrag, mouseDoubleClick, contains */ virtual void mouseUp (const MouseEvent& e); /** Called when a mouse button has been double-clicked in this component. The MouseEvent object passed in contains lots of methods for finding out which button was pressed, as well as which modifier keys (e.g. shift, ctrl) were held down at the time. For altering the time limit used to detect double-clicks, see MouseEvent::setDoubleClickTimeout. @param e details about the position and status of the mouse event @see mouseDown, mouseUp, MouseEvent::setDoubleClickTimeout, MouseEvent::getDoubleClickTimeout */ virtual void mouseDoubleClick (const MouseEvent& e); /** Called when the mouse-wheel is moved. This callback is sent to the component that the mouse is over when the wheel is moved. If not overridden, the component will forward this message to its parent, so that parent components can collect mouse-wheel messages that happen to child components which aren't interested in them. @param e details about the position and status of the mouse event @param wheelIncrementX the speed and direction of the horizontal scroll-wheel - a positive value means the wheel has been pushed to the right, negative means it was pushed to the left @param wheelIncrementY the speed and direction of the vertical scroll-wheel - a positive value means the wheel has been pushed upwards, negative means it was pushed downwards */ virtual void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); /** Ensures that a non-stop stream of mouse-drag events will be sent during the current mouse-drag operation. This allows you to make sure that mouseDrag() events are sent continuously, even when the mouse isn't moving. This can be useful for things like auto-scrolling components when the mouse is near an edge. Call this method during a mouseDown() or mouseDrag() callback, specifying the minimum interval between consecutive mouse drag callbacks. The callbacks will continue until the mouse is released, and then the interval will be reset, so you need to make sure it's called every time you begin a drag event. Passing an interval of 0 or less will cancel the auto-repeat. @see mouseDrag, Desktop::beginDragAutoRepeat */ static void beginDragAutoRepeat (int millisecondsBetweenCallbacks); /** Causes automatic repaints when the mouse enters or exits this component. If turned on, then when the mouse enters/exits, or when the button is pressed/released on the component, it will trigger a repaint. This is handy for things like buttons that need to draw themselves differently when the mouse moves over them, and it avoids having to override all the different mouse callbacks and call repaint(). @see mouseEnter, mouseExit, mouseDown, mouseUp */ void setRepaintsOnMouseActivity (bool shouldRepaint) throw(); /** Registers a listener to be told when mouse events occur in this component. If you need to get informed about mouse events in a component but can't or don't want to override its methods, you can attach any number of listeners to the component, and these will get told about the events in addition to the component's own callbacks being called. Note that a MouseListener can also be attached to more than one component. @param newListener the listener to register @param wantsEventsForAllNestedChildComponents if true, the listener will receive callbacks for events that happen to any child component within this component, including deeply-nested child components. If false, it will only be told about events that this component handles. @see MouseListener, removeMouseListener */ void addMouseListener (MouseListener* newListener, bool wantsEventsForAllNestedChildComponents); /** Deregisters a mouse listener. @see addMouseListener, MouseListener */ void removeMouseListener (MouseListener* listenerToRemove); /** Adds a listener that wants to hear about keypresses that this component receives. The listeners that are registered with a component are called by its keyPressed() or keyStateChanged() methods (assuming these haven't been overridden to do something else). If you add an object as a key listener, be careful to remove it when the object is deleted, or the component will be left with a dangling pointer. @see keyPressed, keyStateChanged, removeKeyListener */ void addKeyListener (KeyListener* newListener); /** Removes a previously-registered key listener. @see addKeyListener */ void removeKeyListener (KeyListener* listenerToRemove); /** Called when a key is pressed. When a key is pressed, the component that has the keyboard focus will have this method called. Remember that a component will only be given the focus if its setWantsKeyboardFocus() method has been used to enable this. If your implementation returns true, the event will be consumed and not passed on to any other listeners. If it returns false, the key will be passed to any KeyListeners that have been registered with this component. As soon as one of these returns true, the process will stop, but if they all return false, the event will be passed upwards to this component's parent, and so on. The default implementation of this method does nothing and returns false. @see keyStateChanged, getCurrentlyFocusedComponent, addKeyListener */ virtual bool keyPressed (const KeyPress& key); /** Called when a key is pressed or released. Whenever a key on the keyboard is pressed or released (including modifier keys like shift and ctrl), this method will be called on the component that currently has the keyboard focus. Remember that a component will only be given the focus if its setWantsKeyboardFocus() method has been used to enable this. If your implementation returns true, the event will be consumed and not passed on to any other listeners. If it returns false, then any KeyListeners that have been registered with this component will have their keyStateChanged methods called. As soon as one of these returns true, the process will stop, but if they all return false, the event will be passed upwards to this component's parent, and so on. The default implementation of this method does nothing and returns false. To find out which keys are up or down at any time, see the KeyPress::isKeyCurrentlyDown() method. @param isKeyDown true if a key has been pressed; false if it has been released @see keyPressed, KeyPress, getCurrentlyFocusedComponent, addKeyListener */ virtual bool keyStateChanged (bool isKeyDown); /** Called when a modifier key is pressed or released. Whenever the shift, control, alt or command keys are pressed or released, this method will be called on the component that currently has the keyboard focus. Remember that a component will only be given the focus if its setWantsKeyboardFocus() method has been used to enable this. The default implementation of this method actually calls its parent's modifierKeysChanged method, so that focused components which aren't interested in this will give their parents a chance to act on the event instead. @see keyStateChanged, ModifierKeys */ virtual void modifierKeysChanged (const ModifierKeys& modifiers); /** Enumeration used by the focusChanged() and focusLost() methods. */ enum FocusChangeType { focusChangedByMouseClick, /**< Means that the user clicked the mouse to change focus. */ focusChangedByTabKey, /**< Means that the user pressed the tab key to move the focus. */ focusChangedDirectly /**< Means that the focus was changed by a call to grabKeyboardFocus(). */ }; /** Called to indicate that this component has just acquired the keyboard focus. @see focusLost, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus */ virtual void focusGained (FocusChangeType cause); /** Called to indicate that this component has just lost the keyboard focus. @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus */ virtual void focusLost (FocusChangeType cause); /** Called to indicate that one of this component's children has been focused or unfocused. Essentially this means that the return value of a call to hasKeyboardFocus (true) has changed. It happens when focus moves from one of this component's children (at any depth) to a component that isn't contained in this one, (or vice-versa). @see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus */ virtual void focusOfChildComponentChanged (FocusChangeType cause); /** Returns true if the mouse is currently over this component. If the mouse isn't over the component, this will return false, even if the mouse is currently being dragged - so you can use this in your mouseDrag method to find out whether it's really over the component or not. Note that when the mouse button is being held down, then the only component for which this method will return true is the one that was originally clicked on. If includeChildren is true, then this will also return true if the mouse is over any of the component's children (recursively) as well as the component itself. @see isMouseButtonDown. isMouseOverOrDragging, mouseDrag */ bool isMouseOver (bool includeChildren = false) const; /** Returns true if the mouse button is currently held down in this component. Note that this is a test to see whether the mouse is being pressed in this component, so it'll return false if called on component A when the mouse is actually being dragged in component B. @see isMouseButtonDownAnywhere, isMouseOver, isMouseOverOrDragging */ bool isMouseButtonDown() const throw(); /** True if the mouse is over this component, or if it's being dragged in this component. This is a handy equivalent to (isMouseOver() || isMouseButtonDown()). @see isMouseOver, isMouseButtonDown, isMouseButtonDownAnywhere */ bool isMouseOverOrDragging() const throw(); /** Returns true if a mouse button is currently down. Unlike isMouseButtonDown, this will test the current state of the buttons without regard to which component (if any) it has been pressed in. @see isMouseButtonDown, ModifierKeys */ static bool JUCE_CALLTYPE isMouseButtonDownAnywhere() throw(); /** Returns the mouse's current position, relative to this component. The return value is relative to the component's top-left corner. */ const Point getMouseXYRelative() const; /** Called when this component's size has been changed. A component can implement this method to do things such as laying out its child components when its width or height changes. The method is called synchronously as a result of the setBounds or setSize methods, so repeatedly changing a components size will repeatedly call its resized method (unlike things like repainting, where multiple calls to repaint are coalesced together). If the component is a top-level window on the desktop, its size could also be changed by operating-system factors beyond the application's control. @see moved, setSize */ virtual void resized(); /** Called when this component's position has been changed. This is called when the position relative to its parent changes, not when its absolute position on the screen changes (so it won't be called for all child components when a parent component is moved). The method is called synchronously as a result of the setBounds, setTopLeftPosition or any of the other repositioning methods, and like resized(), it will be called each time those methods are called. If the component is a top-level window on the desktop, its position could also be changed by operating-system factors beyond the application's control. @see resized, setBounds */ virtual void moved(); /** Called when one of this component's children is moved or resized. If the parent wants to know about changes to its immediate children (not to children of its children), this is the method to override. @see moved, resized, parentSizeChanged */ virtual void childBoundsChanged (Component* child); /** Called when this component's immediate parent has been resized. If the component is a top-level window, this indicates that the screen size has changed. @see childBoundsChanged, moved, resized */ virtual void parentSizeChanged(); /** Called when this component has been moved to the front of its siblings. The component may have been brought to the front by the toFront() method, or by the operating system if it's a top-level window. @see toFront */ virtual void broughtToFront(); /** Adds a listener to be told about changes to the component hierarchy or position. Component listeners get called when this component's size, position or children change - see the ComponentListener class for more details. @param newListener the listener to register - if this is already registered, it will be ignored. @see ComponentListener, removeComponentListener */ void addComponentListener (ComponentListener* newListener); /** Removes a component listener. @see addComponentListener */ void removeComponentListener (ComponentListener* listenerToRemove); /** Dispatches a numbered message to this component. This is a quick and cheap way of allowing simple asynchronous messages to be sent to components. It's also safe, because if the component that you send the message to is a null or dangling pointer, this won't cause an error. The command ID is later delivered to the component's handleCommandMessage() method by the application's message queue. @see handleCommandMessage */ void postCommandMessage (int commandId); /** Called to handle a command that was sent by postCommandMessage(). This is called by the message thread when a command message arrives, and the component can override this method to process it in any way it needs to. @see postCommandMessage */ virtual void handleCommandMessage (int commandId); /** Runs a component modally, waiting until the loop terminates. This method first makes the component visible, brings it to the front and gives it the keyboard focus. It then runs a loop, dispatching messages from the system message queue, but blocking all mouse or keyboard messages from reaching any components other than this one and its children. This loop continues until the component's exitModalState() method is called (or the component is deleted), and then this method returns, returning the value passed into exitModalState(). @see enterModalState, exitModalState, isCurrentlyModal, getCurrentlyModalComponent, isCurrentlyBlockedByAnotherModalComponent, ModalComponentManager */ int runModalLoop(); /** Puts the component into a modal state. This makes the component modal, so that messages are blocked from reaching any components other than this one and its children, but unlike runModalLoop(), this method returns immediately. If takeKeyboardFocus is true, the component will use grabKeyboardFocus() to get the focus, which is usually what you'll want it to do. If not, it will leave the focus unchanged. The callback is an optional object which will receive a callback when the modal component loses its modal status, either by being hidden or when exitModalState() is called. If you pass an object in here, the system will take care of deleting it later, after making the callback @see exitModalState, runModalLoop, ModalComponentManager::attachCallback */ void enterModalState (bool takeKeyboardFocus = true, ModalComponentManager::Callback* callback = 0); /** Ends a component's modal state. If this component is currently modal, this will turn of its modalness, and return a value to the runModalLoop() method that might have be running its modal loop. @see runModalLoop, enterModalState, isCurrentlyModal */ void exitModalState (int returnValue); /** Returns true if this component is the modal one. It's possible to have nested modal components, e.g. a pop-up dialog box that launches another pop-up, but this will only return true for the one at the top of the stack. @see getCurrentlyModalComponent */ bool isCurrentlyModal() const throw(); /** Returns the number of components that are currently in a modal state. @see getCurrentlyModalComponent */ static int JUCE_CALLTYPE getNumCurrentlyModalComponents() throw(); /** Returns one of the components that are currently modal. The index specifies which of the possible modal components to return. The order of the components in this list is the reverse of the order in which they became modal - so the component at index 0 is always the active component, and the others are progressively earlier ones that are themselves now blocked by later ones. @returns the modal component, or null if no components are modal (or if the index is out of range) @see getNumCurrentlyModalComponents, runModalLoop, isCurrentlyModal */ static Component* JUCE_CALLTYPE getCurrentlyModalComponent (int index = 0) throw(); /** Checks whether there's a modal component somewhere that's stopping this one from receiving messages. If there is a modal component, its canModalEventBeSentToComponent() method will be called to see if it will still allow this component to receive events. @see runModalLoop, getCurrentlyModalComponent */ bool isCurrentlyBlockedByAnotherModalComponent() const; /** When a component is modal, this callback allows it to choose which other components can still receive events. When a modal component is active and the user clicks on a non-modal component, this method is called on the modal component, and if it returns true, the event is allowed to reach its target. If it returns false, the event is blocked and the inputAttemptWhenModal() callback is made. It called by the isCurrentlyBlockedByAnotherModalComponent() method. The default implementation just returns false in all cases. */ virtual bool canModalEventBeSentToComponent (const Component* targetComponent); /** Called when the user tries to click on a component that is blocked by another modal component. When a component is modal and the user clicks on one of the other components, the modal component will receive this callback. The default implementation of this method will play a beep, and bring the currently modal component to the front, but it can be overridden to do other tasks. @see isCurrentlyBlockedByAnotherModalComponent, canModalEventBeSentToComponent */ virtual void inputAttemptWhenModal(); /** Returns the set of properties that belong to this component. Each component has a NamedValueSet object which you can use to attach arbitrary items of data to it. */ NamedValueSet& getProperties() throw() { return properties; } /** Returns the set of properties that belong to this component. Each component has a NamedValueSet object which you can use to attach arbitrary items of data to it. */ const NamedValueSet& getProperties() const throw() { return properties; } /** Looks for a colour that has been registered with the given colour ID number. If a colour has been set for this ID number using setColour(), then it is returned. If none has been set, the method will try calling the component's LookAndFeel class's findColour() method. If none has been registered with the look-and-feel either, it will just return black. The colour IDs for various purposes are stored as enums in the components that they are relevent to - for an example, see Slider::ColourIds, Label::ColourIds, TextEditor::ColourIds, TreeView::ColourIds, etc. @see setColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour */ const Colour findColour (int colourId, bool inheritFromParent = false) const; /** Registers a colour to be used for a particular purpose. Changing a colour will cause a synchronous callback to the colourChanged() method, which your component can override if it needs to do something when colours are altered. For more details about colour IDs, see the comments for findColour(). @see findColour, isColourSpecified, colourChanged, LookAndFeel::findColour, LookAndFeel::setColour */ void setColour (int colourId, const Colour& colour); /** If a colour has been set with setColour(), this will remove it. This allows you to make a colour revert to its default state. */ void removeColour (int colourId); /** Returns true if the specified colour ID has been explicitly set for this component using the setColour() method. */ bool isColourSpecified (int colourId) const; /** This looks for any colours that have been specified for this component, and copies them to the specified target component. */ void copyAllExplicitColoursTo (Component& target) const; /** This method is called when a colour is changed by the setColour() method. @see setColour, findColour */ virtual void colourChanged(); /** Components can implement this method to provide a MarkerList. The default implementation of this method returns 0, but you can override it to return a pointer to the component's marker list. If xAxis is true, it should return the X marker list; if false, it should return the Y markers. */ virtual MarkerList* getMarkers (bool xAxis); /** Returns the underlying native window handle for this component. This is platform-dependent and strictly for power-users only! */ void* getWindowHandle() const; /** Holds a pointer to some type of Component, which automatically becomes null if the component is deleted. If you're using a component which may be deleted by another event that's outside of your control, use a SafePointer instead of a normal pointer to refer to it, and you can test whether it's null before using it to see if something has deleted it. The ComponentType typedef must be Component, or some subclass of Component. You may also want to use a WeakReference object for the same purpose. */ template class SafePointer { public: /** Creates a null SafePointer. */ SafePointer() throw() {} /** Creates a SafePointer that points at the given component. */ SafePointer (ComponentType* const component) : weakRef (component) {} /** Creates a copy of another SafePointer. */ SafePointer (const SafePointer& other) throw() : weakRef (other.weakRef) {} /** Copies another pointer to this one. */ SafePointer& operator= (const SafePointer& other) { weakRef = other.weakRef; return *this; } /** Copies another pointer to this one. */ SafePointer& operator= (ComponentType* const newComponent) { weakRef = newComponent; return *this; } /** Returns the component that this pointer refers to, or null if the component no longer exists. */ ComponentType* getComponent() const throw() { return dynamic_cast (weakRef.get()); } /** Returns the component that this pointer refers to, or null if the component no longer exists. */ operator ComponentType*() const throw() { return getComponent(); } /** Returns the component that this pointer refers to, or null if the component no longer exists. */ ComponentType* operator->() throw() { return getComponent(); } /** Returns the component that this pointer refers to, or null if the component no longer exists. */ const ComponentType* operator->() const throw() { return getComponent(); } /** If the component is valid, this deletes it and sets this pointer to null. */ void deleteAndZero() { delete getComponent(); jassert (getComponent() == 0); } bool operator== (ComponentType* component) const throw() { return weakRef == component; } bool operator!= (ComponentType* component) const throw() { return weakRef != component; } private: WeakReference weakRef; }; /** A class to keep an eye on a component and check for it being deleted. This is designed for use with the ListenerList::callChecked() methods, to allow the list iterator to stop cleanly if the component is deleted by a listener callback while the list is still being iterated. */ class JUCE_API BailOutChecker { public: /** Creates a checker that watches one component. */ BailOutChecker (Component* component); /** Returns true if either of the two components have been deleted since this object was created. */ bool shouldBailOut() const throw(); private: const WeakReference safePointer; JUCE_DECLARE_NON_COPYABLE (BailOutChecker); }; /** Base class for objects that can be used to automatically position a component according to some kind of algorithm. The component class simply holds onto a reference to a Positioner, but doesn't actually do anything with it - all the functionality must be implemented by the positioner itself (e.g. it might choose to watch some kind of value and move the component when the value changes). */ class JUCE_API Positioner { public: /** Creates a Positioner which can control the specified component. */ explicit Positioner (Component& component) throw(); /** Destructor. */ virtual ~Positioner() {} /** Returns the component that this positioner controls. */ Component& getComponent() const throw() { return component; } private: Component& component; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner); }; /** Returns the Positioner object that has been set for this component. @see setPositioner() */ Positioner* getPositioner() const throw(); /** Sets a new Positioner object for this component. If there's currently another positioner set, it will be deleted. The object that is passed in will be deleted automatically by this component when it's no longer required. Pass a null pointer to clear the current positioner. @see getPositioner() */ void setPositioner (Positioner* newPositioner); #ifndef DOXYGEN // These methods are deprecated - use localPointToGlobal, getLocalPoint, getLocalPoint, etc instead. JUCE_DEPRECATED (const Point relativePositionToGlobal (const Point&) const); JUCE_DEPRECATED (const Point globalPositionToRelative (const Point&) const); JUCE_DEPRECATED (const Point relativePositionToOtherComponent (const Component*, const Point&) const); #endif private: friend class ComponentPeer; friend class MouseInputSource; friend class MouseInputSourceInternal; #ifndef DOXYGEN static Component* currentlyFocusedComponent; String componentName, componentID; Component* parentComponent; Rectangle bounds; ScopedPointer positioner; ScopedPointer affineTransform; Array childComponentList; LookAndFeel* lookAndFeel; MouseCursor cursor; ImageEffectFilter* effect; Image bufferedImage; class MouseListenerList; friend class MouseListenerList; friend class ScopedPointer ; ScopedPointer mouseListeners; ScopedPointer > keyListeners; ListenerList componentListeners; NamedValueSet properties; friend class WeakReference; WeakReference::Master weakReferenceMaster; const WeakReference::SharedRef& getWeakReference(); struct ComponentFlags { bool hasHeavyweightPeerFlag : 1; bool visibleFlag : 1; bool opaqueFlag : 1; bool ignoresMouseClicksFlag : 1; bool allowChildMouseClicksFlag : 1; bool wantsFocusFlag : 1; bool isFocusContainerFlag : 1; bool dontFocusOnMouseClickFlag : 1; bool alwaysOnTopFlag : 1; bool bufferToImageFlag : 1; bool bringToFrontOnClickFlag : 1; bool repaintOnMouseActivityFlag : 1; bool mouseDownFlag : 1; bool mouseOverFlag : 1; bool mouseInsideFlag : 1; bool currentlyModalFlag : 1; bool isDisabledFlag : 1; bool childCompFocusedFlag : 1; bool dontClipGraphicsFlag : 1; #if JUCE_DEBUG bool isInsidePaintCall : 1; #endif }; union { uint32 componentFlags; ComponentFlags flags; }; uint8 componentTransparency; void internalMouseEnter (MouseInputSource& source, const Point& relativePos, const Time& time); void internalMouseExit (MouseInputSource& source, const Point& relativePos, const Time& time); void internalMouseDown (MouseInputSource& source, const Point& relativePos, const Time& time); void internalMouseUp (MouseInputSource& source, const Point& relativePos, const Time& time, const ModifierKeys& oldModifiers); void internalMouseDrag (MouseInputSource& source, const Point& relativePos, const Time& time); void internalMouseMove (MouseInputSource& source, const Point& relativePos, const Time& time); void internalMouseWheel (MouseInputSource& source, const Point& relativePos, const Time& time, float amountX, float amountY); void internalBroughtToFront(); void internalFocusGain (const FocusChangeType cause, const WeakReference&); void internalFocusGain (const FocusChangeType cause); void internalFocusLoss (const FocusChangeType cause); void internalChildFocusChange (FocusChangeType cause, const WeakReference&); void internalModalInputAttempt(); void internalModifierKeysChanged(); void internalChildrenChanged(); void internalHierarchyChanged(); Component* removeChildComponent (int index, bool sendParentEvents, bool sendChildEvents); void moveChildInternal (int sourceIndex, int destIndex); void paintComponentAndChildren (Graphics& g); void paintComponent (Graphics& g); void paintWithinParentContext (Graphics& g); void sendMovedResizedMessages (bool wasMoved, bool wasResized); void repaintParent(); void sendFakeMouseMove() const; void takeKeyboardFocus (const FocusChangeType cause); void grabFocusInternal (const FocusChangeType cause, bool canTryParent = true); static void giveAwayFocus (bool sendFocusLossEvent); void sendEnablementChangeMessage(); void sendVisibilityChangeMessage(); class ComponentHelpers; friend class ComponentHelpers; /* Components aren't allowed to have copy constructors, as this would mess up parent hierarchies. You might need to give your subclasses a private dummy constructor to avoid compiler warnings. */ JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Component); #if JUCE_CATCH_DEPRECATED_CODE_MISUSE // This is included here just to cause a compile error if your code is still handling // drag-and-drop with this method. If so, just update it to use the new FileDragAndDropTarget // class, which is easy (just make your class inherit from FileDragAndDropTarget, and // implement its methods instead of this Component method). virtual void filesDropped (const StringArray&, int, int) {} // This is included here to cause an error if you use or overload it - it has been deprecated in // favour of contains (const Point&) void contains (int, int); #endif protected: /** @internal */ virtual void internalRepaint (int x, int y, int w, int h); /** @internal */ virtual ComponentPeer* createNewPeer (int styleFlags, void* nativeWindowToAttachTo); #endif }; #endif // __JUCE_COMPONENT_JUCEHEADER__ /*** End of inlined file: juce_Component.h ***/ /*** Start of inlined file: juce_ApplicationCommandInfo.h ***/ #ifndef __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ #define __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ /*** Start of inlined file: juce_ApplicationCommandID.h ***/ #ifndef __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ #define __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ /** A type used to hold the unique ID for an application command. This is a numeric type, so it can be stored as an integer. @see ApplicationCommandInfo, ApplicationCommandManager, ApplicationCommandTarget, KeyPressMappingSet */ typedef int CommandID; /** A set of general-purpose application command IDs. Because these commands are likely to be used in most apps, they're defined here to help different apps to use the same numeric values for them. Of course you don't have to use these, but some of them are used internally by Juce - e.g. the quit ID is recognised as a command by the JUCEApplication class. @see ApplicationCommandInfo, ApplicationCommandManager, ApplicationCommandTarget, KeyPressMappingSet */ namespace StandardApplicationCommandIDs { /** This command ID should be used to send a "Quit the App" command. This command is recognised by the JUCEApplication class, so if it is invoked and no other ApplicationCommandTarget handles the event first, the JUCEApplication object will catch it and call JUCEApplication::systemRequestedQuit(). */ static const CommandID quit = 0x1001; /** The command ID that should be used to send a "Delete" command. */ static const CommandID del = 0x1002; /** The command ID that should be used to send a "Cut" command. */ static const CommandID cut = 0x1003; /** The command ID that should be used to send a "Copy to clipboard" command. */ static const CommandID copy = 0x1004; /** The command ID that should be used to send a "Paste from clipboard" command. */ static const CommandID paste = 0x1005; /** The command ID that should be used to send a "Select all" command. */ static const CommandID selectAll = 0x1006; /** The command ID that should be used to send a "Deselect all" command. */ static const CommandID deselectAll = 0x1007; } #endif // __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ /*** End of inlined file: juce_ApplicationCommandID.h ***/ /** Holds information describing an application command. This object is used to pass information about a particular command, such as its name, description and other usage flags. When an ApplicationCommandTarget is asked to provide information about the commands it can perform, this is the structure gets filled-in to describe each one. @see ApplicationCommandTarget, ApplicationCommandTarget::getCommandInfo(), ApplicationCommandManager */ struct JUCE_API ApplicationCommandInfo { explicit ApplicationCommandInfo (CommandID commandID) throw(); /** Sets a number of the structures values at once. The meanings of each of the parameters is described below, in the appropriate member variable's description. */ void setInfo (const String& shortName, const String& description, const String& categoryName, int flags) throw(); /** An easy way to set or remove the isDisabled bit in the structure's flags field. If isActive is true, the flags member has the isDisabled bit cleared; if isActive is false, the bit is set. */ void setActive (bool isActive) throw(); /** An easy way to set or remove the isTicked bit in the structure's flags field. */ void setTicked (bool isTicked) throw(); /** Handy method for adding a keypress to the defaultKeypresses array. This is just so you can write things like: @code myinfo.addDefaultKeypress ('s', ModifierKeys::commandModifier); @endcode instead of @code myinfo.defaultKeypresses.add (KeyPress ('s', ModifierKeys::commandModifier)); @endcode */ void addDefaultKeypress (int keyCode, const ModifierKeys& modifiers) throw(); /** The command's unique ID number. */ CommandID commandID; /** A short name to describe the command. This should be suitable for use in menus, on buttons that trigger the command, etc. You can use the setInfo() method to quickly set this and some of the command's other properties. */ String shortName; /** A longer description of the command. This should be suitable for use in contexts such as a KeyMappingEditorComponent or pop-up tooltip describing what the command does. You can use the setInfo() method to quickly set this and some of the command's other properties. */ String description; /** A named category that the command fits into. You can give your commands any category you like, and these will be displayed in contexts such as the KeyMappingEditorComponent, where the category is used to group commands together. You can use the setInfo() method to quickly set this and some of the command's other properties. */ String categoryName; /** A list of zero or more keypresses that should be used as the default keys for this command. Methods such as KeyPressMappingSet::resetToDefaultMappings() will use the keypresses in this list to initialise the default set of key-to-command mappings. @see addDefaultKeypress */ Array defaultKeypresses; /** Flags describing the ways in which this command should be used. A bitwise-OR of these values is stored in the ApplicationCommandInfo::flags variable. */ enum CommandFlags { /** Indicates that the command can't currently be performed. The ApplicationCommandTarget::getCommandInfo() method must set this flag if it's not currently permissable to perform the command. If the flag is set, then components that trigger the command, e.g. PopupMenu, may choose to grey-out the command or show themselves as not being enabled. @see ApplicationCommandInfo::setActive */ isDisabled = 1 << 0, /** Indicates that the command should have a tick next to it on a menu. If your command is shown on a menu and this is set, it'll show a tick next to it. Other components such as buttons may also use this flag to indicate that it is a value that can be toggled, and is currently in the 'on' state. @see ApplicationCommandInfo::setTicked */ isTicked = 1 << 1, /** If this flag is present, then when a KeyPressMappingSet invokes the command, it will call the command twice, once on key-down and again on key-up. @see ApplicationCommandTarget::InvocationInfo */ wantsKeyUpDownCallbacks = 1 << 2, /** If this flag is present, then a KeyMappingEditorComponent will not display the command in its list. */ hiddenFromKeyEditor = 1 << 3, /** If this flag is present, then a KeyMappingEditorComponent will display the command in its list, but won't allow the assigned keypress to be changed. */ readOnlyInKeyEditor = 1 << 4, /** If this flag is present and the command is invoked from a keypress, then any buttons or menus that are also connected to the command will not flash to indicate that they've been triggered. */ dontTriggerVisualFeedback = 1 << 5 }; /** A bitwise-OR of the values specified in the CommandFlags enum. You can use the setInfo() method to quickly set this and some of the command's other properties. */ int flags; }; #endif // __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ /*** End of inlined file: juce_ApplicationCommandInfo.h ***/ /*** Start of inlined file: juce_MessageListener.h ***/ #ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__ #define __JUCE_MESSAGELISTENER_JUCEHEADER__ /** MessageListener subclasses can post and receive Message objects. @see Message, MessageManager, ActionListener, ChangeListener */ class JUCE_API MessageListener { protected: /** Creates a MessageListener. */ MessageListener() throw(); public: /** Destructor. When a MessageListener is deleted, it removes itself from a global list of registered listeners, so that the isValidMessageListener() method will no longer return true. */ virtual ~MessageListener(); /** This is the callback method that receives incoming messages. This is called by the MessageManager from its dispatch loop. @see postMessage */ virtual void handleMessage (const Message& message) = 0; /** Sends a message to the message queue, for asynchronous delivery to this listener later on. This method can be called safely by any thread. @param message the message object to send - this will be deleted automatically by the message queue, so don't keep any references to it after calling this method. @see handleMessage */ void postMessage (Message* message) const throw(); /** Checks whether this MessageListener has been deleted. Although not foolproof, this method is safe to call on dangling or null pointers. A list of active MessageListeners is kept internally, so this checks whether the object is on this list or not. Note that it's possible to get a false-positive here, if an object is deleted and another is subsequently created that happens to be at the exact same memory location, but I can't think of a good way of avoiding this. */ bool isValidMessageListener() const throw(); }; #endif // __JUCE_MESSAGELISTENER_JUCEHEADER__ /*** End of inlined file: juce_MessageListener.h ***/ /** A command target publishes a list of command IDs that it can perform. An ApplicationCommandManager despatches commands to targets, which must be able to provide information about what commands they can handle. To create a target, you'll need to inherit from this class, implementing all of its pure virtual methods. For info about how a target is chosen to receive a command, see ApplicationCommandManager::getFirstCommandTarget(). @see ApplicationCommandManager, ApplicationCommandInfo */ class JUCE_API ApplicationCommandTarget { public: /** Creates a command target. */ ApplicationCommandTarget(); /** Destructor. */ virtual ~ApplicationCommandTarget(); /** */ struct JUCE_API InvocationInfo { InvocationInfo (const CommandID commandID); /** The UID of the command that should be performed. */ CommandID commandID; /** The command's flags. See ApplicationCommandInfo for a description of these flag values. */ int commandFlags; /** The types of context in which the command might be called. */ enum InvocationMethod { direct = 0, /**< The command is being invoked directly by a piece of code. */ fromKeyPress, /**< The command is being invoked by a key-press. */ fromMenu, /**< The command is being invoked by a menu selection. */ fromButton /**< The command is being invoked by a button click. */ }; /** The type of event that triggered this command. */ InvocationMethod invocationMethod; /** If triggered by a keypress or menu, this will be the component that had the keyboard focus at the time. If triggered by a button, it may be set to that component, or it may be null. */ Component* originatingComponent; /** The keypress that was used to invoke it. Note that this will be an invalid keypress if the command was invoked by some other means than a keyboard shortcut. */ KeyPress keyPress; /** True if the callback is being invoked when the key is pressed, false if the key is being released. @see KeyPressMappingSet::addCommand() */ bool isKeyDown; /** If the key is being released, this indicates how long it had been held down for. (Only relevant if isKeyDown is false.) */ int millisecsSinceKeyPressed; }; /** This must return the next target to try after this one. When a command is being sent, and the first target can't handle that command, this method is used to determine the next target that should be tried. It may return 0 if it doesn't know of another target. If your target is a Component, you would usually use the findFirstTargetParentComponent() method to return a parent component that might want to handle it. @see invoke */ virtual ApplicationCommandTarget* getNextCommandTarget() = 0; /** This must return a complete list of commands that this target can handle. Your target should add all the command IDs that it handles to the array that is passed-in. */ virtual void getAllCommands (Array & commands) = 0; /** This must provide details about one of the commands that this target can perform. This will be called with one of the command IDs that the target provided in its getAllCommands() methods. It should fill-in all appropriate fields of the ApplicationCommandInfo structure with suitable information about the command. (The commandID field will already have been filled-in by the caller). The easiest way to set the info is using the ApplicationCommandInfo::setInfo() method to set all the fields at once. If the command is currently inactive for some reason, this method must use ApplicationCommandInfo::setActive() to make that clear, (or it should set the isDisabled bit of the ApplicationCommandInfo::flags field). Any default key-presses for the command should be appended to the ApplicationCommandInfo::defaultKeypresses field. Note that if you change something that affects the status of the commands that would be returned by this method (e.g. something that makes some commands active or inactive), you should call ApplicationCommandManager::commandStatusChanged() to cause the manager to refresh its status. */ virtual void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result) = 0; /** This must actually perform the specified command. If this target is able to perform the command specified by the commandID field of the InvocationInfo structure, then it should do so, and must return true. If it can't handle this command, it should return false, which tells the caller to pass the command on to the next target in line. @see invoke, ApplicationCommandManager::invoke */ virtual bool perform (const InvocationInfo& info) = 0; /** Makes this target invoke a command. Your code can call this method to invoke a command on this target, but normally you'd call it indirectly via ApplicationCommandManager::invoke() or ApplicationCommandManager::invokeDirectly(). If this target can perform the given command, it will call its perform() method to do so. If not, then getNextCommandTarget() will be used to determine the next target to try, and the command will be passed along to it. @param invocationInfo this must be correctly filled-in, describing the context for the invocation. @param asynchronously if false, the command will be performed before this method returns. If true, a message will be posted so that the command will be performed later on the message thread, and this method will return immediately. @see perform, ApplicationCommandManager::invoke */ bool invoke (const InvocationInfo& invocationInfo, const bool asynchronously); /** Invokes a given command directly on this target. This is just an easy way to call invoke() without having to fill out the InvocationInfo structure. */ bool invokeDirectly (const CommandID commandID, const bool asynchronously); /** Searches this target and all subsequent ones for the first one that can handle the specified command. This will use getNextCommandTarget() to determine the chain of targets to try after this one. */ ApplicationCommandTarget* getTargetForCommand (const CommandID commandID); /** Checks whether this command can currently be performed by this target. This will return true only if a call to getCommandInfo() doesn't set the isDisabled flag to indicate that the command is inactive. */ bool isCommandActive (const CommandID commandID); /** If this object is a Component, this method will seach upwards in its current UI hierarchy for the next parent component that implements the ApplicationCommandTarget class. If your target is a Component, this is a very handy method to use in your getNextCommandTarget() implementation. */ ApplicationCommandTarget* findFirstTargetParentComponent(); private: // (for async invocation of commands) class CommandTargetMessageInvoker : public MessageListener { public: CommandTargetMessageInvoker (ApplicationCommandTarget* owner); ~CommandTargetMessageInvoker(); void handleMessage (const Message& message); private: ApplicationCommandTarget* const owner; JUCE_DECLARE_NON_COPYABLE (CommandTargetMessageInvoker); }; ScopedPointer messageInvoker; friend class CommandTargetMessageInvoker; bool tryToInvoke (const InvocationInfo& info, bool async); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ApplicationCommandTarget); }; #endif // __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ /*** End of inlined file: juce_ApplicationCommandTarget.h ***/ /*** Start of inlined file: juce_ActionListener.h ***/ #ifndef __JUCE_ACTIONLISTENER_JUCEHEADER__ #define __JUCE_ACTIONLISTENER_JUCEHEADER__ /** Receives callbacks to indicate that some kind of event has occurred. Used by various classes, e.g. buttons when they are pressed, to tell listeners about something that's happened. @see ActionBroadcaster, ChangeListener */ class JUCE_API ActionListener { public: /** Destructor. */ virtual ~ActionListener() {} /** Overridden by your subclass to receive the callback. @param message the string that was specified when the event was triggered by a call to ActionBroadcaster::sendActionMessage() */ virtual void actionListenerCallback (const String& message) = 0; }; #endif // __JUCE_ACTIONLISTENER_JUCEHEADER__ /*** End of inlined file: juce_ActionListener.h ***/ /** An instance of this class is used to specify initialisation and shutdown code for the application. An application that wants to run in the JUCE framework needs to declare a subclass of JUCEApplication and implement its various pure virtual methods. It then needs to use the START_JUCE_APPLICATION macro somewhere in a cpp file to declare an instance of this class and generate a suitable platform-specific main() function. e.g. @code class MyJUCEApp : public JUCEApplication { public: MyJUCEApp() { } ~MyJUCEApp() { } void initialise (const String& commandLine) { myMainWindow = new MyApplicationWindow(); myMainWindow->setBounds (100, 100, 400, 500); myMainWindow->setVisible (true); } void shutdown() { myMainWindow = 0; } const String getApplicationName() { return "Super JUCE-o-matic"; } const String getApplicationVersion() { return "1.0"; } private: ScopedPointer myMainWindow; }; // this creates wrapper code to actually launch the app properly. START_JUCE_APPLICATION (MyJUCEApp) @endcode @see MessageManager, DeletedAtShutdown */ class JUCE_API JUCEApplication : public ApplicationCommandTarget, private ActionListener { protected: /** Constructs a JUCE app object. If subclasses implement a constructor or destructor, they shouldn't call any JUCE code in there - put your startup/shutdown code in initialise() and shutdown() instead. */ JUCEApplication(); public: /** Destructor. If subclasses implement a constructor or destructor, they shouldn't call any JUCE code in there - put your startup/shutdown code in initialise() and shutdown() instead. */ virtual ~JUCEApplication(); /** Returns the global instance of the application object being run. */ static JUCEApplication* getInstance() throw() { return appInstance; } /** Called when the application starts. This will be called once to let the application do whatever initialisation it needs, create its windows, etc. After the method returns, the normal event-dispatch loop will be run, until the quit() method is called, at which point the shutdown() method will be called to let the application clear up anything it needs to delete. If during the initialise() method, the application decides not to start-up after all, it can just call the quit() method and the event loop won't be run. @param commandLineParameters the line passed in does not include the name of the executable, just the parameter list. @see shutdown, quit */ virtual void initialise (const String& commandLineParameters) = 0; /** Returns true if the application hasn't yet completed its initialise() method and entered the main event loop. This is handy for things like splash screens to know when the app's up-and-running properly. */ bool isInitialising() const throw() { return stillInitialising; } /* Called to allow the application to clear up before exiting. After JUCEApplication::quit() has been called, the event-dispatch loop will terminate, and this method will get called to allow the app to sort itself out. Be careful that nothing happens in this method that might rely on messages being sent, or any kind of window activity, because the message loop is no longer running at this point. @see DeletedAtShutdown */ virtual void shutdown() = 0; /** Returns the application's name. An application must implement this to name itself. */ virtual const String getApplicationName() = 0; /** Returns the application's version number. */ virtual const String getApplicationVersion() = 0; /** Checks whether multiple instances of the app are allowed. If you application class returns true for this, more than one instance is permitted to run (except on the Mac where this isn't possible). If it's false, the second instance won't start, but it you will still get a callback to anotherInstanceStarted() to tell you about this - which gives you a chance to react to what the user was trying to do. */ virtual bool moreThanOneInstanceAllowed(); /** Indicates that the user has tried to start up another instance of the app. This will get called even if moreThanOneInstanceAllowed() is false. */ virtual void anotherInstanceStarted (const String& commandLine); /** Called when the operating system is trying to close the application. The default implementation of this method is to call quit(), but it may be overloaded to ignore the request or do some other special behaviour instead. For example, you might want to offer the user the chance to save their changes before quitting, and give them the chance to cancel. If you want to send a quit signal to your app, this is the correct method to call, because it means that requests that come from the system get handled in the same way as those from your own application code. So e.g. you'd call this method from a "quit" item on a menu bar. */ virtual void systemRequestedQuit(); /** If any unhandled exceptions make it through to the message dispatch loop, this callback will be triggered, in case you want to log them or do some other type of error-handling. If the type of exception is derived from the std::exception class, the pointer passed-in will be valid. If the exception is of unknown type, this pointer will be null. */ virtual void unhandledException (const std::exception* e, const String& sourceFilename, int lineNumber); /** Signals that the main message loop should stop and the application should terminate. This isn't synchronous, it just posts a quit message to the main queue, and when this message arrives, the message loop will stop, the shutdown() method will be called, and the app will exit. Note that this will cause an unconditional quit to happen, so if you need an extra level before this, e.g. to give the user the chance to save their work and maybe cancel the quit, you'll need to handle this in the systemRequestedQuit() method - see that method's help for more info. @see MessageManager, DeletedAtShutdown */ static void quit(); /** Sets the value that should be returned as the application's exit code when the app quits. This is the value that's returned by the main() function. Normally you'd leave this as 0 unless you want to indicate an error code. @see getApplicationReturnValue */ void setApplicationReturnValue (int newReturnValue) throw(); /** Returns the value that has been set as the application's exit code. @see setApplicationReturnValue */ int getApplicationReturnValue() const throw() { return appReturnValue; } /** Returns the application's command line params. */ const String getCommandLineParameters() const throw() { return commandLineParameters; } // These are used by the START_JUCE_APPLICATION() macro and aren't for public use. /** @internal */ static int main (const String& commandLine); /** @internal */ static int main (int argc, const char* argv[]); /** @internal */ static void sendUnhandledException (const std::exception* e, const char* sourceFile, int lineNumber); /** Returns true if this executable is running as an app (as opposed to being a plugin or other kind of shared library. */ static inline bool isStandaloneApp() throw() { return createInstance != 0; } /** @internal */ ApplicationCommandTarget* getNextCommandTarget(); /** @internal */ void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result); /** @internal */ void getAllCommands (Array & commands); /** @internal */ bool perform (const InvocationInfo& info); /** @internal */ void actionListenerCallback (const String& message); /** @internal */ bool initialiseApp (const String& commandLine); /** @internal */ int shutdownApp(); /** @internal */ static void appWillTerminateByForce(); /** @internal */ typedef JUCEApplication* (*CreateInstanceFunction)(); /** @internal */ static CreateInstanceFunction createInstance; private: String commandLineParameters; int appReturnValue; bool stillInitialising; ScopedPointer appLock; static JUCEApplication* appInstance; JUCE_DECLARE_NON_COPYABLE (JUCEApplication); }; #endif // __JUCE_APPLICATION_JUCEHEADER__ /*** End of inlined file: juce_Application.h ***/ #endif #ifndef __JUCE_APPLICATIONCOMMANDID_JUCEHEADER__ #endif #ifndef __JUCE_APPLICATIONCOMMANDINFO_JUCEHEADER__ #endif #ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ /*** Start of inlined file: juce_ApplicationCommandManager.h ***/ #ifndef __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ #define __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ /*** Start of inlined file: juce_Desktop.h ***/ #ifndef __JUCE_DESKTOP_JUCEHEADER__ #define __JUCE_DESKTOP_JUCEHEADER__ /*** Start of inlined file: juce_Timer.h ***/ #ifndef __JUCE_TIMER_JUCEHEADER__ #define __JUCE_TIMER_JUCEHEADER__ class InternalTimerThread; /** Makes repeated callbacks to a virtual method at a specified time interval. A Timer's timerCallback() method will be repeatedly called at a given interval. When you create a Timer object, it will do nothing until the startTimer() method is called, which will cause the message thread to start making callbacks at the specified interval, until stopTimer() is called or the object is deleted. The time interval isn't guaranteed to be precise to any more than maybe 10-20ms, and the intervals may end up being much longer than requested if the system is busy. Because the callbacks are made by the main message thread, anything that blocks the message queue for a period of time will also prevent any timers from running until it can carry on. If you need to have a single callback that is shared by multiple timers with different frequencies, then the MultiTimer class allows you to do that - its structure is very similar to the Timer class, but contains multiple timers internally, each one identified by an ID number. @see MultiTimer */ class JUCE_API Timer { protected: /** Creates a Timer. When created, the timer is stopped, so use startTimer() to get it going. */ Timer() throw(); /** Creates a copy of another timer. Note that this timer won't be started, even if the one you're copying is running. */ Timer (const Timer& other) throw(); public: /** Destructor. */ virtual ~Timer(); /** The user-defined callback routine that actually gets called periodically. It's perfectly ok to call startTimer() or stopTimer() from within this callback to change the subsequent intervals. */ virtual void timerCallback() = 0; /** Starts the timer and sets the length of interval required. If the timer is already started, this will reset it, so the time between calling this method and the next timer callback will not be less than the interval length passed in. @param intervalInMilliseconds the interval to use (any values less than 1 will be rounded up to 1) */ void startTimer (int intervalInMilliseconds) throw(); /** Stops the timer. No more callbacks will be made after this method returns. If this is called from a different thread, any callbacks that may be currently executing may be allowed to finish before the method returns. */ void stopTimer() throw(); /** Checks if the timer has been started. @returns true if the timer is running. */ bool isTimerRunning() const throw() { return periodMs > 0; } /** Returns the timer's interval. @returns the timer's interval in milliseconds if it's running, or 0 if it's not. */ int getTimerInterval() const throw() { return periodMs; } private: friend class InternalTimerThread; int countdownMs, periodMs; Timer* previous; Timer* next; Timer& operator= (const Timer&); }; #endif // __JUCE_TIMER_JUCEHEADER__ /*** End of inlined file: juce_Timer.h ***/ /*** Start of inlined file: juce_ComponentAnimator.h ***/ #ifndef __JUCE_COMPONENTANIMATOR_JUCEHEADER__ #define __JUCE_COMPONENTANIMATOR_JUCEHEADER__ /** Animates a set of components, moving them to a new position and/or fading their alpha levels. To animate a component, create a ComponentAnimator instance or (preferably) use the global animator object provided by Desktop::getAnimator(), and call its animateComponent() method to commence the movement. If you're using your own ComponentAnimator instance, you'll need to make sure it isn't deleted before it finishes moving the components, or they'll be abandoned before reaching their destinations. It's ok to delete components while they're being animated - the animator will detect this and safely stop using them. The class is a ChangeBroadcaster and sends a notification when any components start or finish being animated. @see Desktop::getAnimator */ class JUCE_API ComponentAnimator : public ChangeBroadcaster, private Timer { public: /** Creates a ComponentAnimator. */ ComponentAnimator(); /** Destructor. */ ~ComponentAnimator(); /** Starts a component moving from its current position to a specified position. If the component is already in the middle of an animation, that will be abandoned, and a new animation will begin, moving the component from its current location. The start and end speed parameters let you apply some acceleration to the component's movement. @param component the component to move @param finalBounds the destination bounds to which the component should move. To leave the component in the same place, just pass component->getBounds() for this value @param finalAlpha the alpha value that the component should have at the end of the animation @param animationDurationMilliseconds how long the animation should last, in milliseconds @param useProxyComponent if true, this means the component should be replaced by an internally managed temporary component which is a snapshot of the original component. This avoids the component having to paint itself as it moves, so may be more efficient. This option also allows you to delete the original component immediately after starting the animation, because the animation can proceed without it. If you use a proxy, the original component will be made invisible by this call, and then will become visible again at the end of the animation. It'll also mean that the proxy component will be temporarily added to the component's parent, so avoid it if this might confuse the parent component, or if there's a chance the parent might decide to delete its children. @param startSpeed a value to indicate the relative start speed of the animation. If this is 0, the component will start by accelerating from rest; higher values mean that it will have an initial speed greater than zero. If the value if greater than 1, it will decelerate towards the middle of its journey. To move the component at a constant rate for its entire animation, set both the start and end speeds to 1.0 @param endSpeed a relative speed at which the component should be moving when the animation finishes. If this is 0, the component will decelerate to a standstill at its final position; higher values mean the component will still be moving when it stops. To move the component at a constant rate for its entire animation, set both the start and end speeds to 1.0 */ void animateComponent (Component* component, const Rectangle& finalBounds, float finalAlpha, int animationDurationMilliseconds, bool useProxyComponent, double startSpeed, double endSpeed); /** Begins a fade-out of this components alpha level. This is a quick way of invoking animateComponent() with a target alpha value of 0.0f, using a proxy. You're safe to delete the component after calling this method, and this won't interfere with the animation's progress. */ void fadeOut (Component* component, int millisecondsToTake); /** Begins a fade-in of a component. This is a quick way of invoking animateComponent() with a target alpha value of 1.0f. */ void fadeIn (Component* component, int millisecondsToTake); /** Stops a component if it's currently being animated. If moveComponentToItsFinalPosition is true, then the component will be immediately moved to its destination position and size. If false, it will be left in whatever location it currently occupies. */ void cancelAnimation (Component* component, bool moveComponentToItsFinalPosition); /** Clears all of the active animations. If moveComponentsToTheirFinalPositions is true, all the components will be immediately set to their final positions. If false, they will be left in whatever locations they currently occupy. */ void cancelAllAnimations (bool moveComponentsToTheirFinalPositions); /** Returns the destination position for a component. If the component is being animated, this will return the target position that was specified when animateComponent() was called. If the specified component isn't currently being animated, this method will just return its current position. */ const Rectangle getComponentDestination (Component* component); /** Returns true if the specified component is currently being animated. */ bool isAnimating (Component* component) const; private: class AnimationTask; OwnedArray tasks; uint32 lastTime; AnimationTask* findTaskFor (Component* component) const; void timerCallback(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentAnimator); }; #endif // __JUCE_COMPONENTANIMATOR_JUCEHEADER__ /*** End of inlined file: juce_ComponentAnimator.h ***/ class MouseInputSource; class MouseInputSourceInternal; class MouseListener; /** Classes can implement this interface and register themselves with the Desktop class to receive callbacks when the currently focused component changes. @see Desktop::addFocusChangeListener, Desktop::removeFocusChangeListener */ class JUCE_API FocusChangeListener { public: /** Destructor. */ virtual ~FocusChangeListener() {} /** Callback to indicate that the currently focused component has changed. */ virtual void globalFocusChanged (Component* focusedComponent) = 0; }; /** Describes and controls aspects of the computer's desktop. */ class JUCE_API Desktop : private DeletedAtShutdown, private Timer, private AsyncUpdater { public: /** There's only one dektop object, and this method will return it. */ static Desktop& JUCE_CALLTYPE getInstance(); /** Returns a list of the positions of all the monitors available. The first rectangle in the list will be the main monitor area. If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. */ const RectangleList getAllMonitorDisplayAreas (bool clippedToWorkArea = true) const throw(); /** Returns the position and size of the main monitor. If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. */ const Rectangle getMainMonitorArea (bool clippedToWorkArea = true) const throw(); /** Returns the position and size of the monitor which contains this co-ordinate. If none of the monitors contains the point, this will just return the main monitor. If clippedToWorkArea is true, it will exclude any areas like the taskbar on Windows, or the menu bar on Mac. If clippedToWorkArea is false, the entire monitor area is returned. */ const Rectangle getMonitorAreaContaining (const Point& position, bool clippedToWorkArea = true) const; /** Returns the mouse position. The co-ordinates are relative to the top-left of the main monitor. Note that this is just a shortcut for calling getMainMouseSource().getScreenPosition(), and you should only resort to grabbing the global mouse position if there's really no way to get the coordinates via a mouse event callback instead. */ static const Point getMousePosition(); /** Makes the mouse pointer jump to a given location. The co-ordinates are relative to the top-left of the main monitor. */ static void setMousePosition (const Point& newPosition); /** Returns the last position at which a mouse button was pressed. Note that this is just a shortcut for calling getMainMouseSource().getLastMouseDownPosition(), and in a multi-touch environment, it doesn't make much sense. ALWAYS prefer to get this information via other means, such as MouseEvent::getMouseDownScreenPosition() if possible, and only ever call this as a last resort. */ static const Point getLastMouseDownPosition(); /** Returns the number of times the mouse button has been clicked since the app started. Each mouse-down event increments this number by 1. */ static int getMouseButtonClickCounter(); /** This lets you prevent the screensaver from becoming active. Handy if you're running some sort of presentation app where having a screensaver appear would be annoying. Pass false to disable the screensaver, and true to re-enable it. (Note that this won't enable a screensaver unless the user has actually set one up). The disablement will only happen while the Juce application is the foreground process - if another task is running in front of it, then the screensaver will be unaffected. @see isScreenSaverEnabled */ static void setScreenSaverEnabled (bool isEnabled); /** Returns true if the screensaver has not been turned off. This will return the last value passed into setScreenSaverEnabled(). Note that it won't tell you whether the user is actually using a screen saver, just whether this app is deliberately preventing one from running. @see setScreenSaverEnabled */ static bool isScreenSaverEnabled(); /** Registers a MouseListener that will receive all mouse events that occur on any component. @see removeGlobalMouseListener */ void addGlobalMouseListener (MouseListener* listener); /** Unregisters a MouseListener that was added with the addGlobalMouseListener() method. @see addGlobalMouseListener */ void removeGlobalMouseListener (MouseListener* listener); /** Registers a MouseListener that will receive a callback whenever the focused component changes. */ void addFocusChangeListener (FocusChangeListener* listener); /** Unregisters a listener that was added with addFocusChangeListener(). */ void removeFocusChangeListener (FocusChangeListener* listener); /** Takes a component and makes it full-screen, removing the taskbar, dock, etc. The component must already be on the desktop for this method to work. It will be resized to completely fill the screen and any extraneous taskbars, menu bars, etc will be hidden. To exit kiosk mode, just call setKioskModeComponent (0). When this is called, the component that's currently being used will be resized back to the size and position it was in before being put into this mode. If allowMenusAndBars is true, things like the menu and dock (on mac) are still allowed to pop up when the mouse moves onto them. If this is false, it'll try to hide as much on-screen paraphenalia as possible. */ void setKioskModeComponent (Component* componentToUse, bool allowMenusAndBars = true); /** Returns the component that is currently being used in kiosk-mode. This is the component that was last set by setKioskModeComponent(). If none has been set, this returns 0. */ Component* getKioskModeComponent() const throw() { return kioskModeComponent; } /** Returns the number of components that are currently active as top-level desktop windows. @see getComponent, Component::addToDesktop */ int getNumComponents() const throw(); /** Returns one of the top-level desktop window components. The index is from 0 to getNumComponents() - 1. This could return 0 if the index is out-of-range. @see getNumComponents, Component::addToDesktop */ Component* getComponent (int index) const throw(); /** Finds the component at a given screen location. This will drill down into top-level windows to find the child component at the given position. Returns 0 if the co-ordinates are inside a non-Juce window. */ Component* findComponentAt (const Point& screenPosition) const; /** The Desktop object has a ComponentAnimator instance which can be used for performing your animations. Having a single shared ComponentAnimator object makes it more efficient when multiple components are being moved around simultaneously. It's also more convenient than having to manage your own instance of one. @see ComponentAnimator */ ComponentAnimator& getAnimator() throw() { return animator; } /** Returns the number of MouseInputSource objects the system has at its disposal. In a traditional single-mouse system, there might be only one object. On a multi-touch system, there could be one input source per potential finger. To find out how many mouse events are currently happening, use getNumDraggingMouseSources(). @see getMouseSource */ int getNumMouseSources() const throw() { return mouseSources.size(); } /** Returns one of the system's MouseInputSource objects. The index should be from 0 to getNumMouseSources() - 1. Out-of-range indexes will return a null pointer. In a traditional single-mouse system, there might be only one object. On a multi-touch system, there could be one input source per potential finger. */ MouseInputSource* getMouseSource (int index) const throw() { return mouseSources [index]; } /** Returns the main mouse input device that the system is using. @see getNumMouseSources() */ MouseInputSource& getMainMouseSource() const throw() { return *mouseSources.getUnchecked(0); } /** Returns the number of mouse-sources that are currently being dragged. In a traditional single-mouse system, this will be 0 or 1, depending on whether a juce component has the button down on it. In a multi-touch system, this could be any number from 0 to the number of simultaneous touches that can be detected. */ int getNumDraggingMouseSources() const throw(); /** Returns one of the mouse sources that's currently being dragged. The index should be between 0 and getNumDraggingMouseSources() - 1. If the index is out of range, or if no mice or fingers are down, this will return a null pointer. */ MouseInputSource* getDraggingMouseSource (int index) const throw(); /** Ensures that a non-stop stream of mouse-drag events will be sent during the current mouse-drag operation. This allows you to make sure that mouseDrag() events are sent continuously, even when the mouse isn't moving. This can be useful for things like auto-scrolling components when the mouse is near an edge. Call this method during a mouseDown() or mouseDrag() callback, specifying the minimum interval between consecutive mouse drag callbacks. The callbacks will continue until the mouse is released, and then the interval will be reset, so you need to make sure it's called every time you begin a drag event. Passing an interval of 0 or less will cancel the auto-repeat. @see mouseDrag */ void beginDragAutoRepeat (int millisecondsBetweenCallbacks); /** In a tablet device which can be turned around, this is used to inidicate the orientation. */ enum DisplayOrientation { upright = 1, /**< Indicates that the display is the normal way up. */ upsideDown = 2, /**< Indicates that the display is upside-down. */ rotatedClockwise = 4, /**< Indicates that the display is turned 90 degrees clockwise from its upright position. */ rotatedAntiClockwise = 8, /**< Indicates that the display is turned 90 degrees anti-clockwise from its upright position. */ allOrientations = 1 + 2 + 4 + 8 /**< A combination of all the orientation values */ }; /** In a tablet device which can be turned around, this returns the current orientation. */ DisplayOrientation getCurrentOrientation() const; /** Sets which orientations the display is allowed to auto-rotate to. For devices that support rotating desktops, this lets you specify which of the orientations your app can use. The parameter is a bitwise or-ed combination of the values in DisplayOrientation, and must contain at least one set bit. */ void setOrientationsEnabled (int allowedOrientations); /** Returns whether the display is allowed to auto-rotate to the given orientation. Each orientation can be enabled using setOrientationEnabled(). By default, all orientations are allowed. */ bool isOrientationEnabled (DisplayOrientation orientation) const throw(); /** Tells this object to refresh its idea of what the screen resolution is. (Called internally by the native code). */ void refreshMonitorSizes(); /** True if the OS supports semitransparent windows */ static bool canUseSemiTransparentWindows() throw(); private: static Desktop* instance; friend class Component; friend class ComponentPeer; friend class MouseInputSource; friend class MouseInputSourceInternal; friend class DeletedAtShutdown; friend class TopLevelWindowManager; OwnedArray mouseSources; void createMouseInputSources(); ListenerList mouseListeners; ListenerList focusListeners; Array desktopComponents; Array > monitorCoordsClipped, monitorCoordsUnclipped; Point lastFakeMouseMove; void sendMouseMove(); int mouseClickCounter; void incrementMouseClickCounter() throw(); ScopedPointer dragRepeater; Component* kioskModeComponent; Rectangle kioskComponentOriginalBounds; int allowedOrientations; ComponentAnimator animator; void timerCallback(); void resetTimer(); int getNumDisplayMonitors() const throw(); const Rectangle getDisplayMonitorCoordinates (int index, bool clippedToWorkArea) const throw(); void addDesktopComponent (Component* c); void removeDesktopComponent (Component* c); void componentBroughtToFront (Component* c); void triggerFocusCallback(); void handleAsyncUpdate(); Desktop(); ~Desktop(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Desktop); }; #endif // __JUCE_DESKTOP_JUCEHEADER__ /*** End of inlined file: juce_Desktop.h ***/ class KeyPressMappingSet; class ApplicationCommandManagerListener; /** One of these objects holds a list of all the commands your app can perform, and despatches these commands when needed. Application commands are a good way to trigger actions in your app, e.g. "Quit", "Copy", "Paste", etc. Menus, buttons and keypresses can all be given commands to invoke automatically, which means you don't have to handle the result of a menu or button click manually. Commands are despatched to ApplicationCommandTarget objects which can choose which events they want to handle. This architecture also allows for nested ApplicationCommandTargets, so that for example you could have two different objects, one inside the other, both of which can respond to a "delete" command. Depending on which one has focus, the command will be sent to the appropriate place, regardless of whether it was triggered by a menu, keypress or some other method. To set up your app to use commands, you'll need to do the following: - Create a global ApplicationCommandManager to hold the list of all possible commands. (This will also manage a set of key-mappings for them). - Make some of your UI components (or other objects) inherit from ApplicationCommandTarget. This allows the object to provide a list of commands that it can perform, and to handle them. - Register each type of command using ApplicationCommandManager::registerAllCommandsForTarget(), or ApplicationCommandManager::registerCommand(). - If you want key-presses to trigger your commands, use the ApplicationCommandManager::getKeyMappings() method to access the key-mapper object, which you will need to register as a key-listener in whatever top-level component you're using. See the KeyPressMappingSet class for more help about setting this up. - Use methods such as PopupMenu::addCommandItem() or Button::setCommandToTrigger() to cause these commands to be invoked automatically. - Commands can be invoked directly by your code using ApplicationCommandManager::invokeDirectly(). When a command is invoked, the ApplicationCommandManager will try to choose the best ApplicationCommandTarget to receive the specified command. To do this it will use the current keyboard focus to see which component might be interested, and will search the component hierarchy for those that also implement the ApplicationCommandTarget interface. If an ApplicationCommandTarget isn't interested in the command that is being invoked, then the next one in line will be tried (see the ApplicationCommandTarget::getNextCommandTarget() method), and so on until ApplicationCommandTarget::getNextCommandTarget() returns 0. At this point if the command still hasn't been performed, it will be passed to the current JUCEApplication object (which is itself an ApplicationCommandTarget). To exert some custom control over which ApplicationCommandTarget is chosen to invoke a command, you can override the ApplicationCommandManager::getFirstCommandTarget() method and choose the object yourself. @see ApplicationCommandTarget, ApplicationCommandInfo */ class JUCE_API ApplicationCommandManager : private AsyncUpdater, private FocusChangeListener { public: /** Creates an ApplicationCommandManager. Once created, you'll need to register all your app's commands with it, using ApplicationCommandManager::registerAllCommandsForTarget() or ApplicationCommandManager::registerCommand(). */ ApplicationCommandManager(); /** Destructor. Make sure that you don't delete this if pointers to it are still being used by objects such as PopupMenus or Buttons. */ virtual ~ApplicationCommandManager(); /** Clears the current list of all commands. Note that this will also clear the contents of the KeyPressMappingSet. */ void clearCommands(); /** Adds a command to the list of registered commands. @see registerAllCommandsForTarget */ void registerCommand (const ApplicationCommandInfo& newCommand); /** Adds all the commands that this target publishes to the manager's list. This will use ApplicationCommandTarget::getAllCommands() and ApplicationCommandTarget::getCommandInfo() to get details about all the commands that this target can do, and will call registerCommand() to add each one to the manger's list. @see registerCommand */ void registerAllCommandsForTarget (ApplicationCommandTarget* target); /** Removes the command with a specified ID. Note that this will also remove any key mappings that are mapped to the command. */ void removeCommand (CommandID commandID); /** This should be called to tell the manager that one of its registered commands may have changed its active status. Because the command manager only finds out whether a command is active or inactive by querying the current ApplicationCommandTarget, this is used to tell it that things may have changed. It allows things like buttons to update their enablement, etc. This method will cause an asynchronous call to ApplicationCommandManagerListener::applicationCommandListChanged() for any registered listeners. */ void commandStatusChanged(); /** Returns the number of commands that have been registered. @see registerCommand */ int getNumCommands() const throw() { return commands.size(); } /** Returns the details about one of the registered commands. The index is between 0 and (getNumCommands() - 1). */ const ApplicationCommandInfo* getCommandForIndex (int index) const throw() { return commands [index]; } /** Returns the details about a given command ID. This will search the list of registered commands for one with the given command ID number, and return its associated info. If no matching command is found, this will return 0. */ const ApplicationCommandInfo* getCommandForID (CommandID commandID) const throw(); /** Returns the name field for a command. An empty string is returned if no command with this ID has been registered. @see getDescriptionOfCommand */ const String getNameOfCommand (CommandID commandID) const throw(); /** Returns the description field for a command. An empty string is returned if no command with this ID has been registered. If the command has no description, this will return its short name field instead. @see getNameOfCommand */ const String getDescriptionOfCommand (CommandID commandID) const throw(); /** Returns the list of categories. This will go through all registered commands, and return a list of all the distict categoryName values from their ApplicationCommandInfo structure. @see getCommandsInCategory() */ const StringArray getCommandCategories() const; /** Returns a list of all the command UIDs in a particular category. @see getCommandCategories() */ const Array getCommandsInCategory (const String& categoryName) const; /** Returns the manager's internal set of key mappings. This object can be used to edit the keypresses. To actually link this object up to invoke commands when a key is pressed, see the comments for the KeyPressMappingSet class. @see KeyPressMappingSet */ KeyPressMappingSet* getKeyMappings() const throw() { return keyMappings; } /** Invokes the given command directly, sending it to the default target. This is just an easy way to call invoke() without having to fill out the InvocationInfo structure. */ bool invokeDirectly (CommandID commandID, bool asynchronously); /** Sends a command to the default target. This will choose a target using getFirstCommandTarget(), and send the specified command to it using the ApplicationCommandTarget::invoke() method. This means that if the first target can't handle the command, it will be passed on to targets further down the chain (see ApplicationCommandTarget::invoke() for more info). @param invocationInfo this must be correctly filled-in, describing the context for the invocation. @param asynchronously if false, the command will be performed before this method returns. If true, a message will be posted so that the command will be performed later on the message thread, and this method will return immediately. @see ApplicationCommandTarget::invoke */ bool invoke (const ApplicationCommandTarget::InvocationInfo& invocationInfo, bool asynchronously); /** Chooses the ApplicationCommandTarget to which a command should be sent. Whenever the manager needs to know which target a command should be sent to, it calls this method to determine the first one to try. By default, this method will return the target that was set by calling setFirstCommandTarget(). If no target is set, it will return the result of findDefaultComponentTarget(). If you need to make sure all commands go via your own custom target, then you can either use setFirstCommandTarget() to specify a single target, or override this method if you need more complex logic to choose one. It may return 0 if no targets are available. @see getTargetForCommand, invoke, invokeDirectly */ virtual ApplicationCommandTarget* getFirstCommandTarget (CommandID commandID); /** Sets a target to be returned by getFirstCommandTarget(). If this is set to 0, then getFirstCommandTarget() will by default return the result of findDefaultComponentTarget(). If you use this to set a target, make sure you call setFirstCommandTarget (0) before deleting the target object. */ void setFirstCommandTarget (ApplicationCommandTarget* newTarget) throw(); /** Tries to find the best target to use to perform a given command. This will call getFirstCommandTarget() to find the preferred target, and will check whether that target can handle the given command. If it can't, then it'll use ApplicationCommandTarget::getNextCommandTarget() to find the next one to try, and so on until no more are available. If no targets are found that can perform the command, this method will return 0. If a target is found, then it will get the target to fill-in the upToDateInfo structure with the latest info about that command, so that the caller can see whether the command is disabled, ticked, etc. */ ApplicationCommandTarget* getTargetForCommand (CommandID commandID, ApplicationCommandInfo& upToDateInfo); /** Registers a listener that will be called when various events occur. */ void addListener (ApplicationCommandManagerListener* listener); /** Deregisters a previously-added listener. */ void removeListener (ApplicationCommandManagerListener* listener); /** Looks for a suitable command target based on which Components have the keyboard focus. This is used by the default implementation of ApplicationCommandTarget::getFirstCommandTarget(), but is exposed here in case it's useful. It tries to pick the best ApplicationCommandTarget by looking at focused components, top level windows, etc., and using the findTargetForComponent() method. */ static ApplicationCommandTarget* findDefaultComponentTarget(); /** Examines this component and all its parents in turn, looking for the first one which is a ApplicationCommandTarget. Returns the first ApplicationCommandTarget that it finds, or 0 if none of them implement that class. */ static ApplicationCommandTarget* findTargetForComponent (Component* component); private: OwnedArray commands; ListenerList listeners; ScopedPointer keyMappings; ApplicationCommandTarget* firstTarget; void sendListenerInvokeCallback (const ApplicationCommandTarget::InvocationInfo& info); void handleAsyncUpdate(); void globalFocusChanged (Component*); #if JUCE_CATCH_DEPRECATED_CODE_MISUSE // This is just here to cause a compile error in old code that hasn't been changed to use the new // version of this method. virtual short getFirstCommandTarget() { return 0; } #endif JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ApplicationCommandManager); }; /** A listener that receives callbacks from an ApplicationCommandManager when commands are invoked or the command list is changed. @see ApplicationCommandManager::addListener, ApplicationCommandManager::removeListener */ class JUCE_API ApplicationCommandManagerListener { public: /** Destructor. */ virtual ~ApplicationCommandManagerListener() {} /** Called when an app command is about to be invoked. */ virtual void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info) = 0; /** Called when commands are registered or deregistered from the command manager, or when commands are made active or inactive. Note that if you're using this to watch for changes to whether a command is disabled, you'll need to make sure that ApplicationCommandManager::commandStatusChanged() is called whenever the status of your command might have changed. */ virtual void applicationCommandListChanged() = 0; }; #endif // __JUCE_APPLICATIONCOMMANDMANAGER_JUCEHEADER__ /*** End of inlined file: juce_ApplicationCommandManager.h ***/ #endif #ifndef __JUCE_APPLICATIONCOMMANDTARGET_JUCEHEADER__ #endif #ifndef __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ /*** Start of inlined file: juce_ApplicationProperties.h ***/ #ifndef __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ #define __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ /*** Start of inlined file: juce_PropertiesFile.h ***/ #ifndef __JUCE_PROPERTIESFILE_JUCEHEADER__ #define __JUCE_PROPERTIESFILE_JUCEHEADER__ /** Wrapper on a file that stores a list of key/value data pairs. Useful for storing application settings, etc. See the PropertySet class for the interfaces that read and write values. Not designed for very large amounts of data, as it keeps all the values in memory and writes them out to disk lazily when they are changed. Because this class derives from ChangeBroadcaster, ChangeListeners can be registered with it, and these will be signalled when a value changes. @see PropertySet */ class JUCE_API PropertiesFile : public PropertySet, public ChangeBroadcaster, private Timer { public: enum FileFormatOptions { ignoreCaseOfKeyNames = 1, storeAsBinary = 2, storeAsCompressedBinary = 4, storeAsXML = 8 }; /** Creates a PropertiesFile object. @param file the file to use @param millisecondsBeforeSaving if this is zero or greater, then after a value is changed, the object will wait for this amount of time and then save the file. If zero, the file will be written to disk immediately on being changed (which might be slow, as it'll re-write synchronously each time a value-change method is called). If it is less than zero, the file won't be saved until save() or saveIfNeeded() are explicitly called. @param optionFlags a combination of the flags in the FileFormatOptions enum, which specify the type of file to save, and other options. @param processLock an optional InterprocessLock object that will be used to prevent multiple threads or processes from writing to the file at the same time. The PropertiesFile will keep a pointer to this object but will not take ownership of it - the caller is responsible for making sure that the lock doesn't get deleted before the PropertiesFile has been deleted. */ PropertiesFile (const File& file, int millisecondsBeforeSaving, int optionFlags, InterProcessLock* processLock = 0); /** Destructor. When deleted, the file will first call saveIfNeeded() to flush any changes to disk. */ ~PropertiesFile(); /** Returns true if this file was created from a valid (or non-existent) file. If the file failed to load correctly because it was corrupt or had insufficient access, this will be false. */ bool isValidFile() const throw() { return loadedOk; } /** This will flush all the values to disk if they've changed since the last time they were saved. Returns false if it fails to write to the file for some reason (maybe because it's read-only or the directory doesn't exist or something). @see save */ bool saveIfNeeded(); /** This will force a write-to-disk of the current values, regardless of whether anything has changed since the last save. Returns false if it fails to write to the file for some reason (maybe because it's read-only or the directory doesn't exist or something). @see saveIfNeeded */ bool save(); /** Returns true if the properties have been altered since the last time they were saved. The file is flagged as needing to be saved when you change a value, but you can explicitly set this flag with setNeedsToBeSaved(). */ bool needsToBeSaved() const; /** Explicitly sets the flag to indicate whether the file needs saving or not. @see needsToBeSaved */ void setNeedsToBeSaved (bool needsToBeSaved); /** Returns the file that's being used. */ const File getFile() const { return file; } /** Handy utility to create a properties file in whatever the standard OS-specific location is for these things. This uses getDefaultAppSettingsFile() to decide what file to create, then creates a PropertiesFile object with the specified properties. See getDefaultAppSettingsFile() and the class's constructor for descriptions of what the parameters do. @see getDefaultAppSettingsFile */ static PropertiesFile* createDefaultAppPropertiesFile (const String& applicationName, const String& fileNameSuffix, const String& folderName, bool commonToAllUsers, int millisecondsBeforeSaving, int propertiesFileOptions, InterProcessLock* processLock = 0); /** Handy utility to choose a file in the standard OS-dependent location for application settings files. So on a Mac, this will return a file called: ~/Library/Preferences/[folderName]/[applicationName].[fileNameSuffix] On Windows it'll return something like: C:\\Documents and Settings\\username\\Application Data\\[folderName]\\[applicationName].[fileNameSuffix] On Linux it'll return ~/.[folderName]/[applicationName].[fileNameSuffix] If you pass an empty string as the folder name, it'll use the app name for this (or omit the folder name on the Mac). If commonToAllUsers is true, then this will return the same file for all users of the computer, regardless of the current user. If it is false, the file will be specific to only the current user. Use this to choose whether you're saving settings that are common or user-specific. */ static const File getDefaultAppSettingsFile (const String& applicationName, const String& fileNameSuffix, const String& folderName, bool commonToAllUsers); protected: virtual void propertyChanged(); private: File file; int timerInterval; const int options; bool loadedOk, needsWriting; InterProcessLock* processLock; typedef const ScopedPointer ProcessScopedLock; InterProcessLock::ScopedLockType* createProcessLock() const; void timerCallback(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertiesFile); }; #endif // __JUCE_PROPERTIESFILE_JUCEHEADER__ /*** End of inlined file: juce_PropertiesFile.h ***/ /** Manages a collection of properties. This is a slightly higher-level wrapper for PropertiesFile, which can be used as a singleton. It holds two different PropertiesFile objects internally, one for user-specific settings (stored in your user directory), and one for settings that are common to all users (stored in a folder accessible to all users). The class manages the creation of these files on-demand, allowing access via the getUserSettings() and getCommonSettings() methods. It also has a few handy methods like testWriteAccess() to check that the files can be saved. If you're using one of these as a singleton, then your app's start-up code should first of all call setStorageParameters() to tell it the parameters to use to create the properties files. @see PropertiesFile */ class JUCE_API ApplicationProperties : public DeletedAtShutdown { public: /** Creates an ApplicationProperties object. Before using it, you must call setStorageParameters() to give it the info it needs to create the property files. */ ApplicationProperties(); /** Destructor. */ ~ApplicationProperties(); juce_DeclareSingleton (ApplicationProperties, false) /** Gives the object the information it needs to create the appropriate properties files. See the comments for PropertiesFile::createDefaultAppPropertiesFile() for more info about how these parameters are used. */ void setStorageParameters (const String& applicationName, const String& fileNameSuffix, const String& folderName, int millisecondsBeforeSaving, int propertiesFileOptions, InterProcessLock* processLock = 0); /** Tests whether the files can be successfully written to, and can show an error message if not. Returns true if none of the tests fail. @param testUserSettings if true, the user settings file will be tested @param testCommonSettings if true, the common settings file will be tested @param showWarningDialogOnFailure if true, the method will show a helpful error message box if either of the tests fail */ bool testWriteAccess (bool testUserSettings, bool testCommonSettings, bool showWarningDialogOnFailure); /** Returns the user settings file. The first time this is called, it will create and load the properties file. Note that when you search the user PropertiesFile for a value that it doesn't contain, the common settings are used as a second-chance place to look. This is done via the PropertySet::setFallbackPropertySet() method - by default the common settings are set to the fallback for the user settings. @see getCommonSettings */ PropertiesFile* getUserSettings(); /** Returns the common settings file. The first time this is called, it will create and load the properties file. @param returnUserPropsIfReadOnly if this is true, and the common properties file is read-only (e.g. because the user doesn't have permission to write to shared files), then this will return the user settings instead, (like getUserSettings() would do). This is handy if you'd like to write a value to the common settings, but if that's no possible, then you'd rather write to the user settings than none at all. If returnUserPropsIfReadOnly is false, this method will always return the common settings, even if any changes to them can't be saved. @see getUserSettings */ PropertiesFile* getCommonSettings (bool returnUserPropsIfReadOnly); /** Saves both files if they need to be saved. @see PropertiesFile::saveIfNeeded */ bool saveIfNeeded(); /** Flushes and closes both files if they are open. This flushes any pending changes to disk with PropertiesFile::saveIfNeeded() and closes both files. They will then be re-opened the next time getUserSettings() or getCommonSettings() is called. */ void closeFiles(); private: ScopedPointer userProps, commonProps; String appName, fileSuffix, folderName; int msBeforeSaving, options; int commonSettingsAreReadOnly; InterProcessLock* processLock; void openFiles(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ApplicationProperties); }; #endif // __JUCE_APPLICATIONPROPERTIES_JUCEHEADER__ /*** End of inlined file: juce_ApplicationProperties.h ***/ #endif #ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ /*** Start of inlined file: juce_AiffAudioFormat.h ***/ #ifndef __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ #define __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ /*** Start of inlined file: juce_AudioFormat.h ***/ #ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ #define __JUCE_AUDIOFORMAT_JUCEHEADER__ /*** Start of inlined file: juce_AudioFormatReader.h ***/ #ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ #define __JUCE_AUDIOFORMATREADER_JUCEHEADER__ /*** Start of inlined file: juce_AudioDataConverters.h ***/ #ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ #define __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ /** This class a container which holds all the classes pertaining to the AudioData::Pointer audio sample format class. @see AudioData::Pointer. */ class JUCE_API AudioData { public: // These types can be used as the SampleFormat template parameter for the AudioData::Pointer class. class Int8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit integer packed data format. */ class UInt8; /**< Used as a template parameter for AudioData::Pointer. Indicates an 8-bit unsigned integer packed data format. */ class Int16; /**< Used as a template parameter for AudioData::Pointer. Indicates an 16-bit integer packed data format. */ class Int24; /**< Used as a template parameter for AudioData::Pointer. Indicates an 24-bit integer packed data format. */ class Int32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit integer packed data format. */ class Float32; /**< Used as a template parameter for AudioData::Pointer. Indicates an 32-bit float data format. */ // These types can be used as the Endianness template parameter for the AudioData::Pointer class. class BigEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in big-endian order. */ class LittleEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in little-endian order. */ class NativeEndian; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored in the CPU's native endianness. */ // These types can be used as the InterleavingType template parameter for the AudioData::Pointer class. class NonInterleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are stored contiguously. */ class Interleaved; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples are interleaved with a number of other channels. */ // These types can be used as the Constness template parameter for the AudioData::Pointer class. class NonConst; /**< Used as a template parameter for AudioData::Pointer. Indicates that the pointer can be used for non-const data. */ class Const; /**< Used as a template parameter for AudioData::Pointer. Indicates that the samples can only be used for const data.. */ #ifndef DOXYGEN class BigEndian { public: template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatBE(); } template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatBE (newValue); } template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32BE(); } template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32BE (newValue); } template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromBE (source); } enum { isBigEndian = 1 }; }; class LittleEndian { public: template static inline float getAsFloat (SampleFormatType& s) throw() { return s.getAsFloatLE(); } template static inline void setAsFloat (SampleFormatType& s, float newValue) throw() { s.setAsFloatLE (newValue); } template static inline int32 getAsInt32 (SampleFormatType& s) throw() { return s.getAsInt32LE(); } template static inline void setAsInt32 (SampleFormatType& s, int32 newValue) throw() { s.setAsInt32LE (newValue); } template static inline void copyFrom (DestType& dest, SourceType& source) throw() { dest.copyFromLE (source); } enum { isBigEndian = 0 }; }; #if JUCE_BIG_ENDIAN class NativeEndian : public BigEndian {}; #else class NativeEndian : public LittleEndian {}; #endif class Int8 { public: inline Int8 (void* data_) throw() : data (static_cast (data_)) {} inline void advance() throw() { ++data; } inline void skip (int numSamples) throw() { data += numSamples; } inline float getAsFloatLE() const throw() { return (float) (*data * (1.0 / (1.0 + maxValue))); } inline float getAsFloatBE() const throw() { return getAsFloatLE(); } inline void setAsFloatLE (float newValue) throw() { *data = (int8) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))); } inline void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); } inline int32 getAsInt32LE() const throw() { return (int) (*data << 24); } inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); } inline void setAsInt32LE (int newValue) throw() { *data = (int8) (newValue >> 24); } inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); } inline void clear() throw() { *data = 0; } inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;} template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } inline void copyFromSameType (Int8& source) throw() { *data = *source.data; } int8* data; enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 }; }; class UInt8 { public: inline UInt8 (void* data_) throw() : data (static_cast (data_)) {} inline void advance() throw() { ++data; } inline void skip (int numSamples) throw() { data += numSamples; } inline float getAsFloatLE() const throw() { return (float) ((*data - 128) * (1.0 / (1.0 + maxValue))); } inline float getAsFloatBE() const throw() { return getAsFloatLE(); } inline void setAsFloatLE (float newValue) throw() { *data = (uint8) jlimit (0, 255, 128 + roundToInt (newValue * (1.0 + maxValue))); } inline void setAsFloatBE (float newValue) throw() { setAsFloatLE (newValue); } inline int32 getAsInt32LE() const throw() { return (int) ((*data - 128) << 24); } inline int32 getAsInt32BE() const throw() { return getAsInt32LE(); } inline void setAsInt32LE (int newValue) throw() { *data = (uint8) (128 + (newValue >> 24)); } inline void setAsInt32BE (int newValue) throw() { setAsInt32LE (newValue); } inline void clear() throw() { *data = 128; } inline void clearMultiple (int num) throw() { memset (data, 128, num) ;} template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } inline void copyFromSameType (UInt8& source) throw() { *data = *source.data; } uint8* data; enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 }; }; class Int16 { public: inline Int16 (void* data_) throw() : data (static_cast (data_)) {} inline void advance() throw() { ++data; } inline void skip (int numSamples) throw() { data += numSamples; } inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); } inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); } inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int16) -maxValue, (int16) maxValue, (int16) roundToInt (newValue * (1.0 + maxValue)))); } inline int32 getAsInt32LE() const throw() { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); } inline int32 getAsInt32BE() const throw() { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); } inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); } inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); } inline void clear() throw() { *data = 0; } inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;} template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } inline void copyFromSameType (Int16& source) throw() { *data = *source.data; } uint16* data; enum { bytesPerSample = 2, maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 }; }; class Int24 { public: inline Int24 (void* data_) throw() : data (static_cast (data_)) {} inline void advance() throw() { data += 3; } inline void skip (int numSamples) throw() { data += 3 * numSamples; } inline float getAsFloatLE() const throw() { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } inline float getAsFloatBE() const throw() { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + maxValue))); } inline void setAsFloatLE (float newValue) throw() { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } inline void setAsFloatBE (float newValue) throw() { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); } inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::littleEndian24Bit (data) << 8; } inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::bigEndian24Bit (data) << 8; } inline void setAsInt32LE (int32 newValue) throw() { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); } inline void setAsInt32BE (int32 newValue) throw() { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); } inline void clear() throw() { data[0] = 0; data[1] = 0; data[2] = 0; } inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;} template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } inline void copyFromSameType (Int24& source) throw() { data[0] = source.data[0]; data[1] = source.data[1]; data[2] = source.data[2]; } char* data; enum { bytesPerSample = 3, maxValue = 0x7fffff, resolution = (1 << 8), isFloat = 0 }; }; class Int32 { public: inline Int32 (void* data_) throw() : data (static_cast (data_)) {} inline void advance() throw() { ++data; } inline void skip (int numSamples) throw() { data += numSamples; } inline float getAsFloatLE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); } inline float getAsFloatBE() const throw() { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); } inline void setAsFloatLE (float newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } inline void setAsFloatBE (float newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); } inline int32 getAsInt32LE() const throw() { return (int32) ByteOrder::swapIfBigEndian (*data); } inline int32 getAsInt32BE() const throw() { return (int32) ByteOrder::swapIfLittleEndian (*data); } inline void setAsInt32LE (int32 newValue) throw() { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); } inline void setAsInt32BE (int32 newValue) throw() { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); } inline void clear() throw() { *data = 0; } inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;} template inline void copyFromLE (SourceType& source) throw() { setAsInt32LE (source.getAsInt32()); } template inline void copyFromBE (SourceType& source) throw() { setAsInt32BE (source.getAsInt32()); } inline void copyFromSameType (Int32& source) throw() { *data = *source.data; } uint32* data; enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = 1, isFloat = 0 }; }; class Float32 { public: inline Float32 (void* data_) throw() : data (static_cast (data_)) {} inline void advance() throw() { ++data; } inline void skip (int numSamples) throw() { data += numSamples; } #if JUCE_BIG_ENDIAN inline float getAsFloatBE() const throw() { return *data; } inline void setAsFloatBE (float newValue) throw() { *data = newValue; } inline float getAsFloatLE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } inline void setAsFloatLE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } #else inline float getAsFloatLE() const throw() { return *data; } inline void setAsFloatLE (float newValue) throw() { *data = newValue; } inline float getAsFloatBE() const throw() { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; } inline void setAsFloatBE (float newValue) throw() { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); } #endif inline int32 getAsInt32LE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatLE()) * (1.0 + maxValue)); } inline int32 getAsInt32BE() const throw() { return (int32) roundToInt (jlimit (-1.0f, 1.0f, getAsFloatBE()) * (1.0 + maxValue)); } inline void setAsInt32LE (int32 newValue) throw() { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } inline void setAsInt32BE (int32 newValue) throw() { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); } inline void clear() throw() { *data = 0; } inline void clearMultiple (int num) throw() { zeromem (data, num * bytesPerSample) ;} template inline void copyFromLE (SourceType& source) throw() { setAsFloatLE (source.getAsFloat()); } template inline void copyFromBE (SourceType& source) throw() { setAsFloatBE (source.getAsFloat()); } inline void copyFromSameType (Float32& source) throw() { *data = *source.data; } float* data; enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 }; }; class NonInterleaved { public: inline NonInterleaved() throw() {} inline NonInterleaved (const NonInterleaved&) throw() {} inline NonInterleaved (const int) throw() {} inline void copyFrom (const NonInterleaved&) throw() {} template inline void advanceData (SampleFormatType& s) throw() { s.advance(); } template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numSamples); } template inline void clear (SampleFormatType& s, int numSamples) throw() { s.clearMultiple (numSamples); } template inline static int getNumBytesBetweenSamples (const SampleFormatType&) throw() { return SampleFormatType::bytesPerSample; } enum { isInterleavedType = 0, numInterleavedChannels = 1 }; }; class Interleaved { public: inline Interleaved() throw() : numInterleavedChannels (1) {} inline Interleaved (const Interleaved& other) throw() : numInterleavedChannels (other.numInterleavedChannels) {} inline Interleaved (const int numInterleavedChannels_) throw() : numInterleavedChannels (numInterleavedChannels_) {} inline void copyFrom (const Interleaved& other) throw() { numInterleavedChannels = other.numInterleavedChannels; } template inline void advanceData (SampleFormatType& s) throw() { s.skip (numInterleavedChannels); } template inline void advanceDataBy (SampleFormatType& s, int numSamples) throw() { s.skip (numInterleavedChannels * numSamples); } template inline void clear (SampleFormatType& s, int numSamples) throw() { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } } template inline int getNumBytesBetweenSamples (const SampleFormatType&) const throw() { return numInterleavedChannels * SampleFormatType::bytesPerSample; } int numInterleavedChannels; enum { isInterleavedType = 1 }; }; class NonConst { public: typedef void VoidType; static inline void* toVoidPtr (VoidType* v) throw() { return v; } enum { isConst = 0 }; }; class Const { public: typedef const void VoidType; static inline void* toVoidPtr (VoidType* v) throw() { return const_cast (v); } enum { isConst = 1 }; }; #endif /** A pointer to a block of audio data with a particular encoding. This object can be used to read and write from blocks of encoded audio samples. To create one, you specify the audio format as a series of template parameters, e.g. @code // this creates a pointer for reading from a const array of 16-bit little-endian packed samples. AudioData::Pointer pointer (someRawAudioData); // These methods read the sample that is being pointed to float firstSampleAsFloat = pointer.getAsFloat(); int32 firstSampleAsInt = pointer.getAsInt32(); ++pointer; // moves the pointer to the next sample. pointer += 3; // skips the next 3 samples. @endcode The convertSamples() method lets you copy a range of samples from one format to another, automatically converting its format. @see AudioData::Converter */ template class Pointer { public: /** Creates a non-interleaved pointer from some raw data in the appropriate format. This constructor is only used if you've specified the AudioData::NonInterleaved option - for interleaved formats, use the constructor that also takes a number of channels. */ Pointer (typename Constness::VoidType* sourceData) throw() : data (Constness::toVoidPtr (sourceData)) { // If you're using interleaved data, call the other constructor! If you're using non-interleaved data, // you should pass NonInterleaved as the template parameter for the interleaving type! static_jassert (InterleavingType::isInterleavedType == 0); } /** Creates a pointer from some raw data in the appropriate format with the specified number of interleaved channels. For non-interleaved data, use the other constructor. */ Pointer (typename Constness::VoidType* sourceData, int numInterleavedChannels) throw() : data (Constness::toVoidPtr (sourceData)), interleaving (numInterleavedChannels) { } /** Creates a copy of another pointer. */ Pointer (const Pointer& other) throw() : data (other.data), interleaving (other.interleaving) { } Pointer& operator= (const Pointer& other) throw() { data = other.data; interleaving.copyFrom (other.interleaving); return *this; } /** Returns the value of the first sample as a floating point value. The value will be in the range -1.0 to 1.0 for integer formats. For floating point formats, the value could be outside that range, although -1 to 1 is the standard range. */ inline float getAsFloat() const throw() { return Endianness::getAsFloat (data); } /** Sets the value of the first sample as a floating point value. (This method can only be used if the AudioData::NonConst option was used). The value should be in the range -1.0 to 1.0 - for integer formats, values outside that range will be clipped. For floating point formats, any value passed in here will be written directly, although -1 to 1 is the standard range. */ inline void setAsFloat (float newValue) throw() { static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! Endianness::setAsFloat (data, newValue); } /** Returns the value of the first sample as a 32-bit integer. The value returned will be in the range 0x80000000 to 0x7fffffff, and shorter values will be shifted to fill this range (e.g. if you're reading from 24-bit data, the values will be shifted up by 8 bits when returned here). If the source data is floating point, values beyond -1.0 to 1.0 will be clipped so that -1.0 maps onto -0x7fffffff and 1.0 maps to 0x7fffffff. */ inline int32 getAsInt32() const throw() { return Endianness::getAsInt32 (data); } /** Sets the value of the first sample as a 32-bit integer. This will be mapped to the range of the format that is being written - see getAsInt32(). */ inline void setAsInt32 (int32 newValue) throw() { static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! Endianness::setAsInt32 (data, newValue); } /** Moves the pointer along to the next sample. */ inline Pointer& operator++() throw() { advance(); return *this; } /** Moves the pointer back to the previous sample. */ inline Pointer& operator--() throw() { interleaving.advanceDataBy (data, -1); return *this; } /** Adds a number of samples to the pointer's position. */ Pointer& operator+= (int samplesToJump) throw() { interleaving.advanceDataBy (data, samplesToJump); return *this; } /** Writes a stream of samples into this pointer from another pointer. This will copy the specified number of samples, converting between formats appropriately. */ void convertSamples (Pointer source, int numSamples) const throw() { static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! Pointer dest (*this); while (--numSamples >= 0) { dest.data.copyFromSameType (source.data); dest.advance(); source.advance(); } } /** Writes a stream of samples into this pointer from another pointer. This will copy the specified number of samples, converting between formats appropriately. */ template void convertSamples (OtherPointerType source, int numSamples) const throw() { static_jassert (Constness::isConst == 0); // trying to write to a const pointer! For a writeable one, use AudioData::NonConst instead! Pointer dest (*this); if (source.getRawData() != getRawData() || source.getNumBytesBetweenSamples() >= getNumBytesBetweenSamples()) { while (--numSamples >= 0) { Endianness::copyFrom (dest.data, source); dest.advance(); ++source; } } else // copy backwards if we're increasing the sample width.. { dest += numSamples; source += numSamples; while (--numSamples >= 0) Endianness::copyFrom ((--dest).data, --source); } } /** Sets a number of samples to zero. */ void clearSamples (int numSamples) const throw() { Pointer dest (*this); dest.interleaving.clear (dest.data, numSamples); } /** Returns true if the pointer is using a floating-point format. */ static bool isFloatingPoint() throw() { return (bool) SampleFormat::isFloat; } /** Returns true if the format is big-endian. */ static bool isBigEndian() throw() { return (bool) Endianness::isBigEndian; } /** Returns the number of bytes in each sample (ignoring the number of interleaved channels). */ static int getBytesPerSample() throw() { return (int) SampleFormat::bytesPerSample; } /** Returns the number of interleaved channels in the format. */ int getNumInterleavedChannels() const throw() { return (int) this->numInterleavedChannels; } /** Returns the number of bytes between the start address of each sample. */ int getNumBytesBetweenSamples() const throw() { return interleaving.getNumBytesBetweenSamples (data); } /** Returns the accuracy of this format when represented as a 32-bit integer. This is the smallest number above 0 that can be represented in the sample format, converted to a 32-bit range. E,g. if the format is 8-bit, its resolution is 0x01000000; if the format is 24-bit, its resolution is 0x100. */ static int get32BitResolution() throw() { return (int) SampleFormat::resolution; } /** Returns a pointer to the underlying data. */ const void* getRawData() const throw() { return data.data; } private: SampleFormat data; InterleavingType interleaving; // annoyingly, making the interleaving type a superclass to take // advantage of EBCO causes an internal compiler error in VC6.. inline void advance() throw() { interleaving.advanceData (data); } Pointer operator++ (int); // private to force you to use the more efficient pre-increment! Pointer operator-- (int); }; /** A base class for objects that are used to convert between two different sample formats. The AudioData::ConverterInstance implements this base class and can be templated, so you can create an instance that converts between two particular formats, and then store this in the abstract base class. @see AudioData::ConverterInstance */ class Converter { public: virtual ~Converter() {} /** Converts a sequence of samples from the converter's source format into the dest format. */ virtual void convertSamples (void* destSamples, const void* sourceSamples, int numSamples) const = 0; /** Converts a sequence of samples from the converter's source format into the dest format. This method takes sub-channel indexes, which can be used with interleaved formats in order to choose a particular sub-channel of the data to be used. */ virtual void convertSamples (void* destSamples, int destSubChannel, const void* sourceSamples, int sourceSubChannel, int numSamples) const = 0; }; /** A class that converts between two templated AudioData::Pointer types, and which implements the AudioData::Converter interface. This can be used as a concrete instance of the AudioData::Converter abstract class. @see AudioData::Converter */ template class ConverterInstance : public Converter { public: ConverterInstance (int numSourceChannels = 1, int numDestChannels = 1) : sourceChannels (numSourceChannels), destChannels (numDestChannels) {} ~ConverterInstance() {} void convertSamples (void* dest, const void* source, int numSamples) const { SourceSampleType s (source, sourceChannels); DestSampleType d (dest, destChannels); d.convertSamples (s, numSamples); } void convertSamples (void* dest, int destSubChannel, const void* source, int sourceSubChannel, int numSamples) const { jassert (destSubChannel < destChannels && sourceSubChannel < sourceChannels); SourceSampleType s (addBytesToPointer (source, sourceSubChannel * SourceSampleType::getBytesPerSample()), sourceChannels); DestSampleType d (addBytesToPointer (dest, destSubChannel * DestSampleType::getBytesPerSample()), destChannels); d.convertSamples (s, numSamples); } private: JUCE_DECLARE_NON_COPYABLE (ConverterInstance); const int sourceChannels, destChannels; }; }; /** A set of routines to convert buffers of 32-bit floating point data to and from various integer formats. Note that these functions are deprecated - the AudioData class provides a much more flexible set of conversion classes now. */ class JUCE_API AudioDataConverters { public: static void convertFloatToInt16LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 2); static void convertFloatToInt16BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 2); static void convertFloatToInt24LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 3); static void convertFloatToInt24BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 3); static void convertFloatToInt32LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); static void convertFloatToInt32BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); static void convertFloatToFloat32LE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); static void convertFloatToFloat32BE (const float* source, void* dest, int numSamples, int destBytesPerSample = 4); static void convertInt16LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 2); static void convertInt16BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 2); static void convertInt24LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 3); static void convertInt24BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 3); static void convertInt32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); static void convertInt32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); static void convertFloat32LEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); static void convertFloat32BEToFloat (const void* source, float* dest, int numSamples, int srcBytesPerSample = 4); enum DataFormat { int16LE, int16BE, int24LE, int24BE, int32LE, int32BE, float32LE, float32BE, }; static void convertFloatToFormat (DataFormat destFormat, const float* source, void* dest, int numSamples); static void convertFormatToFloat (DataFormat sourceFormat, const void* source, float* dest, int numSamples); static void interleaveSamples (const float** source, float* dest, int numSamples, int numChannels); static void deinterleaveSamples (const float* source, float** dest, int numSamples, int numChannels); private: AudioDataConverters(); JUCE_DECLARE_NON_COPYABLE (AudioDataConverters); }; #endif // __JUCE_AUDIODATACONVERTERS_JUCEHEADER__ /*** End of inlined file: juce_AudioDataConverters.h ***/ class AudioFormat; /** Reads samples from an audio file stream. A subclass that reads a specific type of audio format will be created by an AudioFormat object. @see AudioFormat, AudioFormatWriter */ class JUCE_API AudioFormatReader { protected: /** Creates an AudioFormatReader object. @param sourceStream the stream to read from - this will be deleted by this object when it is no longer needed. (Some specialised readers might not use this parameter and can leave it as 0). @param formatName the description that will be returned by the getFormatName() method */ AudioFormatReader (InputStream* sourceStream, const String& formatName); public: /** Destructor. */ virtual ~AudioFormatReader(); /** Returns a description of what type of format this is. E.g. "AIFF" */ const String getFormatName() const throw() { return formatName; } /** Reads samples from the stream. @param destSamples an array of buffers into which the sample data for each channel will be written. If the format is fixed-point, each channel will be written as an array of 32-bit signed integers using the full range -0x80000000 to 0x7fffffff, regardless of the source's bit-depth. If it is a floating-point format, you should cast the resulting array to a (float**) to get the values (in the range -1.0 to 1.0 or beyond) If the format is stereo, then destSamples[0] is the left channel data, and destSamples[1] is the right channel. The numDestChannels parameter indicates how many pointers this array contains, but some of these pointers can be null if you don't want to read data for some of the channels @param numDestChannels the number of array elements in the destChannels array @param startSampleInSource the position in the audio file or stream at which the samples should be read, as a number of samples from the start of the stream. It's ok for this to be beyond the start or end of the available data - any samples that are out-of-range will be returned as zeros. @param numSamplesToRead the number of samples to read. If this is greater than the number of samples that the file or stream contains. the result will be padded with zeros @param fillLeftoverChannelsWithCopies if true, this indicates that if there's no source data available for some of the channels that you pass in, then they should be filled with copies of valid source channels. E.g. if you're reading a mono file and you pass 2 channels to this method, then if fillLeftoverChannelsWithCopies is true, both destination channels will be filled with the same data from the file's single channel. If fillLeftoverChannelsWithCopies was false, then only the first channel would be filled with the file's contents, and the second would be cleared. If there are many channels, e.g. you try to read 4 channels from a stereo file, then the last 3 would all end up with copies of the same data. @returns true if the operation succeeded, false if there was an error. Note that reading sections of data beyond the extent of the stream isn't an error - the reader should just return zeros for these regions @see readMaxLevels */ bool read (int* const* destSamples, int numDestChannels, int64 startSampleInSource, int numSamplesToRead, bool fillLeftoverChannelsWithCopies); /** Finds the highest and lowest sample levels from a section of the audio stream. This will read a block of samples from the stream, and measure the highest and lowest sample levels from the channels in that section, returning these as normalised floating-point levels. @param startSample the offset into the audio stream to start reading from. It's ok for this to be beyond the start or end of the stream. @param numSamples how many samples to read @param lowestLeft on return, this is the lowest absolute sample from the left channel @param highestLeft on return, this is the highest absolute sample from the left channel @param lowestRight on return, this is the lowest absolute sample from the right channel (if there is one) @param highestRight on return, this is the highest absolute sample from the right channel (if there is one) @see read */ virtual void readMaxLevels (int64 startSample, int64 numSamples, float& lowestLeft, float& highestLeft, float& lowestRight, float& highestRight); /** Scans the source looking for a sample whose magnitude is in a specified range. This will read from the source, either forwards or backwards between two sample positions, until it finds a sample whose magnitude lies between two specified levels. If it finds a suitable sample, it returns its position; if not, it will return -1. There's also a minimumConsecutiveSamples setting to help avoid spikes or zero-crossing points when you're searching for a continuous range of samples @param startSample the first sample to look at @param numSamplesToSearch the number of samples to scan. If this value is negative, the search will go backwards @param magnitudeRangeMinimum the lowest magnitude (inclusive) that is considered a hit, from 0 to 1.0 @param magnitudeRangeMaximum the highest magnitude (inclusive) that is considered a hit, from 0 to 1.0 @param minimumConsecutiveSamples if this is > 0, the method will only look for a sequence of this many consecutive samples, all of which lie within the target range. When it finds such a sequence, it returns the position of the first in-range sample it found (i.e. the earliest one if scanning forwards, the latest one if scanning backwards) */ int64 searchForLevel (int64 startSample, int64 numSamplesToSearch, double magnitudeRangeMinimum, double magnitudeRangeMaximum, int minimumConsecutiveSamples); /** The sample-rate of the stream. */ double sampleRate; /** The number of bits per sample, e.g. 16, 24, 32. */ unsigned int bitsPerSample; /** The total number of samples in the audio stream. */ int64 lengthInSamples; /** The total number of channels in the audio stream. */ unsigned int numChannels; /** Indicates whether the data is floating-point or fixed. */ bool usesFloatingPointData; /** A set of metadata values that the reader has pulled out of the stream. Exactly what these values are depends on the format, so you can check out the format implementation code to see what kind of stuff they understand. */ StringPairArray metadataValues; /** The input stream, for use by subclasses. */ InputStream* input; /** Subclasses must implement this method to perform the low-level read operation. Callers should use read() instead of calling this directly. @param destSamples the array of destination buffers to fill. Some of these pointers may be null @param numDestChannels the number of items in the destSamples array. This value is guaranteed not to be greater than the number of channels that this reader object contains @param startOffsetInDestBuffer the number of samples from the start of the dest data at which to begin writing @param startSampleInFile the number of samples into the source data at which to begin reading. This value is guaranteed to be >= 0. @param numSamples the number of samples to read */ virtual bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples) = 0; protected: /** Used by AudioFormatReader subclasses to copy data to different formats. */ template struct ReadHelper { typedef AudioData::Pointer DestType; typedef AudioData::Pointer SourceType; static void read (int** destData, int destOffset, int numDestChannels, const void* sourceData, int numSourceChannels, int numSamples) throw() { for (int i = 0; i < numDestChannels; ++i) { if (destData[i] != 0) { DestType dest (destData[i]); dest += destOffset; if (i < numSourceChannels) dest.convertSamples (SourceType (addBytesToPointer (sourceData, i * SourceType::getBytesPerSample()), numSourceChannels), numSamples); else dest.clearSamples (numSamples); } } } }; private: String formatName; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioFormatReader); }; #endif // __JUCE_AUDIOFORMATREADER_JUCEHEADER__ /*** End of inlined file: juce_AudioFormatReader.h ***/ /*** Start of inlined file: juce_AudioFormatWriter.h ***/ #ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ #define __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ /*** Start of inlined file: juce_AudioSource.h ***/ #ifndef __JUCE_AUDIOSOURCE_JUCEHEADER__ #define __JUCE_AUDIOSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_AudioSampleBuffer.h ***/ #ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ #define __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ class AudioFormatReader; class AudioFormatWriter; /** A multi-channel buffer of 32-bit floating point audio samples. */ class JUCE_API AudioSampleBuffer { public: /** Creates a buffer with a specified number of channels and samples. The contents of the buffer will initially be undefined, so use clear() to set all the samples to zero. The buffer will allocate its memory internally, and this will be released when the buffer is deleted. */ AudioSampleBuffer (int numChannels, int numSamples) throw(); /** Creates a buffer using a pre-allocated block of memory. Note that if the buffer is resized or its number of channels is changed, it will re-allocate memory internally and copy the existing data to this new area, so it will then stop directly addressing this memory. @param dataToReferTo a pre-allocated array containing pointers to the data for each channel that should be used by this buffer. The buffer will only refer to this memory, it won't try to delete it when the buffer is deleted or resized. @param numChannels the number of channels to use - this must correspond to the number of elements in the array passed in @param numSamples the number of samples to use - this must correspond to the size of the arrays passed in */ AudioSampleBuffer (float** dataToReferTo, int numChannels, int numSamples) throw(); /** Copies another buffer. This buffer will make its own copy of the other's data, unless the buffer was created using an external data buffer, in which case boths buffers will just point to the same shared block of data. */ AudioSampleBuffer (const AudioSampleBuffer& other) throw(); /** Copies another buffer onto this one. This buffer's size will be changed to that of the other buffer. */ AudioSampleBuffer& operator= (const AudioSampleBuffer& other) throw(); /** Destructor. This will free any memory allocated by the buffer. */ virtual ~AudioSampleBuffer() throw(); /** Returns the number of channels of audio data that this buffer contains. @see getSampleData */ int getNumChannels() const throw() { return numChannels; } /** Returns the number of samples allocated in each of the buffer's channels. @see getSampleData */ int getNumSamples() const throw() { return size; } /** Returns a pointer one of the buffer's channels. For speed, this doesn't check whether the channel number is out of range, so be careful when using it! */ float* getSampleData (const int channelNumber) const throw() { jassert (isPositiveAndBelow (channelNumber, numChannels)); return channels [channelNumber]; } /** Returns a pointer to a sample in one of the buffer's channels. For speed, this doesn't check whether the channel and sample number are out-of-range, so be careful when using it! */ float* getSampleData (const int channelNumber, const int sampleOffset) const throw() { jassert (isPositiveAndBelow (channelNumber, numChannels)); jassert (isPositiveAndBelow (sampleOffset, size)); return channels [channelNumber] + sampleOffset; } /** Returns an array of pointers to the channels in the buffer. Don't modify any of the pointers that are returned, and bear in mind that these will become invalid if the buffer is resized. */ float** getArrayOfChannels() const throw() { return channels; } /** Changes the buffer's size or number of channels. This can expand or contract the buffer's length, and add or remove channels. If keepExistingContent is true, it will try to preserve as much of the old data as it can in the new buffer. If clearExtraSpace is true, then any extra channels or space that is allocated will be also be cleared. If false, then this space is left uninitialised. If avoidReallocating is true, then changing the buffer's size won't reduce the amount of memory that is currently allocated (but it will still increase it if the new size is bigger than the amount it currently has). If this is false, then a new allocation will be done so that the buffer uses takes up the minimum amount of memory that it needs. */ void setSize (int newNumChannels, int newNumSamples, bool keepExistingContent = false, bool clearExtraSpace = false, bool avoidReallocating = false) throw(); /** Makes this buffer point to a pre-allocated set of channel data arrays. There's also a constructor that lets you specify arrays like this, but this lets you change the channels dynamically. Note that if the buffer is resized or its number of channels is changed, it will re-allocate memory internally and copy the existing data to this new area, so it will then stop directly addressing this memory. @param dataToReferTo a pre-allocated array containing pointers to the data for each channel that should be used by this buffer. The buffer will only refer to this memory, it won't try to delete it when the buffer is deleted or resized. @param numChannels the number of channels to use - this must correspond to the number of elements in the array passed in @param numSamples the number of samples to use - this must correspond to the size of the arrays passed in */ void setDataToReferTo (float** dataToReferTo, int numChannels, int numSamples) throw(); /** Clears all the samples in all channels. */ void clear() throw(); /** Clears a specified region of all the channels. For speed, this doesn't check whether the channel and sample number are in-range, so be careful! */ void clear (int startSample, int numSamples) throw(); /** Clears a specified region of just one channel. For speed, this doesn't check whether the channel and sample number are in-range, so be careful! */ void clear (int channel, int startSample, int numSamples) throw(); /** Applies a gain multiple to a region of one channel. For speed, this doesn't check whether the channel and sample number are in-range, so be careful! */ void applyGain (int channel, int startSample, int numSamples, float gain) throw(); /** Applies a gain multiple to a region of all the channels. For speed, this doesn't check whether the sample numbers are in-range, so be careful! */ void applyGain (int startSample, int numSamples, float gain) throw(); /** Applies a range of gains to a region of a channel. The gain that is applied to each sample will vary from startGain on the first sample to endGain on the last Sample, so it can be used to do basic fades. For speed, this doesn't check whether the sample numbers are in-range, so be careful! */ void applyGainRamp (int channel, int startSample, int numSamples, float startGain, float endGain) throw(); /** Adds samples from another buffer to this one. @param destChannel the channel within this buffer to add the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to add from @param sourceChannel the channel within the source buffer to read from @param sourceStartSample the offset within the source buffer's channel to start reading samples from @param numSamples the number of samples to process @param gainToApplyToSource an optional gain to apply to the source samples before they are added to this buffer's samples @see copyFrom */ void addFrom (int destChannel, int destStartSample, const AudioSampleBuffer& source, int sourceChannel, int sourceStartSample, int numSamples, float gainToApplyToSource = 1.0f) throw(); /** Adds samples from an array of floats to one of the channels. @param destChannel the channel within this buffer to add the samples to @param destStartSample the start sample within this buffer's channel @param source the source data to use @param numSamples the number of samples to process @param gainToApplyToSource an optional gain to apply to the source samples before they are added to this buffer's samples @see copyFrom */ void addFrom (int destChannel, int destStartSample, const float* source, int numSamples, float gainToApplyToSource = 1.0f) throw(); /** Adds samples from an array of floats, applying a gain ramp to them. @param destChannel the channel within this buffer to add the samples to @param destStartSample the start sample within this buffer's channel @param source the source data to use @param numSamples the number of samples to process @param startGain the gain to apply to the first sample (this is multiplied with the source samples before they are added to this buffer) @param endGain the gain to apply to the final sample. The gain is linearly interpolated between the first and last samples. */ void addFromWithRamp (int destChannel, int destStartSample, const float* source, int numSamples, float startGain, float endGain) throw(); /** Copies samples from another buffer to this one. @param destChannel the channel within this buffer to copy the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to read from @param sourceChannel the channel within the source buffer to read from @param sourceStartSample the offset within the source buffer's channel to start reading samples from @param numSamples the number of samples to process @see addFrom */ void copyFrom (int destChannel, int destStartSample, const AudioSampleBuffer& source, int sourceChannel, int sourceStartSample, int numSamples) throw(); /** Copies samples from an array of floats into one of the channels. @param destChannel the channel within this buffer to copy the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to read from @param numSamples the number of samples to process @see addFrom */ void copyFrom (int destChannel, int destStartSample, const float* source, int numSamples) throw(); /** Copies samples from an array of floats into one of the channels, applying a gain to it. @param destChannel the channel within this buffer to copy the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to read from @param numSamples the number of samples to process @param gain the gain to apply @see addFrom */ void copyFrom (int destChannel, int destStartSample, const float* source, int numSamples, float gain) throw(); /** Copies samples from an array of floats into one of the channels, applying a gain ramp. @param destChannel the channel within this buffer to copy the samples to @param destStartSample the start sample within this buffer's channel @param source the source buffer to read from @param numSamples the number of samples to process @param startGain the gain to apply to the first sample (this is multiplied with the source samples before they are copied to this buffer) @param endGain the gain to apply to the final sample. The gain is linearly interpolated between the first and last samples. @see addFrom */ void copyFromWithRamp (int destChannel, int destStartSample, const float* source, int numSamples, float startGain, float endGain) throw(); /** Finds the highest and lowest sample values in a given range. @param channel the channel to read from @param startSample the start sample within the channel @param numSamples the number of samples to check @param minVal on return, the lowest value that was found @param maxVal on return, the highest value that was found */ void findMinMax (int channel, int startSample, int numSamples, float& minVal, float& maxVal) const throw(); /** Finds the highest absolute sample value within a region of a channel. */ float getMagnitude (int channel, int startSample, int numSamples) const throw(); /** Finds the highest absolute sample value within a region on all channels. */ float getMagnitude (int startSample, int numSamples) const throw(); /** Returns the root mean squared level for a region of a channel. */ float getRMSLevel (int channel, int startSample, int numSamples) const throw(); /** Fills a section of the buffer using an AudioReader as its source. This will convert the reader's fixed- or floating-point data to the buffer's floating-point format, and will try to intelligently cope with mismatches between the number of channels in the reader and the buffer. @see writeToAudioWriter */ void readFromAudioReader (AudioFormatReader* reader, int startSample, int numSamples, int readerStartSample, bool useReaderLeftChan, bool useReaderRightChan); /** Writes a section of this buffer to an audio writer. This saves you having to mess about with channels or floating/fixed point conversion. @see readFromAudioReader */ void writeToAudioWriter (AudioFormatWriter* writer, int startSample, int numSamples) const; private: int numChannels, size; size_t allocatedBytes; float** channels; HeapBlock allocatedData; float* preallocatedChannelSpace [32]; void allocateData(); void allocateChannels (float** dataToReferTo); JUCE_LEAK_DETECTOR (AudioSampleBuffer); }; #endif // __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__ /*** End of inlined file: juce_AudioSampleBuffer.h ***/ /** Used by AudioSource::getNextAudioBlock(). */ struct JUCE_API AudioSourceChannelInfo { /** The destination buffer to fill with audio data. When the AudioSource::getNextAudioBlock() method is called, the active section of this buffer should be filled with whatever output the source produces. Only the samples specified by the startSample and numSamples members of this structure should be affected by the call. The contents of the buffer when it is passed to the the AudioSource::getNextAudioBlock() method can be treated as the input if the source is performing some kind of filter operation, but should be cleared if this is not the case - the clearActiveBufferRegion() is a handy way of doing this. The number of channels in the buffer could be anything, so the AudioSource must cope with this in whatever way is appropriate for its function. */ AudioSampleBuffer* buffer; /** The first sample in the buffer from which the callback is expected to write data. */ int startSample; /** The number of samples in the buffer which the callback is expected to fill with data. */ int numSamples; /** Convenient method to clear the buffer if the source is not producing any data. */ void clearActiveBufferRegion() const { if (buffer != 0) buffer->clear (startSample, numSamples); } }; /** Base class for objects that can produce a continuous stream of audio. An AudioSource has two states: 'prepared' and 'unprepared'. When a source needs to be played, it is first put into a 'prepared' state by a call to prepareToPlay(), and then repeated calls will be made to its getNextAudioBlock() method to process the audio data. Once playback has finished, the releaseResources() method is called to put the stream back into an 'unprepared' state. @see AudioFormatReaderSource, ResamplingAudioSource */ class JUCE_API AudioSource { protected: /** Creates an AudioSource. */ AudioSource() throw() {} public: /** Destructor. */ virtual ~AudioSource() {} /** Tells the source to prepare for playing. An AudioSource has two states: prepared and unprepared. The prepareToPlay() method is guaranteed to be called at least once on an 'unpreprared' source to put it into a 'prepared' state before any calls will be made to getNextAudioBlock(). This callback allows the source to initialise any resources it might need when playing. Once playback has finished, the releaseResources() method is called to put the stream back into an 'unprepared' state. Note that this method could be called more than once in succession without a matching call to releaseResources(), so make sure your code is robust and can handle that kind of situation. @param samplesPerBlockExpected the number of samples that the source will be expected to supply each time its getNextAudioBlock() method is called. This number may vary slightly, because it will be dependent on audio hardware callbacks, and these aren't guaranteed to always use a constant block size, so the source should be able to cope with small variations. @param sampleRate the sample rate that the output will be used at - this is needed by sources such as tone generators. @see releaseResources, getNextAudioBlock */ virtual void prepareToPlay (int samplesPerBlockExpected, double sampleRate) = 0; /** Allows the source to release anything it no longer needs after playback has stopped. This will be called when the source is no longer going to have its getNextAudioBlock() method called, so it should release any spare memory, etc. that it might have allocated during the prepareToPlay() call. Note that there's no guarantee that prepareToPlay() will actually have been called before releaseResources(), and it may be called more than once in succession, so make sure your code is robust and doesn't make any assumptions about when it will be called. @see prepareToPlay, getNextAudioBlock */ virtual void releaseResources() = 0; /** Called repeatedly to fetch subsequent blocks of audio data. After calling the prepareToPlay() method, this callback will be made each time the audio playback hardware (or whatever other destination the audio data is going to) needs another block of data. It will generally be called on a high-priority system thread, or possibly even an interrupt, so be careful not to do too much work here, as that will cause audio glitches! @see AudioSourceChannelInfo, prepareToPlay, releaseResources */ virtual void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill) = 0; }; #endif // __JUCE_AUDIOSOURCE_JUCEHEADER__ /*** End of inlined file: juce_AudioSource.h ***/ class AudioThumbnail; /** Writes samples to an audio file stream. A subclass that writes a specific type of audio format will be created by an AudioFormat object. After creating one of these with the AudioFormat::createWriterFor() method you can call its write() method to store the samples, and then delete it. @see AudioFormat, AudioFormatReader */ class JUCE_API AudioFormatWriter { protected: /** Creates an AudioFormatWriter object. @param destStream the stream to write to - this will be deleted by this object when it is no longer needed @param formatName the description that will be returned by the getFormatName() method @param sampleRate the sample rate to use - the base class just stores this value, it doesn't do anything with it @param numberOfChannels the number of channels to write - the base class just stores this value, it doesn't do anything with it @param bitsPerSample the bit depth of the stream - the base class just stores this value, it doesn't do anything with it */ AudioFormatWriter (OutputStream* destStream, const String& formatName, double sampleRate, unsigned int numberOfChannels, unsigned int bitsPerSample); public: /** Destructor. */ virtual ~AudioFormatWriter(); /** Returns a description of what type of format this is. E.g. "AIFF file" */ const String getFormatName() const throw() { return formatName; } /** Writes a set of samples to the audio stream. Note that if you're trying to write the contents of an AudioSampleBuffer, you can use AudioSampleBuffer::writeToAudioWriter(). @param samplesToWrite an array of arrays containing the sample data for each channel to write. This is a zero-terminated array of arrays, and can contain a different number of channels than the actual stream uses, and the writer should do its best to cope with this. If the format is fixed-point, each channel will be formatted as an array of signed integers using the full 32-bit range -0x80000000 to 0x7fffffff, regardless of the source's bit-depth. If it is a floating-point format, you should treat the arrays as arrays of floats, and just cast it to an (int**) to pass it into the method. @param numSamples the number of samples to write */ virtual bool write (const int** samplesToWrite, int numSamples) = 0; /** Reads a section of samples from an AudioFormatReader, and writes these to the output. This will take care of any floating-point conversion that's required to convert between the two formats. It won't deal with sample-rate conversion, though. If numSamplesToRead < 0, it will write the entire length of the reader. @returns false if it can't read or write properly during the operation */ bool writeFromAudioReader (AudioFormatReader& reader, int64 startSample, int64 numSamplesToRead); /** Reads some samples from an AudioSource, and writes these to the output. The source must already have been initialised with the AudioSource::prepareToPlay() method @param source the source to read from @param numSamplesToRead total number of samples to read and write @param samplesPerBlock the maximum number of samples to fetch from the source @returns false if it can't read or write properly during the operation */ bool writeFromAudioSource (AudioSource& source, int numSamplesToRead, int samplesPerBlock = 2048); /** Writes some samples from an AudioSampleBuffer. */ bool writeFromAudioSampleBuffer (const AudioSampleBuffer& source, int startSample, int numSamples); /** Returns the sample rate being used. */ double getSampleRate() const throw() { return sampleRate; } /** Returns the number of channels being written. */ int getNumChannels() const throw() { return numChannels; } /** Returns the bit-depth of the data being written. */ int getBitsPerSample() const throw() { return bitsPerSample; } /** Returns true if it's a floating-point format, false if it's fixed-point. */ bool isFloatingPoint() const throw() { return usesFloatingPointData; } /** Provides a FIFO for an AudioFormatWriter, allowing you to push incoming data into a buffer which will be flushed to disk by a background thread. */ class ThreadedWriter { public: /** Creates a ThreadedWriter for a given writer and a thread. The writer object which is passed in here will be owned and deleted by the ThreadedWriter when it is no longer needed. To stop the writer and flush the buffer to disk, simply delete this object. */ ThreadedWriter (AudioFormatWriter* writer, TimeSliceThread& backgroundThread, int numSamplesToBuffer); /** Destructor. */ ~ThreadedWriter(); /** Pushes some incoming audio data into the FIFO. If there's enough free space in the buffer, this will add the data to it, If the FIFO is too full to accept this many samples, the method will return false - then you could either wait until the background thread has had time to consume some of the buffered data and try again, or you can give up and lost this block. The data must be an array containing the same number of channels as the AudioFormatWriter object is using. None of these channels can be null. */ bool write (const float** data, int numSamples); /** Allows you to specify a thumbnail that this writer should update with the incoming data. The thumbnail will be cleared and will the writer will begin adding data to it as it arrives. Pass a null pointer to stop the writer updating any thumbnails. */ void setThumbnailToUpdate (AudioThumbnail* thumbnailToUpdate); /** @internal */ class Buffer; // (only public for VC6 compatibility) private: friend class ScopedPointer; ScopedPointer buffer; }; protected: /** The sample rate of the stream. */ double sampleRate; /** The number of channels being written to the stream. */ unsigned int numChannels; /** The bit depth of the file. */ unsigned int bitsPerSample; /** True if it's a floating-point format, false if it's fixed-point. */ bool usesFloatingPointData; /** The output stream for Use by subclasses. */ OutputStream* output; /** Used by AudioFormatWriter subclasses to copy data to different formats. */ template struct WriteHelper { typedef AudioData::Pointer DestType; typedef AudioData::Pointer SourceType; static void write (void* destData, int numDestChannels, const int** source, int numSamples) throw() { for (int i = 0; i < numDestChannels; ++i) { const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels); if (*source != 0) { dest.convertSamples (SourceType (*source), numSamples); ++source; } else { dest.clearSamples (numSamples); } } } }; private: String formatName; friend class ThreadedWriter; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioFormatWriter); }; #endif // __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ /*** End of inlined file: juce_AudioFormatWriter.h ***/ /** Subclasses of AudioFormat are used to read and write different audio file formats. @see AudioFormatReader, AudioFormatWriter, WavAudioFormat, AiffAudioFormat */ class JUCE_API AudioFormat { public: /** Destructor. */ virtual ~AudioFormat(); /** Returns the name of this format. e.g. "WAV file" or "AIFF file" */ const String& getFormatName() const; /** Returns all the file extensions that might apply to a file of this format. The first item will be the one that's preferred when creating a new file. So for a wav file this might just return ".wav"; for an AIFF file it might return two items, ".aif" and ".aiff" */ const StringArray& getFileExtensions() const; /** Returns true if this the given file can be read by this format. Subclasses shouldn't do too much work here, just check the extension or file type. The base class implementation just checks the file's extension against one of the ones that was registered in the constructor. */ virtual bool canHandleFile (const File& fileToTest); /** Returns a set of sample rates that the format can read and write. */ virtual const Array getPossibleSampleRates() = 0; /** Returns a set of bit depths that the format can read and write. */ virtual const Array getPossibleBitDepths() = 0; /** Returns true if the format can do 2-channel audio. */ virtual bool canDoStereo() = 0; /** Returns true if the format can do 1-channel audio. */ virtual bool canDoMono() = 0; /** Returns true if the format uses compressed data. */ virtual bool isCompressed(); /** Returns a list of different qualities that can be used when writing. Non-compressed formats will just return an empty array, but for something like Ogg-Vorbis or MP3, it might return a list of bit-rates, etc. When calling createWriterFor(), an index from this array is passed in to tell the format which option is required. */ virtual const StringArray getQualityOptions(); /** Tries to create an object that can read from a stream containing audio data in this format. The reader object that is returned can be used to read from the stream, and should then be deleted by the caller. @param sourceStream the stream to read from - the AudioFormatReader object that is returned will delete this stream when it no longer needs it. @param deleteStreamIfOpeningFails if no reader can be created, this determines whether this method should delete the stream object that was passed-in. (If a valid reader is returned, it will always be in charge of deleting the stream, so this parameter is ignored) @see AudioFormatReader */ virtual AudioFormatReader* createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails) = 0; /** Tries to create an object that can write to a stream with this audio format. The writer object that is returned can be used to write to the stream, and should then be deleted by the caller. If the stream can't be created for some reason (e.g. the parameters passed in here aren't suitable), this will return 0. @param streamToWriteTo the stream that the data will go to - this will be deleted by the AudioFormatWriter object when it's no longer needed. If no AudioFormatWriter can be created by this method, the stream will NOT be deleted, so that the caller can re-use it to try to open a different format, etc @param sampleRateToUse the sample rate for the file, which must be one of the ones returned by getPossibleSampleRates() @param numberOfChannels the number of channels - this must be either 1 or 2, and the choice will depend on the results of canDoMono() and canDoStereo() @param bitsPerSample the bits per sample to use - this must be one of the values returned by getPossibleBitDepths() @param metadataValues a set of metadata values that the writer should try to write to the stream. Exactly what these are depends on the format, and the subclass doesn't actually have to do anything with them if it doesn't want to. Have a look at the specific format implementation classes to see possible values that can be used @param qualityOptionIndex the index of one of compression qualities returned by the getQualityOptions() method. If there aren't any quality options for this format, just pass 0 in this parameter, as it'll be ignored @see AudioFormatWriter */ virtual AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, double sampleRateToUse, unsigned int numberOfChannels, int bitsPerSample, const StringPairArray& metadataValues, int qualityOptionIndex) = 0; protected: /** Creates an AudioFormat object. @param formatName this sets the value that will be returned by getFormatName() @param fileExtensions a zero-terminated list of file extensions - this is what will be returned by getFileExtension() */ AudioFormat (const String& formatName, const StringArray& fileExtensions); private: String formatName; StringArray fileExtensions; }; #endif // __JUCE_AUDIOFORMAT_JUCEHEADER__ /*** End of inlined file: juce_AudioFormat.h ***/ /** Reads and Writes AIFF format audio files. @see AudioFormat */ class JUCE_API AiffAudioFormat : public AudioFormat { public: /** Creates an format object. */ AiffAudioFormat(); /** Destructor. */ ~AiffAudioFormat(); const Array getPossibleSampleRates(); const Array getPossibleBitDepths(); bool canDoStereo(); bool canDoMono(); #if JUCE_MAC bool canHandleFile (const File& fileToTest); #endif AudioFormatReader* createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails); AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, double sampleRateToUse, unsigned int numberOfChannels, int bitsPerSample, const StringPairArray& metadataValues, int qualityOptionIndex); private: JUCE_LEAK_DETECTOR (AiffAudioFormat); }; #endif // __JUCE_AIFFAUDIOFORMAT_JUCEHEADER__ /*** End of inlined file: juce_AiffAudioFormat.h ***/ #endif #ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ /*** Start of inlined file: juce_AudioCDBurner.h ***/ #ifndef __JUCE_AUDIOCDBURNER_JUCEHEADER__ #define __JUCE_AUDIOCDBURNER_JUCEHEADER__ #if JUCE_USE_CDBURNER || DOXYGEN /** */ class AudioCDBurner : public ChangeBroadcaster { public: /** Returns a list of available optical drives. Use openDevice() to open one of the items from this list. */ static const StringArray findAvailableDevices(); /** Tries to open one of the optical drives. The deviceIndex is an index into the array returned by findAvailableDevices(). */ static AudioCDBurner* openDevice (const int deviceIndex); /** Destructor. */ ~AudioCDBurner(); enum DiskState { unknown, /**< An error condition, if the device isn't responding. */ trayOpen, /**< The drive is currently open. Note that a slot-loading drive may seem to be permanently open. */ noDisc, /**< The drive has no disk in it. */ writableDiskPresent, /**< The drive contains a writeable disk. */ readOnlyDiskPresent /**< The drive contains a read-only disk. */ }; /** Returns the current status of the device. To get informed when the drive's status changes, attach a ChangeListener to the AudioCDBurner. */ DiskState getDiskState() const; /** Returns true if there's a writable disk in the drive. */ bool isDiskPresent() const; /** Sends an eject signal to the drive. The eject will happen asynchronously, so you can use getDiskState() and waitUntilStateChange() to monitor its progress. */ bool openTray(); /** Blocks the current thread until the drive's state changes, or until the timeout expires. @returns the device's new state */ DiskState waitUntilStateChange (int timeOutMilliseconds); /** Returns the set of possible write speeds that the device can handle. These are as a multiple of 'normal' speed, so e.g. '24x' returns 24, etc. Note that if there's no media present in the drive, this value may be unavailable! @see setWriteSpeed, getWriteSpeed */ const Array getAvailableWriteSpeeds() const; /** Tries to enable or disable buffer underrun safety on devices that support it. @returns true if it's now enabled. If the device doesn't support it, this will always return false. */ bool setBufferUnderrunProtection (bool shouldBeEnabled); /** Returns the number of free blocks on the disk. There are 75 blocks per second, at 44100Hz. */ int getNumAvailableAudioBlocks() const; /** Adds a track to be written. The source passed-in here will be kept by this object, and it will be used and deleted at some point in the future, either during the burn() method or when this AudioCDBurner object is deleted. Your caller method shouldn't keep a reference to it or use it again after passing it in here. */ bool addAudioTrack (AudioSource* source, int numSamples); /** Receives progress callbacks during a cd-burn operation. @see AudioCDBurner::burn() */ class BurnProgressListener { public: BurnProgressListener() throw() {} virtual ~BurnProgressListener() {} /** Called at intervals to report on the progress of the AudioCDBurner. To cancel the burn, return true from this method. */ virtual bool audioCDBurnProgress (float proportionComplete) = 0; }; /** Runs the burn process. This method will block until the operation is complete. @param listener the object to receive callbacks about progress @param ejectDiscAfterwards whether to eject the disk after the burn completes @param performFakeBurnForTesting if true, no data will actually be written to the disk @param writeSpeed one of the write speeds from getAvailableWriteSpeeds(), or 0 or less to mean the fastest speed. */ const String burn (BurnProgressListener* listener, bool ejectDiscAfterwards, bool performFakeBurnForTesting, int writeSpeed); /** If a burn operation is currently in progress, this tells it to stop as soon as possible. It's also possible to stop the burn process by returning true from BurnProgressListener::audioCDBurnProgress() */ void abortBurn(); private: AudioCDBurner (const int deviceIndex); class Pimpl; friend class ScopedPointer; ScopedPointer pimpl; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioCDBurner); }; #endif #endif // __JUCE_AUDIOCDBURNER_JUCEHEADER__ /*** End of inlined file: juce_AudioCDBurner.h ***/ #endif #ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ /*** Start of inlined file: juce_AudioCDReader.h ***/ #ifndef __JUCE_AUDIOCDREADER_JUCEHEADER__ #define __JUCE_AUDIOCDREADER_JUCEHEADER__ #if JUCE_USE_CDREADER || DOXYGEN #if JUCE_MAC #endif /** A type of AudioFormatReader that reads from an audio CD. One of these can be used to read a CD as if it's one big audio stream. Use the getPositionOfTrackStart() method to find where the individual tracks are within the stream. @see AudioFormatReader */ class JUCE_API AudioCDReader : public AudioFormatReader { public: /** Returns a list of names of Audio CDs currently available for reading. If there's a CD drive but no CD in it, this might return an empty list, or possibly a device that can be opened but which has no tracks, depending on the platform. @see createReaderForCD */ static const StringArray getAvailableCDNames(); /** Tries to create an AudioFormatReader that can read from an Audio CD. @param index the index of one of the available CDs - use getAvailableCDNames() to find out how many there are. @returns a new AudioCDReader object, or 0 if it couldn't be created. The caller will be responsible for deleting the object returned. */ static AudioCDReader* createReaderForCD (const int index); /** Destructor. */ ~AudioCDReader(); /** Implementation of the AudioFormatReader method. */ bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples); /** Checks whether the CD has been removed from the drive. */ bool isCDStillPresent() const; /** Returns the total number of tracks (audio + data). */ int getNumTracks() const; /** Finds the sample offset of the start of a track. @param trackNum the track number, where trackNum = 0 is the first track and trackNum = getNumTracks() means the end of the CD. */ int getPositionOfTrackStart (int trackNum) const; /** Returns true if a given track is an audio track. @param trackNum the track number, where 0 is the first track. */ bool isTrackAudio (int trackNum) const; /** Returns an array of sample offsets for the start of each track, followed by the sample position of the end of the CD. */ const Array& getTrackOffsets() const; /** Refreshes the object's table of contents. If the disc has been ejected and a different one put in since this object was created, this will cause it to update its idea of how many tracks there are, etc. */ void refreshTrackLengths(); /** Enables scanning for indexes within tracks. @see getLastIndex */ void enableIndexScanning (bool enabled); /** Returns the index number found during the last read() call. Index scanning is turned off by default - turn it on with enableIndexScanning(). Then when the read() method is called, if it comes across an index within that block, the index number is stored and returned by this method. Some devices might not support indexes, of course. (If you don't know what CD indexes are, it's unlikely you'll ever need them). @see enableIndexScanning */ int getLastIndex() const; /** Scans a track to find the position of any indexes within it. @param trackNumber the track to look in, where 0 is the first track on the disc @returns an array of sample positions of any index points found (not including the index that marks the start of the track) */ const Array findIndexesInTrack (const int trackNumber); /** Returns the CDDB id number for the CD. It's not a great way of identifying a disc, but it's traditional. */ int getCDDBId(); /** Tries to eject the disk. Of course this might not be possible, if some other process is using it. */ void ejectDisk(); enum { framesPerSecond = 75, samplesPerFrame = 44100 / framesPerSecond }; private: Array trackStartSamples; #if JUCE_MAC File volumeDir; Array tracks; int currentReaderTrack; ScopedPointer reader; AudioCDReader (const File& volume); #elif JUCE_WINDOWS bool audioTracks [100]; void* handle; bool indexingEnabled; int lastIndex, firstFrameInBuffer, samplesInBuffer; MemoryBlock buffer; AudioCDReader (void* handle); int getIndexAt (int samplePos); #elif JUCE_LINUX AudioCDReader(); #endif JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioCDReader); }; #endif #endif // __JUCE_AUDIOCDREADER_JUCEHEADER__ /*** End of inlined file: juce_AudioCDReader.h ***/ #endif #ifndef __JUCE_AUDIOFORMAT_JUCEHEADER__ #endif #ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ /*** Start of inlined file: juce_AudioFormatManager.h ***/ #ifndef __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ #define __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ /** A class for keeping a list of available audio formats, and for deciding which one to use to open a given file. You can either use this class as a singleton object, or create instances of it yourself. Once created, use its registerFormat() method to tell it which formats it should use. @see AudioFormat */ class JUCE_API AudioFormatManager { public: /** Creates an empty format manager. Before it'll be any use, you'll need to call registerFormat() with all the formats you want it to be able to recognise. */ AudioFormatManager(); /** Destructor. */ ~AudioFormatManager(); /** Adds a format to the manager's list of available file types. The object passed-in will be deleted by this object, so don't keep a pointer to it! If makeThisTheDefaultFormat is true, then the getDefaultFormat() method will return this one when called. */ void registerFormat (AudioFormat* newFormat, bool makeThisTheDefaultFormat); /** Handy method to make it easy to register the formats that come with Juce. Currently, this will add WAV and AIFF to the list. */ void registerBasicFormats(); /** Clears the list of known formats. */ void clearFormats(); /** Returns the number of currently registered file formats. */ int getNumKnownFormats() const; /** Returns one of the registered file formats. */ AudioFormat* getKnownFormat (int index) const; /** Looks for which of the known formats is listed as being for a given file extension. The extension may have a dot before it, so e.g. ".wav" or "wav" are both ok. */ AudioFormat* findFormatForFileExtension (const String& fileExtension) const; /** Returns the format which has been set as the default one. You can set a format as being the default when it is registered. It's useful when you want to write to a file, because the best format may change between platforms, e.g. AIFF is preferred on the Mac, WAV on Windows. If none has been set as the default, this method will just return the first one in the list. */ AudioFormat* getDefaultFormat() const; /** Returns a set of wildcards for file-matching that contains the extensions for all known formats. E.g. if might return "*.wav;*.aiff" if it just knows about wavs and aiffs. */ const String getWildcardForAllFormats() const; /** Searches through the known formats to try to create a suitable reader for this file. If none of the registered formats can open the file, it'll return 0. If it returns a reader, it's the caller's responsibility to delete the reader. */ AudioFormatReader* createReaderFor (const File& audioFile); /** Searches through the known formats to try to create a suitable reader for this stream. The stream object that is passed-in will be deleted by this method or by the reader that is returned, so the caller should not keep any references to it. The stream that is passed-in must be capable of being repositioned so that all the formats can have a go at opening it. If none of the registered formats can open the stream, it'll return 0. If it returns a reader, it's the caller's responsibility to delete the reader. */ AudioFormatReader* createReaderFor (InputStream* audioFileStream); private: OwnedArray knownFormats; int defaultFormatIndex; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioFormatManager); }; #endif // __JUCE_AUDIOFORMATMANAGER_JUCEHEADER__ /*** End of inlined file: juce_AudioFormatManager.h ***/ #endif #ifndef __JUCE_AUDIOFORMATREADER_JUCEHEADER__ #endif #ifndef __JUCE_AUDIOFORMATWRITER_JUCEHEADER__ #endif #ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ /*** Start of inlined file: juce_AudioSubsectionReader.h ***/ #ifndef __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ #define __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ /** This class is used to wrap an AudioFormatReader and only read from a subsection of the file. So if you have a reader which can read a 1000 sample file, you could wrap it in one of these to only access, e.g. samples 100 to 200, and any samples outside that will come back as 0. Accessing sample 0 from this reader will actually read the first sample from the other's subsection, which might be at a non-zero position. @see AudioFormatReader */ class JUCE_API AudioSubsectionReader : public AudioFormatReader { public: /** Creates a AudioSubsectionReader for a given data source. @param sourceReader the source reader from which we'll be taking data @param subsectionStartSample the sample within the source reader which will be mapped onto sample 0 for this reader. @param subsectionLength the number of samples from the source that will make up the subsection. If this reader is asked for any samples beyond this region, it will return zero. @param deleteSourceWhenDeleted if true, the sourceReader object will be deleted when this object is deleted. */ AudioSubsectionReader (AudioFormatReader* sourceReader, int64 subsectionStartSample, int64 subsectionLength, bool deleteSourceWhenDeleted); /** Destructor. */ ~AudioSubsectionReader(); bool readSamples (int** destSamples, int numDestChannels, int startOffsetInDestBuffer, int64 startSampleInFile, int numSamples); void readMaxLevels (int64 startSample, int64 numSamples, float& lowestLeft, float& highestLeft, float& lowestRight, float& highestRight); private: AudioFormatReader* const source; int64 startSample, length; const bool deleteSourceWhenDeleted; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSubsectionReader); }; #endif // __JUCE_AUDIOSUBSECTIONREADER_JUCEHEADER__ /*** End of inlined file: juce_AudioSubsectionReader.h ***/ #endif #ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ /*** Start of inlined file: juce_AudioThumbnail.h ***/ #ifndef __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ #define __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ class AudioThumbnailCache; /** Makes it easy to quickly draw scaled views of the waveform shape of an audio file. To use this class, just create an AudioThumbNail class for the file you want to draw, call setSource to tell it which file or resource to use, then call drawChannel() to draw it. The class will asynchronously scan the wavefile to create its scaled-down view, so you should make your UI repaint itself as this data comes in. To do this, the AudioThumbnail is a ChangeBroadcaster, and will broadcast a message when its listeners should repaint themselves. The thumbnail stores an internal low-res version of the wave data, and this can be loaded and saved to avoid having to scan the file again. @see AudioThumbnailCache */ class JUCE_API AudioThumbnail : public ChangeBroadcaster { public: /** Creates an audio thumbnail. @param sourceSamplesPerThumbnailSample when creating a stored, low-res version of the audio data, this is the scale at which it should be done. (This number is the number of original samples that will be averaged for each low-res sample) @param formatManagerToUse the audio format manager that is used to open the file @param cacheToUse an instance of an AudioThumbnailCache - this provides a background thread and storage that is used to by the thumbnail, and the cache object can be shared between multiple thumbnails */ AudioThumbnail (int sourceSamplesPerThumbnailSample, AudioFormatManager& formatManagerToUse, AudioThumbnailCache& cacheToUse); /** Destructor. */ ~AudioThumbnail(); /** Clears and resets the thumbnail. */ void clear(); /** Specifies the file or stream that contains the audio file. For a file, just call @code setSource (new FileInputSource (file)) @endcode You can pass a zero in here to clear the thumbnail. The source that is passed in will be deleted by this object when it is no longer needed. @returns true if the source could be opened as a valid audio file, false if this failed for some reason. */ bool setSource (InputSource* newSource); /** Gives the thumbnail an AudioFormatReader to use directly. This will start parsing the audio in a background thread (unless the hash code can be looked-up successfully in the thumbnail cache). Note that the reader object will be held by the thumbnail and deleted later when no longer needed. The thumbnail will actually keep hold of this reader until you clear the thumbnail or change the input source, so the file will be held open for all this time. If you don't want the thumbnail to keep a file handle open continuously, you should use the setSource() method instead, which will only open the file when it needs to. */ void setReader (AudioFormatReader* newReader, int64 hashCode); /** Resets the thumbnail, ready for adding data with the specified format. If you're going to generate a thumbnail yourself, call this before using addBlock() to add the data. */ void reset (int numChannels, double sampleRate, int64 totalSamplesInSource = 0); /** Adds a block of level data to the thumbnail. Call reset() before using this, to tell the thumbnail about the data format. */ void addBlock (int64 sampleNumberInSource, const AudioSampleBuffer& newData, int startOffsetInBuffer, int numSamples); /** Reloads the low res thumbnail data from an input stream. This is not an audio file stream! It takes a stream of thumbnail data that would previously have been created by the saveTo() method. @see saveTo */ void loadFrom (InputStream& input); /** Saves the low res thumbnail data to an output stream. The data that is written can later be reloaded using loadFrom(). @see loadFrom */ void saveTo (OutputStream& output) const; /** Returns the number of channels in the file. */ int getNumChannels() const throw(); /** Returns the length of the audio file, in seconds. */ double getTotalLength() const throw(); /** Draws the waveform for a channel. The waveform will be drawn within the specified rectangle, where startTime and endTime specify the times within the audio file that should be positioned at the left and right edges of the rectangle. The waveform will be scaled vertically so that a full-volume sample will fill the rectangle vertically, but you can also specify an extra vertical scale factor with the verticalZoomFactor parameter. */ void drawChannel (Graphics& g, const Rectangle& area, double startTimeSeconds, double endTimeSeconds, int channelNum, float verticalZoomFactor); /** Draws the waveforms for all channels in the thumbnail. This will call drawChannel() to render each of the thumbnail's channels, stacked above each other within the specified area. @see drawChannel */ void drawChannels (Graphics& g, const Rectangle& area, double startTimeSeconds, double endTimeSeconds, float verticalZoomFactor); /** Returns true if the low res preview is fully generated. */ bool isFullyLoaded() const throw(); /** Returns the number of samples that have been set in the thumbnail. */ int64 getNumSamplesFinished() const throw(); /** Returns the highest level in the thumbnail. Note that because the thumb only stores low-resolution data, this isn't an accurate representation of the highest value, it's only a rough approximation. */ float getApproximatePeak() const; /** Returns the hash code that was set by setSource() or setReader(). */ int64 getHashCode() const; #ifndef DOXYGEN // (this is only public to avoid a VC6 bug) class LevelDataSource; #endif private: AudioFormatManager& formatManagerToUse; AudioThumbnailCache& cache; struct MinMaxValue; class ThumbData; class CachedWindow; friend class LevelDataSource; friend class ScopedPointer; friend class ThumbData; friend class OwnedArray; friend class CachedWindow; friend class ScopedPointer; ScopedPointer source; ScopedPointer window; OwnedArray channels; int32 samplesPerThumbSample; int64 totalSamples, numSamplesFinished; int32 numChannels; double sampleRate; CriticalSection lock; bool setDataSource (LevelDataSource* newSource); void setLevels (const MinMaxValue* const* values, int thumbIndex, int numChans, int numValues); void createChannels (int length); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioThumbnail); }; #endif // __JUCE_AUDIOTHUMBNAIL_JUCEHEADER__ /*** End of inlined file: juce_AudioThumbnail.h ***/ #endif #ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ /*** Start of inlined file: juce_AudioThumbnailCache.h ***/ #ifndef __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ #define __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ struct ThumbnailCacheEntry; /** An instance of this class is used to manage multiple AudioThumbnail objects. The cache runs a single background thread that is shared by all the thumbnails that need it, and it maintains a set of low-res previews in memory, to avoid having to re-scan audio files too often. @see AudioThumbnail */ class JUCE_API AudioThumbnailCache : public TimeSliceThread { public: /** Creates a cache object. The maxNumThumbsToStore parameter lets you specify how many previews should be kept in memory at once. */ explicit AudioThumbnailCache (int maxNumThumbsToStore); /** Destructor. */ ~AudioThumbnailCache(); /** Clears out any stored thumbnails. */ void clear(); /** Reloads the specified thumb if this cache contains the appropriate stored data. This is called automatically by the AudioThumbnail class, so you shouldn't normally need to call it directly. */ bool loadThumb (AudioThumbnail& thumb, int64 hashCode); /** Stores the cachable data from the specified thumb in this cache. This is called automatically by the AudioThumbnail class, so you shouldn't normally need to call it directly. */ void storeThumb (const AudioThumbnail& thumb, int64 hashCode); private: OwnedArray thumbs; int maxNumThumbsToStore; ThumbnailCacheEntry* findThumbFor (int64 hash) const; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioThumbnailCache); }; #endif // __JUCE_AUDIOTHUMBNAILCACHE_JUCEHEADER__ /*** End of inlined file: juce_AudioThumbnailCache.h ***/ #endif #ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ /*** Start of inlined file: juce_FlacAudioFormat.h ***/ #ifndef __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ #define __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ #if JUCE_USE_FLAC || defined (DOXYGEN) /** Reads and writes the lossless-compression FLAC audio format. To compile this, you'll need to set the JUCE_USE_FLAC flag in juce_Config.h, and make sure your include search path and library search path are set up to find the FLAC header files and static libraries. @see AudioFormat */ class JUCE_API FlacAudioFormat : public AudioFormat { public: FlacAudioFormat(); ~FlacAudioFormat(); const Array getPossibleSampleRates(); const Array getPossibleBitDepths(); bool canDoStereo(); bool canDoMono(); bool isCompressed(); AudioFormatReader* createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails); AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, double sampleRateToUse, unsigned int numberOfChannels, int bitsPerSample, const StringPairArray& metadataValues, int qualityOptionIndex); private: JUCE_LEAK_DETECTOR (FlacAudioFormat); }; #endif #endif // __JUCE_FLACAUDIOFORMAT_JUCEHEADER__ /*** End of inlined file: juce_FlacAudioFormat.h ***/ #endif #ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ /*** Start of inlined file: juce_OggVorbisAudioFormat.h ***/ #ifndef __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ #define __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ #if JUCE_USE_OGGVORBIS || defined (DOXYGEN) /** Reads and writes the Ogg-Vorbis audio format. To compile this, you'll need to set the JUCE_USE_OGGVORBIS flag in juce_Config.h, and make sure your include search path and library search path are set up to find the Vorbis and Ogg header files and static libraries. @see AudioFormat, */ class JUCE_API OggVorbisAudioFormat : public AudioFormat { public: OggVorbisAudioFormat(); ~OggVorbisAudioFormat(); const Array getPossibleSampleRates(); const Array getPossibleBitDepths(); bool canDoStereo(); bool canDoMono(); bool isCompressed(); const StringArray getQualityOptions(); /** Tries to estimate the quality level of an ogg file based on its size. If it can't read the file for some reason, this will just return 1 (medium quality), otherwise it will return the approximate quality setting that would have been used to create the file. @see getQualityOptions */ int estimateOggFileQuality (const File& source); AudioFormatReader* createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails); AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, double sampleRateToUse, unsigned int numberOfChannels, int bitsPerSample, const StringPairArray& metadataValues, int qualityOptionIndex); private: JUCE_LEAK_DETECTOR (OggVorbisAudioFormat); }; #endif #endif // __JUCE_OGGVORBISAUDIOFORMAT_JUCEHEADER__ /*** End of inlined file: juce_OggVorbisAudioFormat.h ***/ #endif #ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ /*** Start of inlined file: juce_QuickTimeAudioFormat.h ***/ #ifndef __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ #define __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ #if JUCE_QUICKTIME /** Uses QuickTime to read the audio track a movie or media file. As well as QuickTime movies, this should also manage to open other audio files that quicktime can understand, like mp3, m4a, etc. @see AudioFormat */ class JUCE_API QuickTimeAudioFormat : public AudioFormat { public: /** Creates a format object. */ QuickTimeAudioFormat(); /** Destructor. */ ~QuickTimeAudioFormat(); const Array getPossibleSampleRates(); const Array getPossibleBitDepths(); bool canDoStereo(); bool canDoMono(); AudioFormatReader* createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails); AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, double sampleRateToUse, unsigned int numberOfChannels, int bitsPerSample, const StringPairArray& metadataValues, int qualityOptionIndex); private: JUCE_LEAK_DETECTOR (QuickTimeAudioFormat); }; #endif #endif // __JUCE_QUICKTIMEAUDIOFORMAT_JUCEHEADER__ /*** End of inlined file: juce_QuickTimeAudioFormat.h ***/ #endif #ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ /*** Start of inlined file: juce_WavAudioFormat.h ***/ #ifndef __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ #define __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ /** Reads and Writes WAV format audio files. @see AudioFormat */ class JUCE_API WavAudioFormat : public AudioFormat { public: /** Creates a format object. */ WavAudioFormat(); /** Destructor. */ ~WavAudioFormat(); /** Metadata property name used by wav readers and writers for adding a BWAV chunk to the file. @see AudioFormatReader::metadataValues, createWriterFor */ static const char* const bwavDescription; /** Metadata property name used by wav readers and writers for adding a BWAV chunk to the file. @see AudioFormatReader::metadataValues, createWriterFor */ static const char* const bwavOriginator; /** Metadata property name used by wav readers and writers for adding a BWAV chunk to the file. @see AudioFormatReader::metadataValues, createWriterFor */ static const char* const bwavOriginatorRef; /** Metadata property name used by wav readers and writers for adding a BWAV chunk to the file. Date format is: yyyy-mm-dd @see AudioFormatReader::metadataValues, createWriterFor */ static const char* const bwavOriginationDate; /** Metadata property name used by wav readers and writers for adding a BWAV chunk to the file. Time format is: hh-mm-ss @see AudioFormatReader::metadataValues, createWriterFor */ static const char* const bwavOriginationTime; /** Metadata property name used by wav readers and writers for adding a BWAV chunk to the file. This is the number of samples from the start of an edit that the file is supposed to begin at. Seems like an obvious mistake to only allow a file to occur in an edit once, but that's the way it is.. @see AudioFormatReader::metadataValues, createWriterFor */ static const char* const bwavTimeReference; /** Metadata property name used by wav readers and writers for adding a BWAV chunk to the file. This is a @see AudioFormatReader::metadataValues, createWriterFor */ static const char* const bwavCodingHistory; /** Utility function to fill out the appropriate metadata for a BWAV file. This just makes it easier than using the property names directly, and it fills out the time and date in the right format. */ static const StringPairArray createBWAVMetadata (const String& description, const String& originator, const String& originatorRef, const Time& dateAndTime, const int64 timeReferenceSamples, const String& codingHistory); const Array getPossibleSampleRates(); const Array getPossibleBitDepths(); bool canDoStereo(); bool canDoMono(); AudioFormatReader* createReaderFor (InputStream* sourceStream, bool deleteStreamIfOpeningFails); AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo, double sampleRateToUse, unsigned int numberOfChannels, int bitsPerSample, const StringPairArray& metadataValues, int qualityOptionIndex); /** Utility function to replace the metadata in a wav file with a new set of values. If possible, this cheats by overwriting just the metadata region of the file, rather than by copying the whole file again. */ bool replaceMetadataInFile (const File& wavFile, const StringPairArray& newMetadata); private: JUCE_LEAK_DETECTOR (WavAudioFormat); }; #endif // __JUCE_WAVAUDIOFORMAT_JUCEHEADER__ /*** End of inlined file: juce_WavAudioFormat.h ***/ #endif #ifndef __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_AudioFormatReaderSource.h ***/ #ifndef __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ #define __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_PositionableAudioSource.h ***/ #ifndef __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ #define __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ /** A type of AudioSource which can be repositioned. The basic AudioSource just streams continuously with no idea of a current time or length, so the PositionableAudioSource is used for a finite stream that has a current read position. @see AudioSource, AudioTransportSource */ class JUCE_API PositionableAudioSource : public AudioSource { protected: /** Creates the PositionableAudioSource. */ PositionableAudioSource() throw() {} public: /** Destructor */ ~PositionableAudioSource() {} /** Tells the stream to move to a new position. Calling this indicates that the next call to AudioSource::getNextAudioBlock() should return samples from this position. Note that this may be called on a different thread to getNextAudioBlock(), so the subclass should make sure it's synchronised. */ virtual void setNextReadPosition (int newPosition) = 0; /** Returns the position from which the next block will be returned. @see setNextReadPosition */ virtual int getNextReadPosition() const = 0; /** Returns the total length of the stream (in samples). */ virtual int getTotalLength() const = 0; /** Returns true if this source is actually playing in a loop. */ virtual bool isLooping() const = 0; /** Tells the source whether you'd like it to play in a loop. */ virtual void setLooping (bool shouldLoop) { (void) shouldLoop; } }; #endif // __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ /*** End of inlined file: juce_PositionableAudioSource.h ***/ /** A type of AudioSource that will read from an AudioFormatReader. @see PositionableAudioSource, AudioTransportSource, BufferingAudioSource */ class JUCE_API AudioFormatReaderSource : public PositionableAudioSource { public: /** Creates an AudioFormatReaderSource for a given reader. @param sourceReader the reader to use as the data source @param deleteReaderWhenThisIsDeleted if true, the reader passed-in will be deleted when this object is deleted; if false it will be left up to the caller to manage its lifetime */ AudioFormatReaderSource (AudioFormatReader* sourceReader, bool deleteReaderWhenThisIsDeleted); /** Destructor. */ ~AudioFormatReaderSource(); /** Toggles loop-mode. If set to true, it will continuously loop the input source. If false, it will just emit silence after the source has finished. @see isLooping */ void setLooping (bool shouldLoop); /** Returns whether loop-mode is turned on or not. */ bool isLooping() const { return looping; } /** Returns the reader that's being used. */ AudioFormatReader* getAudioFormatReader() const throw() { return reader; } /** Implementation of the AudioSource method. */ void prepareToPlay (int samplesPerBlockExpected, double sampleRate); /** Implementation of the AudioSource method. */ void releaseResources(); /** Implementation of the AudioSource method. */ void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); /** Implements the PositionableAudioSource method. */ void setNextReadPosition (int newPosition); /** Implements the PositionableAudioSource method. */ int getNextReadPosition() const; /** Implements the PositionableAudioSource method. */ int getTotalLength() const; private: AudioFormatReader* reader; bool deleteReader; int volatile nextPlayPos; bool volatile looping; void readBufferSection (int start, int length, AudioSampleBuffer& buffer, int startSample); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioFormatReaderSource); }; #endif // __JUCE_AUDIOFORMATREADERSOURCE_JUCEHEADER__ /*** End of inlined file: juce_AudioFormatReaderSource.h ***/ #endif #ifndef __JUCE_AUDIOSOURCE_JUCEHEADER__ #endif #ifndef __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ /*** Start of inlined file: juce_AudioSourcePlayer.h ***/ #ifndef __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ #define __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ /*** Start of inlined file: juce_AudioIODevice.h ***/ #ifndef __JUCE_AUDIOIODEVICE_JUCEHEADER__ #define __JUCE_AUDIOIODEVICE_JUCEHEADER__ class AudioIODevice; /** One of these is passed to an AudioIODevice object to stream the audio data in and out. The AudioIODevice will repeatedly call this class's audioDeviceIOCallback() method on its own high-priority audio thread, when it needs to send or receive the next block of data. @see AudioIODevice, AudioDeviceManager */ class JUCE_API AudioIODeviceCallback { public: /** Destructor. */ virtual ~AudioIODeviceCallback() {} /** Processes a block of incoming and outgoing audio data. The subclass's implementation should use the incoming audio for whatever purposes it needs to, and must fill all the output channels with the next block of output data before returning. The channel data is arranged with the same array indices as the channel name array returned by AudioIODevice::getOutputChannelNames(), but those channels that aren't specified in AudioIODevice::open() will have a null pointer for their associated channel, so remember to check for this. @param inputChannelData a set of arrays containing the audio data for each incoming channel - this data is valid until the function returns. There will be one channel of data for each input channel that was enabled when the audio device was opened (see AudioIODevice::open()) @param numInputChannels the number of pointers to channel data in the inputChannelData array. @param outputChannelData a set of arrays which need to be filled with the data that should be sent to each outgoing channel of the device. There will be one channel of data for each output channel that was enabled when the audio device was opened (see AudioIODevice::open()) The initial contents of the array is undefined, so the callback function must fill all the channels with zeros if its output is silence. Failing to do this could cause quite an unpleasant noise! @param numOutputChannels the number of pointers to channel data in the outputChannelData array. @param numSamples the number of samples in each channel of the input and output arrays. The number of samples will depend on the audio device's buffer size and will usually remain constant, although this isn't guaranteed, so make sure your code can cope with reasonable changes in the buffer size from one callback to the next. */ virtual void audioDeviceIOCallback (const float** inputChannelData, int numInputChannels, float** outputChannelData, int numOutputChannels, int numSamples) = 0; /** Called to indicate that the device is about to start calling back. This will be called just before the audio callbacks begin, either when this callback has just been added to an audio device, or after the device has been restarted because of a sample-rate or block-size change. You can use this opportunity to find out the sample rate and block size that the device is going to use by calling the AudioIODevice::getCurrentSampleRate() and AudioIODevice::getCurrentBufferSizeSamples() on the supplied pointer. @param device the audio IO device that will be used to drive the callback. Note that if you're going to store this this pointer, it is only valid until the next time that audioDeviceStopped is called. */ virtual void audioDeviceAboutToStart (AudioIODevice* device) = 0; /** Called to indicate that the device has stopped. */ virtual void audioDeviceStopped() = 0; }; /** Base class for an audio device with synchronised input and output channels. Subclasses of this are used to implement different protocols such as DirectSound, ASIO, CoreAudio, etc. To create one of these, you'll need to use the AudioIODeviceType class - see the documentation for that class for more info. For an easier way of managing audio devices and their settings, have a look at the AudioDeviceManager class. @see AudioIODeviceType, AudioDeviceManager */ class JUCE_API AudioIODevice { public: /** Destructor. */ virtual ~AudioIODevice(); /** Returns the device's name, (as set in the constructor). */ const String& getName() const throw() { return name; } /** Returns the type of the device. E.g. "CoreAudio", "ASIO", etc. - this comes from the AudioIODeviceType that created it. */ const String& getTypeName() const throw() { return typeName; } /** Returns the names of all the available output channels on this device. To find out which of these are currently in use, call getActiveOutputChannels(). */ virtual const StringArray getOutputChannelNames() = 0; /** Returns the names of all the available input channels on this device. To find out which of these are currently in use, call getActiveInputChannels(). */ virtual const StringArray getInputChannelNames() = 0; /** Returns the number of sample-rates this device supports. To find out which rates are available on this device, use this method to find out how many there are, and getSampleRate() to get the rates. @see getSampleRate */ virtual int getNumSampleRates() = 0; /** Returns one of the sample-rates this device supports. To find out which rates are available on this device, use getNumSampleRates() to find out how many there are, and getSampleRate() to get the individual rates. The sample rate is set by the open() method. (Note that for DirectSound some rates might not work, depending on combinations of i/o channels that are being opened). @see getNumSampleRates */ virtual double getSampleRate (int index) = 0; /** Returns the number of sizes of buffer that are available. @see getBufferSizeSamples, getDefaultBufferSize */ virtual int getNumBufferSizesAvailable() = 0; /** Returns one of the possible buffer-sizes. @param index the index of the buffer-size to use, from 0 to getNumBufferSizesAvailable() - 1 @returns a number of samples @see getNumBufferSizesAvailable, getDefaultBufferSize */ virtual int getBufferSizeSamples (int index) = 0; /** Returns the default buffer-size to use. @returns a number of samples @see getNumBufferSizesAvailable, getBufferSizeSamples */ virtual int getDefaultBufferSize() = 0; /** Tries to open the device ready to play. @param inputChannels a BigInteger in which a set bit indicates that the corresponding input channel should be enabled @param outputChannels a BigInteger in which a set bit indicates that the corresponding output channel should be enabled @param sampleRate the sample rate to try to use - to find out which rates are available, see getNumSampleRates() and getSampleRate() @param bufferSizeSamples the size of i/o buffer to use - to find out the available buffer sizes, see getNumBufferSizesAvailable() and getBufferSizeSamples() @returns an error description if there's a problem, or an empty string if it succeeds in opening the device @see close */ virtual const String open (const BigInteger& inputChannels, const BigInteger& outputChannels, double sampleRate, int bufferSizeSamples) = 0; /** Closes and releases the device if it's open. */ virtual void close() = 0; /** Returns true if the device is still open. A device might spontaneously close itself if something goes wrong, so this checks if it's still open. */ virtual bool isOpen() = 0; /** Starts the device actually playing. This must be called after the device has been opened. @param callback the callback to use for streaming the data. @see AudioIODeviceCallback, open */ virtual void start (AudioIODeviceCallback* callback) = 0; /** Stops the device playing. Once a device has been started, this will stop it. Any pending calls to the callback class will be flushed before this method returns. */ virtual void stop() = 0; /** Returns true if the device is still calling back. The device might mysteriously stop, so this checks whether it's still playing. */ virtual bool isPlaying() = 0; /** Returns the last error that happened if anything went wrong. */ virtual const String getLastError() = 0; /** Returns the buffer size that the device is currently using. If the device isn't actually open, this value doesn't really mean much. */ virtual int getCurrentBufferSizeSamples() = 0; /** Returns the sample rate that the device is currently using. If the device isn't actually open, this value doesn't really mean much. */ virtual double getCurrentSampleRate() = 0; /** Returns the device's current physical bit-depth. If the device isn't actually open, this value doesn't really mean much. */ virtual int getCurrentBitDepth() = 0; /** Returns a mask showing which of the available output channels are currently enabled. @see getOutputChannelNames */ virtual const BigInteger getActiveOutputChannels() const = 0; /** Returns a mask showing which of the available input channels are currently enabled. @see getInputChannelNames */ virtual const BigInteger getActiveInputChannels() const = 0; /** Returns the device's output latency. This is the delay in samples between a callback getting a block of data, and that data actually getting played. */ virtual int getOutputLatencyInSamples() = 0; /** Returns the device's input latency. This is the delay in samples between some audio actually arriving at the soundcard, and the callback getting passed this block of data. */ virtual int getInputLatencyInSamples() = 0; /** True if this device can show a pop-up control panel for editing its settings. This is generally just true of ASIO devices. If true, you can call showControlPanel() to display it. */ virtual bool hasControlPanel() const; /** Shows a device-specific control panel if there is one. This should only be called for devices which return true from hasControlPanel(). */ virtual bool showControlPanel(); protected: /** Creates a device, setting its name and type member variables. */ AudioIODevice (const String& deviceName, const String& typeName); /** @internal */ String name, typeName; }; #endif // __JUCE_AUDIOIODEVICE_JUCEHEADER__ /*** End of inlined file: juce_AudioIODevice.h ***/ /** Wrapper class to continuously stream audio from an audio source to an AudioIODevice. This object acts as an AudioIODeviceCallback, so can be attached to an output device, and will stream audio from an AudioSource. */ class JUCE_API AudioSourcePlayer : public AudioIODeviceCallback { public: /** Creates an empty AudioSourcePlayer. */ AudioSourcePlayer(); /** Destructor. Make sure this object isn't still being used by an AudioIODevice before deleting it! */ virtual ~AudioSourcePlayer(); /** Changes the current audio source to play from. If the source passed in is already being used, this method will do nothing. If the source is not null, its prepareToPlay() method will be called before it starts being used for playback. If there's another source currently playing, its releaseResources() method will be called after it has been swapped for the new one. @param newSource the new source to use - this will NOT be deleted by this object when no longer needed, so it's the caller's responsibility to manage it. */ void setSource (AudioSource* newSource); /** Returns the source that's playing. May return 0 if there's no source. */ AudioSource* getCurrentSource() const throw() { return source; } /** Sets a gain to apply to the audio data. @see getGain */ void setGain (float newGain) throw(); /** Returns the current gain. @see setGain */ float getGain() const throw() { return gain; } /** Implementation of the AudioIODeviceCallback method. */ void audioDeviceIOCallback (const float** inputChannelData, int totalNumInputChannels, float** outputChannelData, int totalNumOutputChannels, int numSamples); /** Implementation of the AudioIODeviceCallback method. */ void audioDeviceAboutToStart (AudioIODevice* device); /** Implementation of the AudioIODeviceCallback method. */ void audioDeviceStopped(); private: CriticalSection readLock; AudioSource* source; double sampleRate; int bufferSize; float* channels [128]; float* outputChans [128]; const float* inputChans [128]; AudioSampleBuffer tempBuffer; float lastGain, gain; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioSourcePlayer); }; #endif // __JUCE_AUDIOSOURCEPLAYER_JUCEHEADER__ /*** End of inlined file: juce_AudioSourcePlayer.h ***/ #endif #ifndef __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_AudioTransportSource.h ***/ #ifndef __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ #define __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_BufferingAudioSource.h ***/ #ifndef __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ #define __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ /** An AudioSource which takes another source as input, and buffers it using a thread. Create this as a wrapper around another thread, and it will read-ahead with a background thread to smooth out playback. You can either create one of these directly, or use it indirectly using an AudioTransportSource. @see PositionableAudioSource, AudioTransportSource */ class JUCE_API BufferingAudioSource : public PositionableAudioSource { public: /** Creates a BufferingAudioSource. @param source the input source to read from @param deleteSourceWhenDeleted if true, then the input source object will be deleted when this object is deleted @param numberOfSamplesToBuffer the size of buffer to use for reading ahead */ BufferingAudioSource (PositionableAudioSource* source, bool deleteSourceWhenDeleted, int numberOfSamplesToBuffer); /** Destructor. The input source may be deleted depending on whether the deleteSourceWhenDeleted flag was set in the constructor. */ ~BufferingAudioSource(); /** Implementation of the AudioSource method. */ void prepareToPlay (int samplesPerBlockExpected, double sampleRate); /** Implementation of the AudioSource method. */ void releaseResources(); /** Implementation of the AudioSource method. */ void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); /** Implements the PositionableAudioSource method. */ void setNextReadPosition (int newPosition); /** Implements the PositionableAudioSource method. */ int getNextReadPosition() const; /** Implements the PositionableAudioSource method. */ int getTotalLength() const { return source->getTotalLength(); } /** Implements the PositionableAudioSource method. */ bool isLooping() const { return source->isLooping(); } private: PositionableAudioSource* source; bool deleteSourceWhenDeleted; int numberOfSamplesToBuffer; AudioSampleBuffer buffer; CriticalSection bufferStartPosLock; int volatile bufferValidStart, bufferValidEnd, nextPlayPos; bool wasSourceLooping; double volatile sampleRate; friend class SharedBufferingAudioSourceThread; bool readNextBufferChunk(); void readBufferSection (int start, int length, int bufferOffset); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BufferingAudioSource); }; #endif // __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ /*** End of inlined file: juce_BufferingAudioSource.h ***/ /*** Start of inlined file: juce_ResamplingAudioSource.h ***/ #ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ #define __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ /** A type of AudioSource that takes an input source and changes its sample rate. @see AudioSource */ class JUCE_API ResamplingAudioSource : public AudioSource { public: /** Creates a ResamplingAudioSource for a given input source. @param inputSource the input source to read from @param deleteInputWhenDeleted if true, the input source will be deleted when this object is deleted @param numChannels the number of channels to process */ ResamplingAudioSource (AudioSource* inputSource, bool deleteInputWhenDeleted, int numChannels = 2); /** Destructor. */ ~ResamplingAudioSource(); /** Changes the resampling ratio. (This value can be changed at any time, even while the source is running). @param samplesInPerOutputSample if set to 1.0, the input is passed through; higher values will speed it up; lower values will slow it down. The ratio must be greater than 0 */ void setResamplingRatio (double samplesInPerOutputSample); /** Returns the current resampling ratio. This is the value that was set by setResamplingRatio(). */ double getResamplingRatio() const throw() { return ratio; } void prepareToPlay (int samplesPerBlockExpected, double sampleRate); void releaseResources(); void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); private: AudioSource* const input; const bool deleteInputWhenDeleted; double ratio, lastRatio; AudioSampleBuffer buffer; int bufferPos, sampsInBuffer; double subSampleOffset; double coefficients[6]; CriticalSection ratioLock; const int numChannels; HeapBlock destBuffers, srcBuffers; void setFilterCoefficients (double c1, double c2, double c3, double c4, double c5, double c6); void createLowPass (double proportionalRate); struct FilterState { double x1, x2, y1, y2; }; HeapBlock filterStates; void resetFilters(); void applyFilter (float* samples, int num, FilterState& fs); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResamplingAudioSource); }; #endif // __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ /*** End of inlined file: juce_ResamplingAudioSource.h ***/ /** An AudioSource that takes a PositionableAudioSource and allows it to be played, stopped, started, etc. This can also be told use a buffer and background thread to read ahead, and if can correct for different sample-rates. You may want to use one of these along with an AudioSourcePlayer and AudioIODevice to control playback of an audio file. @see AudioSource, AudioSourcePlayer */ class JUCE_API AudioTransportSource : public PositionableAudioSource, public ChangeBroadcaster { public: /** Creates an AudioTransportSource. After creating one of these, use the setSource() method to select an input source. */ AudioTransportSource(); /** Destructor. */ ~AudioTransportSource(); /** Sets the reader that is being used as the input source. This will stop playback, reset the position to 0 and change to the new reader. The source passed in will not be deleted by this object, so must be managed by the caller. @param newSource the new input source to use. This may be zero @param readAheadBufferSize a size of buffer to use for reading ahead. If this is zero, no reading ahead will be done; if it's greater than zero, a BufferingAudioSource will be used to do the reading-ahead @param sourceSampleRateToCorrectFor if this is non-zero, it specifies the sample rate of the source, and playback will be sample-rate adjusted to maintain playback at the correct pitch. If this is 0, no sample-rate adjustment will be performed */ void setSource (PositionableAudioSource* newSource, int readAheadBufferSize = 0, double sourceSampleRateToCorrectFor = 0.0); /** Changes the current playback position in the source stream. The next time the getNextAudioBlock() method is called, this is the time from which it'll read data. @see getPosition */ void setPosition (double newPosition); /** Returns the position that the next data block will be read from This is a time in seconds. */ double getCurrentPosition() const; /** Returns the stream's length in seconds. */ double getLengthInSeconds() const; /** Returns true if the player has stopped because its input stream ran out of data. */ bool hasStreamFinished() const throw() { return inputStreamEOF; } /** Starts playing (if a source has been selected). If it starts playing, this will send a message to any ChangeListeners that are registered with this object. */ void start(); /** Stops playing. If it's actually playing, this will send a message to any ChangeListeners that are registered with this object. */ void stop(); /** Returns true if it's currently playing. */ bool isPlaying() const throw() { return playing; } /** Changes the gain to apply to the output. @param newGain a factor by which to multiply the outgoing samples, so 1.0 = 0dB, 0.5 = -6dB, 2.0 = 6dB, etc. */ void setGain (float newGain) throw(); /** Returns the current gain setting. @see setGain */ float getGain() const throw() { return gain; } /** Implementation of the AudioSource method. */ void prepareToPlay (int samplesPerBlockExpected, double sampleRate); /** Implementation of the AudioSource method. */ void releaseResources(); /** Implementation of the AudioSource method. */ void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); /** Implements the PositionableAudioSource method. */ void setNextReadPosition (int newPosition); /** Implements the PositionableAudioSource method. */ int getNextReadPosition() const; /** Implements the PositionableAudioSource method. */ int getTotalLength() const; /** Implements the PositionableAudioSource method. */ bool isLooping() const; private: PositionableAudioSource* source; ResamplingAudioSource* resamplerSource; BufferingAudioSource* bufferingSource; PositionableAudioSource* positionableSource; AudioSource* masterSource; CriticalSection callbackLock; float volatile gain, lastGain; bool volatile playing, stopped; double sampleRate, sourceSampleRate; int blockSize, readAheadBufferSize; bool isPrepared, inputStreamEOF; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioTransportSource); }; #endif // __JUCE_AUDIOTRANSPORTSOURCE_JUCEHEADER__ /*** End of inlined file: juce_AudioTransportSource.h ***/ #endif #ifndef __JUCE_BUFFERINGAUDIOSOURCE_JUCEHEADER__ #endif #ifndef __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_ChannelRemappingAudioSource.h ***/ #ifndef __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ #define __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ /** An AudioSource that takes the audio from another source, and re-maps its input and output channels to a different arrangement. You can use this to increase or decrease the number of channels that an audio source uses, or to re-order those channels. Call the reset() method before using it to set up a default mapping, and then the setInputChannelMapping() and setOutputChannelMapping() methods to create an appropriate mapping, otherwise no channels will be connected and it'll produce silence. @see AudioSource */ class ChannelRemappingAudioSource : public AudioSource { public: /** Creates a remapping source that will pass on audio from the given input. @param source the input source to use. Make sure that this doesn't get deleted before the ChannelRemappingAudioSource object @param deleteSourceWhenDeleted if true, the input source will be deleted when this object is deleted, if false, the caller is responsible for its deletion */ ChannelRemappingAudioSource (AudioSource* source, bool deleteSourceWhenDeleted); /** Destructor. */ ~ChannelRemappingAudioSource(); /** Specifies a number of channels that this audio source must produce from its getNextAudioBlock() callback. */ void setNumberOfChannelsToProduce (int requiredNumberOfChannels); /** Clears any mapped channels. After this, no channels are mapped, so this object will produce silence. Create some mappings with setInputChannelMapping() and setOutputChannelMapping(). */ void clearAllMappings(); /** Creates an input channel mapping. When the getNextAudioBlock() method is called, the data in channel sourceChannelIndex of the incoming data will be sent to destChannelIndex of our input source. @param destChannelIndex the index of an input channel in our input audio source (i.e. the source specified when this object was created). @param sourceChannelIndex the index of the input channel in the incoming audio data buffer during our getNextAudioBlock() callback */ void setInputChannelMapping (int destChannelIndex, int sourceChannelIndex); /** Creates an output channel mapping. When the getNextAudioBlock() method is called, the data returned in channel sourceChannelIndex by our input audio source will be copied to channel destChannelIndex of the final buffer. @param sourceChannelIndex the index of an output channel coming from our input audio source (i.e. the source specified when this object was created). @param destChannelIndex the index of the output channel in the incoming audio data buffer during our getNextAudioBlock() callback */ void setOutputChannelMapping (int sourceChannelIndex, int destChannelIndex); /** Returns the channel from our input that will be sent to channel inputChannelIndex of our input audio source. */ int getRemappedInputChannel (int inputChannelIndex) const; /** Returns the output channel to which channel outputChannelIndex of our input audio source will be sent to. */ int getRemappedOutputChannel (int outputChannelIndex) const; /** Returns an XML object to encapsulate the state of the mappings. @see restoreFromXml */ XmlElement* createXml() const; /** Restores the mappings from an XML object created by createXML(). @see createXml */ void restoreFromXml (const XmlElement& e); void prepareToPlay (int samplesPerBlockExpected, double sampleRate); void releaseResources(); void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); private: int requiredNumberOfChannels; Array remappedInputs, remappedOutputs; AudioSource* const source; const bool deleteSourceWhenDeleted; AudioSampleBuffer buffer; AudioSourceChannelInfo remappedInfo; CriticalSection lock; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChannelRemappingAudioSource); }; #endif // __JUCE_CHANNELREMAPPINGAUDIOSOURCE_JUCEHEADER__ /*** End of inlined file: juce_ChannelRemappingAudioSource.h ***/ #endif #ifndef __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_IIRFilterAudioSource.h ***/ #ifndef __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ #define __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_IIRFilter.h ***/ #ifndef __JUCE_IIRFILTER_JUCEHEADER__ #define __JUCE_IIRFILTER_JUCEHEADER__ /** An IIR filter that can perform low, high, or band-pass filtering on an audio signal. @see IIRFilterAudioSource */ class JUCE_API IIRFilter { public: /** Creates a filter. Initially the filter is inactive, so will have no effect on samples that you process with it. Use the appropriate method to turn it into the type of filter needed. */ IIRFilter(); /** Creates a copy of another filter. */ IIRFilter (const IIRFilter& other); /** Destructor. */ ~IIRFilter(); /** Resets the filter's processing pipeline, ready to start a new stream of data. Note that this clears the processing state, but the type of filter and its coefficients aren't changed. To put a filter into an inactive state, use the makeInactive() method. */ void reset() throw(); /** Performs the filter operation on the given set of samples. */ void processSamples (float* samples, int numSamples) throw(); /** Processes a single sample, without any locking or checking. Use this if you need fast processing of a single value, but be aware that this isn't thread-safe in the way that processSamples() is. */ float processSingleSampleRaw (float sample) throw(); /** Sets the filter up to act as a low-pass filter. */ void makeLowPass (double sampleRate, double frequency) throw(); /** Sets the filter up to act as a high-pass filter. */ void makeHighPass (double sampleRate, double frequency) throw(); /** Sets the filter up to act as a low-pass shelf filter with variable Q and gain. The gain is a scale factor that the low frequencies are multiplied by, so values greater than 1.0 will boost the low frequencies, values less than 1.0 will attenuate them. */ void makeLowShelf (double sampleRate, double cutOffFrequency, double Q, float gainFactor) throw(); /** Sets the filter up to act as a high-pass shelf filter with variable Q and gain. The gain is a scale factor that the high frequencies are multiplied by, so values greater than 1.0 will boost the high frequencies, values less than 1.0 will attenuate them. */ void makeHighShelf (double sampleRate, double cutOffFrequency, double Q, float gainFactor) throw(); /** Sets the filter up to act as a band pass filter centred around a frequency, with a variable Q and gain. The gain is a scale factor that the centre frequencies are multiplied by, so values greater than 1.0 will boost the centre frequencies, values less than 1.0 will attenuate them. */ void makeBandPass (double sampleRate, double centreFrequency, double Q, float gainFactor) throw(); /** Clears the filter's coefficients so that it becomes inactive. */ void makeInactive() throw(); /** Makes this filter duplicate the set-up of another one. */ void copyCoefficientsFrom (const IIRFilter& other) throw(); protected: CriticalSection processLock; void setCoefficients (double c1, double c2, double c3, double c4, double c5, double c6) throw(); bool active; float coefficients[6]; float x1, x2, y1, y2; // (use the copyCoefficientsFrom() method instead of this operator) IIRFilter& operator= (const IIRFilter&); JUCE_LEAK_DETECTOR (IIRFilter); }; #endif // __JUCE_IIRFILTER_JUCEHEADER__ /*** End of inlined file: juce_IIRFilter.h ***/ /** An AudioSource that performs an IIR filter on another source. */ class JUCE_API IIRFilterAudioSource : public AudioSource { public: /** Creates a IIRFilterAudioSource for a given input source. @param inputSource the input source to read from @param deleteInputWhenDeleted if true, the input source will be deleted when this object is deleted */ IIRFilterAudioSource (AudioSource* inputSource, bool deleteInputWhenDeleted); /** Destructor. */ ~IIRFilterAudioSource(); /** Changes the filter to use the same parameters as the one being passed in. */ void setFilterParameters (const IIRFilter& newSettings); void prepareToPlay (int samplesPerBlockExpected, double sampleRate); void releaseResources(); void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); private: AudioSource* const input; const bool deleteInputWhenDeleted; OwnedArray iirFilters; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (IIRFilterAudioSource); }; #endif // __JUCE_IIRFILTERAUDIOSOURCE_JUCEHEADER__ /*** End of inlined file: juce_IIRFilterAudioSource.h ***/ #endif #ifndef __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_MixerAudioSource.h ***/ #ifndef __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ #define __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ /** An AudioSource that mixes together the output of a set of other AudioSources. Input sources can be added and removed while the mixer is running as long as their prepareToPlay() and releaseResources() methods are called before and after adding them to the mixer. */ class JUCE_API MixerAudioSource : public AudioSource { public: /** Creates a MixerAudioSource. */ MixerAudioSource(); /** Destructor. */ ~MixerAudioSource(); /** Adds an input source to the mixer. If the mixer is running you'll need to make sure that the input source is ready to play by calling its prepareToPlay() method before adding it. If the mixer is stopped, then its input sources will be automatically prepared when the mixer's prepareToPlay() method is called. @param newInput the source to add to the mixer @param deleteWhenRemoved if true, then this source will be deleted when the mixer is deleted or when removeAllInputs() is called (unless the source is previously removed with the removeInputSource method) */ void addInputSource (AudioSource* newInput, bool deleteWhenRemoved); /** Removes an input source. If the mixer is running, this will remove the source but not call its releaseResources() method, so the caller might want to do this manually. @param input the source to remove @param deleteSource whether to delete this source after it's been removed */ void removeInputSource (AudioSource* input, bool deleteSource); /** Removes all the input sources. If the mixer is running, this will remove the sources but not call their releaseResources() method, so the caller might want to do this manually. Any sources which were added with the deleteWhenRemoved flag set will be deleted by this method. */ void removeAllInputs(); /** Implementation of the AudioSource method. This will call prepareToPlay() on all its input sources. */ void prepareToPlay (int samplesPerBlockExpected, double sampleRate); /** Implementation of the AudioSource method. This will call releaseResources() on all its input sources. */ void releaseResources(); /** Implementation of the AudioSource method. */ void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); private: Array inputs; BigInteger inputsToDelete; CriticalSection lock; AudioSampleBuffer tempBuffer; double currentSampleRate; int bufferSizeExpected; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MixerAudioSource); }; #endif // __JUCE_MIXERAUDIOSOURCE_JUCEHEADER__ /*** End of inlined file: juce_MixerAudioSource.h ***/ #endif #ifndef __JUCE_POSITIONABLEAUDIOSOURCE_JUCEHEADER__ #endif #ifndef __JUCE_RESAMPLINGAUDIOSOURCE_JUCEHEADER__ #endif #ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ /*** Start of inlined file: juce_ToneGeneratorAudioSource.h ***/ #ifndef __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ #define __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ /** A simple AudioSource that generates a sine wave. */ class JUCE_API ToneGeneratorAudioSource : public AudioSource { public: /** Creates a ToneGeneratorAudioSource. */ ToneGeneratorAudioSource(); /** Destructor. */ ~ToneGeneratorAudioSource(); /** Sets the signal's amplitude. */ void setAmplitude (float newAmplitude); /** Sets the signal's frequency. */ void setFrequency (double newFrequencyHz); /** Implementation of the AudioSource method. */ void prepareToPlay (int samplesPerBlockExpected, double sampleRate); /** Implementation of the AudioSource method. */ void releaseResources(); /** Implementation of the AudioSource method. */ void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill); private: double frequency, sampleRate; double currentPhase, phasePerSample; float amplitude; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToneGeneratorAudioSource); }; #endif // __JUCE_TONEGENERATORAUDIOSOURCE_JUCEHEADER__ /*** End of inlined file: juce_ToneGeneratorAudioSource.h ***/ #endif #ifndef __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ /*** Start of inlined file: juce_AudioDeviceManager.h ***/ #ifndef __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ #define __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__ /*** Start of inlined file: juce_AudioIODeviceType.h ***/ #ifndef __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ #define __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ class AudioDeviceManager; class Component; /** Represents a type of audio driver, such as DirectSound, ASIO, CoreAudio, etc. To get a list of available audio driver types, use the AudioDeviceManager::createAudioDeviceTypes() method. Each of the objects returned can then be used to list the available devices of that type. E.g. @code OwnedArray types; myAudioDeviceManager.createAudioDeviceTypes (types); for (int i = 0; i < types.size(); ++i) { String typeName (types[i]->getTypeName()); // This will be things like "DirectSound", "CoreAudio", etc. types[i]->scanForDevices(); // This must be called before getting the list of devices StringArray deviceNames (types[i]->getDeviceNames()); // This will now return a list of available devices of this type for (int j = 0; j < deviceNames.size(); ++j) { AudioIODevice* device = types[i]->createDevice (deviceNames [j]); ... } } @endcode For an easier way of managing audio devices and their settings, have a look at the AudioDeviceManager class. @see AudioIODevice, AudioDeviceManager */ class JUCE_API AudioIODeviceType { public: /** Returns the name of this type of driver that this object manages. This will be something like "DirectSound", "ASIO", "CoreAudio", "ALSA", etc. */ const String& getTypeName() const throw() { return typeName; } /** Refreshes the object's cached list of known devices. This must be called at least once before calling getDeviceNames() or any of the other device creation methods. */ virtual void scanForDevices() = 0; /** Returns the list of available devices of this type. The scanForDevices() method must have been called to create this list. @param wantInputNames only really used by DirectSound where devices are split up into inputs and outputs, this indicates whether to use the input or output name to refer to a pair of devices. */ virtual const StringArray getDeviceNames (bool wantInputNames = false) const = 0; /** Returns the name of the default device. This will be one of the names from the getDeviceNames() list. @param forInput if true, this means that a default input device should be returned; if false, it should return the default output */ virtual int getDefaultDeviceIndex (bool forInput) const = 0; /** Returns the index of a given device in the list of device names. If asInput is true, it shows the index in the inputs list, otherwise it looks for it in the outputs list. */ virtual int getIndexOfDevice (AudioIODevice* device, bool asInput) const = 0; /** Returns true if two different devices can be used for the input and output. */ virtual bool hasSeparateInputsAndOutputs() const = 0; /** Creates one of the devices of this type. The deviceName must be one of the strings returned by getDeviceNames(), and scanForDevices() must have been called before this method is used. */ virtual AudioIODevice* createDevice (const String& outputDeviceName, const String& inputDeviceName) = 0; struct DeviceSetupDetails { AudioDeviceManager* manager; int minNumInputChannels, maxNumInputChannels; int minNumOutputChannels, maxNumOutputChannels; bool useStereoPairs; }; /** Destructor. */ virtual ~AudioIODeviceType(); protected: explicit AudioIODeviceType (const String& typeName); private: String typeName; JUCE_DECLARE_NON_COPYABLE (AudioIODeviceType); }; #endif // __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__ /*** End of inlined file: juce_AudioIODeviceType.h ***/ /*** Start of inlined file: juce_MidiInput.h ***/ #ifndef __JUCE_MIDIINPUT_JUCEHEADER__ #define __JUCE_MIDIINPUT_JUCEHEADER__ /*** Start of inlined file: juce_MidiMessage.h ***/ #ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__ #define __JUCE_MIDIMESSAGE_JUCEHEADER__ /** Encapsulates a MIDI message. @see MidiMessageSequence, MidiOutput, MidiInput */ class JUCE_API MidiMessage { public: /** Creates a 3-byte short midi message. @param byte1 message byte 1 @param byte2 message byte 2 @param byte3 message byte 3 @param timeStamp the time to give the midi message - this value doesn't use any particular units, so will be application-specific */ MidiMessage (int byte1, int byte2, int byte3, double timeStamp = 0) throw(); /** Creates a 2-byte short midi message. @param byte1 message byte 1 @param byte2 message byte 2 @param timeStamp the time to give the midi message - this value doesn't use any particular units, so will be application-specific */ MidiMessage (int byte1, int byte2, double timeStamp = 0) throw(); /** Creates a 1-byte short midi message. @param byte1 message byte 1 @param timeStamp the time to give the midi message - this value doesn't use any particular units, so will be application-specific */ MidiMessage (int byte1, double timeStamp = 0) throw(); /** Creates a midi message from a block of data. */ MidiMessage (const void* data, int numBytes, double timeStamp = 0); /** Reads the next midi message from some data. This will read as many bytes from a data stream as it needs to make a complete message, and will return the number of bytes it used. This lets you read a sequence of midi messages from a file or stream. @param data the data to read from @param maxBytesToUse the maximum number of bytes it's allowed to read @param numBytesUsed returns the number of bytes that were actually needed @param lastStatusByte in a sequence of midi messages, the initial byte can be dropped from a message if it's the same as the first byte of the previous message, so this lets you supply the byte to use if the first byte of the message has in fact been dropped. @param timeStamp the time to give the midi message - this value doesn't use any particular units, so will be application-specific */ MidiMessage (const void* data, int maxBytesToUse, int& numBytesUsed, uint8 lastStatusByte, double timeStamp = 0); /** Creates an active-sense message. Since the MidiMessage has to contain a valid message, this default constructor just initialises it with an empty sysex message. */ MidiMessage() throw(); /** Creates a copy of another midi message. */ MidiMessage (const MidiMessage& other); /** Creates a copy of another midi message, with a different timestamp. */ MidiMessage (const MidiMessage& other, double newTimeStamp); /** Destructor. */ ~MidiMessage(); /** Copies this message from another one. */ MidiMessage& operator= (const MidiMessage& other); /** Returns a pointer to the raw midi data. @see getRawDataSize */ uint8* getRawData() const throw() { return data; } /** Returns the number of bytes of data in the message. @see getRawData */ int getRawDataSize() const throw() { return size; } /** Returns the timestamp associated with this message. The exact meaning of this time and its units will vary, as messages are used in a variety of different contexts. If you're getting the message from a midi file, this could be a time in seconds, or a number of ticks - see MidiFile::convertTimestampTicksToSeconds(). If the message is being used in a MidiBuffer, it might indicate the number of audio samples from the start of the buffer. If the message was created by a MidiInput, see MidiInputCallback::handleIncomingMidiMessage() for details of the way that it initialises this value. @see setTimeStamp, addToTimeStamp */ double getTimeStamp() const throw() { return timeStamp; } /** Changes the message's associated timestamp. The units for the timestamp will be application-specific - see the notes for getTimeStamp(). @see addToTimeStamp, getTimeStamp */ void setTimeStamp (double newTimestamp) throw() { timeStamp = newTimestamp; } /** Adds a value to the message's timestamp. The units for the timestamp will be application-specific. */ void addToTimeStamp (double delta) throw() { timeStamp += delta; } /** Returns the midi channel associated with the message. @returns a value 1 to 16 if the message has a channel, or 0 if it hasn't (e.g. if it's a sysex) @see isForChannel, setChannel */ int getChannel() const throw(); /** Returns true if the message applies to the given midi channel. @param channelNumber the channel number to look for, in the range 1 to 16 @see getChannel, setChannel */ bool isForChannel (int channelNumber) const throw(); /** Changes the message's midi channel. This won't do anything for non-channel messages like sysexes. @param newChannelNumber the channel number to change it to, in the range 1 to 16 */ void setChannel (int newChannelNumber) throw(); /** Returns true if this is a system-exclusive message. */ bool isSysEx() const throw(); /** Returns a pointer to the sysex data inside the message. If this event isn't a sysex event, it'll return 0. @see getSysExDataSize */ const uint8* getSysExData() const throw(); /** Returns the size of the sysex data. This value excludes the 0xf0 header byte and the 0xf7 at the end. @see getSysExData */ int getSysExDataSize() const throw(); /** Returns true if this message is a 'key-down' event. @param returnTrueForVelocity0 if true, then if this event is a note-on with velocity 0, it will still be considered to be a note-on and the method will return true. If returnTrueForVelocity0 is false, then if this is a note-on event with velocity 0, it'll be regarded as a note-off, and the method will return false @see isNoteOff, getNoteNumber, getVelocity, noteOn */ bool isNoteOn (bool returnTrueForVelocity0 = false) const throw(); /** Creates a key-down message (using a floating-point velocity). @param channel the midi channel, in the range 1 to 16 @param noteNumber the key number, 0 to 127 @param velocity in the range 0 to 1.0 @see isNoteOn */ static const MidiMessage noteOn (int channel, int noteNumber, float velocity) throw(); /** Creates a key-down message (using an integer velocity). @param channel the midi channel, in the range 1 to 16 @param noteNumber the key number, 0 to 127 @param velocity in the range 0 to 127 @see isNoteOn */ static const MidiMessage noteOn (int channel, int noteNumber, uint8 velocity) throw(); /** Returns true if this message is a 'key-up' event. If returnTrueForNoteOnVelocity0 is true, then his will also return true for a note-on event with a velocity of 0. @see isNoteOn, getNoteNumber, getVelocity, noteOff */ bool isNoteOff (bool returnTrueForNoteOnVelocity0 = true) const throw(); /** Creates a key-up message. @param channel the midi channel, in the range 1 to 16 @param noteNumber the key number, 0 to 127 @see isNoteOff */ static const MidiMessage noteOff (int channel, int noteNumber) throw(); /** Returns true if this message is a 'key-down' or 'key-up' event. @see isNoteOn, isNoteOff */ bool isNoteOnOrOff() const throw(); /** Returns the midi note number for note-on and note-off messages. If the message isn't a note-on or off, the value returned will be meaningless. @see isNoteOff, getMidiNoteName, getMidiNoteInHertz, setNoteNumber */ int getNoteNumber() const throw(); /** Changes the midi note number of a note-on or note-off message. If the message isn't a note on or off, this will do nothing. */ void setNoteNumber (int newNoteNumber) throw(); /** Returns the velocity of a note-on or note-off message. The value returned will be in the range 0 to 127. If the message isn't a note-on or off event, it will return 0. @see getFloatVelocity */ uint8 getVelocity() const throw(); /** Returns the velocity of a note-on or note-off message. The value returned will be in the range 0 to 1.0 If the message isn't a note-on or off event, it will return 0. @see getVelocity, setVelocity */ float getFloatVelocity() const throw(); /** Changes the velocity of a note-on or note-off message. If the message isn't a note on or off, this will do nothing. @param newVelocity the new velocity, in the range 0 to 1.0 @see getFloatVelocity, multiplyVelocity */ void setVelocity (float newVelocity) throw(); /** Multiplies the velocity of a note-on or note-off message by a given amount. If the message isn't a note on or off, this will do nothing. @param scaleFactor the value by which to multiply the velocity @see setVelocity */ void multiplyVelocity (float scaleFactor) throw(); /** Returns true if the message is a program (patch) change message. @see getProgramChangeNumber, getGMInstrumentName */ bool isProgramChange() const throw(); /** Returns the new program number of a program change message. If the message isn't a program change, the value returned will be nonsense. @see isProgramChange, getGMInstrumentName */ int getProgramChangeNumber() const throw(); /** Creates a program-change message. @param channel the midi channel, in the range 1 to 16 @param programNumber the midi program number, 0 to 127 @see isProgramChange, getGMInstrumentName */ static const MidiMessage programChange (int channel, int programNumber) throw(); /** Returns true if the message is a pitch-wheel move. @see getPitchWheelValue, pitchWheel */ bool isPitchWheel() const throw(); /** Returns the pitch wheel position from a pitch-wheel move message. The value returned is a 14-bit number from 0 to 0x3fff, indicating the wheel position. If called for messages which aren't pitch wheel events, the number returned will be nonsense. @see isPitchWheel */ int getPitchWheelValue() const throw(); /** Creates a pitch-wheel move message. @param channel the midi channel, in the range 1 to 16 @param position the wheel position, in the range 0 to 16383 @see isPitchWheel */ static const MidiMessage pitchWheel (int channel, int position) throw(); /** Returns true if the message is an aftertouch event. For aftertouch events, use the getNoteNumber() method to find out the key that it applies to, and getAftertouchValue() to find out the amount. Use getChannel() to find out the channel. @see getAftertouchValue, getNoteNumber */ bool isAftertouch() const throw(); /** Returns the amount of aftertouch from an aftertouch messages. The value returned is in the range 0 to 127, and will be nonsense for messages other than aftertouch messages. @see isAftertouch */ int getAfterTouchValue() const throw(); /** Creates an aftertouch message. @param channel the midi channel, in the range 1 to 16 @param noteNumber the key number, 0 to 127 @param aftertouchAmount the amount of aftertouch, 0 to 127 @see isAftertouch */ static const MidiMessage aftertouchChange (int channel, int noteNumber, int aftertouchAmount) throw(); /** Returns true if the message is a channel-pressure change event. This is like aftertouch, but common to the whole channel rather than a specific note. Use getChannelPressureValue() to find out the pressure, and getChannel() to find out the channel. @see channelPressureChange */ bool isChannelPressure() const throw(); /** Returns the pressure from a channel pressure change message. @returns the pressure, in the range 0 to 127 @see isChannelPressure, channelPressureChange */ int getChannelPressureValue() const throw(); /** Creates a channel-pressure change event. @param channel the midi channel: 1 to 16 @param pressure the pressure, 0 to 127 @see isChannelPressure */ static const MidiMessage channelPressureChange (int channel, int pressure) throw(); /** Returns true if this is a midi controller message. @see getControllerNumber, getControllerValue, controllerEvent */ bool isController() const throw(); /** Returns the controller number of a controller message. The name of the controller can be looked up using the getControllerName() method. Note that the value returned is invalid for messages that aren't controller changes. @see isController, getControllerName, getControllerValue */ int getControllerNumber() const throw(); /** Returns the controller value from a controller message. A value 0 to 127 is returned to indicate the new controller position. Note that the value returned is invalid for messages that aren't controller changes. @see isController, getControllerNumber */ int getControllerValue() const throw(); /** Creates a controller message. @param channel the midi channel, in the range 1 to 16 @param controllerType the type of controller @param value the controller value @see isController */ static const MidiMessage controllerEvent (int channel, int controllerType, int value) throw(); /** Checks whether this message is an all-notes-off message. @see allNotesOff */ bool isAllNotesOff() const throw(); /** Checks whether this message is an all-sound-off message. @see allSoundOff */ bool isAllSoundOff() const throw(); /** Creates an all-notes-off message. @param channel the midi channel, in the range 1 to 16 @see isAllNotesOff */ static const MidiMessage allNotesOff (int channel) throw(); /** Creates an all-sound-off message. @param channel the midi channel, in the range 1 to 16 @see isAllSoundOff */ static const MidiMessage allSoundOff (int channel) throw(); /** Creates an all-controllers-off message. @param channel the midi channel, in the range 1 to 16 */ static const MidiMessage allControllersOff (int channel) throw(); /** Returns true if this event is a meta-event. Meta-events are things like tempo changes, track names, etc. @see getMetaEventType, isTrackMetaEvent, isEndOfTrackMetaEvent, isTextMetaEvent, isTrackNameEvent, isTempoMetaEvent, isTimeSignatureMetaEvent, isKeySignatureMetaEvent, isMidiChannelMetaEvent */ bool isMetaEvent() const throw(); /** Returns a meta-event's type number. If the message isn't a meta-event, this will return -1. @see isMetaEvent, isTrackMetaEvent, isEndOfTrackMetaEvent, isTextMetaEvent, isTrackNameEvent, isTempoMetaEvent, isTimeSignatureMetaEvent, isKeySignatureMetaEvent, isMidiChannelMetaEvent */ int getMetaEventType() const throw(); /** Returns a pointer to the data in a meta-event. @see isMetaEvent, getMetaEventLength */ const uint8* getMetaEventData() const throw(); /** Returns the length of the data for a meta-event. @see isMetaEvent, getMetaEventData */ int getMetaEventLength() const throw(); /** Returns true if this is a 'track' meta-event. */ bool isTrackMetaEvent() const throw(); /** Returns true if this is an 'end-of-track' meta-event. */ bool isEndOfTrackMetaEvent() const throw(); /** Creates an end-of-track meta-event. @see isEndOfTrackMetaEvent */ static const MidiMessage endOfTrack() throw(); /** Returns true if this is an 'track name' meta-event. You can use the getTextFromTextMetaEvent() method to get the track's name. */ bool isTrackNameEvent() const throw(); /** Returns true if this is a 'text' meta-event. @see getTextFromTextMetaEvent */ bool isTextMetaEvent() const throw(); /** Returns the text from a text meta-event. @see isTextMetaEvent */ const String getTextFromTextMetaEvent() const; /** Returns true if this is a 'tempo' meta-event. @see getTempoMetaEventTickLength, getTempoSecondsPerQuarterNote */ bool isTempoMetaEvent() const throw(); /** Returns the tick length from a tempo meta-event. @param timeFormat the 16-bit time format value from the midi file's header. @returns the tick length (in seconds). @see isTempoMetaEvent */ double getTempoMetaEventTickLength (short timeFormat) const throw(); /** Calculates the seconds-per-quarter-note from a tempo meta-event. @see isTempoMetaEvent, getTempoMetaEventTickLength */ double getTempoSecondsPerQuarterNote() const throw(); /** Creates a tempo meta-event. @see isTempoMetaEvent */ static const MidiMessage tempoMetaEvent (int microsecondsPerQuarterNote) throw(); /** Returns true if this is a 'time-signature' meta-event. @see getTimeSignatureInfo */ bool isTimeSignatureMetaEvent() const throw(); /** Returns the time-signature values from a time-signature meta-event. @see isTimeSignatureMetaEvent */ void getTimeSignatureInfo (int& numerator, int& denominator) const throw(); /** Creates a time-signature meta-event. @see isTimeSignatureMetaEvent */ static const MidiMessage timeSignatureMetaEvent (int numerator, int denominator); /** Returns true if this is a 'key-signature' meta-event. @see getKeySignatureNumberOfSharpsOrFlats */ bool isKeySignatureMetaEvent() const throw(); /** Returns the key from a key-signature meta-event. @see isKeySignatureMetaEvent */ int getKeySignatureNumberOfSharpsOrFlats() const throw(); /** Returns true if this is a 'channel' meta-event. A channel meta-event specifies the midi channel that should be used for subsequent meta-events. @see getMidiChannelMetaEventChannel */ bool isMidiChannelMetaEvent() const throw(); /** Returns the channel number from a channel meta-event. @returns the channel, in the range 1 to 16. @see isMidiChannelMetaEvent */ int getMidiChannelMetaEventChannel() const throw(); /** Creates a midi channel meta-event. @param channel the midi channel, in the range 1 to 16 @see isMidiChannelMetaEvent */ static const MidiMessage midiChannelMetaEvent (int channel) throw(); /** Returns true if this is an active-sense message. */ bool isActiveSense() const throw(); /** Returns true if this is a midi start event. @see midiStart */ bool isMidiStart() const throw(); /** Creates a midi start event. */ static const MidiMessage midiStart() throw(); /** Returns true if this is a midi continue event. @see midiContinue */ bool isMidiContinue() const throw(); /** Creates a midi continue event. */ static const MidiMessage midiContinue() throw(); /** Returns true if this is a midi stop event. @see midiStop */ bool isMidiStop() const throw(); /** Creates a midi stop event. */ static const MidiMessage midiStop() throw(); /** Returns true if this is a midi clock event. @see midiClock, songPositionPointer */ bool isMidiClock() const throw(); /** Creates a midi clock event. */ static const MidiMessage midiClock() throw(); /** Returns true if this is a song-position-pointer message. @see getSongPositionPointerMidiBeat, songPositionPointer */ bool isSongPositionPointer() const throw(); /** Returns the midi beat-number of a song-position-pointer message. @see isSongPositionPointer, songPositionPointer */ int getSongPositionPointerMidiBeat() const throw(); /** Creates a song-position-pointer message. The position is a number of midi beats from the start of the song, where 1 midi beat is 6 midi clocks, and there are 24 midi clocks in a quarter-note. So there are 4 midi beats in a quarter-note. @see isSongPositionPointer, getSongPositionPointerMidiBeat */ static const MidiMessage songPositionPointer (int positionInMidiBeats) throw(); /** Returns true if this is a quarter-frame midi timecode message. @see quarterFrame, getQuarterFrameSequenceNumber, getQuarterFrameValue */ bool isQuarterFrame() const throw(); /** Returns the sequence number of a quarter-frame midi timecode message. This will be a value between 0 and 7. @see isQuarterFrame, getQuarterFrameValue, quarterFrame */ int getQuarterFrameSequenceNumber() const throw(); /** Returns the value from a quarter-frame message. This will be the lower nybble of the message's data-byte, a value between 0 and 15 */ int getQuarterFrameValue() const throw(); /** Creates a quarter-frame MTC message. @param sequenceNumber a value 0 to 7 for the upper nybble of the message's data byte @param value a value 0 to 15 for the lower nybble of the message's data byte */ static const MidiMessage quarterFrame (int sequenceNumber, int value) throw(); /** SMPTE timecode types. Used by the getFullFrameParameters() and fullFrame() methods. */ enum SmpteTimecodeType { fps24 = 0, fps25 = 1, fps30drop = 2, fps30 = 3 }; /** Returns true if this is a full-frame midi timecode message. */ bool isFullFrame() const throw(); /** Extracts the timecode information from a full-frame midi timecode message. You should only call this on messages where you've used isFullFrame() to check that they're the right kind. */ void getFullFrameParameters (int& hours, int& minutes, int& seconds, int& frames, SmpteTimecodeType& timecodeType) const throw(); /** Creates a full-frame MTC message. */ static const MidiMessage fullFrame (int hours, int minutes, int seconds, int frames, SmpteTimecodeType timecodeType); /** Types of MMC command. @see isMidiMachineControlMessage, getMidiMachineControlCommand, midiMachineControlCommand */ enum MidiMachineControlCommand { mmc_stop = 1, mmc_play = 2, mmc_deferredplay = 3, mmc_fastforward = 4, mmc_rewind = 5, mmc_recordStart = 6, mmc_recordStop = 7, mmc_pause = 9 }; /** Checks whether this is an MMC message. If it is, you can use the getMidiMachineControlCommand() to find out its type. */ bool isMidiMachineControlMessage() const throw(); /** For an MMC message, this returns its type. Make sure it's actually an MMC message with isMidiMachineControlMessage() before calling this method. */ MidiMachineControlCommand getMidiMachineControlCommand() const throw(); /** Creates an MMC message. */ static const MidiMessage midiMachineControlCommand (MidiMachineControlCommand command); /** Checks whether this is an MMC "goto" message. If it is, the parameters passed-in are set to the time that the message contains. @see midiMachineControlGoto */ bool isMidiMachineControlGoto (int& hours, int& minutes, int& seconds, int& frames) const throw(); /** Creates an MMC "goto" message. This messages tells the device to go to a specific frame. @see isMidiMachineControlGoto */ static const MidiMessage midiMachineControlGoto (int hours, int minutes, int seconds, int frames); /** Creates a master-volume change message. @param volume the volume, 0 to 1.0 */ static const MidiMessage masterVolume (float volume); /** Creates a system-exclusive message. The data passed in is wrapped with header and tail bytes of 0xf0 and 0xf7. */ static const MidiMessage createSysExMessage (const uint8* sysexData, int dataSize); /** Reads a midi variable-length integer. @param data the data to read the number from @param numBytesUsed on return, this will be set to the number of bytes that were read */ static int readVariableLengthVal (const uint8* data, int& numBytesUsed) throw(); /** Based on the first byte of a short midi message, this uses a lookup table to return the message length (either 1, 2, or 3 bytes). The value passed in must be 0x80 or higher. */ static int getMessageLengthFromFirstByte (const uint8 firstByte) throw(); /** Returns the name of a midi note number. E.g "C", "D#", etc. @param noteNumber the midi note number, 0 to 127 @param useSharps if true, sharpened notes are used, e.g. "C#", otherwise they'll be flattened, e.g. "Db" @param includeOctaveNumber if true, the octave number will be appended to the string, e.g. "C#4" @param octaveNumForMiddleC if an octave number is being appended, this indicates the number that will be used for middle C's octave @see getMidiNoteInHertz */ static const String getMidiNoteName (int noteNumber, bool useSharps, bool includeOctaveNumber, int octaveNumForMiddleC); /** Returns the frequency of a midi note number. The frequencyOfA parameter is an optional frequency for 'A', normally 440-444Hz for concert pitch. @see getMidiNoteName */ static const double getMidiNoteInHertz (int noteNumber, const double frequencyOfA = 440.0) throw(); /** Returns the standard name of a GM instrument. @param midiInstrumentNumber the program number 0 to 127 @see getProgramChangeNumber */ static const String getGMInstrumentName (int midiInstrumentNumber); /** Returns the name of a bank of GM instruments. @param midiBankNumber the bank, 0 to 15 */ static const String getGMInstrumentBankName (int midiBankNumber); /** Returns the standard name of a channel 10 percussion sound. @param midiNoteNumber the key number, 35 to 81 */ static const String getRhythmInstrumentName (int midiNoteNumber); /** Returns the name of a controller type number. @see getControllerNumber */ static const String getControllerName (int controllerNumber); private: double timeStamp; uint8* data; int size; #ifndef DOXYGEN union { uint8 asBytes[4]; uint32 asInt32; } preallocatedData; #endif }; #endif // __JUCE_MIDIMESSAGE_JUCEHEADER__ /*** End of inlined file: juce_MidiMessage.h ***/ class MidiInput; /** Receives midi messages from a midi input device. This class is overridden to handle incoming midi messages. See the MidiInput class for more details. @see MidiInput */ class JUCE_API MidiInputCallback { public: /** Destructor. */ virtual ~MidiInputCallback() {} /** Receives an incoming message. A MidiInput object will call this method when a midi event arrives. It'll be called on a high-priority system thread, so avoid doing anything time-consuming in here, and avoid making any UI calls. You might find the MidiBuffer class helpful for queueing incoming messages for use later. @param source the MidiInput object that generated the message @param message the incoming message. The message's timestamp is set to a value equivalent to (Time::getMillisecondCounter() / 1000.0) to specify the time when the message arrived. */ virtual void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message) = 0; /** Notification sent each time a packet of a multi-packet sysex message arrives. If a long sysex message is broken up into multiple packets, this callback is made for each packet that arrives until the message is finished, at which point the normal handleIncomingMidiMessage() callback will be made with the entire message. The message passed in will contain the start of a sysex, but won't be finished with the terminating 0xf7 byte. */ virtual void handlePartialSysexMessage (MidiInput* source, const uint8* messageData, const int numBytesSoFar, const double timestamp) { // (this bit is just to avoid compiler warnings about unused variables) (void) source; (void) messageData; (void) numBytesSoFar; (void) timestamp; } }; /** Represents a midi input device. To create one of these, use the static getDevices() method to find out what inputs are available, and then use the openDevice() method to try to open one. @see MidiOutput */ class JUCE_API MidiInput { public: /** Returns a list of the available midi input devices. You can open one of the devices by passing its index into the openDevice() method. @see getDefaultDeviceIndex, openDevice */ static const StringArray getDevices(); /** Returns the index of the default midi input device to use. This refers to the index in the list returned by getDevices(). */ static int getDefaultDeviceIndex(); /** Tries to open one of the midi input devices. This will return a MidiInput object if it manages to open it. You can then call start() and stop() on this device, and delete it when no longer needed. If the device can't be opened, this will return a null pointer. @param deviceIndex the index of a device from the list returned by getDevices() @param callback the object that will receive the midi messages from this device. @see MidiInputCallback, getDevices */ static MidiInput* openDevice (int deviceIndex, MidiInputCallback* callback); #if JUCE_LINUX || JUCE_MAC || DOXYGEN /** This will try to create a new midi input device (Not available on Windows). This will attempt to create a new midi input device with the specified name, for other apps to connect to. Returns 0 if a device can't be created. @param deviceName the name to use for the new device @param callback the object that will receive the midi messages from this device. */ static MidiInput* createNewDevice (const String& deviceName, MidiInputCallback* callback); #endif /** Destructor. */ virtual ~MidiInput(); /** Returns the name of this device. */ virtual const String getName() const throw() { return name; } /** Allows you to set a custom name for the device, in case you don't like the name it was given when created. */ virtual void setName (const String& newName) throw() { name = newName; } /** Starts the device running. After calling this, the device will start sending midi messages to the MidiInputCallback object that was specified when the openDevice() method was called. @see stop */ virtual void start(); /** Stops the device running. @see start */ virtual void stop(); protected: String name; void* internal; explicit MidiInput (const String& name); private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiInput); }; #endif // __JUCE_MIDIINPUT_JUCEHEADER__ /*** End of inlined file: juce_MidiInput.h ***/ /*** Start of inlined file: juce_MidiOutput.h ***/ #ifndef __JUCE_MIDIOUTPUT_JUCEHEADER__ #define __JUCE_MIDIOUTPUT_JUCEHEADER__ /*** Start of inlined file: juce_MidiBuffer.h ***/ #ifndef __JUCE_MIDIBUFFER_JUCEHEADER__ #define __JUCE_MIDIBUFFER_JUCEHEADER__ /** Holds a sequence of time-stamped midi events. Analogous to the AudioSampleBuffer, this holds a set of midi events with integer time-stamps. The buffer is kept sorted in order of the time-stamps. @see MidiMessage */ class JUCE_API MidiBuffer { public: /** Creates an empty MidiBuffer. */ MidiBuffer() throw(); /** Creates a MidiBuffer containing a single midi message. */ explicit MidiBuffer (const MidiMessage& message) throw(); /** Creates a copy of another MidiBuffer. */ MidiBuffer (const MidiBuffer& other) throw(); /** Makes a copy of another MidiBuffer. */ MidiBuffer& operator= (const MidiBuffer& other) throw(); /** Destructor */ ~MidiBuffer(); /** Removes all events from the buffer. */ void clear() throw(); /** Removes all events between two times from the buffer. All events for which (start <= event position < start + numSamples) will be removed. */ void clear (int start, int numSamples); /** Returns true if the buffer is empty. To actually retrieve the events, use a MidiBuffer::Iterator object */ bool isEmpty() const throw(); /** Counts the number of events in the buffer. This is actually quite a slow operation, as it has to iterate through all the events, so you might prefer to call isEmpty() if that's all you need to know. */ int getNumEvents() const throw(); /** Adds an event to the buffer. The sample number will be used to determine the position of the event in the buffer, which is always kept sorted. The MidiMessage's timestamp is ignored. If an event is added whose sample position is the same as one or more events already in the buffer, the new event will be placed after the existing ones. To retrieve events, use a MidiBuffer::Iterator object */ void addEvent (const MidiMessage& midiMessage, int sampleNumber); /** Adds an event to the buffer from raw midi data. The sample number will be used to determine the position of the event in the buffer, which is always kept sorted. If an event is added whose sample position is the same as one or more events already in the buffer, the new event will be placed after the existing ones. The event data will be inspected to calculate the number of bytes in length that the midi event really takes up, so maxBytesOfMidiData may be longer than the data that actually gets stored. E.g. if you pass in a note-on and a length of 4 bytes, it'll actually only store 3 bytes. If the midi data is invalid, it might not add an event at all. To retrieve events, use a MidiBuffer::Iterator object */ void addEvent (const void* rawMidiData, int maxBytesOfMidiData, int sampleNumber); /** Adds some events from another buffer to this one. @param otherBuffer the buffer containing the events you want to add @param startSample the lowest sample number in the source buffer for which events should be added. Any source events whose timestamp is less than this will be ignored @param numSamples the valid range of samples from the source buffer for which events should be added - i.e. events in the source buffer whose timestamp is greater than or equal to (startSample + numSamples) will be ignored. If this value is less than 0, all events after startSample will be taken. @param sampleDeltaToAdd a value which will be added to the source timestamps of the events that are added to this buffer */ void addEvents (const MidiBuffer& otherBuffer, int startSample, int numSamples, int sampleDeltaToAdd); /** Returns the sample number of the first event in the buffer. If the buffer's empty, this will just return 0. */ int getFirstEventTime() const throw(); /** Returns the sample number of the last event in the buffer. If the buffer's empty, this will just return 0. */ int getLastEventTime() const throw(); /** Exchanges the contents of this buffer with another one. This is a quick operation, because no memory allocating or copying is done, it just swaps the internal state of the two buffers. */ void swapWith (MidiBuffer& other) throw(); /** Preallocates some memory for the buffer to use. This helps to avoid needing to reallocate space when the buffer has messages added to it. */ void ensureSize (size_t minimumNumBytes); /** Used to iterate through the events in a MidiBuffer. Note that altering the buffer while an iterator is using it isn't a safe operation. @see MidiBuffer */ class Iterator { public: /** Creates an Iterator for this MidiBuffer. */ Iterator (const MidiBuffer& buffer) throw(); /** Destructor. */ ~Iterator() throw(); /** Repositions the iterator so that the next event retrieved will be the first one whose sample position is at greater than or equal to the given position. */ void setNextSamplePosition (int samplePosition) throw(); /** Retrieves a copy of the next event from the buffer. @param result on return, this will be the message (the MidiMessage's timestamp is not set) @param samplePosition on return, this will be the position of the event @returns true if an event was found, or false if the iterator has reached the end of the buffer */ bool getNextEvent (MidiMessage& result, int& samplePosition) throw(); /** Retrieves the next event from the buffer. @param midiData on return, this pointer will be set to a block of data containing the midi message. Note that to make it fast, this is a pointer directly into the MidiBuffer's internal data, so is only valid temporarily until the MidiBuffer is altered. @param numBytesOfMidiData on return, this is the number of bytes of data used by the midi message @param samplePosition on return, this will be the position of the event @returns true if an event was found, or false if the iterator has reached the end of the buffer */ bool getNextEvent (const uint8* &midiData, int& numBytesOfMidiData, int& samplePosition) throw(); private: const MidiBuffer& buffer; const uint8* data; JUCE_DECLARE_NON_COPYABLE (Iterator); }; private: friend class MidiBuffer::Iterator; MemoryBlock data; int bytesUsed; uint8* getData() const throw(); uint8* findEventAfter (uint8* d, int samplePosition) const throw(); static int getEventTime (const void* d) throw(); static uint16 getEventDataSize (const void* d) throw(); static uint16 getEventTotalSize (const void* d) throw(); JUCE_LEAK_DETECTOR (MidiBuffer); }; #endif // __JUCE_MIDIBUFFER_JUCEHEADER__ /*** End of inlined file: juce_MidiBuffer.h ***/ /** Represents a midi output device. To create one of these, use the static getDevices() method to find out what outputs are available, then use the openDevice() method to try to open one. @see MidiInput */ class JUCE_API MidiOutput : private Thread { public: /** Returns a list of the available midi output devices. You can open one of the devices by passing its index into the openDevice() method. @see getDefaultDeviceIndex, openDevice */ static const StringArray getDevices(); /** Returns the index of the default midi output device to use. This refers to the index in the list returned by getDevices(). */ static int getDefaultDeviceIndex(); /** Tries to open one of the midi output devices. This will return a MidiOutput object if it manages to open it. You can then send messages to this device, and delete it when no longer needed. If the device can't be opened, this will return a null pointer. @param deviceIndex the index of a device from the list returned by getDevices() @see getDevices */ static MidiOutput* openDevice (int deviceIndex); #if JUCE_LINUX || JUCE_MAC || DOXYGEN /** This will try to create a new midi output device (Not available on Windows). This will attempt to create a new midi output device that other apps can connect to and use as their midi input. Returns 0 if a device can't be created. @param deviceName the name to use for the new device */ static MidiOutput* createNewDevice (const String& deviceName); #endif /** Destructor. */ virtual ~MidiOutput(); /** Makes this device output a midi message. @see MidiMessage */ virtual void sendMessageNow (const MidiMessage& message); /** Sends a midi reset to the device. */ virtual void reset(); /** Returns the current volume setting for this device. */ virtual bool getVolume (float& leftVol, float& rightVol); /** Changes the overall volume for this device. */ virtual void setVolume (float leftVol, float rightVol); /** This lets you supply a block of messages that will be sent out at some point in the future. The MidiOutput class has an internal thread that can send out timestamped messages - this appends a set of messages to its internal buffer, ready for sending. This will only work if you've already started the thread with startBackgroundThread(). A time is supplied, at which the block of messages should be sent. This time uses the same time base as Time::getMillisecondCounter(), and must be in the future. The samplesPerSecondForBuffer parameter indicates the number of samples per second used by the MidiBuffer. Each event in a MidiBuffer has a sample position, and the samplesPerSecondForBuffer value is needed to convert this sample position to a real time. */ virtual void sendBlockOfMessages (const MidiBuffer& buffer, double millisecondCounterToStartAt, double samplesPerSecondForBuffer); /** Gets rid of any midi messages that had been added by sendBlockOfMessages(). */ virtual void clearAllPendingMessages(); /** Starts up a background thread so that the device can send blocks of data. Call this to get the device ready, before using sendBlockOfMessages(). */ virtual void startBackgroundThread(); /** Stops the background thread, and clears any pending midi events. @see startBackgroundThread */ virtual void stopBackgroundThread(); protected: void* internal; struct PendingMessage { PendingMessage (const uint8* data, int len, double sampleNumber); MidiMessage message; PendingMessage* next; }; CriticalSection lock; PendingMessage* firstMessage; MidiOutput(); void run(); private: JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiOutput); }; #endif // __JUCE_MIDIOUTPUT_JUCEHEADER__ /*** End of inlined file: juce_MidiOutput.h ***/ /*** Start of inlined file: juce_ComboBox.h ***/ #ifndef __JUCE_COMBOBOX_JUCEHEADER__ #define __JUCE_COMBOBOX_JUCEHEADER__ /*** Start of inlined file: juce_Label.h ***/ #ifndef __JUCE_LABEL_JUCEHEADER__ #define __JUCE_LABEL_JUCEHEADER__ /*** Start of inlined file: juce_TextEditor.h ***/ #ifndef __JUCE_TEXTEDITOR_JUCEHEADER__ #define __JUCE_TEXTEDITOR_JUCEHEADER__ /*** Start of inlined file: juce_Viewport.h ***/ #ifndef __JUCE_VIEWPORT_JUCEHEADER__ #define __JUCE_VIEWPORT_JUCEHEADER__ /*** Start of inlined file: juce_ScrollBar.h ***/ #ifndef __JUCE_SCROLLBAR_JUCEHEADER__ #define __JUCE_SCROLLBAR_JUCEHEADER__ /*** Start of inlined file: juce_Button.h ***/ #ifndef __JUCE_BUTTON_JUCEHEADER__ #define __JUCE_BUTTON_JUCEHEADER__ /*** Start of inlined file: juce_TooltipWindow.h ***/ #ifndef __JUCE_TOOLTIPWINDOW_JUCEHEADER__ #define __JUCE_TOOLTIPWINDOW_JUCEHEADER__ /*** Start of inlined file: juce_TooltipClient.h ***/ #ifndef __JUCE_TOOLTIPCLIENT_JUCEHEADER__ #define __JUCE_TOOLTIPCLIENT_JUCEHEADER__ /** Components that want to use pop-up tooltips should implement this interface. A TooltipWindow will wait for the mouse to hover over a component that implements the TooltipClient interface, and when it finds one, it will display the tooltip returned by its getTooltip() method. @see TooltipWindow, SettableTooltipClient */ class JUCE_API TooltipClient { public: /** Destructor. */ virtual ~TooltipClient() {} /** Returns the string that this object wants to show as its tooltip. */ virtual const String getTooltip() = 0; }; /** An implementation of TooltipClient that stores the tooltip string and a method for changing it. This makes it easy to add a tooltip to a custom component, by simply adding this as a base class and calling setTooltip(). Many of the Juce widgets already use this as a base class to implement their tooltips. @see TooltipClient, TooltipWindow */ class JUCE_API SettableTooltipClient : public TooltipClient { public: /** Destructor. */ virtual ~SettableTooltipClient() {} /** Assigns a new tooltip to this object. */ virtual void setTooltip (const String& newTooltip) { tooltipString = newTooltip; } /** Returns the tooltip assigned to this object. */ virtual const String getTooltip() { return tooltipString; } protected: SettableTooltipClient() {} private: String tooltipString; }; #endif // __JUCE_TOOLTIPCLIENT_JUCEHEADER__ /*** End of inlined file: juce_TooltipClient.h ***/ /** A window that displays a pop-up tooltip when the mouse hovers over another component. To enable tooltips in your app, just create a single instance of a TooltipWindow object. The TooltipWindow object will then stay invisible, waiting until the mouse hovers for the specified length of time - it will then see if it's currently over a component which implements the TooltipClient interface, and if so, it will make itself visible to show the tooltip in the appropriate place. @see TooltipClient, SettableTooltipClient */ class JUCE_API TooltipWindow : public Component, private Timer { public: /** Creates a tooltip window. Make sure your app only creates one instance of this class, otherwise you'll get multiple overlaid tooltips appearing. The window will initially be invisible and will make itself visible when it needs to display a tip. To change the style of tooltips, see the LookAndFeel class for its tooltip methods. @param parentComponent if set to 0, the TooltipWindow will appear on the desktop, otherwise the tooltip will be added to the given parent component. @param millisecondsBeforeTipAppears the time for which the mouse has to stay still before a tooltip will be shown @see TooltipClient, LookAndFeel::drawTooltip, LookAndFeel::getTooltipSize */ explicit TooltipWindow (Component* parentComponent = 0, int millisecondsBeforeTipAppears = 700); /** Destructor. */ ~TooltipWindow(); /** Changes the time before the tip appears. This lets you change the value that was set in the constructor. */ void setMillisecondsBeforeTipAppears (int newTimeMs = 700) throw(); /** A set of colour IDs to use to change the colour of various aspects of the tooltip. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() methods. @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ enum ColourIds { backgroundColourId = 0x1001b00, /**< The colour to fill the background with. */ textColourId = 0x1001c00, /**< The colour to use for the text. */ outlineColourId = 0x1001c10 /**< The colour to use to draw an outline around the tooltip. */ }; private: int millisecondsBeforeTipAppears; Point lastMousePos; int mouseClicks; unsigned int lastCompChangeTime, lastHideTime; Component* lastComponentUnderMouse; bool changedCompsSinceShown; String tipShowing, lastTipUnderMouse; void paint (Graphics& g); void mouseEnter (const MouseEvent& e); void timerCallback(); static const String getTipFor (Component* c); void showFor (const String& tip); void hide(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TooltipWindow); }; #endif // __JUCE_TOOLTIPWINDOW_JUCEHEADER__ /*** End of inlined file: juce_TooltipWindow.h ***/ #if JUCE_VC6 #define Listener ButtonListener #endif /** A base class for buttons. This contains all the logic for button behaviours such as enabling/disabling, responding to shortcut keystrokes, auto-repeating when held down, toggle-buttons and radio groups, etc. @see TextButton, DrawableButton, ToggleButton */ class JUCE_API Button : public Component, public SettableTooltipClient, public ApplicationCommandManagerListener, public ValueListener, private KeyListener { protected: /** Creates a button. @param buttonName the text to put in the button (the component's name is also initially set to this string, but these can be changed later using the setName() and setButtonText() methods) */ explicit Button (const String& buttonName); public: /** Destructor. */ virtual ~Button(); /** Changes the button's text. @see getButtonText */ void setButtonText (const String& newText); /** Returns the text displayed in the button. @see setButtonText */ const String getButtonText() const { return text; } /** Returns true if the button is currently being held down by the mouse. @see isOver */ bool isDown() const throw(); /** Returns true if the mouse is currently over the button. This will be also be true if the mouse is being held down. @see isDown */ bool isOver() const throw(); /** A button has an on/off state associated with it, and this changes that. By default buttons are 'off' and for simple buttons that you click to perform an action you won't change this. Toggle buttons, however will want to change their state when turned on or off. @param shouldBeOn whether to set the button's toggle state to be on or off. If it's a member of a button group, this will always try to turn it on, and to turn off any other buttons in the group @param sendChangeNotification if true, a callback will be made to clicked(); if false the button will be repainted but no notification will be sent @see getToggleState, setRadioGroupId */ void setToggleState (bool shouldBeOn, bool sendChangeNotification); /** Returns true if the button in 'on'. By default buttons are 'off' and for simple buttons that you click to perform an action you won't change this. Toggle buttons, however will want to change their state when turned on or off. @see setToggleState */ bool getToggleState() const throw() { return isOn.getValue(); } /** Returns the Value object that represents the botton's toggle state. You can use this Value object to connect the button's state to external values or setters, either by taking a copy of the Value, or by using Value::referTo() to make it point to your own Value object. @see getToggleState, Value */ Value& getToggleStateValue() { return isOn; } /** This tells the button to automatically flip the toggle state when the button is clicked. If set to true, then before the clicked() callback occurs, the toggle-state of the button is flipped. */ void setClickingTogglesState (bool shouldToggle) throw(); /** Returns true if this button is set to be an automatic toggle-button. This returns the last value that was passed to setClickingTogglesState(). */ bool getClickingTogglesState() const throw(); /** Enables the button to act as a member of a mutually-exclusive group of 'radio buttons'. If the group ID is set to a non-zero number, then this button will act as part of a group of buttons with the same ID, only one of which can be 'on' at the same time. Note that when it's part of a group, clicking a toggle-button that's 'on' won't turn it off. To find other buttons with the same ID, this button will search through its sibling components for ToggleButtons, so all the buttons for a particular group must be placed inside the same parent component. Set the group ID back to zero if you want it to act as a normal toggle button again. @see getRadioGroupId */ void setRadioGroupId (int newGroupId); /** Returns the ID of the group to which this button belongs. (See setRadioGroupId() for an explanation of this). */ int getRadioGroupId() const throw() { return radioGroupId; } /** Used to receive callbacks when a button is clicked. @see Button::addListener, Button::removeListener */ class JUCE_API Listener { public: /** Destructor. */ virtual ~Listener() {} /** Called when the button is clicked. */ virtual void buttonClicked (Button* button) = 0; /** Called when the button's state changes. */ virtual void buttonStateChanged (Button*) {} }; /** Registers a listener to receive events when this button's state changes. If the listener is already registered, this will not register it again. @see removeListener */ void addListener (Listener* newListener); /** Removes a previously-registered button listener @see addListener */ void removeListener (Listener* listener); /** Causes the button to act as if it's been clicked. This will asynchronously make the button draw itself going down and up, and will then call back the clicked() method as if mouse was clicked on it. @see clicked */ virtual void triggerClick(); /** Sets a command ID for this button to automatically invoke when it's clicked. When the button is pressed, it will use the given manager to trigger the command ID. Obviously be careful that the ApplicationCommandManager doesn't get deleted before this button is. To disable the command triggering, call this method and pass 0 for the parameters. If generateTooltip is true, then the button's tooltip will be automatically generated based on the name of this command and its current shortcut key. @see addShortcut, getCommandID */ void setCommandToTrigger (ApplicationCommandManager* commandManagerToUse, int commandID, bool generateTooltip); /** Returns the command ID that was set by setCommandToTrigger(). */ int getCommandID() const throw() { return commandID; } /** Assigns a shortcut key to trigger the button. The button registers itself with its top-level parent component for keypresses. Note that a different way of linking buttons to keypresses is by using the setCommandToTrigger() method to invoke a command. @see clearShortcuts */ void addShortcut (const KeyPress& key); /** Removes all key shortcuts that had been set for this button. @see addShortcut */ void clearShortcuts(); /** Returns true if the given keypress is a shortcut for this button. @see addShortcut */ bool isRegisteredForShortcut (const KeyPress& key) const; /** Sets an auto-repeat speed for the button when it is held down. (Auto-repeat is disabled by default). @param initialDelayInMillisecs how long to wait after the mouse is pressed before triggering the next click. If this is zero, auto-repeat is disabled @param repeatDelayInMillisecs the frequently subsequent repeated clicks should be triggered @param minimumDelayInMillisecs if this is greater than 0, the auto-repeat speed will get faster, the longer the button is held down, up to the minimum interval specified here */ void setRepeatSpeed (int initialDelayInMillisecs, int repeatDelayInMillisecs, int minimumDelayInMillisecs = -1) throw(); /** Sets whether the button click should happen when the mouse is pressed or released. By default the button is only considered to have been clicked when the mouse is released, but setting this to true will make it call the clicked() method as soon as the button is pressed. This is useful if the button is being used to show a pop-up menu, as it allows the click to be used as a drag onto the menu. */ void setTriggeredOnMouseDown (bool isTriggeredOnMouseDown) throw(); /** Returns the number of milliseconds since the last time the button went into the 'down' state. */ uint32 getMillisecondsSinceButtonDown() const throw(); /** Sets the tooltip for this button. @see TooltipClient, TooltipWindow */ void setTooltip (const String& newTooltip); // (implementation of the TooltipClient method) const String getTooltip(); /** A combination of these flags are used by setConnectedEdges(). */ enum ConnectedEdgeFlags { ConnectedOnLeft = 1, ConnectedOnRight = 2, ConnectedOnTop = 4, ConnectedOnBottom = 8 }; /** Hints about which edges of the button might be connected to adjoining buttons. The value passed in is a bitwise combination of any of the values in the ConnectedEdgeFlags enum. E.g. if you are placing two buttons adjacent to each other, you could use this to indicate which edges are touching, and the LookAndFeel might choose to drawn them without rounded corners on the edges that connect. It's only a hint, so the LookAndFeel can choose to ignore it if it's not relevent for this type of button. */ void setConnectedEdges (int connectedEdgeFlags); /** Returns the set of flags passed into setConnectedEdges(). */ int getConnectedEdgeFlags() const throw() { return connectedEdgeFlags; } /** Indicates whether the button adjoins another one on its left edge. @see setConnectedEdges */ bool isConnectedOnLeft() const throw() { return (connectedEdgeFlags & ConnectedOnLeft) != 0; } /** Indicates whether the button adjoins another one on its right edge. @see setConnectedEdges */ bool isConnectedOnRight() const throw() { return (connectedEdgeFlags & ConnectedOnRight) != 0; } /** Indicates whether the button adjoins another one on its top edge. @see setConnectedEdges */ bool isConnectedOnTop() const throw() { return (connectedEdgeFlags & ConnectedOnTop) != 0; } /** Indicates whether the button adjoins another one on its bottom edge. @see setConnectedEdges */ bool isConnectedOnBottom() const throw() { return (connectedEdgeFlags & ConnectedOnBottom) != 0; } /** Used by setState(). */ enum ButtonState { buttonNormal, buttonOver, buttonDown }; /** Can be used to force the button into a particular state. This only changes the button's appearance, it won't trigger a click, or stop any mouse-clicks from happening. The state that you set here will only last until it is automatically changed when the mouse enters or exits the button, or the mouse-button is pressed or released. */ void setState (const ButtonState newState); // These are deprecated - please use addListener() and removeListener() instead! JUCE_DEPRECATED (void addButtonListener (Listener*)); JUCE_DEPRECATED (void removeButtonListener (Listener*)); protected: /** This method is called when the button has been clicked. Subclasses can override this to perform whatever they actions they need to do. Alternatively, a ButtonListener can be added to the button, and these listeners will be called when the click occurs. @see triggerClick */ virtual void clicked(); /** This method is called when the button has been clicked. By default it just calls clicked(), but you might want to override it to handle things like clicking when a modifier key is pressed, etc. @see ModifierKeys */ virtual void clicked (const ModifierKeys& modifiers); /** Subclasses should override this to actually paint the button's contents. It's better to use this than the paint method, because it gives you information about the over/down state of the button. @param g the graphics context to use @param isMouseOverButton true if the button is either in the 'over' or 'down' state @param isButtonDown true if the button should be drawn in the 'down' position */ virtual void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown) = 0; /** Called when the button's up/down/over state changes. Subclasses can override this if they need to do something special when the button goes up or down. @see isDown, isOver */ virtual void buttonStateChanged(); /** @internal */ virtual void internalClickCallback (const ModifierKeys& modifiers); /** @internal */ void handleCommandMessage (int commandId); /** @internal */ void mouseEnter (const MouseEvent& e); /** @internal */ void mouseExit (const MouseEvent& e); /** @internal */ void mouseDown (const MouseEvent& e); /** @internal */ void mouseDrag (const MouseEvent& e); /** @internal */ void mouseUp (const MouseEvent& e); /** @internal */ bool keyPressed (const KeyPress& key); /** @internal */ bool keyPressed (const KeyPress& key, Component* originatingComponent); /** @internal */ bool keyStateChanged (bool isKeyDown, Component* originatingComponent); /** @internal */ void paint (Graphics& g); /** @internal */ void parentHierarchyChanged(); /** @internal */ void visibilityChanged(); /** @internal */ void focusGained (FocusChangeType cause); /** @internal */ void focusLost (FocusChangeType cause); /** @internal */ void enablementChanged(); /** @internal */ void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo&); /** @internal */ void applicationCommandListChanged(); /** @internal */ void valueChanged (Value& value); private: Array shortcuts; WeakReference keySource; String text; ListenerList buttonListeners; class RepeatTimer; friend class RepeatTimer; friend class ScopedPointer ; ScopedPointer repeatTimer; uint32 buttonPressTime, lastRepeatTime; ApplicationCommandManager* commandManagerToUse; int autoRepeatDelay, autoRepeatSpeed, autoRepeatMinimumDelay; int radioGroupId, commandID, connectedEdgeFlags; ButtonState buttonState; Value isOn; bool lastToggleState : 1; bool clickTogglesState : 1; bool needsToRelease : 1; bool needsRepainting : 1; bool isKeyDown : 1; bool triggerOnMouseDown : 1; bool generateTooltip : 1; void repeatTimerCallback(); RepeatTimer& getRepeatTimer(); ButtonState updateState(); ButtonState updateState (bool isOver, bool isDown); bool isShortcutPressed() const; void turnOffOtherButtonsInGroup (bool sendChangeNotification); void flashButtonState(); void sendClickMessage (const ModifierKeys& modifiers); void sendStateMessage(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Button); }; #ifndef DOXYGEN /** This typedef is just for compatibility with old code and VC6 - newer code should use Button::Listener instead. */ typedef Button::Listener ButtonListener; #endif #if JUCE_VC6 #undef Listener #endif #endif // __JUCE_BUTTON_JUCEHEADER__ /*** End of inlined file: juce_Button.h ***/ /** A scrollbar component. To use a scrollbar, set up its total range using the setRangeLimits() method - this sets the range of values it can represent. Then you can use setCurrentRange() to change the position and size of the scrollbar's 'thumb'. Registering a ScrollBar::Listener with the scrollbar will allow you to find out when the user moves it, and you can use the getCurrentRangeStart() to find out where they moved it to. The scrollbar will adjust its own visibility according to whether its thumb size allows it to actually be scrolled. For most purposes, it's probably easier to use a ViewportContainer or ListBox instead of handling a scrollbar directly. @see ScrollBar::Listener */ class JUCE_API ScrollBar : public Component, public AsyncUpdater, private Timer { public: /** Creates a Scrollbar. @param isVertical whether it should be a vertical or horizontal bar @param buttonsAreVisible whether to show the up/down or left/right buttons */ ScrollBar (bool isVertical, bool buttonsAreVisible = true); /** Destructor. */ ~ScrollBar(); /** Returns true if the scrollbar is vertical, false if it's horizontal. */ bool isVertical() const throw() { return vertical; } /** Changes the scrollbar's direction. You'll also need to resize the bar appropriately - this just changes its internal layout. @param shouldBeVertical true makes it vertical; false makes it horizontal. */ void setOrientation (bool shouldBeVertical); /** Shows or hides the scrollbar's buttons. */ void setButtonVisibility (bool buttonsAreVisible); /** Tells the scrollbar whether to make itself invisible when not needed. The default behaviour is for a scrollbar to become invisible when the thumb fills the whole of its range (i.e. when it can't be moved). Setting this value to false forces the bar to always be visible. @see autoHides() */ void setAutoHide (bool shouldHideWhenFullRange); /** Returns true if this scrollbar is set to auto-hide when its thumb is as big as its maximum range. @see setAutoHide */ bool autoHides() const throw(); /** Sets the minimum and maximum values that the bar will move between. The bar's thumb will always be constrained so that the entire thumb lies within this range. @see setCurrentRange */ void setRangeLimits (const Range& newRangeLimit); /** Sets the minimum and maximum values that the bar will move between. The bar's thumb will always be constrained so that the entire thumb lies within this range. @see setCurrentRange */ void setRangeLimits (double minimum, double maximum); /** Returns the current limits on the thumb position. @see setRangeLimits */ const Range getRangeLimit() const throw() { return totalRange; } /** Returns the lower value that the thumb can be set to. This is the value set by setRangeLimits(). */ double getMinimumRangeLimit() const throw() { return totalRange.getStart(); } /** Returns the upper value that the thumb can be set to. This is the value set by setRangeLimits(). */ double getMaximumRangeLimit() const throw() { return totalRange.getEnd(); } /** Changes the position of the scrollbar's 'thumb'. If this method call actually changes the scrollbar's position, it will trigger an asynchronous call to ScrollBar::Listener::scrollBarMoved() for all the listeners that are registered. @see getCurrentRange. setCurrentRangeStart */ void setCurrentRange (const Range& newRange); /** Changes the position of the scrollbar's 'thumb'. This sets both the position and size of the thumb - to just set the position without changing the size, you can use setCurrentRangeStart(). If this method call actually changes the scrollbar's position, it will trigger an asynchronous call to ScrollBar::Listener::scrollBarMoved() for all the listeners that are registered. @param newStart the top (or left) of the thumb, in the range getMinimumRangeLimit() <= newStart <= getMaximumRangeLimit(). If the value is beyond these limits, it will be clipped. @param newSize the size of the thumb, such that getMinimumRangeLimit() <= newStart + newSize <= getMaximumRangeLimit(). If the size is beyond these limits, it will be clipped. @see setCurrentRangeStart, getCurrentRangeStart, getCurrentRangeSize */ void setCurrentRange (double newStart, double newSize); /** Moves the bar's thumb position. This will move the thumb position without changing the thumb size. Note that the maximum thumb start position is (getMaximumRangeLimit() - getCurrentRangeSize()). If this method call actually changes the scrollbar's position, it will trigger an asynchronous call to ScrollBar::Listener::scrollBarMoved() for all the listeners that are registered. @see setCurrentRange */ void setCurrentRangeStart (double newStart); /** Returns the current thumb range. @see getCurrentRange, setCurrentRange */ const Range getCurrentRange() const throw() { return visibleRange; } /** Returns the position of the top of the thumb. @see getCurrentRange, setCurrentRangeStart */ double getCurrentRangeStart() const throw() { return visibleRange.getStart(); } /** Returns the current size of the thumb. @see getCurrentRange, setCurrentRange */ double getCurrentRangeSize() const throw() { return visibleRange.getLength(); } /** Sets the amount by which the up and down buttons will move the bar. The value here is in terms of the total range, and is added or subtracted from the thumb position when the user clicks an up/down (or left/right) button. */ void setSingleStepSize (double newSingleStepSize); /** Moves the scrollbar by a number of single-steps. This will move the bar by a multiple of its single-step interval (as specified using the setSingleStepSize() method). A positive value here will move the bar down or to the right, a negative value moves it up or to the left. */ void moveScrollbarInSteps (int howManySteps); /** Moves the scroll bar up or down in pages. This will move the bar by a multiple of its current thumb size, effectively doing a page-up or down. A positive value here will move the bar down or to the right, a negative value moves it up or to the left. */ void moveScrollbarInPages (int howManyPages); /** Scrolls to the top (or left). This is the same as calling setCurrentRangeStart (getMinimumRangeLimit()); */ void scrollToTop(); /** Scrolls to the bottom (or right). This is the same as calling setCurrentRangeStart (getMaximumRangeLimit() - getCurrentRangeSize()); */ void scrollToBottom(); /** Changes the delay before the up and down buttons autorepeat when they are held down. For an explanation of what the parameters are for, see Button::setRepeatSpeed(). @see Button::setRepeatSpeed */ void setButtonRepeatSpeed (int initialDelayInMillisecs, int repeatDelayInMillisecs, int minimumDelayInMillisecs = -1); /** A set of colour IDs to use to change the colour of various aspects of the component. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() methods. @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ enum ColourIds { backgroundColourId = 0x1000300, /**< The background colour of the scrollbar. */ thumbColourId = 0x1000400, /**< A base colour to use for the thumb. The look and feel will probably use variations on this colour. */ trackColourId = 0x1000401 /**< A base colour to use for the slot area of the bar. The look and feel will probably use variations on this colour. */ }; /** A class for receiving events from a ScrollBar. You can register a ScrollBar::Listener with a ScrollBar using the ScrollBar::addListener() method, and it will be called when the bar's position changes. @see ScrollBar::addListener, ScrollBar::removeListener */ class JUCE_API Listener { public: /** Destructor. */ virtual ~Listener() {} /** Called when a ScrollBar is moved. @param scrollBarThatHasMoved the bar that has moved @param newRangeStart the new range start of this bar */ virtual void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, double newRangeStart) = 0; }; /** Registers a listener that will be called when the scrollbar is moved. */ void addListener (Listener* listener); /** Deregisters a previously-registered listener. */ void removeListener (Listener* listener); /** @internal */ bool keyPressed (const KeyPress& key); /** @internal */ void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); /** @internal */ void lookAndFeelChanged(); /** @internal */ void handleAsyncUpdate(); /** @internal */ void mouseDown (const MouseEvent& e); /** @internal */ void mouseDrag (const MouseEvent& e); /** @internal */ void mouseUp (const MouseEvent& e); /** @internal */ void paint (Graphics& g); /** @internal */ void resized(); private: Range totalRange, visibleRange; double singleStepSize, dragStartRange; int thumbAreaStart, thumbAreaSize, thumbStart, thumbSize; int dragStartMousePos, lastMousePos; int initialDelayInMillisecs, repeatDelayInMillisecs, minimumDelayInMillisecs; bool vertical, isDraggingThumb, autohides; class ScrollbarButton; friend class ScopedPointer; ScopedPointer upButton, downButton; ListenerList listeners; void updateThumbPosition(); void timerCallback(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ScrollBar); }; /** This typedef is just for compatibility with old code - newer code should use the ScrollBar::Listener class directly. */ typedef ScrollBar::Listener ScrollBarListener; #endif // __JUCE_SCROLLBAR_JUCEHEADER__ /*** End of inlined file: juce_ScrollBar.h ***/ /** A Viewport is used to contain a larger child component, and allows the child to be automatically scrolled around. To use a Viewport, just create one and set the component that goes inside it using the setViewedComponent() method. When the child component changes size, the Viewport will adjust its scrollbars accordingly. A subclass of the viewport can be created which will receive calls to its visibleAreaChanged() method when the subcomponent changes position or size. */ class JUCE_API Viewport : public Component, private ComponentListener, private ScrollBar::Listener { public: /** Creates a Viewport. The viewport is initially empty - use the setViewedComponent() method to add a child component for it to manage. */ explicit Viewport (const String& componentName = String::empty); /** Destructor. */ ~Viewport(); /** Sets the component that this viewport will contain and scroll around. This will add the given component to this Viewport and position it at (0, 0). (Don't add or remove any child components directly using the normal Component::addChildComponent() methods). @param newViewedComponent the component to add to this viewport (this pointer may be null). The component passed in will be deleted by the Viewport when it's no longer needed @see getViewedComponent */ void setViewedComponent (Component* newViewedComponent); /** Returns the component that's currently being used inside the Viewport. @see setViewedComponent */ Component* getViewedComponent() const throw() { return contentComp; } /** Changes the position of the viewed component. The inner component will be moved so that the pixel at the top left of the viewport will be the pixel at position (xPixelsOffset, yPixelsOffset) within the inner component. This will update the scrollbars and might cause a call to visibleAreaChanged(). @see getViewPositionX, getViewPositionY, setViewPositionProportionately */ void setViewPosition (int xPixelsOffset, int yPixelsOffset); /** Changes the position of the viewed component. The inner component will be moved so that the pixel at the top left of the viewport will be the pixel at the specified coordinates within the inner component. This will update the scrollbars and might cause a call to visibleAreaChanged(). @see getViewPositionX, getViewPositionY, setViewPositionProportionately */ void setViewPosition (const Point& newPosition); /** Changes the view position as a proportion of the distance it can move. The values here are from 0.0 to 1.0 - where (0, 0) would put the visible area in the top-left, and (1, 1) would put it as far down and to the right as it's possible to go whilst keeping the child component on-screen. */ void setViewPositionProportionately (double proportionX, double proportionY); /** If the specified position is at the edges of the viewport, this method scrolls the viewport to bring that position nearer to the centre. Call this if you're dragging an object inside a viewport and want to make it scroll when the user approaches an edge. You might also find Component::beginDragAutoRepeat() useful when auto-scrolling. @param mouseX the x position, relative to the Viewport's top-left @param mouseY the y position, relative to the Viewport's top-left @param distanceFromEdge specifies how close to an edge the position needs to be before the viewport should scroll in that direction @param maximumSpeed the maximum number of pixels that the viewport is allowed to scroll by. @returns true if the viewport was scrolled */ bool autoScroll (int mouseX, int mouseY, int distanceFromEdge, int maximumSpeed); /** Returns the position within the child component of the top-left of its visible area. */ const Point getViewPosition() const throw() { return lastVisibleArea.getPosition(); } /** Returns the position within the child component of the top-left of its visible area. @see getViewWidth, setViewPosition */ int getViewPositionX() const throw() { return lastVisibleArea.getX(); } /** Returns the position within the child component of the top-left of its visible area. @see getViewHeight, setViewPosition */ int getViewPositionY() const throw() { return lastVisibleArea.getY(); } /** Returns the width of the visible area of the child component. This may be less than the width of this Viewport if there's a vertical scrollbar or if the child component is itself smaller. */ int getViewWidth() const throw() { return lastVisibleArea.getWidth(); } /** Returns the height of the visible area of the child component. This may be less than the height of this Viewport if there's a horizontal scrollbar or if the child component is itself smaller. */ int getViewHeight() const throw() { return lastVisibleArea.getHeight(); } /** Returns the width available within this component for the contents. This will be the width of the viewport component minus the width of a vertical scrollbar (if visible). */ int getMaximumVisibleWidth() const; /** Returns the height available within this component for the contents. This will be the height of the viewport component minus the space taken up by a horizontal scrollbar (if visible). */ int getMaximumVisibleHeight() const; /** Callback method that is called when the visible area changes. This will be called when the visible area is moved either be scrolling or by calls to setViewPosition(), etc. */ virtual void visibleAreaChanged (const Rectangle& newVisibleArea); /** Turns scrollbars on or off. If set to false, the scrollbars won't ever appear. When true (the default) they will appear only when needed. */ void setScrollBarsShown (bool showVerticalScrollbarIfNeeded, bool showHorizontalScrollbarIfNeeded); /** True if the vertical scrollbar is enabled. @see setScrollBarsShown */ bool isVerticalScrollBarShown() const throw() { return showVScrollbar; } /** True if the horizontal scrollbar is enabled. @see setScrollBarsShown */ bool isHorizontalScrollBarShown() const throw() { return showHScrollbar; } /** Changes the width of the scrollbars. If this isn't specified, the default width from the LookAndFeel class will be used. @see LookAndFeel::getDefaultScrollbarWidth */ void setScrollBarThickness (int thickness); /** Returns the thickness of the scrollbars. @see setScrollBarThickness */ int getScrollBarThickness() const; /** Changes the distance that a single-step click on a scrollbar button will move the viewport. */ void setSingleStepSizes (int stepX, int stepY); /** Shows or hides the buttons on any scrollbars that are used. @see ScrollBar::setButtonVisibility */ void setScrollBarButtonVisibility (bool buttonsVisible); /** Returns a pointer to the scrollbar component being used. Handy if you need to customise the bar somehow. */ ScrollBar* getVerticalScrollBar() throw() { return &verticalScrollBar; } /** Returns a pointer to the scrollbar component being used. Handy if you need to customise the bar somehow. */ ScrollBar* getHorizontalScrollBar() throw() { return &horizontalScrollBar; } /** @internal */ void resized(); /** @internal */ void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, double newRangeStart); /** @internal */ void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); /** @internal */ bool keyPressed (const KeyPress& key); /** @internal */ void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); /** @internal */ bool useMouseWheelMoveIfNeeded (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); private: WeakReference contentComp; Rectangle lastVisibleArea; int scrollBarThickness; int singleStepX, singleStepY; bool showHScrollbar, showVScrollbar; Component contentHolder; ScrollBar verticalScrollBar; ScrollBar horizontalScrollBar; void updateVisibleArea(); void deleteContentComp(); #if JUCE_CATCH_DEPRECATED_CODE_MISUSE // If you get an error here, it's because this method's parameters have changed! See the new definition above.. virtual int visibleAreaChanged (int, int, int, int) { return 0; } #endif JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Viewport); }; #endif // __JUCE_VIEWPORT_JUCEHEADER__ /*** End of inlined file: juce_Viewport.h ***/ /*** Start of inlined file: juce_PopupMenu.h ***/ #ifndef __JUCE_POPUPMENU_JUCEHEADER__ #define __JUCE_POPUPMENU_JUCEHEADER__ /** Creates and displays a popup-menu. To show a popup-menu, you create one of these, add some items to it, then call its show() method, which returns the id of the item the user selects. E.g. @code void MyWidget::mouseDown (const MouseEvent& e) { PopupMenu m; m.addItem (1, "item 1"); m.addItem (2, "item 2"); const int result = m.show(); if (result == 0) { // user dismissed the menu without picking anything } else if (result == 1) { // user picked item 1 } else if (result == 2) { // user picked item 2 } } @endcode Submenus are easy too: @code void MyWidget::mouseDown (const MouseEvent& e) { PopupMenu subMenu; subMenu.addItem (1, "item 1"); subMenu.addItem (2, "item 2"); PopupMenu mainMenu; mainMenu.addItem (3, "item 3"); mainMenu.addSubMenu ("other choices", subMenu); const int result = m.show(); ...etc } @endcode */ class JUCE_API PopupMenu { public: /** Creates an empty popup menu. */ PopupMenu(); /** Creates a copy of another menu. */ PopupMenu (const PopupMenu& other); /** Destructor. */ ~PopupMenu(); /** Copies this menu from another one. */ PopupMenu& operator= (const PopupMenu& other); /** Resets the menu, removing all its items. */ void clear(); /** Appends a new text item for this menu to show. @param itemResultId the number that will be returned from the show() method if the user picks this item. The value should never be zero, because that's used to indicate that the user didn't select anything. @param itemText the text to show. @param isActive if false, the item will be shown 'greyed-out' and can't be picked @param isTicked if true, the item will be shown with a tick next to it @param iconToUse if this is non-zero, it should be an image that will be displayed to the left of the item. This method will take its own copy of the image passed-in, so there's no need to keep it hanging around. @see addSeparator, addColouredItem, addCustomItem, addSubMenu */ void addItem (int itemResultId, const String& itemText, bool isActive = true, bool isTicked = false, const Image& iconToUse = Image::null); /** Adds an item that represents one of the commands in a command manager object. @param commandManager the manager to use to trigger the command and get information about it @param commandID the ID of the command @param displayName if this is non-empty, then this string will be used instead of the command's registered name */ void addCommandItem (ApplicationCommandManager* commandManager, int commandID, const String& displayName = String::empty); /** Appends a text item with a special colour. This is the same as addItem(), but specifies a colour to use for the text, which will override the default colours that are used by the current look-and-feel. See addItem() for a description of the parameters. */ void addColouredItem (int itemResultId, const String& itemText, const Colour& itemTextColour, bool isActive = true, bool isTicked = false, const Image& iconToUse = Image::null); /** Appends a custom menu item that can't be used to trigger a result. This will add a user-defined component to use as a menu item. Unlike the addCustomItem() method that takes a PopupMenu::CustomComponent, this version can't trigger a result from it, so doesn't take a menu ID. It also doesn't delete the component when it's finished, so it's the caller's responsibility to manage the component that is passed-in. if triggerMenuItemAutomaticallyWhenClicked is true, the menu itself will handle detection of a mouse-click on your component, and use that to trigger the menu ID specified in itemResultId. If this is false, the menu item can't be triggered, so itemResultId is not used. @see CustomComponent */ void addCustomItem (int itemResultId, Component* customComponent, int idealWidth, int idealHeight, bool triggerMenuItemAutomaticallyWhenClicked); /** Appends a sub-menu. If the menu that's passed in is empty, it will appear as an inactive item. */ void addSubMenu (const String& subMenuName, const PopupMenu& subMenu, bool isActive = true, const Image& iconToUse = Image::null, bool isTicked = false); /** Appends a separator to the menu, to help break it up into sections. The menu class is smart enough not to display separators at the top or bottom of the menu, and it will replace mutliple adjacent separators with a single one, so your code can be quite free and easy about adding these, and it'll always look ok. */ void addSeparator(); /** Adds a non-clickable text item to the menu. This is a bold-font items which can be used as a header to separate the items into named groups. */ void addSectionHeader (const String& title); /** Returns the number of items that the menu currently contains. (This doesn't count separators). */ int getNumItems() const throw(); /** Returns true if the menu contains a command item that triggers the given command. */ bool containsCommandItem (int commandID) const; /** Returns true if the menu contains any items that can be used. */ bool containsAnyActiveItems() const throw(); /** Displays the menu and waits for the user to pick something. This will display the menu modally, and return the ID of the item that the user picks. If they click somewhere off the menu to get rid of it without choosing anything, this will return 0. The current location of the mouse will be used as the position to show the menu - to explicitly set the menu's position, use showAt() instead. Depending on where this point is on the screen, the menu will appear above, below or to the side of the point. @param itemIdThatMustBeVisible if you set this to the ID of one of the menu items, then when the menu first appears, it will make sure that this item is visible. So if the menu has too many items to fit on the screen, it will be scrolled to a position where this item is visible. @param minimumWidth a minimum width for the menu, in pixels. It may be wider than this if some items are too long to fit. @param maximumNumColumns if there are too many items to fit on-screen in a single vertical column, the menu may be laid out as a series of columns - this is the maximum number allowed. To use the default value for this (probably about 7), you can pass in zero. @param standardItemHeight if this is non-zero, it will be used as the standard height for menu items (apart from custom items) @param callback if this is non-zero, the menu will be launched asynchronously, returning immediately, and the callback will receive a call when the menu is either dismissed or has an item selected. This object will be owned and deleted by the system, so make sure that it works safely and that any pointers that it uses are safely within scope. @see showAt */ int show (int itemIdThatMustBeVisible = 0, int minimumWidth = 0, int maximumNumColumns = 0, int standardItemHeight = 0, ModalComponentManager::Callback* callback = 0); /** Displays the menu at a specific location. This is the same as show(), but uses a specific location (in global screen co-ordinates) rather than the current mouse position. The screenAreaToAttachTo parameter indicates a screen area to which the menu will be adjacent. Depending on where this is, the menu will decide which edge to attach itself to, in order to fit itself fully on-screen. If you just want to trigger a menu at a specific point, you can pass in a rectangle of size (0, 0) with the position that you want. @see show() */ int showAt (const Rectangle& screenAreaToAttachTo, int itemIdThatMustBeVisible = 0, int minimumWidth = 0, int maximumNumColumns = 0, int standardItemHeight = 0, ModalComponentManager::Callback* callback = 0); /** Displays the menu as if it's attached to a component such as a button. This is similar to showAt(), but will position it next to the given component, e.g. so that the menu's edge is aligned with that of the component. This is intended for things like buttons that trigger a pop-up menu. */ int showAt (Component* componentToAttachTo, int itemIdThatMustBeVisible = 0, int minimumWidth = 0, int maximumNumColumns = 0, int standardItemHeight = 0, ModalComponentManager::Callback* callback = 0); /** Closes any menus that are currently open. This might be useful if you have a situation where your window is being closed by some means other than a user action, and you'd like to make sure that menus aren't left hanging around. */ static bool JUCE_CALLTYPE dismissAllActiveMenus(); /** Specifies a look-and-feel for the menu and any sub-menus that it has. This can be called before show() if you need a customised menu. Be careful not to delete the LookAndFeel object before the menu has been deleted. */ void setLookAndFeel (LookAndFeel* newLookAndFeel); /** A set of colour IDs to use to change the colour of various aspects of the menu. These constants can be used either via the LookAndFeel::setColour() method for the look and feel that is set for this menu with setLookAndFeel() @see setLookAndFeel, LookAndFeel::setColour, LookAndFeel::findColour */ enum ColourIds { backgroundColourId = 0x1000700, /**< The colour to fill the menu's background with. */ textColourId = 0x1000600, /**< The colour for normal menu item text, (unless the colour is specified when the item is added). */ headerTextColourId = 0x1000601, /**< The colour for section header item text (see the addSectionHeader() method). */ highlightedBackgroundColourId = 0x1000900, /**< The colour to fill the background of the currently highlighted menu item. */ highlightedTextColourId = 0x1000800, /**< The colour to use for the text of the currently highlighted item. */ }; /** Allows you to iterate through the items in a pop-up menu, and examine their properties. To use this, just create one and repeatedly call its next() method. When this returns true, all the member variables of the iterator are filled-out with information describing the menu item. When it returns false, the end of the list has been reached. */ class JUCE_API MenuItemIterator { public: /** Creates an iterator that will scan through the items in the specified menu. Be careful not to add any items to a menu while it is being iterated, or things could get out of step. */ MenuItemIterator (const PopupMenu& menu); /** Destructor. */ ~MenuItemIterator(); /** Returns true if there is another item, and sets up all this object's member variables to reflect that item's properties. */ bool next(); String itemName; const PopupMenu* subMenu; int itemId; bool isSeparator; bool isTicked; bool isEnabled; bool isCustomComponent; bool isSectionHeader; const Colour* customColour; Image customImage; ApplicationCommandManager* commandManager; private: const PopupMenu& menu; int index; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MenuItemIterator); }; /** A user-defined copmonent that can be used as an item in a popup menu. @see PopupMenu::addCustomItem */ class JUCE_API CustomComponent : public Component, public ReferenceCountedObject { public: /** Creates a custom item. If isTriggeredAutomatically is true, then the menu will automatically detect a mouse-click on this component and use that to invoke the menu item. If it's false, then it's up to your class to manually trigger the item when it wants to. */ CustomComponent (bool isTriggeredAutomatically = true); /** Destructor. */ ~CustomComponent(); /** Returns a rectangle with the size that this component would like to have. Note that the size which this method returns isn't necessarily the one that the menu will give it, as the items will be stretched to have a uniform width. */ virtual void getIdealSize (int& idealWidth, int& idealHeight) = 0; /** Dismisses the menu, indicating that this item has been chosen. This will cause the menu to exit from its modal state, returning this item's id as the result. */ void triggerMenuItem(); /** Returns true if this item should be highlighted because the mouse is over it. You can call this method in your paint() method to find out whether to draw a highlight. */ bool isItemHighlighted() const throw() { return isHighlighted; } /** @internal. */ bool isTriggeredAutomatically() const throw() { return triggeredAutomatically; } /** @internal. */ void setHighlighted (bool shouldBeHighlighted); private: bool isHighlighted, triggeredAutomatically; JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomComponent); }; /** Appends a custom menu item. This will add a user-defined component to use as a menu item. The component passed in will be deleted by this menu when it's no longer needed. @see CustomComponent */ void addCustomItem (int itemResultId, CustomComponent* customComponent); private: class Item; class ItemComponent; class Window; friend class MenuItemIterator; friend class ItemComponent; friend class Window; friend class CustomComponent; friend class MenuBarComponent; friend class OwnedArray ; friend class OwnedArray ; friend class ScopedPointer ; OwnedArray items; LookAndFeel* lookAndFeel; bool separatorPending; void addSeparatorIfPending(); int showMenu (const Rectangle& target, int itemIdThatMustBeVisible, int minimumWidth, int maximumNumColumns, int standardItemHeight, Component* componentAttachedTo, ModalComponentManager::Callback* callback); JUCE_LEAK_DETECTOR (PopupMenu); }; #endif // __JUCE_POPUPMENU_JUCEHEADER__ /*** End of inlined file: juce_PopupMenu.h ***/ /*** Start of inlined file: juce_TextInputTarget.h ***/ #ifndef __JUCE_TEXTINPUTTARGET_JUCEHEADER__ #define __JUCE_TEXTINPUTTARGET_JUCEHEADER__ /** An abstract base class that is implemented by components that wish to be used as text editors. This class allows different types of text editor component to provide a uniform interface, which can be used by things like OS-specific input methods, on-screen keyboards, etc. */ class JUCE_API TextInputTarget { public: /** */ TextInputTarget() {} /** Destructor. */ virtual ~TextInputTarget() {} /** Returns true if this input target is currently accepting input. For example, a text editor might return false if it's in read-only mode. */ virtual bool isTextInputActive() const = 0; /** Returns the extents of the selected text region, or an empty range if nothing is selected, */ virtual const Range getHighlightedRegion() const = 0; /** Sets the currently-selected text region. */ virtual void setHighlightedRegion (const Range& newRange) = 0; /** Returns a specified sub-section of the text. */ virtual const String getTextInRange (const Range& range) const = 0; /** Inserts some text, overwriting the selected text region, if there is one. */ virtual void insertTextAtCaret (const String& textToInsert) = 0; }; #endif // __JUCE_TEXTINPUTTARGET_JUCEHEADER__ /*** End of inlined file: juce_TextInputTarget.h ***/ /** A component containing text that can be edited. A TextEditor can either be in single- or multi-line mode, and supports mixed fonts and colours. @see TextEditor::Listener, Label */ class JUCE_API TextEditor : public Component, public TextInputTarget, public SettableTooltipClient { public: /** Creates a new, empty text editor. @param componentName the name to pass to the component for it to use as its name @param passwordCharacter if this is not zero, this character will be used as a replacement for all characters that are drawn on screen - e.g. to create a password-style textbox containing circular blobs instead of text, you could set this value to 0x25cf, which is the unicode character for a black splodge (not all fonts include this, though), or 0x2022, which is a bullet (probably the best choice for linux). */ explicit TextEditor (const String& componentName = String::empty, juce_wchar passwordCharacter = 0); /** Destructor. */ virtual ~TextEditor(); /** Puts the editor into either multi- or single-line mode. By default, the editor will be in single-line mode, so use this if you need a multi-line editor. See also the setReturnKeyStartsNewLine() method, which will also need to be turned on if you want a multi-line editor with line-breaks. @see isMultiLine, setReturnKeyStartsNewLine */ void setMultiLine (bool shouldBeMultiLine, bool shouldWordWrap = true); /** Returns true if the editor is in multi-line mode. */ bool isMultiLine() const; /** Changes the behaviour of the return key. If set to true, the return key will insert a new-line into the text; if false it will trigger a call to the TextEditor::Listener::textEditorReturnKeyPressed() method. By default this is set to false, and when true it will only insert new-lines when in multi-line mode (see setMultiLine()). */ void setReturnKeyStartsNewLine (bool shouldStartNewLine); /** Returns the value set by setReturnKeyStartsNewLine(). See setReturnKeyStartsNewLine() for more info. */ bool getReturnKeyStartsNewLine() const { return returnKeyStartsNewLine; } /** Indicates whether the tab key should be accepted and used to input a tab character, or whether it gets ignored. By default the tab key is ignored, so that it can be used to switch keyboard focus between components. */ void setTabKeyUsedAsCharacter (bool shouldTabKeyBeUsed); /** Returns true if the tab key is being used for input. @see setTabKeyUsedAsCharacter */ bool isTabKeyUsedAsCharacter() const { return tabKeyUsed; } /** Changes the editor to read-only mode. By default, the text editor is not read-only. If you're making it read-only, you might also want to call setCaretVisible (false) to get rid of the caret. The text can still be highlighted and copied when in read-only mode. @see isReadOnly, setCaretVisible */ void setReadOnly (bool shouldBeReadOnly); /** Returns true if the editor is in read-only mode. */ bool isReadOnly() const; /** Makes the caret visible or invisible. By default the caret is visible. @see setCaretColour, setCaretPosition */ void setCaretVisible (bool shouldBeVisible); /** Returns true if the caret is enabled. @see setCaretVisible */ bool isCaretVisible() const { return caretVisible; } /** Enables/disables a vertical scrollbar. (This only applies when in multi-line mode). When the text gets too long to fit in the component, a scrollbar can appear to allow it to be scrolled. Even when this is enabled, the scrollbar will be hidden unless it's needed. By default the scrollbar is enabled. */ void setScrollbarsShown (bool shouldBeEnabled); /** Returns true if scrollbars are enabled. @see setScrollbarsShown */ bool areScrollbarsShown() const { return scrollbarVisible; } /** Changes the password character used to disguise the text. @param passwordCharacter if this is not zero, this character will be used as a replacement for all characters that are drawn on screen - e.g. to create a password-style textbox containing circular blobs instead of text, you could set this value to 0x25cf, which is the unicode character for a black splodge (not all fonts include this, though), or 0x2022, which is a bullet (probably the best choice for linux). */ void setPasswordCharacter (juce_wchar passwordCharacter); /** Returns the current password character. @see setPasswordCharacter */ juce_wchar getPasswordCharacter() const { return passwordCharacter; } /** Allows a right-click menu to appear for the editor. (This defaults to being enabled). If enabled, right-clicking (or command-clicking on the Mac) will pop up a menu of options such as cut/copy/paste, undo/redo, etc. */ void setPopupMenuEnabled (bool menuEnabled); /** Returns true if the right-click menu is enabled. @see setPopupMenuEnabled */ bool isPopupMenuEnabled() const { return popupMenuEnabled; } /** Returns true if a popup-menu is currently being displayed. */ bool isPopupMenuCurrentlyActive() const { return menuActive; } /** A set of colour IDs to use to change the colour of various aspects of the editor. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() methods. @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ enum ColourIds { backgroundColourId = 0x1000200, /**< The colour to use for the text component's background - this can be transparent if necessary. */ textColourId = 0x1000201, /**< The colour that will be used when text is added to the editor. Note that because the editor can contain multiple colours, calling this method won't change the colour of existing text - to do that, call applyFontToAllText() after calling this method.*/ highlightColourId = 0x1000202, /**< The colour with which to fill the background of highlighted sections of the text - this can be transparent if you don't want to show any highlighting.*/ highlightedTextColourId = 0x1000203, /**< The colour with which to draw the text in highlighted sections. */ caretColourId = 0x1000204, /**< The colour with which to draw the caret. */ outlineColourId = 0x1000205, /**< If this is non-transparent, it will be used to draw a box around the edge of the component. */ focusedOutlineColourId = 0x1000206, /**< If this is non-transparent, it will be used to draw a box around the edge of the component when it has focus. */ shadowColourId = 0x1000207, /**< If this is non-transparent, it'll be used to draw an inner shadow around the edge of the editor. */ }; /** Sets the font to use for newly added text. This will change the font that will be used next time any text is added or entered into the editor. It won't change the font of any existing text - to do that, use applyFontToAllText() instead. @see applyFontToAllText */ void setFont (const Font& newFont); /** Applies a font to all the text in the editor. This will also set the current font to use for any new text that's added. @see setFont */ void applyFontToAllText (const Font& newFont); /** Returns the font that's currently being used for new text. @see setFont */ const Font getFont() const; /** If set to true, focusing on the editor will highlight all its text. (Set to false by default). This is useful for boxes where you expect the user to re-enter all the text when they focus on the component, rather than editing what's already there. */ void setSelectAllWhenFocused (bool b); /** Sets limits on the characters that can be entered. @param maxTextLength if this is > 0, it sets a maximum length limit; if 0, no limit is set @param allowedCharacters if this is non-empty, then only characters that occur in this string are allowed to be entered into the editor. */ void setInputRestrictions (int maxTextLength, const String& allowedCharacters = String::empty); /** When the text editor is empty, it can be set to display a message. This is handy for things like telling the user what to type in the box - the string is only displayed, it's not taken to actually be the contents of the editor. */ void setTextToShowWhenEmpty (const String& text, const Colour& colourToUse); /** Changes the size of the scrollbars that are used. Handy if you need smaller scrollbars for a small text box. */ void setScrollBarThickness (int newThicknessPixels); /** Shows or hides the buttons on any scrollbars that are used. @see ScrollBar::setButtonVisibility */ void setScrollBarButtonVisibility (bool buttonsVisible); /** Receives callbacks from a TextEditor component when it changes. @see TextEditor::addListener */ class JUCE_API Listener { public: /** Destructor. */ virtual ~Listener() {} /** Called when the user changes the text in some way. */ virtual void textEditorTextChanged (TextEditor& editor) = 0; /** Called when the user presses the return key. */ virtual void textEditorReturnKeyPressed (TextEditor& editor) = 0; /** Called when the user presses the escape key. */ virtual void textEditorEscapeKeyPressed (TextEditor& editor) = 0; /** Called when the text editor loses focus. */ virtual void textEditorFocusLost (TextEditor& editor) = 0; }; /** Registers a listener to be told when things happen to the text. @see removeListener */ void addListener (Listener* newListener); /** Deregisters a listener. @see addListener */ void removeListener (Listener* listenerToRemove); /** Returns the entire contents of the editor. */ const String getText() const; /** Returns a section of the contents of the editor. */ const String getTextInRange (const Range& textRange) const; /** Returns true if there are no characters in the editor. This is more efficient than calling getText().isEmpty(). */ bool isEmpty() const; /** Sets the entire content of the editor. This will clear the editor and insert the given text (using the current text colour and font). You can set the current text colour using @code setColour (TextEditor::textColourId, ...); @endcode @param newText the text to add @param sendTextChangeMessage if true, this will cause a change message to be sent to all the listeners. @see insertText */ void setText (const String& newText, bool sendTextChangeMessage = true); /** Returns a Value object that can be used to get or set the text. Bear in mind that this operate quite slowly if your text box contains large amounts of text, as it needs to dynamically build the string that's involved. It's best used for small text boxes. */ Value& getTextValue(); /** Inserts some text at the current cursor position. If a section of the text is highlighted, it will be replaced by this string, otherwise it will be inserted. To delete a section of text, you can use setHighlightedRegion() to highlight it, and call insertTextAtCursor (String::empty). @see setCaretPosition, getCaretPosition, setHighlightedRegion */ void insertTextAtCaret (const String& textToInsert); /** Deletes all the text from the editor. */ void clear(); /** Deletes the currently selected region, and puts it on the clipboard. @see copy, paste, SystemClipboard */ void cut(); /** Copies any currently selected region to the clipboard. @see cut, paste, SystemClipboard */ void copy(); /** Pastes the contents of the clipboard into the editor at the cursor position. @see cut, copy, SystemClipboard */ void paste(); /** Moves the caret to be in front of a given character. @see getCaretPosition */ void setCaretPosition (int newIndex); /** Returns the current index of the caret. @see setCaretPosition */ int getCaretPosition() const; /** Attempts to scroll the text editor so that the caret ends up at a specified position. This won't affect the caret's position within the text, it tries to scroll the entire editor vertically and horizontally so that the caret is sitting at the given position (relative to the top-left of this component). Depending on the amount of text available, it might not be possible to scroll far enough for the caret to reach this exact position, but it will go as far as it can in that direction. */ void scrollEditorToPositionCaret (int desiredCaretX, int desiredCaretY); /** Get the graphical position of the caret. The rectangle returned is relative to the component's top-left corner. @see scrollEditorToPositionCaret */ const Rectangle getCaretRectangle(); /** Selects a section of the text. */ void setHighlightedRegion (const Range& newSelection); /** Returns the range of characters that are selected. If nothing is selected, this will return an empty range. @see setHighlightedRegion */ const Range getHighlightedRegion() const { return selection; } /** Returns the section of text that is currently selected. */ const String getHighlightedText() const; /** Finds the index of the character at a given position. The co-ordinates are relative to the component's top-left. */ int getTextIndexAt (int x, int y); /** Counts the number of characters in the text. This is quicker than getting the text as a string if you just need to know the length. */ int getTotalNumChars() const; /** Returns the total width of the text, as it is currently laid-out. This may be larger than the size of the TextEditor, and can change when the TextEditor is resized or the text changes. */ int getTextWidth() const; /** Returns the maximum height of the text, as it is currently laid-out. This may be larger than the size of the TextEditor, and can change when the TextEditor is resized or the text changes. */ int getTextHeight() const; /** Changes the size of the gap at the top and left-edge of the editor. By default there's a gap of 4 pixels. */ void setIndents (int newLeftIndent, int newTopIndent); /** Changes the size of border left around the edge of the component. @see getBorder */ void setBorder (const BorderSize& border); /** Returns the size of border around the edge of the component. @see setBorder */ const BorderSize getBorder() const; /** Used to disable the auto-scrolling which keeps the cursor visible. If true (the default), the editor will scroll when the cursor moves offscreen. If set to false, it won't. */ void setScrollToShowCursor (bool shouldScrollToShowCursor); /** @internal */ void paint (Graphics& g); /** @internal */ void paintOverChildren (Graphics& g); /** @internal */ void mouseDown (const MouseEvent& e); /** @internal */ void mouseUp (const MouseEvent& e); /** @internal */ void mouseDrag (const MouseEvent& e); /** @internal */ void mouseDoubleClick (const MouseEvent& e); /** @internal */ void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY); /** @internal */ bool keyPressed (const KeyPress& key); /** @internal */ bool keyStateChanged (bool isKeyDown); /** @internal */ void focusGained (FocusChangeType cause); /** @internal */ void focusLost (FocusChangeType cause); /** @internal */ void resized(); /** @internal */ void enablementChanged(); /** @internal */ void colourChanged(); /** @internal */ bool isTextInputActive() const; /** This adds the items to the popup menu. By default it adds the cut/copy/paste items, but you can override this if you need to replace these with your own items. If you want to add your own items to the existing ones, you can override this, call the base class's addPopupMenuItems() method, then append your own items. When the menu has been shown, performPopupMenuAction() will be called to perform the item that the user has chosen. The default menu items will be added using item IDs in the range 0x7fff0000 - 0x7fff1000, so you should avoid those values for your own menu IDs. If this was triggered by a mouse-click, the mouseClickEvent parameter will be a pointer to the info about it, or may be null if the menu is being triggered by some other means. @see performPopupMenuAction, setPopupMenuEnabled, isPopupMenuEnabled */ virtual void addPopupMenuItems (PopupMenu& menuToAddTo, const MouseEvent* mouseClickEvent); /** This is called to perform one of the items that was shown on the popup menu. If you've overridden addPopupMenuItems(), you should also override this to perform the actions that you've added. If you've overridden addPopupMenuItems() but have still left the default items on the menu, remember to call the superclass's performPopupMenuAction() so that it can perform the default actions if that's what the user clicked on. @see addPopupMenuItems, setPopupMenuEnabled, isPopupMenuEnabled */ virtual void performPopupMenuAction (int menuItemID); protected: /** Scrolls the minimum distance needed to get the caret into view. */ void scrollToMakeSureCursorIsVisible(); /** @internal */ void moveCaret (int newCaretPos); /** @internal */ void moveCursorTo (int newPosition, bool isSelecting); /** Used internally to dispatch a text-change message. */ void textChanged(); /** Begins a new transaction in the UndoManager. */ void newTransaction(); /** Used internally to trigger an undo or redo. */ void doUndoRedo (bool isRedo); /** Can be overridden to intercept return key presses directly */ virtual void returnPressed(); /** Can be overridden to intercept escape key presses directly */ virtual void escapePressed(); /** @internal */ void handleCommandMessage (int commandId); private: class Iterator; class UniformTextSection; class TextHolderComponent; class InsertAction; class RemoveAction; friend class InsertAction; friend class RemoveAction; ScopedPointer viewport; TextHolderComponent* textHolder; BorderSize borderSize; bool readOnly : 1; bool multiline : 1; bool wordWrap : 1; bool returnKeyStartsNewLine : 1; bool caretVisible : 1; bool popupMenuEnabled : 1; bool selectAllTextWhenFocused : 1; bool scrollbarVisible : 1; bool wasFocused : 1; bool caretFlashState : 1; bool keepCursorOnScreen : 1; bool tabKeyUsed : 1; bool menuActive : 1; bool valueTextNeedsUpdating : 1; UndoManager undoManager; float cursorX, cursorY, cursorHeight; int maxTextLength; Range selection; int leftIndent, topIndent; unsigned int lastTransactionTime; Font currentFont; mutable int totalNumChars; int caretPosition; Array sections; String textToShowWhenEmpty; Colour colourForTextWhenEmpty; juce_wchar passwordCharacter; Value textValue; enum { notDragging, draggingSelectionStart, draggingSelectionEnd } dragType; String allowedCharacters; ListenerList listeners; void coalesceSimilarSections(); void splitSection (int sectionIndex, int charToSplitAt); void clearInternal (UndoManager* um); void insert (const String& text, int insertIndex, const Font& font, const Colour& colour, UndoManager* um, int caretPositionToMoveTo); void reinsert (int insertIndex, const Array & sections); void remove (const Range& range, UndoManager* um, int caretPositionToMoveTo); void getCharPosition (int index, float& x, float& y, float& lineHeight) const; void updateCaretPosition(); void textWasChangedByValue(); int indexAtPosition (float x, float y); int findWordBreakAfter (int position) const; int findWordBreakBefore (int position) const; friend class TextHolderComponent; friend class TextEditorViewport; void drawContent (Graphics& g); void updateTextHolderSize(); float getWordWrapWidth() const; void timerCallbackInt(); void repaintCaret(); void repaintText (const Range& range); UndoManager* getUndoManager() throw(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextEditor); }; /** This typedef is just for compatibility with old code - newer code should use the TextEditor::Listener class directly. */ typedef TextEditor::Listener TextEditorListener; #endif // __JUCE_TEXTEDITOR_JUCEHEADER__ /*** End of inlined file: juce_TextEditor.h ***/ #if JUCE_VC6 #define Listener ButtonListener #endif /** A component that displays a text string, and can optionally become a text editor when clicked. */ class JUCE_API Label : public Component, public SettableTooltipClient, protected TextEditorListener, private ComponentListener, private ValueListener { public: /** Creates a Label. @param componentName the name to give the component @param labelText the text to show in the label */ Label (const String& componentName = String::empty, const String& labelText = String::empty); /** Destructor. */ ~Label(); /** Changes the label text. If broadcastChangeMessage is true and the new text is different to the current text, then the class will broadcast a change message to any Label::Listener objects that are registered. */ void setText (const String& newText, bool broadcastChangeMessage); /** Returns the label's current text. @param returnActiveEditorContents if this is true and the label is currently being edited, then this method will return the text as it's being shown in the editor. If false, then the value returned here won't be updated until the user has finished typing and pressed the return key. */ const String getText (bool returnActiveEditorContents = false) const; /** Returns the text content as a Value object. You can call Value::referTo() on this object to make the label read and control a Value object that you supply. */ Value& getTextValue() { return textValue; } /** Changes the font to use to draw the text. @see getFont */ void setFont (const Font& newFont); /** Returns the font currently being used. @see setFont */ const Font& getFont() const throw(); /** A set of colour IDs to use to change the colour of various aspects of the label. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() methods. Note that you can also use the constants from TextEditor::ColourIds to change the colour of the text editor that is opened when a label is editable. @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ enum ColourIds { backgroundColourId = 0x1000280, /**< The background colour to fill the label with. */ textColourId = 0x1000281, /**< The colour for the text. */ outlineColourId = 0x1000282 /**< An optional colour to use to draw a border around the label. Leave this transparent to not have an outline. */ }; /** Sets the style of justification to be used for positioning the text. (The default is Justification::centredLeft) */ void setJustificationType (const Justification& justification); /** Returns the type of justification, as set in setJustificationType(). */ const Justification getJustificationType() const throw() { return justification; } /** Changes the gap that is left between the edge of the component and the text. By default there's a small gap left at the sides of the component to allow for the drawing of the border, but you can change this if necessary. */ void setBorderSize (int horizontalBorder, int verticalBorder); /** Returns the size of the horizontal gap being left around the text. */ int getHorizontalBorderSize() const throw() { return horizontalBorderSize; } /** Returns the size of the vertical gap being left around the text. */ int getVerticalBorderSize() const throw() { return verticalBorderSize; } /** Makes this label "stick to" another component. This will cause the label to follow another component around, staying either to its left or above it. @param owner the component to follow @param onLeft if true, the label will stay on the left of its component; if false, it will stay above it. */ void attachToComponent (Component* owner, bool onLeft); /** If this label has been attached to another component using attachToComponent, this returns the other component. Returns 0 if the label is not attached. */ Component* getAttachedComponent() const; /** If the label is attached to the left of another component, this returns true. Returns false if the label is above the other component. This is only relevent if attachToComponent() has been called. */ bool isAttachedOnLeft() const throw() { return leftOfOwnerComp; } /** Specifies the minimum amount that the font can be squashed horizantally before it starts using ellipsis. @see Graphics::drawFittedText */ void setMinimumHorizontalScale (float newScale); float getMinimumHorizontalScale() const throw() { return minimumHorizontalScale; } /** A class for receiving events from a Label. You can register a Label::Listener with a Label using the Label::addListener() method, and it will be called when the text of the label changes, either because of a call to Label::setText() or by the user editing the text (if the label is editable). @see Label::addListener, Label::removeListener */ class JUCE_API Listener { public: /** Destructor. */ virtual ~Listener() {} /** Called when a Label's text has changed. */ virtual void labelTextChanged (Label* labelThatHasChanged) = 0; }; /** Registers a listener that will be called when the label's text changes. */ void addListener (Listener* listener); /** Deregisters a previously-registered listener. */ void removeListener (Listener* listener); /** Makes the label turn into a TextEditor when clicked. By default this is turned off. If turned on, then single- or double-clicking will turn the label into an editor. If the user then changes the text, then the ChangeBroadcaster base class will be used to send change messages to any listeners that have registered. If the user changes the text, the textWasEdited() method will be called afterwards, and subclasses can override this if they need to do anything special. @param editOnSingleClick if true, just clicking once on the label will start editing the text @param editOnDoubleClick if true, a double-click is needed to start editing @param lossOfFocusDiscardsChanges if true, clicking somewhere else while the text is being edited will discard any changes; if false, then this will commit the changes. @see showEditor, setEditorColours, TextEditor */ void setEditable (bool editOnSingleClick, bool editOnDoubleClick = false, bool lossOfFocusDiscardsChanges = false); /** Returns true if this option was set using setEditable(). */ bool isEditableOnSingleClick() const throw() { return editSingleClick; } /** Returns true if this option was set using setEditable(). */ bool isEditableOnDoubleClick() const throw() { return editDoubleClick; } /** Returns true if this option has been set in a call to setEditable(). */ bool doesLossOfFocusDiscardChanges() const throw() { return lossOfFocusDiscardsChanges; } /** Returns true if the user can edit this label's text. */ bool isEditable() const throw() { return editSingleClick || editDoubleClick; } /** Makes the editor appear as if the label had been clicked by the user. @see textWasEdited, setEditable */ void showEditor(); /** Hides the editor if it was being shown. @param discardCurrentEditorContents if true, the label's text will be reset to whatever it was before the editor was shown; if false, the current contents of the editor will be used to set the label's text before it is hidden. */ void hideEditor (bool discardCurrentEditorContents); /** Returns true if the editor is currently focused and active. */ bool isBeingEdited() const throw(); protected: /** Creates the TextEditor component that will be used when the user has clicked on the label. Subclasses can override this if they need to customise this component in some way. */ virtual TextEditor* createEditorComponent(); /** Called after the user changes the text. */ virtual void textWasEdited(); /** Called when the text has been altered. */ virtual void textWasChanged(); /** Called when the text editor has just appeared, due to a user click or other focus change. */ virtual void editorShown (TextEditor* editorComponent); /** Called when the text editor is going to be deleted, after editing has finished. */ virtual void editorAboutToBeHidden (TextEditor* editorComponent); /** @internal */ void paint (Graphics& g); /** @internal */ void resized(); /** @internal */ void mouseUp (const MouseEvent& e); /** @internal */ void mouseDoubleClick (const MouseEvent& e); /** @internal */ void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized); /** @internal */ void componentParentHierarchyChanged (Component& component); /** @internal */ void componentVisibilityChanged (Component& component); /** @internal */ void inputAttemptWhenModal(); /** @internal */ void focusGained (FocusChangeType); /** @internal */ void enablementChanged(); /** @internal */ KeyboardFocusTraverser* createFocusTraverser(); /** @internal */ void textEditorTextChanged (TextEditor& editor); /** @internal */ void textEditorReturnKeyPressed (TextEditor& editor); /** @internal */ void textEditorEscapeKeyPressed (TextEditor& editor); /** @internal */ void textEditorFocusLost (TextEditor& editor); /** @internal */ void colourChanged(); /** @internal */ void valueChanged (Value&); private: Value textValue; String lastTextValue; Font font; Justification justification; ScopedPointer editor; ListenerList listeners; WeakReference ownerComponent; int horizontalBorderSize, verticalBorderSize; float minimumHorizontalScale; bool editSingleClick : 1; bool editDoubleClick : 1; bool lossOfFocusDiscardsChanges : 1; bool leftOfOwnerComp : 1; bool updateFromTextEditorContents(); void callChangeListeners(); JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Label); }; /** This typedef is just for compatibility with old code - newer code should use the Label::Listener class directly. */ typedef Label::Listener LabelListener; #if JUCE_VC6 #undef Listener #endif #endif // __JUCE_LABEL_JUCEHEADER__ /*** End of inlined file: juce_Label.h ***/ #if JUCE_VC6 #define Listener SliderListener #endif /** A component that lets the user choose from a drop-down list of choices. The combo-box has a list of text strings, each with an associated id number, that will be shown in the drop-down list when the user clicks on the component. The currently selected choice is displayed in the combo-box, and this can either be read-only text, or editable. To find out when the user selects a different item or edits the text, you can register a ComboBox::Listener to receive callbacks. @see ComboBox::Listener */ class JUCE_API ComboBox : public Component, public SettableTooltipClient, public LabelListener, // (can't use Label::Listener due to idiotic VC2005 bug) public ValueListener, private AsyncUpdater { public: /** Creates a combo-box. On construction, the text field will be empty, so you should call the setSelectedId() or setText() method to choose the initial value before displaying it. @param componentName the name to set for the component (see Component::setName()) */ explicit ComboBox (const String& componentName = String::empty); /** Destructor. */ ~ComboBox(); /** Sets whether the test in the combo-box is editable. The default state for a new ComboBox is non-editable, and can only be changed by choosing from the drop-down list. */ void setEditableText (bool isEditable); /** Returns true if the text is directly editable. @see setEditableText */ bool isTextEditable() const throw(); /** Sets the style of justification to be used for positioning the text. The default is Justification::centredLeft. The text is displayed using a Label component inside the ComboBox. */ void setJustificationType (const Justification& justification); /** Returns the current justification for the text box. @see setJustificationType */ const Justification getJustificationType() const throw(); /** Adds an item to be shown in the drop-down list. @param newItemText the text of the item to show in the list @param newItemId an associated ID number that can be set or retrieved - see getSelectedId() and setSelectedId(). Note that this value can not be 0! @see setItemEnabled, addSeparator, addSectionHeading, removeItem, getNumItems, getItemText, getItemId */ void addItem (const String& newItemText, int newItemId); /** Adds a separator line to the drop-down list. This is like adding a separator to a popup menu. See PopupMenu::addSeparator(). */ void addSeparator(); /** Adds a heading to the drop-down list, so that you can group the items into different sections. The headings are indented slightly differently to set them apart from the items on the list, and obviously can't be selected. You might want to add separators between your sections too. @see addItem, addSeparator */ void addSectionHeading (const String& headingName); /** This allows items in the drop-down list to be selectively disabled. When you add an item, it's enabled by default, but you can call this method to change its status. If you disable an item which is already selected, this won't change the current selection - it just stops the user choosing that item from the list. */ void setItemEnabled (int itemId, bool shouldBeEnabled); /** Changes the text for an existing item. */ void changeItemText (int itemId, const String& newText); /** Removes all the items from the drop-down list. If this call causes the content to be cleared, then a change-message will be broadcast unless dontSendChangeMessage is true. @see addItem, removeItem, getNumItems */ void clear (bool dontSendChangeMessage = false); /** Returns the number of items that have been added to the list. Note that this doesn't include headers or separators. */ int getNumItems() const throw(); /** Returns the text for one of the items in the list. Note that this doesn't include headers or separators. @param index the item's index from 0 to (getNumItems() - 1) */ const String getItemText (int index) const; /** Returns the ID for one of the items in the list. Note that this doesn't include headers or separators. @param index the item's index from 0 to (getNumItems() - 1) */ int getItemId (int index) const throw(); /** Returns the index in the list of a particular item ID. If no such ID is found, this will return -1. */ int indexOfItemId (int itemId) const throw(); /** Returns the ID of the item that's currently shown in the box. If no item is selected, or if the text is editable and the user has entered something which isn't one of the items in the list, then this will return 0. @see setSelectedId, getSelectedItemIndex, getText */ int getSelectedId() const throw(); /** Returns a Value object that can be used to get or set the selected item's ID. You can call Value::referTo() on this object to make the combo box control another Value object. */ Value& getSelectedIdAsValue() { return currentId; } /** Sets one of the items to be the current selection. This will set the ComboBox's text to that of the item that matches this ID. @param newItemId the new item to select @param dontSendChangeMessage if set to true, this method won't trigger a change notification @see getSelectedId, setSelectedItemIndex, setText */ void setSelectedId (int newItemId, bool dontSendChangeMessage = false); /** Returns the index of the item that's currently shown in the box. If no item is selected, or if the text is editable and the user has entered something which isn't one of the items in the list, then this will return -1. @see setSelectedItemIndex, getSelectedId, getText */ int getSelectedItemIndex() const; /** Sets one of the items to be the current selection. This will set the ComboBox's text to that of the item at the given index in the list. @param newItemIndex the new item to select @param dontSendChangeMessage if set to true, this method won't trigger a change notification @see getSelectedItemIndex, setSelectedId, setText */ void setSelectedItemIndex (int newItemIndex, bool dontSendChangeMessage = false); /** Returns the text that is currently shown in the combo-box's text field. If the ComboBox has editable text, then this text may have been edited by the user; otherwise it will be one of the items from the list, or possibly an empty string if nothing was selected. @see setText, getSelectedId, getSelectedItemIndex */ const String getText() const; /** Sets the contents of the combo-box's text field. The text passed-in will be set as the current text regardless of whether it is one of the items in the list. If the current text isn't one of the items, then getSelectedId() will return -1, otherwise it wil return the approriate ID. @param newText the text to select @param dontSendChangeMessage if set to true, this method won't trigger a change notification @see getText */ void setText (const String& newText, bool dontSendChangeMessage = false); /** Programmatically opens the text editor to allow the user to edit the current item. This is the same effect as when the box is clicked-on. @see Label::showEditor(); */ void showEditor(); /** Pops up the combo box's list. */ void showPopup(); /** A class for receiving events from a ComboBox. You can register a ComboBox::Listener with a ComboBox using the ComboBox::addListener() method, and it will be called when the selected item in the box changes. @see ComboBox::addListener, ComboBox::removeListener */ class JUCE_API Listener { public: /** Destructor. */ virtual ~Listener() {} /** Called when a ComboBox has its selected item changed. */ virtual void comboBoxChanged (ComboBox* comboBoxThatHasChanged) = 0; }; /** Registers a listener that will be called when the box's content changes. */ void addListener (Listener* listener); /** Deregisters a previously-registered listener. */ void removeListener (Listener* listener); /** Sets a message to display when there is no item currently selected. @see getTextWhenNothingSelected */ void setTextWhenNothingSelected (const String& newMessage); /** Returns the text that is shown when no item is selected. @see setTextWhenNothingSelected */ const String getTextWhenNothingSelected() const; /** Sets the message to show when there are no items in the list, and the user clicks on the drop-down box. By default it just says "no choices", but this lets you change it to something more meaningful. */ void setTextWhenNoChoicesAvailable (const String& newMessage); /** Returns the text shown when no items have been added to the list. @see setTextWhenNoChoicesAvailable */ const String getTextWhenNoChoicesAvailable() const; /** Gives the ComboBox a tooltip. */ void setTooltip (const String& newTooltip); /** A set of colour IDs to use to change the colour of various aspects of the combo box. These constants can be used either via the Component::setColour(), or LookAndFeel::setColour() methods. To change the colours of the menu that pops up @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour */ enum ColourIds { backgroundColourId = 0x1000b00, /**< The background colour to fill the box with. */ textColourId = 0x1000a00, /**< The colour for the text in the box. */ outlineColourId = 0x1000c00, /**< The colour for an outline around the box. */ buttonColourId = 0x1000d00, /**< The base colour for the button (a LookAndFeel class will probably use variations on this). */ arrowColourId = 0x1000e00, /**< The colour for the arrow shape that pops up the menu */ }; /** @internal */ void labelTextChanged (Label*); /** @internal */ void enablementChanged(); /** @internal */ void colourChanged(); /** @internal */ void focusGained (Component::FocusChangeType cause); /** @internal */ void focusLost (Component::FocusChangeType cause); /** @internal */ void handleAsyncUpdate(); /** @internal */ const String getTooltip() { return label->getTooltip(); } /** @internal */ void mouseDown (const MouseEvent&); /** @internal */ void mouseDrag (const MouseEvent&); /** @internal */ void mouseUp (const MouseEvent&); /** @internal */ void lookAndFeelChanged(); /** @internal */ void paint (Graphics&); /** @internal */ void resized(); /** @internal */ bool keyStateChanged (bool isKeyDown); /** @internal */ bool keyPressed (const KeyPress&); /** @internal */ void valueChanged (Value&); private: struct ItemInfo { ItemInfo (const String& name, int itemId, bool isEnabled, bool isHeading); bool isSeparator() const throw(); bool isRealItem() const throw(); String name; int itemId; bool isEnabled : 1, isHeading : 1; }; class Callback; friend class Callback; OwnedArray items; Value currentId; int lastCurrentId; bool isButtonDown, separatorPending, menuActive, textIsCustom; ListenerList listeners; ScopedPointer