mirror of
https://github.com/juce-framework/JUCE.git
synced 2026-01-10 23:44:24 +00:00
70038 lines
2.2 MiB
70038 lines
2.2 MiB
/*
|
|
==============================================================================
|
|
|
|
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 54
|
|
#define JUCE_BUILDNUMBER 22
|
|
|
|
/** 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 JUCE_LINUX, JUCE_IOS, JUCE_ANDROID, etc.
|
|
- 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
|
|
*/
|
|
|
|
/* This line is here as a sanity-check to catch syntax errors caused by mistakes in 3rd-party
|
|
header files that have been included before this one. If you hit an error at this line, there
|
|
must be some kind of syntax problem in whatever code immediately precedes this header.
|
|
|
|
It also causes an error if you attempt to build using a C or obj-C compiler rather than a C++ one.
|
|
*/
|
|
namespace JuceDummyNamespace {}
|
|
|
|
#if (defined (_WIN32) || defined (_WIN64))
|
|
#define JUCE_WIN32 1
|
|
#define JUCE_WINDOWS 1
|
|
#elif defined (JUCE_ANDROID)
|
|
#undef JUCE_ANDROID
|
|
#define JUCE_ANDROID 1
|
|
#elif defined (LINUX) || defined (__linux__)
|
|
#define JUCE_LINUX 1
|
|
#elif defined (__APPLE_CPP__) || defined(__APPLE_CC__)
|
|
#define Point CarbonDummyPointName // (workaround to avoid definition of "Point" by old Carbon headers)
|
|
#include <CoreFoundation/CoreFoundation.h> // (needed to find out what platform we're using)
|
|
#undef Point
|
|
|
|
#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 || JUCE_ANDROID
|
|
|
|
#ifdef _DEBUG
|
|
#define JUCE_DEBUG 1
|
|
#endif
|
|
|
|
// Allow override for big-endian Linux platforms
|
|
#if defined (__LITTLE_ENDIAN__) || ! defined (JUCE_BIG_ENDIAN)
|
|
#define JUCE_LITTLE_ENDIAN 1
|
|
#undef JUCE_BIG_ENDIAN
|
|
#else
|
|
#undef JUCE_LITTLE_ENDIAN
|
|
#define JUCE_BIG_ENDIAN 1
|
|
#endif
|
|
|
|
#if defined (__LP64__) || defined (_LP64)
|
|
#define JUCE_64BIT 1
|
|
#else
|
|
#define JUCE_32BIT 1
|
|
#endif
|
|
|
|
#if __MMX__ || __SSE__ || __amd64__
|
|
#define JUCE_INTEL 1
|
|
#endif
|
|
#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.
|
|
*/
|
|
|
|
/** 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_DIRECTSHOW: Enables DirectShow media-streaming architecture (MS Windows only).
|
|
*/
|
|
#ifndef JUCE_DIRECTSHOW
|
|
#define JUCE_DIRECTSHOW 0
|
|
#endif
|
|
|
|
/** JUCE_MEDIAFOUNDATION: Enables Media Foundation multimedia platform (Windows Vista and above).
|
|
*/
|
|
#ifndef JUCE_MEDIAFOUNDATION
|
|
#define JUCE_MEDIAFOUNDATION 0
|
|
#endif
|
|
|
|
#if ! JUCE_WINDOWS
|
|
#undef JUCE_DIRECTSHOW
|
|
#undef JUCE_MEDIAFOUNDATION
|
|
#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_ANDROID || (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.
|
|
*/
|
|
#if ! (defined (JUCE_OPENGL) || JUCE_ANDROID)
|
|
#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 ***/
|
|
|
|
#ifndef JUCE_NAMESPACE
|
|
#define JUCE_NAMESPACE juce
|
|
#endif
|
|
|
|
#define BEGIN_JUCE_NAMESPACE namespace JUCE_NAMESPACE {
|
|
#define END_JUCE_NAMESPACE }
|
|
|
|
|
|
/*** 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_MAC || DOXYGEN
|
|
/** This will try to break into the debugger if the app is currently being debugged.
|
|
If called by an app that's not being debugged, the behaiour isn't defined - it may crash or not, depending
|
|
on the platform.
|
|
@see jassert()
|
|
*/
|
|
#define juce_breakDebugger { Debugger(); }
|
|
#elif JUCE_IOS || JUCE_LINUX || JUCE_ANDROID
|
|
#define juce_breakDebugger { kill (0, SIGTRAP); }
|
|
#elif JUCE_USE_INTRINSICS
|
|
#ifndef __INTEL_COMPILER
|
|
#pragma intrinsic (__debugbreak)
|
|
#endif
|
|
#define juce_breakDebugger { __debugbreak(); }
|
|
#elif JUCE_GCC
|
|
#define juce_breakDebugger { asm("int $3"); }
|
|
#else
|
|
#define juce_breakDebugger { __asm int 3 }
|
|
#endif
|
|
|
|
#if JUCE_DEBUG || DOXYGEN
|
|
/** 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); }
|
|
|
|
/** This will always cause an assertion failure.
|
|
It is only compiled in a debug build, (unless JUCE_LOG_ASSERTIONS is enabled for your build).
|
|
@see jassert
|
|
*/
|
|
#define jassertfalse { juce_LogCurrentAssertion; if (JUCE_NAMESPACE::juce_isRunningUnderDebugger()) juce_breakDebugger; }
|
|
|
|
/** Platform-independent assertion macro.
|
|
|
|
This macro gets turned into a no-op when you're building with debugging turned off, so be
|
|
careful that the expression you pass to it doesn't perform any actions that are vital for the
|
|
correct behaviour of your program!
|
|
@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 <bool b> struct JuceStaticAssert;
|
|
template <> struct JuceStaticAssert <true> { 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. (The actual error
|
|
message that the compiler generates may be completely bizarre and seem to have no relation to
|
|
the place where you put the static_assert though!)
|
|
*/
|
|
#define static_jassert(expression) JUCE_NAMESPACE::JuceStaticAssert<expression>::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
|
|
|
|
/** A good old-fashioned 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
|
|
|
|
#if JUCE_DEBUG || DOXYGEN
|
|
/** A platform-independent way of forcing an inline function.
|
|
Use the syntax: @code
|
|
forcedinline void myfunction (int x)
|
|
@endcode
|
|
*/
|
|
#define forcedinline inline
|
|
#else
|
|
#if JUCE_MSVC
|
|
#define forcedinline __forceinline
|
|
#else
|
|
#define forcedinline inline __attribute__((always_inline))
|
|
#endif
|
|
#endif
|
|
|
|
#if JUCE_MSVC || DOXYGEN
|
|
/** This can be placed before a stack or member variable declaration to tell the compiler
|
|
to align it to the specified number of bytes. */
|
|
#define JUCE_ALIGN(bytes) __declspec (align (bytes))
|
|
#else
|
|
#define JUCE_ALIGN(bytes) __attribute__ ((aligned (bytes)))
|
|
#endif
|
|
|
|
// Cross-compiler deprecation macros..
|
|
#if DOXYGEN || (JUCE_MSVC && ! JUCE_NO_DEPRECATION_WARNINGS)
|
|
/** This can be used to wrap a function which has been deprecated. */
|
|
#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
|
|
|
|
#if JUCE_ANDROID && ! DOXYGEN
|
|
#define JUCE_MODAL_LOOPS_PERMITTED 0
|
|
#else
|
|
/** Some operating environments don't provide a modal loop mechanism, so this flag can be
|
|
used to disable any functions that try to run a modal loop. */
|
|
#define JUCE_MODAL_LOOPS_PERMITTED 1
|
|
#endif
|
|
|
|
// Here, we'll check for C++2011 compiler support, and if it's not available, define
|
|
// a few workarounds, so that we can still use a few of the newer language features.
|
|
#if defined (__GXX_EXPERIMENTAL_CXX0X__) && defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5))
|
|
#define JUCE_COMPILER_SUPPORTS_CXX2011 1
|
|
#endif
|
|
|
|
#if defined (__clang__) && defined (__has_feature)
|
|
#if __has_feature (cxx_noexcept) // (NB: do not add this test to the previous line)
|
|
#define JUCE_COMPILER_SUPPORTS_CXX2011 1
|
|
#endif
|
|
#endif
|
|
|
|
#if defined (_MSC_VER) && _MSC_VER >= 1600
|
|
//#define JUCE_COMPILER_SUPPORTS_CXX2011 1
|
|
#endif
|
|
|
|
#if ! (DOXYGEN || JUCE_COMPILER_SUPPORTS_CXX2011)
|
|
#define noexcept throw() // for c++98 compilers, we can fake these newer language features.
|
|
#define nullptr (0)
|
|
#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 <typename Type> Type abs (Type a) { if (a < 0) return -a; return a; }
|
|
template <typename Type> Type tan (Type a) { return static_cast<Type> (::tan (static_cast<double> (a))); }
|
|
template <typename Type> Type sin (Type a) { return static_cast<Type> (::sin (static_cast<double> (a))); }
|
|
template <typename Type> Type cos (Type a) { return static_cast<Type> (::cos (static_cast<double> (a))); }
|
|
template <typename Type> Type sqrt (Type a) { return static_cast<Type> (::sqrt (static_cast<double> (a))); }
|
|
template <typename Type> Type floor (Type a) { return static_cast<Type> (::floor (static_cast<double> (a))); }
|
|
template <typename Type> Type ceil (Type a) { return static_cast<Type> (::ceil (static_cast<double> (a))); }
|
|
template <typename Type> Type atan2 (Type a, Type b) { return static_cast<Type> (::atan2 (static_cast<double> (a), static_cast<double> (b))); }
|
|
}
|
|
#endif
|
|
|
|
#pragma warning (push)
|
|
#pragma warning (disable: 4514 4245 4100)
|
|
#endif
|
|
|
|
#include <cstdlib>
|
|
#include <cstdarg>
|
|
#include <climits>
|
|
#include <limits>
|
|
#include <cmath>
|
|
#include <cwchar>
|
|
#include <stdexcept>
|
|
#include <typeinfo>
|
|
#include <cstring>
|
|
#include <cstdio>
|
|
#include <iostream>
|
|
#include <vector>
|
|
|
|
#if JUCE_USE_INTRINSICS
|
|
#include <intrin.h>
|
|
#endif
|
|
|
|
#if JUCE_MAC || JUCE_IOS
|
|
#include <libkern/OSAtomic.h>
|
|
#endif
|
|
|
|
#if JUCE_LINUX
|
|
#include <signal.h>
|
|
|
|
#if __INTEL_COMPILER
|
|
#if __ia64__
|
|
#include <ia64intrin.h>
|
|
#else
|
|
#include <ia32intrin.h>
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#if JUCE_MSVC && JUCE_DEBUG
|
|
#include <crtdbg.h>
|
|
#endif
|
|
|
|
#if JUCE_MSVC
|
|
#include <malloc.h>
|
|
#pragma warning (pop)
|
|
#endif
|
|
|
|
#if JUCE_ANDROID
|
|
#include <sys/atomics.h>
|
|
#include <byteswap.h>
|
|
#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
|
|
#ifdef __INTEL_COMPILER
|
|
#pragma warning (disable: 1125) // (virtual override warning)
|
|
#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) noexcept;
|
|
#endif
|
|
|
|
|
|
/*** Start of inlined file: juce_Memory.h ***/
|
|
#ifndef __JUCE_MEMORY_JUCEHEADER__
|
|
#define __JUCE_MEMORY_JUCEHEADER__
|
|
|
|
#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) noexcept { memset (memory, 0, numBytes); }
|
|
|
|
/** Overwrites a structure or object with zeros. */
|
|
template <typename Type>
|
|
inline void zerostruct (Type& structure) noexcept { 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 <typename Type>
|
|
inline void deleteAndZero (Type& pointer) { delete pointer; pointer = nullptr; }
|
|
|
|
/** 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 <typename Type>
|
|
inline Type* addBytesToPointer (Type* pointer, int bytes) noexcept { return (Type*) (((char*) pointer) + bytes); }
|
|
|
|
/** A handy function which returns the difference between any two pointers, in bytes.
|
|
The address of the second pointer is subtracted from the first, and the difference in bytes is returned.
|
|
*/
|
|
template <typename Type1, typename Type2>
|
|
inline int getAddressDifference (Type1* pointer1, Type2* pointer2) noexcept { return (int) (((const char*) pointer1) - (const char*) pointer2); }
|
|
|
|
/* In a win32 DLL build, we'll expose some malloc/free functions that live inside the DLL, and use these for
|
|
allocating all the objects - that way all juce objects in the DLL and in the host will live in the same heap,
|
|
avoiding problems when an object is created in one module and passed across to another where it is deleted.
|
|
By piggy-backing on the JUCE_LEAK_DETECTOR macro, these allocators can be injected into most juce classes.
|
|
*/
|
|
#if JUCE_MSVC && defined (JUCE_DLL) && ! DOXYGEN
|
|
extern JUCE_API void* juceDLL_malloc (size_t);
|
|
extern JUCE_API void juceDLL_free (void*);
|
|
|
|
#define JUCE_LEAK_DETECTOR(OwnerClass) public:\
|
|
static void* operator new (size_t sz) { return JUCE_NAMESPACE::juceDLL_malloc ((int) sz); } \
|
|
static void* operator new (size_t, void* p) { return p; } \
|
|
static void operator delete (void* p) { JUCE_NAMESPACE::juceDLL_free (p); } \
|
|
static void operator delete (void*, void*) {}
|
|
#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
|
|
|
|
#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
|
|
|
|
// Some indispensible min/max functions
|
|
|
|
/** Returns the larger of two values. */
|
|
template <typename Type>
|
|
inline Type jmax (const Type a, const Type b) { return (a < b) ? b : a; }
|
|
|
|
/** Returns the larger of three values. */
|
|
template <typename Type>
|
|
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 <typename Type>
|
|
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 <typename Type>
|
|
inline Type jmin (const Type a, const Type b) { return (b < a) ? b : a; }
|
|
|
|
/** Returns the smaller of three values. */
|
|
template <typename Type>
|
|
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 <typename Type>
|
|
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 <typename Type>
|
|
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 <typename Type>
|
|
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 <typename Type>
|
|
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 <typename Type>
|
|
inline Type jlimit (const Type lowerLimit,
|
|
const Type upperLimit,
|
|
const Type valueToConstrain) noexcept
|
|
{
|
|
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 <typename Type>
|
|
inline bool isPositiveAndBelow (Type valueToTest, Type upperLimit) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
|
return static_cast <unsigned int> (valueToTest) < static_cast <unsigned int> (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 <typename Type>
|
|
inline bool isPositiveAndNotGreaterThan (Type valueToTest, Type upperLimit) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
jassert (upperLimit >= 0); // makes no sense to call this if the upper limit is itself below zero..
|
|
return static_cast <unsigned int> (valueToTest) <= static_cast <unsigned int> (upperLimit);
|
|
}
|
|
#endif
|
|
|
|
/** Handy function to swap two values. */
|
|
template <typename Type>
|
|
inline void swapVariables (Type& variable1, Type& variable2)
|
|
{
|
|
std::swap (variable1, variable2);
|
|
}
|
|
|
|
#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 <typename Type, int N>
|
|
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 <typename Type>
|
|
inline Type juce_hypot (Type a, Type b) noexcept
|
|
{
|
|
#if JUCE_WINDOWS
|
|
return static_cast <Type> (_hypot (a, b));
|
|
#else
|
|
return static_cast <Type> (hypot (a, b));
|
|
#endif
|
|
}
|
|
|
|
/** 64-bit abs function. */
|
|
inline int64 abs64 (const int64 n) noexcept
|
|
{
|
|
return (n >= 0) ? n : -n;
|
|
}
|
|
|
|
/** This templated negate function will negate pointers as well as integers */
|
|
template <typename Type>
|
|
inline Type juce_negate (Type n) noexcept
|
|
{
|
|
return sizeof (Type) == 1 ? (Type) -(signed 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 <typename Type>
|
|
inline Type* juce_negate (Type* n) noexcept
|
|
{
|
|
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 <typename FloatingPointType>
|
|
inline bool juce_isfinite (FloatingPointType value)
|
|
{
|
|
#if JUCE_WINDOWS
|
|
return _finite (value);
|
|
#elif JUCE_ANDROID
|
|
return isfinite (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 <typename FloatType>
|
|
inline int roundToInt (const FloatType value) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
return roundToInt (value);
|
|
}
|
|
|
|
#if (JUCE_INTEL && JUCE_32BIT) || defined (DOXYGEN)
|
|
/** This macro can be applied to a float variable to check whether it contains a denormalised
|
|
value, and to normalise it if necessary.
|
|
On CPUs that aren't vulnerable to denormalisation problems, this will have no effect.
|
|
*/
|
|
#define JUCE_UNDENORMALISE(x) x += 1.0f; x -= 1.0f;
|
|
#else
|
|
#define JUCE_UNDENORMALISE(x)
|
|
#endif
|
|
|
|
/** This namespace contains a few template classes for helping work out class type variations.
|
|
*/
|
|
namespace TypeHelpers
|
|
{
|
|
#if JUCE_VC8_OR_EARLIER
|
|
#define PARAMETER_TYPE(type) const type&
|
|
#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<SomeClass>::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 <typename Type> struct ParameterType { typedef const Type& type; };
|
|
|
|
#if ! DOXYGEN
|
|
template <typename Type> struct ParameterType <Type&> { typedef Type& type; };
|
|
template <typename Type> struct ParameterType <Type*> { typedef Type* type; };
|
|
template <> struct ParameterType <char> { typedef char type; };
|
|
template <> struct ParameterType <unsigned char> { typedef unsigned char type; };
|
|
template <> struct ParameterType <short> { typedef short type; };
|
|
template <> struct ParameterType <unsigned short> { typedef unsigned short type; };
|
|
template <> struct ParameterType <int> { typedef int type; };
|
|
template <> struct ParameterType <unsigned int> { typedef unsigned int type; };
|
|
template <> struct ParameterType <long> { typedef long type; };
|
|
template <> struct ParameterType <unsigned long> { typedef unsigned long type; };
|
|
template <> struct ParameterType <int64> { typedef int64 type; };
|
|
template <> struct ParameterType <uint64> { typedef uint64 type; };
|
|
template <> struct ParameterType <bool> { typedef bool type; };
|
|
template <> struct ParameterType <float> { typedef float type; };
|
|
template <> struct ParameterType <double> { typedef double type; };
|
|
#endif
|
|
|
|
/** A helpful macro to simplify the use of the ParameterType template.
|
|
@see ParameterType
|
|
*/
|
|
#define PARAMETER_TYPE(a) typename TypeHelpers::ParameterType<a>::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 && ! defined (__INTEL_COMPILER)
|
|
#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 <uint16> (_byteswap_ushort (n));
|
|
#else
|
|
return static_cast <uint16> ((n << 8) | (n >> 8));
|
|
#endif
|
|
}
|
|
|
|
inline uint32 ByteOrder::swap (uint32 n)
|
|
{
|
|
#if JUCE_MAC || JUCE_IOS
|
|
return OSSwapInt32 (n);
|
|
#elif JUCE_GCC && JUCE_INTEL
|
|
asm("bswap %%eax" : "=a"(n) : "a"(n));
|
|
return n;
|
|
#elif JUCE_USE_INTRINSICS
|
|
return _byteswap_ulong (n);
|
|
#elif JUCE_MSVC
|
|
__asm {
|
|
mov eax, n
|
|
bswap eax
|
|
mov n, eax
|
|
}
|
|
return n;
|
|
#elif JUCE_ANDROID
|
|
return bswap_32 (n);
|
|
#else
|
|
return (n << 24) | (n >> 24) | ((n & 0xff00) << 8) | ((n & 0xff0000) >> 8);
|
|
#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 <const uint32*> (bytes); }
|
|
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) { return *static_cast <const uint16*> (bytes); }
|
|
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) { return swap (*static_cast <const uint32*> (bytes)); }
|
|
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) { return swap (*static_cast <const uint16*> (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 <const uint32*> (bytes)); }
|
|
inline uint16 ByteOrder::littleEndianShort (const void* const bytes) { return swap (*static_cast <const uint16*> (bytes)); }
|
|
inline uint32 ByteOrder::bigEndianInt (const void* const bytes) { return *static_cast <const uint32*> (bytes); }
|
|
inline uint16 ByteOrder::bigEndianShort (const void* const bytes) { return *static_cast <const uint16*> (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__
|
|
|
|
#if JUCE_WINDOWS && ! DOXYGEN
|
|
#define JUCE_NATIVE_WCHAR_IS_UTF8 0
|
|
#define JUCE_NATIVE_WCHAR_IS_UTF16 1
|
|
#define JUCE_NATIVE_WCHAR_IS_UTF32 0
|
|
#else
|
|
/** This macro will be set to 1 if the compiler's native wchar_t is an 8-bit type. */
|
|
#define JUCE_NATIVE_WCHAR_IS_UTF8 0
|
|
/** This macro will be set to 1 if the compiler's native wchar_t is a 16-bit type. */
|
|
#define JUCE_NATIVE_WCHAR_IS_UTF16 0
|
|
/** This macro will be set to 1 if the compiler's native wchar_t is a 32-bit type. */
|
|
#define JUCE_NATIVE_WCHAR_IS_UTF32 1
|
|
#endif
|
|
|
|
#if JUCE_NATIVE_WCHAR_IS_UTF32 || DOXYGEN
|
|
/** A platform-independent 32-bit unicode character type. */
|
|
typedef wchar_t juce_wchar;
|
|
#else
|
|
typedef uint32 juce_wchar;
|
|
#endif
|
|
|
|
/** This macro is deprecated, but preserved for compatibility with old code.*/
|
|
#define JUCE_T(stringLiteral) (L##stringLiteral)
|
|
|
|
#if ! JUCE_DONT_DEFINE_MACROS
|
|
/** The 'T' macro is an alternative for using the "L" prefix in front of a string literal.
|
|
|
|
This macro is deprectated, but kept here for compatibility with old code. The best (i.e.
|
|
most portable) way to encode your string literals is just as standard 8-bit strings, but
|
|
using escaped utf-8 character codes for extended characters.
|
|
|
|
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
|
|
|
|
#undef max
|
|
#undef min
|
|
|
|
/**
|
|
A set of methods for manipulating characters and character strings.
|
|
|
|
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 juce_wchar toUpperCase (juce_wchar character) noexcept;
|
|
static juce_wchar toLowerCase (juce_wchar character) noexcept;
|
|
|
|
static bool isUpperCase (juce_wchar character) noexcept;
|
|
static bool isLowerCase (juce_wchar character) noexcept;
|
|
|
|
static bool isWhitespace (char character) noexcept;
|
|
static bool isWhitespace (juce_wchar character) noexcept;
|
|
|
|
static bool isDigit (char character) noexcept;
|
|
static bool isDigit (juce_wchar character) noexcept;
|
|
|
|
static bool isLetter (char character) noexcept;
|
|
static bool isLetter (juce_wchar character) noexcept;
|
|
|
|
static bool isLetterOrDigit (char character) noexcept;
|
|
static bool isLetterOrDigit (juce_wchar character) noexcept;
|
|
|
|
/** Returns 0 to 16 for '0' to 'F", or -1 for characters that aren't a legal hex digit. */
|
|
static int getHexDigitValue (juce_wchar digit) noexcept;
|
|
|
|
template <typename CharPointerType>
|
|
static double readDoubleValue (CharPointerType& text) noexcept
|
|
{
|
|
double result[3] = { 0 }, accumulator[2] = { 0 };
|
|
int exponentAdjustment[2] = { 0 }, exponentAccumulator[2] = { -1, -1 };
|
|
int exponent = 0, decPointIndex = 0, digit = 0;
|
|
int lastDigit = 0, numSignificantDigits = 0;
|
|
bool isNegative = false, digitsFound = false;
|
|
const int maxSignificantDigits = 15 + 2;
|
|
|
|
text = text.findEndOfWhitespace();
|
|
juce_wchar c = *text;
|
|
|
|
switch (c)
|
|
{
|
|
case '-': isNegative = true; // fall-through..
|
|
case '+': c = *++text;
|
|
}
|
|
|
|
switch (c)
|
|
{
|
|
case 'n':
|
|
case 'N':
|
|
if ((text[1] == 'a' || text[1] == 'A') && (text[2] == 'n' || text[2] == 'N'))
|
|
return std::numeric_limits<double>::quiet_NaN();
|
|
break;
|
|
|
|
case 'i':
|
|
case 'I':
|
|
if ((text[1] == 'n' || text[1] == 'N') && (text[2] == 'f' || text[2] == 'F'))
|
|
return std::numeric_limits<double>::infinity();
|
|
break;
|
|
}
|
|
|
|
for (;;)
|
|
{
|
|
if (text.isDigit())
|
|
{
|
|
lastDigit = digit;
|
|
digit = text.getAndAdvance() - '0';
|
|
digitsFound = true;
|
|
|
|
if (decPointIndex != 0)
|
|
exponentAdjustment[1]++;
|
|
|
|
if (numSignificantDigits == 0 && digit == 0)
|
|
continue;
|
|
|
|
if (++numSignificantDigits > maxSignificantDigits)
|
|
{
|
|
if (digit > 5)
|
|
++accumulator [decPointIndex];
|
|
else if (digit == 5 && (lastDigit & 1) != 0)
|
|
++accumulator [decPointIndex];
|
|
|
|
if (decPointIndex > 0)
|
|
exponentAdjustment[1]--;
|
|
else
|
|
exponentAdjustment[0]++;
|
|
|
|
while (text.isDigit())
|
|
{
|
|
++text;
|
|
if (decPointIndex == 0)
|
|
exponentAdjustment[0]++;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const double maxAccumulatorValue = (double) ((std::numeric_limits<unsigned int>::max() - 9) / 10);
|
|
if (accumulator [decPointIndex] > maxAccumulatorValue)
|
|
{
|
|
result [decPointIndex] = mulexp10 (result [decPointIndex], exponentAccumulator [decPointIndex])
|
|
+ accumulator [decPointIndex];
|
|
accumulator [decPointIndex] = 0;
|
|
exponentAccumulator [decPointIndex] = 0;
|
|
}
|
|
|
|
accumulator [decPointIndex] = accumulator[decPointIndex] * 10 + digit;
|
|
exponentAccumulator [decPointIndex]++;
|
|
}
|
|
}
|
|
else if (decPointIndex == 0 && *text == '.')
|
|
{
|
|
++text;
|
|
decPointIndex = 1;
|
|
|
|
if (numSignificantDigits > maxSignificantDigits)
|
|
{
|
|
while (text.isDigit())
|
|
++text;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
result[0] = mulexp10 (result[0], exponentAccumulator[0]) + accumulator[0];
|
|
|
|
if (decPointIndex != 0)
|
|
result[1] = mulexp10 (result[1], exponentAccumulator[1]) + accumulator[1];
|
|
|
|
c = *text;
|
|
if ((c == 'e' || c == 'E') && digitsFound)
|
|
{
|
|
bool negativeExponent = false;
|
|
|
|
switch (*++text)
|
|
{
|
|
case '-': negativeExponent = true; // fall-through..
|
|
case '+': ++text;
|
|
}
|
|
|
|
while (text.isDigit())
|
|
exponent = (exponent * 10) + (text.getAndAdvance() - '0');
|
|
|
|
if (negativeExponent)
|
|
exponent = -exponent;
|
|
}
|
|
|
|
double r = mulexp10 (result[0], exponent + exponentAdjustment[0]);
|
|
if (decPointIndex != 0)
|
|
r += mulexp10 (result[1], exponent - exponentAdjustment[1]);
|
|
|
|
return isNegative ? -r : r;
|
|
}
|
|
|
|
template <typename CharPointerType>
|
|
static double getDoubleValue (const CharPointerType& text) noexcept
|
|
{
|
|
CharPointerType t (text);
|
|
return readDoubleValue (t);
|
|
}
|
|
|
|
template <typename IntType, typename CharPointerType>
|
|
static IntType getIntValue (const CharPointerType& text) noexcept
|
|
{
|
|
IntType v = 0;
|
|
CharPointerType s (text.findEndOfWhitespace());
|
|
|
|
const bool isNeg = *s == '-';
|
|
if (isNeg)
|
|
++s;
|
|
|
|
for (;;)
|
|
{
|
|
const juce_wchar c = s.getAndAdvance();
|
|
|
|
if (c >= '0' && c <= '9')
|
|
v = v * 10 + (IntType) (c - '0');
|
|
else
|
|
break;
|
|
}
|
|
|
|
return isNeg ? -v : v;
|
|
}
|
|
|
|
template <typename CharPointerType>
|
|
static size_t lengthUpTo (CharPointerType text, const size_t maxCharsToCount) noexcept
|
|
{
|
|
size_t len = 0;
|
|
|
|
while (len < maxCharsToCount && text.getAndAdvance() != 0)
|
|
++len;
|
|
|
|
return len;
|
|
}
|
|
|
|
template <typename CharPointerType>
|
|
static size_t lengthUpTo (CharPointerType start, const CharPointerType& end) noexcept
|
|
{
|
|
size_t len = 0;
|
|
|
|
while (start < end && start.getAndAdvance() != 0)
|
|
++len;
|
|
|
|
return len;
|
|
}
|
|
|
|
template <typename DestCharPointerType, typename SrcCharPointerType>
|
|
static void copyAll (DestCharPointerType& dest, SrcCharPointerType src) noexcept
|
|
{
|
|
for (;;)
|
|
{
|
|
const juce_wchar c = src.getAndAdvance();
|
|
|
|
if (c == 0)
|
|
break;
|
|
|
|
dest.write (c);
|
|
}
|
|
|
|
dest.writeNull();
|
|
}
|
|
|
|
template <typename DestCharPointerType, typename SrcCharPointerType>
|
|
static int copyWithDestByteLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxBytes) noexcept
|
|
{
|
|
typename DestCharPointerType::CharType const* const startAddress = dest.getAddress();
|
|
maxBytes -= sizeof (typename DestCharPointerType::CharType); // (allow for a terminating null)
|
|
|
|
for (;;)
|
|
{
|
|
const juce_wchar c = src.getAndAdvance();
|
|
const int bytesNeeded = (int) DestCharPointerType::getBytesRequiredFor (c);
|
|
|
|
maxBytes -= bytesNeeded;
|
|
if (c == 0 || maxBytes < 0)
|
|
break;
|
|
|
|
dest.write (c);
|
|
}
|
|
|
|
dest.writeNull();
|
|
|
|
return getAddressDifference (dest.getAddress(), startAddress);
|
|
}
|
|
|
|
template <typename DestCharPointerType, typename SrcCharPointerType>
|
|
static void copyWithCharLimit (DestCharPointerType& dest, SrcCharPointerType src, int maxChars) noexcept
|
|
{
|
|
while (--maxChars > 0)
|
|
{
|
|
const juce_wchar c = src.getAndAdvance();
|
|
if (c == 0)
|
|
break;
|
|
|
|
dest.write (c);
|
|
}
|
|
|
|
dest.writeNull();
|
|
}
|
|
|
|
template <typename CharPointerType1, typename CharPointerType2>
|
|
static int compare (CharPointerType1 s1, CharPointerType2 s2) noexcept
|
|
{
|
|
for (;;)
|
|
{
|
|
const int c1 = (int) s1.getAndAdvance();
|
|
const int c2 = (int) s2.getAndAdvance();
|
|
|
|
const int diff = c1 - c2;
|
|
if (diff != 0)
|
|
return diff < 0 ? -1 : 1;
|
|
else if (c1 == 0)
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <typename CharPointerType1, typename CharPointerType2>
|
|
static int compareUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
|
|
{
|
|
while (--maxChars >= 0)
|
|
{
|
|
const int c1 = (int) s1.getAndAdvance();
|
|
const int c2 = (int) s2.getAndAdvance();
|
|
|
|
const int diff = c1 - c2;
|
|
if (diff != 0)
|
|
return diff < 0 ? -1 : 1;
|
|
else if (c1 == 0)
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <typename CharPointerType1, typename CharPointerType2>
|
|
static int compareIgnoreCase (CharPointerType1 s1, CharPointerType2 s2) noexcept
|
|
{
|
|
for (;;)
|
|
{
|
|
int c1 = s1.toUpperCase();
|
|
int c2 = s2.toUpperCase();
|
|
++s1;
|
|
++s2;
|
|
|
|
const int diff = c1 - c2;
|
|
if (diff != 0)
|
|
return diff < 0 ? -1 : 1;
|
|
else if (c1 == 0)
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <typename CharPointerType1, typename CharPointerType2>
|
|
static int compareIgnoreCaseUpTo (CharPointerType1 s1, CharPointerType2 s2, int maxChars) noexcept
|
|
{
|
|
while (--maxChars >= 0)
|
|
{
|
|
int c1 = s1.toUpperCase();
|
|
int c2 = s2.toUpperCase();
|
|
++s1;
|
|
++s2;
|
|
|
|
const int diff = c1 - c2;
|
|
if (diff != 0)
|
|
return diff < 0 ? -1 : 1;
|
|
else if (c1 == 0)
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
template <typename CharPointerType1, typename CharPointerType2>
|
|
static int indexOf (CharPointerType1 haystack, const CharPointerType2& needle) noexcept
|
|
{
|
|
int index = 0;
|
|
const int needleLength = (int) needle.length();
|
|
|
|
for (;;)
|
|
{
|
|
if (haystack.compareUpTo (needle, needleLength) == 0)
|
|
return index;
|
|
|
|
if (haystack.getAndAdvance() == 0)
|
|
return -1;
|
|
|
|
++index;
|
|
}
|
|
}
|
|
|
|
template <typename CharPointerType1, typename CharPointerType2>
|
|
static int indexOfIgnoreCase (CharPointerType1 haystack, const CharPointerType2& needle) noexcept
|
|
{
|
|
int index = 0;
|
|
const int needleLength = (int) needle.length();
|
|
|
|
for (;;)
|
|
{
|
|
if (haystack.compareIgnoreCaseUpTo (needle, needleLength) == 0)
|
|
return index;
|
|
|
|
if (haystack.getAndAdvance() == 0)
|
|
return -1;
|
|
|
|
++index;
|
|
}
|
|
}
|
|
|
|
template <typename Type>
|
|
static int indexOfChar (Type text, const juce_wchar charToFind) noexcept
|
|
{
|
|
int i = 0;
|
|
|
|
while (! text.isEmpty())
|
|
{
|
|
if (text.getAndAdvance() == charToFind)
|
|
return i;
|
|
|
|
++i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
template <typename Type>
|
|
static int indexOfCharIgnoreCase (Type text, juce_wchar charToFind) noexcept
|
|
{
|
|
charToFind = CharacterFunctions::toLowerCase (charToFind);
|
|
int i = 0;
|
|
|
|
while (! text.isEmpty())
|
|
{
|
|
if (text.toLowerCase() == charToFind)
|
|
return i;
|
|
|
|
++text;
|
|
++i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
template <typename Type>
|
|
static Type findEndOfWhitespace (const Type& text) noexcept
|
|
{
|
|
Type p (text);
|
|
|
|
while (p.isWhitespace())
|
|
++p;
|
|
|
|
return p;
|
|
}
|
|
|
|
template <typename Type>
|
|
static Type findEndOfToken (const Type& text, const Type& breakCharacters, const Type& quoteCharacters)
|
|
{
|
|
Type t (text);
|
|
juce_wchar currentQuoteChar = 0;
|
|
|
|
while (! t.isEmpty())
|
|
{
|
|
const juce_wchar c = t.getAndAdvance();
|
|
|
|
if (currentQuoteChar == 0 && breakCharacters.indexOf (c) >= 0)
|
|
{
|
|
--t;
|
|
break;
|
|
}
|
|
|
|
if (quoteCharacters.indexOf (c) >= 0)
|
|
{
|
|
if (currentQuoteChar == 0)
|
|
currentQuoteChar = c;
|
|
else if (currentQuoteChar == c)
|
|
currentQuoteChar = 0;
|
|
}
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
private:
|
|
static double mulexp10 (const double value, int exponent) noexcept;
|
|
};
|
|
|
|
#endif // __JUCE_CHARACTERFUNCTIONS_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CharacterFunctions.h ***/
|
|
|
|
#ifndef JUCE_STRING_UTF_TYPE
|
|
#define JUCE_STRING_UTF_TYPE 8
|
|
#endif
|
|
|
|
#if JUCE_MSVC
|
|
#pragma warning (push)
|
|
#pragma warning (disable: 4514 4996)
|
|
#endif
|
|
|
|
|
|
/*** 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 <typename Type>
|
|
class Atomic
|
|
{
|
|
public:
|
|
/** Creates a new value, initialised to zero. */
|
|
inline Atomic() noexcept
|
|
: value (0)
|
|
{
|
|
}
|
|
|
|
/** Creates a new value, with a given initial value. */
|
|
inline Atomic (const Type initialValue) noexcept
|
|
: value (initialValue)
|
|
{
|
|
}
|
|
|
|
/** Copies another value (atomically). */
|
|
inline Atomic (const Atomic& other) noexcept
|
|
: value (other.get())
|
|
{
|
|
}
|
|
|
|
/** Destructor. */
|
|
inline ~Atomic() noexcept
|
|
{
|
|
// 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 noexcept;
|
|
|
|
/** Copies another value onto this one (atomically). */
|
|
inline Atomic& operator= (const Atomic& other) noexcept { exchange (other.get()); return *this; }
|
|
|
|
/** Copies another value onto this one (atomically). */
|
|
inline Atomic& operator= (const Type newValue) noexcept { exchange (newValue); return *this; }
|
|
|
|
/** Atomically sets the current value. */
|
|
void set (Type newValue) noexcept { exchange (newValue); }
|
|
|
|
/** Atomically sets the current value, returning the value that was replaced. */
|
|
Type exchange (Type value) noexcept;
|
|
|
|
/** Atomically adds a number to this value, returning the new value. */
|
|
Type operator+= (Type amountToAdd) noexcept;
|
|
|
|
/** Atomically subtracts a number from this value, returning the new value. */
|
|
Type operator-= (Type amountToSubtract) noexcept;
|
|
|
|
/** Atomically increments this value, returning the new value. */
|
|
Type operator++() noexcept;
|
|
|
|
/** Atomically decrements this value, returning the new value. */
|
|
Type operator--() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Implements a memory read/write barrier. */
|
|
static void memoryBarrier() noexcept;
|
|
|
|
#if JUCE_64BIT
|
|
JUCE_ALIGN (8)
|
|
#else
|
|
JUCE_ALIGN (4)
|
|
#endif
|
|
|
|
/** 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) noexcept { return *(Type*) &value; }
|
|
static inline Type castFrom64Bit (int64 value) noexcept { return *(Type*) &value; }
|
|
static inline int32 castTo32Bit (Type value) noexcept { return *(int32*) &value; }
|
|
static inline int64 castTo64Bit (Type value) noexcept { 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 <typename Type> static Type OSAtomicAdd64Barrier (Type b, JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return *a += b; }
|
|
template <typename Type> static Type OSAtomicIncrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return ++*a; }
|
|
template <typename Type> static Type OSAtomicDecrement64Barrier (JUCE_MAC_ATOMICS_VOLATILE Type* a) noexcept { jassertfalse; return --*a; }
|
|
template <typename Type> static bool OSAtomicCompareAndSwap64Barrier (Type old, Type newValue, JUCE_MAC_ATOMICS_VOLATILE Type* value) noexcept
|
|
{ jassertfalse; if (old == *value) { *value = newValue; return true; } return false; }
|
|
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
|
#endif
|
|
|
|
#elif JUCE_ANDROID
|
|
#define JUCE_ATOMICS_ANDROID 1 // Android atomic functions
|
|
#define JUCE_64BIT_ATOMICS_UNAVAILABLE 1
|
|
|
|
#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
|
|
#ifndef __INTEL_COMPILER
|
|
#pragma intrinsic (_InterlockedExchange, _InterlockedIncrement, _InterlockedDecrement, _InterlockedCompareExchange, \
|
|
_InterlockedCompareExchange64, _InterlockedExchangeAdd, _ReadWriteBarrier)
|
|
#endif
|
|
#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) noexcept;
|
|
long juce_InterlockedIncrement (volatile long* a) noexcept;
|
|
long juce_InterlockedDecrement (volatile long* a) noexcept;
|
|
long juce_InterlockedExchangeAdd (volatile long* a, long b) noexcept;
|
|
long juce_InterlockedCompareExchange (volatile long* a, long b, long c) noexcept;
|
|
__int64 juce_InterlockedCompareExchange64 (volatile __int64* a, __int64 b, __int64 c) noexcept;
|
|
inline void juce_MemoryBarrier() noexcept { long x = 0; juce_InterlockedIncrement (&x); }
|
|
#endif
|
|
|
|
#if JUCE_64BIT
|
|
#ifndef __INTEL_COMPILER
|
|
#pragma intrinsic (_InterlockedExchangeAdd64, _InterlockedExchange64, _InterlockedIncrement64, _InterlockedDecrement64)
|
|
#endif
|
|
#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 <typename Type> static Type juce_InterlockedExchangeAdd64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a += b; return old; }
|
|
template <typename Type> static Type juce_InterlockedExchange64 (volatile Type* a, Type b) noexcept { jassertfalse; Type old = *a; *a = b; return old; }
|
|
template <typename Type> static Type juce_InterlockedIncrement64 (volatile Type* a) noexcept { jassertfalse; return ++*a; }
|
|
template <typename Type> static Type juce_InterlockedDecrement64 (volatile Type* a) noexcept { 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 <typename Type>
|
|
inline Type Atomic<Type>::get() const noexcept
|
|
{
|
|
#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_ANDROID
|
|
return value;
|
|
#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 <typename Type>
|
|
inline Type Atomic<Type>::exchange (const Type newValue) noexcept
|
|
{
|
|
#if JUCE_ATOMICS_ANDROID
|
|
return castFrom32Bit (__atomic_swap (castTo32Bit (newValue), (volatile int*) &value));
|
|
#elif 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 <typename Type>
|
|
inline Type Atomic<Type>::operator+= (const Type amountToAdd) noexcept
|
|
{
|
|
#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_ANDROID
|
|
for (;;)
|
|
{
|
|
const Type oldValue (value);
|
|
const Type newValue (castFrom32Bit (castTo32Bit (oldValue) + castTo32Bit (amountToAdd)));
|
|
if (compareAndSetBool (newValue, oldValue))
|
|
return newValue;
|
|
}
|
|
#elif JUCE_ATOMICS_GCC
|
|
return (Type) __sync_add_and_fetch (&value, amountToAdd);
|
|
#endif
|
|
}
|
|
|
|
template <typename Type>
|
|
inline Type Atomic<Type>::operator-= (const Type amountToSubtract) noexcept
|
|
{
|
|
return operator+= (juce_negate (amountToSubtract));
|
|
}
|
|
|
|
template <typename Type>
|
|
inline Type Atomic<Type>::operator++() noexcept
|
|
{
|
|
#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_ANDROID
|
|
return (Type) (__atomic_inc ((volatile int*) &value) + 1);
|
|
#elif JUCE_ATOMICS_GCC
|
|
return (Type) __sync_add_and_fetch (&value, 1);
|
|
#endif
|
|
}
|
|
|
|
template <typename Type>
|
|
inline Type Atomic<Type>::operator--() noexcept
|
|
{
|
|
#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_ANDROID
|
|
return (Type) (__atomic_dec ((volatile int*) &value) - 1);
|
|
#elif JUCE_ATOMICS_GCC
|
|
return (Type) __sync_add_and_fetch (&value, -1);
|
|
#endif
|
|
}
|
|
|
|
template <typename Type>
|
|
inline bool Atomic<Type>::compareAndSetBool (const Type newValue, const Type valueToCompare) noexcept
|
|
{
|
|
#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_ANDROID
|
|
return __atomic_cmpxchg (castTo32Bit (valueToCompare), castTo32Bit (newValue), (volatile int*) &value) == 0;
|
|
#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 <typename Type>
|
|
inline Type Atomic<Type>::compareAndSetValue (const Type newValue, const Type valueToCompare) noexcept
|
|
{
|
|
#if JUCE_ATOMICS_MAC || JUCE_ATOMICS_ANDROID
|
|
for (;;) // Annoying workaround for 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 <typename Type>
|
|
inline void Atomic<Type>::memoryBarrier() noexcept
|
|
{
|
|
#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 ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_CharPointer_UTF8.h ***/
|
|
#ifndef __JUCE_CHARPOINTER_UTF8_JUCEHEADER__
|
|
#define __JUCE_CHARPOINTER_UTF8_JUCEHEADER__
|
|
|
|
/**
|
|
Wraps a pointer to a null-terminated UTF-8 character string, and provides
|
|
various methods to operate on the data.
|
|
@see CharPointer_UTF16, CharPointer_UTF32
|
|
*/
|
|
class CharPointer_UTF8
|
|
{
|
|
public:
|
|
typedef char CharType;
|
|
|
|
inline explicit CharPointer_UTF8 (const CharType* const rawPointer) noexcept
|
|
: data (const_cast <CharType*> (rawPointer))
|
|
{
|
|
}
|
|
|
|
inline CharPointer_UTF8 (const CharPointer_UTF8& other) noexcept
|
|
: data (other.data)
|
|
{
|
|
}
|
|
|
|
inline CharPointer_UTF8& operator= (const CharPointer_UTF8& other) noexcept
|
|
{
|
|
data = other.data;
|
|
return *this;
|
|
}
|
|
|
|
inline CharPointer_UTF8& operator= (const CharType* text) noexcept
|
|
{
|
|
data = const_cast <CharType*> (text);
|
|
return *this;
|
|
}
|
|
|
|
/** This is a pointer comparison, it doesn't compare the actual text. */
|
|
inline bool operator== (const CharPointer_UTF8& other) const noexcept { return data == other.data; }
|
|
inline bool operator!= (const CharPointer_UTF8& other) const noexcept { return data != other.data; }
|
|
inline bool operator<= (const CharPointer_UTF8& other) const noexcept { return data <= other.data; }
|
|
inline bool operator< (const CharPointer_UTF8& other) const noexcept { return data < other.data; }
|
|
inline bool operator>= (const CharPointer_UTF8& other) const noexcept { return data >= other.data; }
|
|
inline bool operator> (const CharPointer_UTF8& other) const noexcept { return data > other.data; }
|
|
|
|
/** Returns the address that this pointer is pointing to. */
|
|
inline CharType* getAddress() const noexcept { return data; }
|
|
|
|
/** Returns the address that this pointer is pointing to. */
|
|
inline operator const CharType*() const noexcept { return data; }
|
|
|
|
/** Returns true if this pointer is pointing to a null character. */
|
|
inline bool isEmpty() const noexcept { return *data == 0; }
|
|
|
|
/** Returns the unicode character that this pointer is pointing to. */
|
|
juce_wchar operator*() const noexcept
|
|
{
|
|
const signed char byte = (signed char) *data;
|
|
|
|
if (byte >= 0)
|
|
return byte;
|
|
|
|
uint32 n = (uint32) (uint8) byte;
|
|
uint32 mask = 0x7f;
|
|
uint32 bit = 0x40;
|
|
size_t numExtraValues = 0;
|
|
|
|
while ((n & bit) != 0 && bit > 0x10)
|
|
{
|
|
mask >>= 1;
|
|
++numExtraValues;
|
|
bit >>= 1;
|
|
}
|
|
|
|
n &= mask;
|
|
|
|
for (size_t i = 1; i <= numExtraValues; ++i)
|
|
{
|
|
const juce_wchar nextByte = data [i];
|
|
|
|
if ((nextByte & 0xc0) != 0x80)
|
|
break;
|
|
|
|
n <<= 6;
|
|
n |= (nextByte & 0x3f);
|
|
}
|
|
|
|
return (juce_wchar) n;
|
|
}
|
|
|
|
/** Moves this pointer along to the next character in the string. */
|
|
CharPointer_UTF8& operator++() noexcept
|
|
{
|
|
const signed char n = (signed char) *data++;
|
|
|
|
if (n < 0)
|
|
{
|
|
juce_wchar bit = 0x40;
|
|
|
|
while ((n & bit) != 0 && bit > 0x8)
|
|
{
|
|
++data;
|
|
bit >>= 1;
|
|
}
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/** Moves this pointer back to the previous character in the string. */
|
|
CharPointer_UTF8& operator--() noexcept
|
|
{
|
|
const char n = *--data;
|
|
|
|
if ((n & 0xc0) == 0xc0)
|
|
{
|
|
int count = 3;
|
|
|
|
do
|
|
{
|
|
--data;
|
|
}
|
|
while ((*data & 0xc0) == 0xc0 && --count >= 0);
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/** Returns the character that this pointer is currently pointing to, and then
|
|
advances the pointer to point to the next character. */
|
|
juce_wchar getAndAdvance() noexcept
|
|
{
|
|
const signed char byte = (signed char) *data++;
|
|
|
|
if (byte >= 0)
|
|
return byte;
|
|
|
|
uint32 n = (uint32) (uint8) byte;
|
|
uint32 mask = 0x7f;
|
|
uint32 bit = 0x40;
|
|
int numExtraValues = 0;
|
|
|
|
while ((n & bit) != 0 && bit > 0x8)
|
|
{
|
|
mask >>= 1;
|
|
++numExtraValues;
|
|
bit >>= 1;
|
|
}
|
|
|
|
n &= mask;
|
|
|
|
while (--numExtraValues >= 0)
|
|
{
|
|
const uint32 nextByte = (uint32) (uint8) *data++;
|
|
|
|
if ((nextByte & 0xc0) != 0x80)
|
|
break;
|
|
|
|
n <<= 6;
|
|
n |= (nextByte & 0x3f);
|
|
}
|
|
|
|
return (juce_wchar) n;
|
|
}
|
|
|
|
/** Moves this pointer along to the next character in the string. */
|
|
CharPointer_UTF8 operator++ (int) noexcept
|
|
{
|
|
CharPointer_UTF8 temp (*this);
|
|
++*this;
|
|
return temp;
|
|
}
|
|
|
|
/** Moves this pointer forwards by the specified number of characters. */
|
|
void operator+= (int numToSkip) noexcept
|
|
{
|
|
if (numToSkip < 0)
|
|
{
|
|
while (++numToSkip <= 0)
|
|
--*this;
|
|
}
|
|
else
|
|
{
|
|
while (--numToSkip >= 0)
|
|
++*this;
|
|
}
|
|
}
|
|
|
|
/** Moves this pointer backwards by the specified number of characters. */
|
|
void operator-= (int numToSkip) noexcept
|
|
{
|
|
operator+= (-numToSkip);
|
|
}
|
|
|
|
/** Returns the character at a given character index from the start of the string. */
|
|
juce_wchar operator[] (int characterIndex) const noexcept
|
|
{
|
|
CharPointer_UTF8 p (*this);
|
|
p += characterIndex;
|
|
return *p;
|
|
}
|
|
|
|
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
|
|
CharPointer_UTF8 operator+ (int numToSkip) const noexcept
|
|
{
|
|
CharPointer_UTF8 p (*this);
|
|
p += numToSkip;
|
|
return p;
|
|
}
|
|
|
|
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
|
|
CharPointer_UTF8 operator- (int numToSkip) const noexcept
|
|
{
|
|
CharPointer_UTF8 p (*this);
|
|
p += -numToSkip;
|
|
return p;
|
|
}
|
|
|
|
/** Returns the number of characters in this string. */
|
|
size_t length() const noexcept
|
|
{
|
|
const CharType* d = data;
|
|
size_t count = 0;
|
|
|
|
for (;;)
|
|
{
|
|
const uint32 n = (uint32) (uint8) *d++;
|
|
|
|
if ((n & 0x80) != 0)
|
|
{
|
|
uint32 bit = 0x40;
|
|
|
|
while ((n & bit) != 0)
|
|
{
|
|
++d;
|
|
bit >>= 1;
|
|
|
|
if (bit == 0)
|
|
break; // illegal utf-8 sequence
|
|
}
|
|
}
|
|
else if (n == 0)
|
|
break;
|
|
|
|
++count;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/** Returns the number of characters in this string, or the given value, whichever is lower. */
|
|
size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
|
|
{
|
|
return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
|
|
}
|
|
|
|
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
|
|
size_t lengthUpTo (const CharPointer_UTF8& end) const noexcept
|
|
{
|
|
return CharacterFunctions::lengthUpTo (*this, end);
|
|
}
|
|
|
|
/** Returns the number of bytes that are used to represent this string.
|
|
This includes the terminating null character.
|
|
*/
|
|
size_t sizeInBytes() const noexcept
|
|
{
|
|
return strlen (data) + 1;
|
|
}
|
|
|
|
/** Returns the number of bytes that would be needed to represent the given
|
|
unicode character in this encoding format.
|
|
*/
|
|
static size_t getBytesRequiredFor (const juce_wchar charToWrite) noexcept
|
|
{
|
|
size_t num = 1;
|
|
const uint32 c = (uint32) charToWrite;
|
|
|
|
if (c >= 0x80)
|
|
{
|
|
++num;
|
|
if (c >= 0x800)
|
|
{
|
|
++num;
|
|
if (c >= 0x10000)
|
|
++num;
|
|
}
|
|
}
|
|
|
|
return num;
|
|
}
|
|
|
|
/** Returns the number of bytes that would be needed to represent the given
|
|
string in this encoding format.
|
|
The value returned does NOT include the terminating null character.
|
|
*/
|
|
template <class CharPointer>
|
|
static size_t getBytesRequiredFor (CharPointer text) noexcept
|
|
{
|
|
size_t count = 0;
|
|
juce_wchar n;
|
|
|
|
while ((n = text.getAndAdvance()) != 0)
|
|
count += getBytesRequiredFor (n);
|
|
|
|
return count;
|
|
}
|
|
|
|
/** Returns a pointer to the null character that terminates this string. */
|
|
CharPointer_UTF8 findTerminatingNull() const noexcept
|
|
{
|
|
return CharPointer_UTF8 (data + strlen (data));
|
|
}
|
|
|
|
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
|
|
void write (const juce_wchar charToWrite) noexcept
|
|
{
|
|
const uint32 c = (uint32) charToWrite;
|
|
|
|
if (c >= 0x80)
|
|
{
|
|
int numExtraBytes = 1;
|
|
if (c >= 0x800)
|
|
{
|
|
++numExtraBytes;
|
|
if (c >= 0x10000)
|
|
++numExtraBytes;
|
|
}
|
|
|
|
*data++ = (CharType) ((0xff << (7 - numExtraBytes)) | (c >> (numExtraBytes * 6)));
|
|
|
|
while (--numExtraBytes >= 0)
|
|
*data++ = (CharType) (0x80 | (0x3f & (c >> (numExtraBytes * 6))));
|
|
}
|
|
else
|
|
{
|
|
*data++ = (CharType) c;
|
|
}
|
|
}
|
|
|
|
/** Writes a null character to this string (leaving the pointer's position unchanged). */
|
|
inline void writeNull() const noexcept
|
|
{
|
|
*data = 0;
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes. */
|
|
template <typename CharPointer>
|
|
void writeAll (const CharPointer& src) noexcept
|
|
{
|
|
CharacterFunctions::copyAll (*this, src);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes. */
|
|
void writeAll (const CharPointer_UTF8& src) noexcept
|
|
{
|
|
const CharType* s = src.data;
|
|
|
|
while ((*data = *s) != 0)
|
|
{
|
|
++data;
|
|
++s;
|
|
}
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes.
|
|
The maxDestBytes parameter specifies the maximum number of bytes that can be written
|
|
to the destination buffer before stopping.
|
|
*/
|
|
template <typename CharPointer>
|
|
int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) noexcept
|
|
{
|
|
return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes.
|
|
The maxChars parameter specifies the maximum number of characters that can be
|
|
written to the destination buffer before stopping (including the terminating null).
|
|
*/
|
|
template <typename CharPointer>
|
|
void writeWithCharLimit (const CharPointer& src, const int maxChars) noexcept
|
|
{
|
|
CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
template <typename CharPointer>
|
|
int compare (const CharPointer& other) const noexcept
|
|
{
|
|
return CharacterFunctions::compare (*this, other);
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
template <typename CharPointer>
|
|
int compareUpTo (const CharPointer& other, const int maxChars) const noexcept
|
|
{
|
|
return CharacterFunctions::compareUpTo (*this, other, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
template <typename CharPointer>
|
|
int compareIgnoreCase (const CharPointer& other) const noexcept
|
|
{
|
|
return CharacterFunctions::compareIgnoreCase (*this, other);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
int compareIgnoreCase (const CharPointer_UTF8& other) const noexcept
|
|
{
|
|
#if JUCE_WINDOWS
|
|
return stricmp (data, other.data);
|
|
#else
|
|
return strcasecmp (data, other.data);
|
|
#endif
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
template <typename CharPointer>
|
|
int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const noexcept
|
|
{
|
|
return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
int compareIgnoreCaseUpTo (const CharPointer_UTF8& other, const int maxChars) const noexcept
|
|
{
|
|
#if JUCE_WINDOWS
|
|
return strnicmp (data, other.data, maxChars);
|
|
#else
|
|
return strncasecmp (data, other.data, maxChars);
|
|
#endif
|
|
}
|
|
|
|
/** Returns the character index of a substring, or -1 if it isn't found. */
|
|
template <typename CharPointer>
|
|
int indexOf (const CharPointer& stringToFind) const noexcept
|
|
{
|
|
return CharacterFunctions::indexOf (*this, stringToFind);
|
|
}
|
|
|
|
/** Returns the character index of a unicode character, or -1 if it isn't found. */
|
|
int indexOf (const juce_wchar charToFind) const noexcept
|
|
{
|
|
return CharacterFunctions::indexOfChar (*this, charToFind);
|
|
}
|
|
|
|
/** Returns the character index of a unicode character, or -1 if it isn't found. */
|
|
int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
|
|
{
|
|
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
|
|
: CharacterFunctions::indexOfChar (*this, charToFind);
|
|
}
|
|
|
|
/** Returns true if the first character of this string is whitespace. */
|
|
bool isWhitespace() const noexcept { return *data == ' ' || (*data <= 13 && *data >= 9); }
|
|
/** Returns true if the first character of this string is a digit. */
|
|
bool isDigit() const noexcept { return *data >= '0' && *data <= '9'; }
|
|
/** Returns true if the first character of this string is a letter. */
|
|
bool isLetter() const noexcept { return CharacterFunctions::isLetter (operator*()) != 0; }
|
|
/** Returns true if the first character of this string is a letter or digit. */
|
|
bool isLetterOrDigit() const noexcept { return CharacterFunctions::isLetterOrDigit (operator*()) != 0; }
|
|
/** Returns true if the first character of this string is upper-case. */
|
|
bool isUpperCase() const noexcept { return CharacterFunctions::isUpperCase (operator*()) != 0; }
|
|
/** Returns true if the first character of this string is lower-case. */
|
|
bool isLowerCase() const noexcept { return CharacterFunctions::isLowerCase (operator*()) != 0; }
|
|
|
|
/** Returns an upper-case version of the first character of this string. */
|
|
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (operator*()); }
|
|
/** Returns a lower-case version of the first character of this string. */
|
|
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (operator*()); }
|
|
|
|
/** Parses this string as a 32-bit integer. */
|
|
int getIntValue32() const noexcept { return atoi (data); }
|
|
|
|
/** Parses this string as a 64-bit integer. */
|
|
int64 getIntValue64() const noexcept
|
|
{
|
|
#if JUCE_LINUX || JUCE_ANDROID
|
|
return atoll (data);
|
|
#elif JUCE_WINDOWS
|
|
return _atoi64 (data);
|
|
#else
|
|
return CharacterFunctions::getIntValue <int64, CharPointer_UTF8> (*this);
|
|
#endif
|
|
}
|
|
|
|
/** Parses this string as a floating point double. */
|
|
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); }
|
|
|
|
/** Returns the first non-whitespace character in the string. */
|
|
CharPointer_UTF8 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); }
|
|
|
|
/** Returns true if the given unicode character can be represented in this encoding. */
|
|
static bool canRepresent (juce_wchar character) noexcept
|
|
{
|
|
return ((unsigned int) character) < (unsigned int) 0x10ffff;
|
|
}
|
|
|
|
/** Returns true if this data contains a valid string in this encoding. */
|
|
static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
|
|
{
|
|
while (--maxBytesToRead >= 0 && *dataToTest != 0)
|
|
{
|
|
const signed char byte = (signed char) *dataToTest;
|
|
|
|
if (byte < 0)
|
|
{
|
|
uint32 n = (uint32) (uint8) byte;
|
|
uint32 mask = 0x7f;
|
|
uint32 bit = 0x40;
|
|
int numExtraValues = 0;
|
|
|
|
while ((n & bit) != 0)
|
|
{
|
|
if (bit <= 0x10)
|
|
return false;
|
|
|
|
mask >>= 1;
|
|
++numExtraValues;
|
|
bit >>= 1;
|
|
}
|
|
|
|
n &= mask;
|
|
|
|
while (--numExtraValues >= 0)
|
|
{
|
|
const uint32 nextByte = (uint32) (uint8) *dataToTest++;
|
|
|
|
if ((nextByte & 0xc0) != 0x80)
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/** Atomically swaps this pointer for a new value, returning the previous value. */
|
|
CharPointer_UTF8 atomicSwap (const CharPointer_UTF8& newValue)
|
|
{
|
|
return CharPointer_UTF8 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
|
|
}
|
|
|
|
/** These values are the byte-order-mark (BOM) values for a UTF-8 stream. */
|
|
enum
|
|
{
|
|
byteOrderMark1 = 0xef,
|
|
byteOrderMark2 = 0xbb,
|
|
byteOrderMark3 = 0xbf
|
|
};
|
|
|
|
private:
|
|
CharType* data;
|
|
};
|
|
|
|
#endif // __JUCE_CHARPOINTER_UTF8_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CharPointer_UTF8.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_CharPointer_UTF16.h ***/
|
|
#ifndef __JUCE_CHARPOINTER_UTF16_JUCEHEADER__
|
|
#define __JUCE_CHARPOINTER_UTF16_JUCEHEADER__
|
|
|
|
/**
|
|
Wraps a pointer to a null-terminated UTF-16 character string, and provides
|
|
various methods to operate on the data.
|
|
@see CharPointer_UTF8, CharPointer_UTF32
|
|
*/
|
|
class CharPointer_UTF16
|
|
{
|
|
public:
|
|
#if JUCE_NATIVE_WCHAR_IS_UTF16
|
|
typedef wchar_t CharType;
|
|
#else
|
|
typedef int16 CharType;
|
|
#endif
|
|
|
|
inline explicit CharPointer_UTF16 (const CharType* const rawPointer) noexcept
|
|
: data (const_cast <CharType*> (rawPointer))
|
|
{
|
|
}
|
|
|
|
inline CharPointer_UTF16 (const CharPointer_UTF16& other) noexcept
|
|
: data (other.data)
|
|
{
|
|
}
|
|
|
|
inline CharPointer_UTF16& operator= (const CharPointer_UTF16& other) noexcept
|
|
{
|
|
data = other.data;
|
|
return *this;
|
|
}
|
|
|
|
inline CharPointer_UTF16& operator= (const CharType* text) noexcept
|
|
{
|
|
data = const_cast <CharType*> (text);
|
|
return *this;
|
|
}
|
|
|
|
/** This is a pointer comparison, it doesn't compare the actual text. */
|
|
inline bool operator== (const CharPointer_UTF16& other) const noexcept { return data == other.data; }
|
|
inline bool operator!= (const CharPointer_UTF16& other) const noexcept { return data != other.data; }
|
|
inline bool operator<= (const CharPointer_UTF16& other) const noexcept { return data <= other.data; }
|
|
inline bool operator< (const CharPointer_UTF16& other) const noexcept { return data < other.data; }
|
|
inline bool operator>= (const CharPointer_UTF16& other) const noexcept { return data >= other.data; }
|
|
inline bool operator> (const CharPointer_UTF16& other) const noexcept { return data > other.data; }
|
|
|
|
/** Returns the address that this pointer is pointing to. */
|
|
inline CharType* getAddress() const noexcept { return data; }
|
|
|
|
/** Returns the address that this pointer is pointing to. */
|
|
inline operator const CharType*() const noexcept { return data; }
|
|
|
|
/** Returns true if this pointer is pointing to a null character. */
|
|
inline bool isEmpty() const noexcept { return *data == 0; }
|
|
|
|
/** Returns the unicode character that this pointer is pointing to. */
|
|
juce_wchar operator*() const noexcept
|
|
{
|
|
uint32 n = (uint32) (uint16) *data;
|
|
|
|
if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) data[1]) >= 0xdc00)
|
|
n = 0x10000 + (((n - 0xd800) << 10) | (((uint32) (uint16) data[1]) - 0xdc00));
|
|
|
|
return (juce_wchar) n;
|
|
}
|
|
|
|
/** Moves this pointer along to the next character in the string. */
|
|
CharPointer_UTF16& operator++() noexcept
|
|
{
|
|
const juce_wchar n = *data++;
|
|
|
|
if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00)
|
|
++data;
|
|
|
|
return *this;
|
|
}
|
|
|
|
/** Moves this pointer back to the previous character in the string. */
|
|
CharPointer_UTF16& operator--() noexcept
|
|
{
|
|
const juce_wchar n = *--data;
|
|
|
|
if (n >= 0xdc00 && n <= 0xdfff)
|
|
--data;
|
|
|
|
return *this;
|
|
}
|
|
|
|
/** Returns the character that this pointer is currently pointing to, and then
|
|
advances the pointer to point to the next character. */
|
|
juce_wchar getAndAdvance() noexcept
|
|
{
|
|
uint32 n = (uint32) (uint16) *data++;
|
|
|
|
if (n >= 0xd800 && n <= 0xdfff && ((uint32) (uint16) *data) >= 0xdc00)
|
|
n = 0x10000 + ((((n - 0xd800) << 10) | (((uint32) (uint16) *data++) - 0xdc00)));
|
|
|
|
return (juce_wchar) n;
|
|
}
|
|
|
|
/** Moves this pointer along to the next character in the string. */
|
|
CharPointer_UTF16 operator++ (int) noexcept
|
|
{
|
|
CharPointer_UTF16 temp (*this);
|
|
++*this;
|
|
return temp;
|
|
}
|
|
|
|
/** Moves this pointer forwards by the specified number of characters. */
|
|
void operator+= (int numToSkip) noexcept
|
|
{
|
|
if (numToSkip < 0)
|
|
{
|
|
while (++numToSkip <= 0)
|
|
--*this;
|
|
}
|
|
else
|
|
{
|
|
while (--numToSkip >= 0)
|
|
++*this;
|
|
}
|
|
}
|
|
|
|
/** Moves this pointer backwards by the specified number of characters. */
|
|
void operator-= (int numToSkip) noexcept
|
|
{
|
|
operator+= (-numToSkip);
|
|
}
|
|
|
|
/** Returns the character at a given character index from the start of the string. */
|
|
juce_wchar operator[] (const int characterIndex) const noexcept
|
|
{
|
|
CharPointer_UTF16 p (*this);
|
|
p += characterIndex;
|
|
return *p;
|
|
}
|
|
|
|
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
|
|
CharPointer_UTF16 operator+ (const int numToSkip) const noexcept
|
|
{
|
|
CharPointer_UTF16 p (*this);
|
|
p += numToSkip;
|
|
return p;
|
|
}
|
|
|
|
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
|
|
CharPointer_UTF16 operator- (const int numToSkip) const noexcept
|
|
{
|
|
CharPointer_UTF16 p (*this);
|
|
p += -numToSkip;
|
|
return p;
|
|
}
|
|
|
|
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
|
|
void write (juce_wchar charToWrite) noexcept
|
|
{
|
|
if (charToWrite >= 0x10000)
|
|
{
|
|
charToWrite -= 0x10000;
|
|
*data++ = (CharType) (0xd800 + (charToWrite >> 10));
|
|
*data++ = (CharType) (0xdc00 + (charToWrite & 0x3ff));
|
|
}
|
|
else
|
|
{
|
|
*data++ = (CharType) charToWrite;
|
|
}
|
|
}
|
|
|
|
/** Writes a null character to this string (leaving the pointer's position unchanged). */
|
|
inline void writeNull() const noexcept
|
|
{
|
|
*data = 0;
|
|
}
|
|
|
|
/** Returns the number of characters in this string. */
|
|
size_t length() const noexcept
|
|
{
|
|
const CharType* d = data;
|
|
size_t count = 0;
|
|
|
|
for (;;)
|
|
{
|
|
const int n = *d++;
|
|
|
|
if (n >= 0xd800 && n <= 0xdfff)
|
|
{
|
|
if (*d++ == 0)
|
|
break;
|
|
}
|
|
else if (n == 0)
|
|
break;
|
|
|
|
++count;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
/** Returns the number of characters in this string, or the given value, whichever is lower. */
|
|
size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
|
|
{
|
|
return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
|
|
}
|
|
|
|
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
|
|
size_t lengthUpTo (const CharPointer_UTF16& end) const noexcept
|
|
{
|
|
return CharacterFunctions::lengthUpTo (*this, end);
|
|
}
|
|
|
|
/** Returns the number of bytes that are used to represent this string.
|
|
This includes the terminating null character.
|
|
*/
|
|
size_t sizeInBytes() const noexcept
|
|
{
|
|
return sizeof (CharType) * (findNullIndex (data) + 1);
|
|
}
|
|
|
|
/** Returns the number of bytes that would be needed to represent the given
|
|
unicode character in this encoding format.
|
|
*/
|
|
static size_t getBytesRequiredFor (const juce_wchar charToWrite) noexcept
|
|
{
|
|
return (charToWrite >= 0x10000) ? (sizeof (CharType) * 2) : sizeof (CharType);
|
|
}
|
|
|
|
/** Returns the number of bytes that would be needed to represent the given
|
|
string in this encoding format.
|
|
The value returned does NOT include the terminating null character.
|
|
*/
|
|
template <class CharPointer>
|
|
static size_t getBytesRequiredFor (CharPointer text) noexcept
|
|
{
|
|
size_t count = 0;
|
|
juce_wchar n;
|
|
|
|
while ((n = text.getAndAdvance()) != 0)
|
|
count += getBytesRequiredFor (n);
|
|
|
|
return count;
|
|
}
|
|
|
|
/** Returns a pointer to the null character that terminates this string. */
|
|
CharPointer_UTF16 findTerminatingNull() const noexcept
|
|
{
|
|
const CharType* t = data;
|
|
|
|
while (*t != 0)
|
|
++t;
|
|
|
|
return CharPointer_UTF16 (t);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes. */
|
|
template <typename CharPointer>
|
|
void writeAll (const CharPointer& src) noexcept
|
|
{
|
|
CharacterFunctions::copyAll (*this, src);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes. */
|
|
void writeAll (const CharPointer_UTF16& src) noexcept
|
|
{
|
|
const CharType* s = src.data;
|
|
|
|
while ((*data = *s) != 0)
|
|
{
|
|
++data;
|
|
++s;
|
|
}
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes.
|
|
The maxDestBytes parameter specifies the maximum number of bytes that can be written
|
|
to the destination buffer before stopping.
|
|
*/
|
|
template <typename CharPointer>
|
|
int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) noexcept
|
|
{
|
|
return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes.
|
|
The maxChars parameter specifies the maximum number of characters that can be
|
|
written to the destination buffer before stopping (including the terminating null).
|
|
*/
|
|
template <typename CharPointer>
|
|
void writeWithCharLimit (const CharPointer& src, const int maxChars) noexcept
|
|
{
|
|
CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
template <typename CharPointer>
|
|
int compare (const CharPointer& other) const noexcept
|
|
{
|
|
return CharacterFunctions::compare (*this, other);
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
template <typename CharPointer>
|
|
int compareUpTo (const CharPointer& other, const int maxChars) const noexcept
|
|
{
|
|
return CharacterFunctions::compareUpTo (*this, other, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
template <typename CharPointer>
|
|
int compareIgnoreCase (const CharPointer& other) const noexcept
|
|
{
|
|
return CharacterFunctions::compareIgnoreCase (*this, other);
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
template <typename CharPointer>
|
|
int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const noexcept
|
|
{
|
|
return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
|
|
}
|
|
|
|
#if JUCE_WINDOWS && ! DOXYGEN
|
|
int compareIgnoreCase (const CharPointer_UTF16& other) const noexcept
|
|
{
|
|
return _wcsicmp (data, other.data);
|
|
}
|
|
|
|
int compareIgnoreCaseUpTo (const CharPointer_UTF16& other, int maxChars) const noexcept
|
|
{
|
|
return _wcsnicmp (data, other.data, maxChars);
|
|
}
|
|
|
|
int indexOf (const CharPointer_UTF16& stringToFind) const noexcept
|
|
{
|
|
const CharType* const t = wcsstr (data, stringToFind.getAddress());
|
|
return t == nullptr ? -1 : (int) (t - data);
|
|
}
|
|
#endif
|
|
|
|
/** Returns the character index of a substring, or -1 if it isn't found. */
|
|
template <typename CharPointer>
|
|
int indexOf (const CharPointer& stringToFind) const noexcept
|
|
{
|
|
return CharacterFunctions::indexOf (*this, stringToFind);
|
|
}
|
|
|
|
/** Returns the character index of a unicode character, or -1 if it isn't found. */
|
|
int indexOf (const juce_wchar charToFind) const noexcept
|
|
{
|
|
return CharacterFunctions::indexOfChar (*this, charToFind);
|
|
}
|
|
|
|
/** Returns the character index of a unicode character, or -1 if it isn't found. */
|
|
int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
|
|
{
|
|
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
|
|
: CharacterFunctions::indexOfChar (*this, charToFind);
|
|
}
|
|
|
|
/** Returns true if the first character of this string is whitespace. */
|
|
bool isWhitespace() const noexcept { return CharacterFunctions::isWhitespace (operator*()) != 0; }
|
|
/** Returns true if the first character of this string is a digit. */
|
|
bool isDigit() const noexcept { return CharacterFunctions::isDigit (operator*()) != 0; }
|
|
/** Returns true if the first character of this string is a letter. */
|
|
bool isLetter() const noexcept { return CharacterFunctions::isLetter (operator*()) != 0; }
|
|
/** Returns true if the first character of this string is a letter or digit. */
|
|
bool isLetterOrDigit() const noexcept { return CharacterFunctions::isLetterOrDigit (operator*()) != 0; }
|
|
/** Returns true if the first character of this string is upper-case. */
|
|
bool isUpperCase() const noexcept { return CharacterFunctions::isUpperCase (operator*()) != 0; }
|
|
/** Returns true if the first character of this string is lower-case. */
|
|
bool isLowerCase() const noexcept { return CharacterFunctions::isLowerCase (operator*()) != 0; }
|
|
|
|
/** Returns an upper-case version of the first character of this string. */
|
|
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (operator*()); }
|
|
/** Returns a lower-case version of the first character of this string. */
|
|
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (operator*()); }
|
|
|
|
/** Parses this string as a 32-bit integer. */
|
|
int getIntValue32() const noexcept
|
|
{
|
|
#if JUCE_WINDOWS
|
|
return _wtoi (data);
|
|
#else
|
|
return CharacterFunctions::getIntValue <int, CharPointer_UTF16> (*this);
|
|
#endif
|
|
}
|
|
|
|
/** Parses this string as a 64-bit integer. */
|
|
int64 getIntValue64() const noexcept
|
|
{
|
|
#if JUCE_WINDOWS
|
|
return _wtoi64 (data);
|
|
#else
|
|
return CharacterFunctions::getIntValue <int64, CharPointer_UTF16> (*this);
|
|
#endif
|
|
}
|
|
|
|
/** Parses this string as a floating point double. */
|
|
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); }
|
|
|
|
/** Returns the first non-whitespace character in the string. */
|
|
CharPointer_UTF16 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); }
|
|
|
|
/** Returns true if the given unicode character can be represented in this encoding. */
|
|
static bool canRepresent (juce_wchar character) noexcept
|
|
{
|
|
return ((unsigned int) character) < (unsigned int) 0x10ffff
|
|
&& (((unsigned int) character) < 0xd800 || ((unsigned int) character) > 0xdfff);
|
|
}
|
|
|
|
/** Returns true if this data contains a valid string in this encoding. */
|
|
static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
|
|
{
|
|
maxBytesToRead /= sizeof (CharType);
|
|
|
|
while (--maxBytesToRead >= 0 && *dataToTest != 0)
|
|
{
|
|
const uint32 n = (uint32) (uint16) *dataToTest++;
|
|
|
|
if (n >= 0xd800)
|
|
{
|
|
if (n > 0x10ffff)
|
|
return false;
|
|
|
|
if (n <= 0xdfff)
|
|
{
|
|
if (n > 0xdc00)
|
|
return false;
|
|
|
|
const uint32 nextChar = (uint32) (uint16) *dataToTest++;
|
|
|
|
if (nextChar < 0xdc00 || nextChar > 0xdfff)
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/** Atomically swaps this pointer for a new value, returning the previous value. */
|
|
CharPointer_UTF16 atomicSwap (const CharPointer_UTF16& newValue)
|
|
{
|
|
return CharPointer_UTF16 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
|
|
}
|
|
|
|
/** These values are the byte-order-mark (BOM) values for a UTF-16 stream. */
|
|
enum
|
|
{
|
|
byteOrderMarkBE1 = 0xfe,
|
|
byteOrderMarkBE2 = 0xff,
|
|
byteOrderMarkLE1 = 0xff,
|
|
byteOrderMarkLE2 = 0xfe
|
|
};
|
|
|
|
private:
|
|
CharType* data;
|
|
|
|
static int findNullIndex (const CharType* const t) noexcept
|
|
{
|
|
int n = 0;
|
|
|
|
while (t[n] != 0)
|
|
++n;
|
|
|
|
return n;
|
|
}
|
|
};
|
|
|
|
#endif // __JUCE_CHARPOINTER_UTF16_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CharPointer_UTF16.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_CharPointer_UTF32.h ***/
|
|
#ifndef __JUCE_CHARPOINTER_UTF32_JUCEHEADER__
|
|
#define __JUCE_CHARPOINTER_UTF32_JUCEHEADER__
|
|
|
|
/**
|
|
Wraps a pointer to a null-terminated UTF-32 character string, and provides
|
|
various methods to operate on the data.
|
|
@see CharPointer_UTF8, CharPointer_UTF16
|
|
*/
|
|
class CharPointer_UTF32
|
|
{
|
|
public:
|
|
typedef juce_wchar CharType;
|
|
|
|
inline explicit CharPointer_UTF32 (const CharType* const rawPointer) noexcept
|
|
: data (const_cast <CharType*> (rawPointer))
|
|
{
|
|
}
|
|
|
|
inline CharPointer_UTF32 (const CharPointer_UTF32& other) noexcept
|
|
: data (other.data)
|
|
{
|
|
}
|
|
|
|
inline CharPointer_UTF32& operator= (const CharPointer_UTF32& other) noexcept
|
|
{
|
|
data = other.data;
|
|
return *this;
|
|
}
|
|
|
|
inline CharPointer_UTF32& operator= (const CharType* text) noexcept
|
|
{
|
|
data = const_cast <CharType*> (text);
|
|
return *this;
|
|
}
|
|
|
|
/** This is a pointer comparison, it doesn't compare the actual text. */
|
|
inline bool operator== (const CharPointer_UTF32& other) const noexcept { return data == other.data; }
|
|
inline bool operator!= (const CharPointer_UTF32& other) const noexcept { return data != other.data; }
|
|
inline bool operator<= (const CharPointer_UTF32& other) const noexcept { return data <= other.data; }
|
|
inline bool operator< (const CharPointer_UTF32& other) const noexcept { return data < other.data; }
|
|
inline bool operator>= (const CharPointer_UTF32& other) const noexcept { return data >= other.data; }
|
|
inline bool operator> (const CharPointer_UTF32& other) const noexcept { return data > other.data; }
|
|
|
|
/** Returns the address that this pointer is pointing to. */
|
|
inline CharType* getAddress() const noexcept { return data; }
|
|
|
|
/** Returns the address that this pointer is pointing to. */
|
|
inline operator const CharType*() const noexcept { return data; }
|
|
|
|
/** Returns true if this pointer is pointing to a null character. */
|
|
inline bool isEmpty() const noexcept { return *data == 0; }
|
|
|
|
/** Returns the unicode character that this pointer is pointing to. */
|
|
inline juce_wchar operator*() const noexcept { return *data; }
|
|
|
|
/** Moves this pointer along to the next character in the string. */
|
|
inline CharPointer_UTF32& operator++() noexcept
|
|
{
|
|
++data;
|
|
return *this;
|
|
}
|
|
|
|
/** Moves this pointer to the previous character in the string. */
|
|
inline CharPointer_UTF32& operator--() noexcept
|
|
{
|
|
--data;
|
|
return *this;
|
|
}
|
|
|
|
/** Returns the character that this pointer is currently pointing to, and then
|
|
advances the pointer to point to the next character. */
|
|
inline juce_wchar getAndAdvance() noexcept { return *data++; }
|
|
|
|
/** Moves this pointer along to the next character in the string. */
|
|
CharPointer_UTF32 operator++ (int) noexcept
|
|
{
|
|
CharPointer_UTF32 temp (*this);
|
|
++data;
|
|
return temp;
|
|
}
|
|
|
|
/** Moves this pointer forwards by the specified number of characters. */
|
|
inline void operator+= (const int numToSkip) noexcept
|
|
{
|
|
data += numToSkip;
|
|
}
|
|
|
|
inline void operator-= (const int numToSkip) noexcept
|
|
{
|
|
data -= numToSkip;
|
|
}
|
|
|
|
/** Returns the character at a given character index from the start of the string. */
|
|
inline juce_wchar& operator[] (const int characterIndex) const noexcept
|
|
{
|
|
return data [characterIndex];
|
|
}
|
|
|
|
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
|
|
CharPointer_UTF32 operator+ (const int numToSkip) const noexcept
|
|
{
|
|
return CharPointer_UTF32 (data + numToSkip);
|
|
}
|
|
|
|
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
|
|
CharPointer_UTF32 operator- (const int numToSkip) const noexcept
|
|
{
|
|
return CharPointer_UTF32 (data - numToSkip);
|
|
}
|
|
|
|
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
|
|
inline void write (const juce_wchar charToWrite) noexcept
|
|
{
|
|
*data++ = charToWrite;
|
|
}
|
|
|
|
inline void replaceChar (const juce_wchar newChar) noexcept
|
|
{
|
|
*data = newChar;
|
|
}
|
|
|
|
/** Writes a null character to this string (leaving the pointer's position unchanged). */
|
|
inline void writeNull() const noexcept
|
|
{
|
|
*data = 0;
|
|
}
|
|
|
|
/** Returns the number of characters in this string. */
|
|
size_t length() const noexcept
|
|
{
|
|
#if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
|
|
return wcslen (data);
|
|
#else
|
|
size_t n = 0;
|
|
while (data[n] != 0)
|
|
++n;
|
|
return n;
|
|
#endif
|
|
}
|
|
|
|
/** Returns the number of characters in this string, or the given value, whichever is lower. */
|
|
size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
|
|
{
|
|
return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
|
|
}
|
|
|
|
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
|
|
size_t lengthUpTo (const CharPointer_UTF32& end) const noexcept
|
|
{
|
|
return CharacterFunctions::lengthUpTo (*this, end);
|
|
}
|
|
|
|
/** Returns the number of bytes that are used to represent this string.
|
|
This includes the terminating null character.
|
|
*/
|
|
size_t sizeInBytes() const noexcept
|
|
{
|
|
return sizeof (CharType) * (length() + 1);
|
|
}
|
|
|
|
/** Returns the number of bytes that would be needed to represent the given
|
|
unicode character in this encoding format.
|
|
*/
|
|
static inline size_t getBytesRequiredFor (const juce_wchar) noexcept
|
|
{
|
|
return sizeof (CharType);
|
|
}
|
|
|
|
/** Returns the number of bytes that would be needed to represent the given
|
|
string in this encoding format.
|
|
The value returned does NOT include the terminating null character.
|
|
*/
|
|
template <class CharPointer>
|
|
static size_t getBytesRequiredFor (const CharPointer& text) noexcept
|
|
{
|
|
return sizeof (CharType) * text.length();
|
|
}
|
|
|
|
/** Returns a pointer to the null character that terminates this string. */
|
|
CharPointer_UTF32 findTerminatingNull() const noexcept
|
|
{
|
|
return CharPointer_UTF32 (data + length());
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes. */
|
|
template <typename CharPointer>
|
|
void writeAll (const CharPointer& src) noexcept
|
|
{
|
|
CharacterFunctions::copyAll (*this, src);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes. */
|
|
void writeAll (const CharPointer_UTF32& src) noexcept
|
|
{
|
|
const CharType* s = src.data;
|
|
|
|
while ((*data = *s) != 0)
|
|
{
|
|
++data;
|
|
++s;
|
|
}
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes.
|
|
The maxDestBytes parameter specifies the maximum number of bytes that can be written
|
|
to the destination buffer before stopping.
|
|
*/
|
|
template <typename CharPointer>
|
|
int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) noexcept
|
|
{
|
|
return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes.
|
|
The maxChars parameter specifies the maximum number of characters that can be
|
|
written to the destination buffer before stopping (including the terminating null).
|
|
*/
|
|
template <typename CharPointer>
|
|
void writeWithCharLimit (const CharPointer& src, const int maxChars) noexcept
|
|
{
|
|
CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
template <typename CharPointer>
|
|
int compare (const CharPointer& other) const noexcept
|
|
{
|
|
return CharacterFunctions::compare (*this, other);
|
|
}
|
|
|
|
#if JUCE_NATIVE_WCHAR_IS_UTF32 && ! JUCE_ANDROID
|
|
/** Compares this string with another one. */
|
|
int compare (const CharPointer_UTF32& other) const noexcept
|
|
{
|
|
return wcscmp (data, other.data);
|
|
}
|
|
#endif
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
template <typename CharPointer>
|
|
int compareUpTo (const CharPointer& other, const int maxChars) const noexcept
|
|
{
|
|
return CharacterFunctions::compareUpTo (*this, other, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
template <typename CharPointer>
|
|
int compareIgnoreCase (const CharPointer& other) const
|
|
{
|
|
return CharacterFunctions::compareIgnoreCase (*this, other);
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
template <typename CharPointer>
|
|
int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const noexcept
|
|
{
|
|
return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
|
|
}
|
|
|
|
/** Returns the character index of a substring, or -1 if it isn't found. */
|
|
template <typename CharPointer>
|
|
int indexOf (const CharPointer& stringToFind) const noexcept
|
|
{
|
|
return CharacterFunctions::indexOf (*this, stringToFind);
|
|
}
|
|
|
|
/** Returns the character index of a unicode character, or -1 if it isn't found. */
|
|
int indexOf (const juce_wchar charToFind) const noexcept
|
|
{
|
|
int i = 0;
|
|
|
|
while (data[i] != 0)
|
|
{
|
|
if (data[i] == charToFind)
|
|
return i;
|
|
|
|
++i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/** Returns the character index of a unicode character, or -1 if it isn't found. */
|
|
int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
|
|
{
|
|
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
|
|
: CharacterFunctions::indexOfChar (*this, charToFind);
|
|
}
|
|
|
|
/** Returns true if the first character of this string is whitespace. */
|
|
bool isWhitespace() const { return CharacterFunctions::isWhitespace (*data) != 0; }
|
|
/** Returns true if the first character of this string is a digit. */
|
|
bool isDigit() const { return CharacterFunctions::isDigit (*data) != 0; }
|
|
/** Returns true if the first character of this string is a letter. */
|
|
bool isLetter() const { return CharacterFunctions::isLetter (*data) != 0; }
|
|
/** Returns true if the first character of this string is a letter or digit. */
|
|
bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
|
|
/** Returns true if the first character of this string is upper-case. */
|
|
bool isUpperCase() const { return CharacterFunctions::isUpperCase (*data) != 0; }
|
|
/** Returns true if the first character of this string is lower-case. */
|
|
bool isLowerCase() const { return CharacterFunctions::isLowerCase (*data) != 0; }
|
|
|
|
/** Returns an upper-case version of the first character of this string. */
|
|
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (*data); }
|
|
/** Returns a lower-case version of the first character of this string. */
|
|
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (*data); }
|
|
|
|
/** Parses this string as a 32-bit integer. */
|
|
int getIntValue32() const noexcept { return CharacterFunctions::getIntValue <int, CharPointer_UTF32> (*this); }
|
|
/** Parses this string as a 64-bit integer. */
|
|
int64 getIntValue64() const noexcept { return CharacterFunctions::getIntValue <int64, CharPointer_UTF32> (*this); }
|
|
|
|
/** Parses this string as a floating point double. */
|
|
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); }
|
|
|
|
/** Returns the first non-whitespace character in the string. */
|
|
CharPointer_UTF32 findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); }
|
|
|
|
/** Returns true if the given unicode character can be represented in this encoding. */
|
|
static bool canRepresent (juce_wchar character) noexcept
|
|
{
|
|
return ((unsigned int) character) < (unsigned int) 0x10ffff;
|
|
}
|
|
|
|
/** Returns true if this data contains a valid string in this encoding. */
|
|
static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
|
|
{
|
|
maxBytesToRead /= sizeof (CharType);
|
|
|
|
while (--maxBytesToRead >= 0 && *dataToTest != 0)
|
|
if (! canRepresent (*dataToTest++))
|
|
return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
/** Atomically swaps this pointer for a new value, returning the previous value. */
|
|
CharPointer_UTF32 atomicSwap (const CharPointer_UTF32& newValue)
|
|
{
|
|
return CharPointer_UTF32 (reinterpret_cast <Atomic<CharType*>&> (data).exchange (newValue.data));
|
|
}
|
|
|
|
private:
|
|
CharType* data;
|
|
};
|
|
|
|
#endif // __JUCE_CHARPOINTER_UTF32_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CharPointer_UTF32.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_CharPointer_ASCII.h ***/
|
|
#ifndef __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
|
|
#define __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
|
|
|
|
/**
|
|
Wraps a pointer to a null-terminated ASCII character string, and provides
|
|
various methods to operate on the data.
|
|
|
|
A valid ASCII string is assumed to not contain any characters above 127.
|
|
|
|
@see CharPointer_UTF8, CharPointer_UTF16, CharPointer_UTF32
|
|
*/
|
|
class CharPointer_ASCII
|
|
{
|
|
public:
|
|
typedef char CharType;
|
|
|
|
inline explicit CharPointer_ASCII (const CharType* const rawPointer) noexcept
|
|
: data (const_cast <CharType*> (rawPointer))
|
|
{
|
|
}
|
|
|
|
inline CharPointer_ASCII (const CharPointer_ASCII& other) noexcept
|
|
: data (other.data)
|
|
{
|
|
}
|
|
|
|
inline CharPointer_ASCII& operator= (const CharPointer_ASCII& other) noexcept
|
|
{
|
|
data = other.data;
|
|
return *this;
|
|
}
|
|
|
|
inline CharPointer_ASCII& operator= (const CharType* text) noexcept
|
|
{
|
|
data = const_cast <CharType*> (text);
|
|
return *this;
|
|
}
|
|
|
|
/** This is a pointer comparison, it doesn't compare the actual text. */
|
|
inline bool operator== (const CharPointer_ASCII& other) const noexcept { return data == other.data; }
|
|
inline bool operator!= (const CharPointer_ASCII& other) const noexcept { return data != other.data; }
|
|
inline bool operator<= (const CharPointer_ASCII& other) const noexcept { return data <= other.data; }
|
|
inline bool operator< (const CharPointer_ASCII& other) const noexcept { return data < other.data; }
|
|
inline bool operator>= (const CharPointer_ASCII& other) const noexcept { return data >= other.data; }
|
|
inline bool operator> (const CharPointer_ASCII& other) const noexcept { return data > other.data; }
|
|
|
|
/** Returns the address that this pointer is pointing to. */
|
|
inline CharType* getAddress() const noexcept { return data; }
|
|
|
|
/** Returns the address that this pointer is pointing to. */
|
|
inline operator const CharType*() const noexcept { return data; }
|
|
|
|
/** Returns true if this pointer is pointing to a null character. */
|
|
inline bool isEmpty() const noexcept { return *data == 0; }
|
|
|
|
/** Returns the unicode character that this pointer is pointing to. */
|
|
inline juce_wchar operator*() const noexcept { return *data; }
|
|
|
|
/** Moves this pointer along to the next character in the string. */
|
|
inline CharPointer_ASCII& operator++() noexcept
|
|
{
|
|
++data;
|
|
return *this;
|
|
}
|
|
|
|
/** Moves this pointer to the previous character in the string. */
|
|
inline CharPointer_ASCII& operator--() noexcept
|
|
{
|
|
--data;
|
|
return *this;
|
|
}
|
|
|
|
/** Returns the character that this pointer is currently pointing to, and then
|
|
advances the pointer to point to the next character. */
|
|
inline juce_wchar getAndAdvance() noexcept { return *data++; }
|
|
|
|
/** Moves this pointer along to the next character in the string. */
|
|
CharPointer_ASCII operator++ (int) noexcept
|
|
{
|
|
CharPointer_ASCII temp (*this);
|
|
++data;
|
|
return temp;
|
|
}
|
|
|
|
/** Moves this pointer forwards by the specified number of characters. */
|
|
inline void operator+= (const int numToSkip) noexcept
|
|
{
|
|
data += numToSkip;
|
|
}
|
|
|
|
inline void operator-= (const int numToSkip) noexcept
|
|
{
|
|
data -= numToSkip;
|
|
}
|
|
|
|
/** Returns the character at a given character index from the start of the string. */
|
|
inline juce_wchar operator[] (const int characterIndex) const noexcept
|
|
{
|
|
return (juce_wchar) (unsigned char) data [characterIndex];
|
|
}
|
|
|
|
/** Returns a pointer which is moved forwards from this one by the specified number of characters. */
|
|
CharPointer_ASCII operator+ (const int numToSkip) const noexcept
|
|
{
|
|
return CharPointer_ASCII (data + numToSkip);
|
|
}
|
|
|
|
/** Returns a pointer which is moved backwards from this one by the specified number of characters. */
|
|
CharPointer_ASCII operator- (const int numToSkip) const noexcept
|
|
{
|
|
return CharPointer_ASCII (data - numToSkip);
|
|
}
|
|
|
|
/** Writes a unicode character to this string, and advances this pointer to point to the next position. */
|
|
inline void write (const juce_wchar charToWrite) noexcept
|
|
{
|
|
*data++ = (char) charToWrite;
|
|
}
|
|
|
|
inline void replaceChar (const juce_wchar newChar) noexcept
|
|
{
|
|
*data = (char) newChar;
|
|
}
|
|
|
|
/** Writes a null character to this string (leaving the pointer's position unchanged). */
|
|
inline void writeNull() const noexcept
|
|
{
|
|
*data = 0;
|
|
}
|
|
|
|
/** Returns the number of characters in this string. */
|
|
size_t length() const noexcept
|
|
{
|
|
return (size_t) strlen (data);
|
|
}
|
|
|
|
/** Returns the number of characters in this string, or the given value, whichever is lower. */
|
|
size_t lengthUpTo (const size_t maxCharsToCount) const noexcept
|
|
{
|
|
return CharacterFunctions::lengthUpTo (*this, maxCharsToCount);
|
|
}
|
|
|
|
/** Returns the number of characters in this string, or up to the given end pointer, whichever is lower. */
|
|
size_t lengthUpTo (const CharPointer_ASCII& end) const noexcept
|
|
{
|
|
return CharacterFunctions::lengthUpTo (*this, end);
|
|
}
|
|
|
|
/** Returns the number of bytes that are used to represent this string.
|
|
This includes the terminating null character.
|
|
*/
|
|
size_t sizeInBytes() const noexcept
|
|
{
|
|
return length() + 1;
|
|
}
|
|
|
|
/** Returns the number of bytes that would be needed to represent the given
|
|
unicode character in this encoding format.
|
|
*/
|
|
static inline size_t getBytesRequiredFor (const juce_wchar) noexcept
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
/** Returns the number of bytes that would be needed to represent the given
|
|
string in this encoding format.
|
|
The value returned does NOT include the terminating null character.
|
|
*/
|
|
template <class CharPointer>
|
|
static size_t getBytesRequiredFor (const CharPointer& text) noexcept
|
|
{
|
|
return text.length();
|
|
}
|
|
|
|
/** Returns a pointer to the null character that terminates this string. */
|
|
CharPointer_ASCII findTerminatingNull() const noexcept
|
|
{
|
|
return CharPointer_ASCII (data + length());
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes. */
|
|
template <typename CharPointer>
|
|
void writeAll (const CharPointer& src) noexcept
|
|
{
|
|
CharacterFunctions::copyAll (*this, src);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes. */
|
|
void writeAll (const CharPointer_ASCII& src) noexcept
|
|
{
|
|
strcpy (data, src.data);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes.
|
|
The maxDestBytes parameter specifies the maximum number of bytes that can be written
|
|
to the destination buffer before stopping.
|
|
*/
|
|
template <typename CharPointer>
|
|
int writeWithDestByteLimit (const CharPointer& src, const int maxDestBytes) noexcept
|
|
{
|
|
return CharacterFunctions::copyWithDestByteLimit (*this, src, maxDestBytes);
|
|
}
|
|
|
|
/** Copies a source string to this pointer, advancing this pointer as it goes.
|
|
The maxChars parameter specifies the maximum number of characters that can be
|
|
written to the destination buffer before stopping (including the terminating null).
|
|
*/
|
|
template <typename CharPointer>
|
|
void writeWithCharLimit (const CharPointer& src, const int maxChars) noexcept
|
|
{
|
|
CharacterFunctions::copyWithCharLimit (*this, src, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
template <typename CharPointer>
|
|
int compare (const CharPointer& other) const noexcept
|
|
{
|
|
return CharacterFunctions::compare (*this, other);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
int compare (const CharPointer_ASCII& other) const noexcept
|
|
{
|
|
return strcmp (data, other.data);
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
template <typename CharPointer>
|
|
int compareUpTo (const CharPointer& other, const int maxChars) const noexcept
|
|
{
|
|
return CharacterFunctions::compareUpTo (*this, other, maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
int compareUpTo (const CharPointer_ASCII& other, const int maxChars) const noexcept
|
|
{
|
|
return strncmp (data, other.data, (size_t) maxChars);
|
|
}
|
|
|
|
/** Compares this string with another one. */
|
|
template <typename CharPointer>
|
|
int compareIgnoreCase (const CharPointer& other) const
|
|
{
|
|
return CharacterFunctions::compareIgnoreCase (*this, other);
|
|
}
|
|
|
|
int compareIgnoreCase (const CharPointer_ASCII& other) const
|
|
{
|
|
#if JUCE_WINDOWS
|
|
return stricmp (data, other.data);
|
|
#else
|
|
return strcasecmp (data, other.data);
|
|
#endif
|
|
}
|
|
|
|
/** Compares this string with another one, up to a specified number of characters. */
|
|
template <typename CharPointer>
|
|
int compareIgnoreCaseUpTo (const CharPointer& other, const int maxChars) const noexcept
|
|
{
|
|
return CharacterFunctions::compareIgnoreCaseUpTo (*this, other, maxChars);
|
|
}
|
|
|
|
/** Returns the character index of a substring, or -1 if it isn't found. */
|
|
template <typename CharPointer>
|
|
int indexOf (const CharPointer& stringToFind) const noexcept
|
|
{
|
|
return CharacterFunctions::indexOf (*this, stringToFind);
|
|
}
|
|
|
|
/** Returns the character index of a unicode character, or -1 if it isn't found. */
|
|
int indexOf (const juce_wchar charToFind) const noexcept
|
|
{
|
|
int i = 0;
|
|
|
|
while (data[i] != 0)
|
|
{
|
|
if (data[i] == (char) charToFind)
|
|
return i;
|
|
|
|
++i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/** Returns the character index of a unicode character, or -1 if it isn't found. */
|
|
int indexOf (const juce_wchar charToFind, const bool ignoreCase) const noexcept
|
|
{
|
|
return ignoreCase ? CharacterFunctions::indexOfCharIgnoreCase (*this, charToFind)
|
|
: CharacterFunctions::indexOfChar (*this, charToFind);
|
|
}
|
|
|
|
/** Returns true if the first character of this string is whitespace. */
|
|
bool isWhitespace() const { return CharacterFunctions::isWhitespace (*data) != 0; }
|
|
/** Returns true if the first character of this string is a digit. */
|
|
bool isDigit() const { return CharacterFunctions::isDigit (*data) != 0; }
|
|
/** Returns true if the first character of this string is a letter. */
|
|
bool isLetter() const { return CharacterFunctions::isLetter (*data) != 0; }
|
|
/** Returns true if the first character of this string is a letter or digit. */
|
|
bool isLetterOrDigit() const { return CharacterFunctions::isLetterOrDigit (*data) != 0; }
|
|
/** Returns true if the first character of this string is upper-case. */
|
|
bool isUpperCase() const { return CharacterFunctions::isUpperCase (*data) != 0; }
|
|
/** Returns true if the first character of this string is lower-case. */
|
|
bool isLowerCase() const { return CharacterFunctions::isLowerCase (*data) != 0; }
|
|
|
|
/** Returns an upper-case version of the first character of this string. */
|
|
juce_wchar toUpperCase() const noexcept { return CharacterFunctions::toUpperCase (*data); }
|
|
/** Returns a lower-case version of the first character of this string. */
|
|
juce_wchar toLowerCase() const noexcept { return CharacterFunctions::toLowerCase (*data); }
|
|
|
|
/** Parses this string as a 32-bit integer. */
|
|
int getIntValue32() const noexcept { return atoi (data); }
|
|
|
|
/** Parses this string as a 64-bit integer. */
|
|
int64 getIntValue64() const noexcept
|
|
{
|
|
#if JUCE_LINUX || JUCE_ANDROID
|
|
return atoll (data);
|
|
#elif JUCE_WINDOWS
|
|
return _atoi64 (data);
|
|
#else
|
|
return CharacterFunctions::getIntValue <int64, CharPointer_ASCII> (*this);
|
|
#endif
|
|
}
|
|
|
|
/** Parses this string as a floating point double. */
|
|
double getDoubleValue() const noexcept { return CharacterFunctions::getDoubleValue (*this); }
|
|
|
|
/** Returns the first non-whitespace character in the string. */
|
|
CharPointer_ASCII findEndOfWhitespace() const noexcept { return CharacterFunctions::findEndOfWhitespace (*this); }
|
|
|
|
/** Returns true if the given unicode character can be represented in this encoding. */
|
|
static bool canRepresent (juce_wchar character) noexcept
|
|
{
|
|
return ((unsigned int) character) < (unsigned int) 128;
|
|
}
|
|
|
|
/** Returns true if this data contains a valid string in this encoding. */
|
|
static bool isValidString (const CharType* dataToTest, int maxBytesToRead)
|
|
{
|
|
while (--maxBytesToRead >= 0)
|
|
{
|
|
if (((signed char) *dataToTest) <= 0)
|
|
return *dataToTest == 0;
|
|
|
|
++dataToTest;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
private:
|
|
CharType* data;
|
|
};
|
|
|
|
#endif // __JUCE_CHARPOINTER_ASCII_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CharPointer_ASCII.h ***/
|
|
|
|
#if JUCE_MSVC
|
|
#pragma warning (pop)
|
|
#endif
|
|
|
|
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() noexcept;
|
|
|
|
/** Creates a copy of another string. */
|
|
String (const String& other) noexcept;
|
|
|
|
/** Creates a string from a zero-terminated ascii text string.
|
|
|
|
The string passed-in must not contain any characters with a value above 127, because
|
|
these can't be converted to unicode without knowing the original encoding that was
|
|
used to create the string. If you attempt to pass-in values above 127, you'll get an
|
|
assertion.
|
|
|
|
To create strings with extended characters from UTF-8, you should explicitly call
|
|
String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
|
|
use UTF-8 with escape characters in your source code to represent extended characters,
|
|
because there's no other way to represent unicode strings in a way that isn't dependent
|
|
on the compiler, source code editor and platform.
|
|
*/
|
|
String (const char* text);
|
|
|
|
/** Creates a string from a string of 8-bit ascii characters.
|
|
|
|
The string passed-in must not contain any characters with a value above 127, because
|
|
these can't be converted to unicode without knowing the original encoding that was
|
|
used to create the string. If you attempt to pass-in values above 127, you'll get an
|
|
assertion.
|
|
|
|
To create strings with extended characters from UTF-8, you should explicitly call
|
|
String (CharPointer_UTF8 ("my utf8 string..")). It's *highly* recommended that you
|
|
use UTF-8 with escape characters in your source code to represent extended characters,
|
|
because there's no other way to represent unicode strings in a way that isn't dependent
|
|
on the compiler, source code editor and platform.
|
|
|
|
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 whcar_t character string.
|
|
Depending on the platform, this may be treated as either UTF-32 or UTF-16.
|
|
*/
|
|
String (const wchar_t* text);
|
|
|
|
/** Creates a string from a whcar_t character string.
|
|
Depending on the platform, this may be treated as either UTF-32 or UTF-16.
|
|
*/
|
|
String (const wchar_t* text, size_t maxChars);
|
|
|
|
/** Creates a string from a UTF-8 character string */
|
|
String (const CharPointer_UTF8& text);
|
|
|
|
/** Creates a string from a UTF-8 character string */
|
|
String (const CharPointer_UTF8& text, size_t maxChars);
|
|
|
|
/** Creates a string from a UTF-8 character string */
|
|
String (const CharPointer_UTF8& start, const CharPointer_UTF8& end);
|
|
|
|
/** Creates a string from a UTF-16 character string */
|
|
String (const CharPointer_UTF16& text);
|
|
|
|
/** Creates a string from a UTF-16 character string */
|
|
String (const CharPointer_UTF16& text, size_t maxChars);
|
|
|
|
/** Creates a string from a UTF-16 character string */
|
|
String (const CharPointer_UTF16& start, const CharPointer_UTF16& end);
|
|
|
|
/** Creates a string from a UTF-32 character string */
|
|
String (const CharPointer_UTF32& text);
|
|
|
|
/** Creates a string from a UTF-32 character string */
|
|
String (const CharPointer_UTF32& text, size_t maxChars);
|
|
|
|
/** Creates a string from a UTF-32 character string */
|
|
String (const CharPointer_UTF32& start, const CharPointer_UTF32& end);
|
|
|
|
/** Creates a string from an ASCII character string */
|
|
String (const CharPointer_ASCII& text);
|
|
|
|
/** Creates a string from a single character. */
|
|
static String charToString (juce_wchar character);
|
|
|
|
/** Destructor. */
|
|
~String() noexcept;
|
|
|
|
/** 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;
|
|
|
|
/** This is the character encoding type used internally to store the string.
|
|
|
|
By setting the value of JUCE_STRING_UTF_TYPE to 8, 16, or 32, you can change the
|
|
internal storage format of the String class. UTF-8 uses the least space (if your strings
|
|
contain few extended characters), but call operator[] involves iterating the string to find
|
|
the required index. UTF-32 provides instant random access to its characters, but uses 4 bytes
|
|
per character to store them. UTF-16 uses more space than UTF-8 and is also slow to index,
|
|
but is the native wchar_t format used in Windows.
|
|
|
|
It doesn't matter too much which format you pick, because the toUTF8(), toUTF16() and
|
|
toUTF32() methods let you access the string's content in any of the other formats.
|
|
*/
|
|
#if (JUCE_STRING_UTF_TYPE == 32)
|
|
typedef CharPointer_UTF32 CharPointerType;
|
|
#elif (JUCE_STRING_UTF_TYPE == 16)
|
|
typedef CharPointer_UTF16 CharPointerType;
|
|
#elif (JUCE_STRING_UTF_TYPE == 8)
|
|
typedef CharPointer_UTF8 CharPointerType;
|
|
#else
|
|
#error "You must set the value of JUCE_STRING_UTF_TYPE to be either 8, 16, or 32!"
|
|
#endif
|
|
|
|
/** Generates a probably-unique 32-bit hashcode from this string. */
|
|
int hashCode() const noexcept;
|
|
|
|
/** Generates a probably-unique 64-bit hashcode from this string. */
|
|
int64 hashCode64() const noexcept;
|
|
|
|
/** Returns the number of characters in the string. */
|
|
int length() const noexcept;
|
|
|
|
// Assignment and concatenation operators..
|
|
|
|
/** Replaces this string's contents with another string. */
|
|
String& operator= (const String& other) noexcept;
|
|
|
|
/** Appends another string at the end of this one. */
|
|
String& operator+= (const String& stringToAppend);
|
|
/** Appends another string at the end of this one. */
|
|
String& operator+= (const char* textToAppend);
|
|
/** Appends another string at the end of this one. */
|
|
String& operator+= (const wchar_t* textToAppend);
|
|
/** Appends a decimal number at the end of this string. */
|
|
String& operator+= (int numberToAppend);
|
|
/** Appends a character at the end of this string. */
|
|
String& operator+= (char characterToAppend);
|
|
/** Appends a character at the end of this string. */
|
|
String& operator+= (wchar_t characterToAppend);
|
|
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
|
|
/** Appends a character at the end of this string. */
|
|
String& operator+= (juce_wchar characterToAppend);
|
|
#endif
|
|
|
|
/** Appends a string to 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 String& textToAppend, size_t maxCharsToTake);
|
|
|
|
/** Appends a string to 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
|
|
*/
|
|
template <class CharPointer>
|
|
void appendCharPointer (const CharPointer& textToAppend, size_t maxCharsToTake)
|
|
{
|
|
if (textToAppend.getAddress() != nullptr)
|
|
{
|
|
size_t extraBytesNeeded = 0;
|
|
size_t numChars = 0;
|
|
|
|
for (CharPointer t (textToAppend); numChars < maxCharsToTake && ! t.isEmpty();)
|
|
{
|
|
extraBytesNeeded += CharPointerType::getBytesRequiredFor (t.getAndAdvance());
|
|
++numChars;
|
|
}
|
|
|
|
if (numChars > 0)
|
|
{
|
|
const size_t byteOffsetOfNull = getByteOffsetOfEnd();
|
|
|
|
preallocateBytes (byteOffsetOfNull + extraBytesNeeded);
|
|
CharPointerType (addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull)).writeWithCharLimit (textToAppend, (int) (numChars + 1));
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Appends a string to the end of this one. */
|
|
template <class CharPointer>
|
|
void appendCharPointer (const CharPointer& textToAppend)
|
|
{
|
|
if (textToAppend.getAddress() != nullptr)
|
|
{
|
|
size_t extraBytesNeeded = 0;
|
|
|
|
for (CharPointer t (textToAppend); ! t.isEmpty();)
|
|
extraBytesNeeded += CharPointerType::getBytesRequiredFor (t.getAndAdvance());
|
|
|
|
if (extraBytesNeeded > 0)
|
|
{
|
|
const size_t byteOffsetOfNull = getByteOffsetOfEnd();
|
|
|
|
preallocateBytes (byteOffsetOfNull + extraBytesNeeded);
|
|
CharPointerType (addBytesToPointer (text.getAddress(), (int) byteOffsetOfNull)).writeAll (textToAppend);
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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 noexcept { 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 noexcept { return text[0] != 0; }
|
|
|
|
/** Case-insensitive comparison with another string. */
|
|
bool equalsIgnoreCase (const String& other) const noexcept;
|
|
|
|
/** Case-insensitive comparison with another string. */
|
|
bool equalsIgnoreCase (const wchar_t* other) const noexcept;
|
|
|
|
/** Case-insensitive comparison with another string. */
|
|
bool equalsIgnoreCase (const char* other) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 wchar_t* other) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Tests whether the string contains a particular character.
|
|
Uses a case-sensitive comparison.
|
|
*/
|
|
bool containsChar (juce_wchar character) const noexcept;
|
|
|
|
/** Tests whether the string contains another substring.
|
|
Uses a case-insensitive comparison.
|
|
*/
|
|
bool containsIgnoreCase (const String& text) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
// 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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.
|
|
If textToLookFor is an empty string, this will always return 0.
|
|
*/
|
|
int indexOf (const String& textToLookFor) const noexcept;
|
|
|
|
/** 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.
|
|
If textToLookFor is an empty string, this will always return -1.
|
|
*/
|
|
int indexOf (int startIndex, const String& textToLookFor) const noexcept;
|
|
|
|
/** 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.
|
|
If textToLookFor is an empty string, this will always return 0.
|
|
*/
|
|
int indexOfIgnoreCase (const String& textToLookFor) const noexcept;
|
|
|
|
/** 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.
|
|
If textToLookFor is an empty string, this will always return -1.
|
|
*/
|
|
int indexOfIgnoreCase (int startIndex, const String& textToLookFor) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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. If textToLookFor is an empty string, this will always return -1.
|
|
*/
|
|
int lastIndexOf (const String& textToLookFor) const noexcept;
|
|
|
|
/** 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. If textToLookFor is an empty string, this will always return -1.
|
|
*/
|
|
int lastIndexOfIgnoreCase (const String& textToLookFor) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
// Substring extraction and manipulation methods..
|
|
|
|
/** Returns the character at this index in the string.
|
|
In a release build, no checks are made to see if the index is within a valid range, so be
|
|
careful! In a debug build, the index is checked and an assertion fires if it's out-of-range.
|
|
|
|
Also beware that depending on the encoding format that the string is using internally, this
|
|
method may execute in either O(1) or O(n) time, so be careful when using it in your algorithms.
|
|
If you're scanning through a string to inspect its characters, you should never use this operator
|
|
for random access, it's far more efficient to call getCharPointer() to return a pointer, and
|
|
then to use that to iterate the string.
|
|
@see getCharPointer
|
|
*/
|
|
const juce_wchar operator[] (int index) const noexcept;
|
|
|
|
/** Returns the final character of the string.
|
|
If the string is empty this will return 0.
|
|
*/
|
|
juce_wchar getLastCharacter() const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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. */
|
|
String trim() const;
|
|
|
|
/** Returns a copy of this string with any whitespace characters removed from the start. */
|
|
String trimStart() const;
|
|
|
|
/** Returns a copy of this string with any whitespace characters removed from the end. */
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
String trimCharactersAtEnd (const String& charactersToTrim) const;
|
|
|
|
/** Returns an upper-case version of this string. */
|
|
String toUpperCase() const;
|
|
|
|
/** Returns an lower-case version of this string. */
|
|
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.
|
|
*/
|
|
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.
|
|
*/
|
|
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. */
|
|
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.
|
|
*/
|
|
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.
|
|
*/
|
|
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.
|
|
*/
|
|
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.
|
|
*/
|
|
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. (If none of the specified
|
|
characters are found in the string, the return value will just be the original string).
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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 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.
|
|
*/
|
|
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.
|
|
*/
|
|
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 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. And bear in mind that internally, depending
|
|
on the platform, it may be using wchar_t or char character types, so that even string
|
|
literals can't be safely used as parameters if you're writing portable code.
|
|
*/
|
|
static String formatted (const String 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Creates a string representing this 32-bit value in hexadecimal. */
|
|
static String toHexString (int number);
|
|
|
|
/** Creates a string representing this 64-bit value in hexadecimal. */
|
|
static String toHexString (int64 number);
|
|
|
|
/** Creates a string representing this 16-bit value in hexadecimal. */
|
|
static 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 String toHexString (const void* data, int size, int groupSize = 1);
|
|
|
|
/** Returns the character pointer currently being used to store 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.
|
|
*/
|
|
inline const CharPointerType& getCharPointer() const noexcept { 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.
|
|
|
|
To find out how many bytes you need to store this string as UTF-8, you can call
|
|
CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
|
|
|
|
@see getCharPointer, toUTF16, toUTF32
|
|
*/
|
|
const CharPointer_UTF8 toUTF8() const;
|
|
|
|
/** Returns a pointer to a UTF-32 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.
|
|
|
|
To find out how many bytes you need to store this string as UTF-16, you can call
|
|
CharPointer_UTF16::getBytesRequiredFor (myString.getCharPointer())
|
|
|
|
@see getCharPointer, toUTF8, toUTF32
|
|
*/
|
|
CharPointer_UTF16 toUTF16() const;
|
|
|
|
/** Returns a pointer to a UTF-32 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 getCharPointer, toUTF8, toUTF16
|
|
*/
|
|
CharPointer_UTF32 toUTF32() const;
|
|
|
|
/** Returns a pointer to a wchar_t 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.
|
|
|
|
Bear in mind that the wchar_t type is different on different platforms, so on
|
|
Windows, this will be equivalent to calling toUTF16(), on unix it'll be the same
|
|
as calling toUTF32(), etc.
|
|
|
|
@see getCharPointer, toUTF8, toUTF16, toUTF32
|
|
*/
|
|
const wchar_t* toWideCharPointer() 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 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 noexcept;
|
|
|
|
/** Copies the string to a buffer as UTF-8 characters.
|
|
|
|
Returns the number of bytes copied to the buffer, including the terminating null
|
|
character.
|
|
|
|
To find out how many bytes you need to store this string as UTF-8, you can call
|
|
CharPointer_UTF8::getBytesRequiredFor (myString.getCharPointer())
|
|
|
|
@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.
|
|
@see CharPointer_UTF8::writeWithDestByteLimit
|
|
*/
|
|
int copyToUTF8 (CharPointer_UTF8::CharType* destBuffer, int maxBufferSizeBytes) const noexcept;
|
|
|
|
/** Copies the string to a buffer as UTF-16 characters.
|
|
|
|
Returns the number of bytes copied to the buffer, including the terminating null
|
|
character.
|
|
|
|
To find out how many bytes you need to store this string as UTF-16, you can call
|
|
CharPointer_UTF16::getBytesRequiredFor (myString.getCharPointer())
|
|
|
|
@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.
|
|
@see CharPointer_UTF16::writeWithDestByteLimit
|
|
*/
|
|
int copyToUTF16 (CharPointer_UTF16::CharType* destBuffer, int maxBufferSizeBytes) const noexcept;
|
|
|
|
/** Copies the string to a buffer as UTF-16 characters.
|
|
|
|
Returns the number of bytes copied to the buffer, including the terminating null
|
|
character.
|
|
|
|
To find out how many bytes you need to store this string as UTF-32, you can call
|
|
CharPointer_UTF32::getBytesRequiredFor (myString.getCharPointer())
|
|
|
|
@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.
|
|
@see CharPointer_UTF32::writeWithDestByteLimit
|
|
*/
|
|
int copyToUTF32 (CharPointer_UTF32::CharType* destBuffer, int maxBufferSizeBytes) const noexcept;
|
|
|
|
/** 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 numBytesNeeded the number of bytes to allocate storage for. If this
|
|
value is less than the currently allocated size, it will
|
|
have no effect.
|
|
*/
|
|
void preallocateBytes (size_t numBytesNeeded);
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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);
|
|
};
|
|
|
|
#if JUCE_MAC || JUCE_IOS || DOXYGEN
|
|
|
|
/** MAC ONLY - Creates a String from an OSX CFString. */
|
|
static String fromCFString (CFStringRef cfString);
|
|
|
|
/** MAC ONLY - Converts this string to a CFString.
|
|
Remember that you must use CFRelease() to free the returned string when you're
|
|
finished with it.
|
|
*/
|
|
CFStringRef toCFString() const;
|
|
|
|
/** MAC ONLY - Returns a copy of this string in which any decomposed unicode characters have
|
|
been converted to their precomposed equivalents. */
|
|
String convertToPrecomposedUnicode() const;
|
|
#endif
|
|
|
|
private:
|
|
|
|
CharPointerType text;
|
|
|
|
struct PreallocationBytes
|
|
{
|
|
explicit PreallocationBytes (size_t);
|
|
size_t numBytes;
|
|
};
|
|
|
|
explicit String (const PreallocationBytes&); // This constructor preallocates a certain amount of memory
|
|
void appendFixedLength (const char* text, int numExtraChars);
|
|
size_t getByteOffsetOfEnd() const noexcept;
|
|
JUCE_DEPRECATED (String (const String& stringToCopy, size_t charsToAllocate));
|
|
|
|
// 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 noexcept { return false; }
|
|
};
|
|
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (const char* string1, const String& string2);
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (const wchar_t* string1, const String& string2);
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (char string1, const String& string2);
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (wchar_t string1, const String& string2);
|
|
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (juce_wchar string1, const String& string2);
|
|
#endif
|
|
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (String string1, const String& string2);
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (String string1, const char* string2);
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (String string1, const wchar_t* string2);
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (String string1, char characterToAppend);
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (String string1, wchar_t characterToAppend);
|
|
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
|
|
/** Concatenates two strings. */
|
|
JUCE_API String JUCE_CALLTYPE operator+ (String string1, juce_wchar characterToAppend);
|
|
#endif
|
|
|
|
/** 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, wchar_t characterToAppend);
|
|
#if ! JUCE_NATIVE_WCHAR_IS_UTF32
|
|
/** Appends a character at the end of a string. */
|
|
JUCE_API String& JUCE_CALLTYPE operator<< (String& string1, juce_wchar characterToAppend);
|
|
#endif
|
|
|
|
/** 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 wchar_t* 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, 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) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const char* string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const wchar_t* string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF8& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF16& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator== (const String& string1, const CharPointer_UTF32& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const String& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const char* string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const wchar_t* string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF8& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF16& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator!= (const String& string1, const CharPointer_UTF32& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator> (const String& string1, const String& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator< (const String& string1, const String& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator>= (const String& string1, const String& string2) noexcept;
|
|
/** Case-sensitive comparison of two strings. */
|
|
JUCE_API bool JUCE_CALLTYPE operator<= (const String& string1, const String& string2) noexcept;
|
|
|
|
/** This operator allows you to write a juce String directly to std output streams.
|
|
This is handy for writing strings to std::cout, std::cerr, etc.
|
|
*/
|
|
template <class traits>
|
|
std::basic_ostream <char, traits>& JUCE_CALLTYPE operator<< (std::basic_ostream <char, traits>& stream, const String& stringToWrite)
|
|
{
|
|
return stream << stringToWrite.toUTF8().getAddress();
|
|
}
|
|
|
|
/** This operator allows you to write a juce String directly to std output streams.
|
|
This is handy for writing strings to std::wcout, std::wcerr, etc.
|
|
*/
|
|
template <class traits>
|
|
std::basic_ostream <wchar_t, traits>& JUCE_CALLTYPE operator<< (std::basic_ostream <wchar_t, traits>& stream, const String& stringToWrite)
|
|
{
|
|
return stream << stringToWrite.toWideCharPointer();
|
|
}
|
|
|
|
/** Writes a string to an OutputStream as UTF8. */
|
|
JUCE_API OutputStream& JUCE_CALLTYPE operator<< (OutputStream& stream, const String& stringToWrite);
|
|
|
|
#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__
|
|
|
|
/**
|
|
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 OwnerClass>
|
|
class LeakedObjectDetector
|
|
{
|
|
public:
|
|
|
|
LeakedObjectDetector() noexcept { ++(getCounter().numObjects); }
|
|
LeakedObjectDetector (const LeakedObjectDetector&) noexcept { ++(getCounter().numObjects); }
|
|
|
|
~LeakedObjectDetector()
|
|
{
|
|
if (--(getCounter().numObjects) < 0)
|
|
{
|
|
DBG ("*** Dangling pointer deletion! Class: " << getLeakedObjectClassName());
|
|
|
|
/** 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() noexcept {}
|
|
|
|
~LeakCounter()
|
|
{
|
|
if (numObjects.value > 0)
|
|
{
|
|
DBG ("*** Leaked objects detected: " << numObjects.value << " instance(s) of class " << getLeakedObjectClassName());
|
|
|
|
/** 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<int> numObjects;
|
|
};
|
|
|
|
static const char* getLeakedObjectClassName()
|
|
{
|
|
return OwnerClass::getLeakedObjectClassName();
|
|
}
|
|
|
|
static LeakCounter& getCounter() noexcept
|
|
{
|
|
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) \
|
|
friend class JUCE_NAMESPACE::LeakedObjectDetector<OwnerClass>; \
|
|
static const char* getLeakedObjectClassName() noexcept { return #OwnerClass; } \
|
|
JUCE_NAMESPACE::LeakedObjectDetector<OwnerClass> JUCE_JOIN_MACRO (leakDetector, __LINE__);
|
|
#else
|
|
#define JUCE_LEAK_DETECTOR(OwnerClass)
|
|
#endif
|
|
#endif
|
|
|
|
#endif // __JUCE_LEAKEDOBJECTDETECTOR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_LeakedObjectDetector.h ***/
|
|
|
|
#undef TYPE_BOOL // (stupidly-named CoreServices definition which interferes with other libraries).
|
|
|
|
#if JUCE_MAC || JUCE_IOS || DOXYGEN
|
|
|
|
/** A handy C++ wrapper that creates and deletes an NSAutoreleasePool object using RAII. */
|
|
class JUCE_API ScopedAutoReleasePool
|
|
{
|
|
public:
|
|
ScopedAutoReleasePool();
|
|
~ScopedAutoReleasePool();
|
|
|
|
private:
|
|
void* pool;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (ScopedAutoReleasePool);
|
|
};
|
|
|
|
/** A macro that can be used to easily declare a local ScopedAutoReleasePool object for RAII-based obj-C autoreleasing. */
|
|
#define JUCE_AUTORELEASEPOOL const JUCE_NAMESPACE::ScopedAutoReleasePool JUCE_JOIN_MACRO (autoReleasePool_, __LINE__);
|
|
|
|
#else
|
|
#define JUCE_AUTORELEASEPOOL
|
|
#endif
|
|
|
|
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)
|
|
#ifdef __INTEL_COMPILER
|
|
#pragma warning (disable: 1125)
|
|
#endif
|
|
#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) noexcept;
|
|
|
|
/** Destructor */
|
|
~AbstractFifo();
|
|
|
|
/** Returns the total size of the buffer being managed. */
|
|
int getTotalSize() const noexcept;
|
|
|
|
/** Returns the number of items that can currently be added to the buffer without it overflowing. */
|
|
int getFreeSpace() const noexcept;
|
|
|
|
/** Returns the number of items that can currently be read from the buffer. */
|
|
int getNumReady() const noexcept;
|
|
|
|
/** Clears the buffer positions, so that it appears empty. */
|
|
void reset() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Called after reading from the FIFO, to indicate that this many items have been added.
|
|
@see prepareToWrite
|
|
*/
|
|
void finishedWrite (int numWritten) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Called after reading from the FIFO, to indicate that this many items have now been consumed.
|
|
@see prepareToRead
|
|
*/
|
|
void finishedRead (int numRead) noexcept;
|
|
|
|
private:
|
|
|
|
int bufferSize;
|
|
Atomic <int> 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<char> 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 <int> 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 ElementType>
|
|
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() noexcept : data (nullptr)
|
|
{
|
|
}
|
|
|
|
/** 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 <ElementType*> (::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 noexcept { 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 noexcept { 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 noexcept { return static_cast <void*> (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 noexcept { return static_cast <const void*> (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 noexcept { 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 <typename IndexType>
|
|
inline ElementType& operator[] (IndexType index) const noexcept { 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 <typename IndexType>
|
|
inline ElementType* operator+ (IndexType index) const noexcept { 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 noexcept { 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 noexcept { 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 <ElementType*> (::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 <ElementType*> (::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 <ElementType*> (::calloc (newNumElements, sizeof (ElementType)));
|
|
else
|
|
data = static_cast <ElementType*> (::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 == nullptr)
|
|
data = static_cast <ElementType*> (::malloc (newNumElements * elementSize));
|
|
else
|
|
data = static_cast <ElementType*> (::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 = nullptr;
|
|
}
|
|
|
|
/** Swaps this object's data with the data of another HeapBlock.
|
|
The two objects simply exchange their data pointers.
|
|
*/
|
|
void swapWith (HeapBlock <ElementType>& other) noexcept
|
|
{
|
|
std::swap (data, other.data);
|
|
}
|
|
|
|
/** This fills the block with zeros, up to the number of elements specified.
|
|
Since the block has no way of knowing its own size, you must make sure that the number of
|
|
elements you specify doesn't exceed the allocated size.
|
|
*/
|
|
void clear (size_t numElements) noexcept
|
|
{
|
|
zeromem (data, sizeof (ElementType) * numElements);
|
|
}
|
|
|
|
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 ElementType, class TypeOfCriticalSectionToUse>
|
|
class ArrayAllocationBase : public TypeOfCriticalSectionToUse
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty array. */
|
|
ArrayAllocationBase() noexcept
|
|
: 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 <ElementType, TypeOfCriticalSectionToUse>& other) noexcept
|
|
{
|
|
elements.swapWith (other.elements);
|
|
std::swap (numAllocated, other.numAllocated);
|
|
}
|
|
|
|
HeapBlock <ElementType> 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 <class ElementType, class ElementComparator>
|
|
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)
|
|
{
|
|
std::swap (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;
|
|
|
|
std::swap (array[j], array[maxIndex]);
|
|
--j;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
const int mid = firstElement + (size >> 1);
|
|
std::swap (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;
|
|
|
|
std::swap (array[i], array[j]);
|
|
}
|
|
|
|
std::swap (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 <class ElementType, class ElementComparator>
|
|
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 <int> myArray;
|
|
DefaultElementComparator<int> sorter;
|
|
myArray.sort (sorter);
|
|
@endcode
|
|
|
|
@see ElementComparator
|
|
*/
|
|
template <class ElementType>
|
|
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__
|
|
|
|
|
|
/*** Start of inlined file: juce_ScopedLock.h ***/
|
|
#ifndef __JUCE_SCOPEDLOCK_JUCEHEADER__
|
|
#define __JUCE_SCOPEDLOCK_JUCEHEADER__
|
|
|
|
/**
|
|
Automatically locks and unlocks a mutex object.
|
|
|
|
Use one of these as a local variable to provide RAII-based locking of a mutex.
|
|
|
|
The templated class could be a CriticalSection, SpinLock, or anything else that
|
|
provides enter() and exit() methods.
|
|
|
|
e.g. @code
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection);
|
|
// myCriticalSection is now locked
|
|
|
|
...do some stuff...
|
|
|
|
// myCriticalSection gets unlocked here.
|
|
}
|
|
@endcode
|
|
|
|
@see GenericScopedUnlock, CriticalSection, SpinLock, ScopedLock, ScopedUnlock
|
|
*/
|
|
template <class LockType>
|
|
class GenericScopedLock
|
|
{
|
|
public:
|
|
|
|
/** Creates a GenericScopedLock.
|
|
|
|
As soon as it is created, this will acquire the lock, and when the GenericScopedLock
|
|
object is deleted, the lock will be released.
|
|
|
|
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 GenericScopedLock (const LockType& lock) noexcept : lock_ (lock) { lock.enter(); }
|
|
|
|
/** Destructor.
|
|
The lock will be released 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 ~GenericScopedLock() noexcept { lock_.exit(); }
|
|
|
|
private:
|
|
|
|
const LockType& lock_;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (GenericScopedLock);
|
|
};
|
|
|
|
/**
|
|
Automatically unlocks and re-locks a mutex object.
|
|
|
|
This is the reverse of a GenericScopedLock object - instead of locking the mutex
|
|
for the lifetime of this object, it unlocks it.
|
|
|
|
Make sure you don't try to unlock mutexes that aren't actually locked!
|
|
|
|
e.g. @code
|
|
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const GenericScopedLock<CriticalSection> myScopedLock (myCriticalSection);
|
|
// myCriticalSection is now locked
|
|
|
|
... do some stuff with it locked ..
|
|
|
|
while (xyz)
|
|
{
|
|
... do some stuff with it locked ..
|
|
|
|
const GenericScopedUnlock<CriticalSection> 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 GenericScopedLock, CriticalSection, ScopedLock, ScopedUnlock
|
|
*/
|
|
template <class LockType>
|
|
class GenericScopedUnlock
|
|
{
|
|
public:
|
|
|
|
/** Creates a GenericScopedUnlock.
|
|
|
|
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 GenericScopedUnlock (const LockType& lock) noexcept : 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 ~GenericScopedUnlock() noexcept { lock_.enter(); }
|
|
|
|
private:
|
|
|
|
const LockType& lock_;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (GenericScopedUnlock);
|
|
};
|
|
|
|
/**
|
|
Automatically locks and unlocks a mutex object.
|
|
|
|
Use one of these as a local variable to provide RAII-based locking of a mutex.
|
|
|
|
The templated class could be a CriticalSection, SpinLock, or anything else that
|
|
provides enter() and exit() methods.
|
|
|
|
e.g. @code
|
|
|
|
CriticalSection myCriticalSection;
|
|
|
|
for (;;)
|
|
{
|
|
const GenericScopedTryLock<CriticalSection> 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, GenericScopedLock, GenericScopedUnlock
|
|
*/
|
|
template <class LockType>
|
|
class GenericScopedTryLock
|
|
{
|
|
public:
|
|
|
|
/** Creates a GenericScopedTryLock.
|
|
|
|
As soon as it is created, this will attempt to acquire the lock, and when the
|
|
GenericScopedTryLock is deleted, the lock will be released (if the lock was
|
|
successfully acquired).
|
|
|
|
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 GenericScopedTryLock (const LockType& lock) noexcept
|
|
: lock_ (lock), lockWasSuccessful (lock.tryEnter()) {}
|
|
|
|
/** Destructor.
|
|
|
|
The mutex will be unlocked (if it had been successfully 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 ~GenericScopedTryLock() noexcept { if (lockWasSuccessful) lock_.exit(); }
|
|
|
|
/** Returns true if the mutex was successfully locked. */
|
|
bool isLocked() const noexcept { return lockWasSuccessful; }
|
|
|
|
private:
|
|
|
|
const LockType& lock_;
|
|
const bool lockWasSuccessful;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (GenericScopedTryLock);
|
|
};
|
|
|
|
#endif // __JUCE_SCOPEDLOCK_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ScopedLock.h ***/
|
|
|
|
/**
|
|
A mutex class.
|
|
|
|
A CriticalSection acts as a re-entrant mutex lock. The best way to lock and unlock
|
|
one of these is by using RAII in the form of a local ScopedLock object - have a look
|
|
through the codebase for many examples of how to do this.
|
|
|
|
@see ScopedLock, ScopedTryLock, ScopedUnlock, SpinLock, ReadWriteLock, Thread, InterProcessLock
|
|
*/
|
|
class JUCE_API CriticalSection
|
|
{
|
|
public:
|
|
|
|
/** Creates a CriticalSection object. */
|
|
CriticalSection() noexcept;
|
|
|
|
/** Destructor.
|
|
If the critical section is deleted whilst locked, any subsequent behaviour
|
|
is unpredictable.
|
|
*/
|
|
~CriticalSection() noexcept;
|
|
|
|
/** Acquires the lock.
|
|
|
|
If the lock is already held by the caller thread, the method returns immediately.
|
|
If the lock is currently held by another thread, this will wait until it becomes free.
|
|
|
|
It's strongly recommended that you never call this method directly - instead use the
|
|
ScopedLock class to manage the locking using an RAII pattern instead.
|
|
|
|
@see exit, tryEnter, ScopedLock
|
|
*/
|
|
void enter() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Provides the type of scoped lock to use with a CriticalSection. */
|
|
typedef GenericScopedLock <CriticalSection> ScopedLockType;
|
|
|
|
/** Provides the type of scoped unlocker to use with a CriticalSection. */
|
|
typedef GenericScopedUnlock <CriticalSection> ScopedUnlockType;
|
|
|
|
/** Provides the type of scoped try-locker to use with a CriticalSection. */
|
|
typedef GenericScopedTryLock <CriticalSection> ScopedTryLockType;
|
|
|
|
private:
|
|
|
|
#if JUCE_WINDOWS
|
|
// To avoid including windows.h in the public JUCE headers, we'll just allocate a
|
|
// block of memory here that's big enough to be used internally as a windows critical
|
|
// section structure.
|
|
#if JUCE_64BIT
|
|
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, but which
|
|
doesn't perform any locking.
|
|
|
|
This is currently used by some templated classes, and most compilers should
|
|
manage to optimise it out of existence.
|
|
|
|
@see CriticalSection, Array, OwnedArray, ReferenceCountedArray
|
|
*/
|
|
class JUCE_API DummyCriticalSection
|
|
{
|
|
public:
|
|
inline DummyCriticalSection() noexcept {}
|
|
inline ~DummyCriticalSection() noexcept {}
|
|
|
|
inline void enter() const noexcept {}
|
|
inline bool tryEnter() const noexcept { return true; }
|
|
inline void exit() const noexcept {}
|
|
|
|
/** A dummy scoped-lock type to use with a dummy critical section. */
|
|
struct ScopedLockType
|
|
{
|
|
ScopedLockType (const DummyCriticalSection&) noexcept {}
|
|
};
|
|
|
|
/** A dummy scoped-unlocker type to use with a dummy critical section. */
|
|
typedef ScopedLockType ScopedUnlockType;
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE (DummyCriticalSection);
|
|
};
|
|
|
|
/**
|
|
Automatically locks and unlocks a CriticalSection object.
|
|
|
|
Use one of these as a local variable to provide RAII-based locking of 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
|
|
*/
|
|
typedef CriticalSection::ScopedLockType 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
|
|
*/
|
|
typedef CriticalSection::ScopedUnlockType ScopedUnlock;
|
|
|
|
/**
|
|
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
|
|
*/
|
|
typedef CriticalSection::ScopedTryLockType ScopedTryLock;
|
|
|
|
#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<int>, Array<Rectangle> or Array<MyClass*>
|
|
|
|
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 <MyClass*>, 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\<String\>, 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 <typename ElementType,
|
|
typename TypeOfCriticalSectionToUse = DummyCriticalSection>
|
|
class Array
|
|
{
|
|
private:
|
|
typedef PARAMETER_TYPE (ElementType) ParameterType;
|
|
|
|
public:
|
|
|
|
/** Creates an empty array. */
|
|
Array() noexcept
|
|
: numUsed (0)
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another array.
|
|
@param other the array to copy
|
|
*/
|
|
Array (const Array<ElementType, TypeOfCriticalSectionToUse>& 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 <typename TypeToCreateFrom>
|
|
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 <typename TypeToCreateFrom>
|
|
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<ElementType, TypeOfCriticalSectionToUse> 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 <class OtherArrayType>
|
|
bool operator== (const OtherArrayType& other) const
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
const typename OtherArrayType::ScopedLockType lock2 (other.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 <class OtherArrayType>
|
|
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 noexcept
|
|
{
|
|
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
|
|
*/
|
|
const 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 noexcept
|
|
{
|
|
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() noexcept
|
|
{
|
|
return data.elements;
|
|
}
|
|
|
|
/** Returns a pointer to the first element in the array.
|
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
|
*/
|
|
inline ElementType* begin() const noexcept
|
|
{
|
|
return data.elements;
|
|
}
|
|
|
|
/** Returns a pointer to the element which follows the last element in the array.
|
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
|
*/
|
|
inline ElementType* end() const noexcept
|
|
{
|
|
return data.elements + numUsed;
|
|
}
|
|
|
|
/** 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;
|
|
|
|
for (; e != end_; ++e)
|
|
if (elementToLookFor == *e)
|
|
return static_cast <int> (e - data.elements.getData());
|
|
|
|
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;
|
|
|
|
for (; e != end_; ++e)
|
|
if (elementToLookFor == *e)
|
|
return true;
|
|
|
|
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) noexcept
|
|
{
|
|
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 <class OtherArrayType>
|
|
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++));
|
|
}
|
|
}
|
|
|
|
/** This will enlarge or shrink the array to the given number of elements, by adding
|
|
or removing items from its end.
|
|
|
|
If the array is smaller than the given target size, empty elements will be appended
|
|
until its size is as specified. If its size is larger than the target, items will be
|
|
removed from its end to shorten it.
|
|
*/
|
|
void resize (const int targetNumItems)
|
|
{
|
|
jassert (targetNumItems >= 0);
|
|
|
|
const int numToAdd = targetNumItems - numUsed;
|
|
if (numToAdd > 0)
|
|
insertMultiple (numUsed, ElementType(), numToAdd);
|
|
else if (numToAdd < 0)
|
|
removeRange (targetNumItems, -numToAdd);
|
|
}
|
|
|
|
/** 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
|
|
@returns the index at which the new item was added
|
|
@see addUsingDefaultSort, add, sort
|
|
*/
|
|
template <class ElementComparator>
|
|
int addSorted (ElementComparator& comparator, ParameterType newElement)
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newElement, 0, numUsed);
|
|
insert (index, newElement);
|
|
return index;
|
|
}
|
|
|
|
/** 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 <ElementType> 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 <class ElementComparator>
|
|
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* const e = data.elements;
|
|
|
|
for (int i = 0; i < numUsed; ++i)
|
|
{
|
|
if (valueToRemove == e[i])
|
|
{
|
|
remove (i);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** 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 <class OtherArrayType>
|
|
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 <class OtherArrayType>
|
|
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) noexcept
|
|
{
|
|
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 <class ElementComparator>
|
|
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 noexcept { return data; }
|
|
|
|
/** Returns the type of scoped lock to use for locking this array */
|
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
|
|
|
private:
|
|
|
|
ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse> 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__
|
|
|
|
class StringPool;
|
|
|
|
/**
|
|
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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Creates a copy of another identifier. */
|
|
Identifier& operator= (const Identifier& other) noexcept;
|
|
|
|
/** Destructor */
|
|
~Identifier();
|
|
|
|
/** Compares two identifiers. This is a very fast operation. */
|
|
inline bool operator== (const Identifier& other) const noexcept { return name == other.name; }
|
|
|
|
/** Compares two identifiers. This is a very fast operation. */
|
|
inline bool operator!= (const Identifier& other) const noexcept { return name != other.name; }
|
|
|
|
/** Returns this identifier as a string. */
|
|
String toString() const { return name; }
|
|
|
|
/** Returns this identifier's raw string pointer. */
|
|
operator const String::CharPointerType() const noexcept { return name; }
|
|
|
|
/** Checks a given string for characters that might not be valid in an Identifier.
|
|
Since Identifiers are used as a script variables and XML attributes, they should only contain
|
|
alphanumeric characters, underscores, or the '-' and ':' characters.
|
|
*/
|
|
static bool isValidIdentifier (const String& possibleIdentifier) noexcept;
|
|
|
|
private:
|
|
|
|
String::CharPointerType 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() noexcept { return "\r\n"; }
|
|
|
|
/** Returns the default new-line sequence that the library uses.
|
|
@see getDefault()
|
|
*/
|
|
operator String() const { return getDefault(); }
|
|
};
|
|
|
|
/** A 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 ***/
|
|
|
|
class InputStream;
|
|
class MemoryBlock;
|
|
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 byte to the output stream a given number of times. */
|
|
virtual void writeRepeatedByte (uint8 byte, int numTimesToRepeat);
|
|
|
|
/** 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 the text as UTF-8 or UTF-16, and can also add the UTF-16 byte-order-mark
|
|
bytes (0xff, 0xfe) to indicate the endianness (these should only be used 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 asUTF16,
|
|
bool writeUTF16ByteOrderMark);
|
|
|
|
/** 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 noexcept { 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 ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_InputStream.h ***/
|
|
#ifndef __JUCE_INPUTSTREAM_JUCEHEADER__
|
|
#define __JUCE_INPUTSTREAM_JUCEHEADER__
|
|
|
|
class MemoryBlock;
|
|
|
|
/** 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 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 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 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() noexcept {}
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InputStream);
|
|
};
|
|
|
|
#endif // __JUCE_INPUTSTREAM_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_InputStream.h ***/
|
|
|
|
#ifndef DOXYGEN
|
|
class ReferenceCountedObject;
|
|
class 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
|
|
any kind of ReferenceCountedObject. The var class is intended to act like
|
|
the kind of values used in dynamic scripting languages.
|
|
|
|
You can save/load var objects either in a small, proprietary binary format
|
|
using writeToStream()/readFromStream(), or as JSON by using the JSON class.
|
|
|
|
@see JSON, DynamicObject
|
|
*/
|
|
class JUCE_API var
|
|
{
|
|
public:
|
|
|
|
typedef const var (DynamicObject::*MethodFunction) (const var* arguments, int numArguments);
|
|
typedef Identifier identifier;
|
|
|
|
/** Creates a void variant. */
|
|
var() noexcept;
|
|
|
|
/** Destructor. */
|
|
~var() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
var (int64 value) noexcept;
|
|
var (bool value) noexcept;
|
|
var (double value) noexcept;
|
|
var (const char* value);
|
|
var (const wchar_t* value);
|
|
var (const String& value);
|
|
var (const Array<var>& value);
|
|
var (ReferenceCountedObject* object);
|
|
var (MethodFunction method) noexcept;
|
|
|
|
const var& operator= (const var& valueToCopy);
|
|
const var& operator= (int value);
|
|
const var& operator= (int64 value);
|
|
const var& operator= (bool value);
|
|
const var& operator= (double value);
|
|
const var& operator= (const char* value);
|
|
const var& operator= (const wchar_t* value);
|
|
const var& operator= (const String& value);
|
|
const var& operator= (const Array<var>& value);
|
|
const var& operator= (ReferenceCountedObject* object);
|
|
const var& operator= (MethodFunction method);
|
|
|
|
void swapWith (var& other) noexcept;
|
|
|
|
operator int() const noexcept;
|
|
operator int64() const noexcept;
|
|
operator bool() const noexcept;
|
|
operator float() const noexcept;
|
|
operator double() const noexcept;
|
|
operator String() const;
|
|
String toString() const;
|
|
Array<var>* getArray() const noexcept;
|
|
ReferenceCountedObject* getObject() const noexcept;
|
|
DynamicObject* getDynamicObject() const noexcept;
|
|
|
|
bool isVoid() const noexcept;
|
|
bool isInt() const noexcept;
|
|
bool isInt64() const noexcept;
|
|
bool isBool() const noexcept;
|
|
bool isDouble() const noexcept;
|
|
bool isString() const noexcept;
|
|
bool isObject() const noexcept;
|
|
bool isArray() const noexcept;
|
|
bool isMethod() const noexcept;
|
|
|
|
/** Returns true if this var has the same value as the one supplied.
|
|
Note that this ignores the type, so a string var "123" and an integer var with the
|
|
value 123 are considered to be equal.
|
|
@see equalsWithSameType
|
|
*/
|
|
bool equals (const var& other) const noexcept;
|
|
|
|
/** Returns true if this var has the same value and type as the one supplied.
|
|
This differs from equals() because e.g. "123" and 123 will be considered different.
|
|
@see equals
|
|
*/
|
|
bool equalsWithSameType (const var& other) const noexcept;
|
|
|
|
/** If the var is an array, this returns the number of elements.
|
|
If the var isn't actually an array, this will return 0.
|
|
*/
|
|
int size() const;
|
|
|
|
/** If the var is an array, this can be used to return one of its elements.
|
|
To call this method, you must make sure that the var is actually an array, and
|
|
that the index is a valid number. If these conditions aren't met, behaviour is
|
|
undefined.
|
|
For more control over the array's contents, you can call getArray() and manipulate
|
|
it directly as an Array\<var\>.
|
|
*/
|
|
const var& operator[] (int arrayIndex) const;
|
|
|
|
/** If the var is an array, this can be used to return one of its elements.
|
|
To call this method, you must make sure that the var is actually an array, and
|
|
that the index is a valid number. If these conditions aren't met, behaviour is
|
|
undefined.
|
|
For more control over the array's contents, you can call getArray() and manipulate
|
|
it directly as an Array\<var\>.
|
|
*/
|
|
var& operator[] (int arrayIndex);
|
|
|
|
/** Appends an element to the var, converting it to an array if it isn't already one.
|
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
|
this value will be kept as the first element of the new array. The parameter value
|
|
will then be appended to it.
|
|
For more control over the array's contents, you can call getArray() and manipulate
|
|
it directly as an Array\<var\>.
|
|
*/
|
|
void append (const var& valueToAppend);
|
|
|
|
/** Inserts an element to the var, converting it to an array if it isn't already one.
|
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
|
this value will be kept as the first element of the new array. The parameter value
|
|
will then be inserted into it.
|
|
For more control over the array's contents, you can call getArray() and manipulate
|
|
it directly as an Array\<var\>.
|
|
*/
|
|
void insert (int index, const var& value);
|
|
|
|
/** If the var is an array, this removes one of its elements.
|
|
If the index is out-of-range or the var isn't an array, nothing will be done.
|
|
For more control over the array's contents, you can call getArray() and manipulate
|
|
it directly as an Array\<var\>.
|
|
*/
|
|
void remove (int index);
|
|
|
|
/** Treating the var as an array, this resizes it to contain the specified number of elements.
|
|
If the var isn't an array, it will be converted to one, and if its value was non-void,
|
|
this value will be kept as the first element of the new array before resizing.
|
|
For more control over the array's contents, you can call getArray() and manipulate
|
|
it directly as an Array\<var\>.
|
|
*/
|
|
void resize (int numArrayElementsWanted);
|
|
|
|
/** If the var is an array, this searches it for the first occurrence of the specified value,
|
|
and returns its index.
|
|
If the var isn't an array, or if the value isn't found, this returns -1.
|
|
*/
|
|
int indexOf (const var& value) const;
|
|
|
|
/** If this variant is an object, this returns one of its properties. */
|
|
var operator[] (const Identifier& propertyName) const;
|
|
/** If this variant is an object, this returns one of its properties. */
|
|
var operator[] (const char* propertyName) const;
|
|
/** If this variant is an object, this returns one of its properties, or a default
|
|
fallback value if the property is not set. */
|
|
var getProperty (const Identifier& propertyName, const var& defaultReturnValue) const;
|
|
|
|
/** If this variant is an object, this invokes one of its methods with no arguments. */
|
|
var call (const Identifier& method) const;
|
|
/** If this variant is an object, this invokes one of its methods with one argument. */
|
|
var call (const Identifier& method, const var& arg1) const;
|
|
/** If this variant is an object, this invokes one of its methods with 2 arguments. */
|
|
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. */
|
|
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. */
|
|
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. */
|
|
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. */
|
|
var invoke (const Identifier& method, const var* arguments, int numArguments) const;
|
|
|
|
/** Writes a binary representation of this value to a stream.
|
|
The data can be read back later using readFromStream().
|
|
@see JSON
|
|
*/
|
|
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.
|
|
@see JSON
|
|
*/
|
|
static var readFromStream (InputStream& input);
|
|
|
|
private:
|
|
|
|
class VariantType; friend class VariantType;
|
|
class VariantType_Void; friend class VariantType_Void;
|
|
class VariantType_Int; friend class VariantType_Int;
|
|
class VariantType_Int64; friend class VariantType_Int64;
|
|
class VariantType_Double; friend class VariantType_Double;
|
|
class VariantType_Bool; friend class VariantType_Bool;
|
|
class VariantType_String; friend class VariantType_String;
|
|
class VariantType_Object; friend class VariantType_Object;
|
|
class VariantType_Array; friend class VariantType_Array;
|
|
class VariantType_Method; friend class VariantType_Method;
|
|
|
|
union ValueUnion
|
|
{
|
|
int intValue;
|
|
int64 int64Value;
|
|
bool boolValue;
|
|
double doubleValue;
|
|
char stringValue [sizeof (String)];
|
|
ReferenceCountedObject* objectValue;
|
|
Array<var>* arrayValue;
|
|
MethodFunction methodValue;
|
|
};
|
|
|
|
const VariantType* type;
|
|
ValueUnion value;
|
|
|
|
Array<var>* convertToArray();
|
|
friend class DynamicObject;
|
|
var invokeMethod (DynamicObject*, const var*, int) const;
|
|
};
|
|
|
|
/** Compares the values of two var objects, using the var::equals() comparison. */
|
|
bool operator== (const var& v1, const var& v2) noexcept;
|
|
/** Compares the values of two var objects, using the var::equals() comparison. */
|
|
bool operator!= (const var& v1, const var& v2) noexcept;
|
|
bool operator== (const var& v1, const String& v2);
|
|
bool operator!= (const var& v1, const String& v2);
|
|
bool operator== (const var& v1, const char* v2);
|
|
bool operator!= (const var& v1, const char* v2);
|
|
|
|
#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<MyObject> instead).
|
|
LinkedListPointer<MyObject> nextListItem;
|
|
};
|
|
|
|
LinkedListPointer<MyObject> myList;
|
|
myList.append (new MyObject());
|
|
myList.append (new MyObject());
|
|
|
|
int numItems = myList.size(); // returns 2
|
|
MyObject* lastInList = myList.getLast();
|
|
@endcode
|
|
*/
|
|
template <class ObjectType>
|
|
class LinkedListPointer
|
|
{
|
|
public:
|
|
|
|
/** Creates a null pointer to an empty list. */
|
|
LinkedListPointer() noexcept
|
|
: item (nullptr)
|
|
{
|
|
}
|
|
|
|
/** Creates a pointer to a list whose head is the item provided. */
|
|
explicit LinkedListPointer (ObjectType* const headItem) noexcept
|
|
: item (headItem)
|
|
{
|
|
}
|
|
|
|
/** Sets this pointer to point to a new list. */
|
|
LinkedListPointer& operator= (ObjectType* const newItem) noexcept
|
|
{
|
|
item = newItem;
|
|
return *this;
|
|
}
|
|
|
|
/** Returns the item which this pointer points to. */
|
|
inline operator ObjectType*() const noexcept
|
|
{
|
|
return item;
|
|
}
|
|
|
|
/** Returns the item which this pointer points to. */
|
|
inline ObjectType* get() const noexcept
|
|
{
|
|
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() noexcept
|
|
{
|
|
LinkedListPointer* l = this;
|
|
|
|
while (l->item != nullptr)
|
|
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 noexcept
|
|
{
|
|
int total = 0;
|
|
|
|
for (ObjectType* i = item; i != nullptr; 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) noexcept
|
|
{
|
|
LinkedListPointer* l = this;
|
|
|
|
while (--index >= 0 && l->item != nullptr)
|
|
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 noexcept
|
|
{
|
|
const LinkedListPointer* l = this;
|
|
|
|
while (--index >= 0 && l->item != nullptr)
|
|
l = &(l->item->nextListItem);
|
|
|
|
return *l;
|
|
}
|
|
|
|
/** Returns true if the list contains the given item. */
|
|
bool contains (const ObjectType* const itemToLookFor) const noexcept
|
|
{
|
|
for (ObjectType* i = item; i != nullptr; 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 != nullptr);
|
|
jassert (newItem->nextListItem == nullptr);
|
|
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 != nullptr);
|
|
LinkedListPointer* l = this;
|
|
|
|
while (index != 0 && l->item != nullptr)
|
|
{
|
|
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) noexcept
|
|
{
|
|
jassert (newItem != nullptr);
|
|
jassert (newItem->nextListItem == nullptr);
|
|
|
|
ObjectType* const oldItem = item;
|
|
item = newItem;
|
|
item->nextListItem = oldItem->nextListItem.item;
|
|
oldItem->nextListItem = (ObjectType*) 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 != nullptr; 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() noexcept
|
|
{
|
|
ObjectType* const oldItem = item;
|
|
|
|
if (oldItem != nullptr)
|
|
{
|
|
item = oldItem->nextListItem;
|
|
oldItem->nextListItem = (ObjectType*) 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 != nullptr)
|
|
l->removeNext();
|
|
}
|
|
|
|
/** Iterates the list, calling the delete operator on all of its elements and
|
|
leaving this pointer empty.
|
|
*/
|
|
void deleteAll()
|
|
{
|
|
while (item != nullptr)
|
|
{
|
|
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) noexcept
|
|
{
|
|
LinkedListPointer* l = this;
|
|
|
|
while (l->item != nullptr)
|
|
{
|
|
if (l->item == itemToLookFor)
|
|
return l;
|
|
|
|
l = &(l->item->nextListItem);
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
jassert (destArray != nullptr);
|
|
|
|
for (ObjectType* i = item; i != nullptr; 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) noexcept
|
|
: endOfList (&endOfListPointer)
|
|
{
|
|
// This can only be used to add to the end of a list.
|
|
jassert (endOfListPointer.item == nullptr);
|
|
}
|
|
|
|
/** Appends an item to the list. */
|
|
void append (ObjectType* const newItem) noexcept
|
|
{
|
|
*endOfList = newItem;
|
|
endOfList = &(newItem->nextListItem);
|
|
}
|
|
|
|
private:
|
|
LinkedListPointer* endOfList;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (Appender);
|
|
};
|
|
|
|
private:
|
|
|
|
ObjectType* item;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (LinkedListPointer);
|
|
};
|
|
|
|
#endif // __JUCE_LINKEDLISTPOINTER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_LinkedListPointer.h ***/
|
|
|
|
class XmlElement;
|
|
#ifndef DOXYGEN
|
|
class JSONFormatter;
|
|
#endif
|
|
|
|
/** 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() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
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 noexcept;
|
|
|
|
/** 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() noexcept;
|
|
NamedValue (const NamedValue&);
|
|
NamedValue (const Identifier& name, const var& value);
|
|
NamedValue& operator= (const NamedValue&);
|
|
bool operator== (const NamedValue& other) const noexcept;
|
|
|
|
LinkedListPointer<NamedValue> nextListItem;
|
|
Identifier name;
|
|
var value;
|
|
|
|
private:
|
|
JUCE_LEAK_DETECTOR (NamedValue);
|
|
};
|
|
|
|
friend class LinkedListPointer<NamedValue>;
|
|
LinkedListPointer<NamedValue> values;
|
|
|
|
friend class JSONFormatter;
|
|
};
|
|
|
|
#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<MyClass> Ptr;
|
|
};
|
|
|
|
MyClass::Ptr p = new MyClass();
|
|
MyClass::Ptr p2 = p;
|
|
p = nullptr;
|
|
p2->foo();
|
|
@endcode
|
|
|
|
Once a new ReferenceCountedObject has been assigned to a pointer, be
|
|
careful not to delete the object manually.
|
|
|
|
This class uses an Atomic<int> value to hold the reference count, so that it
|
|
the pointers can be passed between threads safely. For a faster but non-thread-safe
|
|
version, use SingleThreadedReferenceCountedObject instead.
|
|
|
|
@see ReferenceCountedObjectPtr, ReferenceCountedArray, SingleThreadedReferenceCountedObject
|
|
*/
|
|
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() noexcept
|
|
{
|
|
++refCount;
|
|
}
|
|
|
|
/** Decreases the object's reference count.
|
|
|
|
If the count gets to zero, the object will be deleted.
|
|
*/
|
|
inline void decReferenceCount() noexcept
|
|
{
|
|
jassert (getReferenceCount() > 0);
|
|
|
|
if (--refCount == 0)
|
|
delete this;
|
|
}
|
|
|
|
/** Returns the object's current reference count. */
|
|
inline int getReferenceCount() const noexcept { 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 <int> refCount;
|
|
};
|
|
|
|
/**
|
|
Adds reference-counting to an object.
|
|
|
|
This is efectively a version of the ReferenceCountedObject class, but which
|
|
uses a non-atomic counter, and so is not thread-safe (but which will be more
|
|
efficient).
|
|
For more details on how to use it, see the ReferenceCountedObject class notes.
|
|
|
|
@see ReferenceCountedObject, ReferenceCountedObjectPtr, ReferenceCountedArray
|
|
*/
|
|
class JUCE_API SingleThreadedReferenceCountedObject
|
|
{
|
|
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() noexcept
|
|
{
|
|
++refCount;
|
|
}
|
|
|
|
/** Decreases the object's reference count.
|
|
|
|
If the count gets to zero, the object will be deleted.
|
|
*/
|
|
inline void decReferenceCount() noexcept
|
|
{
|
|
jassert (getReferenceCount() > 0);
|
|
|
|
if (--refCount == 0)
|
|
delete this;
|
|
}
|
|
|
|
/** Returns the object's current reference count. */
|
|
inline int getReferenceCount() const noexcept { return refCount; }
|
|
|
|
protected:
|
|
|
|
/** Creates the reference-counted object (with an initial ref count of zero). */
|
|
SingleThreadedReferenceCountedObject() : refCount (0) {}
|
|
|
|
/** Destructor. */
|
|
virtual ~SingleThreadedReferenceCountedObject()
|
|
{
|
|
// it's dangerous to delete an object that's still referenced by something else!
|
|
jassert (getReferenceCount() == 0);
|
|
}
|
|
|
|
private:
|
|
|
|
int refCount;
|
|
};
|
|
|
|
/**
|
|
A smart-pointer class which points to a reference-counted object.
|
|
|
|
The template parameter specifies the class of the object you want to point to - the easiest
|
|
way to make a class reference-countable is to simply make it inherit from ReferenceCountedObject,
|
|
but if you need to, you could roll your own reference-countable class by implementing a pair of
|
|
mathods called incReferenceCount() and decReferenceCount().
|
|
|
|
When using this class, you'll probably want to create a typedef to abbreviate the full
|
|
templated name - e.g.
|
|
@code typedef ReferenceCountedObjectPtr<MyClass> MyClassPtr;@endcode
|
|
|
|
@see ReferenceCountedObject, ReferenceCountedObjectArray
|
|
*/
|
|
template <class ReferenceCountedObjectClass>
|
|
class ReferenceCountedObjectPtr
|
|
{
|
|
public:
|
|
/** The class being referenced by this pointer. */
|
|
typedef ReferenceCountedObjectClass ReferencedType;
|
|
|
|
/** Creates a pointer to a null object. */
|
|
inline ReferenceCountedObjectPtr() noexcept
|
|
: referencedObject (nullptr)
|
|
{
|
|
}
|
|
|
|
/** Creates a pointer to an object.
|
|
|
|
This will increment the object's reference-count if it is non-null.
|
|
*/
|
|
inline ReferenceCountedObjectPtr (ReferenceCountedObjectClass* const refCountedObject) noexcept
|
|
: referencedObject (refCountedObject)
|
|
{
|
|
if (refCountedObject != nullptr)
|
|
refCountedObject->incReferenceCount();
|
|
}
|
|
|
|
/** Copies another pointer.
|
|
|
|
This will increment the object's reference-count (if it is non-null).
|
|
*/
|
|
inline ReferenceCountedObjectPtr (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& other) noexcept
|
|
: referencedObject (other.referencedObject)
|
|
{
|
|
if (referencedObject != nullptr)
|
|
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<ReferenceCountedObjectClass>& operator= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& other)
|
|
{
|
|
ReferenceCountedObjectClass* const newObject = other.referencedObject;
|
|
|
|
if (newObject != referencedObject)
|
|
{
|
|
if (newObject != nullptr)
|
|
newObject->incReferenceCount();
|
|
|
|
ReferenceCountedObjectClass* const oldObject = referencedObject;
|
|
referencedObject = newObject;
|
|
|
|
if (oldObject != nullptr)
|
|
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<ReferenceCountedObjectClass>& operator= (ReferenceCountedObjectClass* const newObject)
|
|
{
|
|
if (referencedObject != newObject)
|
|
{
|
|
if (newObject != nullptr)
|
|
newObject->incReferenceCount();
|
|
|
|
ReferenceCountedObjectClass* const oldObject = referencedObject;
|
|
referencedObject = newObject;
|
|
|
|
if (oldObject != nullptr)
|
|
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 != nullptr)
|
|
referencedObject->decReferenceCount();
|
|
}
|
|
|
|
/** Returns the object that this pointer references.
|
|
The pointer returned may be zero, of course.
|
|
*/
|
|
inline operator ReferenceCountedObjectClass*() const noexcept
|
|
{
|
|
return referencedObject;
|
|
}
|
|
|
|
// the -> operator is called on the referenced object
|
|
inline ReferenceCountedObjectClass* operator->() const noexcept
|
|
{
|
|
return referencedObject;
|
|
}
|
|
|
|
/** Returns the object that this pointer references.
|
|
The pointer returned may be zero, of course.
|
|
*/
|
|
inline ReferenceCountedObjectClass* getObject() const noexcept
|
|
{
|
|
return referencedObject;
|
|
}
|
|
|
|
private:
|
|
|
|
ReferenceCountedObjectClass* referencedObject;
|
|
};
|
|
|
|
/** Compares two ReferenceCountedObjectPointers. */
|
|
template <class ReferenceCountedObjectClass>
|
|
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectClass* const object2) noexcept
|
|
{
|
|
return object1.getObject() == object2;
|
|
}
|
|
|
|
/** Compares two ReferenceCountedObjectPointers. */
|
|
template <class ReferenceCountedObjectClass>
|
|
bool operator== (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
|
{
|
|
return object1.getObject() == object2.getObject();
|
|
}
|
|
|
|
/** Compares two ReferenceCountedObjectPointers. */
|
|
template <class ReferenceCountedObjectClass>
|
|
bool operator== (ReferenceCountedObjectClass* object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
|
{
|
|
return object1 == object2.getObject();
|
|
}
|
|
|
|
/** Compares two ReferenceCountedObjectPointers. */
|
|
template <class ReferenceCountedObjectClass>
|
|
bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, const ReferenceCountedObjectClass* object2) noexcept
|
|
{
|
|
return object1.getObject() != object2;
|
|
}
|
|
|
|
/** Compares two ReferenceCountedObjectPointers. */
|
|
template <class ReferenceCountedObjectClass>
|
|
bool operator!= (const ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
|
{
|
|
return object1.getObject() != object2.getObject();
|
|
}
|
|
|
|
/** Compares two ReferenceCountedObjectPointers. */
|
|
template <class ReferenceCountedObjectClass>
|
|
bool operator!= (ReferenceCountedObjectClass* object1, ReferenceCountedObjectPtr<ReferenceCountedObjectClass>& object2) noexcept
|
|
{
|
|
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 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 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();
|
|
|
|
/** Returns the NamedValueSet that holds the object's properties. */
|
|
NamedValueSet& getProperties() noexcept { return properties; }
|
|
|
|
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_HASHMAP_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_HashMap.h ***/
|
|
#ifndef __JUCE_HASHMAP_JUCEHEADER__
|
|
#define __JUCE_HASHMAP_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<MyObjectClass>
|
|
|
|
..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 ObjectClass,
|
|
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
|
|
|
class OwnedArray
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty array. */
|
|
OwnedArray() noexcept
|
|
: 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 noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
|
|
: static_cast <ObjectClass*> (nullptr);
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
return numUsed > 0 ? data.elements [0]
|
|
: static_cast <ObjectClass*> (nullptr);
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
return numUsed > 0 ? data.elements [numUsed - 1]
|
|
: static_cast <ObjectClass*> (nullptr);
|
|
}
|
|
|
|
/** 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() noexcept
|
|
{
|
|
return data.elements;
|
|
}
|
|
|
|
/** Returns a pointer to the first element in the array.
|
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
|
*/
|
|
inline ObjectClass** begin() const noexcept
|
|
{
|
|
return data.elements;
|
|
}
|
|
|
|
/** Returns a pointer to the element which follows the last element in the array.
|
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
|
*/
|
|
inline ObjectClass** end() const noexcept
|
|
{
|
|
return data.elements + numUsed;
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
ObjectClass* const* e = data.elements.getData();
|
|
ObjectClass* const* const end_ = e + numUsed;
|
|
|
|
for (; e != end_; ++e)
|
|
if (objectToLookFor == *e)
|
|
return static_cast <int> (e - data.elements.getData());
|
|
|
|
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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
ObjectClass* const* e = data.elements.getData();
|
|
ObjectClass* const* const end_ = e + numUsed;
|
|
|
|
for (; e != end_; ++e)
|
|
if (objectToLookFor == *e)
|
|
return true;
|
|
|
|
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) noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
data.ensureAllocatedSize (numUsed + 1);
|
|
data.elements [numUsed++] = const_cast <ObjectClass*> (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) noexcept
|
|
{
|
|
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 <ObjectClass*> (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) noexcept
|
|
{
|
|
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 = nullptr;
|
|
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
|
|
if (indexToChange < numUsed)
|
|
{
|
|
if (deleteOldElement)
|
|
{
|
|
toDelete = data.elements [indexToChange];
|
|
|
|
if (toDelete == newObject)
|
|
toDelete = nullptr;
|
|
}
|
|
|
|
data.elements [indexToChange] = const_cast <ObjectClass*> (newObject);
|
|
}
|
|
else
|
|
{
|
|
data.ensureAllocatedSize (numUsed + 1);
|
|
data.elements [numUsed++] = const_cast <ObjectClass*> (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 <class OtherArrayType>
|
|
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 <class OtherArrayType>
|
|
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
|
|
@returns the index at which the new object was added
|
|
@see add, sort, indexOfSorted
|
|
*/
|
|
template <class ElementComparator>
|
|
int addSorted (ElementComparator& comparator, ObjectClass* const newObject) noexcept
|
|
{
|
|
(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());
|
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
|
insert (index, newObject);
|
|
return index;
|
|
}
|
|
|
|
/** 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 <class ElementComparator>
|
|
int indexOfSorted (ElementComparator& comparator,
|
|
const ObjectClass* const objectToLookFor) const noexcept
|
|
{
|
|
(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 = nullptr;
|
|
|
|
{
|
|
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 = nullptr;
|
|
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** const e = data.elements.getData();
|
|
|
|
for (int i = 0; i < numUsed; ++i)
|
|
{
|
|
if (objectToRemove == e[i])
|
|
{
|
|
remove (i, deleteObject);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** 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] = nullptr; // (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) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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() noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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 <class ElementComparator>
|
|
void sort (ElementComparator& comparator,
|
|
const bool retainOrderOfEquivalentItems = false) const noexcept
|
|
{
|
|
(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 noexcept { return data; }
|
|
|
|
/** Returns the type of scoped lock to use for locking this array */
|
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
|
|
|
private:
|
|
|
|
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
|
|
int numUsed;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OwnedArray);
|
|
};
|
|
|
|
#endif // __JUCE_OWNEDARRAY_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_OwnedArray.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 ObjectType>
|
|
class ScopedPointer
|
|
{
|
|
public:
|
|
|
|
/** Creates a ScopedPointer containing a null pointer. */
|
|
inline ScopedPointer() noexcept : object (nullptr)
|
|
{
|
|
}
|
|
|
|
/** Creates a ScopedPointer that owns the specified object. */
|
|
inline ScopedPointer (ObjectType* const objectToTakePossessionOf) noexcept
|
|
: 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) noexcept
|
|
: object (objectToTransferFrom.object)
|
|
{
|
|
objectToTransferFrom.object = nullptr;
|
|
}
|
|
|
|
/** 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 == nullptr || object != objectToTransferFrom.object);
|
|
|
|
ObjectType* const oldObject = object;
|
|
object = objectToTransferFrom.object;
|
|
objectToTransferFrom.object = nullptr;
|
|
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 noexcept { return object; }
|
|
|
|
/** Returns the object that this ScopedPointer refers to. */
|
|
inline ObjectType& operator*() const noexcept { return *object; }
|
|
|
|
/** Lets you access methods and properties of the object that this ScopedPointer refers to. */
|
|
inline ObjectType* operator->() const noexcept { 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() noexcept { ObjectType* const o = object; object = nullptr; return o; }
|
|
|
|
/** Swaps this object with that of another ScopedPointer.
|
|
The two objects simply exchange their pointers.
|
|
*/
|
|
void swapWith (ScopedPointer <ObjectType>& other) noexcept
|
|
{
|
|
// 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);
|
|
|
|
std::swap (object, other.object);
|
|
}
|
|
|
|
private:
|
|
|
|
ObjectType* object;
|
|
|
|
// (Required as an alternative to the overloaded & operator).
|
|
const ScopedPointer* getAddress() const noexcept { 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<MyClass> 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<MyClass> 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 <class ObjectType>
|
|
bool operator== (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
|
{
|
|
return static_cast <ObjectType*> (pointer1) == pointer2;
|
|
}
|
|
|
|
/** Compares a ScopedPointer with another pointer.
|
|
This can be handy for checking whether this is a null pointer.
|
|
*/
|
|
template <class ObjectType>
|
|
bool operator!= (const ScopedPointer<ObjectType>& pointer1, ObjectType* const pointer2) noexcept
|
|
{
|
|
return static_cast <ObjectType*> (pointer1) != pointer2;
|
|
}
|
|
|
|
#endif // __JUCE_SCOPEDPOINTER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ScopedPointer.h ***/
|
|
|
|
/**
|
|
A simple class to generate hash functions for some primitive types, intended for
|
|
use with the HashMap class.
|
|
@see HashMap
|
|
*/
|
|
class DefaultHashFunctions
|
|
{
|
|
public:
|
|
/** Generates a simple hash from an integer. */
|
|
static int generateHash (const int key, const int upperLimit) noexcept { return std::abs (key) % upperLimit; }
|
|
/** Generates a simple hash from a string. */
|
|
static int generateHash (const String& key, const int upperLimit) noexcept { return (int) (((uint32) key.hashCode()) % upperLimit); }
|
|
/** Generates a simple hash from a variant. */
|
|
static int generateHash (const var& key, const int upperLimit) noexcept { return generateHash (key.toString(), upperLimit); }
|
|
};
|
|
|
|
/**
|
|
Holds a set of mappings between some key/value pairs.
|
|
|
|
The types of the key and value objects are set as template parameters.
|
|
You can also specify a class to supply a hash function that converts a key value
|
|
into an hashed integer. This class must have the form:
|
|
|
|
@code
|
|
struct MyHashGenerator
|
|
{
|
|
static int generateHash (MyKeyType key, int upperLimit)
|
|
{
|
|
// The function must return a value 0 <= x < upperLimit
|
|
return someFunctionOfMyKeyType (key) % upperLimit;
|
|
}
|
|
};
|
|
@endcode
|
|
|
|
Like the Array class, the key and value types are expected to be copy-by-value types, so
|
|
if you define them to be pointer types, this class won't delete the objects that they
|
|
point to.
|
|
|
|
If you don't supply a class for the HashFunctionToUse template parameter, the
|
|
default one provides some simple mappings for strings and ints.
|
|
|
|
@code
|
|
HashMap<int, String> hash;
|
|
hash.set (1, "item1");
|
|
hash.set (2, "item2");
|
|
|
|
DBG (hash [1]); // prints "item1"
|
|
DBG (hash [2]); // prints "item2"
|
|
|
|
// This iterates the map, printing all of its key -> value pairs..
|
|
for (HashMap<int, String>::Iterator i (hash); i.next();)
|
|
DBG (i.getKey() << " -> " << i.getValue());
|
|
@endcode
|
|
|
|
@see CriticalSection, DefaultHashFunctions, NamedValueSet, SortedSet
|
|
*/
|
|
template <typename KeyType,
|
|
typename ValueType,
|
|
class HashFunctionToUse = DefaultHashFunctions,
|
|
class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
|
class HashMap
|
|
{
|
|
private:
|
|
typedef PARAMETER_TYPE (KeyType) KeyTypeParameter;
|
|
typedef PARAMETER_TYPE (ValueType) ValueTypeParameter;
|
|
|
|
public:
|
|
|
|
/** Creates an empty hash-map.
|
|
|
|
The numberOfSlots parameter specifies the number of hash entries the map will use. This
|
|
will be the "upperLimit" parameter that is passed to your generateHash() function. The number
|
|
of hash slots will grow automatically if necessary, or it can be remapped manually using remapTable().
|
|
*/
|
|
explicit HashMap (const int numberOfSlots = defaultHashTableSize)
|
|
: totalNumItems (0)
|
|
{
|
|
slots.insertMultiple (0, nullptr, numberOfSlots);
|
|
}
|
|
|
|
/** Destructor. */
|
|
~HashMap()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
/** Removes all values from the map.
|
|
Note that this will clear the content, but won't affect the number of slots (see
|
|
remapTable and getNumSlots).
|
|
*/
|
|
void clear()
|
|
{
|
|
const ScopedLockType sl (getLock());
|
|
|
|
for (int i = slots.size(); --i >= 0;)
|
|
{
|
|
HashEntry* h = slots.getUnchecked(i);
|
|
|
|
while (h != nullptr)
|
|
{
|
|
const ScopedPointer<HashEntry> deleter (h);
|
|
h = h->nextEntry;
|
|
}
|
|
|
|
slots.set (i, nullptr);
|
|
}
|
|
|
|
totalNumItems = 0;
|
|
}
|
|
|
|
/** Returns the current number of items in the map. */
|
|
inline int size() const noexcept
|
|
{
|
|
return totalNumItems;
|
|
}
|
|
|
|
/** Returns the value corresponding to a given key.
|
|
If the map doesn't contain the key, a default instance of the value type is returned.
|
|
@param keyToLookFor the key of the item being requested
|
|
*/
|
|
inline const ValueType operator[] (KeyTypeParameter keyToLookFor) const
|
|
{
|
|
const ScopedLockType sl (getLock());
|
|
|
|
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
|
|
if (entry->key == keyToLookFor)
|
|
return entry->value;
|
|
|
|
return ValueType();
|
|
}
|
|
|
|
/** Returns true if the map contains an item with the specied key. */
|
|
bool contains (KeyTypeParameter keyToLookFor) const
|
|
{
|
|
const ScopedLockType sl (getLock());
|
|
|
|
for (const HashEntry* entry = slots.getUnchecked (generateHashFor (keyToLookFor)); entry != nullptr; entry = entry->nextEntry)
|
|
if (entry->key == keyToLookFor)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/** Returns true if the hash contains at least one occurrence of a given value. */
|
|
bool containsValue (ValueTypeParameter valueToLookFor) const
|
|
{
|
|
const ScopedLockType sl (getLock());
|
|
|
|
for (int i = getNumSlots(); --i >= 0;)
|
|
for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
|
if (entry->value == valueToLookFor)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/** Adds or replaces an element in the hash-map.
|
|
If there's already an item with the given key, this will replace its value. Otherwise, a new item
|
|
will be added to the map.
|
|
*/
|
|
void set (KeyTypeParameter newKey, ValueTypeParameter newValue)
|
|
{
|
|
const ScopedLockType sl (getLock());
|
|
const int hashIndex = generateHashFor (newKey);
|
|
|
|
HashEntry* const firstEntry = slots.getUnchecked (hashIndex);
|
|
|
|
for (HashEntry* entry = firstEntry; entry != nullptr; entry = entry->nextEntry)
|
|
{
|
|
if (entry->key == newKey)
|
|
{
|
|
entry->value = newValue;
|
|
return;
|
|
}
|
|
}
|
|
|
|
slots.set (hashIndex, new HashEntry (newKey, newValue, firstEntry));
|
|
++totalNumItems;
|
|
|
|
if (totalNumItems > (getNumSlots() * 3) / 2)
|
|
remapTable (getNumSlots() * 2);
|
|
}
|
|
|
|
/** Removes an item with the given key. */
|
|
void remove (KeyTypeParameter keyToRemove)
|
|
{
|
|
const ScopedLockType sl (getLock());
|
|
const int hashIndex = generateHashFor (keyToRemove);
|
|
HashEntry* entry = slots.getUnchecked (hashIndex);
|
|
HashEntry* previous = nullptr;
|
|
|
|
while (entry != nullptr)
|
|
{
|
|
if (entry->key == keyToRemove)
|
|
{
|
|
const ScopedPointer<HashEntry> deleter (entry);
|
|
|
|
entry = entry->nextEntry;
|
|
|
|
if (previous != nullptr)
|
|
previous->nextEntry = entry;
|
|
else
|
|
slots.set (hashIndex, entry);
|
|
|
|
--totalNumItems;
|
|
}
|
|
else
|
|
{
|
|
previous = entry;
|
|
entry = entry->nextEntry;
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Removes all items with the given value. */
|
|
void removeValue (ValueTypeParameter valueToRemove)
|
|
{
|
|
const ScopedLockType sl (getLock());
|
|
|
|
for (int i = getNumSlots(); --i >= 0;)
|
|
{
|
|
HashEntry* entry = slots.getUnchecked(i);
|
|
HashEntry* previous = nullptr;
|
|
|
|
while (entry != nullptr)
|
|
{
|
|
if (entry->value == valueToRemove)
|
|
{
|
|
const ScopedPointer<HashEntry> deleter (entry);
|
|
|
|
entry = entry->nextEntry;
|
|
|
|
if (previous != nullptr)
|
|
previous->nextEntry = entry;
|
|
else
|
|
slots.set (i, entry);
|
|
|
|
--totalNumItems;
|
|
}
|
|
else
|
|
{
|
|
previous = entry;
|
|
entry = entry->nextEntry;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Remaps the hash-map to use a different number of slots for its hash function.
|
|
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
|
@see getNumSlots()
|
|
*/
|
|
void remapTable (int newNumberOfSlots)
|
|
{
|
|
HashMap newTable (newNumberOfSlots);
|
|
|
|
for (int i = getNumSlots(); --i >= 0;)
|
|
for (const HashEntry* entry = slots.getUnchecked(i); entry != nullptr; entry = entry->nextEntry)
|
|
newTable.set (entry->key, entry->value);
|
|
|
|
swapWith (newTable);
|
|
}
|
|
|
|
/** Returns the number of slots which are available for hashing.
|
|
Each slot corresponds to a single hash-code, and each one can contain multiple items.
|
|
@see getNumSlots()
|
|
*/
|
|
inline int getNumSlots() const noexcept
|
|
{
|
|
return slots.size();
|
|
}
|
|
|
|
/** Efficiently swaps the contents of two hash-maps. */
|
|
void swapWith (HashMap& otherHashMap) noexcept
|
|
{
|
|
const ScopedLockType lock1 (getLock());
|
|
const ScopedLockType lock2 (otherHashMap.getLock());
|
|
|
|
slots.swapWithArray (otherHashMap.slots);
|
|
std::swap (totalNumItems, otherHashMap.totalNumItems);
|
|
}
|
|
|
|
/** Returns the CriticalSection that locks this structure.
|
|
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 noexcept { return lock; }
|
|
|
|
/** Returns the type of scoped lock to use for locking this array */
|
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
|
|
|
private:
|
|
|
|
class HashEntry
|
|
{
|
|
public:
|
|
HashEntry (KeyTypeParameter key_, ValueTypeParameter value_, HashEntry* const nextEntry_)
|
|
: key (key_), value (value_), nextEntry (nextEntry_)
|
|
{}
|
|
|
|
const KeyType key;
|
|
ValueType value;
|
|
HashEntry* nextEntry;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (HashEntry);
|
|
};
|
|
|
|
public:
|
|
|
|
/** Iterates over the items in a HashMap.
|
|
|
|
To use it, repeatedly call next() until it returns false, e.g.
|
|
@code
|
|
HashMap <String, String> myMap;
|
|
|
|
HashMap<String, String>::Iterator i (myMap);
|
|
|
|
while (i.next())
|
|
{
|
|
DBG (i.getKey() << " -> " << i.getValue());
|
|
}
|
|
@endcode
|
|
|
|
The order in which items are iterated bears no resemblence to the order in which
|
|
they were originally added!
|
|
|
|
Obviously as soon as you call any non-const methods on the original hash-map, any
|
|
iterators that were created beforehand will cease to be valid, and should not be used.
|
|
|
|
@see HashMap
|
|
*/
|
|
class Iterator
|
|
{
|
|
public:
|
|
|
|
Iterator (const HashMap& hashMapToIterate)
|
|
: hashMap (hashMapToIterate), entry (0), index (0)
|
|
{}
|
|
|
|
/** Moves to the next item, if one is available.
|
|
When this returns true, you can get the item's key and value using getKey() and
|
|
getValue(). If it returns false, the iteration has finished and you should stop.
|
|
*/
|
|
bool next()
|
|
{
|
|
if (entry != nullptr)
|
|
entry = entry->nextEntry;
|
|
|
|
while (entry == nullptr)
|
|
{
|
|
if (index >= hashMap.getNumSlots())
|
|
return false;
|
|
|
|
entry = hashMap.slots.getUnchecked (index++);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/** Returns the current item's key.
|
|
This should only be called when a call to next() has just returned true.
|
|
*/
|
|
const KeyType getKey() const
|
|
{
|
|
return entry != nullptr ? entry->key : KeyType();
|
|
}
|
|
|
|
/** Returns the current item's value.
|
|
This should only be called when a call to next() has just returned true.
|
|
*/
|
|
const ValueType getValue() const
|
|
{
|
|
return entry != nullptr ? entry->value : ValueType();
|
|
}
|
|
|
|
private:
|
|
|
|
const HashMap& hashMap;
|
|
HashEntry* entry;
|
|
int index;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Iterator);
|
|
};
|
|
|
|
private:
|
|
|
|
enum { defaultHashTableSize = 101 };
|
|
friend class Iterator;
|
|
|
|
Array <HashEntry*> slots;
|
|
int totalNumItems;
|
|
TypeOfCriticalSectionToUse lock;
|
|
|
|
int generateHashFor (KeyTypeParameter key) const
|
|
{
|
|
const int hash = HashFunctionToUse::generateHash (key, getNumSlots());
|
|
jassert (isPositiveAndBelow (hash, getNumSlots())); // your hash function is generating out-of-range numbers!
|
|
return hash;
|
|
}
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HashMap);
|
|
};
|
|
|
|
#endif // __JUCE_HASHMAP_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_HashMap.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_LINKEDLISTPOINTER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_NAMEDVALUESET_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_OWNEDARRAY_JUCEHEADER__
|
|
|
|
#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() noexcept;
|
|
|
|
/** 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 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 char* 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 wchar_t* const* strings);
|
|
|
|
/** 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 wchar_t* const* strings, int numberOfStrings);
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the number of strings in the array */
|
|
inline int size() const noexcept { 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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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,
|
|
CharPointer_UTF8 preNumberString = CharPointer_UTF8 (nullptr),
|
|
CharPointer_UTF8 postNumberString = CharPointer_UTF8 (nullptr));
|
|
|
|
/** 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.
|
|
*/
|
|
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 <String> 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[]
|
|
*/
|
|
String getValue (const String& key, const String& defaultReturnValue) const;
|
|
|
|
/** Returns a list of all keys in the array. */
|
|
const StringArray& getAllKeys() const noexcept { return keys; }
|
|
|
|
/** Returns a list of all values in the array. */
|
|
const StringArray& getAllValues() const noexcept { return values; }
|
|
|
|
/** Returns the number of strings in the array */
|
|
inline int size() const noexcept { 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.
|
|
*/
|
|
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) noexcept;
|
|
|
|
/** Copies another relative time. */
|
|
RelativeTime (const RelativeTime& other) noexcept;
|
|
|
|
/** Copies another relative time. */
|
|
RelativeTime& operator= (const RelativeTime& other) noexcept;
|
|
|
|
/** Destructor. */
|
|
~RelativeTime() noexcept;
|
|
|
|
/** Creates a new RelativeTime object representing a number of milliseconds.
|
|
@see minutes, hours, days, weeks
|
|
*/
|
|
static const RelativeTime milliseconds (int milliseconds) noexcept;
|
|
|
|
/** Creates a new RelativeTime object representing a number of milliseconds.
|
|
@see minutes, hours, days, weeks
|
|
*/
|
|
static const RelativeTime milliseconds (int64 milliseconds) noexcept;
|
|
|
|
/** Creates a new RelativeTime object representing a number of minutes.
|
|
@see milliseconds, hours, days, weeks
|
|
*/
|
|
static const RelativeTime minutes (double numberOfMinutes) noexcept;
|
|
|
|
/** Creates a new RelativeTime object representing a number of hours.
|
|
@see milliseconds, minutes, days, weeks
|
|
*/
|
|
static const RelativeTime hours (double numberOfHours) noexcept;
|
|
|
|
/** Creates a new RelativeTime object representing a number of days.
|
|
@see milliseconds, minutes, hours, weeks
|
|
*/
|
|
static const RelativeTime days (double numberOfDays) noexcept;
|
|
|
|
/** Creates a new RelativeTime object representing a number of weeks.
|
|
@see milliseconds, minutes, hours, days
|
|
*/
|
|
static const RelativeTime weeks (double numberOfWeeks) noexcept;
|
|
|
|
/** Returns the number of milliseconds this time represents.
|
|
@see milliseconds, inSeconds, inMinutes, inHours, inDays, inWeeks
|
|
*/
|
|
int64 inMilliseconds() const noexcept;
|
|
|
|
/** Returns the number of seconds this time represents.
|
|
@see inMilliseconds, inMinutes, inHours, inDays, inWeeks
|
|
*/
|
|
double inSeconds() const noexcept { return seconds; }
|
|
|
|
/** Returns the number of minutes this time represents.
|
|
@see inMilliseconds, inSeconds, inHours, inDays, inWeeks
|
|
*/
|
|
double inMinutes() const noexcept;
|
|
|
|
/** Returns the number of hours this time represents.
|
|
@see inMilliseconds, inSeconds, inMinutes, inDays, inWeeks
|
|
*/
|
|
double inHours() const noexcept;
|
|
|
|
/** Returns the number of days this time represents.
|
|
@see inMilliseconds, inSeconds, inMinutes, inHours, inWeeks
|
|
*/
|
|
double inDays() const noexcept;
|
|
|
|
/** Returns the number of weeks this time represents.
|
|
@see inMilliseconds, inSeconds, inMinutes, inHours, inDays
|
|
*/
|
|
double inWeeks() const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
String getDescription (const String& returnValueForZeroTime = "0") const;
|
|
|
|
/** Adds another RelativeTime to this one. */
|
|
const RelativeTime& operator+= (const RelativeTime& timeToAdd) noexcept;
|
|
/** Subtracts another RelativeTime from this one. */
|
|
const RelativeTime& operator-= (const RelativeTime& timeToSubtract) noexcept;
|
|
|
|
/** Adds a number of seconds to this time. */
|
|
const RelativeTime& operator+= (double secondsToAdd) noexcept;
|
|
/** Subtracts a number of seconds from this time. */
|
|
const RelativeTime& operator-= (double secondsToSubtract) noexcept;
|
|
|
|
private:
|
|
|
|
double seconds;
|
|
};
|
|
|
|
/** Compares two RelativeTimes. */
|
|
bool operator== (const RelativeTime& t1, const RelativeTime& t2) noexcept;
|
|
/** Compares two RelativeTimes. */
|
|
bool operator!= (const RelativeTime& t1, const RelativeTime& t2) noexcept;
|
|
/** Compares two RelativeTimes. */
|
|
bool operator> (const RelativeTime& t1, const RelativeTime& t2) noexcept;
|
|
/** Compares two RelativeTimes. */
|
|
bool operator< (const RelativeTime& t1, const RelativeTime& t2) noexcept;
|
|
/** Compares two RelativeTimes. */
|
|
bool operator>= (const RelativeTime& t1, const RelativeTime& t2) noexcept;
|
|
/** Compares two RelativeTimes. */
|
|
bool operator<= (const RelativeTime& t1, const RelativeTime& t2) noexcept;
|
|
|
|
/** Adds two RelativeTimes together. */
|
|
RelativeTime operator+ (const RelativeTime& t1, const RelativeTime& t2) noexcept;
|
|
/** Subtracts two RelativeTimes. */
|
|
RelativeTime operator- (const RelativeTime& t1, const RelativeTime& t2) noexcept;
|
|
|
|
#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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Creates a copy of another Time object. */
|
|
Time (const Time& other) noexcept;
|
|
|
|
/** Destructor. */
|
|
~Time() noexcept;
|
|
|
|
/** Copies this time from another one. */
|
|
Time& operator= (const Time& other) noexcept;
|
|
|
|
/** Returns a Time object that is set to the current system time.
|
|
|
|
@see currentTimeMillis
|
|
*/
|
|
static Time JUCE_CALLTYPE getCurrentTime() noexcept;
|
|
|
|
/** 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 noexcept { return millisSinceEpoch; }
|
|
|
|
/** Returns the year.
|
|
|
|
A 4-digit format is used, e.g. 2004.
|
|
*/
|
|
int getYear() const noexcept;
|
|
|
|
/** Returns the number of the month.
|
|
|
|
The value returned is in the range 0 to 11.
|
|
@see getMonthName
|
|
*/
|
|
int getMonth() const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
String getMonthName (bool threeLetterVersion) const;
|
|
|
|
/** Returns the day of the month.
|
|
|
|
The value returned is in the range 1 to 31.
|
|
*/
|
|
int getDayOfMonth() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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".
|
|
*/
|
|
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 noexcept;
|
|
|
|
/** Returns true if the time is in the afternoon.
|
|
|
|
So it returns true for "PM", false for "AM".
|
|
|
|
@see getHoursInAmPmFormat, getHours
|
|
*/
|
|
bool isAfternoon() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the number of minutes, 0 to 59. */
|
|
int getMinutes() const noexcept;
|
|
|
|
/** Returns the number of seconds, 0 to 59. */
|
|
int getSeconds() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns true if the local timezone uses a daylight saving correction. */
|
|
bool isDaylightSavingTime() const noexcept;
|
|
|
|
/** Returns a 3-character string to indicate the local timezone. */
|
|
String getTimeZone() const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
String toString (bool includeDate,
|
|
bool includeTime,
|
|
bool includeSeconds = true,
|
|
bool use24HourClock = false) const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
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 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 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() noexcept;
|
|
|
|
/** 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.
|
|
|
|
Being a 32-bit return value, it will of course wrap back to 0 after 2^32 seconds of
|
|
uptime, so be careful to take that into account. If you need a 64-bit time, you can
|
|
use currentTimeMillis() instead.
|
|
|
|
@see getApproximateMillisecondCounter
|
|
*/
|
|
static uint32 getMillisecondCounter() noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
// 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() noexcept;
|
|
|
|
/** Returns the resolution of the high-resolution counter in ticks per second.
|
|
|
|
@see getHighResolutionTicks, highResolutionTicksToSeconds,
|
|
secondsToHighResolutionTicks
|
|
*/
|
|
static int64 getHighResolutionTicksPerSecond() noexcept;
|
|
|
|
/** Converts a number of high-resolution ticks into seconds.
|
|
|
|
@see getHighResolutionTicks, getHighResolutionTicksPerSecond,
|
|
secondsToHighResolutionTicks
|
|
*/
|
|
static double highResolutionTicksToSeconds (int64 ticks) noexcept;
|
|
|
|
/** Converts a number seconds into high-resolution ticks.
|
|
|
|
@see getHighResolutionTicks, getHighResolutionTicksPerSecond,
|
|
highResolutionTicksToSeconds
|
|
*/
|
|
static int64 secondsToHighResolutionTicks (double seconds) noexcept;
|
|
|
|
private:
|
|
|
|
int64 millisSinceEpoch;
|
|
};
|
|
|
|
/** Adds a RelativeTime to a Time. */
|
|
JUCE_API Time operator+ (const Time& time, const RelativeTime& delta);
|
|
/** Adds a RelativeTime to a Time. */
|
|
JUCE_API Time operator+ (const RelativeTime& delta, const Time& time);
|
|
|
|
/** Subtracts a RelativeTime from a Time. */
|
|
JUCE_API Time operator- (const Time& time, const RelativeTime& delta);
|
|
/** Returns the relative time difference between two times. */
|
|
JUCE_API const RelativeTime operator- (const Time& time1, const Time& time2);
|
|
|
|
/** Compares two Time objects. */
|
|
JUCE_API bool operator== (const Time& time1, const Time& time2);
|
|
/** Compares two Time objects. */
|
|
JUCE_API bool operator!= (const Time& time1, const Time& time2);
|
|
/** Compares two Time objects. */
|
|
JUCE_API bool operator< (const Time& time1, const Time& time2);
|
|
/** Compares two Time objects. */
|
|
JUCE_API bool operator<= (const Time& time1, const Time& time2);
|
|
/** Compares two Time objects. */
|
|
JUCE_API bool operator> (const Time& time1, const Time& time2);
|
|
/** Compares two Time objects. */
|
|
JUCE_API bool operator>= (const Time& time1, const Time& time2);
|
|
|
|
#endif // __JUCE_TIME_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Time.h ***/
|
|
|
|
|
|
/*** 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() noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Compares two memory blocks.
|
|
|
|
@returns true if the two blocks are different sizes or have different contents.
|
|
*/
|
|
bool operator!= (const MemoryBlock& other) const noexcept;
|
|
|
|
/** Returns true if the data in this MemoryBlock matches the raw bytes passed-in.
|
|
*/
|
|
bool matches (const void* data, size_t dataSize) const noexcept;
|
|
|
|
/** Returns a void pointer to the data.
|
|
|
|
Note that the pointer returned will probably become invalid when the
|
|
block is resized.
|
|
*/
|
|
void* getData() const noexcept { return data; }
|
|
|
|
/** Returns a byte from the memory block.
|
|
|
|
This returns a reference, so you can also use it to set a byte.
|
|
*/
|
|
template <typename Type>
|
|
char& operator[] (const Type offset) const noexcept { return data [offset]; }
|
|
|
|
/** Returns the block's current allocated size, in bytes. */
|
|
size_t getSize() const noexcept { 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 UTF8 string. */
|
|
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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
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 <char> data;
|
|
size_t size;
|
|
static const char* const encodingTable;
|
|
|
|
JUCE_LEAK_DETECTOR (MemoryBlock);
|
|
};
|
|
|
|
#endif // __JUCE_MEMORYBLOCK_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MemoryBlock.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_Result.h ***/
|
|
#ifndef __JUCE_RESULT_JUCEHEADER__
|
|
#define __JUCE_RESULT_JUCEHEADER__
|
|
|
|
/**
|
|
Represents the 'success' or 'failure' of an operation, and holds an associated
|
|
error message to describe the error when there's a failure.
|
|
|
|
E.g.
|
|
@code
|
|
Result myOperation()
|
|
{
|
|
if (doSomeKindOfFoobar())
|
|
return Result::ok();
|
|
else
|
|
return Result::fail ("foobar didn't work!");
|
|
}
|
|
|
|
const Result result (myOperation());
|
|
|
|
if (result.wasOk())
|
|
{
|
|
...it's all good...
|
|
}
|
|
else
|
|
{
|
|
warnUserAboutFailure ("The foobar operation failed! Error message was: "
|
|
+ result.getErrorMessage());
|
|
}
|
|
@endcode
|
|
*/
|
|
class JUCE_API Result
|
|
{
|
|
public:
|
|
|
|
/** Creates and returns a 'successful' result. */
|
|
static Result ok() noexcept;
|
|
|
|
/** Creates a 'failure' result.
|
|
If you pass a blank error message in here, a default "Unknown Error" message
|
|
will be used instead.
|
|
*/
|
|
static Result fail (const String& errorMessage) noexcept;
|
|
|
|
/** Returns true if this result indicates a success. */
|
|
bool wasOk() const noexcept;
|
|
|
|
/** Returns true if this result indicates a failure.
|
|
You can use getErrorMessage() to retrieve the error message associated
|
|
with the failure.
|
|
*/
|
|
bool failed() const noexcept;
|
|
|
|
/** Returns true if this result indicates a success.
|
|
This is equivalent to calling wasOk().
|
|
*/
|
|
operator bool() const noexcept;
|
|
|
|
/** Returns true if this result indicates a failure.
|
|
This is equivalent to calling failed().
|
|
*/
|
|
bool operator!() const noexcept;
|
|
|
|
/** Returns the error message that was set when this result was created.
|
|
For a successful result, this will be an empty string;
|
|
*/
|
|
const String& getErrorMessage() const noexcept;
|
|
|
|
Result (const Result& other);
|
|
Result& operator= (const Result& other);
|
|
|
|
bool operator== (const Result& other) const noexcept;
|
|
bool operator!= (const Result& other) const noexcept;
|
|
|
|
private:
|
|
String errorMessage;
|
|
|
|
explicit Result (const String& errorMessage) noexcept;
|
|
|
|
// These casts are private to prevent people trying to use the Result object in numeric contexts
|
|
operator int() const;
|
|
operator void*() const;
|
|
};
|
|
|
|
#endif // __JUCE_RESULT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Result.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 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 noexcept { 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
|
|
*/
|
|
String getFileName() const;
|
|
|
|
/** Creates a relative path that refers to a file relatively to a given directory.
|
|
|
|
e.g. File ("/moose/foo.txt").getRelativePathFrom (File ("/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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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".
|
|
*/
|
|
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.
|
|
*/
|
|
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.
|
|
*/
|
|
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.
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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.
|
|
*/
|
|
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
|
|
*/
|
|
Result 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 a result to indicate whether the directory was created successfully, or
|
|
an error message if it failed.
|
|
@see create
|
|
*/
|
|
Result 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<File>& 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.
|
|
*/
|
|
String loadFileAsString() const;
|
|
|
|
/** Reads the contents of this file as text and splits it into lines, which are
|
|
appended to the given StringArray.
|
|
*/
|
|
void readLines (StringArray& destLines) 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<File>& 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
|
|
*/
|
|
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 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 File createTempFile (const String& fileNameEnding);
|
|
|
|
/** Returns the current working directory.
|
|
|
|
@see setAsCurrentWorkingDirectory
|
|
*/
|
|
static 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 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 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 File createFileWithoutCheckingPath (const String& path);
|
|
|
|
/** Adds a separator character to the end of a path if it doesn't already have one. */
|
|
static String addTrailingSeparator (const String& path);
|
|
|
|
#if JUCE_MAC || JUCE_IOS || DOXYGEN
|
|
|
|
/** OSX ONLY - Finds the OSType of a file from the its resources. */
|
|
OSType getMacOSType() const;
|
|
|
|
/** OSX ONLY - Returns true if this file is actually a bundle. */
|
|
bool isBundle() const;
|
|
#endif
|
|
|
|
#if JUCE_MAC || DOXYGEN
|
|
/** OSX ONLY - Adds this file to the OSX dock */
|
|
void addToDock() const;
|
|
#endif
|
|
|
|
private:
|
|
|
|
String fullPath;
|
|
|
|
// internal way of contructing a file without checking the path
|
|
friend class DirectoryIterator;
|
|
File (const String&, int);
|
|
String getPathUpToLastSlash() const;
|
|
|
|
Result 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 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 (JUCE_NAMESPACE::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 <MYTAG> element..
|
|
doSomethingWithMYTAGElement (child);
|
|
}
|
|
|
|
@endcode
|
|
|
|
@see forEachXmlChildElement
|
|
*/
|
|
#define forEachXmlChildElementWithTagName(parentXmlElement, childElementVariableName, requiredTagName) \
|
|
\
|
|
for (JUCE_NAMESPACE::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) noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 "<?xml version..etc" line at the start of the
|
|
document
|
|
@param encodingType the character encoding format string to put into the xml
|
|
header
|
|
@param lineWrapLength the line length that will be used before items get placed on
|
|
a new line. This isn't an absolute maximum length, it just
|
|
determines how lists of attributes get broken up
|
|
@see writeToStream, writeToFile
|
|
*/
|
|
String createDocument (const String& dtdToUse,
|
|
bool allOnOneLine = false,
|
|
bool includeXmlHeader = true,
|
|
const String& encodingType = "UTF-8",
|
|
int lineWrapLength = 60) const;
|
|
|
|
/** Writes the document to a stream as UTF-8.
|
|
|
|
@param output the stream to write to
|
|
@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 "<?xml version..etc" line at the start of the
|
|
document
|
|
@param encodingType the character encoding format string to put into the xml
|
|
header
|
|
@param lineWrapLength the line length that will be used before items get placed on
|
|
a new line. This isn't an absolute maximum length, it just
|
|
determines how lists of attributes get broken up
|
|
@see writeToFile, createDocument
|
|
*/
|
|
void writeToStream (OutputStream& output,
|
|
const String& dtdToUse,
|
|
bool allOnOneLine = false,
|
|
bool includeXmlHeader = true,
|
|
const String& encodingType = "UTF-8",
|
|
int lineWrapLength = 60) const;
|
|
|
|
/** Writes the element to a file as an XML document.
|
|
|
|
To improve safety in case something goes wrong while writing the file, this
|
|
will actually write the document to a new temporary file in the same
|
|
directory as the destination file, and if this succeeds, it will rename this
|
|
new file as the destination file (overwriting any existing file that was there).
|
|
|
|
@param destinationFile the file to write to. If this already exists, it will be
|
|
overwritten.
|
|
@param dtdToUse the DTD to add to the document
|
|
@param encodingType the character encoding format string to put into the xml
|
|
header
|
|
@param lineWrapLength the line length that will be used before items get placed on
|
|
a new line. This isn't an absolute maximum length, it just
|
|
determines how lists of attributes get broken up
|
|
@returns true if the file is written successfully; false if something goes wrong
|
|
in the process
|
|
@see createDocument
|
|
*/
|
|
bool writeToFile (const File& destinationFile,
|
|
const String& dtdToUse,
|
|
const String& encodingType = "UTF-8",
|
|
int lineWrapLength = 60) const;
|
|
|
|
/** Returns this element's tag type name.
|
|
|
|
E.g. for an element such as \<MOOSE legs="4" antlers="2">, this would return
|
|
"MOOSE".
|
|
|
|
@see hasTagName
|
|
*/
|
|
inline const String& getTagName() const noexcept { 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 noexcept;
|
|
|
|
/** Returns the number of XML attributes this element contains.
|
|
|
|
E.g. for an element such as \<MOOSE legs="4" antlers="2">, this would
|
|
return 2.
|
|
*/
|
|
int getNumAttributes() const noexcept;
|
|
|
|
/** Returns the name of one of the elements attributes.
|
|
|
|
E.g. for an element such as \<MOOSE legs="4" antlers="2">, then
|
|
getAttributeName(1) would return "antlers".
|
|
|
|
@see getAttributeValue, getStringAttribute
|
|
*/
|
|
const String& getAttributeName (int attributeIndex) const noexcept;
|
|
|
|
/** Returns the value of one of the elements attributes.
|
|
|
|
E.g. for an element such as \<MOOSE legs="4" antlers="2">, then
|
|
getAttributeName(1) would return "2".
|
|
|
|
@see getAttributeName, getStringAttribute
|
|
*/
|
|
const String& getAttributeValue (int attributeIndex) const noexcept;
|
|
|
|
// Attribute-handling methods..
|
|
|
|
/** Checks whether the element contains an attribute with a certain name. */
|
|
bool hasAttribute (const String& attributeName) const noexcept;
|
|
|
|
/** Returns the value of a named attribute.
|
|
|
|
@param attributeName the name of the attribute to look up
|
|
*/
|
|
const String& getStringAttribute (const String& attributeName) const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Removes all attributes from this element.
|
|
*/
|
|
void removeAllAttributes() noexcept;
|
|
|
|
// 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 noexcept { 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 != nullptr)
|
|
{
|
|
...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 noexcept { 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Deletes all the child elements in the element.
|
|
|
|
@see removeChildElement, deleteAllChildElementsWithTagName
|
|
*/
|
|
void deleteAllChildElements() noexcept;
|
|
|
|
/** Deletes all the child elements with a given tag name.
|
|
|
|
@see removeChildElement
|
|
*/
|
|
void deleteAllChildElementsWithTagName (const String& tagName) noexcept;
|
|
|
|
/** Returns true if the given element is a child of this one. */
|
|
bool containsChildElement (const XmlElement* possibleChild) const noexcept;
|
|
|
|
/** Recursively searches all sub-elements to find one that contains the specified
|
|
child element.
|
|
*/
|
|
XmlElement* findParentElementOf (const XmlElement* elementToLookFor) noexcept;
|
|
|
|
/** 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 <class ElementComparator>
|
|
void sortChildElements (ElementComparator& comparator,
|
|
bool retainOrderOfEquivalentItems = false)
|
|
{
|
|
const int num = getNumChildElements();
|
|
|
|
if (num > 1)
|
|
{
|
|
HeapBlock <XmlElement*> 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 noexcept;
|
|
|
|
/** Returns the text for a text element.
|
|
|
|
Note that if you have an element like this:
|
|
|
|
@code<xyz>hello</xyz>@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 noexcept;
|
|
|
|
/** 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. If you're trying to add text inside a normal
|
|
element, you probably want to use addTextElement() instead.
|
|
*/
|
|
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. @code<xyz>hello <x>there</x> world</xyz>@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
|
|
*/
|
|
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
|
|
*/
|
|
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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
XmlAttributeNode (const String& name, const String& value) noexcept;
|
|
|
|
LinkedListPointer<XmlAttributeNode> nextListItem;
|
|
String name, value;
|
|
|
|
bool hasName (const String& name) const noexcept;
|
|
|
|
private:
|
|
XmlAttributeNode& operator= (const XmlAttributeNode&);
|
|
};
|
|
|
|
friend class XmlDocument;
|
|
friend class LinkedListPointer<XmlAttributeNode>;
|
|
friend class LinkedListPointer <XmlElement>;
|
|
friend class LinkedListPointer <XmlElement>::Appender;
|
|
|
|
LinkedListPointer <XmlElement> nextListItem;
|
|
LinkedListPointer <XmlElement> firstChildElement;
|
|
LinkedListPointer <XmlAttributeNode> attributes;
|
|
String tagName;
|
|
|
|
XmlElement (int) noexcept;
|
|
void copyChildrenAndAttributesFrom (const XmlElement& other);
|
|
void writeElementAsText (OutputStream& out, int indentationLevel, int lineWrapLength) const;
|
|
void getChildElementsAsArray (XmlElement**) const noexcept;
|
|
void reorderChildElements (XmlElement**, int) noexcept;
|
|
|
|
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
|
|
*/
|
|
String getValue (const String& keyName,
|
|
const String& defaultReturnValue = String::empty) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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);
|
|
|
|
/** This copies all the values from a source PropertySet to this one.
|
|
This won't remove any existing settings, it just adds any that it finds in the source set.
|
|
*/
|
|
void addAllPropertiesFrom (const PropertySet& source);
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Removes all values. */
|
|
void clear();
|
|
|
|
/** Returns the keys/value pair array containing all the properties. */
|
|
StringPairArray& getAllProperties() noexcept { return properties; }
|
|
|
|
/** Returns the lock used when reading or writing to this set */
|
|
const CriticalSection& getLock() const noexcept { 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) noexcept;
|
|
|
|
/** Returns the fallback property set.
|
|
@see setFallbackPropertySet
|
|
*/
|
|
PropertySet* getFallbackPropertySet() const noexcept { 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 ObjectClass, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
|
class ReferenceCountedArray
|
|
{
|
|
public:
|
|
typedef ReferenceCountedObjectPtr<ObjectClass> ObjectClassPtr;
|
|
|
|
/** Creates an empty array.
|
|
@see ReferenceCountedObject, Array, OwnedArray
|
|
*/
|
|
ReferenceCountedArray() noexcept
|
|
: numUsed (0)
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another array */
|
|
ReferenceCountedArray (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
|
|
{
|
|
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] != nullptr)
|
|
data.elements[i]->incReferenceCount();
|
|
}
|
|
|
|
/** Copies another array into this one.
|
|
|
|
Any existing objects in this array will first be released.
|
|
*/
|
|
ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& operator= (const ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse>& other) noexcept
|
|
{
|
|
if (this != &other)
|
|
{
|
|
ReferenceCountedArray<ObjectClass, TypeOfCriticalSectionToUse> 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] != nullptr)
|
|
data.elements [numUsed]->decReferenceCount();
|
|
|
|
jassert (numUsed == 0);
|
|
data.setAllocatedSize (0);
|
|
}
|
|
|
|
/** Returns the current number of objects in the array. */
|
|
inline int size() const noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
return isPositiveAndBelow (index, numUsed) ? data.elements [index]
|
|
: static_cast <ObjectClass*> (nullptr);
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
return numUsed > 0 ? data.elements [0]
|
|
: static_cast <ObjectClass*> (nullptr);
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
return numUsed > 0 ? data.elements [numUsed - 1]
|
|
: static_cast <ObjectClass*> (nullptr);
|
|
}
|
|
|
|
/** Returns a pointer to the first element in the array.
|
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
|
*/
|
|
inline ObjectClass** begin() const noexcept
|
|
{
|
|
return data.elements;
|
|
}
|
|
|
|
/** Returns a pointer to the element which follows the last element in the array.
|
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
|
*/
|
|
inline ObjectClass** end() const noexcept
|
|
{
|
|
return data.elements + numUsed;
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
ObjectClass** e = data.elements.getData();
|
|
ObjectClass** const end_ = e + numUsed;
|
|
|
|
while (e != end_)
|
|
{
|
|
if (objectToLookFor == *e)
|
|
return static_cast <int> (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 noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
data.ensureAllocatedSize (numUsed + 1);
|
|
data.elements [numUsed++] = newObject;
|
|
|
|
if (newObject != nullptr)
|
|
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) noexcept
|
|
{
|
|
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 != nullptr)
|
|
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) noexcept
|
|
{
|
|
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 != nullptr)
|
|
newObject->incReferenceCount();
|
|
|
|
if (indexToChange < numUsed)
|
|
{
|
|
if (data.elements [indexToChange] != nullptr)
|
|
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<ObjectClass, TypeOfCriticalSectionToUse>& arrayToAddFrom,
|
|
int startIndex = 0,
|
|
int numElementsToAdd = -1) noexcept
|
|
{
|
|
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
|
|
@returns the index at which the new object was added
|
|
@see add, sort
|
|
*/
|
|
template <class ElementComparator>
|
|
int addSorted (ElementComparator& comparator, ObjectClass* newObject) noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
const int index = findInsertIndexInSortedArray (comparator, data.elements.getData(), newObject, 0, numUsed);
|
|
insert (index, newObject);
|
|
return index;
|
|
}
|
|
|
|
/** 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 <class ElementComparator>
|
|
void addOrReplaceSorted (ElementComparator& comparator,
|
|
ObjectClass* newObject) noexcept
|
|
{
|
|
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 != nullptr)
|
|
(*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 != nullptr)
|
|
{
|
|
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] != nullptr)
|
|
{
|
|
data.elements[i]->decReferenceCount();
|
|
data.elements[i] = nullptr; // (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) noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
|
|
if (isPositiveAndBelow (index1, numUsed)
|
|
&& isPositiveAndBelow (index2, numUsed))
|
|
{
|
|
std::swap (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) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
const ScopedLockType lock1 (getLock());
|
|
const ScopedLockType lock2 (otherArray.getLock());
|
|
|
|
data.swapWith (otherArray.data);
|
|
std::swap (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 noexcept
|
|
{
|
|
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<ObjectClass, TypeOfCriticalSectionToUse>& other) const noexcept
|
|
{
|
|
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 <class ElementComparator>
|
|
void sort (ElementComparator& comparator,
|
|
const bool retainOrderOfEquivalentItems = false) const noexcept
|
|
{
|
|
(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() noexcept
|
|
{
|
|
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 noexcept { return data; }
|
|
|
|
/** Returns the type of scoped lock to use for locking this array */
|
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
|
|
|
private:
|
|
|
|
ArrayAllocationBase <ObjectClass*, TypeOfCriticalSectionToUse> data;
|
|
int numUsed;
|
|
};
|
|
|
|
#endif // __JUCE_REFERENCECOUNTEDARRAY_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ReferenceCountedArray.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SCOPEDVALUESETTER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ScopedValueSetter.h ***/
|
|
#ifndef __JUCE_SCOPEDVALUESETTER_JUCEHEADER__
|
|
#define __JUCE_SCOPEDVALUESETTER_JUCEHEADER__
|
|
|
|
/**
|
|
Helper class providing an RAII-based mechanism for temporarily setting and
|
|
then re-setting a value.
|
|
|
|
E.g. @code
|
|
int x = 1;
|
|
|
|
{
|
|
ScopedValueSetter setter (x, 2);
|
|
|
|
// x is now 2
|
|
}
|
|
|
|
// x is now 1 again
|
|
|
|
{
|
|
ScopedValueSetter setter (x, 3, 4);
|
|
|
|
// x is now 3
|
|
}
|
|
|
|
// x is now 4
|
|
@endcode
|
|
|
|
*/
|
|
template <typename ValueType>
|
|
class ScopedValueSetter
|
|
{
|
|
public:
|
|
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
|
given new value, and will then reset it to its original value when this object is deleted.
|
|
*/
|
|
ScopedValueSetter (ValueType& valueToSet,
|
|
const ValueType& newValue)
|
|
: value (valueToSet),
|
|
originalValue (valueToSet)
|
|
{
|
|
valueToSet = newValue;
|
|
}
|
|
|
|
/** Creates a ScopedValueSetter that will immediately change the specified value to the
|
|
given new value, and will then reset it to be valueWhenDeleted when this object is deleted.
|
|
*/
|
|
ScopedValueSetter (ValueType& valueToSet,
|
|
const ValueType& newValue,
|
|
const ValueType& valueWhenDeleted)
|
|
: value (valueToSet),
|
|
originalValue (valueWhenDeleted)
|
|
{
|
|
valueToSet = newValue;
|
|
}
|
|
|
|
~ScopedValueSetter()
|
|
{
|
|
value = originalValue;
|
|
}
|
|
|
|
private:
|
|
|
|
ValueType& value;
|
|
const ValueType originalValue;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (ScopedValueSetter);
|
|
};
|
|
|
|
#endif // __JUCE_SCOPEDVALUESETTER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ScopedValueSetter.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 ElementType, class TypeOfCriticalSectionToUse = DummyCriticalSection>
|
|
class SortedSet
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty set. */
|
|
SortedSet() noexcept
|
|
: numUsed (0)
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another set.
|
|
@param other the set to copy
|
|
*/
|
|
SortedSet (const SortedSet& other) noexcept
|
|
{
|
|
const ScopedLockType lock (other.getLock());
|
|
numUsed = other.numUsed;
|
|
data.setAllocatedSize (other.numUsed);
|
|
memcpy (data.elements, other.data.elements, numUsed * sizeof (ElementType));
|
|
}
|
|
|
|
/** Destructor. */
|
|
~SortedSet() noexcept
|
|
{
|
|
}
|
|
|
|
/** Copies another set over this one.
|
|
@param other the set to copy
|
|
*/
|
|
SortedSet& operator= (const SortedSet& other) noexcept
|
|
{
|
|
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<ElementType>& other) const noexcept
|
|
{
|
|
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<ElementType>& other) const noexcept
|
|
{
|
|
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() noexcept
|
|
{
|
|
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() noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
numUsed = 0;
|
|
}
|
|
|
|
/** Returns the current number of elements in the set.
|
|
*/
|
|
inline int size() const noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
jassert (isPositiveAndBelow (index, numUsed));
|
|
return data.elements [index];
|
|
}
|
|
|
|
/** Returns a direct reference to one of the elements in the set, 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)
|
|
*/
|
|
inline ElementType& getReference (const int index) const noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
return numUsed > 0 ? data.elements [numUsed - 1] : ElementType();
|
|
}
|
|
|
|
/** Returns a pointer to the first element in the set.
|
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
|
*/
|
|
inline ElementType* begin() const noexcept
|
|
{
|
|
return data.elements;
|
|
}
|
|
|
|
/** Returns a pointer to the element which follows the last element in the set.
|
|
This method is provided for compatibility with standard C++ iteration mechanisms.
|
|
*/
|
|
inline ElementType* end() const noexcept
|
|
{
|
|
return data.elements + numUsed;
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
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])
|
|
end_ = halfway;
|
|
else
|
|
start = 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 noexcept
|
|
{
|
|
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])
|
|
end_ = halfway;
|
|
else
|
|
start = 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) noexcept
|
|
{
|
|
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, newElement);
|
|
else
|
|
insertInternal (start + 1, newElement);
|
|
|
|
break;
|
|
}
|
|
else if (newElement < data.elements [halfway])
|
|
end_ = halfway;
|
|
else
|
|
start = 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) noexcept
|
|
{
|
|
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 <class OtherSetType>
|
|
void addSet (const OtherSetType& setToAddFrom,
|
|
int startIndex = 0,
|
|
int numElementsToAdd = -1) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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 ElementType();
|
|
}
|
|
|
|
/** 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) noexcept
|
|
{
|
|
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 <class OtherSetType>
|
|
void removeValuesIn (const OtherSetType& otherSet) noexcept
|
|
{
|
|
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 <class OtherSetType>
|
|
void removeValuesNotIn (const OtherSetType& otherSet) noexcept
|
|
{
|
|
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() noexcept
|
|
{
|
|
const ScopedLockType lock (getLock());
|
|
data.shrinkToNoMoreThan (numUsed);
|
|
}
|
|
|
|
/** Increases the set's internal storage to hold a minimum number of elements.
|
|
|
|
Calling this before adding a large known number of elements means that
|
|
the set 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);
|
|
}
|
|
|
|
/** 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 noexcept { return data; }
|
|
|
|
/** Returns the type of scoped lock to use for locking this array */
|
|
typedef typename TypeOfCriticalSectionToUse::ScopedLockType ScopedLockType;
|
|
|
|
private:
|
|
|
|
ArrayAllocationBase <ElementType, TypeOfCriticalSectionToUse> data;
|
|
int numUsed;
|
|
|
|
void insertInternal (const int indexToInsertAt, const ElementType newElement) noexcept
|
|
{
|
|
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 <typename ValueType>
|
|
class Range
|
|
{
|
|
public:
|
|
|
|
/** Constructs an empty range. */
|
|
Range() noexcept
|
|
: start (ValueType()), end (ValueType())
|
|
{
|
|
}
|
|
|
|
/** Constructs a range with given start and end values. */
|
|
Range (const ValueType start_, const ValueType end_) noexcept
|
|
: start (start_), end (jmax (start_, end_))
|
|
{
|
|
}
|
|
|
|
/** Constructs a copy of another range. */
|
|
Range (const Range& other) noexcept
|
|
: start (other.start), end (other.end)
|
|
{
|
|
}
|
|
|
|
/** Copies another range object. */
|
|
Range& operator= (const Range& other) noexcept
|
|
{
|
|
start = other.start;
|
|
end = other.end;
|
|
return *this;
|
|
}
|
|
|
|
/** Destructor. */
|
|
~Range() noexcept
|
|
{
|
|
}
|
|
|
|
/** Returns the range that lies between two positions (in either order). */
|
|
static Range between (const ValueType position1, const ValueType position2) noexcept
|
|
{
|
|
return (position1 < position2) ? Range (position1, position2)
|
|
: Range (position2, position1);
|
|
}
|
|
|
|
/** Returns a range with the specified start position and a length of zero. */
|
|
static Range emptyRange (const ValueType start) noexcept
|
|
{
|
|
return Range (start, start);
|
|
}
|
|
|
|
/** Returns the start of the range. */
|
|
inline ValueType getStart() const noexcept { return start; }
|
|
|
|
/** Returns the length of the range. */
|
|
inline ValueType getLength() const noexcept { return end - start; }
|
|
|
|
/** Returns the end of the range. */
|
|
inline ValueType getEnd() const noexcept { return end; }
|
|
|
|
/** Returns true if the range has a length of zero. */
|
|
inline bool isEmpty() const noexcept { 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) noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Range withStart (const ValueType newStart) const noexcept
|
|
{
|
|
return Range (newStart, jmax (newStart, end));
|
|
}
|
|
|
|
/** Returns a range with the same length as this one, but moved to have the given start position. */
|
|
Range movedToStartAt (const ValueType newStart) const noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Range withEnd (const ValueType newEnd) const noexcept
|
|
{
|
|
return Range (jmin (start, newEnd), newEnd);
|
|
}
|
|
|
|
/** Returns a range with the same length as this one, but moved to have the given start position. */
|
|
Range movedToEndAt (const ValueType newEnd) const noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Range withLength (const ValueType newLength) const noexcept
|
|
{
|
|
return Range (start, start + newLength);
|
|
}
|
|
|
|
/** Adds an amount to the start and end of the range. */
|
|
inline const Range& operator+= (const ValueType amountToAdd) noexcept
|
|
{
|
|
start += amountToAdd;
|
|
end += amountToAdd;
|
|
return *this;
|
|
}
|
|
|
|
/** Subtracts an amount from the start and end of the range. */
|
|
inline const Range& operator-= (const ValueType amountToSubtract) noexcept
|
|
{
|
|
start -= amountToSubtract;
|
|
end -= amountToSubtract;
|
|
return *this;
|
|
}
|
|
|
|
/** Returns a range that is equal to this one with an amount added to its
|
|
start and end.
|
|
*/
|
|
Range operator+ (const ValueType amountToAdd) const noexcept
|
|
{
|
|
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. */
|
|
Range operator- (const ValueType amountToSubtract) const noexcept
|
|
{
|
|
return Range (start - amountToSubtract, end - amountToSubtract);
|
|
}
|
|
|
|
bool operator== (const Range& other) const noexcept { return start == other.start && end == other.end; }
|
|
bool operator!= (const Range& other) const noexcept { return start != other.start || end != other.end; }
|
|
|
|
/** Returns true if the given position lies inside this range. */
|
|
bool contains (const ValueType position) const noexcept
|
|
{
|
|
return start <= position && position < end;
|
|
}
|
|
|
|
/** Returns the nearest value to the one supplied, which lies within the range. */
|
|
ValueType clipValue (const ValueType value) const noexcept
|
|
{
|
|
return jlimit (start, end, value);
|
|
}
|
|
|
|
/** Returns true if the given range lies entirely inside this range. */
|
|
bool contains (const Range& other) const noexcept
|
|
{
|
|
return start <= other.start && end >= other.end;
|
|
}
|
|
|
|
/** Returns true if the given range intersects this one. */
|
|
bool intersects (const Range& other) const noexcept
|
|
{
|
|
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. */
|
|
Range getIntersectionWith (const Range& other) const noexcept
|
|
{
|
|
return Range (jmax (start, other.start),
|
|
jmin (end, other.end));
|
|
}
|
|
|
|
/** Returns the smallest range that contains both this one and the other one. */
|
|
Range getUnionWith (const Range& other) const noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Range constrainRange (const Range& rangeToConstrain) const noexcept
|
|
{
|
|
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 Type>
|
|
class SparseSet
|
|
{
|
|
public:
|
|
|
|
/** Creates a new empty set. */
|
|
SparseSet()
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another SparseSet. */
|
|
SparseSet (const SparseSet<Type>& other)
|
|
: values (other.values)
|
|
{
|
|
}
|
|
|
|
/** Clears the set. */
|
|
void clear()
|
|
{
|
|
values.clear();
|
|
}
|
|
|
|
/** Checks whether the set is empty.
|
|
|
|
This is much quicker than using (size() == 0).
|
|
*/
|
|
bool isEmpty() const noexcept
|
|
{
|
|
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();
|
|
}
|
|
|
|
/** 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 noexcept
|
|
{
|
|
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<Type> getRange (const int rangeIndex) const
|
|
{
|
|
if (isPositiveAndBelow (rangeIndex, getNumRanges()))
|
|
return Range<Type> (values.getUnchecked (rangeIndex << 1),
|
|
values.getUnchecked ((rangeIndex << 1) + 1));
|
|
else
|
|
return Range<Type>();
|
|
}
|
|
|
|
/** Returns the range between the lowest and highest values in the set.
|
|
@see getRange
|
|
*/
|
|
const Range<Type> getTotalRange() const
|
|
{
|
|
if (values.size() > 0)
|
|
{
|
|
jassert ((values.size() & 1) == 0);
|
|
return Range<Type> (values.getUnchecked (0),
|
|
values.getUnchecked (values.size() - 1));
|
|
}
|
|
|
|
return Range<Type>();
|
|
}
|
|
|
|
/** Adds a range of contiguous values to the set.
|
|
e.g. addRange (Range \<int\> (10, 14)) will add (10, 11, 12, 13) to the set.
|
|
*/
|
|
void addRange (const Range<Type>& 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\<int\> (10, 14)) will remove (10, 11, 12, 13) from the set.
|
|
*/
|
|
void removeRange (const Range<Type>& 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<Type>& 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<Type>& 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<Type>& 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<Type>& other) noexcept
|
|
{
|
|
return values == other.values;
|
|
}
|
|
|
|
bool operator!= (const SparseSet<Type>& other) noexcept
|
|
{
|
|
return values != other.values;
|
|
}
|
|
|
|
private:
|
|
|
|
// alternating start/end values of ranges of values that are present.
|
|
Array<Type, DummyCriticalSection> 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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 <Message> Ptr;
|
|
|
|
private:
|
|
friend class MessageListener;
|
|
friend class MessageManager;
|
|
MessageListener* messageRecipient;
|
|
|
|
// Avoid the leak-detector because for plugins, the host can unload our DLL with undelivered
|
|
// messages still in the system event queue. These aren't harmful, but can cause annoying assertions.
|
|
JUCE_DECLARE_NON_COPYABLE (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() noexcept;
|
|
|
|
/** 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:
|
|
|
|
// Avoid the leak-detector because for plugins, the host can unload our DLL with undelivered
|
|
// messages still in the system event queue. These aren't harmful, but can cause annoying assertions.
|
|
JUCE_DECLARE_NON_COPYABLE (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() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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<CallbackMessage> message;
|
|
Atomic<int>& getDeliveryFlag() const noexcept;
|
|
|
|
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 <MyListenerType> 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 ListenerClass,
|
|
class ArrayType = Array <ListenerClass*> >
|
|
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 != nullptr);
|
|
|
|
if (listenerToAdd != nullptr)
|
|
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 != nullptr);
|
|
|
|
listeners.removeValue (listenerToRemove);
|
|
}
|
|
|
|
/** Returns the number of registered listeners. */
|
|
int size() const noexcept
|
|
{
|
|
return listeners.size();
|
|
}
|
|
|
|
/** Returns true if any listeners are registered. */
|
|
bool isEmpty() const noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
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 <const DummyBailOutChecker&> (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 <class BailOutCheckerType>
|
|
void callChecked (const BailOutCheckerType& bailOutChecker,
|
|
void (ListenerClass::*callbackFunction) ())
|
|
{
|
|
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
|
(iter.getListener()->*callbackFunction) ();
|
|
}
|
|
|
|
/** Calls a member function on each listener in the list, with 1 parameter. */
|
|
template <LL_TEMPLATE(1)>
|
|
void call (void (ListenerClass::*callbackFunction) (P1), LL_PARAM(1))
|
|
{
|
|
for (Iterator<DummyBailOutChecker, ThisType> 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 <class BailOutCheckerType, LL_TEMPLATE(1)>
|
|
void callChecked (const BailOutCheckerType& bailOutChecker,
|
|
void (ListenerClass::*callbackFunction) (P1),
|
|
LL_PARAM(1))
|
|
{
|
|
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
|
(iter.getListener()->*callbackFunction) (param1);
|
|
}
|
|
|
|
/** Calls a member function on each listener in the list, with 2 parameters. */
|
|
template <LL_TEMPLATE(1), LL_TEMPLATE(2)>
|
|
void call (void (ListenerClass::*callbackFunction) (P1, P2),
|
|
LL_PARAM(1), LL_PARAM(2))
|
|
{
|
|
for (Iterator<DummyBailOutChecker, ThisType> 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 <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2)>
|
|
void callChecked (const BailOutCheckerType& bailOutChecker,
|
|
void (ListenerClass::*callbackFunction) (P1, P2),
|
|
LL_PARAM(1), LL_PARAM(2))
|
|
{
|
|
for (Iterator<BailOutCheckerType, ThisType> iter (*this); iter.next (bailOutChecker);)
|
|
(iter.getListener()->*callbackFunction) (param1, param2);
|
|
}
|
|
|
|
/** Calls a member function on each listener in the list, with 3 parameters. */
|
|
template <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
|
|
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3),
|
|
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3))
|
|
{
|
|
for (Iterator<DummyBailOutChecker, ThisType> 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 <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3)>
|
|
void callChecked (const BailOutCheckerType& bailOutChecker,
|
|
void (ListenerClass::*callbackFunction) (P1, P2, P3),
|
|
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3))
|
|
{
|
|
for (Iterator<BailOutCheckerType, ThisType> 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 <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
|
|
void call (void (ListenerClass::*callbackFunction) (P1, P2, P3, P4),
|
|
LL_PARAM(1), LL_PARAM(2), LL_PARAM(3), LL_PARAM(4))
|
|
{
|
|
for (Iterator<DummyBailOutChecker, ThisType> 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 <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4)>
|
|
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<BailOutCheckerType, ThisType> 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 <LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
|
|
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<DummyBailOutChecker, ThisType> 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 <class BailOutCheckerType, LL_TEMPLATE(1), LL_TEMPLATE(2), LL_TEMPLATE(3), LL_TEMPLATE(4), LL_TEMPLATE(5)>
|
|
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<BailOutCheckerType, ThisType> 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 noexcept { return false; }
|
|
};
|
|
|
|
/** Iterates the listeners in a ListenerList. */
|
|
template <class BailOutCheckerType, class ListType>
|
|
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 noexcept
|
|
{
|
|
return list.getListeners().getUnchecked (index);
|
|
}
|
|
|
|
private:
|
|
const ListType& list;
|
|
int index;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (Iterator);
|
|
};
|
|
|
|
typedef ListenerList<ListenerClass, ArrayType> ThisType;
|
|
typedef ListenerClass ListenerType;
|
|
|
|
const ArrayType& getListeners() const noexcept { 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. */
|
|
var getValue() const;
|
|
|
|
/** Returns the current value. */
|
|
operator var() const;
|
|
|
|
/** Returns the value as a string.
|
|
|
|
This is alternative to writing things like "myValue.getValue().toString()".
|
|
*/
|
|
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 SingleThreadedReferenceCountedObject,
|
|
public AsyncUpdater
|
|
{
|
|
public:
|
|
ValueSource();
|
|
virtual ~ValueSource();
|
|
|
|
/** Returns the current value of this object. */
|
|
virtual 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 <Value*> 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() noexcept { return *value; }
|
|
|
|
private:
|
|
|
|
friend class ValueSource;
|
|
ReferenceCountedObjectPtr <ValueSource> value;
|
|
ListenerList <Listener> 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() noexcept;
|
|
|
|
/** 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 <ChangeListener> 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() noexcept {}
|
|
|
|
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 nullptr; }
|
|
};
|
|
|
|
#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
|
|
*/
|
|
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 <const UndoableAction*>& 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
|
|
*/
|
|
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 <OwnedArray <UndoableAction> > 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() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 != nullptr; }
|
|
|
|
/** 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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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.
|
|
|
|
Note that when you register a listener to a tree, it will receive this callback for
|
|
child changes in both that tree and 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,
|
|
just check the parentTree parameter to make sure it's the one that you're interested in.
|
|
*/
|
|
virtual void valueTreeChildAdded (ValueTree& parentTree,
|
|
ValueTree& childWhichHasBeenAdded) = 0;
|
|
|
|
/** This method is called when a child sub-tree is removed.
|
|
|
|
Note that when you register a listener to a tree, it will receive this callback for
|
|
child changes in both that tree and 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,
|
|
just check the parentTree parameter to make sure it's the one that you're interested in.
|
|
*/
|
|
virtual void valueTreeChildRemoved (ValueTree& parentTree,
|
|
ValueTree& childWhichHasBeenRemoved) = 0;
|
|
|
|
/** This method is called when a tree's children have been re-shuffled.
|
|
|
|
Note that when you register a listener to a tree, it will receive this callback for
|
|
child changes in both that tree and 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,
|
|
just check the parameter to make sure it's the tree that you're interested in.
|
|
*/
|
|
virtual void valueTreeChildOrderChanged (ValueTree& parentTreeWhoseChildrenHaveMoved) = 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 <typename ElementComparator>
|
|
void sort (ElementComparator& comparator, UndoManager* undoManager, bool retainOrderOfEquivalentItems)
|
|
{
|
|
if (object != nullptr)
|
|
{
|
|
ReferenceCountedArray <SharedObject> sortedList (object->children);
|
|
ComparatorAdapter <ElementComparator> 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 SingleThreadedReferenceCountedObject
|
|
{
|
|
public:
|
|
explicit SharedObject (const Identifier& type);
|
|
SharedObject (const SharedObject& other);
|
|
~SharedObject();
|
|
|
|
const Identifier type;
|
|
NamedValueSet properties;
|
|
ReferenceCountedArray <SharedObject> children;
|
|
SortedSet <ValueTree*> valueTreesWithListeners;
|
|
SharedObject* parent;
|
|
|
|
void sendPropertyChangeMessage (const Identifier& property);
|
|
void sendPropertyChangeMessage (ValueTree& tree, const Identifier& property);
|
|
void sendChildAddedMessage (ValueTree& parent, ValueTree& child);
|
|
void sendChildAddedMessage (ValueTree child);
|
|
void sendChildRemovedMessage (ValueTree& parent, ValueTree& child);
|
|
void sendChildRemovedMessage (ValueTree child);
|
|
void sendChildOrderChangedMessage (ValueTree& parent);
|
|
void sendChildOrderChangedMessage();
|
|
void sendParentChangeMessage();
|
|
const var& getProperty (const Identifier& name) 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 <SharedObject>& newOrder, UndoManager*);
|
|
bool isEquivalentTo (const SharedObject& other) const;
|
|
XmlElement* createXml() const;
|
|
|
|
private:
|
|
SharedObject& operator= (const SharedObject&);
|
|
JUCE_LEAK_DETECTOR (SharedObject);
|
|
};
|
|
|
|
template <typename ElementComparator>
|
|
class ComparatorAdapter
|
|
{
|
|
public:
|
|
ComparatorAdapter (ElementComparator& comparator_) noexcept : 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 <SharedObject> SharedObjectPtr;
|
|
|
|
SharedObjectPtr object;
|
|
ListenerList <Listener> 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);
|
|
|
|
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
|
|
Process::setCurrentModuleInstanceHandle() method.
|
|
|
|
@see shutdownJuce_GUI()
|
|
*/
|
|
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()
|
|
*/
|
|
JUCE_API void JUCE_CALLTYPE shutdownJuce_GUI();
|
|
|
|
/** 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 JUCE_ANDROID
|
|
#define START_JUCE_APPLICATION(AppClass) \
|
|
JUCE_NAMESPACE::JUCEApplication* juce_CreateApplication() { return new AppClass(); }
|
|
|
|
#elif 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::Process::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::Process::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::Process::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_RELATIVETIME_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RESULT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_SINGLETON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_Singleton.h ***/
|
|
#ifndef __JUCE_SINGLETON_JUCEHEADER__
|
|
#define __JUCE_SINGLETON_JUCEHEADER__
|
|
|
|
/**
|
|
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 == nullptr) \
|
|
{\
|
|
const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \
|
|
\
|
|
if (_singletonInstance == nullptr) \
|
|
{ \
|
|
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() noexcept\
|
|
{ \
|
|
return _singletonInstance; \
|
|
} \
|
|
\
|
|
static void JUCE_CALLTYPE deleteInstance() \
|
|
{ \
|
|
const JUCE_NAMESPACE::ScopedLock sl (_singletonLock); \
|
|
if (_singletonInstance != nullptr) \
|
|
{ \
|
|
classname* const old = _singletonInstance; \
|
|
_singletonInstance = nullptr; \
|
|
delete old; \
|
|
} \
|
|
} \
|
|
\
|
|
void clearSingletonInstance() noexcept\
|
|
{ \
|
|
if (_singletonInstance == this) \
|
|
_singletonInstance = nullptr; \
|
|
}
|
|
|
|
/** 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 = nullptr; \
|
|
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 == nullptr) \
|
|
{ \
|
|
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() noexcept\
|
|
{ \
|
|
return _singletonInstance; \
|
|
} \
|
|
\
|
|
static void deleteInstance() \
|
|
{ \
|
|
if (_singletonInstance != nullptr) \
|
|
{ \
|
|
classname* const old = _singletonInstance; \
|
|
_singletonInstance = nullptr; \
|
|
delete old; \
|
|
} \
|
|
} \
|
|
\
|
|
void clearSingletonInstance() noexcept\
|
|
{ \
|
|
if (_singletonInstance == this) \
|
|
_singletonInstance = nullptr; \
|
|
}
|
|
|
|
/**
|
|
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 == nullptr) \
|
|
_singletonInstance = new classname(); \
|
|
\
|
|
return _singletonInstance; \
|
|
} \
|
|
\
|
|
static inline classname* getInstanceWithoutCreating() noexcept\
|
|
{ \
|
|
return _singletonInstance; \
|
|
} \
|
|
\
|
|
static void deleteInstance() \
|
|
{ \
|
|
if (_singletonInstance != nullptr) \
|
|
{ \
|
|
classname* const old = _singletonInstance; \
|
|
_singletonInstance = nullptr; \
|
|
delete old; \
|
|
} \
|
|
} \
|
|
\
|
|
void clearSingletonInstance() noexcept\
|
|
{ \
|
|
if (_singletonInstance == this) \
|
|
_singletonInstance = nullptr; \
|
|
}
|
|
|
|
/** 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 = nullptr;
|
|
|
|
#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,
|
|
|
|
See also the JUCE_VERSION, JUCE_MAJOR_VERSION and JUCE_MINOR_VERSION macros.
|
|
*/
|
|
static String getJUCEVersion();
|
|
|
|
/** The set of possible results of the getOperatingSystemType() method.
|
|
*/
|
|
enum OperatingSystemType
|
|
{
|
|
UnknownOS = 0,
|
|
|
|
MacOSX = 0x1000,
|
|
Linux = 0x2000,
|
|
Android = 0x3000,
|
|
|
|
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 String getOperatingSystemName();
|
|
|
|
/** Returns true if the OS is 64-bit, or false for a 32-bit OS.
|
|
*/
|
|
static bool isOperatingSystem64Bit();
|
|
|
|
#if JUCE_MAC || DOXYGEN
|
|
/** OSX 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
|
|
|
|
/** Returns the current user's name, if available.
|
|
@see getFullUserName()
|
|
*/
|
|
static 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 String getFullUserName();
|
|
|
|
/** Returns the host-name of the computer. */
|
|
static String getComputerName();
|
|
|
|
// 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 String getCpuVendor();
|
|
|
|
/** Checks whether Intel MMX instructions are available. */
|
|
static bool hasMMX() noexcept { return getCPUFlags().hasMMX; }
|
|
|
|
/** Checks whether Intel SSE instructions are available. */
|
|
static bool hasSSE() noexcept { return getCPUFlags().hasSSE; }
|
|
|
|
/** Checks whether Intel SSE2 instructions are available. */
|
|
static bool hasSSE2() noexcept { return getCPUFlags().hasSSE2; }
|
|
|
|
/** Checks whether AMD 3DNOW instructions are available. */
|
|
static bool has3DNow() noexcept { return getCPUFlags().has3DNow; }
|
|
|
|
/** Returns the number of CPUs. */
|
|
static int getNumCpus() noexcept { return getCPUFlags().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();
|
|
|
|
private:
|
|
|
|
struct CPUFlags
|
|
{
|
|
CPUFlags();
|
|
|
|
int numCpus;
|
|
bool hasMMX : 1;
|
|
bool hasSSE : 1;
|
|
bool hasSSE2 : 1;
|
|
bool has3DNow : 1;
|
|
};
|
|
|
|
SystemStats();
|
|
static const CPUFlags& getCPUFlags();
|
|
|
|
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() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
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 noexcept { 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 noexcept;
|
|
|
|
/** Decrypts a pair of 32-bit integers. */
|
|
void decrypt (uint32& data1, uint32& data2) const noexcept;
|
|
|
|
private:
|
|
|
|
uint32 p[18];
|
|
HeapBlock <uint32> s[4];
|
|
|
|
uint32 F (uint32 x) const noexcept;
|
|
|
|
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. */
|
|
MemoryBlock getRawChecksumData() const;
|
|
|
|
/** Returns the checksum as a 32-digit hex string. */
|
|
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&, 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns true if no bits are set. */
|
|
bool isZero() const noexcept;
|
|
|
|
/** Returns true if the value is 1. */
|
|
bool isOne() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Resets the value to 0. */
|
|
void clear();
|
|
|
|
/** Clears a particular bit in the number. */
|
|
void clearBit (int bitNumber) noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the index of the highest set bit in the number.
|
|
If the value is zero, this will return -1.
|
|
*/
|
|
int getHighestBit() const noexcept;
|
|
|
|
// 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--();
|
|
BigInteger operator++ (int);
|
|
BigInteger operator-- (int);
|
|
|
|
BigInteger operator-() const;
|
|
BigInteger operator+ (const BigInteger& other) const;
|
|
BigInteger operator- (const BigInteger& other) const;
|
|
BigInteger operator* (const BigInteger& other) const;
|
|
BigInteger operator/ (const BigInteger& other) const;
|
|
BigInteger operator| (const BigInteger& other) const;
|
|
BigInteger operator& (const BigInteger& other) const;
|
|
BigInteger operator^ (const BigInteger& other) const;
|
|
BigInteger operator% (const BigInteger& other) const;
|
|
BigInteger operator<< (int numBitsToShift) const;
|
|
BigInteger operator>> (int numBitsToShift) const;
|
|
|
|
bool operator== (const BigInteger& other) const noexcept;
|
|
bool operator!= (const BigInteger& other) const noexcept;
|
|
bool operator< (const BigInteger& other) const noexcept;
|
|
bool operator<= (const BigInteger& other) const noexcept;
|
|
bool operator> (const BigInteger& other) const noexcept;
|
|
bool operator>= (const BigInteger& other) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
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 noexcept;
|
|
|
|
/** Changes the sign of the number to be positive or negative.
|
|
@see isNegative, negate
|
|
*/
|
|
void setNegative (bool shouldBeNegative) noexcept;
|
|
|
|
/** Inverts the sign of the number.
|
|
@see isNegative, setNegative
|
|
*/
|
|
void negate() noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
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
|
|
*/
|
|
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 <uint32> values;
|
|
int numValues, highestBit;
|
|
bool negative;
|
|
|
|
void ensureSize (int numVals);
|
|
void shiftLeft (int bits, int startBit);
|
|
void shiftRight (int bits, int startBit);
|
|
static BigInteger simpleGCD (BigInteger* m, BigInteger* n);
|
|
|
|
static inline int bitToIndex (const int bit) noexcept { return bit >> 5; }
|
|
static inline uint32 bitToMask (const int bit) noexcept { 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 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 noexcept;
|
|
bool operator!= (const RSAKey& other) const noexcept;
|
|
|
|
/** Turns the key into a string representation.
|
|
|
|
This can be reloaded using the constructor that takes a string.
|
|
*/
|
|
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 = nullptr,
|
|
int numRandomSeeds = 0);
|
|
|
|
protected:
|
|
|
|
BigInteger part1, part2;
|
|
|
|
private:
|
|
|
|
static 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_SHA256_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_SHA256.h ***/
|
|
#ifndef __JUCE_SHA256_JUCEHEADER__
|
|
#define __JUCE_SHA256_JUCEHEADER__
|
|
|
|
/**
|
|
SHA-256 secure hash generator.
|
|
|
|
Create one of these objects from a block of source data or a string, and it
|
|
represents the SHA-256 hash of that data.
|
|
|
|
You can retrieve the hash as a raw 32-byte block, or as a 64-digit hex string.
|
|
*/
|
|
class JUCE_API SHA256
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty SHA256 object.
|
|
The default constructor just creates a hash filled with zeros. (This is not
|
|
equal to the hash of an empty block of data).
|
|
*/
|
|
SHA256();
|
|
|
|
/** Destructor. */
|
|
~SHA256();
|
|
|
|
/** Creates a copy of another SHA256. */
|
|
SHA256 (const SHA256& other);
|
|
|
|
/** Copies another SHA256. */
|
|
SHA256& operator= (const SHA256& other);
|
|
|
|
/** Creates a hash from a block of raw data. */
|
|
explicit SHA256 (const MemoryBlock& data);
|
|
|
|
/** Creates a hash from a block of raw data. */
|
|
SHA256 (const void* data, size_t numBytes);
|
|
|
|
/** Creates a hash from the contents of a stream.
|
|
|
|
This will read from the stream until the stream is exhausted, or until
|
|
maxBytesToRead bytes have been read. If maxBytesToRead is negative, the entire
|
|
stream will be read.
|
|
*/
|
|
SHA256 (InputStream& input, int64 maxBytesToRead = -1);
|
|
|
|
/** Reads a file and generates the hash of its contents.
|
|
If the file can't be opened, the hash will be left uninitialised (i.e. full
|
|
of zeros).
|
|
*/
|
|
explicit SHA256 (const File& file);
|
|
|
|
/** Returns the hash as a 32-byte block of data. */
|
|
MemoryBlock getRawData() const;
|
|
|
|
/** Returns the checksum as a 64-digit hex string. */
|
|
String toHexString() const;
|
|
|
|
bool operator== (const SHA256& other) const noexcept;
|
|
bool operator!= (const SHA256& other) const noexcept;
|
|
|
|
private:
|
|
|
|
uint8 result [32];
|
|
|
|
JUCE_LEAK_DETECTOR (SHA256);
|
|
};
|
|
|
|
#endif // __JUCE_SHA256_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_SHA256.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<Pimpl>;
|
|
ScopedPointer<Pimpl> pimpl;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NativeIterator);
|
|
};
|
|
|
|
friend class ScopedPointer<NativeIterator::Pimpl>;
|
|
NativeIterator fileFinder;
|
|
String wildCard, path;
|
|
int index;
|
|
mutable int totalNumFiles;
|
|
const int whatToLookFor;
|
|
const bool isRecursive;
|
|
bool hasBeenAdvanced;
|
|
ScopedPointer <DirectoryIterator> 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();
|
|
|
|
/** Returns the file that this stream is reading from. */
|
|
const File& getFile() const noexcept { return file; }
|
|
|
|
/** Returns the status of the file stream.
|
|
The result will be ok if the file opened successfully. If an error occurs while
|
|
opening or reading from the file, this will contain an error message.
|
|
*/
|
|
Result getStatus() const { return status; }
|
|
|
|
int64 getTotalLength();
|
|
int read (void* destBuffer, int maxBytesToRead);
|
|
bool isExhausted();
|
|
int64 getPosition();
|
|
bool setPosition (int64 pos);
|
|
|
|
private:
|
|
|
|
File file;
|
|
void* fileHandle;
|
|
int64 currentPosition, totalSize;
|
|
Result status;
|
|
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 the status of the file stream.
|
|
The result will be ok if the file opened successfully. If an error occurs while
|
|
opening or writing to the file, this will contain an error message.
|
|
*/
|
|
Result getStatus() const { return status; }
|
|
|
|
/** Returns true if the stream couldn't be opened for some reason.
|
|
@see getResult()
|
|
*/
|
|
bool failedToOpen() const { return status.failed(); }
|
|
|
|
void flush();
|
|
int64 getPosition();
|
|
bool setPosition (int64 pos);
|
|
bool write (const void* data, int numBytes);
|
|
void writeRepeatedByte (uint8 byte, int numTimesToRepeat);
|
|
|
|
private:
|
|
|
|
File file;
|
|
void* fileHandle;
|
|
Result status;
|
|
int64 currentPosition;
|
|
int bufferSize, bytesInBuffer;
|
|
HeapBlock <char> buffer;
|
|
|
|
void openHandle();
|
|
void closeHandle();
|
|
void flushInternal();
|
|
bool flushBuffer();
|
|
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
|
|
*/
|
|
File operator[] (int index) const;
|
|
|
|
/** Returns the search path as a semicolon-separated list of directories. */
|
|
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<File>& 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_MEMORYMAPPEDFILE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MemoryMappedFile.h ***/
|
|
#ifndef __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__
|
|
#define __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__
|
|
|
|
/**
|
|
Maps a file into virtual memory for easy reading and/or writing.
|
|
*/
|
|
class JUCE_API MemoryMappedFile
|
|
{
|
|
public:
|
|
/** The read/write flags used when opening a memory mapped file. */
|
|
enum AccessMode
|
|
{
|
|
readOnly, /**< Indicates that the memory can only be read. */
|
|
readWrite /**< Indicates that the memory can be read and written to - changes that are
|
|
made will be flushed back to disk at the whim of the OS. */
|
|
};
|
|
|
|
/** Opens a file and maps it to an area of virtual memory.
|
|
|
|
The file should already exist, and should already be the size that you want to work with
|
|
when you call this. If the file is resized after being opened, the behaviour is undefined.
|
|
|
|
If the file exists and the operation succeeds, the getData() and getSize() methods will
|
|
return the location and size of the data that can be read or written. Note that the entire
|
|
file is not read into memory immediately - the OS simply creates a virtual mapping, which
|
|
will lazily pull the data into memory when blocks are accessed.
|
|
|
|
If the file can't be opened for some reason, the getData() method will return a null pointer.
|
|
*/
|
|
MemoryMappedFile (const File& file, AccessMode mode);
|
|
|
|
/** Destructor. */
|
|
~MemoryMappedFile();
|
|
|
|
/** Returns the address at which this file has been mapped, or a null pointer if
|
|
the file couldn't be successfully mapped.
|
|
*/
|
|
void* getData() const noexcept { return address; }
|
|
|
|
/** Returns the number of bytes of data that are available for reading or writing.
|
|
This will normally be the size of the file.
|
|
*/
|
|
size_t getSize() const noexcept { return length; }
|
|
|
|
private:
|
|
|
|
void* address;
|
|
size_t length;
|
|
|
|
#if JUCE_WINDOWS
|
|
void* fileHandle;
|
|
#else
|
|
int fileHandle;
|
|
#endif
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MemoryMappedFile);
|
|
};
|
|
|
|
#endif // __JUCE_MEMORYMAPPEDFILE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MemoryMappedFile.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. */
|
|
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 <FileOutputStream> out (temp.getFile().createOutputStream());
|
|
|
|
if (out != nullptr)
|
|
{
|
|
out->write ( ...etc )
|
|
out->flush();
|
|
out = nullptr; // (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() noexcept {}
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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);
|
|
|
|
/** Used to create a new zip file.
|
|
|
|
Create a ZipFile::Builder object, and call its addFile() method to add some files,
|
|
then you can write it to a stream with write().
|
|
|
|
Currently this just stores the files with no compression.. That will be added
|
|
soon!
|
|
*/
|
|
class Builder
|
|
{
|
|
public:
|
|
Builder();
|
|
~Builder();
|
|
|
|
/** Adds a file while should be added to the archive.
|
|
The file isn't read immediately, all the files will be read later when the writeToStream()
|
|
method is called.
|
|
|
|
The compressionLevel can be between 0 (no compression), and 9 (maximum compression).
|
|
If the storedPathName parameter is specified, you can customise the partial pathname that
|
|
will be stored for this file.
|
|
*/
|
|
void addFile (const File& fileToAdd, int compressionLevel,
|
|
const String& storedPathName = String::empty);
|
|
|
|
/** Generates the zip file, writing it to the specified stream. */
|
|
bool writeToStream (OutputStream& target) const;
|
|
|
|
private:
|
|
class Item;
|
|
friend class OwnedArray<Item>;
|
|
OwnedArray<Item> items;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Builder);
|
|
};
|
|
|
|
private:
|
|
|
|
class ZipInputStream;
|
|
class ZipFilenameComparator;
|
|
class ZipEntryInfo;
|
|
friend class ZipInputStream;
|
|
friend class ZipFilenameComparator;
|
|
friend class ZipEntryInfo;
|
|
|
|
OwnedArray <ZipEntryInfo> entries;
|
|
CriticalSection lock;
|
|
InputStream* inputStream;
|
|
ScopedPointer <InputStream> streamToDelete;
|
|
ScopedPointer <InputSource> 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<MACAddress>& 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 noexcept { return asBytes; }
|
|
|
|
/** Returns a dash-separated string in the form "11-22-33-44-55-66" */
|
|
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 noexcept;
|
|
|
|
/** Returns true if this address is null (00-00-00-00-00-00). */
|
|
bool isNull() const noexcept;
|
|
|
|
bool operator== (const MACAddress& other) const noexcept;
|
|
bool operator!= (const MACAddress& other) const noexcept;
|
|
|
|
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 noexcept { return connected; }
|
|
|
|
/** Closes the connection. */
|
|
void close();
|
|
|
|
/** Returns the name of the currently connected host. */
|
|
const String& getHostName() const noexcept { return hostName; }
|
|
|
|
/** Returns the port number that's currently open. */
|
|
int getPort() const noexcept { return portNumber; }
|
|
|
|
/** True if the socket is connected to this machine rather than over the network. */
|
|
bool isLocal() const noexcept;
|
|
|
|
/** 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 noexcept { return connected; }
|
|
|
|
/** Closes the connection. */
|
|
void close();
|
|
|
|
/** Returns the name of the currently connected host. */
|
|
const String& getHostName() const noexcept { return hostName; }
|
|
|
|
/** Returns the port number that's currently open. */
|
|
int getPort() const noexcept { return portNumber; }
|
|
|
|
/** True if the socket is connected to this machine rather than over the network. */
|
|
bool isLocal() const noexcept;
|
|
|
|
/** 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__
|
|
|
|
class InputStream;
|
|
class XmlElement;
|
|
|
|
/**
|
|
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.
|
|
*/
|
|
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".
|
|
*/
|
|
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".
|
|
*/
|
|
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).
|
|
*/
|
|
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().
|
|
*/
|
|
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 = nullptr,
|
|
void* progressCallbackContext = nullptr,
|
|
const String& extraHeaders = String::empty,
|
|
int connectionTimeOutMs = 0,
|
|
StringPairArray* responseHeaders = nullptr) 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
|
|
*/
|
|
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 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 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__
|
|
|
|
|
|
/*** Start of inlined file: juce_OptionalScopedPointer.h ***/
|
|
#ifndef __JUCE_OPTIONALSCOPEDPOINTER_JUCEHEADER__
|
|
#define __JUCE_OPTIONALSCOPEDPOINTER_JUCEHEADER__
|
|
|
|
/**
|
|
Holds a pointer to an object which can optionally be deleted when this pointer
|
|
goes out of scope.
|
|
|
|
This acts in many ways like a ScopedPointer, but allows you to specify whether or
|
|
not the object is deleted.
|
|
|
|
@see ScopedPointer
|
|
*/
|
|
template <class ObjectType>
|
|
class OptionalScopedPointer
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty OptionalScopedPointer. */
|
|
OptionalScopedPointer() : shouldDelete (false) {}
|
|
|
|
/** Creates an OptionalScopedPointer to point to a given object, and specifying whether
|
|
the OptionalScopedPointer will delete it.
|
|
|
|
If takeOwnership is true, then the OptionalScopedPointer will act like a ScopedPointer,
|
|
deleting the object when it is itself deleted. If this parameter is false, then the
|
|
OptionalScopedPointer just holds a normal pointer to the object, and won't delete it.
|
|
*/
|
|
OptionalScopedPointer (ObjectType* objectToHold, bool takeOwnership)
|
|
: object (objectToHold), shouldDelete (takeOwnership)
|
|
{
|
|
}
|
|
|
|
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
|
|
|
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
|
|
as ownership of the managed object is transferred to this object.
|
|
|
|
The flag to indicate whether or not to delete the managed object is also
|
|
copied from the source object.
|
|
*/
|
|
OptionalScopedPointer (OptionalScopedPointer& objectToTransferFrom)
|
|
: object (objectToTransferFrom.release()),
|
|
shouldDelete (objectToTransferFrom.shouldDelete)
|
|
{
|
|
}
|
|
|
|
/** Takes ownership of the object that another OptionalScopedPointer holds.
|
|
|
|
Like a normal ScopedPointer, the objectToTransferFrom object will become null,
|
|
as ownership of the managed object is transferred to this object.
|
|
|
|
The ownership flag that says whether or not to delete the managed object is also
|
|
copied from the source object.
|
|
*/
|
|
OptionalScopedPointer& operator= (OptionalScopedPointer& objectToTransferFrom)
|
|
{
|
|
if (object != objectToTransferFrom.object)
|
|
{
|
|
clear();
|
|
object = objectToTransferFrom.object;
|
|
}
|
|
|
|
shouldDelete = objectToTransferFrom.shouldDelete;
|
|
return *this;
|
|
}
|
|
|
|
/** The destructor may or may not delete the object that is being held, depending on the
|
|
takeOwnership flag that was specified when the object was first passed into an
|
|
OptionalScopedPointer constructor.
|
|
*/
|
|
~OptionalScopedPointer()
|
|
{
|
|
clear();
|
|
}
|
|
|
|
/** Returns the object that this pointer is managing. */
|
|
inline operator ObjectType*() const noexcept { return object; }
|
|
|
|
/** Returns the object that this pointer is managing. */
|
|
inline ObjectType& operator*() const noexcept { return *object; }
|
|
|
|
/** Lets you access methods and properties of the object that this pointer is holding. */
|
|
inline ObjectType* operator->() const noexcept { return object; }
|
|
|
|
/** Removes the current object from this OptionalScopedPointer without deleting it.
|
|
This will return the current object, and set this OptionalScopedPointer to a null pointer.
|
|
*/
|
|
ObjectType* release() noexcept { return object.release(); }
|
|
|
|
/** Resets this pointer to null, possibly deleting the object that it holds, if it has
|
|
ownership of it.
|
|
*/
|
|
void clear()
|
|
{
|
|
if (! shouldDelete)
|
|
object.release();
|
|
}
|
|
|
|
/** Swaps this object with another OptionalScopedPointer.
|
|
The two objects simply exchange their states.
|
|
*/
|
|
void swapWith (OptionalScopedPointer<ObjectType>& other) noexcept
|
|
{
|
|
object.swapWith (other.object);
|
|
std::swap (shouldDelete, other.shouldDelete);
|
|
}
|
|
|
|
private:
|
|
|
|
ScopedPointer<ObjectType> object;
|
|
bool shouldDelete;
|
|
};
|
|
|
|
#endif // __JUCE_OPTIONALSCOPEDPOINTER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_OptionalScopedPointer.h ***/
|
|
|
|
/** 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);
|
|
String readString();
|
|
bool isExhausted();
|
|
|
|
private:
|
|
|
|
OptionalScopedPointer<InputStream> source;
|
|
int bufferSize;
|
|
int64 position, lastReadPos, bufferStart, bufferOverlap;
|
|
HeapBlock <char> 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:
|
|
|
|
OptionalScopedPointer<OutputStream> destStream;
|
|
HeapBlock <uint8> buffer;
|
|
class GZIPCompressorHelper;
|
|
friend class ScopedPointer <GZIPCompressorHelper>;
|
|
ScopedPointer <GZIPCompressorHelper> helper;
|
|
bool doNextBlock();
|
|
void flushInternal();
|
|
|
|
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:
|
|
OptionalScopedPointer<InputStream> sourceStream;
|
|
const int64 uncompressedStreamLength;
|
|
const bool noWrap;
|
|
bool isEof;
|
|
int activeBufferSize;
|
|
int64 originalSourcePos, currentPos;
|
|
HeapBlock <uint8> buffer;
|
|
|
|
class GZIPDecompressHelper;
|
|
friend class ScopedPointer <GZIPDecompressHelper>;
|
|
ScopedPointer <GZIPDecompressHelper> 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;
|
|
HeapBlock<char> internalCopy;
|
|
|
|
void createInternalCopy();
|
|
|
|
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 noexcept;
|
|
|
|
/** Returns the number of bytes of data that have been written to the stream.
|
|
|
|
@see getData
|
|
*/
|
|
size_t getDataSize() const noexcept { return size; }
|
|
|
|
/** Resets the stream, clearing any data that has been written to it so far. */
|
|
void reset() noexcept;
|
|
|
|
/** 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. */
|
|
String toUTF8() const;
|
|
|
|
/** Attempts to detect the encoding of the data and convert it to a string.
|
|
@see String::createStringFromData
|
|
*/
|
|
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);
|
|
void writeRepeatedByte (uint8 byte, int numTimesToRepeat);
|
|
|
|
private:
|
|
|
|
MemoryBlock& data;
|
|
MemoryBlock internalBlock;
|
|
size_t position, size;
|
|
|
|
void trimExternalBlockSize();
|
|
void prepareToWrite (int numBytes);
|
|
|
|
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:
|
|
OptionalScopedPointer<InputStream> source;
|
|
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::Scope 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. */
|
|
String toString() const;
|
|
|
|
/** Returns an expression which is an addtion operation of two existing expressions. */
|
|
Expression operator+ (const Expression& other) const;
|
|
/** Returns an expression which is a subtraction operation of two existing expressions. */
|
|
Expression operator- (const Expression& other) const;
|
|
/** Returns an expression which is a multiplication operation of two existing expressions. */
|
|
Expression operator* (const Expression& other) const;
|
|
/** Returns an expression which is a division operation of two existing expressions. */
|
|
Expression operator/ (const Expression& other) const;
|
|
/** Returns an expression which performs a negation operation on an existing expression. */
|
|
Expression operator-() const;
|
|
|
|
/** Returns an Expression which is an identifier reference. */
|
|
static Expression symbol (const String& symbol);
|
|
|
|
/** Returns an Expression which is a function call. */
|
|
static Expression function (const String& functionName, const Array<Expression>& parameters);
|
|
|
|
/** Returns an Expression which parses a string from a character pointer, and updates the pointer
|
|
to indicate where it finished.
|
|
|
|
The pointer 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 Expression parse (String::CharPointerType& stringToParse);
|
|
|
|
/** When evaluating an Expression object, this class is used to resolve symbols and
|
|
perform functions that the expression uses.
|
|
*/
|
|
class JUCE_API Scope
|
|
{
|
|
public:
|
|
Scope();
|
|
virtual ~Scope();
|
|
|
|
/** Returns some kind of globally unique ID that identifies this scope. */
|
|
virtual String getScopeUID() const;
|
|
|
|
/** 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 Expression getSymbolValue (const String& symbol) 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 numParameters) const;
|
|
|
|
/** Used as a callback by the Scope::visitRelativeScope() method.
|
|
You should never create an instance of this class yourself, it's used by the
|
|
expression evaluation code.
|
|
*/
|
|
class Visitor
|
|
{
|
|
public:
|
|
virtual ~Visitor() {}
|
|
virtual void visit (const Scope&) = 0;
|
|
};
|
|
|
|
/** Creates a Scope object for a named scope, and then calls a visitor
|
|
to do some kind of processing with this new scope.
|
|
|
|
If the name is valid, this method must create a suitable (temporary) Scope
|
|
object to represent it, and must call the Visitor::visit() method with this
|
|
new scope.
|
|
*/
|
|
virtual void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
|
|
};
|
|
|
|
/** Evaluates this expression, without using a Scope.
|
|
Without a Scope, no symbols can be used, and only basic functions such as sin, cos, tan,
|
|
min, max are available.
|
|
To find out about any errors during evaluation, use the other version of this method which
|
|
takes a String parameter.
|
|
*/
|
|
double evaluate() const;
|
|
|
|
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
|
or functions that it uses.
|
|
To find out about any errors during evaluation, use the other version of this method which
|
|
takes a String parameter.
|
|
*/
|
|
double evaluate (const Scope& scope) const;
|
|
|
|
/** Evaluates this expression, providing a scope that should be able to evaluate any symbols
|
|
or functions that it uses.
|
|
*/
|
|
double evaluate (const Scope& scope, String& evaluationError) 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 the original expression.
|
|
|
|
@throws Expression::EvaluationError
|
|
*/
|
|
Expression adjustedToGiveNewResult (double targetValue, const Scope& scope) const;
|
|
|
|
/** Represents a symbol that is used in an Expression. */
|
|
struct Symbol
|
|
{
|
|
Symbol (const String& scopeUID, const String& symbolName);
|
|
bool operator== (const Symbol&) const noexcept;
|
|
bool operator!= (const Symbol&) const noexcept;
|
|
|
|
String scopeUID; /**< The unique ID of the Scope that contains this symbol. */
|
|
String symbolName; /**< The name of the symbol. */
|
|
};
|
|
|
|
/** Returns a copy of this expression in which all instances of a given symbol have been renamed. */
|
|
Expression withRenamedSymbol (const Symbol& oldSymbol, const String& newName, const Scope& scope) const;
|
|
|
|
/** Returns true if this expression makes use of the specified symbol.
|
|
If a suitable scope 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 scope parameter is null, this just checks
|
|
whether the expression contains any direct references to the symbol.
|
|
|
|
@throws Expression::EvaluationError
|
|
*/
|
|
bool referencesSymbol (const Symbol& symbol, const Scope& scope) const;
|
|
|
|
/** Returns true if this expression contains any symbols. */
|
|
bool usesAnySymbols() const;
|
|
|
|
/** Returns a list of all symbols that may be needed to resolve this expression in the given scope. */
|
|
void findReferencedSymbols (Array<Symbol>& results, const Scope& scope) const;
|
|
|
|
/** An exception that can be thrown by Expression::parse(). */
|
|
class ParseError : public std::exception
|
|
{
|
|
public:
|
|
ParseError (const String& message);
|
|
|
|
String description;
|
|
};
|
|
|
|
/** Expression type.
|
|
@see Expression::getType()
|
|
*/
|
|
enum Type
|
|
{
|
|
constantType,
|
|
functionType,
|
|
operatorType,
|
|
symbolType
|
|
};
|
|
|
|
/** Returns the type of this expression. */
|
|
Type getType() const noexcept;
|
|
|
|
/** If this expression is a symbol, function or operator, this returns its identifier. */
|
|
String getSymbolOrFunction() const;
|
|
|
|
/** Returns the number of inputs to this expression.
|
|
@see getInput
|
|
*/
|
|
int getNumInputs() const;
|
|
|
|
/** Retrieves one of the inputs to this expression.
|
|
@see getNumInputs
|
|
*/
|
|
Expression getInput (int index) const;
|
|
|
|
private:
|
|
|
|
class Term;
|
|
class Helpers;
|
|
friend class Term;
|
|
friend class Helpers;
|
|
friend class ScopedPointer<Term>;
|
|
friend class ReferenceCountedObjectPtr<Term>;
|
|
ReferenceCountedObjectPtr<Term> 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 random number generator.
|
|
|
|
You can create a Random object and use it to generate a sequence of random numbers.
|
|
*/
|
|
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) noexcept;
|
|
|
|
/** Creates a Random object using a random seed value.
|
|
Internally, this calls setSeedRandomly() to randomise the seed.
|
|
*/
|
|
Random();
|
|
|
|
/** Destructor. */
|
|
~Random() noexcept;
|
|
|
|
/** Returns the next random 32 bit integer.
|
|
|
|
@returns a random integer from the full range 0x80000000 to 0x7fffffff
|
|
*/
|
|
int nextInt() noexcept;
|
|
|
|
/** Returns the next random number, limited to a given range.
|
|
The maxValue parameter may not be negative, or zero.
|
|
@returns a random integer between 0 (inclusive) and maxValue (exclusive).
|
|
*/
|
|
int nextInt (int maxValue) noexcept;
|
|
|
|
/** Returns the next 64-bit random number.
|
|
|
|
@returns a random integer from the full range 0x8000000000000000 to 0x7fffffffffffffff
|
|
*/
|
|
int64 nextInt64() noexcept;
|
|
|
|
/** Returns the next random floating-point number.
|
|
|
|
@returns a random value in the range 0 to 1.0
|
|
*/
|
|
float nextFloat() noexcept;
|
|
|
|
/** Returns the next random floating-point number.
|
|
|
|
@returns a random value in the range 0 to 1.0
|
|
*/
|
|
double nextDouble() noexcept;
|
|
|
|
/** Returns the next random boolean value.
|
|
*/
|
|
bool nextBool() noexcept;
|
|
|
|
/** Returns a BigInteger containing a random number.
|
|
|
|
@returns a random value in the range 0 to (maximumValue - 1).
|
|
*/
|
|
BigInteger nextLargeNumber (const BigInteger& maximumValue);
|
|
|
|
/** Sets a range of bits in a BigInteger to random values. */
|
|
void fillBitsRandomly (BigInteger& arrayToChange, int startBit, int numBits);
|
|
|
|
/** Resets this Random object to a given seed value. */
|
|
void setSeed (int64 newSeed) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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();
|
|
|
|
/** The overhead of creating a new Random object is fairly small, but if you want to avoid
|
|
it, you can call this method to get a global shared Random object.
|
|
|
|
It's not thread-safe though, so threads should use their own Random object, otherwise
|
|
you run the risk of your random numbers becoming.. erm.. randomly corrupted..
|
|
*/
|
|
static Random& getSystemRandom() noexcept;
|
|
|
|
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_OPTIONALSCOPEDPOINTER_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<MyObject>::SharedRef& getWeakReference()
|
|
{
|
|
return masterReference (this);
|
|
}
|
|
|
|
private:
|
|
// You need to embed one of these inside your object. It can be private.
|
|
WeakReference<MyObject>::Master masterReference;
|
|
};
|
|
|
|
// Here's an example of using a pointer..
|
|
|
|
MyObject* n = new MyObject();
|
|
WeakReference<MyObject> 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 ObjectType, class ReferenceCountingType = ReferenceCountedObject>
|
|
class WeakReference
|
|
{
|
|
public:
|
|
/** Creates a null SafePointer. */
|
|
inline WeakReference() noexcept {}
|
|
|
|
/** Creates a WeakReference that points at the given object. */
|
|
WeakReference (ObjectType* const object) : holder (object != nullptr ? object->getWeakReference() : nullptr) {}
|
|
|
|
/** Creates a copy of another WeakReference. */
|
|
WeakReference (const WeakReference& other) noexcept : 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 != nullptr) ? newObject->getWeakReference() : nullptr; return *this; }
|
|
|
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
|
ObjectType* get() const noexcept { return holder != nullptr ? holder->get() : nullptr; }
|
|
|
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
|
operator ObjectType*() const noexcept { return get(); }
|
|
|
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
|
ObjectType* operator->() noexcept { return get(); }
|
|
|
|
/** Returns the object that this pointer refers to, or null if the object no longer exists. */
|
|
const ObjectType* operator->() const noexcept { 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 noexcept { return holder != nullptr && holder->get() == nullptr; }
|
|
|
|
bool operator== (ObjectType* const object) const noexcept { return get() == object; }
|
|
bool operator!= (ObjectType* const object) const noexcept { 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 ReferenceCountingType
|
|
{
|
|
public:
|
|
explicit SharedPointer (ObjectType* const owner_) noexcept : owner (owner_) {}
|
|
|
|
inline ObjectType* get() const noexcept { return owner; }
|
|
void clearPointer() noexcept { owner = nullptr; }
|
|
|
|
private:
|
|
ObjectType* volatile owner;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (SharedPointer);
|
|
};
|
|
|
|
typedef ReferenceCountedObjectPtr<SharedPointer> 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() noexcept {}
|
|
|
|
~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 == nullptr || sharedPointer->get() == nullptr);
|
|
}
|
|
|
|
/** 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 == nullptr)
|
|
{
|
|
sharedPointer = new SharedPointer (object);
|
|
}
|
|
else
|
|
{
|
|
// You're trying to create a weak reference to an object that has already been deleted!!
|
|
jassert (sharedPointer->get() != nullptr);
|
|
}
|
|
|
|
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 != nullptr)
|
|
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_CHARPOINTER_ASCII_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CHARPOINTER_UTF16_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CHARPOINTER_UTF32_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CHARPOINTER_UTF8_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_IDENTIFIER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_JSON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_JSON.h ***/
|
|
#ifndef __JUCE_JSON_JUCEHEADER__
|
|
#define __JUCE_JSON_JUCEHEADER__
|
|
|
|
class InputStream;
|
|
class OutputStream;
|
|
class File;
|
|
|
|
/**
|
|
Contains static methods for converting JSON-formatted text to and from var objects.
|
|
|
|
The var class is structurally compatible with JSON-formatted data, so these
|
|
functions allow you to parse JSON into a var object, and to convert a var
|
|
object to JSON-formatted text.
|
|
|
|
@see var
|
|
*/
|
|
class JSON
|
|
{
|
|
public:
|
|
|
|
/** Parses a string of JSON-formatted text, and returns a result code containing
|
|
any parse errors.
|
|
|
|
This will return the parsed structure in the parsedResult parameter, and will
|
|
return a Result object to indicate whether parsing was successful, and if not,
|
|
it will contain an error message.
|
|
|
|
If you're not interested in the error message, you can use one of the other
|
|
shortcut parse methods, which simply return a var::null if the parsing fails.
|
|
*/
|
|
static Result parse (const String& text, var& parsedResult);
|
|
|
|
/** Attempts to parse some JSON-formatted text, and returns the result as a var object.
|
|
|
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
|
*/
|
|
static var parse (const String& text);
|
|
|
|
/** Attempts to parse some JSON-formatted text from a file, and returns the result
|
|
as a var object.
|
|
|
|
Note that this is just a short-cut for reading the entire file into a string and
|
|
parsing the result.
|
|
|
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
|
*/
|
|
static var parse (const File& file);
|
|
|
|
/** Attempts to parse some JSON-formatted text from a stream, and returns the result
|
|
as a var object.
|
|
|
|
Note that this is just a short-cut for reading the entire stream into a string and
|
|
parsing the result.
|
|
|
|
If the parsing fails, this simply returns var::null - if you need to find out more
|
|
detail about the parse error, use the alternative parse() method which returns a Result.
|
|
*/
|
|
static var parse (InputStream& input);
|
|
|
|
/** Returns a string which contains a JSON-formatted representation of the var object.
|
|
If allOnOneLine is true, the result will be compacted into a single line of text
|
|
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
|
@see writeToStream
|
|
*/
|
|
static String toString (const var& objectToFormat,
|
|
bool allOnOneLine = false);
|
|
|
|
/** Writes a JSON-formatted representation of the var object to the given stream.
|
|
If allOnOneLine is true, the result will be compacted into a single line of text
|
|
with no carriage-returns. If false, it will be laid-out in a more human-readable format.
|
|
@see toString
|
|
*/
|
|
static void writeToStream (OutputStream& output,
|
|
const var& objectToFormat,
|
|
bool allOnOneLine = false);
|
|
|
|
private:
|
|
|
|
JSON(); // This class can't be instantiated - just use its static methods.
|
|
};
|
|
|
|
#endif // __JUCE_JSON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_JSON.h ***/
|
|
|
|
|
|
#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) \
|
|
JUCE_NAMESPACE::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 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 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.
|
|
*/
|
|
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
|
|
*/
|
|
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__
|
|
|
|
/*** 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() noexcept;
|
|
|
|
/** 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 String::CharPointerType 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 String::CharPointerType 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 String::CharPointerType getPooledString (const wchar_t* original);
|
|
|
|
/** Returns the number of strings in the pool. */
|
|
int size() const noexcept;
|
|
|
|
/** Returns one of the strings in the pool, by index. */
|
|
const String::CharPointerType operator[] (int index) const noexcept;
|
|
|
|
private:
|
|
Array <String> strings;
|
|
};
|
|
|
|
#endif // __JUCE_STRINGPOOL_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_StringPool.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_XMLDOCUMENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_XmlDocument.h ***/
|
|
#ifndef __JUCE_XMLDOCUMENT_JUCEHEADER__
|
|
#define __JUCE_XMLDOCUMENT_JUCEHEADER__
|
|
|
|
class InputSource;
|
|
|
|
/**
|
|
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 == nullptr)
|
|
{
|
|
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 != nullptr && 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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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;
|
|
String::CharPointerType input;
|
|
bool outOfData, errorOccurred;
|
|
|
|
String lastError, dtdText;
|
|
StringArray tokenisedDTD;
|
|
bool needToLoadDTD, ignoreEmptyTextElements;
|
|
ScopedPointer <InputSource> inputSource;
|
|
|
|
void setLastError (const String& desc, bool carryOn);
|
|
void skipHeader();
|
|
void skipNextWhiteSpace();
|
|
juce_wchar readNextChar() noexcept;
|
|
XmlElement* readNextElement (bool alsoParseSubElements);
|
|
void readChildElements (XmlElement* parent);
|
|
int findNextTokenLength() noexcept;
|
|
void readQuotedString (String& result);
|
|
void readEntity (String& result);
|
|
|
|
String getFileContents (const String& filename) const;
|
|
String expandEntity (const String& entity);
|
|
String expandExternalEntity (const String& entity);
|
|
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_DYNAMICLIBRARY_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DynamicLibrary.h ***/
|
|
#ifndef __JUCE_DYNAMICLIBRARY_JUCEHEADER__
|
|
#define __JUCE_DYNAMICLIBRARY_JUCEHEADER__
|
|
|
|
/**
|
|
Handles the opening and closing of DLLs.
|
|
|
|
This class can be used to open a DLL and get some function pointers from it.
|
|
Since the DLL is freed when this object is deleted, it's handy for managing
|
|
library lifetimes using RAII.
|
|
*/
|
|
class JUCE_API DynamicLibrary
|
|
{
|
|
public:
|
|
/** Creates an unopened DynamicLibrary object.
|
|
Call open() to actually open one.
|
|
*/
|
|
DynamicLibrary() noexcept : handle (nullptr) {}
|
|
|
|
/**
|
|
*/
|
|
DynamicLibrary (const String& name) : handle (nullptr) { open (name); }
|
|
|
|
/** Destructor.
|
|
If a library is currently open, it will be closed when this object is destroyed.
|
|
*/
|
|
~DynamicLibrary() { close(); }
|
|
|
|
/** Opens a DLL.
|
|
The name and the method by which it gets found is of course platform-specific, and
|
|
may or may not include a path, depending on the OS.
|
|
If a library is already open when this method is called, it will first close the library
|
|
before attempting to load the new one.
|
|
@returns true if the library was successfully found and opened.
|
|
*/
|
|
bool open (const String& name);
|
|
|
|
/** Releases the currently-open DLL, or has no effect if none was open. */
|
|
void close();
|
|
|
|
/** Tries to find a named function in the currently-open DLL, and returns a pointer to it.
|
|
If no library is open, or if the function isn't found, this will return a null pointer.
|
|
*/
|
|
void* getFunction (const String& functionName) noexcept;
|
|
|
|
/** Returns the platform-specific native library handle.
|
|
You'll need to cast this to whatever is appropriate for the OS that's in use.
|
|
*/
|
|
void* getNativeHandle() const noexcept { return handle; }
|
|
|
|
private:
|
|
void* handle;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DynamicLibrary);
|
|
};
|
|
|
|
#endif // __JUCE_DYNAMICLIBRARY_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DynamicLibrary.h ***/
|
|
|
|
|
|
#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 noexcept { return lockWasSuccessful; }
|
|
|
|
private:
|
|
|
|
InterProcessLock& lock_;
|
|
bool lockWasSuccessful;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (ScopedLockType);
|
|
};
|
|
|
|
private:
|
|
|
|
class Pimpl;
|
|
friend class ScopedPointer <Pimpl>;
|
|
ScopedPointer <Pimpl> 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();
|
|
|
|
/** Tries to launch the OS's default reader application for a given file or URL. */
|
|
static bool openDocument (const String& documentURL, const String& parameters);
|
|
|
|
/** Tries to launch the OS's default email application to let the user create a message. */
|
|
static bool openEmailWithAttachments (const String& targetEmailAddress,
|
|
const String& emailSubject,
|
|
const String& bodyText,
|
|
const StringArray& filesToAttach);
|
|
|
|
#if JUCE_WINDOWS || DOXYGEN
|
|
|
|
/** WINDOWS ONLY - This returns the HINSTANCE of the current module.
|
|
|
|
The return type is a void* to avoid being dependent on windows.h - just cast
|
|
it to a HINSTANCE to use it.
|
|
|
|
In a normal JUCE application, this will be automatically set to the module
|
|
handle of the executable.
|
|
|
|
If you've built a DLL and plan to use any JUCE messaging or windowing classes,
|
|
you'll need to make sure you call the setCurrentModuleInstanceHandle()
|
|
to provide the correct module handle in your DllMain() function, because
|
|
the system relies on the correct instance handle when opening windows.
|
|
*/
|
|
static void* JUCE_CALLTYPE getCurrentModuleInstanceHandle() noexcept;
|
|
|
|
/** WINDOWS ONLY - Sets a new module handle to be used by the library.
|
|
|
|
The parameter type is a void* to avoid being dependent on windows.h, but it actually
|
|
expects a HINSTANCE value.
|
|
|
|
@see getCurrentModuleInstanceHandle()
|
|
*/
|
|
static void JUCE_CALLTYPE setCurrentModuleInstanceHandle (void* newHandle) noexcept;
|
|
|
|
/** WINDOWS ONLY - Gets the command-line params as a string.
|
|
This is needed to avoid unicode problems with the argc type params.
|
|
*/
|
|
static String JUCE_CALLTYPE getCurrentCommandLineParams();
|
|
#endif
|
|
|
|
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_SpinLock.h ***/
|
|
#ifndef __JUCE_SPINLOCK_JUCEHEADER__
|
|
#define __JUCE_SPINLOCK_JUCEHEADER__
|
|
|
|
/**
|
|
A simple spin-lock class that can be used as a simple, low-overhead mutex for
|
|
uncontended situations.
|
|
|
|
Note that unlike a CriticalSection, this type of lock is not re-entrant, and may
|
|
be less efficient when used it a highly contended situation, but it's very small and
|
|
requires almost no initialisation.
|
|
It's most appropriate for simple situations where you're only going to hold the
|
|
lock for a very brief time.
|
|
|
|
@see CriticalSection
|
|
*/
|
|
class JUCE_API SpinLock
|
|
{
|
|
public:
|
|
inline SpinLock() noexcept {}
|
|
inline ~SpinLock() noexcept {}
|
|
|
|
/** Acquires the lock.
|
|
This will block until the lock has been successfully acquired by this thread.
|
|
Note that a SpinLock is NOT re-entrant, and is not smart enough to know whether the
|
|
caller thread already has the lock - so if a thread tries to acquire a lock that it
|
|
already holds, this method will never return!
|
|
|
|
It's strongly recommended that you never call this method directly - instead use the
|
|
ScopedLockType class to manage the locking using an RAII pattern instead.
|
|
*/
|
|
void enter() const noexcept;
|
|
|
|
/** Attempts to acquire the lock, returning true if this was successful. */
|
|
inline bool tryEnter() const noexcept
|
|
{
|
|
return lock.compareAndSetBool (1, 0);
|
|
}
|
|
|
|
/** Releases the lock. */
|
|
inline void exit() const noexcept
|
|
{
|
|
jassert (lock.value == 1); // Agh! Releasing a lock that isn't currently held!
|
|
lock = 0;
|
|
}
|
|
|
|
/** Provides the type of scoped lock to use for locking a SpinLock. */
|
|
typedef GenericScopedLock <SpinLock> ScopedLockType;
|
|
|
|
/** Provides the type of scoped unlocker to use with a SpinLock. */
|
|
typedef GenericScopedUnlock <SpinLock> ScopedUnlockType;
|
|
|
|
private:
|
|
|
|
mutable Atomic<int> lock;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (SpinLock);
|
|
};
|
|
|
|
#endif // __JUCE_SPINLOCK_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_SpinLock.h ***/
|
|
|
|
|
|
/*** 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) noexcept;
|
|
|
|
/** Destructor.
|
|
|
|
If other threads are waiting on this object when it gets deleted, this
|
|
can cause nasty errors, so be careful!
|
|
*/
|
|
~WaitableEvent() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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.
|
|
|
|
If the WaitableEvent is manual reset, all current and future threads that wait upon this
|
|
object will be woken, until reset() is explicitly called.
|
|
|
|
If the WaitableEvent is automatic reset, and one or more threads is waiting upon the object,
|
|
then one of them will be woken up. If no threads are currently waiting, then the next thread
|
|
to call wait() will be woken up. As soon as a thread is woken, the signal is automatically
|
|
reset.
|
|
|
|
@see wait, reset
|
|
*/
|
|
void signal() const noexcept;
|
|
|
|
/** Resets the event to an unsignalled state.
|
|
|
|
If it's not already signalled, this does nothing.
|
|
*/
|
|
void reset() const noexcept;
|
|
|
|
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 noexcept { return threadId_; }
|
|
|
|
/** Returns the name of the thread.
|
|
|
|
This is the name that gets set in the constructor.
|
|
*/
|
|
const String& getThreadName() const { return threadName_; }
|
|
|
|
/** Changes the name of the caller thread.
|
|
Different OSes may place different length or content limits on this name.
|
|
*/
|
|
static void setCurrentThreadName (const String& newThreadName);
|
|
|
|
/** 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 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() noexcept;
|
|
|
|
/** Destructor.
|
|
|
|
If the object is deleted whilst locked, any subsequent behaviour
|
|
is unpredictable.
|
|
*/
|
|
~ReadWriteLock() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
private:
|
|
|
|
SpinLock accessLock;
|
|
WaitableEvent waitEvent;
|
|
mutable int numWaitingWriters, numWriters;
|
|
mutable Thread::ThreadID writerThreadId;
|
|
mutable Array <Thread::ThreadID> 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) noexcept : 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() noexcept { 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_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) noexcept : 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() noexcept { 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_SPINLOCK_JUCEHEADER__
|
|
|
|
#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
|
|
*/
|
|
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.
|
|
*/
|
|
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 <ThreadPoolThread>;
|
|
OwnedArray <ThreadPoolThread> threads;
|
|
Array <ThreadPoolJob*> 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__
|
|
|
|
class TimeSliceThread;
|
|
|
|
/**
|
|
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 the number of milliseconds which it would like to wait before being called
|
|
again. Returning 0 will make the thread call again as soon as possible (after possibly servicing
|
|
other busy clients). If you return a value below zero, your client will be removed from the list of clients,
|
|
and won't be called again. The value you specify isn't a guaranteee, and is only used as a hint by the
|
|
thread - the actual time before the next callback may be more or less than specified.
|
|
You can force the TimeSliceThread to wake up and poll again immediately by calling its notify() method.
|
|
*/
|
|
virtual int useTimeSlice() = 0;
|
|
|
|
private:
|
|
friend class TimeSliceThread;
|
|
Time nextCallTime;
|
|
};
|
|
|
|
/**
|
|
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 after the number of milliseconds specified
|
|
by millisecondsBeforeStarting (and this may happen before this method has returned).
|
|
*/
|
|
void addTimeSliceClient (TimeSliceClient* client, int millisecondsBeforeStarting = 0);
|
|
|
|
/** 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;
|
|
|
|
#ifndef DOXYGEN
|
|
void run();
|
|
#endif
|
|
|
|
private:
|
|
CriticalSection callbackLock, listLock;
|
|
Array <TimeSliceClient*> clients;
|
|
TimeSliceClient* clientBeingCalled;
|
|
|
|
TimeSliceClient* getNextClient (int index) const;
|
|
|
|
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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
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) noexcept;
|
|
|
|
/** Creates a copy of another object. */
|
|
ModifierKeys (const ModifierKeys& other) noexcept;
|
|
|
|
/** Copies this object from another one. */
|
|
ModifierKeys& operator= (const ModifierKeys& other) noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept { return (flags & popupMenuClickModifier) != 0; }
|
|
|
|
/** Checks whether the flag is set for the left mouse-button. */
|
|
inline bool isLeftButtonDown() const noexcept { 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 noexcept { return (flags & rightButtonModifier) != 0; }
|
|
|
|
inline bool isMiddleButtonDown() const noexcept { return (flags & middleButtonModifier) != 0; }
|
|
|
|
/** Tests for any of the mouse-button flags. */
|
|
inline bool isAnyMouseButtonDown() const noexcept { return (flags & allMouseButtonModifiers) != 0; }
|
|
|
|
/** Tests for any of the modifier key flags. */
|
|
inline bool isAnyModifierKeyDown() const noexcept { return (flags & (shiftModifier | ctrlModifier | altModifier | commandModifier)) != 0; }
|
|
|
|
/** Checks whether the shift key's flag is set. */
|
|
inline bool isShiftDown() const noexcept { 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 noexcept { return (flags & ctrlModifier) != 0; }
|
|
|
|
/** Checks whether the shift key's flag is set. */
|
|
inline bool isAltDown() const noexcept { 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 */
|
|
ModifierKeys withOnlyMouseButtons() const noexcept { return ModifierKeys (flags & allMouseButtonModifiers); }
|
|
|
|
/** Returns a copy of only the non-mouse flags */
|
|
ModifierKeys withoutMouseButtons() const noexcept { return ModifierKeys (flags & ~allMouseButtonModifiers); }
|
|
|
|
bool operator== (const ModifierKeys& other) const noexcept { return flags == other.flags; }
|
|
bool operator!= (const ModifierKeys& other) const noexcept { return flags != other.flags; }
|
|
|
|
/** Returns the raw flags for direct testing. */
|
|
inline int getRawFlags() const noexcept { return flags; }
|
|
|
|
inline const ModifierKeys withoutFlags (int rawFlagsToClear) const noexcept { return ModifierKeys (flags & ~rawFlagsToClear); }
|
|
inline const ModifierKeys withFlags (int rawFlagsToSet) const noexcept { 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 noexcept { return (flags & flagsToTest) != 0; }
|
|
|
|
/** Returns the total number of mouse buttons that are down. */
|
|
int getNumMouseButtonsDown() const noexcept;
|
|
|
|
/** Creates a ModifierKeys object to represent the last-known state of the
|
|
keyboard and mouse buttons.
|
|
|
|
@see getCurrentModifiersRealtime
|
|
*/
|
|
static ModifierKeys getCurrentModifiers() noexcept;
|
|
|
|
/** 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 ModifierKeys getCurrentModifiersRealtime() noexcept;
|
|
|
|
private:
|
|
|
|
int flags;
|
|
|
|
static ModifierKeys currentModifiers;
|
|
|
|
friend class ComponentPeer;
|
|
friend class MouseInputSource;
|
|
friend class MouseInputSourceInternal;
|
|
static void updateCurrentModifiers() noexcept;
|
|
};
|
|
|
|
#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() noexcept;
|
|
|
|
/** Creates a copy of another transform. */
|
|
AffineTransform (const AffineTransform& other) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Copies from another AffineTransform object */
|
|
AffineTransform& operator= (const AffineTransform& other) noexcept;
|
|
|
|
/** Compares two transforms. */
|
|
bool operator== (const AffineTransform& other) const noexcept;
|
|
|
|
/** Compares two transforms. */
|
|
bool operator!= (const AffineTransform& other) const noexcept;
|
|
|
|
/** 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 <typename ValueType>
|
|
void transformPoint (ValueType& x, ValueType& y) const noexcept
|
|
{
|
|
const ValueType oldX = x;
|
|
x = static_cast <ValueType> (mat00 * oldX + mat01 * y + mat02);
|
|
y = static_cast <ValueType> (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 <typename ValueType>
|
|
void transformPoints (ValueType& x1, ValueType& y1,
|
|
ValueType& x2, ValueType& y2) const noexcept
|
|
{
|
|
const ValueType oldX1 = x1, oldX2 = x2;
|
|
x1 = static_cast <ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
|
|
y1 = static_cast <ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
|
|
x2 = static_cast <ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
|
|
y2 = static_cast <ValueType> (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 <typename ValueType>
|
|
void transformPoints (ValueType& x1, ValueType& y1,
|
|
ValueType& x2, ValueType& y2,
|
|
ValueType& x3, ValueType& y3) const noexcept
|
|
{
|
|
const ValueType oldX1 = x1, oldX2 = x2, oldX3 = x3;
|
|
x1 = static_cast <ValueType> (mat00 * oldX1 + mat01 * y1 + mat02);
|
|
y1 = static_cast <ValueType> (mat10 * oldX1 + mat11 * y1 + mat12);
|
|
x2 = static_cast <ValueType> (mat00 * oldX2 + mat01 * y2 + mat02);
|
|
y2 = static_cast <ValueType> (mat10 * oldX2 + mat11 * y2 + mat12);
|
|
x3 = static_cast <ValueType> (mat00 * oldX3 + mat01 * y3 + mat02);
|
|
y3 = static_cast <ValueType> (mat10 * oldX3 + mat11 * y3 + mat12);
|
|
}
|
|
|
|
/** Returns a new transform which is the same as this one followed by a translation. */
|
|
AffineTransform translated (float deltaX,
|
|
float deltaY) const noexcept;
|
|
|
|
/** Returns a new transform which is a translation. */
|
|
static AffineTransform translation (float deltaX,
|
|
float deltaY) noexcept;
|
|
|
|
/** 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).
|
|
*/
|
|
AffineTransform rotated (float angleInRadians) const noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
AffineTransform rotated (float angleInRadians,
|
|
float pivotX,
|
|
float pivotY) const noexcept;
|
|
|
|
/** Returns a new transform which is a rotation about (0, 0). */
|
|
static AffineTransform rotation (float angleInRadians) noexcept;
|
|
|
|
/** Returns a new transform which is a rotation about a given point. */
|
|
static AffineTransform rotation (float angleInRadians,
|
|
float pivotX,
|
|
float pivotY) noexcept;
|
|
|
|
/** Returns a transform which is the same as this one followed by a re-scaling.
|
|
The scaling is centred around the origin (0, 0).
|
|
*/
|
|
AffineTransform scaled (float factorX,
|
|
float factorY) const noexcept;
|
|
|
|
/** Returns a transform which is the same as this one followed by a re-scaling.
|
|
The scaling is centred around the origin provided.
|
|
*/
|
|
AffineTransform scaled (float factorX, float factorY,
|
|
float pivotX, float pivotY) const noexcept;
|
|
|
|
/** Returns a new transform which is a re-scale about the origin. */
|
|
static AffineTransform scale (float factorX,
|
|
float factorY) noexcept;
|
|
|
|
/** Returns a new transform which is a re-scale centred around the point provided. */
|
|
static AffineTransform scale (float factorX, float factorY,
|
|
float pivotX, float pivotY) noexcept;
|
|
|
|
/** Returns a transform which is the same as this one followed by a shear.
|
|
The shear is centred around the origin (0, 0).
|
|
*/
|
|
AffineTransform sheared (float shearX, float shearY) const noexcept;
|
|
|
|
/** Returns a shear transform, centred around the origin (0, 0). */
|
|
static AffineTransform shear (float shearX, float shearY) noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
AffineTransform inverted() const noexcept;
|
|
|
|
/** 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 AffineTransform fromTargetPoints (float x00, float y00,
|
|
float x10, float y10,
|
|
float x01, float y01) noexcept;
|
|
|
|
/** Returns the transform that will map three specified points onto three target points.
|
|
*/
|
|
static 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) noexcept;
|
|
|
|
/** Returns the result of concatenating another transformation after this one. */
|
|
AffineTransform followedBy (const AffineTransform& other) const noexcept;
|
|
|
|
/** Returns true if this transform has no effect on points. */
|
|
bool isIdentity() const noexcept;
|
|
|
|
/** Returns true if this transform maps to a singularity - i.e. if it has no inverse. */
|
|
bool isSingularity() const noexcept;
|
|
|
|
/** Returns true if the transform only translates, and doesn't scale or rotate the
|
|
points. */
|
|
bool isOnlyTranslation() const noexcept;
|
|
|
|
/** If this transform is only a translation, this returns the X offset.
|
|
@see isOnlyTranslation
|
|
*/
|
|
float getTranslationX() const noexcept { return mat02; }
|
|
|
|
/** If this transform is only a translation, this returns the X offset.
|
|
@see isOnlyTranslation
|
|
*/
|
|
float getTranslationY() const noexcept { 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 noexcept;
|
|
|
|
/* 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 <typename ValueType>
|
|
class Point
|
|
{
|
|
public:
|
|
|
|
/** Creates a point with co-ordinates (0, 0). */
|
|
Point() noexcept : x(), y() {}
|
|
|
|
/** Creates a copy of another point. */
|
|
Point (const Point& other) noexcept : x (other.x), y (other.y) {}
|
|
|
|
/** Creates a point from an (x, y) position. */
|
|
Point (const ValueType initialX, const ValueType initialY) noexcept : x (initialX), y (initialY) {}
|
|
|
|
/** Destructor. */
|
|
~Point() noexcept {}
|
|
|
|
/** Copies this point from another one. */
|
|
Point& operator= (const Point& other) noexcept { x = other.x; y = other.y; return *this; }
|
|
|
|
inline bool operator== (const Point& other) const noexcept { return x == other.x && y == other.y; }
|
|
inline bool operator!= (const Point& other) const noexcept { return x != other.x || y != other.y; }
|
|
|
|
/** Returns true if the point is (0, 0). */
|
|
bool isOrigin() const noexcept { return x == ValueType() && y == ValueType(); }
|
|
|
|
/** Returns the point's x co-ordinate. */
|
|
inline ValueType getX() const noexcept { return x; }
|
|
|
|
/** Returns the point's y co-ordinate. */
|
|
inline ValueType getY() const noexcept { return y; }
|
|
|
|
/** Sets the point's x co-ordinate. */
|
|
inline void setX (const ValueType newX) noexcept { x = newX; }
|
|
|
|
/** Sets the point's y co-ordinate. */
|
|
inline void setY (const ValueType newY) noexcept { y = newY; }
|
|
|
|
/** Returns a point which has the same Y position as this one, but a new X. */
|
|
Point withX (const ValueType newX) const noexcept { return Point (newX, y); }
|
|
|
|
/** Returns a point which has the same X position as this one, but a new Y. */
|
|
Point withY (const ValueType newY) const noexcept { return Point (x, newY); }
|
|
|
|
/** Changes the point's x and y co-ordinates. */
|
|
void setXY (const ValueType newX, const ValueType newY) noexcept { x = newX; y = newY; }
|
|
|
|
/** Adds a pair of co-ordinates to this value. */
|
|
void addXY (const ValueType xToAdd, const ValueType yToAdd) noexcept { x += xToAdd; y += yToAdd; }
|
|
|
|
/** Returns a point with a given offset from this one. */
|
|
Point translated (const ValueType xDelta, const ValueType yDelta) const noexcept { return Point (x + xDelta, y + yDelta); }
|
|
|
|
/** Adds two points together. */
|
|
Point operator+ (const Point& other) const noexcept { return Point (x + other.x, y + other.y); }
|
|
|
|
/** Adds another point's co-ordinates to this one. */
|
|
Point& operator+= (const Point& other) noexcept { x += other.x; y += other.y; return *this; }
|
|
|
|
/** Subtracts one points from another. */
|
|
Point operator- (const Point& other) const noexcept { return Point (x - other.x, y - other.y); }
|
|
|
|
/** Subtracts another point's co-ordinates to this one. */
|
|
Point& operator-= (const Point& other) noexcept { x -= other.x; y -= other.y; return *this; }
|
|
|
|
/** Returns a point whose coordinates are multiplied by a given value. */
|
|
Point operator* (const ValueType multiplier) const noexcept { return Point (x * multiplier, y * multiplier); }
|
|
|
|
/** Multiplies the point's co-ordinates by a value. */
|
|
Point& operator*= (const ValueType multiplier) noexcept { x *= multiplier; y *= multiplier; return *this; }
|
|
|
|
/** Returns a point whose coordinates are divided by a given value. */
|
|
Point operator/ (const ValueType divisor) const noexcept { return Point (x / divisor, y / divisor); }
|
|
|
|
/** Divides the point's co-ordinates by a value. */
|
|
Point& operator/= (const ValueType divisor) noexcept { x /= divisor; y /= divisor; return *this; }
|
|
|
|
/** Returns the inverse of this point. */
|
|
Point operator-() const noexcept { return Point (-x, -y); }
|
|
|
|
/** Returns the straight-line distance between this point and another one. */
|
|
ValueType getDistanceFromOrigin() const noexcept { return juce_hypot (x, y); }
|
|
|
|
/** Returns the straight-line distance between this point and another one. */
|
|
ValueType getDistanceFrom (const Point& other) const noexcept { 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 noexcept { 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.
|
|
*/
|
|
Point getPointOnCircumference (const float radius, const float angle) const noexcept { return Point<float> (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.
|
|
*/
|
|
Point getPointOnCircumference (const float radiusX, const float radiusY, const float angle) const noexcept { return Point<float> (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) noexcept { transform.transformPoint (x, y); }
|
|
|
|
/** Returns the position of this point, if it is transformed by a given AffineTransform. */
|
|
Point transformedBy (const AffineTransform& transform) const noexcept { return Point (transform.mat00 * x + transform.mat01 * y + transform.mat02,
|
|
transform.mat10 * x + transform.mat11 * y + transform.mat12); }
|
|
|
|
/** Casts this point to a Point<int> object. */
|
|
Point<int> toInt() const noexcept { return Point<int> (static_cast <int> (x), static_cast<int> (y)); }
|
|
|
|
/** Casts this point to a Point<float> object. */
|
|
Point<float> toFloat() const noexcept { return Point<float> (static_cast <float> (x), static_cast<float> (y)); }
|
|
|
|
/** Casts this point to a Point<double> object. */
|
|
Point<double> toDouble() const noexcept { return Point<double> (static_cast <double> (x), static_cast<double> (y)); }
|
|
|
|
/** Returns the point as a string in the form "x, y". */
|
|
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<int>& position,
|
|
const ModifierKeys& modifiers,
|
|
Component* eventComponent,
|
|
Component* originator,
|
|
const Time& eventTime,
|
|
const Point<int> mouseDownPos,
|
|
const Time& mouseDownTime,
|
|
int numberOfClicks,
|
|
bool mouseWasDragged) noexcept;
|
|
|
|
/** Destructor. */
|
|
~MouseEvent() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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<int> getMouseDownPosition() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the difference between the mouse's current postion and where it was
|
|
when the button was last pressed.
|
|
|
|
@see getDistanceFromDragStart
|
|
*/
|
|
const Point<int> getOffsetFromDragStart() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept;
|
|
|
|
/** 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<int> getPosition() const noexcept;
|
|
|
|
/** 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<int> 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<int> 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.
|
|
*/
|
|
MouseEvent getEventRelativeTo (Component* otherComponent) const noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
MouseEvent withNewPosition (const Point<int>& newPosition) const noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
private:
|
|
|
|
const Point<int> mouseDownPos;
|
|
const Time mouseDownTime;
|
|
const int numberOfClicks;
|
|
const bool wasMovedSinceMouseDown;
|
|
static int doubleClickTimeOutMs;
|
|
|
|
MouseEvent& operator= (const 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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Creates a keypress with a keyCode but no modifiers or text character.
|
|
*/
|
|
KeyPress (int keyCode) noexcept;
|
|
|
|
/** Creates a copy of another KeyPress. */
|
|
KeyPress (const KeyPress& other) noexcept;
|
|
|
|
/** Copies this KeyPress from another one. */
|
|
KeyPress& operator= (const KeyPress& other) noexcept;
|
|
|
|
/** Compares two KeyPress objects. */
|
|
bool operator== (const KeyPress& other) const noexcept;
|
|
|
|
/** Compares two KeyPress objects. */
|
|
bool operator!= (const KeyPress& other) const noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept { return keyCode; }
|
|
|
|
/** Returns the key modifiers.
|
|
|
|
@see ModifierKeys
|
|
*/
|
|
const ModifierKeys getModifiers() const noexcept { 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 noexcept { 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 noexcept { 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.
|
|
*/
|
|
String getTextDescription() const;
|
|
|
|
/** Creates a textual description of the key combination, using unicode icon symbols if possible.
|
|
|
|
On OSX, this uses the Apple symbols for command, option, shift, etc, instead of the textual
|
|
modifier key descriptions that are returned by getTextDescription()
|
|
*/
|
|
String getTextDescriptionWithIcons() 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_GraphicsContext.h ***/
|
|
#ifndef __JUCE_GRAPHICSCONTEXT_JUCEHEADER__
|
|
#define __JUCE_GRAPHICSCONTEXT_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__
|
|
|
|
class Path;
|
|
class Font;
|
|
class EdgeTable;
|
|
class AffineTransform;
|
|
|
|
/**
|
|
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 SingleThreadedReferenceCountedObject
|
|
{
|
|
public:
|
|
|
|
/** A handy typedef for a pointer to a typeface. */
|
|
typedef ReferenceCountedObjectPtr <Typeface> Ptr;
|
|
|
|
/** Returns the name of the typeface.
|
|
@see Font::getTypefaceName
|
|
*/
|
|
const String& getName() const noexcept { return name; }
|
|
|
|
/** Creates a new system typeface. */
|
|
static 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 <int>& glyphs, Array<float>& 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 a new EdgeTable that contains the path for the givem glyph, with the specified transform applied. */
|
|
virtual EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform);
|
|
|
|
/** 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;
|
|
|
|
explicit Typeface (const String& name) noexcept;
|
|
|
|
static Ptr getFallbackTypeface();
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Typeface);
|
|
};
|
|
|
|
#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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
bool operator== (const Font& other) const noexcept;
|
|
bool operator!= (const Font& other) const noexcept;
|
|
|
|
/** Destructor. */
|
|
~Font() noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept { 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 noexcept { 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. */
|
|
Font boldened() const;
|
|
/** Returns true if the font is bold. */
|
|
bool isBold() const noexcept;
|
|
|
|
/** Makes the font italic or non-italic. */
|
|
void setItalic (bool shouldBeItalic);
|
|
/** Returns a copy of this font with the italic attribute set. */
|
|
Font italicised() const;
|
|
/** Returns true if the font is italic. */
|
|
bool isItalic() const noexcept;
|
|
|
|
/** Makes the font underlined or non-underlined. */
|
|
void setUnderline (bool shouldBeUnderlined);
|
|
/** Returns true if the font is underlined. */
|
|
bool isUnderlined() const noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept { 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 <int>& glyphs, Array <float>& 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<Font>& 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 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().
|
|
*/
|
|
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 Font fromString (const String& fontDescription);
|
|
|
|
private:
|
|
|
|
friend class FontGlyphAlphaMap;
|
|
friend class TypefaceCache;
|
|
|
|
class SharedFontInternal : public SingleThreadedReferenceCountedObject
|
|
{
|
|
public:
|
|
SharedFontInternal (float height, int styleFlags) noexcept;
|
|
SharedFontInternal (const String& typefaceName, float height, int styleFlags) noexcept;
|
|
SharedFontInternal (const Typeface::Ptr& typeface) noexcept;
|
|
SharedFontInternal (const SharedFontInternal& other) noexcept;
|
|
|
|
bool operator== (const SharedFontInternal&) const noexcept;
|
|
|
|
String typefaceName;
|
|
float height, horizontalScale, kerning, ascent;
|
|
int styleFlags;
|
|
Typeface::Ptr typeface;
|
|
};
|
|
|
|
ReferenceCountedObjectPtr <SharedFontInternal> font;
|
|
void dupeInternalIfShared();
|
|
|
|
JUCE_LEAK_DETECTOR (Font);
|
|
};
|
|
|
|
#endif // __JUCE_FONT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Font.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 <typename ValueType>
|
|
class Rectangle
|
|
{
|
|
public:
|
|
|
|
/** Creates a rectangle of zero size.
|
|
|
|
The default co-ordinates will be (0, 0, 0, 0).
|
|
*/
|
|
Rectangle() noexcept
|
|
: x(), y(), w(), h()
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another rectangle. */
|
|
Rectangle (const Rectangle& other) noexcept
|
|
: 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) noexcept
|
|
: 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) noexcept
|
|
: x(), y(), w (width), h (height)
|
|
{
|
|
}
|
|
|
|
/** Creates a Rectangle from the positions of two opposite corners. */
|
|
Rectangle (const Point<ValueType>& corner1, const Point<ValueType>& corner2) noexcept
|
|
: x (jmin (corner1.getX(), corner2.getX())),
|
|
y (jmin (corner1.getY(), corner2.getY())),
|
|
w (corner1.getX() - corner2.getX()),
|
|
h (corner1.getY() - corner2.getY())
|
|
{
|
|
if (w < ValueType()) w = -w;
|
|
if (h < ValueType()) 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 Rectangle leftTopRightBottom (const ValueType left, const ValueType top,
|
|
const ValueType right, const ValueType bottom) noexcept
|
|
{
|
|
return Rectangle (left, top, right - left, bottom - top);
|
|
}
|
|
|
|
Rectangle& operator= (const Rectangle& other) noexcept
|
|
{
|
|
x = other.x; y = other.y;
|
|
w = other.w; h = other.h;
|
|
return *this;
|
|
}
|
|
|
|
/** Destructor. */
|
|
~Rectangle() noexcept {}
|
|
|
|
/** Returns true if the rectangle's width and height are both zero or less */
|
|
bool isEmpty() const noexcept { return w <= ValueType() || h <= ValueType(); }
|
|
|
|
/** Returns the x co-ordinate of the rectangle's left-hand-side. */
|
|
inline ValueType getX() const noexcept { return x; }
|
|
|
|
/** Returns the y co-ordinate of the rectangle's top edge. */
|
|
inline ValueType getY() const noexcept { return y; }
|
|
|
|
/** Returns the width of the rectangle. */
|
|
inline ValueType getWidth() const noexcept { return w; }
|
|
|
|
/** Returns the height of the rectangle. */
|
|
inline ValueType getHeight() const noexcept { return h; }
|
|
|
|
/** Returns the x co-ordinate of the rectangle's right-hand-side. */
|
|
inline ValueType getRight() const noexcept { return x + w; }
|
|
|
|
/** Returns the y co-ordinate of the rectangle's bottom edge. */
|
|
inline ValueType getBottom() const noexcept { return y + h; }
|
|
|
|
/** Returns the x co-ordinate of the rectangle's centre. */
|
|
ValueType getCentreX() const noexcept { return x + w / (ValueType) 2; }
|
|
|
|
/** Returns the y co-ordinate of the rectangle's centre. */
|
|
ValueType getCentreY() const noexcept { return y + h / (ValueType) 2; }
|
|
|
|
/** Returns the centre point of the rectangle. */
|
|
Point<ValueType> getCentre() const noexcept { return Point<ValueType> (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 noexcept { return widthOverHeight ? w / h : h / w; }
|
|
|
|
/** Returns the rectangle's top-left position as a Point. */
|
|
Point<ValueType> getPosition() const noexcept { return Point<ValueType> (x, y); }
|
|
|
|
/** Changes the position of the rectangle's top-left corner (leaving its size unchanged). */
|
|
void setPosition (const Point<ValueType>& newPos) noexcept { 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) noexcept { x = newX; y = newY; }
|
|
|
|
/** Returns a rectangle with the same size as this one, but a new position. */
|
|
Rectangle withPosition (const ValueType newX, const ValueType newY) const noexcept { return Rectangle (newX, newY, w, h); }
|
|
|
|
/** Returns a rectangle with the same size as this one, but a new position. */
|
|
Rectangle withPosition (const Point<ValueType>& newPos) const noexcept { return Rectangle (newPos.getX(), newPos.getY(), w, h); }
|
|
|
|
/** Returns the rectangle's top-left position as a Point. */
|
|
Point<ValueType> getTopLeft() const noexcept { return getPosition(); }
|
|
|
|
/** Returns the rectangle's top-right position as a Point. */
|
|
Point<ValueType> getTopRight() const noexcept { return Point<ValueType> (x + w, y); }
|
|
|
|
/** Returns the rectangle's bottom-left position as a Point. */
|
|
Point<ValueType> getBottomLeft() const noexcept { return Point<ValueType> (x, y + h); }
|
|
|
|
/** Returns the rectangle's bottom-right position as a Point. */
|
|
Point<ValueType> getBottomRight() const noexcept { return Point<ValueType> (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) noexcept { w = newWidth; h = newHeight; }
|
|
|
|
/** Returns a rectangle with the same position as this one, but a new size. */
|
|
Rectangle withSize (const ValueType newWidth, const ValueType newHeight) const noexcept { 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) noexcept
|
|
{
|
|
x = newX; y = newY; w = newWidth; h = newHeight;
|
|
}
|
|
|
|
/** Changes the rectangle's X coordinate */
|
|
void setX (const ValueType newX) noexcept { x = newX; }
|
|
|
|
/** Changes the rectangle's Y coordinate */
|
|
void setY (const ValueType newY) noexcept { y = newY; }
|
|
|
|
/** Changes the rectangle's width */
|
|
void setWidth (const ValueType newWidth) noexcept { w = newWidth; }
|
|
|
|
/** Changes the rectangle's height */
|
|
void setHeight (const ValueType newHeight) noexcept { h = newHeight; }
|
|
|
|
/** Returns a rectangle which has the same size and y-position as this one, but with a different x-position. */
|
|
Rectangle withX (const ValueType newX) const noexcept { 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. */
|
|
Rectangle withY (const ValueType newY) const noexcept { return Rectangle (x, newY, w, h); }
|
|
|
|
/** Returns a rectangle which has the same position and height as this one, but with a different width. */
|
|
Rectangle withWidth (const ValueType newWidth) const noexcept { return Rectangle (x, y, newWidth, h); }
|
|
|
|
/** Returns a rectangle which has the same position and width as this one, but with a different height. */
|
|
Rectangle withHeight (const ValueType newHeight) const noexcept { 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) noexcept
|
|
{
|
|
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
|
|
*/
|
|
Rectangle withLeft (const ValueType newLeft) const noexcept { 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) noexcept
|
|
{
|
|
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
|
|
*/
|
|
Rectangle withTop (const ValueType newTop) const noexcept { 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) noexcept
|
|
{
|
|
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
|
|
*/
|
|
Rectangle withRight (const ValueType newRight) const noexcept { 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) noexcept
|
|
{
|
|
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
|
|
*/
|
|
Rectangle withBottom (const ValueType newBottom) const noexcept { 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) noexcept
|
|
{
|
|
x += deltaX;
|
|
y += deltaY;
|
|
}
|
|
|
|
/** Returns a rectangle which is the same as this one moved by a given amount. */
|
|
Rectangle translated (const ValueType deltaX,
|
|
const ValueType deltaY) const noexcept
|
|
{
|
|
return Rectangle (x + deltaX, y + deltaY, w, h);
|
|
}
|
|
|
|
/** Returns a rectangle which is the same as this one moved by a given amount. */
|
|
Rectangle operator+ (const Point<ValueType>& deltaPosition) const noexcept
|
|
{
|
|
return Rectangle (x + deltaPosition.getX(), y + deltaPosition.getY(), w, h);
|
|
}
|
|
|
|
/** Moves this rectangle by a given amount. */
|
|
Rectangle& operator+= (const Point<ValueType>& deltaPosition) noexcept
|
|
{
|
|
x += deltaPosition.getX(); y += deltaPosition.getY();
|
|
return *this;
|
|
}
|
|
|
|
/** Returns a rectangle which is the same as this one moved by a given amount. */
|
|
Rectangle operator- (const Point<ValueType>& deltaPosition) const noexcept
|
|
{
|
|
return Rectangle (x - deltaPosition.getX(), y - deltaPosition.getY(), w, h);
|
|
}
|
|
|
|
/** Moves this rectangle by a given amount. */
|
|
Rectangle& operator-= (const Point<ValueType>& deltaPosition) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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
|
|
*/
|
|
Rectangle expanded (const ValueType deltaX,
|
|
const ValueType deltaY) const noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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
|
|
*/
|
|
Rectangle reduced (const ValueType deltaX,
|
|
const ValueType deltaY) const noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Rectangle removeFromTop (const ValueType amountToRemove) noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Rectangle removeFromLeft (const ValueType amountToRemove) noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Rectangle removeFromRight (ValueType amountToRemove) noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Rectangle removeFromBottom (ValueType amountToRemove) noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
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<ValueType>& point) const noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
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. */
|
|
Point<ValueType> getConstrainedPoint (const Point<ValueType>& point) const noexcept
|
|
{
|
|
return Point<ValueType> (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 noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Rectangle getIntersection (const Rectangle& other) const noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
const int maxX = jmax (otherX, x);
|
|
otherW = jmin (otherX + otherW, x + w) - maxX;
|
|
|
|
if (otherW > ValueType())
|
|
{
|
|
const int maxY = jmax (otherY, y);
|
|
otherH = jmin (otherY + otherH, y + h) - maxY;
|
|
|
|
if (otherH > ValueType())
|
|
{
|
|
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.
|
|
*/
|
|
Rectangle getUnion (const Rectangle& other) const noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Rectangle transformed (const AffineTransform& transform) const noexcept
|
|
{
|
|
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()
|
|
*/
|
|
Rectangle<int> getSmallestIntegerContainer() const noexcept
|
|
{
|
|
const int x1 = (int) std::floor (static_cast<float> (x));
|
|
const int y1 = (int) std::floor (static_cast<float> (y));
|
|
const int x2 = (int) std::ceil (static_cast<float> (x + w));
|
|
const int y2 = (int) std::ceil (static_cast<float> (y + h));
|
|
|
|
return Rectangle<int> (x1, y1, x2 - x1, y2 - y1);
|
|
}
|
|
|
|
/** Returns the smallest Rectangle that can contain a set of points. */
|
|
static Rectangle findAreaContainingPoints (const Point<ValueType>* const points, const int numPoints) noexcept
|
|
{
|
|
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<float>.
|
|
Obviously this is mainly useful for rectangles that use integer types.
|
|
@see getSmallestIntegerContainer
|
|
*/
|
|
Rectangle<float> toFloat() const noexcept
|
|
{
|
|
return Rectangle<float> (static_cast<float> (x), static_cast<float> (y),
|
|
static_cast<float> (w), static_cast<float> (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) noexcept
|
|
{
|
|
const ValueType x = jmax (x1, x2);
|
|
w1 = jmin (x1 + w1, x2 + w2) - x;
|
|
|
|
if (w1 > ValueType())
|
|
{
|
|
const ValueType y = jmax (y1, y2);
|
|
h1 = jmin (y1 + h1, y2 + h2) - y;
|
|
|
|
if (h1 > ValueType())
|
|
{
|
|
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
|
|
*/
|
|
String toString() const
|
|
{
|
|
String s;
|
|
s.preallocateBytes (32);
|
|
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 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_PathStrokeType.h ***/
|
|
#ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__
|
|
#define __JUCE_PATHSTROKETYPE_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 <typename ValueType>
|
|
class Line
|
|
{
|
|
public:
|
|
|
|
/** Creates a line, using (0, 0) as its start and end points. */
|
|
Line() noexcept {}
|
|
|
|
/** Creates a copy of another line. */
|
|
Line (const Line& other) noexcept
|
|
: 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) noexcept
|
|
: start (startX, startY),
|
|
end (endX, endY)
|
|
{
|
|
}
|
|
|
|
/** Creates a line from its start and end points. */
|
|
Line (const Point<ValueType>& startPoint,
|
|
const Point<ValueType>& endPoint) noexcept
|
|
: start (startPoint),
|
|
end (endPoint)
|
|
{
|
|
}
|
|
|
|
/** Copies a line from another one. */
|
|
Line& operator= (const Line& other) noexcept
|
|
{
|
|
start = other.start;
|
|
end = other.end;
|
|
return *this;
|
|
}
|
|
|
|
/** Destructor. */
|
|
~Line() noexcept {}
|
|
|
|
/** Returns the x co-ordinate of the line's start point. */
|
|
inline ValueType getStartX() const noexcept { return start.getX(); }
|
|
|
|
/** Returns the y co-ordinate of the line's start point. */
|
|
inline ValueType getStartY() const noexcept { return start.getY(); }
|
|
|
|
/** Returns the x co-ordinate of the line's end point. */
|
|
inline ValueType getEndX() const noexcept { return end.getX(); }
|
|
|
|
/** Returns the y co-ordinate of the line's end point. */
|
|
inline ValueType getEndY() const noexcept { return end.getY(); }
|
|
|
|
/** Returns the line's start point. */
|
|
inline const Point<ValueType>& getStart() const noexcept { return start; }
|
|
|
|
/** Returns the line's end point. */
|
|
inline const Point<ValueType>& getEnd() const noexcept { return end; }
|
|
|
|
/** Changes this line's start point */
|
|
void setStart (ValueType newStartX, ValueType newStartY) noexcept { start.setXY (newStartX, newStartY); }
|
|
|
|
/** Changes this line's end point */
|
|
void setEnd (ValueType newEndX, ValueType newEndY) noexcept { end.setXY (newEndX, newEndY); }
|
|
|
|
/** Changes this line's start point */
|
|
void setStart (const Point<ValueType>& newStart) noexcept { start = newStart; }
|
|
|
|
/** Changes this line's end point */
|
|
void setEnd (const Point<ValueType>& newEnd) noexcept { end = newEnd; }
|
|
|
|
/** Returns a line that is the same as this one, but with the start and end reversed, */
|
|
const Line reversed() const noexcept { return Line (end, start); }
|
|
|
|
/** Applies an affine transform to the line's start and end points. */
|
|
void applyTransform (const AffineTransform& transform) noexcept
|
|
{
|
|
start.applyTransform (transform);
|
|
end.applyTransform (transform);
|
|
}
|
|
|
|
/** Returns the length of the line. */
|
|
ValueType getLength() const noexcept { return start.getDistanceFrom (end); }
|
|
|
|
/** Returns true if the line's start and end x co-ordinates are the same. */
|
|
bool isVertical() const noexcept { return start.getX() == end.getX(); }
|
|
|
|
/** Returns true if the line's start and end y co-ordinates are the same. */
|
|
bool isHorizontal() const noexcept { 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 noexcept { return start.getAngleToPoint (end); }
|
|
|
|
/** Compares two lines. */
|
|
bool operator== (const Line& other) const noexcept { return start == other.start && end == other.end; }
|
|
|
|
/** Compares two lines. */
|
|
bool operator!= (const Line& other) const noexcept { 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<ValueType>& intersection) const noexcept
|
|
{
|
|
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
|
|
*/
|
|
Point<ValueType> getIntersection (const Line& line) const noexcept
|
|
{
|
|
Point<ValueType> 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
|
|
*/
|
|
Point<ValueType> getPointAlongLine (ValueType distanceFromStart) const noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Point<ValueType> getPointAlongLine (ValueType distanceFromStart,
|
|
ValueType perpendicularDistance) const noexcept
|
|
{
|
|
const Point<ValueType> delta (end - start);
|
|
const double length = juce_hypot ((double) delta.getX(),
|
|
(double) delta.getY());
|
|
if (length <= 0)
|
|
return start;
|
|
|
|
return Point<ValueType> (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
|
|
*/
|
|
Point<ValueType> getPointAlongLineProportionally (ValueType proportionOfLength) const noexcept
|
|
{
|
|
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<ValueType>& targetPoint,
|
|
Point<ValueType>& pointOnLine) const noexcept
|
|
{
|
|
const Point<ValueType> 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<ValueType>& point) const noexcept
|
|
{
|
|
const Point<ValueType> 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
|
|
*/
|
|
Point<ValueType> findNearestPointTo (const Point<ValueType>& point) const noexcept
|
|
{
|
|
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<ValueType>& point) const noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Line withShortenedStart (ValueType distanceToShortenBy) const noexcept
|
|
{
|
|
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.
|
|
*/
|
|
Line withShortenedEnd (ValueType distanceToShortenBy) const noexcept
|
|
{
|
|
const ValueType length = getLength();
|
|
return Line (start, getPointAlongLine (length - jmin (distanceToShortenBy, length)));
|
|
}
|
|
|
|
private:
|
|
|
|
Point<ValueType> start, end;
|
|
|
|
static bool findIntersection (const Point<ValueType>& p1, const Point<ValueType>& p2,
|
|
const Point<ValueType>& p3, const Point<ValueType>& p4,
|
|
Point<ValueType>& intersection) noexcept
|
|
{
|
|
if (p2 == p3)
|
|
{
|
|
intersection = p2;
|
|
return true;
|
|
}
|
|
|
|
const Point<ValueType> d1 (p2 - p1);
|
|
const Point<ValueType> 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_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_) noexcept : flags (flags_) {}
|
|
|
|
/** Creates a copy of another Justification object. */
|
|
Justification (const Justification& other) noexcept;
|
|
|
|
/** Copies another Justification object. */
|
|
Justification& operator= (const Justification& other) noexcept;
|
|
|
|
bool operator== (const Justification& other) const noexcept { return flags == other.flags; }
|
|
bool operator!= (const Justification& other) const noexcept { return flags != other.flags; }
|
|
|
|
/** Returns the raw flags that are set for this Justification object. */
|
|
inline int getFlags() const noexcept { 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 noexcept { return (flags & flagsToTest) != 0; }
|
|
|
|
/** Returns just the flags from this object that deal with vertical layout. */
|
|
int getOnlyVerticalFlags() const noexcept;
|
|
|
|
/** Returns just the flags from this object that deal with horizontal layout. */
|
|
int getOnlyHorizontalFlags() const noexcept;
|
|
|
|
/** 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 <typename ValueType>
|
|
void applyToRectangle (ValueType& x, ValueType& y, ValueType w, ValueType h,
|
|
ValueType spaceX, ValueType spaceY, ValueType spaceW, ValueType spaceH) const noexcept
|
|
{
|
|
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 <typename ValueType>
|
|
const Rectangle<ValueType> appliedToRectangle (const Rectangle<ValueType>& areaToAdjust,
|
|
const Rectangle<ValueType>& targetSpace) const noexcept
|
|
{
|
|
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;
|
|
class InputStream;
|
|
class OutputStream;
|
|
|
|
/**
|
|
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 noexcept;
|
|
bool operator!= (const Path& other) const noexcept;
|
|
|
|
/** Returns true if the path doesn't contain any lines or curves. */
|
|
bool isEmpty() const noexcept;
|
|
|
|
/** Returns the smallest rectangle that contains all points within the path.
|
|
*/
|
|
Rectangle<float> getBounds() const noexcept;
|
|
|
|
/** Returns the smallest rectangle that contains all points within the path
|
|
after it's been transformed with the given tranasform matrix.
|
|
*/
|
|
Rectangle<float> getBoundsTransformed (const AffineTransform& transform) const noexcept;
|
|
|
|
/** 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<float>& 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<float>& 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
|
|
*/
|
|
Line<float> getClippedLine (const Line<float>& 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
|
|
*/
|
|
Point<float> 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<float>& targetPoint,
|
|
Point<float>& pointOnPath,
|
|
const AffineTransform& transform = AffineTransform::identity) const;
|
|
|
|
/** Removes all lines and curves, resetting the path completely. */
|
|
void clear() noexcept;
|
|
|
|
/** 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<float>& 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<float>& 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<float>& controlPoint,
|
|
const Point<float>& 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<float>& controlPoint1,
|
|
const Point<float>& controlPoint2,
|
|
const Point<float>& endPoint);
|
|
|
|
/** Returns the last point that was added to the path by one of the drawing methods.
|
|
*/
|
|
Point<float> 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 <typename ValueType>
|
|
void addRectangle (const Rectangle<ValueType>& rectangle)
|
|
{
|
|
addRectangle (static_cast <float> (rectangle.getX()), static_cast <float> (rectangle.getY()),
|
|
static_cast <float> (rectangle.getWidth()), static_cast <float> (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 <typename ValueType>
|
|
void addRoundedRectangle (const Rectangle<ValueType>& rectangle, float cornerSizeX, float cornerSizeY)
|
|
{
|
|
addRoundedRectangle (static_cast <float> (rectangle.getX()), static_cast <float> (rectangle.getY()),
|
|
static_cast <float> (rectangle.getWidth()), static_cast <float> (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 <typename ValueType>
|
|
void addRoundedRectangle (const Rectangle<ValueType>& 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<float>& 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<float>& line,
|
|
float lineThickness,
|
|
float arrowheadWidth,
|
|
float arrowheadLength);
|
|
|
|
/** Adds a polygon shape to the path.
|
|
@see addStar
|
|
*/
|
|
void addPolygon (const Point<float>& centre,
|
|
int numberOfSides,
|
|
float radius,
|
|
float startAngle = 0.0f);
|
|
|
|
/** Adds a star shape to the path.
|
|
@see addPolygon
|
|
*/
|
|
void addStar (const Point<float>& 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) noexcept;
|
|
|
|
/** Applies a 2D transform to all the vertices in the path.
|
|
|
|
@see AffineTransform, scaleToFit, getTransformToScaleToFit
|
|
*/
|
|
void applyTransform (const AffineTransform& transform) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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
|
|
|
|
*/
|
|
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.
|
|
*/
|
|
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) noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
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 <float, DummyCriticalSection> 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 ***/
|
|
|
|
/**
|
|
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) noexcept;
|
|
|
|
/** Createes a copy of another stroke type. */
|
|
PathStrokeType (const PathStrokeType& other) noexcept;
|
|
|
|
/** Copies another stroke onto this one. */
|
|
PathStrokeType& operator= (const PathStrokeType& other) noexcept;
|
|
|
|
/** Destructor. */
|
|
~PathStrokeType() noexcept;
|
|
|
|
/** 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 noexcept { return thickness; }
|
|
|
|
/** Sets the stroke thickness. */
|
|
void setStrokeThickness (float newThickness) noexcept { thickness = newThickness; }
|
|
|
|
/** Returns the joint style. */
|
|
JointStyle getJointStyle() const noexcept { return jointStyle; }
|
|
|
|
/** Sets the joint style. */
|
|
void setJointStyle (JointStyle newStyle) noexcept { jointStyle = newStyle; }
|
|
|
|
/** Returns the end-cap style. */
|
|
EndCapStyle getEndStyle() const noexcept { return endStyle; }
|
|
|
|
/** Sets the end-cap style. */
|
|
void setEndStyle (EndCapStyle newStyle) noexcept { endStyle = newStyle; }
|
|
|
|
/** Compares the stroke thickness, joint and end styles of two stroke types. */
|
|
bool operator== (const PathStrokeType& other) const noexcept;
|
|
|
|
/** Compares the stroke thickness, joint and end styles of two stroke types. */
|
|
bool operator!= (const PathStrokeType& other) const noexcept;
|
|
|
|
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() noexcept {}
|
|
~PixelARGB() noexcept {}
|
|
|
|
/** Creates a pixel from a 32-bit argb value.
|
|
*/
|
|
PixelARGB (const uint32 argb_) noexcept
|
|
: argb (argb_)
|
|
{
|
|
}
|
|
|
|
forcedinline uint32 getARGB() const noexcept { return argb; }
|
|
forcedinline uint32 getUnpremultipliedARGB() const noexcept { PixelARGB p (argb); p.unpremultiply(); return p.getARGB(); }
|
|
|
|
forcedinline uint32 getRB() const noexcept { return 0x00ff00ff & argb; }
|
|
forcedinline uint32 getAG() const noexcept { return 0x00ff00ff & (argb >> 8); }
|
|
|
|
forcedinline uint8 getAlpha() const noexcept { return components.a; }
|
|
forcedinline uint8 getRed() const noexcept { return components.r; }
|
|
forcedinline uint8 getGreen() const noexcept { return components.g; }
|
|
forcedinline uint8 getBlue() const noexcept { 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) noexcept
|
|
{
|
|
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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 <class Pixel>
|
|
forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept
|
|
{
|
|
++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 <class Pixel>
|
|
forcedinline void tween (const Pixel& src, const uint32 amount) noexcept
|
|
{
|
|
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 <class Pixel>
|
|
forcedinline void set (const Pixel& src) noexcept
|
|
{
|
|
argb = src.getARGB();
|
|
}
|
|
|
|
/** Replaces the colour's alpha value with another one. */
|
|
forcedinline void setAlpha (const uint8 newAlpha) noexcept
|
|
{
|
|
components.a = newAlpha;
|
|
}
|
|
|
|
/** Multiplies the colour's alpha value with another one. */
|
|
forcedinline void multiplyAlpha (int multiplier) noexcept
|
|
{
|
|
++multiplier;
|
|
|
|
argb = ((multiplier * getAG()) & 0xff00ff00)
|
|
| (((multiplier * getRB()) >> 8) & 0x00ff00ff);
|
|
}
|
|
|
|
forcedinline void multiplyAlpha (const float multiplier) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
components.b = b;
|
|
components.g = g;
|
|
components.r = r;
|
|
components.a = a;
|
|
}
|
|
|
|
/** Premultiplies the pixel's RGB values by its alpha. */
|
|
forcedinline void premultiply() noexcept
|
|
{
|
|
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() noexcept
|
|
{
|
|
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() noexcept
|
|
{
|
|
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() noexcept {}
|
|
~PixelRGB() noexcept {}
|
|
|
|
/** Creates a pixel from a 32-bit argb value.
|
|
|
|
(The argb format is that used by PixelARGB)
|
|
*/
|
|
PixelRGB (const uint32 argb) noexcept
|
|
{
|
|
r = (uint8) (argb >> 16);
|
|
g = (uint8) (argb >> 8);
|
|
b = (uint8) (argb);
|
|
}
|
|
|
|
forcedinline uint32 getARGB() const noexcept { return 0xff000000 | b | (g << 8) | (r << 16); }
|
|
forcedinline uint32 getUnpremultipliedARGB() const noexcept { return getARGB(); }
|
|
|
|
forcedinline uint32 getRB() const noexcept { return b | (uint32) (r << 16); }
|
|
forcedinline uint32 getAG() const noexcept { return 0xff0000 | g; }
|
|
|
|
forcedinline uint8 getAlpha() const noexcept { return 0xff; }
|
|
forcedinline uint8 getRed() const noexcept { return r; }
|
|
forcedinline uint8 getGreen() const noexcept { return g; }
|
|
forcedinline uint8 getBlue() const noexcept { 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) noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
set (src);
|
|
}
|
|
|
|
forcedinline void blend (const PixelAlpha& src) noexcept;
|
|
|
|
/** 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 <class Pixel>
|
|
forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept
|
|
{
|
|
++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 <class Pixel>
|
|
forcedinline void tween (const Pixel& src, const uint32 amount) noexcept
|
|
{
|
|
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 <class Pixel>
|
|
forcedinline void set (const Pixel& src) noexcept
|
|
{
|
|
b = src.getBlue();
|
|
g = src.getGreen();
|
|
r = src.getRed();
|
|
}
|
|
|
|
/** This method is included for compatibility with the PixelARGB class. */
|
|
forcedinline void setAlpha (const uint8) noexcept {}
|
|
|
|
/** Multiplies the colour's alpha value with another one. */
|
|
forcedinline void multiplyAlpha (int) noexcept {}
|
|
|
|
/** Sets the pixel's colour from individual components. */
|
|
void setARGB (const uint8, const uint8 r_, const uint8 g_, const uint8 b_) noexcept
|
|
{
|
|
r = r_;
|
|
g = g_;
|
|
b = b_;
|
|
}
|
|
|
|
/** Premultiplies the pixel's RGB values by its alpha. */
|
|
forcedinline void premultiply() noexcept {}
|
|
|
|
/** Unpremultiplies the pixel's RGB values. */
|
|
forcedinline void unpremultiply() noexcept {}
|
|
|
|
forcedinline void desaturate() noexcept
|
|
{
|
|
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) noexcept
|
|
{
|
|
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() noexcept {}
|
|
~PixelAlpha() noexcept {}
|
|
|
|
/** Creates a pixel from a 32-bit argb value.
|
|
|
|
(The argb format is that used by PixelARGB)
|
|
*/
|
|
PixelAlpha (const uint32 argb) noexcept
|
|
{
|
|
a = (uint8) (argb >> 24);
|
|
}
|
|
|
|
forcedinline uint32 getARGB() const noexcept { return (((uint32) a) << 24) | (((uint32) a) << 16) | (((uint32) a) << 8) | a; }
|
|
forcedinline uint32 getUnpremultipliedARGB() const noexcept { return (((uint32) a) << 24) | 0xffffff; }
|
|
|
|
forcedinline uint32 getRB() const noexcept { return (((uint32) a) << 16) | a; }
|
|
forcedinline uint32 getAG() const noexcept { return (((uint32) a) << 16) | a; }
|
|
|
|
forcedinline uint8 getAlpha() const noexcept { return a; }
|
|
forcedinline uint8 getRed() const noexcept { return 0; }
|
|
forcedinline uint8 getGreen() const noexcept { return 0; }
|
|
forcedinline uint8 getBlue() const noexcept { return 0; }
|
|
|
|
/** Blends another pixel onto this one.
|
|
|
|
This takes into account the opacity of the pixel being overlaid, and blends
|
|
it accordingly.
|
|
*/
|
|
template <class Pixel>
|
|
forcedinline void blend (const Pixel& src) noexcept
|
|
{
|
|
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 <class Pixel>
|
|
forcedinline void blend (const Pixel& src, uint32 extraAlpha) noexcept
|
|
{
|
|
++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 <class Pixel>
|
|
forcedinline void tween (const Pixel& src, const uint32 amount) noexcept
|
|
{
|
|
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 <class Pixel>
|
|
forcedinline void set (const Pixel& src) noexcept
|
|
{
|
|
a = src.getAlpha();
|
|
}
|
|
|
|
/** Replaces the colour's alpha value with another one. */
|
|
forcedinline void setAlpha (const uint8 newAlpha) noexcept
|
|
{
|
|
a = newAlpha;
|
|
}
|
|
|
|
/** Multiplies the colour's alpha value with another one. */
|
|
forcedinline void multiplyAlpha (int multiplier) noexcept
|
|
{
|
|
++multiplier;
|
|
a = (uint8) ((a * multiplier) >> 8);
|
|
}
|
|
|
|
forcedinline void multiplyAlpha (const float multiplier) noexcept
|
|
{
|
|
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*/) noexcept
|
|
{
|
|
a = a_;
|
|
}
|
|
|
|
/** Premultiplies the pixel's RGB values by its alpha. */
|
|
forcedinline void premultiply() noexcept
|
|
{
|
|
}
|
|
|
|
/** Unpremultiplies the pixel's RGB values. */
|
|
forcedinline void unpremultiply() noexcept
|
|
{
|
|
}
|
|
|
|
forcedinline void desaturate() noexcept
|
|
{
|
|
}
|
|
|
|
/** 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) noexcept
|
|
{
|
|
blend (PixelARGB (src.getARGB()));
|
|
}
|
|
|
|
forcedinline void PixelARGB::blend (const PixelAlpha& src) noexcept
|
|
{
|
|
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() noexcept;
|
|
|
|
/** Creates a copy of another Colour object. */
|
|
Colour (const Colour& other) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Creates an opaque colour using 8-bit red, green and blue values */
|
|
Colour (uint8 red,
|
|
uint8 green,
|
|
uint8 blue) noexcept;
|
|
|
|
/** Creates an opaque colour using 8-bit red, green and blue values */
|
|
static Colour fromRGB (uint8 red,
|
|
uint8 green,
|
|
uint8 blue) noexcept;
|
|
|
|
/** Creates a colour using 8-bit red, green, blue and alpha values. */
|
|
Colour (uint8 red,
|
|
uint8 green,
|
|
uint8 blue,
|
|
uint8 alpha) noexcept;
|
|
|
|
/** Creates a colour using 8-bit red, green, blue and alpha values. */
|
|
static Colour fromRGBA (uint8 red,
|
|
uint8 green,
|
|
uint8 blue,
|
|
uint8 alpha) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Creates a colour using 8-bit red, green, blue and float alpha values. */
|
|
static Colour fromRGBAFloat (uint8 red,
|
|
uint8 green,
|
|
uint8 blue,
|
|
float alpha) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 Colour fromHSV (float hue,
|
|
float saturation,
|
|
float brightness,
|
|
float alpha) noexcept;
|
|
|
|
/** Destructor. */
|
|
~Colour() noexcept;
|
|
|
|
/** Copies another Colour object. */
|
|
Colour& operator= (const Colour& other) noexcept;
|
|
|
|
/** Compares two colours. */
|
|
bool operator== (const Colour& other) const noexcept;
|
|
/** Compares two colours. */
|
|
bool operator!= (const Colour& other) const noexcept;
|
|
|
|
/** Returns the red component of this colour.
|
|
|
|
@returns a value between 0x00 and 0xff.
|
|
*/
|
|
uint8 getRed() const noexcept { return argb.getRed(); }
|
|
|
|
/** Returns the green component of this colour.
|
|
|
|
@returns a value between 0x00 and 0xff.
|
|
*/
|
|
uint8 getGreen() const noexcept { return argb.getGreen(); }
|
|
|
|
/** Returns the blue component of this colour.
|
|
|
|
@returns a value between 0x00 and 0xff.
|
|
*/
|
|
uint8 getBlue() const noexcept { 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 noexcept;
|
|
|
|
/** Returns the green component of this colour as a floating point value.
|
|
|
|
@returns a value between 0.0 and 1.0
|
|
*/
|
|
float getFloatGreen() const noexcept;
|
|
|
|
/** Returns the blue component of this colour as a floating point value.
|
|
|
|
@returns a value between 0.0 and 1.0
|
|
*/
|
|
float getFloatBlue() const noexcept;
|
|
|
|
/** Returns a premultiplied ARGB pixel object that represents this colour.
|
|
*/
|
|
const PixelARGB getPixelARGB() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the colour's alpha (opacity).
|
|
|
|
Alpha of 0x00 is completely transparent, 0xff is completely opaque.
|
|
*/
|
|
uint8 getAlpha() const noexcept { 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 noexcept;
|
|
|
|
/** Returns true if this colour is completely opaque.
|
|
|
|
Equivalent to (getAlpha() == 0xff).
|
|
*/
|
|
bool isOpaque() const noexcept;
|
|
|
|
/** Returns true if this colour is completely transparent.
|
|
|
|
Equivalent to (getAlpha() == 0x00).
|
|
*/
|
|
bool isTransparent() const noexcept;
|
|
|
|
/** Returns a colour that's the same colour as this one, but with a new alpha value. */
|
|
Colour withAlpha (uint8 newAlpha) const noexcept;
|
|
|
|
/** Returns a colour that's the same colour as this one, but with a new alpha value. */
|
|
Colour withAlpha (float newAlpha) const noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
Colour withMultipliedAlpha (float alphaMultiplier) const noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
Colour overlaidWith (const Colour& foregroundColour) const noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
Colour interpolatedWith (const Colour& other, float proportionOfOther) const noexcept;
|
|
|
|
/** Returns the colour's hue component.
|
|
The value returned is in the range 0.0 to 1.0
|
|
*/
|
|
float getHue() const noexcept;
|
|
|
|
/** Returns the colour's saturation component.
|
|
The value returned is in the range 0.0 to 1.0
|
|
*/
|
|
float getSaturation() const noexcept;
|
|
|
|
/** Returns the colour's brightness component.
|
|
The value returned is in the range 0.0 to 1.0
|
|
*/
|
|
float getBrightness() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns a copy of this colour with a different hue. */
|
|
Colour withHue (float newHue) const noexcept;
|
|
|
|
/** Returns a copy of this colour with a different saturation. */
|
|
Colour withSaturation (float newSaturation) const noexcept;
|
|
|
|
/** Returns a copy of this colour with a different brightness.
|
|
@see brighter, darker, withMultipliedBrightness
|
|
*/
|
|
Colour withBrightness (float newBrightness) const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
Colour withRotatedHue (float amountToRotate) const noexcept;
|
|
|
|
/** 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).
|
|
*/
|
|
Colour withMultipliedSaturation (float multiplier) const noexcept;
|
|
|
|
/** 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).
|
|
*/
|
|
Colour withMultipliedBrightness (float amount) const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
Colour brighter (float amountBrighter = 0.4f) const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
Colour darker (float amountDarker = 0.4f) const noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
Colour contrasting (float amount = 1.0f) const noexcept;
|
|
|
|
/** 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 Colour contrasting (const Colour& colour1,
|
|
const Colour& colour2) noexcept;
|
|
|
|
/** Returns an opaque shade of grey.
|
|
|
|
@param brightness the level of grey to return - 0 is black, 1.0 is white
|
|
*/
|
|
static Colour greyLevel (float brightness) noexcept;
|
|
|
|
/** Returns a stringified version of this colour.
|
|
|
|
The string can be turned back into a colour using the fromString() method.
|
|
*/
|
|
String toString() const;
|
|
|
|
/** Reads the colour from a string that was created with toString().
|
|
*/
|
|
static Colour fromString (const String& encodedColourString);
|
|
|
|
/** Returns the colour as a hex string in the form RRGGBB or AARRGGBB. */
|
|
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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Returns the number of colour-stops that have been added. */
|
|
int getNumColours() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the colour that was added with a given index.
|
|
The index is from 0 to getNumColours() - 1.
|
|
*/
|
|
const Colour getColour (int index) const noexcept;
|
|
|
|
/** Changes the colour at a given index.
|
|
The index is from 0 to getNumColours() - 1.
|
|
*/
|
|
void setColour (int index, const Colour& newColour) noexcept;
|
|
|
|
/** Returns the an interpolated colour at any position along the gradient.
|
|
@param position the position along the gradient, between 0 and 1
|
|
*/
|
|
Colour getColourAtPosition (double position) const noexcept;
|
|
|
|
/** 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 <PixelARGB>& resultLookupTable) const;
|
|
|
|
/** Returns true if all colours are opaque. */
|
|
bool isOpaque() const noexcept;
|
|
|
|
/** Returns true if all colours are completely transparent. */
|
|
bool isInvisible() const noexcept;
|
|
|
|
Point<float> 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 noexcept;
|
|
bool operator!= (const ColourGradient& other) const noexcept;
|
|
|
|
private:
|
|
|
|
struct ColourPoint
|
|
{
|
|
ColourPoint() noexcept {}
|
|
|
|
ColourPoint (const double position_, const Colour& colour_) noexcept
|
|
: position (position_), colour (colour_)
|
|
{}
|
|
|
|
bool operator== (const ColourPoint& other) const noexcept;
|
|
bool operator!= (const ColourPoint& other) const noexcept;
|
|
|
|
double position;
|
|
Colour colour;
|
|
};
|
|
|
|
Array <ColourPoint> 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_) noexcept : flags (flags_) {}
|
|
|
|
/** Creates a copy of another RectanglePlacement object. */
|
|
RectanglePlacement (const RectanglePlacement& other) noexcept;
|
|
|
|
/** Copies another RectanglePlacement object. */
|
|
RectanglePlacement& operator= (const RectanglePlacement& other) noexcept;
|
|
|
|
bool operator== (const RectanglePlacement& other) const noexcept;
|
|
bool operator!= (const RectanglePlacement& other) const noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept { 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 noexcept;
|
|
|
|
/** Returns the transform that should be applied to these source co-ordinates to fit them
|
|
into the destination rectangle using the current flags.
|
|
*/
|
|
template <typename ValueType>
|
|
const Rectangle<ValueType> appliedTo (const Rectangle<ValueType>& source,
|
|
const Rectangle<ValueType>& destination) const noexcept
|
|
{
|
|
double x = source.getX(), y = source.getY(), w = source.getWidth(), h = source.getHeight();
|
|
applyTo (x, y, w, h, static_cast <double> (destination.getX()), static_cast <double> (destination.getY()),
|
|
static_cast <double> (destination.getWidth()), static_cast <double> (destination.getHeight()));
|
|
return Rectangle<ValueType> (static_cast <ValueType> (x), static_cast <ValueType> (y),
|
|
static_cast <ValueType> (w), static_cast <ValueType> (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<float>& source,
|
|
const Rectangle<float>& destination) const noexcept;
|
|
|
|
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. */
|
|
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<int>& 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<float>& rectangle,
|
|
float cornerSize) const;
|
|
|
|
/** Fills a rectangle with a checkerboard pattern, alternating between two colours.
|
|
*/
|
|
void fillCheckerBoard (const Rectangle<int>& 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<int>& 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<float>& 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<float>& line) const;
|
|
|
|
/** Draws a line between two points with a given thickness.
|
|
|
|
@see Path::addLineSegment
|
|
*/
|
|
void drawLine (const Line<float>& line, float lineThickness) const;
|
|
|
|
/** Draws a dashed line using a custom set of dash-lengths.
|
|
|
|
@param line the line to draw
|
|
@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
|
|
@param dashIndexToStartFrom the index in the dash-length array to use for the first segment
|
|
@see PathStrokeType::createDashedStroke
|
|
*/
|
|
void drawDashedLine (const Line<float>& line,
|
|
const float* dashLengths, int numDashLengths,
|
|
float lineThickness = 1.0f,
|
|
int dashIndexToStartFrom = 0) 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.
|
|
|
|
The bottom parameter must be greater than or equal to the top parameter.
|
|
*/
|
|
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.
|
|
|
|
The right parameter must be greater than or equal to the left parameter.
|
|
*/
|
|
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<float>& 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<int> 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<int>& 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<int>& 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<int>& 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) noexcept;
|
|
|
|
/** @internal */
|
|
LowLevelGraphicsContext* getInternalContext() const noexcept { return context; }
|
|
|
|
private:
|
|
|
|
LowLevelGraphicsContext* const context;
|
|
ScopedPointer <LowLevelGraphicsContext> contextToDelete;
|
|
|
|
bool saveStatePending;
|
|
void saveStateIfPending();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Graphics);
|
|
};
|
|
|
|
#endif // __JUCE_GRAPHICSCONTEXT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_GraphicsContext.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 noexcept { 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 noexcept { 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 noexcept { return image != nullptr; }
|
|
|
|
/** 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 noexcept { return image == nullptr; }
|
|
|
|
/** 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 noexcept { return image == nullptr ? 0 : image->width; }
|
|
|
|
/** Returns the image's height (in pixels). */
|
|
int getHeight() const noexcept { return image == nullptr ? 0 : image->height; }
|
|
|
|
/** Returns a rectangle with the same size as this image.
|
|
The rectangle's origin is always (0, 0).
|
|
*/
|
|
const Rectangle<int> getBounds() const noexcept { return image == nullptr ? Rectangle<int>() : Rectangle<int> (image->width, image->height); }
|
|
|
|
/** Returns the image's pixel format. */
|
|
PixelFormat getFormat() const noexcept { return image == nullptr ? UnknownFormat : image->format; }
|
|
|
|
/** True if the image's format is ARGB. */
|
|
bool isARGB() const noexcept { return getFormat() == ARGB; }
|
|
|
|
/** True if the image's format is RGB. */
|
|
bool isRGB() const noexcept { return getFormat() == RGB; }
|
|
|
|
/** True if the image's format is a single-channel alpha map. */
|
|
bool isSingleChannel() const noexcept { return getFormat() == SingleChannel; }
|
|
|
|
/** True if the image contains an alpha-channel. */
|
|
bool hasAlphaChannel() const noexcept { 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<int>& 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.
|
|
*/
|
|
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.
|
|
*/
|
|
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.
|
|
*/
|
|
Image getClippedImage (const Rectangle<int>& 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:
|
|
enum ReadWriteMode
|
|
{
|
|
readOnly,
|
|
writeOnly,
|
|
readWrite
|
|
};
|
|
|
|
BitmapData (Image& image, int x, int y, int w, int h, ReadWriteMode mode);
|
|
BitmapData (const Image& image, int x, int y, int w, int h);
|
|
BitmapData (const Image& image, ReadWriteMode mode);
|
|
~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 noexcept { 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 noexcept { 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
uint8* data;
|
|
PixelFormat pixelFormat;
|
|
int lineStride, pixelStride, width, height;
|
|
|
|
/** Used internally by custom image types to manage pixel data lifetime. */
|
|
class BitmapDataReleaser
|
|
{
|
|
protected:
|
|
BitmapDataReleaser() {}
|
|
public:
|
|
virtual ~BitmapDataReleaser() {}
|
|
};
|
|
|
|
ScopedPointer<BitmapDataReleaser> dataReleaser;
|
|
|
|
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 noexcept { return image == nullptr ? 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;
|
|
virtual void initialiseBitmapData (BitmapData& bitmapData, int x, int y, BitmapData::ReadWriteMode mode) = 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 noexcept { return format; }
|
|
int getWidth() const noexcept { return width; }
|
|
int getHeight() const noexcept { return height; }
|
|
|
|
protected:
|
|
friend class Image;
|
|
friend class BitmapData;
|
|
const PixelFormat format;
|
|
const int width, height;
|
|
NamedValueSet userData;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SharedImage);
|
|
};
|
|
|
|
/** @internal */
|
|
SharedImage* getSharedImage() const noexcept { return image; }
|
|
/** @internal */
|
|
explicit Image (SharedImage* instance);
|
|
|
|
private:
|
|
|
|
friend class SharedImage;
|
|
friend class BitmapData;
|
|
|
|
ReferenceCountedObjectPtr<SharedImage> 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() noexcept;
|
|
|
|
/** Creates a copy of another list */
|
|
RectangleList (const RectangleList& other);
|
|
|
|
/** Creates a list containing just one rectangle. */
|
|
RectangleList (const Rectangle<int>& rect);
|
|
|
|
/** Copies this list from another one. */
|
|
RectangleList& operator= (const RectangleList& other);
|
|
|
|
/** Destructor. */
|
|
~RectangleList();
|
|
|
|
/** Returns true if the region is empty. */
|
|
bool isEmpty() const noexcept;
|
|
|
|
/** Returns the number of rectangles in the list. */
|
|
int getNumRectangles() const noexcept { 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.
|
|
*/
|
|
Rectangle<int> getRectangle (int index) const noexcept;
|
|
|
|
/** 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<int>& 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<int>& 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<int>& 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<int>& 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<int>& 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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<int>& 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<int>& rectangleToCheck) const noexcept;
|
|
|
|
/** Checks whether this region intersects any part of another one.
|
|
|
|
@see intersectsRectangle
|
|
*/
|
|
bool intersects (const RectangleList& other) const noexcept;
|
|
|
|
/** Returns the smallest rectangle that can enclose the whole of this region. */
|
|
Rectangle<int> getBounds() const noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Creates a Path object to represent this region. */
|
|
Path toPath() const;
|
|
|
|
/** An iterator for accessing all the rectangles in a RectangleList. */
|
|
class JUCE_API Iterator
|
|
{
|
|
public:
|
|
|
|
Iterator (const RectangleList& list) noexcept;
|
|
~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() noexcept;
|
|
|
|
/** Returns the current rectangle. */
|
|
const Rectangle<int>* getRectangle() const noexcept { return current; }
|
|
|
|
private:
|
|
const Rectangle<int>* current;
|
|
const RectangleList& owner;
|
|
int index;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (Iterator);
|
|
};
|
|
|
|
private:
|
|
|
|
friend class Iterator;
|
|
Array <Rectangle<int> > 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
|
|
*/
|
|
template <typename ValueType>
|
|
class BorderSize
|
|
{
|
|
public:
|
|
|
|
/** Creates a null border.
|
|
All sizes are left as 0.
|
|
*/
|
|
BorderSize() noexcept
|
|
: top(), left(), bottom(), right()
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another border. */
|
|
BorderSize (const BorderSize& other) noexcept
|
|
: top (other.top), left (other.left), bottom (other.bottom), right (other.right)
|
|
{
|
|
}
|
|
|
|
/** Creates a border with the given gaps. */
|
|
BorderSize (ValueType topGap, ValueType leftGap, ValueType bottomGap, ValueType rightGap) noexcept
|
|
: top (topGap), left (leftGap), bottom (bottomGap), right (rightGap)
|
|
{
|
|
}
|
|
|
|
/** Creates a border with the given gap on all sides. */
|
|
explicit BorderSize (ValueType allGaps) noexcept
|
|
: top (allGaps), left (allGaps), bottom (allGaps), right (allGaps)
|
|
{
|
|
}
|
|
|
|
/** Returns the gap that should be left at the top of the region. */
|
|
ValueType getTop() const noexcept { return top; }
|
|
|
|
/** Returns the gap that should be left at the top of the region. */
|
|
ValueType getLeft() const noexcept { return left; }
|
|
|
|
/** Returns the gap that should be left at the top of the region. */
|
|
ValueType getBottom() const noexcept { return bottom; }
|
|
|
|
/** Returns the gap that should be left at the top of the region. */
|
|
ValueType getRight() const noexcept { return right; }
|
|
|
|
/** Returns the sum of the top and bottom gaps. */
|
|
ValueType getTopAndBottom() const noexcept { return top + bottom; }
|
|
|
|
/** Returns the sum of the left and right gaps. */
|
|
ValueType getLeftAndRight() const noexcept { return left + right; }
|
|
|
|
/** Returns true if this border has no thickness along any edge. */
|
|
bool isEmpty() const noexcept { return left + right + top + bottom == ValueType(); }
|
|
|
|
/** Changes the top gap. */
|
|
void setTop (ValueType newTopGap) noexcept { top = newTopGap; }
|
|
|
|
/** Changes the left gap. */
|
|
void setLeft (ValueType newLeftGap) noexcept { left = newLeftGap; }
|
|
|
|
/** Changes the bottom gap. */
|
|
void setBottom (ValueType newBottomGap) noexcept { bottom = newBottomGap; }
|
|
|
|
/** Changes the right gap. */
|
|
void setRight (ValueType newRightGap) noexcept { right = newRightGap; }
|
|
|
|
/** Returns a rectangle with these borders removed from it. */
|
|
Rectangle<ValueType> subtractedFrom (const Rectangle<ValueType>& original) const noexcept
|
|
{
|
|
return Rectangle<ValueType> (original.getX() + left,
|
|
original.getY() + top,
|
|
original.getWidth() - (left + right),
|
|
original.getHeight() - (top + bottom));
|
|
}
|
|
|
|
/** Removes this border from a given rectangle. */
|
|
void subtractFrom (Rectangle<ValueType>& rectangle) const noexcept
|
|
{
|
|
rectangle = subtractedFrom (rectangle);
|
|
}
|
|
|
|
/** Returns a rectangle with these borders added around it. */
|
|
Rectangle<ValueType> addedTo (const Rectangle<ValueType>& original) const noexcept
|
|
{
|
|
return Rectangle<ValueType> (original.getX() - left,
|
|
original.getY() - top,
|
|
original.getWidth() + (left + right),
|
|
original.getHeight() + (top + bottom));
|
|
}
|
|
|
|
/** Adds this border around a given rectangle. */
|
|
void addTo (Rectangle<ValueType>& rectangle) const noexcept
|
|
{
|
|
rectangle = addedTo (rectangle);
|
|
}
|
|
|
|
bool operator== (const BorderSize& other) const noexcept
|
|
{
|
|
return top == other.top && left == other.left && bottom == other.bottom && right == other.right;
|
|
}
|
|
|
|
bool operator!= (const BorderSize& other) const noexcept
|
|
{
|
|
return ! operator== (other);
|
|
}
|
|
|
|
private:
|
|
|
|
ValueType 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 Array <DeletedAtShutdown*>& 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().
|
|
|
|
For some quick ways of creating callback objects, see the ModalCallbackFunction class.
|
|
@see ModalCallbackFunction
|
|
*/
|
|
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 (bool topOneShouldGrabFocus = true);
|
|
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
/** Runs the event loop until the currently topmost modal component is dismissed, and
|
|
returns the exit code for that component.
|
|
*/
|
|
int runEventLoopForCurrentComponent();
|
|
#endif
|
|
|
|
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 <ModalItem>;
|
|
OwnedArray <ModalItem> stack;
|
|
|
|
void startModal (Component* component);
|
|
void endModal (Component* component, int returnValue);
|
|
void endModal (Component* component);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (ModalComponentManager);
|
|
};
|
|
|
|
/**
|
|
This class provides some handy utility methods for creating ModalComponentManager::Callback
|
|
objects that will invoke a static function with some parameters when a modal component is dismissed.
|
|
*/
|
|
class ModalCallbackFunction
|
|
{
|
|
public:
|
|
|
|
/** This is a utility function to create a ModalComponentManager::Callback that will
|
|
call a static function with a parameter.
|
|
|
|
The function that you supply must take two parameters - the first being an int, which is
|
|
the result code that was used when the modal component was dismissed, and the second
|
|
can be a custom type. Note that this custom value will be copied and stored, so it must
|
|
be a primitive type or a class that provides copy-by-value semantics.
|
|
|
|
E.g. @code
|
|
static void myCallbackFunction (int modalResult, double customValue)
|
|
{
|
|
if (modalResult == 1)
|
|
doSomethingWith (customValue);
|
|
}
|
|
|
|
Component* someKindOfComp;
|
|
...
|
|
someKindOfComp->enterModalState (ModalCallbackFunction::create (myCallbackFunction, 3.0));
|
|
@endcode
|
|
@see ModalComponentManager::Callback
|
|
*/
|
|
template <typename ParamType>
|
|
static ModalComponentManager::Callback* create (void (*functionToCall) (int, ParamType),
|
|
ParamType parameterValue)
|
|
{
|
|
return new FunctionCaller1 <ParamType> (functionToCall, parameterValue);
|
|
}
|
|
|
|
/** This is a utility function to create a ModalComponentManager::Callback that will
|
|
call a static function with two custom parameters.
|
|
|
|
The function that you supply must take three parameters - the first being an int, which is
|
|
the result code that was used when the modal component was dismissed, and the next two are
|
|
your custom types. Note that these custom values will be copied and stored, so they must
|
|
be primitive types or classes that provide copy-by-value semantics.
|
|
|
|
E.g. @code
|
|
static void myCallbackFunction (int modalResult, double customValue1, String customValue2)
|
|
{
|
|
if (modalResult == 1)
|
|
doSomethingWith (customValue1, customValue2);
|
|
}
|
|
|
|
Component* someKindOfComp;
|
|
...
|
|
someKindOfComp->enterModalState (ModalCallbackFunction::create (myCallbackFunction, 3.0, String ("xyz")));
|
|
@endcode
|
|
@see ModalComponentManager::Callback
|
|
*/
|
|
template <typename ParamType1, typename ParamType2>
|
|
static ModalComponentManager::Callback* withParam (void (*functionToCall) (int, ParamType1, ParamType2),
|
|
ParamType1 parameterValue1,
|
|
ParamType2 parameterValue2)
|
|
{
|
|
return new FunctionCaller2 <ParamType1, ParamType2> (functionToCall, parameterValue1, parameterValue2);
|
|
}
|
|
|
|
/** This is a utility function to create a ModalComponentManager::Callback that will
|
|
call a static function with a component.
|
|
|
|
The function that you supply must take two parameters - the first being an int, which is
|
|
the result code that was used when the modal component was dismissed, and the second
|
|
can be a Component class. The component will be stored as a WeakReference, so that if it gets
|
|
deleted before this callback is invoked, the pointer that is passed to the function will be null.
|
|
|
|
E.g. @code
|
|
static void myCallbackFunction (int modalResult, Slider* mySlider)
|
|
{
|
|
if (modalResult == 1 && mySlider != nullptr) // (must check that mySlider isn't null in case it was deleted..)
|
|
mySlider->setValue (0.0);
|
|
}
|
|
|
|
Component* someKindOfComp;
|
|
Slider* mySlider;
|
|
...
|
|
someKindOfComp->enterModalState (ModalCallbackFunction::forComponent (myCallbackFunction, mySlider));
|
|
@endcode
|
|
@see ModalComponentManager::Callback
|
|
*/
|
|
template <class ComponentType>
|
|
static ModalComponentManager::Callback* forComponent (void (*functionToCall) (int, ComponentType*),
|
|
ComponentType* component)
|
|
{
|
|
return new ComponentCaller1 <ComponentType> (functionToCall, component);
|
|
}
|
|
|
|
/** Creates a ModalComponentManager::Callback that will call a static function with a component.
|
|
|
|
The function that you supply must take three parameters - the first being an int, which is
|
|
the result code that was used when the modal component was dismissed, the second being a Component
|
|
class, and the third being a custom type (which must be a primitive type or have copy-by-value semantics).
|
|
The component will be stored as a WeakReference, so that if it gets deleted before this callback is
|
|
invoked, the pointer that is passed into the function will be null.
|
|
|
|
E.g. @code
|
|
static void myCallbackFunction (int modalResult, Slider* mySlider, String customParam)
|
|
{
|
|
if (modalResult == 1 && mySlider != nullptr) // (must check that mySlider isn't null in case it was deleted..)
|
|
mySlider->setName (customParam);
|
|
}
|
|
|
|
Component* someKindOfComp;
|
|
Slider* mySlider;
|
|
...
|
|
someKindOfComp->enterModalState (ModalCallbackFunction::forComponent (myCallbackFunction, mySlider, String ("hello")));
|
|
@endcode
|
|
@see ModalComponentManager::Callback
|
|
*/
|
|
template <class ComponentType, typename ParamType>
|
|
static ModalComponentManager::Callback* forComponent (void (*functionToCall) (int, ComponentType*, ParamType),
|
|
ComponentType* component,
|
|
ParamType param)
|
|
{
|
|
return new ComponentCaller2 <ComponentType, ParamType> (functionToCall, component, param);
|
|
}
|
|
|
|
private:
|
|
|
|
template <typename ParamType>
|
|
class FunctionCaller1 : public ModalComponentManager::Callback
|
|
{
|
|
public:
|
|
typedef void (*FunctionType) (int, ParamType);
|
|
|
|
FunctionCaller1 (FunctionType& function_, ParamType& param_)
|
|
: function (function_), param (param_) {}
|
|
|
|
void modalStateFinished (int returnValue) { function (returnValue, param); }
|
|
|
|
private:
|
|
const FunctionType function;
|
|
ParamType param;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FunctionCaller1);
|
|
};
|
|
|
|
template <typename ParamType1, typename ParamType2>
|
|
class FunctionCaller2 : public ModalComponentManager::Callback
|
|
{
|
|
public:
|
|
typedef void (*FunctionType) (int, ParamType1, ParamType2);
|
|
|
|
FunctionCaller2 (FunctionType& function_, ParamType1& param1_, ParamType2& param2_)
|
|
: function (function_), param1 (param1_), param2 (param2_) {}
|
|
|
|
void modalStateFinished (int returnValue) { function (returnValue, param1, param2); }
|
|
|
|
private:
|
|
const FunctionType function;
|
|
ParamType1 param1;
|
|
ParamType2 param2;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FunctionCaller2);
|
|
};
|
|
|
|
template <typename ComponentType>
|
|
class ComponentCaller1 : public ModalComponentManager::Callback
|
|
{
|
|
public:
|
|
typedef void (*FunctionType) (int, ComponentType*);
|
|
|
|
ComponentCaller1 (FunctionType& function_, ComponentType* comp_)
|
|
: function (function_), comp (comp_) {}
|
|
|
|
void modalStateFinished (int returnValue)
|
|
{
|
|
function (returnValue, static_cast <ComponentType*> (comp.get()));
|
|
}
|
|
|
|
private:
|
|
const FunctionType function;
|
|
WeakReference<Component> comp;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentCaller1);
|
|
};
|
|
|
|
template <typename ComponentType, typename ParamType1>
|
|
class ComponentCaller2 : public ModalComponentManager::Callback
|
|
{
|
|
public:
|
|
typedef void (*FunctionType) (int, ComponentType*, ParamType1);
|
|
|
|
ComponentCaller2 (FunctionType& function_, ComponentType* comp_, ParamType1 param1_)
|
|
: function (function_), comp (comp_), param1 (param1_) {}
|
|
|
|
void modalStateFinished (int returnValue)
|
|
{
|
|
function (returnValue, static_cast <ComponentType*> (comp.get()), param1);
|
|
}
|
|
|
|
private:
|
|
const FunctionType function;
|
|
WeakReference<Component> comp;
|
|
ParamType1 param1;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentCaller2);
|
|
};
|
|
|
|
ModalCallbackFunction();
|
|
~ModalCallbackFunction();
|
|
JUCE_DECLARE_NON_COPYABLE (ModalCallbackFunction);
|
|
};
|
|
|
|
#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 noexcept { 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 noexcept { 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 noexcept { 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 = nullptr);
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept { return bounds.getY(); }
|
|
|
|
/** Returns the component's width in pixels. */
|
|
inline int getWidth() const noexcept { return bounds.getWidth(); }
|
|
|
|
/** Returns the component's height in pixels. */
|
|
inline int getHeight() const noexcept { 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 noexcept { return bounds.getRight(); }
|
|
|
|
/** Returns the component's top-left position as a Point. */
|
|
Point<int> getPosition() const noexcept { 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 noexcept { 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<int>& getBounds() const noexcept { 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.
|
|
*/
|
|
Rectangle<int> getLocalBounds() const noexcept;
|
|
|
|
/** 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().
|
|
*/
|
|
Rectangle<int> getBoundsInParent() const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
Point<int> getScreenPosition() const;
|
|
|
|
/** Returns the bounds of this component, relative to the screen's top-left.
|
|
@see getScreenPosition
|
|
*/
|
|
Rectangle<int> 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.
|
|
*/
|
|
Point<int> getLocalPoint (const Component* sourceComponent,
|
|
const Point<int>& 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.
|
|
*/
|
|
Rectangle<int> getLocalArea (const Component* sourceComponent,
|
|
const Rectangle<int>& areaRelativeToSourceComponent) const;
|
|
|
|
/** Converts a point relative to this component's top-left into a screen coordinate.
|
|
@see getLocalPoint, localAreaToGlobal
|
|
*/
|
|
Point<int> localPointToGlobal (const Point<int>& 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
|
|
*/
|
|
Rectangle<int> localAreaToGlobal (const Rectangle<int>& 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<int>& 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:
|
|
- "left", "right", "top", "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 "left + 100".
|
|
- "[id].left", "[id].right", "[id].top", "[id].bottom", "[id].width", "[id].height", 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".
|
|
- Instead of an [id], you can use the name "parent" to refer to this component's parent. Like
|
|
any other component, these values are relative to their component's parent, so "parent.right" won't be
|
|
very useful for positioning a component because it refers to a position with the parent's parent.. but
|
|
"parent.width" can be used for setting positions relative to the parent's size. E.g. to make a 10x10
|
|
component which remains 1 pixel away from its parent's bottom-right, you could use
|
|
"right - 10, bottom - 10, parent.width - 1, parent.height - 1".
|
|
- The name of one of the parent component's markers can also be used as a symbol. 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.width / 2 - 50, parent.height / 2 - 50, left + 100, top + 100"));
|
|
@endcode
|
|
..or an alternative way to achieve the same thing:
|
|
@code myComp.setBounds (RelativeBounds ("right - 100, bottom - 100, parent.width / 2 + 50, parent.height / 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, left + 100, 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);
|
|
|
|
/** Sets the component's bounds with an expression.
|
|
The string is parsed as a RelativeRectangle expression - see the notes for
|
|
Component::setBounds (const RelativeRectangle&) for more information. This method is
|
|
basically just a shortcut for writing setBounds (RelativeRectangle ("..."))
|
|
*/
|
|
void setBounds (const String& newBoundsExpression);
|
|
|
|
/** 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<int>& 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
|
|
*/
|
|
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 noexcept;
|
|
|
|
/** Returns a proportion of the component's width.
|
|
|
|
This is a handy equivalent of (getWidth() * proportion).
|
|
*/
|
|
int proportionOfWidth (float proportion) const noexcept;
|
|
|
|
/** Returns a proportion of the component's height.
|
|
|
|
This is a handy equivalent of (getHeight() * proportion).
|
|
*/
|
|
int proportionOfHeight (float proportion) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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.
|
|
*/
|
|
Rectangle<int> getParentMonitorArea() const;
|
|
|
|
/** Returns the number of child components that this component contains.
|
|
|
|
@see getChildComponent, getIndexOfChildComponent
|
|
*/
|
|
int getNumChildComponents() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept { return parentComponent; }
|
|
|
|
/** Searches the parent components for a component of a specified class.
|
|
|
|
For example findParentComponentOfClass \<MyComp\>() 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 <class TargetClass>
|
|
TargetClass* findParentComponentOfClass (TargetClass* const dummyParameter = nullptr) const
|
|
{
|
|
(void) dummyParameter;
|
|
Component* p = parentComponent;
|
|
while (p != nullptr)
|
|
{
|
|
TargetClass* target = dynamic_cast <TargetClass*> (p);
|
|
if (target != nullptr)
|
|
return target;
|
|
|
|
p = p->parentComponent;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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<int>& 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<int>& 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<int>& 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<int>& 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
|
|
*/
|
|
Image createComponentSnapshot (const Rectangle<int>& 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) noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Indicates whether the component should be brought to the front when clicked-on.
|
|
|
|
@see setBroughtToFrontOnMouseClick
|
|
*/
|
|
bool isBroughtToFrontOnMouseClick() const noexcept;
|
|
|
|
// 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Returns true if this component has been marked as a focus container.
|
|
|
|
See setFocusContainer() for more details.
|
|
|
|
@see setFocusContainer, moveKeyboardFocusToSibling, createFocusTraverser
|
|
*/
|
|
bool isFocusContainer() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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;
|
|
|
|
/** 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;
|
|
|
|
/** 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() noexcept;
|
|
|
|
/** Returns the mouse's current position, relative to this component.
|
|
The return value is relative to the component's top-left corner.
|
|
*/
|
|
Point<int> 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
|
|
*/
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
int runModalLoop();
|
|
#endif
|
|
|
|
/** 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
|
|
|
|
If deleteWhenDismissed is true, then when it is dismissed, the component will be
|
|
deleted and then the callback will be called. (This will safely handle the situation
|
|
where the component is deleted before its exitModalState() method is called).
|
|
|
|
@see exitModalState, runModalLoop, ModalComponentManager::attachCallback
|
|
*/
|
|
void enterModalState (bool takeKeyboardFocus = true,
|
|
ModalComponentManager::Callback* callback = nullptr,
|
|
bool deleteWhenDismissed = false);
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the number of components that are currently in a modal state.
|
|
@see getCurrentlyModalComponent
|
|
*/
|
|
static int JUCE_CALLTYPE getNumCurrentlyModalComponents() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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() noexcept { 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 noexcept { 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<Component> object for the same purpose.
|
|
*/
|
|
template <class ComponentType>
|
|
class SafePointer
|
|
{
|
|
public:
|
|
/** Creates a null SafePointer. */
|
|
SafePointer() noexcept {}
|
|
|
|
/** 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) noexcept : 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 noexcept { return dynamic_cast <ComponentType*> (weakRef.get()); }
|
|
|
|
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
|
|
operator ComponentType*() const noexcept { return getComponent(); }
|
|
|
|
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
|
|
ComponentType* operator->() noexcept { return getComponent(); }
|
|
|
|
/** Returns the component that this pointer refers to, or null if the component no longer exists. */
|
|
const ComponentType* operator->() const noexcept { return getComponent(); }
|
|
|
|
/** If the component is valid, this deletes it and sets this pointer to null. */
|
|
void deleteAndZero() { delete getComponent(); jassert (getComponent() == nullptr); }
|
|
|
|
bool operator== (ComponentType* component) const noexcept { return weakRef == component; }
|
|
bool operator!= (ComponentType* component) const noexcept { return weakRef != component; }
|
|
|
|
private:
|
|
WeakReference<Component> 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 noexcept;
|
|
|
|
private:
|
|
const WeakReference<Component> 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) noexcept;
|
|
/** Destructor. */
|
|
virtual ~Positioner() {}
|
|
|
|
/** Returns the component that this positioner controls. */
|
|
Component& getComponent() const noexcept { return component; }
|
|
|
|
/** Attempts to set the component's position to the given rectangle.
|
|
Unlike simply calling Component::setBounds(), this may involve the positioner
|
|
being smart enough to adjust itself to fit the new bounds, e.g. a RelativeRectangle's
|
|
positioner may try to reverse the expressions used to make them fit these new coordinates.
|
|
*/
|
|
virtual void applyNewBounds (const Rectangle<int>& newBounds) = 0;
|
|
|
|
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 noexcept;
|
|
|
|
/** 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<int> relativePositionToGlobal (const Point<int>&) const);
|
|
JUCE_DEPRECATED (const Point<int> globalPositionToRelative (const Point<int>&) const);
|
|
JUCE_DEPRECATED (const Point<int> relativePositionToOtherComponent (const Component*, const Point<int>&) const);
|
|
#endif
|
|
|
|
private:
|
|
|
|
friend class ComponentPeer;
|
|
friend class MouseInputSource;
|
|
friend class MouseInputSourceInternal;
|
|
|
|
#ifndef DOXYGEN
|
|
static Component* currentlyFocusedComponent;
|
|
|
|
String componentName, componentID;
|
|
Component* parentComponent;
|
|
Rectangle<int> bounds;
|
|
ScopedPointer <Positioner> positioner;
|
|
ScopedPointer <AffineTransform> affineTransform;
|
|
Array <Component*> childComponentList;
|
|
LookAndFeel* lookAndFeel;
|
|
MouseCursor cursor;
|
|
ImageEffectFilter* effect;
|
|
Image bufferedImage;
|
|
|
|
class MouseListenerList;
|
|
friend class MouseListenerList;
|
|
friend class ScopedPointer <MouseListenerList>;
|
|
ScopedPointer <MouseListenerList> mouseListeners;
|
|
ScopedPointer <Array <KeyListener*> > keyListeners;
|
|
ListenerList <ComponentListener> componentListeners;
|
|
NamedValueSet properties;
|
|
|
|
friend class WeakReference<Component>;
|
|
WeakReference<Component>::Master weakReferenceMaster;
|
|
const WeakReference<Component>::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 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<int>& relativePos, const Time& time);
|
|
void internalMouseExit (MouseInputSource& source, const Point<int>& relativePos, const Time& time);
|
|
void internalMouseDown (MouseInputSource& source, const Point<int>& relativePos, const Time& time);
|
|
void internalMouseUp (MouseInputSource& source, const Point<int>& relativePos, const Time& time, const ModifierKeys& oldModifiers);
|
|
void internalMouseDrag (MouseInputSource& source, const Point<int>& relativePos, const Time& time);
|
|
void internalMouseMove (MouseInputSource& source, const Point<int>& relativePos, const Time& time);
|
|
void internalMouseWheel (MouseInputSource& source, const Point<int>& relativePos, const Time& time, float amountX, float amountY);
|
|
void internalBroughtToFront();
|
|
void internalFocusGain (const FocusChangeType cause, const WeakReference<Component>&);
|
|
void internalFocusGain (const FocusChangeType cause);
|
|
void internalFocusLoss (const FocusChangeType cause);
|
|
void internalChildFocusChange (FocusChangeType cause, const WeakReference<Component>&);
|
|
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<int>&)
|
|
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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** An easy way to set or remove the isTicked bit in the structure's flags field.
|
|
*/
|
|
void setTicked (bool isTicked) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 <KeyPress> 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() noexcept;
|
|
|
|
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;
|
|
|
|
/** 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 noexcept;
|
|
};
|
|
|
|
#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 <CommandID>& 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 <CommandTargetMessageInvoker> 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 <MyApplicationWindow> myMainWindow;
|
|
};
|
|
|
|
// this creates wrapper code to actually launch the app properly.
|
|
START_JUCE_APPLICATION (MyJUCEApp)
|
|
@endcode
|
|
|
|
@see MessageManager
|
|
*/
|
|
class JUCE_API JUCEApplication : public ApplicationCommandTarget
|
|
{
|
|
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() noexcept { 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 noexcept { 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
|
|
*/
|
|
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) noexcept;
|
|
|
|
/** Returns the value that has been set as the application's exit code.
|
|
@see setApplicationReturnValue
|
|
*/
|
|
int getApplicationReturnValue() const noexcept { return appReturnValue; }
|
|
|
|
/** Returns the application's command line parameters. */
|
|
const String& getCommandLineParameters() const noexcept { return commandLineParameters; }
|
|
|
|
/** 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() noexcept { return createInstance != 0; }
|
|
|
|
/** @internal */
|
|
ApplicationCommandTarget* getNextCommandTarget();
|
|
/** @internal */
|
|
void getCommandInfo (CommandID commandID, ApplicationCommandInfo& result);
|
|
/** @internal */
|
|
void getAllCommands (Array <CommandID>& commands);
|
|
/** @internal */
|
|
bool perform (const InvocationInfo& info);
|
|
|
|
#ifndef DOXYGEN
|
|
// The following methods are internal calls - not for public use.
|
|
static int main (const String& commandLine);
|
|
static int main (int argc, const char* argv[]);
|
|
static void sendUnhandledException (const std::exception* e, const char* sourceFile, int lineNumber);
|
|
bool initialiseApp (const String& commandLine);
|
|
int shutdownApp();
|
|
static void appWillTerminateByForce();
|
|
typedef JUCEApplication* (*CreateInstanceFunction)();
|
|
static CreateInstanceFunction createInstance;
|
|
#endif
|
|
|
|
private:
|
|
|
|
static JUCEApplication* appInstance;
|
|
|
|
String commandLineParameters;
|
|
ScopedPointer<InterProcessLock> appLock;
|
|
ScopedPointer<ActionListener> broadcastCallback;
|
|
int appReturnValue;
|
|
bool stillInitialising;
|
|
|
|
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() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
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) noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
/** Checks if the timer has been started.
|
|
|
|
@returns true if the timer is running.
|
|
*/
|
|
bool isTimerRunning() const noexcept { 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 noexcept { 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<int>& 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<int> getComponentDestination (Component* component);
|
|
|
|
/** Returns true if the specified component is currently being animated. */
|
|
bool isAnimating (Component* component) const;
|
|
|
|
private:
|
|
|
|
class AnimationTask;
|
|
OwnedArray <AnimationTask> 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;
|
|
|
|
/** 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<int> getMainMonitorArea (bool clippedToWorkArea = true) const noexcept;
|
|
|
|
/** 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<int> getMonitorAreaContaining (const Point<int>& 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<int> 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<int>& 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<int> 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 (nullptr). 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 noexcept { return kioskModeComponent; }
|
|
|
|
/** Returns the number of components that are currently active as top-level
|
|
desktop windows.
|
|
|
|
@see getComponent, Component::addToDesktop
|
|
*/
|
|
int getNumComponents() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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<int>& 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() noexcept { return animator; }
|
|
|
|
/** Returns the current default look-and-feel for components which don't have one
|
|
explicitly set.
|
|
@see setDefaultLookAndFeel
|
|
*/
|
|
LookAndFeel& getDefaultLookAndFeel() noexcept;
|
|
|
|
/** Changes the default look-and-feel.
|
|
@param newDefaultLookAndFeel the new look-and-feel object to use - if this is
|
|
set to nullptr, it will revert to using the system's
|
|
default one. The object passed-in must be deleted by the
|
|
caller when it's no longer needed.
|
|
@see getDefaultLookAndFeel
|
|
*/
|
|
void setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel);
|
|
|
|
/** 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 noexcept { 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 noexcept { return mouseSources [index]; }
|
|
|
|
/** Returns the main mouse input device that the system is using.
|
|
@see getNumMouseSources()
|
|
*/
|
|
MouseInputSource& getMainMouseSource() const noexcept { 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
private:
|
|
|
|
static Desktop* instance;
|
|
|
|
friend class Component;
|
|
friend class ComponentPeer;
|
|
friend class MouseInputSource;
|
|
friend class MouseInputSourceInternal;
|
|
friend class DeletedAtShutdown;
|
|
friend class TopLevelWindowManager;
|
|
|
|
OwnedArray <MouseInputSource> mouseSources;
|
|
void createMouseInputSources();
|
|
|
|
ListenerList <MouseListener> mouseListeners;
|
|
ListenerList <FocusChangeListener> focusListeners;
|
|
|
|
Array <Component*> desktopComponents;
|
|
Array <Rectangle<int> > monitorCoordsClipped, monitorCoordsUnclipped;
|
|
|
|
Point<int> lastFakeMouseMove;
|
|
void sendMouseMove();
|
|
|
|
int mouseClickCounter;
|
|
void incrementMouseClickCounter() noexcept;
|
|
|
|
ScopedPointer<Timer> dragRepeater;
|
|
|
|
ScopedPointer<LookAndFeel> defaultLookAndFeel;
|
|
WeakReference<LookAndFeel> currentLookAndFeel;
|
|
|
|
Component* kioskModeComponent;
|
|
Rectangle<int> kioskComponentOriginalBounds;
|
|
|
|
int allowedOrientations;
|
|
|
|
ComponentAnimator animator;
|
|
|
|
void timerCallback();
|
|
void resetTimer();
|
|
ListenerList <MouseListener>& getMouseListeners();
|
|
|
|
int getNumDisplayMonitors() const noexcept;
|
|
const Rectangle<int> getDisplayMonitorCoordinates (int index, bool clippedToWorkArea) const noexcept;
|
|
static void getCurrentMonitorPositions (Array <Rectangle<int> >& monitorCoords, const bool clipToWorkArea);
|
|
|
|
void addDesktopComponent (Component* c);
|
|
void removeDesktopComponent (Component* c);
|
|
void componentBroughtToFront (Component* c);
|
|
|
|
static void setKioskComponent (Component* kioskModeComponent, bool enableOrDisable, bool allowMenusAndBars);
|
|
|
|
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 noexcept { 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 noexcept { 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 noexcept;
|
|
|
|
/** Returns the name field for a command.
|
|
|
|
An empty string is returned if no command with this ID has been registered.
|
|
@see getDescriptionOfCommand
|
|
*/
|
|
String getNameOfCommand (CommandID commandID) const noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
String getDescriptionOfCommand (CommandID commandID) const noexcept;
|
|
|
|
/** 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()
|
|
*/
|
|
StringArray getCommandCategories() const;
|
|
|
|
/** Returns a list of all the command UIDs in a particular category.
|
|
|
|
@see getCommandCategories()
|
|
*/
|
|
Array<CommandID> 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 noexcept { 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) noexcept;
|
|
|
|
/** 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 <ApplicationCommandInfo> commands;
|
|
ListenerList <ApplicationCommandManagerListener> listeners;
|
|
ScopedPointer <KeyPressMappingSet> 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 StorageFormat
|
|
{
|
|
storeAsBinary,
|
|
storeAsCompressedBinary,
|
|
storeAsXML
|
|
};
|
|
|
|
struct Options
|
|
{
|
|
/** Creates an empty Options structure.
|
|
You'll need to fill-in the data memebers appropriately before using this structure.
|
|
*/
|
|
Options();
|
|
|
|
/** The name of your application - this is used to help generate the path and filename
|
|
at which the properties file will be stored. */
|
|
String applicationName;
|
|
|
|
/** The suffix to use for your properties file.
|
|
It doesn't really matter what this is - you may want to use ".settings" or
|
|
".properties" or something.
|
|
*/
|
|
String filenameSuffix;
|
|
|
|
/** The name of a subfolder in which you'd like your properties file to live.
|
|
See the getDefaultFile() method for more details about how this is used.
|
|
*/
|
|
String folderName;
|
|
|
|
/** If you're using properties files on a Mac, you must set this value - failure to
|
|
do so will cause a runtime assertion.
|
|
|
|
The PropertiesFile class always used to put its settings files in "Library/Preferences", but Apple
|
|
have changed their advice, and now stipulate that settings should go in "Library/Application Support".
|
|
|
|
Because older apps would be broken by a silent change in this class's behaviour, you must now
|
|
explicitly set the osxLibrarySubFolder value to indicate which path you want to use.
|
|
|
|
In newer apps, you should always set this to "Application Support".
|
|
|
|
If your app needs to load settings files that were created by older versions of juce and
|
|
you want to maintain backwards-compatibility, then you can set this to "Preferences".
|
|
But.. for better Apple-compliance, the recommended approach would be to write some code that
|
|
finds your old settings files in ~/Library/Preferences, moves them to ~/Library/Application Support,
|
|
and then uses the new path.
|
|
*/
|
|
String osxLibrarySubFolder;
|
|
|
|
/** If true, the file will be created in a location that's shared between users.
|
|
The default constructor initialises this value to false.
|
|
*/
|
|
bool commonToAllUsers;
|
|
|
|
/** If true, this means that property names are matched in a case-insensitive manner.
|
|
See the PropertySet constructor for more info.
|
|
The default constructor initialises this value to false.
|
|
*/
|
|
bool ignoreCaseOfKeyNames;
|
|
|
|
/** 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 this 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.
|
|
The default constructor sets this to a reasonable value of a few seconds, so you
|
|
only need to change it if you need a special case.
|
|
*/
|
|
int millisecondsBeforeSaving;
|
|
|
|
/** Specifies whether the file should be written as XML, binary, etc.
|
|
The default constructor sets this to storeAsXML, so you only need to set it explicitly
|
|
if you want to use a different format.
|
|
*/
|
|
StorageFormat storageFormat;
|
|
|
|
/** 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.
|
|
The default constructor initialises this value to nullptr, so you don't need to touch it
|
|
unless you want to use a lock.
|
|
*/
|
|
InterProcessLock* processLock;
|
|
|
|
/** This can be called to suggest a file that should be used, based on the values
|
|
in this structure.
|
|
|
|
So on a Mac, this will return a file called:
|
|
~/Library/[osxLibrarySubFolder]/[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 the folderName variable is empty, it'll use the app name for this (or omit the
|
|
folder name on the Mac).
|
|
|
|
The paths will also vary depending on whether commonToAllUsers is true.
|
|
*/
|
|
File getDefaultFile() const;
|
|
};
|
|
|
|
/** Creates a PropertiesFile object.
|
|
The file used will be chosen by calling PropertiesFile::Options::getDefaultFile()
|
|
for the options provided. To set the file explicitly, use the other constructor.
|
|
*/
|
|
explicit PropertiesFile (const Options& options);
|
|
|
|
/** Creates a PropertiesFile object.
|
|
Unlike the other constructor, this one allows you to explicitly set the file that you
|
|
want to be used, rather than using the default one.
|
|
*/
|
|
PropertiesFile (const File& file,
|
|
const Options& options);
|
|
|
|
/** 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 noexcept { 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. */
|
|
File getFile() const { return file; }
|
|
|
|
protected:
|
|
/** @internal */
|
|
virtual void propertyChanged();
|
|
|
|
private:
|
|
|
|
File file;
|
|
Options options;
|
|
bool loadedOk, needsWriting;
|
|
|
|
typedef const ScopedPointer<InterProcessLock::ScopedLockType> ProcessScopedLock;
|
|
InterProcessLock::ScopedLockType* createProcessLock() const;
|
|
|
|
void timerCallback();
|
|
void initialise();
|
|
|
|
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 managing PropertiesFile objects.
|
|
|
|
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.
|
|
|
|
After creating an instance of an ApplicationProperties object, you should first
|
|
of all call setStorageParameters() to tell it the parameters to use to create
|
|
its files.
|
|
|
|
@see PropertiesFile
|
|
*/
|
|
class JUCE_API ApplicationProperties
|
|
{
|
|
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();
|
|
|
|
/** Gives the object the information it needs to create the appropriate properties files.
|
|
See the PropertiesFile::Options class for details about what options you need to set.
|
|
*/
|
|
void setStorageParameters (const PropertiesFile::Options& options);
|
|
|
|
/** 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:
|
|
|
|
PropertiesFile::Options options;
|
|
ScopedPointer <PropertiesFile> userProps, commonProps;
|
|
int commonSettingsAreReadOnly;
|
|
|
|
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 <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatBE(); }
|
|
template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatBE (newValue); }
|
|
template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32BE(); }
|
|
template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32BE (newValue); }
|
|
template <class SourceType, class DestType> static inline void copyFrom (DestType& dest, SourceType& source) noexcept { dest.copyFromBE (source); }
|
|
enum { isBigEndian = 1 };
|
|
};
|
|
|
|
class LittleEndian
|
|
{
|
|
public:
|
|
template <class SampleFormatType> static inline float getAsFloat (SampleFormatType& s) noexcept { return s.getAsFloatLE(); }
|
|
template <class SampleFormatType> static inline void setAsFloat (SampleFormatType& s, float newValue) noexcept { s.setAsFloatLE (newValue); }
|
|
template <class SampleFormatType> static inline int32 getAsInt32 (SampleFormatType& s) noexcept { return s.getAsInt32LE(); }
|
|
template <class SampleFormatType> static inline void setAsInt32 (SampleFormatType& s, int32 newValue) noexcept { s.setAsInt32LE (newValue); }
|
|
template <class SourceType, class DestType> static inline void copyFrom (DestType& dest, SourceType& source) noexcept { 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_) noexcept : data (static_cast <int8*> (data_)) {}
|
|
|
|
inline void advance() noexcept { ++data; }
|
|
inline void skip (int numSamples) noexcept { data += numSamples; }
|
|
inline float getAsFloatLE() const noexcept { return (float) (*data * (1.0 / (1.0 + maxValue))); }
|
|
inline float getAsFloatBE() const noexcept { return getAsFloatLE(); }
|
|
inline void setAsFloatLE (float newValue) noexcept { *data = (int8) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))); }
|
|
inline void setAsFloatBE (float newValue) noexcept { setAsFloatLE (newValue); }
|
|
inline int32 getAsInt32LE() const noexcept { return (int) (*data << 24); }
|
|
inline int32 getAsInt32BE() const noexcept { return getAsInt32LE(); }
|
|
inline void setAsInt32LE (int newValue) noexcept { *data = (int8) (newValue >> 24); }
|
|
inline void setAsInt32BE (int newValue) noexcept { setAsInt32LE (newValue); }
|
|
inline void clear() noexcept { *data = 0; }
|
|
inline void clearMultiple (int num) noexcept { zeromem (data, num * bytesPerSample) ;}
|
|
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
|
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
|
inline void copyFromSameType (Int8& source) noexcept { *data = *source.data; }
|
|
|
|
int8* data;
|
|
enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
|
|
};
|
|
|
|
class UInt8
|
|
{
|
|
public:
|
|
inline UInt8 (void* data_) noexcept : data (static_cast <uint8*> (data_)) {}
|
|
|
|
inline void advance() noexcept { ++data; }
|
|
inline void skip (int numSamples) noexcept { data += numSamples; }
|
|
inline float getAsFloatLE() const noexcept { return (float) ((*data - 128) * (1.0 / (1.0 + maxValue))); }
|
|
inline float getAsFloatBE() const noexcept { return getAsFloatLE(); }
|
|
inline void setAsFloatLE (float newValue) noexcept { *data = (uint8) jlimit (0, 255, 128 + roundToInt (newValue * (1.0 + maxValue))); }
|
|
inline void setAsFloatBE (float newValue) noexcept { setAsFloatLE (newValue); }
|
|
inline int32 getAsInt32LE() const noexcept { return (int) ((*data - 128) << 24); }
|
|
inline int32 getAsInt32BE() const noexcept { return getAsInt32LE(); }
|
|
inline void setAsInt32LE (int newValue) noexcept { *data = (uint8) (128 + (newValue >> 24)); }
|
|
inline void setAsInt32BE (int newValue) noexcept { setAsInt32LE (newValue); }
|
|
inline void clear() noexcept { *data = 128; }
|
|
inline void clearMultiple (int num) noexcept { memset (data, 128, num) ;}
|
|
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
|
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
|
inline void copyFromSameType (UInt8& source) noexcept { *data = *source.data; }
|
|
|
|
uint8* data;
|
|
enum { bytesPerSample = 1, maxValue = 0x7f, resolution = (1 << 24), isFloat = 0 };
|
|
};
|
|
|
|
class Int16
|
|
{
|
|
public:
|
|
inline Int16 (void* data_) noexcept : data (static_cast <uint16*> (data_)) {}
|
|
|
|
inline void advance() noexcept { ++data; }
|
|
inline void skip (int numSamples) noexcept { data += numSamples; }
|
|
inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfBigEndian (*data)); }
|
|
inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int16) ByteOrder::swapIfLittleEndian (*data)); }
|
|
inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint16) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); }
|
|
inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint16) jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue)))); }
|
|
inline int32 getAsInt32LE() const noexcept { return (int32) (ByteOrder::swapIfBigEndian ((uint16) *data) << 16); }
|
|
inline int32 getAsInt32BE() const noexcept { return (int32) (ByteOrder::swapIfLittleEndian ((uint16) *data) << 16); }
|
|
inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint16) (newValue >> 16)); }
|
|
inline void setAsInt32BE (int32 newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint16) (newValue >> 16)); }
|
|
inline void clear() noexcept { *data = 0; }
|
|
inline void clearMultiple (int num) noexcept { zeromem (data, num * bytesPerSample) ;}
|
|
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
|
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
|
inline void copyFromSameType (Int16& source) noexcept { *data = *source.data; }
|
|
|
|
uint16* data;
|
|
enum { bytesPerSample = 2, maxValue = 0x7fff, resolution = (1 << 16), isFloat = 0 };
|
|
};
|
|
|
|
class Int24
|
|
{
|
|
public:
|
|
inline Int24 (void* data_) noexcept : data (static_cast <char*> (data_)) {}
|
|
|
|
inline void advance() noexcept { data += 3; }
|
|
inline void skip (int numSamples) noexcept { data += 3 * numSamples; }
|
|
inline float getAsFloatLE() const noexcept { return (float) (ByteOrder::littleEndian24Bit (data) * (1.0 / (1.0 + maxValue))); }
|
|
inline float getAsFloatBE() const noexcept { return (float) (ByteOrder::bigEndian24Bit (data) * (1.0 / (1.0 + maxValue))); }
|
|
inline void setAsFloatLE (float newValue) noexcept { ByteOrder::littleEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); }
|
|
inline void setAsFloatBE (float newValue) noexcept { ByteOrder::bigEndian24BitToChars (jlimit ((int) -maxValue, (int) maxValue, roundToInt (newValue * (1.0 + maxValue))), data); }
|
|
inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::littleEndian24Bit (data) << 8; }
|
|
inline int32 getAsInt32BE() const noexcept { return (int32) ByteOrder::bigEndian24Bit (data) << 8; }
|
|
inline void setAsInt32LE (int32 newValue) noexcept { ByteOrder::littleEndian24BitToChars (newValue >> 8, data); }
|
|
inline void setAsInt32BE (int32 newValue) noexcept { ByteOrder::bigEndian24BitToChars (newValue >> 8, data); }
|
|
inline void clear() noexcept { data[0] = 0; data[1] = 0; data[2] = 0; }
|
|
inline void clearMultiple (int num) noexcept { zeromem (data, num * bytesPerSample) ;}
|
|
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
|
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
|
inline void copyFromSameType (Int24& source) noexcept { 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_) noexcept : data (static_cast <uint32*> (data_)) {}
|
|
|
|
inline void advance() noexcept { ++data; }
|
|
inline void skip (int numSamples) noexcept { data += numSamples; }
|
|
inline float getAsFloatLE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfBigEndian (*data)); }
|
|
inline float getAsFloatBE() const noexcept { return (float) ((1.0 / (1.0 + maxValue)) * (int32) ByteOrder::swapIfLittleEndian (*data)); }
|
|
inline void setAsFloatLE (float newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); }
|
|
inline void setAsFloatBE (float newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) (maxValue * jlimit (-1.0, 1.0, (double) newValue))); }
|
|
inline int32 getAsInt32LE() const noexcept { return (int32) ByteOrder::swapIfBigEndian (*data); }
|
|
inline int32 getAsInt32BE() const noexcept { return (int32) ByteOrder::swapIfLittleEndian (*data); }
|
|
inline void setAsInt32LE (int32 newValue) noexcept { *data = ByteOrder::swapIfBigEndian ((uint32) newValue); }
|
|
inline void setAsInt32BE (int32 newValue) noexcept { *data = ByteOrder::swapIfLittleEndian ((uint32) newValue); }
|
|
inline void clear() noexcept { *data = 0; }
|
|
inline void clearMultiple (int num) noexcept { zeromem (data, num * bytesPerSample) ;}
|
|
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsInt32LE (source.getAsInt32()); }
|
|
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsInt32BE (source.getAsInt32()); }
|
|
inline void copyFromSameType (Int32& source) noexcept { *data = *source.data; }
|
|
|
|
uint32* data;
|
|
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = 1, isFloat = 0 };
|
|
};
|
|
|
|
class Float32
|
|
{
|
|
public:
|
|
inline Float32 (void* data_) noexcept : data (static_cast <float*> (data_)) {}
|
|
|
|
inline void advance() noexcept { ++data; }
|
|
inline void skip (int numSamples) noexcept { data += numSamples; }
|
|
#if JUCE_BIG_ENDIAN
|
|
inline float getAsFloatBE() const noexcept { return *data; }
|
|
inline void setAsFloatBE (float newValue) noexcept { *data = newValue; }
|
|
inline float getAsFloatLE() const noexcept { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; }
|
|
inline void setAsFloatLE (float newValue) noexcept { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); }
|
|
#else
|
|
inline float getAsFloatLE() const noexcept { return *data; }
|
|
inline void setAsFloatLE (float newValue) noexcept { *data = newValue; }
|
|
inline float getAsFloatBE() const noexcept { union { uint32 asInt; float asFloat; } n; n.asInt = ByteOrder::swap (*(uint32*) data); return n.asFloat; }
|
|
inline void setAsFloatBE (float newValue) noexcept { union { uint32 asInt; float asFloat; } n; n.asFloat = newValue; *(uint32*) data = ByteOrder::swap (n.asInt); }
|
|
#endif
|
|
inline int32 getAsInt32LE() const noexcept { return (int32) roundToInt (jlimit (-1.0, 1.0, (double) getAsFloatLE()) * (double) maxValue); }
|
|
inline int32 getAsInt32BE() const noexcept { return (int32) roundToInt (jlimit (-1.0, 1.0, (double) getAsFloatBE()) * (double) maxValue); }
|
|
inline void setAsInt32LE (int32 newValue) noexcept { setAsFloatLE ((float) (newValue * (1.0 / (1.0 + maxValue)))); }
|
|
inline void setAsInt32BE (int32 newValue) noexcept { setAsFloatBE ((float) (newValue * (1.0 / (1.0 + maxValue)))); }
|
|
inline void clear() noexcept { *data = 0; }
|
|
inline void clearMultiple (int num) noexcept { zeromem (data, num * bytesPerSample) ;}
|
|
template <class SourceType> inline void copyFromLE (SourceType& source) noexcept { setAsFloatLE (source.getAsFloat()); }
|
|
template <class SourceType> inline void copyFromBE (SourceType& source) noexcept { setAsFloatBE (source.getAsFloat()); }
|
|
inline void copyFromSameType (Float32& source) noexcept { *data = *source.data; }
|
|
|
|
float* data;
|
|
enum { bytesPerSample = 4, maxValue = 0x7fffffff, resolution = (1 << 8), isFloat = 1 };
|
|
};
|
|
|
|
class NonInterleaved
|
|
{
|
|
public:
|
|
inline NonInterleaved() noexcept {}
|
|
inline NonInterleaved (const NonInterleaved&) noexcept {}
|
|
inline NonInterleaved (const int) noexcept {}
|
|
inline void copyFrom (const NonInterleaved&) noexcept {}
|
|
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) noexcept { s.advance(); }
|
|
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) noexcept { s.skip (numSamples); }
|
|
template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) noexcept { s.clearMultiple (numSamples); }
|
|
template <class SampleFormatType> inline static int getNumBytesBetweenSamples (const SampleFormatType&) noexcept { return SampleFormatType::bytesPerSample; }
|
|
|
|
enum { isInterleavedType = 0, numInterleavedChannels = 1 };
|
|
};
|
|
|
|
class Interleaved
|
|
{
|
|
public:
|
|
inline Interleaved() noexcept : numInterleavedChannels (1) {}
|
|
inline Interleaved (const Interleaved& other) noexcept : numInterleavedChannels (other.numInterleavedChannels) {}
|
|
inline Interleaved (const int numInterleavedChannels_) noexcept : numInterleavedChannels (numInterleavedChannels_) {}
|
|
inline void copyFrom (const Interleaved& other) noexcept { numInterleavedChannels = other.numInterleavedChannels; }
|
|
template <class SampleFormatType> inline void advanceData (SampleFormatType& s) noexcept { s.skip (numInterleavedChannels); }
|
|
template <class SampleFormatType> inline void advanceDataBy (SampleFormatType& s, int numSamples) noexcept { s.skip (numInterleavedChannels * numSamples); }
|
|
template <class SampleFormatType> inline void clear (SampleFormatType& s, int numSamples) noexcept { while (--numSamples >= 0) { s.clear(); s.skip (numInterleavedChannels); } }
|
|
template <class SampleFormatType> inline int getNumBytesBetweenSamples (const SampleFormatType&) const noexcept { return numInterleavedChannels * SampleFormatType::bytesPerSample; }
|
|
int numInterleavedChannels;
|
|
enum { isInterleavedType = 1 };
|
|
};
|
|
|
|
class NonConst
|
|
{
|
|
public:
|
|
typedef void VoidType;
|
|
static inline void* toVoidPtr (VoidType* v) noexcept { return v; }
|
|
enum { isConst = 0 };
|
|
};
|
|
|
|
class Const
|
|
{
|
|
public:
|
|
typedef const void VoidType;
|
|
static inline void* toVoidPtr (VoidType* v) noexcept { return const_cast<void*> (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 <AudioData::Int16,
|
|
AudioData::LittleEndian,
|
|
AudioData::NonInterleaved,
|
|
AudioData::Const> 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 <typename SampleFormat,
|
|
typename Endianness,
|
|
typename InterleavingType,
|
|
typename Constness>
|
|
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) noexcept
|
|
: 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) noexcept
|
|
: data (Constness::toVoidPtr (sourceData)),
|
|
interleaving (numInterleavedChannels)
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another pointer. */
|
|
Pointer (const Pointer& other) noexcept
|
|
: data (other.data),
|
|
interleaving (other.interleaving)
|
|
{
|
|
}
|
|
|
|
Pointer& operator= (const Pointer& other) noexcept
|
|
{
|
|
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 noexcept { 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) noexcept
|
|
{
|
|
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 noexcept { 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) noexcept
|
|
{
|
|
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++() noexcept { advance(); return *this; }
|
|
|
|
/** Moves the pointer back to the previous sample. */
|
|
inline Pointer& operator--() noexcept { interleaving.advanceDataBy (data, -1); return *this; }
|
|
|
|
/** Adds a number of samples to the pointer's position. */
|
|
Pointer& operator+= (int samplesToJump) noexcept { 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 noexcept
|
|
{
|
|
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 <class OtherPointerType>
|
|
void convertSamples (OtherPointerType source, int numSamples) const noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
Pointer dest (*this);
|
|
dest.interleaving.clear (dest.data, numSamples);
|
|
}
|
|
|
|
/** Returns true if the pointer is using a floating-point format. */
|
|
static bool isFloatingPoint() noexcept { return (bool) SampleFormat::isFloat; }
|
|
|
|
/** Returns true if the format is big-endian. */
|
|
static bool isBigEndian() noexcept { return (bool) Endianness::isBigEndian; }
|
|
|
|
/** Returns the number of bytes in each sample (ignoring the number of interleaved channels). */
|
|
static int getBytesPerSample() noexcept { return (int) SampleFormat::bytesPerSample; }
|
|
|
|
/** Returns the number of interleaved channels in the format. */
|
|
int getNumInterleavedChannels() const noexcept { return (int) this->numInterleavedChannels; }
|
|
|
|
/** Returns the number of bytes between the start address of each sample. */
|
|
int getNumBytesBetweenSamples() const noexcept { 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() noexcept { return (int) SampleFormat::resolution; }
|
|
|
|
/** Returns a pointer to the underlying data. */
|
|
const void* getRawData() const noexcept { 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() noexcept { 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 SourceSampleType, class DestSampleType>
|
|
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 noexcept { 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 <class DestSampleType, class SourceSampleType, class SourceEndianness>
|
|
struct ReadHelper
|
|
{
|
|
typedef AudioData::Pointer <DestSampleType, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::NonConst> DestType;
|
|
typedef AudioData::Pointer <SourceSampleType, SourceEndianness, AudioData::Interleaved, AudioData::Const> SourceType;
|
|
|
|
static void read (int** destData, int destOffset, int numDestChannels, const void* sourceData, int numSourceChannels, int numSamples) noexcept
|
|
{
|
|
for (int i = 0; i < numDestChannels; ++i)
|
|
{
|
|
if (destData[i] != nullptr)
|
|
{
|
|
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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 startSample the offset within the arrays at which the data begins
|
|
@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 startSample,
|
|
int numSamples) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Copies another buffer onto this one.
|
|
|
|
This buffer's size will be changed to that of the other buffer.
|
|
*/
|
|
AudioSampleBuffer& operator= (const AudioSampleBuffer& other) noexcept;
|
|
|
|
/** Destructor.
|
|
|
|
This will free any memory allocated by the buffer.
|
|
*/
|
|
virtual ~AudioSampleBuffer() noexcept;
|
|
|
|
/** Returns the number of channels of audio data that this buffer contains.
|
|
|
|
@see getSampleData
|
|
*/
|
|
int getNumChannels() const noexcept { return numChannels; }
|
|
|
|
/** Returns the number of samples allocated in each of the buffer's channels.
|
|
|
|
@see getSampleData
|
|
*/
|
|
int getNumSamples() const noexcept { 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 noexcept
|
|
{
|
|
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 noexcept
|
|
{
|
|
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 noexcept { 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Clears all the samples in all channels. */
|
|
void clear() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Finds the highest absolute sample value within a region of a channel.
|
|
*/
|
|
float getMagnitude (int channel,
|
|
int startSample,
|
|
int numSamples) const noexcept;
|
|
|
|
/** Finds the highest absolute sample value within a region on all channels.
|
|
*/
|
|
float getMagnitude (int startSample,
|
|
int numSamples) const noexcept;
|
|
|
|
/** Returns the root mean squared level for a region of a channel.
|
|
*/
|
|
float getRMSLevel (int channel,
|
|
int startSample,
|
|
int numSamples) const noexcept;
|
|
|
|
/** 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,
|
|
int64 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 <char> allocatedData;
|
|
float* preallocatedChannelSpace [32];
|
|
|
|
void allocateData();
|
|
void allocateChannels (float** dataToReferTo, int offset);
|
|
|
|
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 != nullptr)
|
|
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() noexcept {}
|
|
|
|
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 noexcept { 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 noexcept { return sampleRate; }
|
|
|
|
/** Returns the number of channels being written. */
|
|
int getNumChannels() const noexcept { return numChannels; }
|
|
|
|
/** Returns the bit-depth of the data being written. */
|
|
int getBitsPerSample() const noexcept { return bitsPerSample; }
|
|
|
|
/** Returns true if it's a floating-point format, false if it's fixed-point. */
|
|
bool isFloatingPoint() const noexcept { 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);
|
|
|
|
#ifndef DOXYGEN
|
|
class Buffer; // (only public for VC6 compatibility)
|
|
#endif
|
|
|
|
private:
|
|
friend class ScopedPointer<Buffer>;
|
|
ScopedPointer<Buffer> 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 <class DestSampleType, class SourceSampleType, class DestEndianness>
|
|
struct WriteHelper
|
|
{
|
|
typedef AudioData::Pointer <DestSampleType, DestEndianness, AudioData::Interleaved, AudioData::NonConst> DestType;
|
|
typedef AudioData::Pointer <SourceSampleType, AudioData::NativeEndian, AudioData::NonInterleaved, AudioData::Const> SourceType;
|
|
|
|
static void write (void* destData, int numDestChannels, const int** source,
|
|
int numSamples, const int sourceOffset = 0) noexcept
|
|
{
|
|
for (int i = 0; i < numDestChannels; ++i)
|
|
{
|
|
const DestType dest (addBytesToPointer (destData, i * DestType::getBytesPerSample()), numDestChannels);
|
|
|
|
if (*source != nullptr)
|
|
{
|
|
dest.convertSamples (SourceType (*source + sourceOffset), 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 <int> getPossibleSampleRates() = 0;
|
|
|
|
/** Returns a set of bit depths that the format can read and write. */
|
|
virtual const Array <int> 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 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 <int> getPossibleSampleRates();
|
|
const Array <int> 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_DECLARE_NON_COPYABLE_WITH_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 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
|
|
*/
|
|
Array<int> 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() noexcept {}
|
|
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.
|
|
*/
|
|
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<Pimpl>;
|
|
ScopedPointer<Pimpl> 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 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<int>& 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 <int> 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<int> trackStartSamples;
|
|
|
|
#if JUCE_MAC
|
|
File volumeDir;
|
|
Array<File> tracks;
|
|
int currentReaderTrack;
|
|
ScopedPointer <AudioFormatReader> reader;
|
|
AudioCDReader (const File& volume);
|
|
|
|
#elif JUCE_WINDOWS
|
|
bool audioTracks [100];
|
|
void* handle;
|
|
MemoryBlock buffer;
|
|
bool indexingEnabled;
|
|
int lastIndex, firstFrameInBuffer, samplesInBuffer;
|
|
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.
|
|
|
|
After creating an AudioFormatManager object, you should call registerFormat()
|
|
or registerBasicFormats() to give it a list of format types that it can 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.
|
|
*/
|
|
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<AudioFormat> 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 noexcept;
|
|
|
|
/** Returns the length of the audio file, in seconds. */
|
|
double getTotalLength() const noexcept;
|
|
|
|
/** 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<int>& 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<int>& area,
|
|
double startTimeSeconds,
|
|
double endTimeSeconds,
|
|
float verticalZoomFactor);
|
|
|
|
/** Returns true if the low res preview is fully generated. */
|
|
bool isFullyLoaded() const noexcept;
|
|
|
|
/** Returns the number of samples that have been set in the thumbnail. */
|
|
int64 getNumSamplesFinished() const noexcept;
|
|
|
|
/** 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;
|
|
|
|
/** Reads the approximate min and max levels from a section of the thumbnail.
|
|
The lowest and highest samples are returned in minValue and maxValue, but obviously
|
|
because the thumb only stores low-resolution data, these numbers will only be a rough
|
|
approximation of the true values.
|
|
*/
|
|
void getApproximateMinMax (double startTime, double endTime, int channelIndex,
|
|
float& minValue, float& maxValue) const noexcept;
|
|
|
|
/** Returns the hash code that was set by setSource() or setReader(). */
|
|
int64 getHashCode() const;
|
|
|
|
#ifndef DOXYGEN
|
|
class LevelDataSource; // (this is only public to avoid a VC6 bug)
|
|
#endif
|
|
|
|
private:
|
|
|
|
AudioFormatManager& formatManagerToUse;
|
|
AudioThumbnailCache& cache;
|
|
|
|
struct MinMaxValue;
|
|
class ThumbData;
|
|
class CachedWindow;
|
|
|
|
friend class LevelDataSource;
|
|
friend class ScopedPointer<LevelDataSource>;
|
|
friend class ThumbData;
|
|
friend class OwnedArray<ThumbData>;
|
|
friend class CachedWindow;
|
|
friend class ScopedPointer<CachedWindow>;
|
|
|
|
ScopedPointer<LevelDataSource> source;
|
|
ScopedPointer<CachedWindow> window;
|
|
OwnedArray<ThumbData> channels;
|
|
|
|
int32 samplesPerThumbSample;
|
|
int64 totalSamples, numSamplesFinished;
|
|
int32 numChannels;
|
|
double sampleRate;
|
|
CriticalSection lock;
|
|
|
|
void clearChannelData();
|
|
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 <ThumbnailCacheEntry> 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_COREAUDIOFORMAT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_CoreAudioFormat.h ***/
|
|
#ifndef __JUCE_COREAUDIOFORMAT_JUCEHEADER__
|
|
#define __JUCE_COREAUDIOFORMAT_JUCEHEADER__
|
|
|
|
#if JUCE_MAC || JUCE_IOS
|
|
|
|
/**
|
|
OSX and iOS only - This uses the AudioToolbox framework to read any audio
|
|
format that the system has a codec for.
|
|
|
|
This should be able to understand formats such as mp3, m4a, etc.
|
|
|
|
@see AudioFormat
|
|
*/
|
|
class JUCE_API CoreAudioFormat : public AudioFormat
|
|
{
|
|
public:
|
|
|
|
/** Creates a format object. */
|
|
CoreAudioFormat();
|
|
|
|
/** Destructor. */
|
|
~CoreAudioFormat();
|
|
|
|
const Array <int> getPossibleSampleRates();
|
|
const Array <int> 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_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CoreAudioFormat);
|
|
};
|
|
|
|
#endif
|
|
#endif // __JUCE_COREAUDIOFORMAT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CoreAudioFormat.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 <int> getPossibleSampleRates();
|
|
const Array <int> getPossibleBitDepths();
|
|
bool canDoStereo();
|
|
bool canDoMono();
|
|
bool isCompressed();
|
|
StringArray getQualityOptions();
|
|
|
|
AudioFormatReader* createReaderFor (InputStream* sourceStream,
|
|
bool deleteStreamIfOpeningFails);
|
|
|
|
AudioFormatWriter* createWriterFor (OutputStream* streamToWriteTo,
|
|
double sampleRateToUse,
|
|
unsigned int numberOfChannels,
|
|
int bitsPerSample,
|
|
const StringPairArray& metadataValues,
|
|
int qualityOptionIndex);
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_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<int> getPossibleSampleRates();
|
|
const Array<int> getPossibleBitDepths();
|
|
bool canDoStereo();
|
|
bool canDoMono();
|
|
bool isCompressed();
|
|
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_DECLARE_NON_COPYABLE_WITH_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 <int> getPossibleSampleRates();
|
|
const Array <int> 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_DECLARE_NON_COPYABLE_WITH_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 StringPairArray createBWAVMetadata (const String& description,
|
|
const String& originator,
|
|
const String& originatorRef,
|
|
const Time& dateAndTime,
|
|
const int64 timeReferenceSamples,
|
|
const String& codingHistory);
|
|
|
|
const Array <int> getPossibleSampleRates();
|
|
const Array <int> 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_DECLARE_NON_COPYABLE_WITH_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() noexcept {}
|
|
|
|
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 (int64 newPosition) = 0;
|
|
|
|
/** Returns the position from which the next block will be returned.
|
|
|
|
@see setNextReadPosition
|
|
*/
|
|
virtual int64 getNextReadPosition() const = 0;
|
|
|
|
/** Returns the total length of the stream (in samples). */
|
|
virtual int64 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 - this must
|
|
not be null
|
|
@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 noexcept { 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 (int64 newPosition);
|
|
|
|
/** Implements the PositionableAudioSource method. */
|
|
int64 getNextReadPosition() const;
|
|
|
|
/** Implements the PositionableAudioSource method. */
|
|
int64 getTotalLength() const;
|
|
|
|
private:
|
|
|
|
OptionalScopedPointer<AudioFormatReader> reader;
|
|
|
|
int64 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;
|
|
|
|
/** This can be overridden to be told if the device generates an error while operating.
|
|
Be aware that this could be called by any thread! And not all devices perform
|
|
this callback.
|
|
*/
|
|
virtual void audioDeviceError (const String& errorMessage);
|
|
};
|
|
|
|
/**
|
|
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 noexcept { 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 noexcept { 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 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 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 noexcept { return source; }
|
|
|
|
/** Sets a gain to apply to the audio data.
|
|
@see getGain
|
|
*/
|
|
void setGain (float newGain) noexcept;
|
|
|
|
/** Returns the current gain.
|
|
@see setGain
|
|
*/
|
|
float getGain() const noexcept { 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
|
|
@param numberOfChannels the number of channels that will be played
|
|
*/
|
|
BufferingAudioSource (PositionableAudioSource* source,
|
|
bool deleteSourceWhenDeleted,
|
|
int numberOfSamplesToBuffer,
|
|
int numberOfChannels = 2);
|
|
|
|
/** 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 (int64 newPosition);
|
|
|
|
/** Implements the PositionableAudioSource method. */
|
|
int64 getNextReadPosition() const;
|
|
|
|
/** Implements the PositionableAudioSource method. */
|
|
int64 getTotalLength() const { return source->getTotalLength(); }
|
|
|
|
/** Implements the PositionableAudioSource method. */
|
|
bool isLooping() const { return source->isLooping(); }
|
|
|
|
private:
|
|
|
|
OptionalScopedPointer<PositionableAudioSource> source;
|
|
int numberOfSamplesToBuffer, numberOfChannels;
|
|
AudioSampleBuffer buffer;
|
|
CriticalSection bufferStartPosLock;
|
|
int64 volatile bufferValidStart, bufferValidEnd, nextPlayPos;
|
|
double volatile sampleRate;
|
|
bool wasSourceLooping;
|
|
|
|
friend class SharedBufferingAudioSourceThread;
|
|
bool readNextBufferChunk();
|
|
void readBufferSection (int64 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 noexcept { return ratio; }
|
|
|
|
void prepareToPlay (int samplesPerBlockExpected, double sampleRate);
|
|
void releaseResources();
|
|
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill);
|
|
|
|
private:
|
|
|
|
OptionalScopedPointer<AudioSource> input;
|
|
double ratio, lastRatio;
|
|
AudioSampleBuffer buffer;
|
|
int bufferPos, sampsInBuffer;
|
|
double subSampleOffset;
|
|
double coefficients[6];
|
|
SpinLock ratioLock;
|
|
const int numChannels;
|
|
HeapBlock<float*> 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<FilterState> 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
|
|
@param maxNumChannels the maximum number of channels that may need to be played
|
|
*/
|
|
void setSource (PositionableAudioSource* newSource,
|
|
int readAheadBufferSize = 0,
|
|
double sourceSampleRateToCorrectFor = 0.0,
|
|
int maxNumChannels = 2);
|
|
|
|
/** 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 noexcept { 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 noexcept { 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) noexcept;
|
|
|
|
/** Returns the current gain setting.
|
|
|
|
@see setGain
|
|
*/
|
|
float getGain() const noexcept { 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 (int64 newPosition);
|
|
|
|
/** Implements the PositionableAudioSource method. */
|
|
int64 getNextReadPosition() const;
|
|
|
|
/** Implements the PositionableAudioSource method. */
|
|
int64 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;
|
|
|
|
void releaseMasterResources();
|
|
|
|
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:
|
|
|
|
OptionalScopedPointer<AudioSource> source;
|
|
Array <int> remappedInputs, remappedOutputs;
|
|
int requiredNumberOfChannels;
|
|
|
|
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() noexcept;
|
|
|
|
/** Performs the filter operation on the given set of samples.
|
|
*/
|
|
void processSamples (float* samples,
|
|
int numSamples) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Sets the filter up to act as a low-pass filter.
|
|
*/
|
|
void makeLowPass (double sampleRate,
|
|
double frequency) noexcept;
|
|
|
|
/** Sets the filter up to act as a high-pass filter.
|
|
*/
|
|
void makeHighPass (double sampleRate,
|
|
double frequency) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Clears the filter's coefficients so that it becomes inactive.
|
|
*/
|
|
void makeInactive() noexcept;
|
|
|
|
/** Makes this filter duplicate the set-up of another one.
|
|
*/
|
|
void copyCoefficientsFrom (const IIRFilter& other) noexcept;
|
|
|
|
protected:
|
|
|
|
CriticalSection processLock;
|
|
|
|
void setCoefficients (double c1, double c2, double c3,
|
|
double c4, double c5, double c6) noexcept;
|
|
|
|
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 - this must not be null
|
|
@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:
|
|
|
|
OptionalScopedPointer<AudioSource> input;
|
|
OwnedArray <IIRFilter> 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 <AudioSource*> 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_REVERBAUDIOSOURCE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ReverbAudioSource.h ***/
|
|
#ifndef __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__
|
|
#define __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_Reverb.h ***/
|
|
#ifndef __JUCE_REVERB_JUCEHEADER__
|
|
#define __JUCE_REVERB_JUCEHEADER__
|
|
|
|
/**
|
|
Performs a simple reverb effect on a stream of audio data.
|
|
|
|
This is a simple stereo reverb, based on the technique and tunings used in FreeVerb.
|
|
Use setSampleRate() to prepare it, and then call processStereo() or processMono() to
|
|
apply the reverb to your audio data.
|
|
|
|
@see ReverbAudioSource
|
|
*/
|
|
class Reverb
|
|
{
|
|
public:
|
|
|
|
Reverb()
|
|
{
|
|
setParameters (Parameters());
|
|
setSampleRate (44100.0);
|
|
}
|
|
|
|
/** Holds the parameters being used by a Reverb object. */
|
|
struct Parameters
|
|
{
|
|
Parameters() noexcept
|
|
: roomSize (0.5f),
|
|
damping (0.5f),
|
|
wetLevel (0.33f),
|
|
dryLevel (0.4f),
|
|
width (1.0f),
|
|
freezeMode (0)
|
|
{}
|
|
|
|
float roomSize; /**< Room size, 0 to 1.0, where 1.0 is big, 0 is small. */
|
|
float damping; /**< Damping, 0 to 1.0, where 0 is not damped, 1.0 is fully damped. */
|
|
float wetLevel; /**< Wet level, 0 to 1.0 */
|
|
float dryLevel; /**< Dry level, 0 to 1.0 */
|
|
float width; /**< Reverb width, 0 to 1.0, where 1.0 is very wide. */
|
|
float freezeMode; /**< Freeze mode - values < 0.5 are "normal" mode, values > 0.5
|
|
put the reverb into a continuous feedback loop. */
|
|
};
|
|
|
|
/** Returns the reverb's current parameters. */
|
|
const Parameters& getParameters() const noexcept { return parameters; }
|
|
|
|
/** Applies a new set of parameters to the reverb.
|
|
Note that this doesn't attempt to lock the reverb, so if you call this in parallel with
|
|
the process method, you may get artifacts.
|
|
*/
|
|
void setParameters (const Parameters& newParams)
|
|
{
|
|
const float wetScaleFactor = 3.0f;
|
|
const float dryScaleFactor = 2.0f;
|
|
|
|
const float wet = newParams.wetLevel * wetScaleFactor;
|
|
wet1 = wet * (newParams.width * 0.5f + 0.5f);
|
|
wet2 = wet * (1.0f - newParams.width) * 0.5f;
|
|
dry = newParams.dryLevel * dryScaleFactor;
|
|
gain = isFrozen (newParams.freezeMode) ? 0.0f : 0.015f;
|
|
parameters = newParams;
|
|
shouldUpdateDamping = true;
|
|
}
|
|
|
|
/** Sets the sample rate that will be used for the reverb.
|
|
You must call this before the process methods, in order to tell it the correct sample rate.
|
|
*/
|
|
void setSampleRate (const double sampleRate)
|
|
{
|
|
jassert (sampleRate > 0);
|
|
|
|
static const short combTunings[] = { 1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617 }; // (at 44100Hz)
|
|
static const short allPassTunings[] = { 556, 441, 341, 225 };
|
|
const int stereoSpread = 23;
|
|
const int intSampleRate = (int) sampleRate;
|
|
|
|
int i;
|
|
for (i = 0; i < numCombs; ++i)
|
|
{
|
|
comb[0][i].setSize ((intSampleRate * combTunings[i]) / 44100);
|
|
comb[1][i].setSize ((intSampleRate * (combTunings[i] + stereoSpread)) / 44100);
|
|
}
|
|
|
|
for (i = 0; i < numAllPasses; ++i)
|
|
{
|
|
allPass[0][i].setSize ((intSampleRate * allPassTunings[i]) / 44100);
|
|
allPass[1][i].setSize ((intSampleRate * (allPassTunings[i] + stereoSpread)) / 44100);
|
|
}
|
|
|
|
shouldUpdateDamping = true;
|
|
}
|
|
|
|
/** Clears the reverb's buffers. */
|
|
void reset()
|
|
{
|
|
for (int j = 0; j < numChannels; ++j)
|
|
{
|
|
int i;
|
|
for (i = 0; i < numCombs; ++i)
|
|
comb[j][i].clear();
|
|
|
|
for (i = 0; i < numAllPasses; ++i)
|
|
allPass[j][i].clear();
|
|
}
|
|
}
|
|
|
|
/** Applies the reverb to two stereo channels of audio data. */
|
|
void processStereo (float* const left, float* const right, const int numSamples) noexcept
|
|
{
|
|
jassert (left != nullptr && right != nullptr);
|
|
|
|
if (shouldUpdateDamping)
|
|
updateDamping();
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
{
|
|
const float input = (left[i] + right[i]) * gain;
|
|
float outL = 0, outR = 0;
|
|
|
|
int j;
|
|
for (j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
|
|
{
|
|
outL += comb[0][j].process (input);
|
|
outR += comb[1][j].process (input);
|
|
}
|
|
|
|
for (j = 0; j < numAllPasses; ++j) // run the allpass filters in series
|
|
{
|
|
outL = allPass[0][j].process (outL);
|
|
outR = allPass[1][j].process (outR);
|
|
}
|
|
|
|
left[i] = outL * wet1 + outR * wet2 + left[i] * dry;
|
|
right[i] = outR * wet1 + outL * wet2 + right[i] * dry;
|
|
}
|
|
}
|
|
|
|
/** Applies the reverb to a single mono channel of audio data. */
|
|
void processMono (float* const samples, const int numSamples) noexcept
|
|
{
|
|
jassert (samples != nullptr);
|
|
|
|
if (shouldUpdateDamping)
|
|
updateDamping();
|
|
|
|
for (int i = 0; i < numSamples; ++i)
|
|
{
|
|
const float input = samples[i] * gain;
|
|
float output = 0;
|
|
|
|
int j;
|
|
for (j = 0; j < numCombs; ++j) // accumulate the comb filters in parallel
|
|
output += comb[0][j].process (input);
|
|
|
|
for (j = 0; j < numAllPasses; ++j) // run the allpass filters in series
|
|
output = allPass[0][j].process (output);
|
|
|
|
samples[i] = output * wet1 + input * dry;
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
Parameters parameters;
|
|
|
|
volatile bool shouldUpdateDamping;
|
|
float gain, wet1, wet2, dry;
|
|
|
|
inline static bool isFrozen (const float freezeMode) noexcept { return freezeMode >= 0.5f; }
|
|
|
|
void updateDamping() noexcept
|
|
{
|
|
const float roomScaleFactor = 0.28f;
|
|
const float roomOffset = 0.7f;
|
|
const float dampScaleFactor = 0.4f;
|
|
|
|
shouldUpdateDamping = false;
|
|
|
|
if (isFrozen (parameters.freezeMode))
|
|
setDamping (1.0f, 0.0f);
|
|
else
|
|
setDamping (parameters.damping * dampScaleFactor,
|
|
parameters.roomSize * roomScaleFactor + roomOffset);
|
|
}
|
|
|
|
void setDamping (const float dampingToUse, const float roomSizeToUse) noexcept
|
|
{
|
|
for (int j = 0; j < numChannels; ++j)
|
|
for (int i = numCombs; --i >= 0;)
|
|
comb[j][i].setFeedbackAndDamp (roomSizeToUse, dampingToUse);
|
|
}
|
|
|
|
class CombFilter
|
|
{
|
|
public:
|
|
CombFilter() noexcept : bufferSize (0), bufferIndex (0) {}
|
|
|
|
void setSize (const int size)
|
|
{
|
|
if (size != bufferSize)
|
|
{
|
|
bufferIndex = 0;
|
|
buffer.malloc (size);
|
|
bufferSize = size;
|
|
}
|
|
|
|
clear();
|
|
}
|
|
|
|
void clear() noexcept
|
|
{
|
|
last = 0;
|
|
buffer.clear (bufferSize);
|
|
}
|
|
|
|
void setFeedbackAndDamp (const float f, const float d) noexcept
|
|
{
|
|
damp1 = d;
|
|
damp2 = 1.0f - d;
|
|
feedback = f;
|
|
}
|
|
|
|
inline float process (const float input) noexcept
|
|
{
|
|
const float output = buffer [bufferIndex];
|
|
last = (output * damp2) + (last * damp1);
|
|
JUCE_UNDENORMALISE (last);
|
|
|
|
float temp = input + (last * feedback);
|
|
JUCE_UNDENORMALISE (temp);
|
|
buffer [bufferIndex] = temp;
|
|
bufferIndex = (bufferIndex + 1) % bufferSize;
|
|
return output;
|
|
}
|
|
|
|
private:
|
|
HeapBlock<float> buffer;
|
|
int bufferSize, bufferIndex;
|
|
float feedback, last, damp1, damp2;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (CombFilter);
|
|
};
|
|
|
|
class AllPassFilter
|
|
{
|
|
public:
|
|
AllPassFilter() noexcept : bufferSize (0), bufferIndex (0) {}
|
|
|
|
void setSize (const int size)
|
|
{
|
|
if (size != bufferSize)
|
|
{
|
|
bufferIndex = 0;
|
|
buffer.malloc (size);
|
|
bufferSize = size;
|
|
}
|
|
|
|
clear();
|
|
}
|
|
|
|
void clear() noexcept
|
|
{
|
|
buffer.clear (bufferSize);
|
|
}
|
|
|
|
inline float process (const float input) noexcept
|
|
{
|
|
const float bufferedValue = buffer [bufferIndex];
|
|
float temp = input + (bufferedValue * 0.5f);
|
|
JUCE_UNDENORMALISE (temp);
|
|
buffer [bufferIndex] = temp;
|
|
bufferIndex = (bufferIndex + 1) % bufferSize;
|
|
return bufferedValue - input;
|
|
}
|
|
|
|
private:
|
|
HeapBlock<float> buffer;
|
|
int bufferSize, bufferIndex;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (AllPassFilter);
|
|
};
|
|
|
|
enum { numCombs = 8, numAllPasses = 4, numChannels = 2 };
|
|
|
|
CombFilter comb [numChannels][numCombs];
|
|
AllPassFilter allPass [numChannels][numAllPasses];
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Reverb);
|
|
};
|
|
|
|
#endif // __JUCE_REVERB_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Reverb.h ***/
|
|
|
|
/**
|
|
An AudioSource that uses the Reverb class to apply a reverb to another AudioSource.
|
|
|
|
@see Reverb
|
|
*/
|
|
class JUCE_API ReverbAudioSource : public AudioSource
|
|
{
|
|
public:
|
|
/** Creates a ReverbAudioSource to process a given input source.
|
|
|
|
@param inputSource the input source to read from - this must not be null
|
|
@param deleteInputWhenDeleted if true, the input source will be deleted when
|
|
this object is deleted
|
|
*/
|
|
ReverbAudioSource (AudioSource* inputSource,
|
|
bool deleteInputWhenDeleted);
|
|
|
|
/** Destructor. */
|
|
~ReverbAudioSource();
|
|
|
|
/** Returns the parameters from the reverb. */
|
|
const Reverb::Parameters& getParameters() const noexcept { return reverb.getParameters(); }
|
|
|
|
/** Changes the reverb's parameters. */
|
|
void setParameters (const Reverb::Parameters& newParams);
|
|
|
|
void setBypassed (bool isBypassed) noexcept;
|
|
bool isBypassed() const noexcept { return bypass; }
|
|
|
|
void prepareToPlay (int samplesPerBlockExpected, double sampleRate);
|
|
void releaseResources();
|
|
void getNextAudioBlock (const AudioSourceChannelInfo& bufferToFill);
|
|
|
|
private:
|
|
|
|
CriticalSection lock;
|
|
OptionalScopedPointer<AudioSource> input;
|
|
Reverb reverb;
|
|
volatile bool bypass;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ReverbAudioSource);
|
|
};
|
|
|
|
#endif // __JUCE_REVERBAUDIOSOURCE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ReverbAudioSource.h ***/
|
|
|
|
|
|
#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;
|
|
|
|
/**
|
|
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 <AudioIODeviceType> 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 noexcept { 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 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;
|
|
|
|
/**
|
|
A class for receiving events when audio devices are inserted or removed.
|
|
|
|
You can register a AudioIODeviceType::Listener with an~AudioIODeviceType object
|
|
using the AudioIODeviceType::addListener() method, and it will be called when
|
|
devices of that type are added or removed.
|
|
|
|
@see AudioIODeviceType::addListener, AudioIODeviceType::removeListener
|
|
*/
|
|
class Listener
|
|
{
|
|
public:
|
|
virtual ~Listener() {}
|
|
|
|
/** Called when the list of available audio devices changes. */
|
|
virtual void audioDeviceListChanged() = 0;
|
|
};
|
|
|
|
/** Adds a listener that will be called when this type of device is added or
|
|
removed from the system.
|
|
*/
|
|
void addListener (Listener* listener);
|
|
|
|
/** Removes a listener that was previously added with addListener(). */
|
|
void removeListener (Listener* listener);
|
|
|
|
/** Destructor. */
|
|
virtual ~AudioIODeviceType();
|
|
|
|
/** Creates a CoreAudio device type if it's available on this platform, or returns null. */
|
|
static AudioIODeviceType* createAudioIODeviceType_CoreAudio();
|
|
/** Creates an iOS device type if it's available on this platform, or returns null. */
|
|
static AudioIODeviceType* createAudioIODeviceType_iOSAudio();
|
|
/** Creates a WASAPI device type if it's available on this platform, or returns null. */
|
|
static AudioIODeviceType* createAudioIODeviceType_WASAPI();
|
|
/** Creates a DirectSound device type if it's available on this platform, or returns null. */
|
|
static AudioIODeviceType* createAudioIODeviceType_DirectSound();
|
|
/** Creates an ASIO device type if it's available on this platform, or returns null. */
|
|
static AudioIODeviceType* createAudioIODeviceType_ASIO();
|
|
/** Creates an ALSA device type if it's available on this platform, or returns null. */
|
|
static AudioIODeviceType* createAudioIODeviceType_ALSA();
|
|
/** Creates a JACK device type if it's available on this platform, or returns null. */
|
|
static AudioIODeviceType* createAudioIODeviceType_JACK();
|
|
/** Creates an Android device type if it's available on this platform, or returns null. */
|
|
static AudioIODeviceType* createAudioIODeviceType_Android();
|
|
|
|
protected:
|
|
explicit AudioIODeviceType (const String& typeName);
|
|
|
|
/** Synchronously calls all the registered device list change listeners. */
|
|
void callDeviceChangeListeners();
|
|
|
|
private:
|
|
String typeName;
|
|
ListenerList<Listener> listeners;
|
|
|
|
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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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() noexcept;
|
|
|
|
/** 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 noexcept { return data; }
|
|
|
|
/** Returns the number of bytes of data in the message.
|
|
|
|
@see getRawData
|
|
*/
|
|
int getRawDataSize() const noexcept { 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 noexcept { 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) noexcept { timeStamp = newTimestamp; }
|
|
|
|
/** Adds a value to the message's timestamp.
|
|
|
|
The units for the timestamp will be application-specific.
|
|
*/
|
|
void addToTimeStamp (double delta) noexcept { 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Returns true if this is a system-exclusive message.
|
|
*/
|
|
bool isSysEx() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 MidiMessage noteOn (int channel, int noteNumber, float velocity) noexcept;
|
|
|
|
/** 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 MidiMessage noteOn (int channel, int noteNumber, uint8 velocity) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Creates a key-up message.
|
|
|
|
@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 isNoteOff
|
|
*/
|
|
static MidiMessage noteOff (int channel, int noteNumber, uint8 velocity = 0) noexcept;
|
|
|
|
/** Returns true if this message is a 'key-down' or 'key-up' event.
|
|
|
|
@see isNoteOn, isNoteOff
|
|
*/
|
|
bool isNoteOnOrOff() const noexcept;
|
|
|
|
/** 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 is undefined.
|
|
|
|
@see isNoteOff, getMidiNoteName, getMidiNoteInHertz, setNoteNumber
|
|
*/
|
|
int getNoteNumber() const noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Returns true if this message is a 'sustain pedal down' controller message. */
|
|
bool isSustainPedalOn() const noexcept;
|
|
/** Returns true if this message is a 'sustain pedal up' controller message. */
|
|
bool isSustainPedalOff() const noexcept;
|
|
|
|
/** Returns true if this message is a 'sostenuto pedal down' controller message. */
|
|
bool isSostenutoPedalOn() const noexcept;
|
|
/** Returns true if this message is a 'sostenuto pedal up' controller message. */
|
|
bool isSostenutoPedalOff() const noexcept;
|
|
|
|
/** Returns true if this message is a 'soft pedal down' controller message. */
|
|
bool isSoftPedalOn() const noexcept;
|
|
/** Returns true if this message is a 'soft pedal up' controller message. */
|
|
bool isSoftPedalOff() const noexcept;
|
|
|
|
/** Returns true if the message is a program (patch) change message.
|
|
|
|
@see getProgramChangeNumber, getGMInstrumentName
|
|
*/
|
|
bool isProgramChange() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 MidiMessage programChange (int channel, int programNumber) noexcept;
|
|
|
|
/** Returns true if the message is a pitch-wheel move.
|
|
|
|
@see getPitchWheelValue, pitchWheel
|
|
*/
|
|
bool isPitchWheel() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 MidiMessage pitchWheel (int channel, int position) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 MidiMessage aftertouchChange (int channel,
|
|
int noteNumber,
|
|
int aftertouchAmount) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the pressure from a channel pressure change message.
|
|
|
|
@returns the pressure, in the range 0 to 127
|
|
@see isChannelPressure, channelPressureChange
|
|
*/
|
|
int getChannelPressureValue() const noexcept;
|
|
|
|
/** Creates a channel-pressure change event.
|
|
|
|
@param channel the midi channel: 1 to 16
|
|
@param pressure the pressure, 0 to 127
|
|
@see isChannelPressure
|
|
*/
|
|
static MidiMessage channelPressureChange (int channel, int pressure) noexcept;
|
|
|
|
/** Returns true if this is a midi controller message.
|
|
|
|
@see getControllerNumber, getControllerValue, controllerEvent
|
|
*/
|
|
bool isController() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns true if this message is a controller message and if it has the specified
|
|
controller type.
|
|
*/
|
|
bool isControllerOfType (int controllerType) const noexcept;
|
|
|
|
/** 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 MidiMessage controllerEvent (int channel,
|
|
int controllerType,
|
|
int value) noexcept;
|
|
|
|
/** Checks whether this message is an all-notes-off message.
|
|
|
|
@see allNotesOff
|
|
*/
|
|
bool isAllNotesOff() const noexcept;
|
|
|
|
/** Checks whether this message is an all-sound-off message.
|
|
|
|
@see allSoundOff
|
|
*/
|
|
bool isAllSoundOff() const noexcept;
|
|
|
|
/** Creates an all-notes-off message.
|
|
|
|
@param channel the midi channel, in the range 1 to 16
|
|
@see isAllNotesOff
|
|
*/
|
|
static MidiMessage allNotesOff (int channel) noexcept;
|
|
|
|
/** Creates an all-sound-off message.
|
|
|
|
@param channel the midi channel, in the range 1 to 16
|
|
@see isAllSoundOff
|
|
*/
|
|
static MidiMessage allSoundOff (int channel) noexcept;
|
|
|
|
/** Creates an all-controllers-off message.
|
|
|
|
@param channel the midi channel, in the range 1 to 16
|
|
*/
|
|
static MidiMessage allControllersOff (int channel) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns a pointer to the data in a meta-event.
|
|
|
|
@see isMetaEvent, getMetaEventLength
|
|
*/
|
|
const uint8* getMetaEventData() const noexcept;
|
|
|
|
/** Returns the length of the data for a meta-event.
|
|
|
|
@see isMetaEvent, getMetaEventData
|
|
*/
|
|
int getMetaEventLength() const noexcept;
|
|
|
|
/** Returns true if this is a 'track' meta-event. */
|
|
bool isTrackMetaEvent() const noexcept;
|
|
|
|
/** Returns true if this is an 'end-of-track' meta-event. */
|
|
bool isEndOfTrackMetaEvent() const noexcept;
|
|
|
|
/** Creates an end-of-track meta-event.
|
|
|
|
@see isEndOfTrackMetaEvent
|
|
*/
|
|
static MidiMessage endOfTrack() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns true if this is a 'text' meta-event.
|
|
|
|
@see getTextFromTextMetaEvent
|
|
*/
|
|
bool isTextMetaEvent() const noexcept;
|
|
|
|
/** Returns the text from a text meta-event.
|
|
|
|
@see isTextMetaEvent
|
|
*/
|
|
String getTextFromTextMetaEvent() const;
|
|
|
|
/** Returns true if this is a 'tempo' meta-event.
|
|
|
|
@see getTempoMetaEventTickLength, getTempoSecondsPerQuarterNote
|
|
*/
|
|
bool isTempoMetaEvent() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Calculates the seconds-per-quarter-note from a tempo meta-event.
|
|
|
|
@see isTempoMetaEvent, getTempoMetaEventTickLength
|
|
*/
|
|
double getTempoSecondsPerQuarterNote() const noexcept;
|
|
|
|
/** Creates a tempo meta-event.
|
|
|
|
@see isTempoMetaEvent
|
|
*/
|
|
static MidiMessage tempoMetaEvent (int microsecondsPerQuarterNote) noexcept;
|
|
|
|
/** Returns true if this is a 'time-signature' meta-event.
|
|
|
|
@see getTimeSignatureInfo
|
|
*/
|
|
bool isTimeSignatureMetaEvent() const noexcept;
|
|
|
|
/** Returns the time-signature values from a time-signature meta-event.
|
|
|
|
@see isTimeSignatureMetaEvent
|
|
*/
|
|
void getTimeSignatureInfo (int& numerator, int& denominator) const noexcept;
|
|
|
|
/** Creates a time-signature meta-event.
|
|
|
|
@see isTimeSignatureMetaEvent
|
|
*/
|
|
static MidiMessage timeSignatureMetaEvent (int numerator, int denominator);
|
|
|
|
/** Returns true if this is a 'key-signature' meta-event.
|
|
|
|
@see getKeySignatureNumberOfSharpsOrFlats
|
|
*/
|
|
bool isKeySignatureMetaEvent() const noexcept;
|
|
|
|
/** Returns the key from a key-signature meta-event.
|
|
|
|
@see isKeySignatureMetaEvent
|
|
*/
|
|
int getKeySignatureNumberOfSharpsOrFlats() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the channel number from a channel meta-event.
|
|
|
|
@returns the channel, in the range 1 to 16.
|
|
@see isMidiChannelMetaEvent
|
|
*/
|
|
int getMidiChannelMetaEventChannel() const noexcept;
|
|
|
|
/** Creates a midi channel meta-event.
|
|
|
|
@param channel the midi channel, in the range 1 to 16
|
|
@see isMidiChannelMetaEvent
|
|
*/
|
|
static MidiMessage midiChannelMetaEvent (int channel) noexcept;
|
|
|
|
/** Returns true if this is an active-sense message. */
|
|
bool isActiveSense() const noexcept;
|
|
|
|
/** Returns true if this is a midi start event.
|
|
|
|
@see midiStart
|
|
*/
|
|
bool isMidiStart() const noexcept;
|
|
|
|
/** Creates a midi start event. */
|
|
static MidiMessage midiStart() noexcept;
|
|
|
|
/** Returns true if this is a midi continue event.
|
|
|
|
@see midiContinue
|
|
*/
|
|
bool isMidiContinue() const noexcept;
|
|
|
|
/** Creates a midi continue event. */
|
|
static MidiMessage midiContinue() noexcept;
|
|
|
|
/** Returns true if this is a midi stop event.
|
|
|
|
@see midiStop
|
|
*/
|
|
bool isMidiStop() const noexcept;
|
|
|
|
/** Creates a midi stop event. */
|
|
static MidiMessage midiStop() noexcept;
|
|
|
|
/** Returns true if this is a midi clock event.
|
|
|
|
@see midiClock, songPositionPointer
|
|
*/
|
|
bool isMidiClock() const noexcept;
|
|
|
|
/** Creates a midi clock event. */
|
|
static MidiMessage midiClock() noexcept;
|
|
|
|
/** Returns true if this is a song-position-pointer message.
|
|
|
|
@see getSongPositionPointerMidiBeat, songPositionPointer
|
|
*/
|
|
bool isSongPositionPointer() const noexcept;
|
|
|
|
/** Returns the midi beat-number of a song-position-pointer message.
|
|
|
|
@see isSongPositionPointer, songPositionPointer
|
|
*/
|
|
int getSongPositionPointerMidiBeat() const noexcept;
|
|
|
|
/** 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 MidiMessage songPositionPointer (int positionInMidiBeats) noexcept;
|
|
|
|
/** Returns true if this is a quarter-frame midi timecode message.
|
|
|
|
@see quarterFrame, getQuarterFrameSequenceNumber, getQuarterFrameValue
|
|
*/
|
|
bool isQuarterFrame() const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 MidiMessage quarterFrame (int sequenceNumber, int value) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Creates a full-frame MTC message.
|
|
*/
|
|
static 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Creates an MMC message.
|
|
*/
|
|
static 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 noexcept;
|
|
|
|
/** Creates an MMC "goto" message.
|
|
|
|
This messages tells the device to go to a specific frame.
|
|
|
|
@see isMidiMachineControlGoto
|
|
*/
|
|
static 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 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 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 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) noexcept;
|
|
|
|
/** Returns the standard name of a GM instrument.
|
|
|
|
@param midiInstrumentNumber the program number 0 to 127
|
|
@see getProgramChangeNumber
|
|
*/
|
|
static String getGMInstrumentName (int midiInstrumentNumber);
|
|
|
|
/** Returns the name of a bank of GM instruments.
|
|
|
|
@param midiBankNumber the bank, 0 to 15
|
|
*/
|
|
static String getGMInstrumentBankName (int midiBankNumber);
|
|
|
|
/** Returns the standard name of a channel 10 percussion sound.
|
|
|
|
@param midiNoteNumber the key number, 35 to 81
|
|
*/
|
|
static String getRhythmInstrumentName (int midiNoteNumber);
|
|
|
|
/** Returns the name of a controller type number.
|
|
|
|
@see getControllerNumber
|
|
*/
|
|
static 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 incoming messages from a physical 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 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. */
|
|
const String& getName() const noexcept { 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.
|
|
*/
|
|
void setName (const String& newName) noexcept { 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() noexcept;
|
|
|
|
/** Creates a MidiBuffer containing a single midi message. */
|
|
explicit MidiBuffer (const MidiMessage& message) noexcept;
|
|
|
|
/** Creates a copy of another MidiBuffer. */
|
|
MidiBuffer (const MidiBuffer& other) noexcept;
|
|
|
|
/** Makes a copy of another MidiBuffer. */
|
|
MidiBuffer& operator= (const MidiBuffer& other) noexcept;
|
|
|
|
/** Destructor */
|
|
~MidiBuffer();
|
|
|
|
/** Removes all events from the buffer. */
|
|
void clear() noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Returns the sample number of the last event in the buffer.
|
|
|
|
If the buffer's empty, this will just return 0.
|
|
*/
|
|
int getLastEventTime() const noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 JUCE_API Iterator
|
|
{
|
|
public:
|
|
|
|
/** Creates an Iterator for this MidiBuffer. */
|
|
Iterator (const MidiBuffer& buffer) noexcept;
|
|
|
|
/** Destructor. */
|
|
~Iterator() noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
private:
|
|
|
|
const MidiBuffer& buffer;
|
|
const uint8* data;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (Iterator);
|
|
};
|
|
|
|
private:
|
|
|
|
friend class MidiBuffer::Iterator;
|
|
MemoryBlock data;
|
|
int bytesUsed;
|
|
|
|
uint8* getData() const noexcept;
|
|
uint8* findEventAfter (uint8* d, int samplePosition) const noexcept;
|
|
static int getEventTime (const void* d) noexcept;
|
|
static uint16 getEventDataSize (const void* d) noexcept;
|
|
static uint16 getEventTotalSize (const void* d) noexcept;
|
|
|
|
JUCE_LEAK_DETECTOR (MidiBuffer);
|
|
};
|
|
|
|
#endif // __JUCE_MIDIBUFFER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MidiBuffer.h ***/
|
|
|
|
/**
|
|
Controls a physical MIDI output device.
|
|
|
|
To create one of these, use the static getDevices() method to get a list of the
|
|
available output devices, 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 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);
|
|
|
|
/** 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;
|
|
CriticalSection lock;
|
|
struct PendingMessage;
|
|
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 ***/
|
|
|
|
/**
|
|
Manages the state of some audio and midi i/o devices.
|
|
|
|
This class keeps tracks of a currently-selected audio device, through
|
|
with which it continuously streams data from an audio callback, as well as
|
|
one or more midi inputs.
|
|
|
|
The idea is that your application will create one global instance of this object,
|
|
and let it take care of creating and deleting specific types of audio devices
|
|
internally. So when the device is changed, your callbacks will just keep running
|
|
without having to worry about this.
|
|
|
|
The manager can save and reload all of its device settings as XML, which
|
|
makes it very easy for you to save and reload the audio setup of your
|
|
application.
|
|
|
|
And to make it easy to let the user change its settings, there's a component
|
|
to do just that - the AudioDeviceSelectorComponent class, which contains a set of
|
|
device selection/sample-rate/latency controls.
|
|
|
|
To use an AudioDeviceManager, create one, and use initialise() to set it up. Then
|
|
call addAudioCallback() to register your audio callback with it, and use that to process
|
|
your audio data.
|
|
|
|
The manager also acts as a handy hub for incoming midi messages, allowing a
|
|
listener to register for messages from either a specific midi device, or from whatever
|
|
the current default midi input device is. The listener then doesn't have to worry about
|
|
re-registering with different midi devices if they are changed or deleted.
|
|
|
|
And yet another neat trick is that amount of CPU time being used is measured and
|
|
available with the getCpuUsage() method.
|
|
|
|
The AudioDeviceManager is a ChangeBroadcaster, and will send a change message to
|
|
listeners whenever one of its settings is changed.
|
|
|
|
@see AudioDeviceSelectorComponent, AudioIODevice, AudioIODeviceType
|
|
*/
|
|
class JUCE_API AudioDeviceManager : public ChangeBroadcaster
|
|
{
|
|
public:
|
|
|
|
/** Creates a default AudioDeviceManager.
|
|
|
|
Initially no audio device will be selected. You should call the initialise() method
|
|
and register an audio callback with setAudioCallback() before it'll be able to
|
|
actually make any noise.
|
|
*/
|
|
AudioDeviceManager();
|
|
|
|
/** Destructor. */
|
|
~AudioDeviceManager();
|
|
|
|
/**
|
|
This structure holds a set of properties describing the current audio setup.
|
|
|
|
An AudioDeviceManager uses this class to save/load its current settings, and to
|
|
specify your preferred options when opening a device.
|
|
|
|
@see AudioDeviceManager::setAudioDeviceSetup(), AudioDeviceManager::initialise()
|
|
*/
|
|
struct JUCE_API AudioDeviceSetup
|
|
{
|
|
/** Creates an AudioDeviceSetup object.
|
|
|
|
The default constructor sets all the member variables to indicate default values.
|
|
You can then fill-in any values you want to before passing the object to
|
|
AudioDeviceManager::initialise().
|
|
*/
|
|
AudioDeviceSetup();
|
|
|
|
bool operator== (const AudioDeviceSetup& other) const;
|
|
|
|
/** The name of the audio device used for output.
|
|
The name has to be one of the ones listed by the AudioDeviceManager's currently
|
|
selected device type.
|
|
This may be the same as the input device.
|
|
An empty string indicates the default device.
|
|
*/
|
|
String outputDeviceName;
|
|
|
|
/** The name of the audio device used for input.
|
|
This may be the same as the output device.
|
|
An empty string indicates the default device.
|
|
*/
|
|
String inputDeviceName;
|
|
|
|
/** The current sample rate.
|
|
This rate is used for both the input and output devices.
|
|
A value of 0 indicates the default rate.
|
|
*/
|
|
double sampleRate;
|
|
|
|
/** The buffer size, in samples.
|
|
This buffer size is used for both the input and output devices.
|
|
A value of 0 indicates the default buffer size.
|
|
*/
|
|
int bufferSize;
|
|
|
|
/** The set of active input channels.
|
|
The bits that are set in this array indicate the channels of the
|
|
input device that are active.
|
|
If useDefaultInputChannels is true, this value is ignored.
|
|
*/
|
|
BigInteger inputChannels;
|
|
|
|
/** If this is true, it indicates that the inputChannels array
|
|
should be ignored, and instead, the device's default channels
|
|
should be used.
|
|
*/
|
|
bool useDefaultInputChannels;
|
|
|
|
/** The set of active output channels.
|
|
The bits that are set in this array indicate the channels of the
|
|
input device that are active.
|
|
If useDefaultOutputChannels is true, this value is ignored.
|
|
*/
|
|
BigInteger outputChannels;
|
|
|
|
/** If this is true, it indicates that the outputChannels array
|
|
should be ignored, and instead, the device's default channels
|
|
should be used.
|
|
*/
|
|
bool useDefaultOutputChannels;
|
|
};
|
|
|
|
/** Opens a set of audio devices ready for use.
|
|
|
|
This will attempt to open either a default audio device, or one that was
|
|
previously saved as XML.
|
|
|
|
@param numInputChannelsNeeded a minimum number of input channels needed
|
|
by your app.
|
|
@param numOutputChannelsNeeded a minimum number of output channels to open
|
|
@param savedState either a previously-saved state that was produced
|
|
by createStateXml(), or 0 if you want the manager
|
|
to choose the best device to open.
|
|
@param selectDefaultDeviceOnFailure if true, then if the device specified in the XML
|
|
fails to open, then a default device will be used
|
|
instead. If false, then on failure, no device is
|
|
opened.
|
|
@param preferredDefaultDeviceName if this is not empty, and there's a device with this
|
|
name, then that will be used as the default device
|
|
(assuming that there wasn't one specified in the XML).
|
|
The string can actually be a simple wildcard, containing "*"
|
|
and "?" characters
|
|
@param preferredSetupOptions if this is non-null, the structure will be used as the
|
|
set of preferred settings when opening the device. If you
|
|
use this parameter, the preferredDefaultDeviceName
|
|
field will be ignored
|
|
|
|
@returns an error message if anything went wrong, or an empty string if it worked ok.
|
|
*/
|
|
String initialise (int numInputChannelsNeeded,
|
|
int numOutputChannelsNeeded,
|
|
const XmlElement* savedState,
|
|
bool selectDefaultDeviceOnFailure,
|
|
const String& preferredDefaultDeviceName = String::empty,
|
|
const AudioDeviceSetup* preferredSetupOptions = 0);
|
|
|
|
/** Returns some XML representing the current state of the manager.
|
|
|
|
This stores the current device, its samplerate, block size, etc, and
|
|
can be restored later with initialise().
|
|
|
|
Note that this can return a null pointer if no settings have been explicitly changed
|
|
(i.e. if the device manager has just been left in its default state).
|
|
*/
|
|
XmlElement* createStateXml() const;
|
|
|
|
/** Returns the current device properties that are in use.
|
|
|
|
@see setAudioDeviceSetup
|
|
*/
|
|
void getAudioDeviceSetup (AudioDeviceSetup& setup);
|
|
|
|
/** Changes the current device or its settings.
|
|
|
|
If you want to change a device property, like the current sample rate or
|
|
block size, you can call getAudioDeviceSetup() to retrieve the current
|
|
settings, then tweak the appropriate fields in the AudioDeviceSetup structure,
|
|
and pass it back into this method to apply the new settings.
|
|
|
|
@param newSetup the settings that you'd like to use
|
|
@param treatAsChosenDevice if this is true and if the device opens correctly, these new
|
|
settings will be taken as having been explicitly chosen by the
|
|
user, and the next time createStateXml() is called, these settings
|
|
will be returned. If it's false, then the device is treated as a
|
|
temporary or default device, and a call to createStateXml() will
|
|
return either the last settings that were made with treatAsChosenDevice
|
|
as true, or the last XML settings that were passed into initialise().
|
|
@returns an error message if anything went wrong, or an empty string if it worked ok.
|
|
|
|
@see getAudioDeviceSetup
|
|
*/
|
|
String setAudioDeviceSetup (const AudioDeviceSetup& newSetup,
|
|
bool treatAsChosenDevice);
|
|
|
|
/** Returns the currently-active audio device. */
|
|
AudioIODevice* getCurrentAudioDevice() const noexcept { return currentAudioDevice; }
|
|
|
|
/** Returns the type of audio device currently in use.
|
|
@see setCurrentAudioDeviceType
|
|
*/
|
|
String getCurrentAudioDeviceType() const { return currentDeviceType; }
|
|
|
|
/** Returns the currently active audio device type object.
|
|
Don't keep a copy of this pointer - it's owned by the device manager and could
|
|
change at any time.
|
|
*/
|
|
AudioIODeviceType* getCurrentDeviceTypeObject() const;
|
|
|
|
/** Changes the class of audio device being used.
|
|
|
|
This switches between, e.g. ASIO and DirectSound. On the Mac you probably won't ever call
|
|
this because there's only one type: CoreAudio.
|
|
|
|
For a list of types, see getAvailableDeviceTypes().
|
|
*/
|
|
void setCurrentAudioDeviceType (const String& type,
|
|
bool treatAsChosenDevice);
|
|
|
|
/** Closes the currently-open device.
|
|
|
|
You can call restartLastAudioDevice() later to reopen it in the same state
|
|
that it was just in.
|
|
*/
|
|
void closeAudioDevice();
|
|
|
|
/** Tries to reload the last audio device that was running.
|
|
|
|
Note that this only reloads the last device that was running before
|
|
closeAudioDevice() was called - it doesn't reload any kind of saved-state,
|
|
and can only be called after a device has been opened with SetAudioDevice().
|
|
|
|
If a device is already open, this call will do nothing.
|
|
*/
|
|
void restartLastAudioDevice();
|
|
|
|
/** Registers an audio callback to be used.
|
|
|
|
The manager will redirect callbacks from whatever audio device is currently
|
|
in use to all registered callback objects. If more than one callback is
|
|
active, they will all be given the same input data, and their outputs will
|
|
be summed.
|
|
|
|
If necessary, this method will invoke audioDeviceAboutToStart() on the callback
|
|
object before returning.
|
|
|
|
To remove a callback, use removeAudioCallback().
|
|
*/
|
|
void addAudioCallback (AudioIODeviceCallback* newCallback);
|
|
|
|
/** Deregisters a previously added callback.
|
|
|
|
If necessary, this method will invoke audioDeviceStopped() on the callback
|
|
object before returning.
|
|
|
|
@see addAudioCallback
|
|
*/
|
|
void removeAudioCallback (AudioIODeviceCallback* callback);
|
|
|
|
/** Returns the average proportion of available CPU being spent inside the audio callbacks.
|
|
|
|
Returns a value between 0 and 1.0
|
|
*/
|
|
double getCpuUsage() const;
|
|
|
|
/** Enables or disables a midi input device.
|
|
|
|
The list of devices can be obtained with the MidiInput::getDevices() method.
|
|
|
|
Any incoming messages from enabled input devices will be forwarded on to all the
|
|
listeners that have been registered with the addMidiInputCallback() method. They
|
|
can either register for messages from a particular device, or from just the
|
|
"default" midi input.
|
|
|
|
Routing the midi input via an AudioDeviceManager means that when a listener
|
|
registers for the default midi input, this default device can be changed by the
|
|
manager without the listeners having to know about it or re-register.
|
|
|
|
It also means that a listener can stay registered for a midi input that is disabled
|
|
or not present, so that when the input is re-enabled, the listener will start
|
|
receiving messages again.
|
|
|
|
@see addMidiInputCallback, isMidiInputEnabled
|
|
*/
|
|
void setMidiInputEnabled (const String& midiInputDeviceName, bool enabled);
|
|
|
|
/** Returns true if a given midi input device is being used.
|
|
|
|
@see setMidiInputEnabled
|
|
*/
|
|
bool isMidiInputEnabled (const String& midiInputDeviceName) const;
|
|
|
|
/** Registers a listener for callbacks when midi events arrive from a midi input.
|
|
|
|
The device name can be empty to indicate that it wants events from whatever the
|
|
current "default" device is. Or it can be the name of one of the midi input devices
|
|
(see MidiInput::getDevices() for the names).
|
|
|
|
Only devices which are enabled (see the setMidiInputEnabled() method) will have their
|
|
events forwarded on to listeners.
|
|
*/
|
|
void addMidiInputCallback (const String& midiInputDeviceName,
|
|
MidiInputCallback* callback);
|
|
|
|
/** Removes a listener that was previously registered with addMidiInputCallback().
|
|
*/
|
|
void removeMidiInputCallback (const String& midiInputDeviceName,
|
|
MidiInputCallback* callback);
|
|
|
|
/** Sets a midi output device to use as the default.
|
|
|
|
The list of devices can be obtained with the MidiOutput::getDevices() method.
|
|
|
|
The specified device will be opened automatically and can be retrieved with the
|
|
getDefaultMidiOutput() method.
|
|
|
|
Pass in an empty string to deselect all devices. For the default device, you
|
|
can use MidiOutput::getDevices() [MidiOutput::getDefaultDeviceIndex()].
|
|
|
|
@see getDefaultMidiOutput, getDefaultMidiOutputName
|
|
*/
|
|
void setDefaultMidiOutput (const String& deviceName);
|
|
|
|
/** Returns the name of the default midi output.
|
|
|
|
@see setDefaultMidiOutput, getDefaultMidiOutput
|
|
*/
|
|
String getDefaultMidiOutputName() const { return defaultMidiOutputName; }
|
|
|
|
/** Returns the current default midi output device.
|
|
|
|
If no device has been selected, or the device can't be opened, this will
|
|
return 0.
|
|
|
|
@see getDefaultMidiOutputName
|
|
*/
|
|
MidiOutput* getDefaultMidiOutput() const noexcept { return defaultMidiOutput; }
|
|
|
|
/** Returns a list of the types of device supported.
|
|
*/
|
|
const OwnedArray <AudioIODeviceType>& getAvailableDeviceTypes();
|
|
|
|
/** Creates a list of available types.
|
|
|
|
This will add a set of new AudioIODeviceType objects to the specified list, to
|
|
represent each available types of device.
|
|
|
|
You can override this if your app needs to do something specific, like avoid
|
|
using DirectSound devices, etc.
|
|
*/
|
|
virtual void createAudioDeviceTypes (OwnedArray <AudioIODeviceType>& types);
|
|
|
|
/** Plays a beep through the current audio device.
|
|
|
|
This is here to allow the audio setup UI panels to easily include a "test"
|
|
button so that the user can check where the audio is coming from.
|
|
*/
|
|
void playTestSound();
|
|
|
|
/** Turns on level-measuring.
|
|
|
|
When enabled, the device manager will measure the peak input level
|
|
across all channels, and you can get this level by calling getCurrentInputLevel().
|
|
|
|
This is mainly intended for audio setup UI panels to use to create a mic
|
|
level display, so that the user can check that they've selected the right
|
|
device.
|
|
|
|
A simple filter is used to make the level decay smoothly, but this is
|
|
only intended for giving rough feedback, and not for any kind of accurate
|
|
measurement.
|
|
*/
|
|
void enableInputLevelMeasurement (bool enableMeasurement);
|
|
|
|
/** Returns the current input level.
|
|
|
|
To use this, you must first enable it by calling enableInputLevelMeasurement().
|
|
|
|
See enableInputLevelMeasurement() for more info.
|
|
*/
|
|
double getCurrentInputLevel() const;
|
|
|
|
/** Returns the a lock that can be used to synchronise access to the audio callback.
|
|
Obviously while this is locked, you're blocking the audio thread from running, so
|
|
it must only be used for very brief periods when absolutely necessary.
|
|
*/
|
|
CriticalSection& getAudioCallbackLock() noexcept { return audioCallbackLock; }
|
|
|
|
/** Returns the a lock that can be used to synchronise access to the midi callback.
|
|
Obviously while this is locked, you're blocking the midi system from running, so
|
|
it must only be used for very brief periods when absolutely necessary.
|
|
*/
|
|
CriticalSection& getMidiCallbackLock() noexcept { return midiCallbackLock; }
|
|
|
|
private:
|
|
|
|
OwnedArray <AudioIODeviceType> availableDeviceTypes;
|
|
OwnedArray <AudioDeviceSetup> lastDeviceTypeConfigs;
|
|
|
|
AudioDeviceSetup currentSetup;
|
|
ScopedPointer <AudioIODevice> currentAudioDevice;
|
|
Array <AudioIODeviceCallback*> callbacks;
|
|
int numInputChansNeeded, numOutputChansNeeded;
|
|
String currentDeviceType;
|
|
BigInteger inputChannels, outputChannels;
|
|
ScopedPointer <XmlElement> lastExplicitSettings;
|
|
mutable bool listNeedsScanning;
|
|
bool useInputNames;
|
|
int inputLevelMeasurementEnabledCount;
|
|
double inputLevel;
|
|
ScopedPointer <AudioSampleBuffer> testSound;
|
|
int testSoundPosition;
|
|
AudioSampleBuffer tempBuffer;
|
|
|
|
StringArray midiInsFromXml;
|
|
OwnedArray <MidiInput> enabledMidiInputs;
|
|
Array <MidiInputCallback*> midiCallbacks;
|
|
StringArray midiCallbackDevices;
|
|
String defaultMidiOutputName;
|
|
ScopedPointer <MidiOutput> defaultMidiOutput;
|
|
CriticalSection audioCallbackLock, midiCallbackLock;
|
|
|
|
double cpuUsageMs, timeToCpuScale;
|
|
|
|
class CallbackHandler : public AudioIODeviceCallback,
|
|
public MidiInputCallback,
|
|
public AudioIODeviceType::Listener
|
|
{
|
|
public:
|
|
void audioDeviceIOCallback (const float**, int, float**, int, int);
|
|
void audioDeviceAboutToStart (AudioIODevice*);
|
|
void audioDeviceStopped();
|
|
void handleIncomingMidiMessage (MidiInput*, const MidiMessage&);
|
|
void audioDeviceListChanged();
|
|
|
|
AudioDeviceManager* owner;
|
|
};
|
|
|
|
CallbackHandler callbackHandler;
|
|
friend class CallbackHandler;
|
|
|
|
void audioDeviceIOCallbackInt (const float** inputChannelData, int totalNumInputChannels,
|
|
float** outputChannelData, int totalNumOutputChannels, int numSamples);
|
|
void audioDeviceAboutToStartInt (AudioIODevice*);
|
|
void audioDeviceStoppedInt();
|
|
void handleIncomingMidiMessageInt (MidiInput*, const MidiMessage&);
|
|
void audioDeviceListChanged();
|
|
|
|
String restartDevice (int blockSizeToUse, double sampleRateToUse,
|
|
const BigInteger& ins, const BigInteger& outs);
|
|
void stopDevice();
|
|
|
|
void updateXml();
|
|
|
|
void createDeviceTypesIfNeeded();
|
|
void scanDevicesIfNeeded();
|
|
void deleteCurrentDevice();
|
|
double chooseBestSampleRate (double preferred) const;
|
|
int chooseBestBufferSize (int preferred) const;
|
|
void insertDefaultDeviceNames (AudioDeviceSetup&) const;
|
|
|
|
AudioIODeviceType* findType (const String& inputName, const String& outputName);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioDeviceManager);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIODEVICEMANAGER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioDeviceManager.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOIODEVICE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOIODEVICETYPE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIODATACONVERTERS_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOSAMPLEBUFFER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_DECIBELS_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_Decibels.h ***/
|
|
#ifndef __JUCE_DECIBELS_JUCEHEADER__
|
|
#define __JUCE_DECIBELS_JUCEHEADER__
|
|
|
|
/**
|
|
This class contains some helpful static methods for dealing with decibel values.
|
|
*/
|
|
class Decibels
|
|
{
|
|
public:
|
|
|
|
/** Converts a dBFS value to its equivalent gain level.
|
|
|
|
A gain of 1.0 = 0 dB, and lower gains map onto negative decibel values. Any
|
|
decibel value lower than minusInfinityDb will return a gain of 0.
|
|
*/
|
|
template <typename Type>
|
|
static Type decibelsToGain (const Type decibels,
|
|
const Type minusInfinityDb = (Type) defaultMinusInfinitydB)
|
|
{
|
|
return decibels > minusInfinityDb ? powf ((Type) 10.0, decibels * (Type) 0.05)
|
|
: Type();
|
|
}
|
|
|
|
/** Converts a gain level into a dBFS value.
|
|
|
|
A gain of 1.0 = 0 dB, and lower gains map onto negative decibel values.
|
|
If the gain is 0 (or negative), then the method will return the value
|
|
provided as minusInfinityDb.
|
|
*/
|
|
template <typename Type>
|
|
static Type gainToDecibels (const Type gain,
|
|
const Type minusInfinityDb = (Type) defaultMinusInfinitydB)
|
|
{
|
|
return gain > Type() ? jmax (minusInfinityDb, (Type) std::log10 (gain) * (Type) 20.0)
|
|
: minusInfinityDb;
|
|
}
|
|
|
|
/** Converts a decibel reading to a string, with the 'dB' suffix.
|
|
If the decibel value is lower than minusInfinityDb, the return value will
|
|
be "-INF dB".
|
|
*/
|
|
template <typename Type>
|
|
static String toString (const Type decibels,
|
|
const int decimalPlaces = 2,
|
|
const Type minusInfinityDb = (Type) defaultMinusInfinitydB)
|
|
{
|
|
String s;
|
|
|
|
if (decibels <= minusInfinityDb)
|
|
{
|
|
s = "-INF dB";
|
|
}
|
|
else
|
|
{
|
|
if (decibels >= Type())
|
|
s << '+';
|
|
|
|
s << String (decibels, decimalPlaces) << " dB";
|
|
}
|
|
|
|
return s;
|
|
}
|
|
|
|
private:
|
|
|
|
enum
|
|
{
|
|
defaultMinusInfinitydB = -100
|
|
};
|
|
|
|
Decibels(); // This class can't be instantiated, it's just a holder for static methods..
|
|
JUCE_DECLARE_NON_COPYABLE (Decibels);
|
|
};
|
|
|
|
#endif // __JUCE_DECIBELS_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Decibels.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_IIRFILTER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_REVERB_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIBUFFER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIFILE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MidiFile.h ***/
|
|
#ifndef __JUCE_MIDIFILE_JUCEHEADER__
|
|
#define __JUCE_MIDIFILE_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_MidiMessageSequence.h ***/
|
|
#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__
|
|
#define __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__
|
|
|
|
/**
|
|
A sequence of timestamped midi messages.
|
|
|
|
This allows the sequence to be manipulated, and also to be read from and
|
|
written to a standard midi file.
|
|
|
|
@see MidiMessage, MidiFile
|
|
*/
|
|
class JUCE_API MidiMessageSequence
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty midi sequence object. */
|
|
MidiMessageSequence();
|
|
|
|
/** Creates a copy of another sequence. */
|
|
MidiMessageSequence (const MidiMessageSequence& other);
|
|
|
|
/** Replaces this sequence with another one. */
|
|
MidiMessageSequence& operator= (const MidiMessageSequence& other);
|
|
|
|
/** Destructor. */
|
|
~MidiMessageSequence();
|
|
|
|
/** Structure used to hold midi events in the sequence.
|
|
|
|
These structures act as 'handles' on the events as they are moved about in
|
|
the list, and make it quick to find the matching note-offs for note-on events.
|
|
|
|
@see MidiMessageSequence::getEventPointer
|
|
*/
|
|
class MidiEventHolder
|
|
{
|
|
public:
|
|
|
|
/** Destructor. */
|
|
~MidiEventHolder();
|
|
|
|
/** The message itself, whose timestamp is used to specify the event's time.
|
|
*/
|
|
MidiMessage message;
|
|
|
|
/** The matching note-off event (if this is a note-on event).
|
|
|
|
If this isn't a note-on, this pointer will be null.
|
|
|
|
Use the MidiMessageSequence::updateMatchedPairs() method to keep these
|
|
note-offs up-to-date after events have been moved around in the sequence
|
|
or deleted.
|
|
*/
|
|
MidiEventHolder* noteOffObject;
|
|
|
|
private:
|
|
|
|
friend class MidiMessageSequence;
|
|
MidiEventHolder (const MidiMessage& message);
|
|
JUCE_LEAK_DETECTOR (MidiEventHolder);
|
|
};
|
|
|
|
/** Clears the sequence. */
|
|
void clear();
|
|
|
|
/** Returns the number of events in the sequence. */
|
|
int getNumEvents() const;
|
|
|
|
/** Returns a pointer to one of the events. */
|
|
MidiEventHolder* getEventPointer (int index) const;
|
|
|
|
/** Returns the time of the note-up that matches the note-on at this index.
|
|
|
|
If the event at this index isn't a note-on, it'll just return 0.
|
|
|
|
@see MidiMessageSequence::MidiEventHolder::noteOffObject
|
|
*/
|
|
double getTimeOfMatchingKeyUp (int index) const;
|
|
|
|
/** Returns the index of the note-up that matches the note-on at this index.
|
|
|
|
If the event at this index isn't a note-on, it'll just return -1.
|
|
|
|
@see MidiMessageSequence::MidiEventHolder::noteOffObject
|
|
*/
|
|
int getIndexOfMatchingKeyUp (int index) const;
|
|
|
|
/** Returns the index of an event. */
|
|
int getIndexOf (MidiEventHolder* event) const;
|
|
|
|
/** Returns the index of the first event on or after the given timestamp.
|
|
|
|
If the time is beyond the end of the sequence, this will return the
|
|
number of events.
|
|
*/
|
|
int getNextIndexAtTime (double timeStamp) const;
|
|
|
|
/** Returns the timestamp of the first event in the sequence.
|
|
|
|
@see getEndTime
|
|
*/
|
|
double getStartTime() const;
|
|
|
|
/** Returns the timestamp of the last event in the sequence.
|
|
|
|
@see getStartTime
|
|
*/
|
|
double getEndTime() const;
|
|
|
|
/** Returns the timestamp of the event at a given index.
|
|
|
|
If the index is out-of-range, this will return 0.0
|
|
*/
|
|
double getEventTime (int index) const;
|
|
|
|
/** Inserts a midi message into the sequence.
|
|
|
|
The index at which the new message gets inserted will depend on its timestamp,
|
|
because the sequence is kept sorted.
|
|
|
|
Remember to call updateMatchedPairs() after adding note-on events.
|
|
|
|
@param newMessage the new message to add (an internal copy will be made)
|
|
@param timeAdjustment an optional value to add to the timestamp of the message
|
|
that will be inserted
|
|
@see updateMatchedPairs
|
|
*/
|
|
void addEvent (const MidiMessage& newMessage,
|
|
double timeAdjustment = 0);
|
|
|
|
/** Deletes one of the events in the sequence.
|
|
|
|
Remember to call updateMatchedPairs() after removing events.
|
|
|
|
@param index the index of the event to delete
|
|
@param deleteMatchingNoteUp whether to also remove the matching note-off
|
|
if the event you're removing is a note-on
|
|
*/
|
|
void deleteEvent (int index, bool deleteMatchingNoteUp);
|
|
|
|
/** Merges another sequence into this one.
|
|
|
|
Remember to call updateMatchedPairs() after using this method.
|
|
|
|
@param other the sequence to add from
|
|
@param timeAdjustmentDelta an amount to add to the timestamps of the midi events
|
|
as they are read from the other sequence
|
|
@param firstAllowableDestTime events will not be added if their time is earlier
|
|
than this time. (This is after their time has been adjusted
|
|
by the timeAdjustmentDelta)
|
|
@param endOfAllowableDestTimes events will not be added if their time is equal to
|
|
or greater than this time. (This is after their time has
|
|
been adjusted by the timeAdjustmentDelta)
|
|
*/
|
|
void addSequence (const MidiMessageSequence& other,
|
|
double timeAdjustmentDelta,
|
|
double firstAllowableDestTime,
|
|
double endOfAllowableDestTimes);
|
|
|
|
/** Makes sure all the note-on and note-off pairs are up-to-date.
|
|
|
|
Call this after moving messages about or deleting/adding messages, and it
|
|
will scan the list and make sure all the note-offs in the MidiEventHolder
|
|
structures are pointing at the correct ones.
|
|
*/
|
|
void updateMatchedPairs();
|
|
|
|
/** Copies all the messages for a particular midi channel to another sequence.
|
|
|
|
@param channelNumberToExtract the midi channel to look for, in the range 1 to 16
|
|
@param destSequence the sequence that the chosen events should be copied to
|
|
@param alsoIncludeMetaEvents if true, any meta-events (which don't apply to a specific
|
|
channel) will also be copied across.
|
|
@see extractSysExMessages
|
|
*/
|
|
void extractMidiChannelMessages (int channelNumberToExtract,
|
|
MidiMessageSequence& destSequence,
|
|
bool alsoIncludeMetaEvents) const;
|
|
|
|
/** Copies all midi sys-ex messages to another sequence.
|
|
|
|
@param destSequence this is the sequence to which any sys-exes in this sequence
|
|
will be added
|
|
@see extractMidiChannelMessages
|
|
*/
|
|
void extractSysExMessages (MidiMessageSequence& destSequence) const;
|
|
|
|
/** Removes any messages in this sequence that have a specific midi channel.
|
|
|
|
@param channelNumberToRemove the midi channel to look for, in the range 1 to 16
|
|
*/
|
|
void deleteMidiChannelMessages (int channelNumberToRemove);
|
|
|
|
/** Removes any sys-ex messages from this sequence.
|
|
*/
|
|
void deleteSysExMessages();
|
|
|
|
/** Adds an offset to the timestamps of all events in the sequence.
|
|
|
|
@param deltaTime the amount to add to each timestamp.
|
|
*/
|
|
void addTimeToMessages (double deltaTime);
|
|
|
|
/** Scans through the sequence to determine the state of any midi controllers at
|
|
a given time.
|
|
|
|
This will create a sequence of midi controller changes that can be
|
|
used to set all midi controllers to the state they would be in at the
|
|
specified time within this sequence.
|
|
|
|
As well as controllers, it will also recreate the midi program number
|
|
and pitch bend position.
|
|
|
|
@param channelNumber the midi channel to look for, in the range 1 to 16. Controllers
|
|
for other channels will be ignored.
|
|
@param time the time at which you want to find out the state - there are
|
|
no explicit units for this time measurement, it's the same units
|
|
as used for the timestamps of the messages
|
|
@param resultMessages an array to which midi controller-change messages will be added. This
|
|
will be the minimum number of controller changes to recreate the
|
|
state at the required time.
|
|
*/
|
|
void createControllerUpdatesForTime (int channelNumber, double time,
|
|
OwnedArray<MidiMessage>& resultMessages);
|
|
|
|
/** Swaps this sequence with another one. */
|
|
void swapWith (MidiMessageSequence& other) noexcept;
|
|
|
|
/** @internal */
|
|
static int compareElements (const MidiMessageSequence::MidiEventHolder* first,
|
|
const MidiMessageSequence::MidiEventHolder* second) noexcept;
|
|
|
|
private:
|
|
|
|
friend class MidiFile;
|
|
OwnedArray <MidiEventHolder> list;
|
|
|
|
void sort();
|
|
|
|
JUCE_LEAK_DETECTOR (MidiMessageSequence);
|
|
};
|
|
|
|
#endif // __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MidiMessageSequence.h ***/
|
|
|
|
/**
|
|
Reads/writes standard midi format files.
|
|
|
|
To read a midi file, create a MidiFile object and call its readFrom() method. You
|
|
can then get the individual midi tracks from it using the getTrack() method.
|
|
|
|
To write a file, create a MidiFile object, add some MidiMessageSequence objects
|
|
to it using the addTrack() method, and then call its writeTo() method to stream
|
|
it out.
|
|
|
|
@see MidiMessageSequence
|
|
*/
|
|
class JUCE_API MidiFile
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty MidiFile object.
|
|
*/
|
|
MidiFile();
|
|
|
|
/** Destructor. */
|
|
~MidiFile();
|
|
|
|
/** Returns the number of tracks in the file.
|
|
|
|
@see getTrack, addTrack
|
|
*/
|
|
int getNumTracks() const noexcept;
|
|
|
|
/** Returns a pointer to one of the tracks in the file.
|
|
|
|
@returns a pointer to the track, or 0 if the index is out-of-range
|
|
@see getNumTracks, addTrack
|
|
*/
|
|
const MidiMessageSequence* getTrack (int index) const noexcept;
|
|
|
|
/** Adds a midi track to the file.
|
|
|
|
This will make its own internal copy of the sequence that is passed-in.
|
|
|
|
@see getNumTracks, getTrack
|
|
*/
|
|
void addTrack (const MidiMessageSequence& trackSequence);
|
|
|
|
/** Removes all midi tracks from the file.
|
|
|
|
@see getNumTracks
|
|
*/
|
|
void clear();
|
|
|
|
/** Returns the raw time format code that will be written to a stream.
|
|
|
|
After reading a midi file, this method will return the time-format that
|
|
was read from the file's header. It can be changed using the setTicksPerQuarterNote()
|
|
or setSmpteTimeFormat() methods.
|
|
|
|
If the value returned is positive, it indicates the number of midi ticks
|
|
per quarter-note - see setTicksPerQuarterNote().
|
|
|
|
It it's negative, the upper byte indicates the frames-per-second (but negative), and
|
|
the lower byte is the number of ticks per frame - see setSmpteTimeFormat().
|
|
*/
|
|
short getTimeFormat() const noexcept;
|
|
|
|
/** Sets the time format to use when this file is written to a stream.
|
|
|
|
If this is called, the file will be written as bars/beats using the
|
|
specified resolution, rather than SMPTE absolute times, as would be
|
|
used if setSmpteTimeFormat() had been called instead.
|
|
|
|
@param ticksPerQuarterNote e.g. 96, 960
|
|
@see setSmpteTimeFormat
|
|
*/
|
|
void setTicksPerQuarterNote (int ticksPerQuarterNote) noexcept;
|
|
|
|
/** Sets the time format to use when this file is written to a stream.
|
|
|
|
If this is called, the file will be written using absolute times, rather
|
|
than bars/beats as would be the case if setTicksPerBeat() had been called
|
|
instead.
|
|
|
|
@param framesPerSecond must be 24, 25, 29 or 30
|
|
@param subframeResolution the sub-second resolution, e.g. 4 (midi time code),
|
|
8, 10, 80 (SMPTE bit resolution), or 100. For millisecond
|
|
timing, setSmpteTimeFormat (25, 40)
|
|
@see setTicksPerBeat
|
|
*/
|
|
void setSmpteTimeFormat (int framesPerSecond,
|
|
int subframeResolution) noexcept;
|
|
|
|
/** Makes a list of all the tempo-change meta-events from all tracks in the midi file.
|
|
|
|
Useful for finding the positions of all the tempo changes in a file.
|
|
|
|
@param tempoChangeEvents a list to which all the events will be added
|
|
*/
|
|
void findAllTempoEvents (MidiMessageSequence& tempoChangeEvents) const;
|
|
|
|
/** Makes a list of all the time-signature meta-events from all tracks in the midi file.
|
|
|
|
Useful for finding the positions of all the tempo changes in a file.
|
|
|
|
@param timeSigEvents a list to which all the events will be added
|
|
*/
|
|
void findAllTimeSigEvents (MidiMessageSequence& timeSigEvents) const;
|
|
|
|
/** Returns the latest timestamp in any of the tracks.
|
|
|
|
(Useful for finding the length of the file).
|
|
*/
|
|
double getLastTimestamp() const;
|
|
|
|
/** Reads a midi file format stream.
|
|
|
|
After calling this, you can get the tracks that were read from the file by using the
|
|
getNumTracks() and getTrack() methods.
|
|
|
|
The timestamps of the midi events in the tracks will represent their positions in
|
|
terms of midi ticks. To convert them to seconds, use the convertTimestampTicksToSeconds()
|
|
method.
|
|
|
|
@returns true if the stream was read successfully
|
|
*/
|
|
bool readFrom (InputStream& sourceStream);
|
|
|
|
/** Writes the midi tracks as a standard midi file.
|
|
|
|
@returns true if the operation succeeded.
|
|
*/
|
|
bool writeTo (OutputStream& destStream);
|
|
|
|
/** Converts the timestamp of all the midi events from midi ticks to seconds.
|
|
|
|
This will use the midi time format and tempo/time signature info in the
|
|
tracks to convert all the timestamps to absolute values in seconds.
|
|
*/
|
|
void convertTimestampTicksToSeconds();
|
|
|
|
private:
|
|
|
|
OwnedArray <MidiMessageSequence> tracks;
|
|
short timeFormat;
|
|
|
|
void readNextTrack (const uint8* data, int size);
|
|
void writeTrack (OutputStream& mainOut, int trackNum);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiFile);
|
|
};
|
|
|
|
#endif // __JUCE_MIDIFILE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MidiFile.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIINPUT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MidiKeyboardState.h ***/
|
|
#ifndef __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__
|
|
#define __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__
|
|
|
|
class MidiKeyboardState;
|
|
|
|
/**
|
|
Receives events from a MidiKeyboardState object.
|
|
|
|
@see MidiKeyboardState
|
|
*/
|
|
class JUCE_API MidiKeyboardStateListener
|
|
{
|
|
public:
|
|
|
|
MidiKeyboardStateListener() noexcept {}
|
|
virtual ~MidiKeyboardStateListener() {}
|
|
|
|
/** Called when one of the MidiKeyboardState's keys is pressed.
|
|
|
|
This will be called synchronously when the state is either processing a
|
|
buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
|
|
when a note is being played with its MidiKeyboardState::noteOn() method.
|
|
|
|
Note that this callback could happen from an audio callback thread, so be
|
|
careful not to block, and avoid any UI activity in the callback.
|
|
*/
|
|
virtual void handleNoteOn (MidiKeyboardState* source,
|
|
int midiChannel, int midiNoteNumber, float velocity) = 0;
|
|
|
|
/** Called when one of the MidiKeyboardState's keys is released.
|
|
|
|
This will be called synchronously when the state is either processing a
|
|
buffer in its MidiKeyboardState::processNextMidiBuffer() method, or
|
|
when a note is being played with its MidiKeyboardState::noteOff() method.
|
|
|
|
Note that this callback could happen from an audio callback thread, so be
|
|
careful not to block, and avoid any UI activity in the callback.
|
|
*/
|
|
virtual void handleNoteOff (MidiKeyboardState* source,
|
|
int midiChannel, int midiNoteNumber) = 0;
|
|
};
|
|
|
|
/**
|
|
Represents a piano keyboard, keeping track of which keys are currently pressed.
|
|
|
|
This object can parse a stream of midi events, using them to update its idea
|
|
of which keys are pressed for each individiual midi channel.
|
|
|
|
When keys go up or down, it can broadcast these events to listener objects.
|
|
|
|
It also allows key up/down events to be triggered with its noteOn() and noteOff()
|
|
methods, and midi messages for these events will be merged into the
|
|
midi stream that gets processed by processNextMidiBuffer().
|
|
*/
|
|
class JUCE_API MidiKeyboardState
|
|
{
|
|
public:
|
|
|
|
MidiKeyboardState();
|
|
~MidiKeyboardState();
|
|
|
|
/** Resets the state of the object.
|
|
|
|
All internal data for all the channels is reset, but no events are sent as a
|
|
result.
|
|
|
|
If you want to release any keys that are currently down, and to send out note-up
|
|
midi messages for this, use the allNotesOff() method instead.
|
|
*/
|
|
void reset();
|
|
|
|
/** Returns true if the given midi key is currently held down for the given midi channel.
|
|
|
|
The channel number must be between 1 and 16. If you want to see if any notes are
|
|
on for a range of channels, use the isNoteOnForChannels() method.
|
|
*/
|
|
bool isNoteOn (int midiChannel, int midiNoteNumber) const noexcept;
|
|
|
|
/** Returns true if the given midi key is currently held down on any of a set of midi channels.
|
|
|
|
The channel mask has a bit set for each midi channel you want to test for - bit
|
|
0 = midi channel 1, bit 1 = midi channel 2, etc.
|
|
|
|
If a note is on for at least one of the specified channels, this returns true.
|
|
*/
|
|
bool isNoteOnForChannels (int midiChannelMask, int midiNoteNumber) const noexcept;
|
|
|
|
/** Turns a specified note on.
|
|
|
|
This will cause a suitable midi note-on event to be injected into the midi buffer during the
|
|
next call to processNextMidiBuffer().
|
|
|
|
It will also trigger a synchronous callback to the listeners to tell them that the key has
|
|
gone down.
|
|
*/
|
|
void noteOn (int midiChannel, int midiNoteNumber, float velocity);
|
|
|
|
/** Turns a specified note off.
|
|
|
|
This will cause a suitable midi note-off event to be injected into the midi buffer during the
|
|
next call to processNextMidiBuffer().
|
|
|
|
It will also trigger a synchronous callback to the listeners to tell them that the key has
|
|
gone up.
|
|
|
|
But if the note isn't acutally down for the given channel, this method will in fact do nothing.
|
|
*/
|
|
void noteOff (int midiChannel, int midiNoteNumber);
|
|
|
|
/** This will turn off any currently-down notes for the given midi channel.
|
|
|
|
If you pass 0 for the midi channel, it will in fact turn off all notes on all channels.
|
|
|
|
Calling this method will make calls to noteOff(), so can trigger synchronous callbacks
|
|
and events being added to the midi stream.
|
|
*/
|
|
void allNotesOff (int midiChannel);
|
|
|
|
/** Looks at a key-up/down event and uses it to update the state of this object.
|
|
|
|
To process a buffer full of midi messages, use the processNextMidiBuffer() method
|
|
instead.
|
|
*/
|
|
void processNextMidiEvent (const MidiMessage& message);
|
|
|
|
/** Scans a midi stream for up/down events and adds its own events to it.
|
|
|
|
This will look for any up/down events and use them to update the internal state,
|
|
synchronously making suitable callbacks to the listeners.
|
|
|
|
If injectIndirectEvents is true, then midi events to produce the recent noteOn()
|
|
and noteOff() calls will be added into the buffer.
|
|
|
|
Only the section of the buffer whose timestamps are between startSample and
|
|
(startSample + numSamples) will be affected, and any events added will be placed
|
|
between these times.
|
|
|
|
If you're going to use this method, you'll need to keep calling it regularly for
|
|
it to work satisfactorily.
|
|
|
|
To process a single midi event at a time, use the processNextMidiEvent() method
|
|
instead.
|
|
*/
|
|
void processNextMidiBuffer (MidiBuffer& buffer,
|
|
int startSample,
|
|
int numSamples,
|
|
bool injectIndirectEvents);
|
|
|
|
/** Registers a listener for callbacks when keys go up or down.
|
|
|
|
@see removeListener
|
|
*/
|
|
void addListener (MidiKeyboardStateListener* listener);
|
|
|
|
/** Deregisters a listener.
|
|
|
|
@see addListener
|
|
*/
|
|
void removeListener (MidiKeyboardStateListener* listener);
|
|
|
|
private:
|
|
|
|
CriticalSection lock;
|
|
uint16 noteStates [128];
|
|
MidiBuffer eventsToAdd;
|
|
Array <MidiKeyboardStateListener*> listeners;
|
|
|
|
void noteOnInternal (int midiChannel, int midiNoteNumber, float velocity);
|
|
void noteOffInternal (int midiChannel, int midiNoteNumber);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiKeyboardState);
|
|
};
|
|
|
|
#endif // __JUCE_MIDIKEYBOARDSTATE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MidiKeyboardState.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIMESSAGE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MidiMessageCollector.h ***/
|
|
#ifndef __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__
|
|
#define __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__
|
|
|
|
/**
|
|
Collects incoming realtime MIDI messages and turns them into blocks suitable for
|
|
processing by a block-based audio callback.
|
|
|
|
The class can also be used as either a MidiKeyboardStateListener or a MidiInputCallback
|
|
so it can easily use a midi input or keyboard component as its source.
|
|
|
|
@see MidiMessage, MidiInput
|
|
*/
|
|
class JUCE_API MidiMessageCollector : public MidiKeyboardStateListener,
|
|
public MidiInputCallback
|
|
{
|
|
public:
|
|
|
|
/** Creates a MidiMessageCollector. */
|
|
MidiMessageCollector();
|
|
|
|
/** Destructor. */
|
|
~MidiMessageCollector();
|
|
|
|
/** Clears any messages from the queue.
|
|
|
|
You need to call this method before starting to use the collector, so that
|
|
it knows the correct sample rate to use.
|
|
*/
|
|
void reset (double sampleRate);
|
|
|
|
/** Takes an incoming real-time message and adds it to the queue.
|
|
|
|
The message's timestamp is taken, and it will be ready for retrieval as part
|
|
of the block returned by the next call to removeNextBlockOfMessages().
|
|
|
|
This method is fully thread-safe when overlapping calls are made with
|
|
removeNextBlockOfMessages().
|
|
*/
|
|
void addMessageToQueue (const MidiMessage& message);
|
|
|
|
/** Removes all the pending messages from the queue as a buffer.
|
|
|
|
This will also correct the messages' timestamps to make sure they're in
|
|
the range 0 to numSamples - 1.
|
|
|
|
This call should be made regularly by something like an audio processing
|
|
callback, because the time that it happens is used in calculating the
|
|
midi event positions.
|
|
|
|
This method is fully thread-safe when overlapping calls are made with
|
|
addMessageToQueue().
|
|
*/
|
|
void removeNextBlockOfMessages (MidiBuffer& destBuffer, int numSamples);
|
|
|
|
/** @internal */
|
|
void handleNoteOn (MidiKeyboardState* source, int midiChannel, int midiNoteNumber, float velocity);
|
|
/** @internal */
|
|
void handleNoteOff (MidiKeyboardState* source, int midiChannel, int midiNoteNumber);
|
|
/** @internal */
|
|
void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message);
|
|
|
|
private:
|
|
|
|
double lastCallbackTime;
|
|
CriticalSection midiCallbackLock;
|
|
MidiBuffer incomingMessages;
|
|
double sampleRate;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiMessageCollector);
|
|
};
|
|
|
|
#endif // __JUCE_MIDIMESSAGECOLLECTOR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MidiMessageCollector.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIMESSAGESEQUENCE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIOUTPUT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_AudioUnitPluginFormat.h ***/
|
|
#ifndef __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__
|
|
#define __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_AudioPluginFormat.h ***/
|
|
#ifndef __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__
|
|
#define __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_AudioPluginInstance.h ***/
|
|
#ifndef __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__
|
|
#define __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_AudioProcessor.h ***/
|
|
#ifndef __JUCE_AUDIOPROCESSOR_JUCEHEADER__
|
|
#define __JUCE_AUDIOPROCESSOR_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_AudioProcessorEditor.h ***/
|
|
#ifndef __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__
|
|
#define __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__
|
|
|
|
class AudioProcessor;
|
|
|
|
/**
|
|
Base class for the component that acts as the GUI for an AudioProcessor.
|
|
|
|
Derive your editor component from this class, and create an instance of it
|
|
by overriding the AudioProcessor::createEditor() method.
|
|
|
|
@see AudioProcessor, GenericAudioProcessorEditor
|
|
*/
|
|
class JUCE_API AudioProcessorEditor : public Component
|
|
{
|
|
protected:
|
|
|
|
/** Creates an editor for the specified processor.
|
|
*/
|
|
AudioProcessorEditor (AudioProcessor* owner);
|
|
|
|
public:
|
|
/** Destructor. */
|
|
~AudioProcessorEditor();
|
|
|
|
/** Returns a pointer to the processor that this editor represents. */
|
|
AudioProcessor* getAudioProcessor() const noexcept { return owner; }
|
|
|
|
private:
|
|
|
|
AudioProcessor* const owner;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (AudioProcessorEditor);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioProcessorEditor.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_AudioProcessorListener.h ***/
|
|
#ifndef __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__
|
|
#define __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__
|
|
|
|
class AudioProcessor;
|
|
|
|
/**
|
|
Base class for listeners that want to know about changes to an AudioProcessor.
|
|
|
|
Use AudioProcessor::addListener() to register your listener with an AudioProcessor.
|
|
|
|
@see AudioProcessor
|
|
*/
|
|
class JUCE_API AudioProcessorListener
|
|
{
|
|
public:
|
|
|
|
/** Destructor. */
|
|
virtual ~AudioProcessorListener() {}
|
|
|
|
/** Receives a callback when a parameter is changed.
|
|
|
|
IMPORTANT NOTE: this will be called synchronously when a parameter changes, and
|
|
many audio processors will change their parameter during their audio callback.
|
|
This means that not only has your handler code got to be completely thread-safe,
|
|
but it's also got to be VERY fast, and avoid blocking. If you need to handle
|
|
this event on your message thread, use this callback to trigger an AsyncUpdater
|
|
or ChangeBroadcaster which you can respond to on the message thread.
|
|
*/
|
|
virtual void audioProcessorParameterChanged (AudioProcessor* processor,
|
|
int parameterIndex,
|
|
float newValue) = 0;
|
|
|
|
/** Called to indicate that something else in the plugin has changed, like its
|
|
program, number of parameters, etc.
|
|
|
|
IMPORTANT NOTE: this will be called synchronously, and many audio processors will
|
|
call it during their audio callback. This means that not only has your handler code
|
|
got to be completely thread-safe, but it's also got to be VERY fast, and avoid
|
|
blocking. If you need to handle this event on your message thread, use this callback
|
|
to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the
|
|
message thread.
|
|
*/
|
|
virtual void audioProcessorChanged (AudioProcessor* processor) = 0;
|
|
|
|
/** Indicates that a parameter change gesture has started.
|
|
|
|
E.g. if the user is dragging a slider, this would be called when they first
|
|
press the mouse button, and audioProcessorParameterChangeGestureEnd would be
|
|
called when they release it.
|
|
|
|
IMPORTANT NOTE: this will be called synchronously, and many audio processors will
|
|
call it during their audio callback. This means that not only has your handler code
|
|
got to be completely thread-safe, but it's also got to be VERY fast, and avoid
|
|
blocking. If you need to handle this event on your message thread, use this callback
|
|
to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the
|
|
message thread.
|
|
|
|
@see audioProcessorParameterChangeGestureEnd
|
|
*/
|
|
virtual void audioProcessorParameterChangeGestureBegin (AudioProcessor* processor,
|
|
int parameterIndex);
|
|
|
|
/** Indicates that a parameter change gesture has finished.
|
|
|
|
E.g. if the user is dragging a slider, this would be called when they release
|
|
the mouse button.
|
|
|
|
IMPORTANT NOTE: this will be called synchronously, and many audio processors will
|
|
call it during their audio callback. This means that not only has your handler code
|
|
got to be completely thread-safe, but it's also got to be VERY fast, and avoid
|
|
blocking. If you need to handle this event on your message thread, use this callback
|
|
to trigger an AsyncUpdater or ChangeBroadcaster which you can respond to later on the
|
|
message thread.
|
|
|
|
@see audioProcessorParameterChangeGestureBegin
|
|
*/
|
|
virtual void audioProcessorParameterChangeGestureEnd (AudioProcessor* processor,
|
|
int parameterIndex);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioProcessorListener.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_AudioPlayHead.h ***/
|
|
#ifndef __JUCE_AUDIOPLAYHEAD_JUCEHEADER__
|
|
#define __JUCE_AUDIOPLAYHEAD_JUCEHEADER__
|
|
|
|
/**
|
|
A subclass of AudioPlayHead can supply information about the position and
|
|
status of a moving play head during audio playback.
|
|
|
|
One of these can be supplied to an AudioProcessor object so that it can find
|
|
out about the position of the audio that it is rendering.
|
|
|
|
@see AudioProcessor::setPlayHead, AudioProcessor::getPlayHead
|
|
*/
|
|
class JUCE_API AudioPlayHead
|
|
{
|
|
protected:
|
|
|
|
AudioPlayHead() {}
|
|
|
|
public:
|
|
virtual ~AudioPlayHead() {}
|
|
|
|
/** Frame rate types. */
|
|
enum FrameRateType
|
|
{
|
|
fps24 = 0,
|
|
fps25 = 1,
|
|
fps2997 = 2,
|
|
fps30 = 3,
|
|
fps2997drop = 4,
|
|
fps30drop = 5,
|
|
fpsUnknown = 99
|
|
};
|
|
|
|
/** This structure is filled-in by the AudioPlayHead::getCurrentPosition() method.
|
|
*/
|
|
struct CurrentPositionInfo
|
|
{
|
|
/** The tempo in BPM */
|
|
double bpm;
|
|
|
|
/** Time signature numerator, e.g. the 3 of a 3/4 time sig */
|
|
int timeSigNumerator;
|
|
/** Time signature denominator, e.g. the 4 of a 3/4 time sig */
|
|
int timeSigDenominator;
|
|
|
|
/** The current play position, in seconds from the start of the edit. */
|
|
double timeInSeconds;
|
|
|
|
/** For timecode, the position of the start of the edit, in seconds from 00:00:00:00. */
|
|
double editOriginTime;
|
|
|
|
/** The current play position in pulses-per-quarter-note.
|
|
|
|
This is the number of quarter notes since the edit start.
|
|
*/
|
|
double ppqPosition;
|
|
|
|
/** The position of the start of the last bar, in pulses-per-quarter-note.
|
|
|
|
This is the number of quarter notes from the start of the edit to the
|
|
start of the current bar.
|
|
|
|
Note - this value may be unavailable on some hosts, e.g. Pro-Tools. If
|
|
it's not available, the value will be 0.
|
|
*/
|
|
double ppqPositionOfLastBarStart;
|
|
|
|
/** The video frame rate, if applicable. */
|
|
FrameRateType frameRate;
|
|
|
|
/** True if the transport is currently playing. */
|
|
bool isPlaying;
|
|
|
|
/** True if the transport is currently recording.
|
|
|
|
(When isRecording is true, then isPlaying will also be true).
|
|
*/
|
|
bool isRecording;
|
|
|
|
bool operator== (const CurrentPositionInfo& other) const noexcept;
|
|
bool operator!= (const CurrentPositionInfo& other) const noexcept;
|
|
|
|
void resetToDefault();
|
|
};
|
|
|
|
/** Fills-in the given structure with details about the transport's
|
|
position at the start of the current processing block.
|
|
*/
|
|
virtual bool getCurrentPosition (CurrentPositionInfo& result) = 0;
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPLAYHEAD_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioPlayHead.h ***/
|
|
|
|
/**
|
|
Base class for audio processing filters or plugins.
|
|
|
|
This is intended to act as a base class of audio filter that is general enough to
|
|
be wrapped as a VST, AU, RTAS, etc, or used internally.
|
|
|
|
It is also used by the plugin hosting code as the wrapper around an instance
|
|
of a loaded plugin.
|
|
|
|
Derive your filter class from this base class, and if you're building a plugin,
|
|
you should implement a global function called createPluginFilter() which creates
|
|
and returns a new instance of your subclass.
|
|
*/
|
|
class JUCE_API AudioProcessor
|
|
{
|
|
protected:
|
|
|
|
/** Constructor.
|
|
|
|
You can also do your initialisation tasks in the initialiseFilterInfo()
|
|
call, which will be made after this object has been created.
|
|
*/
|
|
AudioProcessor();
|
|
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~AudioProcessor();
|
|
|
|
/** Returns the name of this processor.
|
|
*/
|
|
virtual const String getName() const = 0;
|
|
|
|
/** Called before playback starts, to let the filter prepare itself.
|
|
|
|
The sample rate is the target sample rate, and will remain constant until
|
|
playback stops.
|
|
|
|
The estimatedSamplesPerBlock value is a HINT about the typical number of
|
|
samples that will be processed for each callback, but isn't any kind
|
|
of guarantee. The actual block sizes that the host uses may be different
|
|
each time the callback happens, and may be more or less than this value.
|
|
*/
|
|
virtual void prepareToPlay (double sampleRate,
|
|
int estimatedSamplesPerBlock) = 0;
|
|
|
|
/** Called after playback has stopped, to let the filter free up any resources it
|
|
no longer needs.
|
|
*/
|
|
virtual void releaseResources() = 0;
|
|
|
|
/** Renders the next block.
|
|
|
|
When this method is called, the buffer contains a number of channels which is
|
|
at least as great as the maximum number of input and output channels that
|
|
this filter is using. It will be filled with the filter's input data and
|
|
should be replaced with the filter's output.
|
|
|
|
So for example if your filter has 2 input channels and 4 output channels, then
|
|
the buffer will contain 4 channels, the first two being filled with the
|
|
input data. Your filter should read these, do its processing, and replace
|
|
the contents of all 4 channels with its output.
|
|
|
|
Or if your filter has 5 inputs and 2 outputs, the buffer will have 5 channels,
|
|
all filled with data, and your filter should overwrite the first 2 of these
|
|
with its output. But be VERY careful not to write anything to the last 3
|
|
channels, as these might be mapped to memory that the host assumes is read-only!
|
|
|
|
Note that if you have more outputs than inputs, then only those channels that
|
|
correspond to an input channel are guaranteed to contain sensible data - e.g.
|
|
in the case of 2 inputs and 4 outputs, the first two channels contain the input,
|
|
but the last two channels may contain garbage, so you should be careful not to
|
|
let this pass through without being overwritten or cleared.
|
|
|
|
Also note that the buffer may have more channels than are strictly necessary,
|
|
but your should only read/write from the ones that your filter is supposed to
|
|
be using.
|
|
|
|
The number of samples in these buffers is NOT guaranteed to be the same for every
|
|
callback, and may be more or less than the estimated value given to prepareToPlay().
|
|
Your code must be able to cope with variable-sized blocks, or you're going to get
|
|
clicks and crashes!
|
|
|
|
If the filter is receiving a midi input, then the midiMessages array will be filled
|
|
with the midi messages for this block. Each message's timestamp will indicate the
|
|
message's time, as a number of samples from the start of the block.
|
|
|
|
Any messages left in the midi buffer when this method has finished are assumed to
|
|
be the filter's midi output. This means that your filter should be careful to
|
|
clear any incoming messages from the array if it doesn't want them to be passed-on.
|
|
|
|
Be very careful about what you do in this callback - it's going to be called by
|
|
the audio thread, so any kind of interaction with the UI is absolutely
|
|
out of the question. If you change a parameter in here and need to tell your UI to
|
|
update itself, the best way is probably to inherit from a ChangeBroadcaster, let
|
|
the UI components register as listeners, and then call sendChangeMessage() inside the
|
|
processBlock() method to send out an asynchronous message. You could also use
|
|
the AsyncUpdater class in a similar way.
|
|
*/
|
|
virtual void processBlock (AudioSampleBuffer& buffer,
|
|
MidiBuffer& midiMessages) = 0;
|
|
|
|
/** Returns the current AudioPlayHead object that should be used to find
|
|
out the state and position of the playhead.
|
|
|
|
You can call this from your processBlock() method, and use the AudioPlayHead
|
|
object to get the details about the time of the start of the block currently
|
|
being processed.
|
|
|
|
If the host hasn't supplied a playhead object, this will return 0.
|
|
*/
|
|
AudioPlayHead* getPlayHead() const noexcept { return playHead; }
|
|
|
|
/** Returns the current sample rate.
|
|
|
|
This can be called from your processBlock() method - it's not guaranteed
|
|
to be valid at any other time, and may return 0 if it's unknown.
|
|
*/
|
|
double getSampleRate() const noexcept { return sampleRate; }
|
|
|
|
/** Returns the current typical block size that is being used.
|
|
|
|
This can be called from your processBlock() method - it's not guaranteed
|
|
to be valid at any other time.
|
|
|
|
Remember it's not the ONLY block size that may be used when calling
|
|
processBlock, it's just the normal one. The actual block sizes used may be
|
|
larger or smaller than this, and will vary between successive calls.
|
|
*/
|
|
int getBlockSize() const noexcept { return blockSize; }
|
|
|
|
/** Returns the number of input channels that the host will be sending the filter.
|
|
|
|
If writing a plugin, your JucePluginCharacteristics.h file should specify the
|
|
number of channels that your filter would prefer to have, and this method lets
|
|
you know how many the host is actually using.
|
|
|
|
Note that this method is only valid during or after the prepareToPlay()
|
|
method call. Until that point, the number of channels will be unknown.
|
|
*/
|
|
int getNumInputChannels() const noexcept { return numInputChannels; }
|
|
|
|
/** Returns the number of output channels that the host will be sending the filter.
|
|
|
|
If writing a plugin, your JucePluginCharacteristics.h file should specify the
|
|
number of channels that your filter would prefer to have, and this method lets
|
|
you know how many the host is actually using.
|
|
|
|
Note that this method is only valid during or after the prepareToPlay()
|
|
method call. Until that point, the number of channels will be unknown.
|
|
*/
|
|
int getNumOutputChannels() const noexcept { return numOutputChannels; }
|
|
|
|
/** Returns the name of one of the input channels, as returned by the host.
|
|
|
|
The host might not supply very useful names for channels, and this might be
|
|
something like "1", "2", "left", "right", etc.
|
|
*/
|
|
virtual const String getInputChannelName (int channelIndex) const = 0;
|
|
|
|
/** Returns the name of one of the output channels, as returned by the host.
|
|
|
|
The host might not supply very useful names for channels, and this might be
|
|
something like "1", "2", "left", "right", etc.
|
|
*/
|
|
virtual const String getOutputChannelName (int channelIndex) const = 0;
|
|
|
|
/** Returns true if the specified channel is part of a stereo pair with its neighbour. */
|
|
virtual bool isInputChannelStereoPair (int index) const = 0;
|
|
|
|
/** Returns true if the specified channel is part of a stereo pair with its neighbour. */
|
|
virtual bool isOutputChannelStereoPair (int index) const = 0;
|
|
|
|
/** This returns the number of samples delay that the filter imposes on the audio
|
|
passing through it.
|
|
|
|
The host will call this to find the latency - the filter itself should set this value
|
|
by calling setLatencySamples() as soon as it can during its initialisation.
|
|
*/
|
|
int getLatencySamples() const noexcept { return latencySamples; }
|
|
|
|
/** The filter should call this to set the number of samples delay that it introduces.
|
|
|
|
The filter should call this as soon as it can during initialisation, and can call it
|
|
later if the value changes.
|
|
*/
|
|
void setLatencySamples (int newLatency);
|
|
|
|
/** Returns true if the processor wants midi messages. */
|
|
virtual bool acceptsMidi() const = 0;
|
|
|
|
/** Returns true if the processor produces midi messages. */
|
|
virtual bool producesMidi() const = 0;
|
|
|
|
/** This returns a critical section that will automatically be locked while the host
|
|
is calling the processBlock() method.
|
|
|
|
Use it from your UI or other threads to lock access to variables that are used
|
|
by the process callback, but obviously be careful not to keep it locked for
|
|
too long, because that could cause stuttering playback. If you need to do something
|
|
that'll take a long time and need the processing to stop while it happens, use the
|
|
suspendProcessing() method instead.
|
|
|
|
@see suspendProcessing
|
|
*/
|
|
const CriticalSection& getCallbackLock() const noexcept { return callbackLock; }
|
|
|
|
/** Enables and disables the processing callback.
|
|
|
|
If you need to do something time-consuming on a thread and would like to make sure
|
|
the audio processing callback doesn't happen until you've finished, use this
|
|
to disable the callback and re-enable it again afterwards.
|
|
|
|
E.g.
|
|
@code
|
|
void loadNewPatch()
|
|
{
|
|
suspendProcessing (true);
|
|
|
|
..do something that takes ages..
|
|
|
|
suspendProcessing (false);
|
|
}
|
|
@endcode
|
|
|
|
If the host tries to make an audio callback while processing is suspended, the
|
|
filter will return an empty buffer, but won't block the audio thread like it would
|
|
do if you use the getCallbackLock() critical section to synchronise access.
|
|
|
|
If you're going to use this, your processBlock() method must call isSuspended() and
|
|
check whether it's suspended or not. If it is, then it should skip doing any real
|
|
processing, either emitting silence or passing the input through unchanged.
|
|
|
|
@see getCallbackLock
|
|
*/
|
|
void suspendProcessing (bool shouldBeSuspended);
|
|
|
|
/** Returns true if processing is currently suspended.
|
|
@see suspendProcessing
|
|
*/
|
|
bool isSuspended() const noexcept { return suspended; }
|
|
|
|
/** A plugin can override this to be told when it should reset any playing voices.
|
|
|
|
The default implementation does nothing, but a host may call this to tell the
|
|
plugin that it should stop any tails or sounds that have been left running.
|
|
*/
|
|
virtual void reset();
|
|
|
|
/** Returns true if the processor is being run in an offline mode for rendering.
|
|
|
|
If the processor is being run live on realtime signals, this returns false.
|
|
If the mode is unknown, this will assume it's realtime and return false.
|
|
|
|
This value may be unreliable until the prepareToPlay() method has been called,
|
|
and could change each time prepareToPlay() is called.
|
|
|
|
@see setNonRealtime()
|
|
*/
|
|
bool isNonRealtime() const noexcept { return nonRealtime; }
|
|
|
|
/** Called by the host to tell this processor whether it's being used in a non-realime
|
|
capacity for offline rendering or bouncing.
|
|
|
|
Whatever value is passed-in will be
|
|
*/
|
|
void setNonRealtime (bool isNonRealtime) noexcept;
|
|
|
|
/** Creates the filter's UI.
|
|
|
|
This can return 0 if you want a UI-less filter, in which case the host may create
|
|
a generic UI that lets the user twiddle the parameters directly.
|
|
|
|
If you do want to pass back a component, the component should be created and set to
|
|
the correct size before returning it. If you implement this method, you must
|
|
also implement the hasEditor() method and make it return true.
|
|
|
|
Remember not to do anything silly like allowing your filter to keep a pointer to
|
|
the component that gets created - it could be deleted later without any warning, which
|
|
would make your pointer into a dangler. Use the getActiveEditor() method instead.
|
|
|
|
The correct way to handle the connection between an editor component and its
|
|
filter is to use something like a ChangeBroadcaster so that the editor can
|
|
register itself as a listener, and be told when a change occurs. This lets them
|
|
safely unregister themselves when they are deleted.
|
|
|
|
Here are a few things to bear in mind when writing an editor:
|
|
|
|
- Initially there won't be an editor, until the user opens one, or they might
|
|
not open one at all. Your filter mustn't rely on it being there.
|
|
- An editor object may be deleted and a replacement one created again at any time.
|
|
- It's safe to assume that an editor will be deleted before its filter.
|
|
|
|
@see hasEditor
|
|
*/
|
|
virtual AudioProcessorEditor* createEditor() = 0;
|
|
|
|
/** Your filter must override this and return true if it can create an editor component.
|
|
@see createEditor
|
|
*/
|
|
virtual bool hasEditor() const = 0;
|
|
|
|
/** Returns the active editor, if there is one.
|
|
|
|
Bear in mind this can return 0, even if an editor has previously been
|
|
opened.
|
|
*/
|
|
AudioProcessorEditor* getActiveEditor() const noexcept { return activeEditor; }
|
|
|
|
/** Returns the active editor, or if there isn't one, it will create one.
|
|
|
|
This may call createEditor() internally to create the component.
|
|
*/
|
|
AudioProcessorEditor* createEditorIfNeeded();
|
|
|
|
/** This must return the correct value immediately after the object has been
|
|
created, and mustn't change the number of parameters later.
|
|
*/
|
|
virtual int getNumParameters() = 0;
|
|
|
|
/** Returns the name of a particular parameter. */
|
|
virtual const String getParameterName (int parameterIndex) = 0;
|
|
|
|
/** Called by the host to find out the value of one of the filter's parameters.
|
|
|
|
The host will expect the value returned to be between 0 and 1.0.
|
|
|
|
This could be called quite frequently, so try to make your code efficient.
|
|
It's also likely to be called by non-UI threads, so the code in here should
|
|
be thread-aware.
|
|
*/
|
|
virtual float getParameter (int parameterIndex) = 0;
|
|
|
|
/** Returns the value of a parameter as a text string. */
|
|
virtual const String getParameterText (int parameterIndex) = 0;
|
|
|
|
/** The host will call this method to change the value of one of the filter's parameters.
|
|
|
|
The host may call this at any time, including during the audio processing
|
|
callback, so the filter has to process this very fast and avoid blocking.
|
|
|
|
If you want to set the value of a parameter internally, e.g. from your
|
|
editor component, then don't call this directly - instead, use the
|
|
setParameterNotifyingHost() method, which will also send a message to
|
|
the host telling it about the change. If the message isn't sent, the host
|
|
won't be able to automate your parameters properly.
|
|
|
|
The value passed will be between 0 and 1.0.
|
|
*/
|
|
virtual void setParameter (int parameterIndex,
|
|
float newValue) = 0;
|
|
|
|
/** Your filter can call this when it needs to change one of its parameters.
|
|
|
|
This could happen when the editor or some other internal operation changes
|
|
a parameter. This method will call the setParameter() method to change the
|
|
value, and will then send a message to the host telling it about the change.
|
|
|
|
Note that to make sure the host correctly handles automation, you should call
|
|
the beginParameterChangeGesture() and endParameterChangeGesture() methods to
|
|
tell the host when the user has started and stopped changing the parameter.
|
|
*/
|
|
void setParameterNotifyingHost (int parameterIndex,
|
|
float newValue);
|
|
|
|
/** Returns true if the host can automate this parameter.
|
|
|
|
By default, this returns true for all parameters.
|
|
*/
|
|
virtual bool isParameterAutomatable (int parameterIndex) const;
|
|
|
|
/** Should return true if this parameter is a "meta" parameter.
|
|
|
|
A meta-parameter is a parameter that changes other params. It is used
|
|
by some hosts (e.g. AudioUnit hosts).
|
|
|
|
By default this returns false.
|
|
*/
|
|
virtual bool isMetaParameter (int parameterIndex) const;
|
|
|
|
/** Sends a signal to the host to tell it that the user is about to start changing this
|
|
parameter.
|
|
|
|
This allows the host to know when a parameter is actively being held by the user, and
|
|
it may use this information to help it record automation.
|
|
|
|
If you call this, it must be matched by a later call to endParameterChangeGesture().
|
|
*/
|
|
void beginParameterChangeGesture (int parameterIndex);
|
|
|
|
/** Tells the host that the user has finished changing this parameter.
|
|
|
|
This allows the host to know when a parameter is actively being held by the user, and
|
|
it may use this information to help it record automation.
|
|
|
|
A call to this method must follow a call to beginParameterChangeGesture().
|
|
*/
|
|
void endParameterChangeGesture (int parameterIndex);
|
|
|
|
/** The filter can call this when something (apart from a parameter value) has changed.
|
|
|
|
It sends a hint to the host that something like the program, number of parameters,
|
|
etc, has changed, and that it should update itself.
|
|
*/
|
|
void updateHostDisplay();
|
|
|
|
/** Returns the number of preset programs the filter supports.
|
|
|
|
The value returned must be valid as soon as this object is created, and
|
|
must not change over its lifetime.
|
|
|
|
This value shouldn't be less than 1.
|
|
*/
|
|
virtual int getNumPrograms() = 0;
|
|
|
|
/** Returns the number of the currently active program.
|
|
*/
|
|
virtual int getCurrentProgram() = 0;
|
|
|
|
/** Called by the host to change the current program.
|
|
*/
|
|
virtual void setCurrentProgram (int index) = 0;
|
|
|
|
/** Must return the name of a given program. */
|
|
virtual const String getProgramName (int index) = 0;
|
|
|
|
/** Called by the host to rename a program.
|
|
*/
|
|
virtual void changeProgramName (int index, const String& newName) = 0;
|
|
|
|
/** The host will call this method when it wants to save the filter's internal state.
|
|
|
|
This must copy any info about the filter's state into the block of memory provided,
|
|
so that the host can store this and later restore it using setStateInformation().
|
|
|
|
Note that there's also a getCurrentProgramStateInformation() method, which only
|
|
stores the current program, not the state of the entire filter.
|
|
|
|
See also the helper function copyXmlToBinary() for storing settings as XML.
|
|
|
|
@see getCurrentProgramStateInformation
|
|
*/
|
|
virtual void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData) = 0;
|
|
|
|
/** The host will call this method if it wants to save the state of just the filter's
|
|
current program.
|
|
|
|
Unlike getStateInformation, this should only return the current program's state.
|
|
|
|
Not all hosts support this, and if you don't implement it, the base class
|
|
method just calls getStateInformation() instead. If you do implement it, be
|
|
sure to also implement getCurrentProgramStateInformation.
|
|
|
|
@see getStateInformation, setCurrentProgramStateInformation
|
|
*/
|
|
virtual void getCurrentProgramStateInformation (JUCE_NAMESPACE::MemoryBlock& destData);
|
|
|
|
/** This must restore the filter's state from a block of data previously created
|
|
using getStateInformation().
|
|
|
|
Note that there's also a setCurrentProgramStateInformation() method, which tries
|
|
to restore just the current program, not the state of the entire filter.
|
|
|
|
See also the helper function getXmlFromBinary() for loading settings as XML.
|
|
|
|
@see setCurrentProgramStateInformation
|
|
*/
|
|
virtual void setStateInformation (const void* data, int sizeInBytes) = 0;
|
|
|
|
/** The host will call this method if it wants to restore the state of just the filter's
|
|
current program.
|
|
|
|
Not all hosts support this, and if you don't implement it, the base class
|
|
method just calls setStateInformation() instead. If you do implement it, be
|
|
sure to also implement getCurrentProgramStateInformation.
|
|
|
|
@see setStateInformation, getCurrentProgramStateInformation
|
|
*/
|
|
virtual void setCurrentProgramStateInformation (const void* data, int sizeInBytes);
|
|
|
|
/** Adds a listener that will be called when an aspect of this processor changes. */
|
|
void addListener (AudioProcessorListener* newListener);
|
|
|
|
/** Removes a previously added listener. */
|
|
void removeListener (AudioProcessorListener* listenerToRemove);
|
|
|
|
/** Tells the processor to use this playhead object.
|
|
The processor will not take ownership of the object, so the caller must delete it when
|
|
it is no longer being used.
|
|
*/
|
|
void setPlayHead (AudioPlayHead* newPlayHead) noexcept;
|
|
|
|
/** Not for public use - this is called before deleting an editor component. */
|
|
void editorBeingDeleted (AudioProcessorEditor* editor) noexcept;
|
|
|
|
/** Not for public use - this is called to initialise the processor before playing. */
|
|
void setPlayConfigDetails (int numIns, int numOuts,
|
|
double sampleRate,
|
|
int blockSize) noexcept;
|
|
|
|
protected:
|
|
|
|
/** Helper function that just converts an xml element into a binary blob.
|
|
|
|
Use this in your filter's getStateInformation() method if you want to
|
|
store its state as xml.
|
|
|
|
Then use getXmlFromBinary() to reverse this operation and retrieve the XML
|
|
from a binary blob.
|
|
*/
|
|
static void copyXmlToBinary (const XmlElement& xml,
|
|
JUCE_NAMESPACE::MemoryBlock& destData);
|
|
|
|
/** Retrieves an XML element that was stored as binary with the copyXmlToBinary() method.
|
|
|
|
This might return 0 if the data's unsuitable or corrupted. Otherwise it will return
|
|
an XmlElement object that the caller must delete when no longer needed.
|
|
*/
|
|
static XmlElement* getXmlFromBinary (const void* data, int sizeInBytes);
|
|
|
|
/** @internal */
|
|
AudioPlayHead* playHead;
|
|
|
|
/** @internal */
|
|
void sendParamChangeMessageToListeners (int parameterIndex, float newValue);
|
|
|
|
private:
|
|
Array <AudioProcessorListener*> listeners;
|
|
Component::SafePointer<AudioProcessorEditor> activeEditor;
|
|
double sampleRate;
|
|
int blockSize, numInputChannels, numOutputChannels, latencySamples;
|
|
bool suspended, nonRealtime;
|
|
CriticalSection callbackLock, listenerLock;
|
|
|
|
#if JUCE_DEBUG
|
|
BigInteger changingParams;
|
|
#endif
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessor);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPROCESSOR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioProcessor.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_PluginDescription.h ***/
|
|
#ifndef __JUCE_PLUGINDESCRIPTION_JUCEHEADER__
|
|
#define __JUCE_PLUGINDESCRIPTION_JUCEHEADER__
|
|
|
|
/**
|
|
A small class to represent some facts about a particular type of plugin.
|
|
|
|
This class is for storing and managing the details about a plugin without
|
|
actually having to load an instance of it.
|
|
|
|
A KnownPluginList contains a list of PluginDescription objects.
|
|
|
|
@see KnownPluginList
|
|
*/
|
|
class JUCE_API PluginDescription
|
|
{
|
|
public:
|
|
|
|
PluginDescription();
|
|
PluginDescription (const PluginDescription& other);
|
|
PluginDescription& operator= (const PluginDescription& other);
|
|
~PluginDescription();
|
|
|
|
/** The name of the plugin. */
|
|
String name;
|
|
|
|
/** A more descriptive name for the plugin.
|
|
This may be the same as the 'name' field, but some plugins may provide an
|
|
alternative name.
|
|
*/
|
|
String descriptiveName;
|
|
|
|
/** The plugin format, e.g. "VST", "AudioUnit", etc.
|
|
*/
|
|
String pluginFormatName;
|
|
|
|
/** A category, such as "Dynamics", "Reverbs", etc.
|
|
*/
|
|
String category;
|
|
|
|
/** The manufacturer. */
|
|
String manufacturerName;
|
|
|
|
/** The version. This string doesn't have any particular format. */
|
|
String version;
|
|
|
|
/** Either the file containing the plugin module, or some other unique way
|
|
of identifying it.
|
|
|
|
E.g. for an AU, this would be an ID string that the component manager
|
|
could use to retrieve the plugin. For a VST, it's the file path.
|
|
*/
|
|
String fileOrIdentifier;
|
|
|
|
/** The last time the plugin file was changed.
|
|
This is handy when scanning for new or changed plugins.
|
|
*/
|
|
Time lastFileModTime;
|
|
|
|
/** A unique ID for the plugin.
|
|
|
|
Note that this might not be unique between formats, e.g. a VST and some
|
|
other format might actually have the same id.
|
|
|
|
@see createIdentifierString
|
|
*/
|
|
int uid;
|
|
|
|
/** True if the plugin identifies itself as a synthesiser. */
|
|
bool isInstrument;
|
|
|
|
/** The number of inputs. */
|
|
int numInputChannels;
|
|
|
|
/** The number of outputs. */
|
|
int numOutputChannels;
|
|
|
|
/** Returns true if the two descriptions refer the the same plugin.
|
|
|
|
This isn't quite as simple as them just having the same file (because of
|
|
shell plugins).
|
|
*/
|
|
bool isDuplicateOf (const PluginDescription& other) const;
|
|
|
|
/** Returns a string that can be saved and used to uniquely identify the
|
|
plugin again.
|
|
|
|
This contains less info than the XML encoding, and is independent of the
|
|
plugin's file location, so can be used to store a plugin ID for use
|
|
across different machines.
|
|
*/
|
|
String createIdentifierString() const;
|
|
|
|
/** Creates an XML object containing these details.
|
|
|
|
@see loadFromXml
|
|
*/
|
|
XmlElement* createXml() const;
|
|
|
|
/** Reloads the info in this structure from an XML record that was previously
|
|
saved with createXML().
|
|
|
|
Returns true if the XML was a valid plugin description.
|
|
*/
|
|
bool loadFromXml (const XmlElement& xml);
|
|
|
|
private:
|
|
|
|
JUCE_LEAK_DETECTOR (PluginDescription);
|
|
};
|
|
|
|
#endif // __JUCE_PLUGINDESCRIPTION_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_PluginDescription.h ***/
|
|
|
|
/**
|
|
Base class for an active instance of a plugin.
|
|
|
|
This derives from the AudioProcessor class, and adds some extra functionality
|
|
that helps when wrapping dynamically loaded plugins.
|
|
|
|
@see AudioProcessor, AudioPluginFormat
|
|
*/
|
|
class JUCE_API AudioPluginInstance : public AudioProcessor
|
|
{
|
|
public:
|
|
|
|
/** Destructor.
|
|
|
|
Make sure that you delete any UI components that belong to this plugin before
|
|
deleting the plugin.
|
|
*/
|
|
virtual ~AudioPluginInstance() {}
|
|
|
|
/** Fills-in the appropriate parts of this plugin description object.
|
|
*/
|
|
virtual void fillInPluginDescription (PluginDescription& description) const = 0;
|
|
|
|
/** Returns a pointer to some kind of platform-specific data about the plugin.
|
|
|
|
E.g. For a VST, this value can be cast to an AEffect*. For an AudioUnit, it can be
|
|
cast to an AudioUnit handle.
|
|
*/
|
|
virtual void* getPlatformSpecificData() { return nullptr; }
|
|
|
|
protected:
|
|
|
|
AudioPluginInstance() {}
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginInstance);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioPluginInstance.h ***/
|
|
|
|
class PluginDescription;
|
|
|
|
/**
|
|
The base class for a type of plugin format, such as VST, AudioUnit, LADSPA, etc.
|
|
|
|
Use the static getNumFormats() and getFormat() calls to find the types
|
|
of format that are available.
|
|
*/
|
|
class JUCE_API AudioPluginFormat
|
|
{
|
|
public:
|
|
|
|
/** Destructor. */
|
|
virtual ~AudioPluginFormat();
|
|
|
|
/** Returns the format name.
|
|
|
|
E.g. "VST", "AudioUnit", etc.
|
|
*/
|
|
virtual String getName() const = 0;
|
|
|
|
/** This tries to create descriptions for all the plugin types available in
|
|
a binary module file.
|
|
|
|
The file will be some kind of DLL or bundle.
|
|
|
|
Normally there will only be one type returned, but some plugins
|
|
(e.g. VST shells) can use a single DLL to create a set of different plugin
|
|
subtypes, so in that case, each subtype is returned as a separate object.
|
|
*/
|
|
virtual void findAllTypesForFile (OwnedArray <PluginDescription>& results,
|
|
const String& fileOrIdentifier) = 0;
|
|
|
|
/** Tries to recreate a type from a previously generated PluginDescription.
|
|
|
|
@see PluginDescription::createInstance
|
|
*/
|
|
virtual AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc) = 0;
|
|
|
|
/** Should do a quick check to see if this file or directory might be a plugin of
|
|
this format.
|
|
|
|
This is for searching for potential files, so it shouldn't actually try to
|
|
load the plugin or do anything time-consuming.
|
|
*/
|
|
virtual bool fileMightContainThisPluginType (const String& fileOrIdentifier) = 0;
|
|
|
|
/** Returns a readable version of the name of the plugin that this identifier refers to.
|
|
*/
|
|
virtual String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) = 0;
|
|
|
|
/** Checks whether this plugin could possibly be loaded.
|
|
|
|
It doesn't actually need to load it, just to check whether the file or component
|
|
still exists.
|
|
*/
|
|
virtual bool doesPluginStillExist (const PluginDescription& desc) = 0;
|
|
|
|
/** Searches a suggested set of directories for any plugins in this format.
|
|
|
|
The path might be ignored, e.g. by AUs, which are found by the OS rather
|
|
than manually.
|
|
*/
|
|
virtual StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch,
|
|
bool recursive) = 0;
|
|
|
|
/** Returns the typical places to look for this kind of plugin.
|
|
|
|
Note that if this returns no paths, it means that the format can't be scanned-for
|
|
(i.e. it's an internal format that doesn't live in files)
|
|
*/
|
|
virtual FileSearchPath getDefaultLocationsToSearch() = 0;
|
|
|
|
protected:
|
|
|
|
AudioPluginFormat() noexcept;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormat);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioPluginFormat.h ***/
|
|
|
|
#if JUCE_PLUGINHOST_AU && JUCE_MAC
|
|
|
|
/**
|
|
Implements a plugin format manager for AudioUnits.
|
|
*/
|
|
class JUCE_API AudioUnitPluginFormat : public AudioPluginFormat
|
|
{
|
|
public:
|
|
|
|
AudioUnitPluginFormat();
|
|
~AudioUnitPluginFormat();
|
|
|
|
String getName() const { return "AudioUnit"; }
|
|
void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier);
|
|
AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc);
|
|
bool fileMightContainThisPluginType (const String& fileOrIdentifier);
|
|
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier);
|
|
StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, bool recursive);
|
|
bool doesPluginStillExist (const PluginDescription& desc);
|
|
FileSearchPath getDefaultLocationsToSearch();
|
|
|
|
private:
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioUnitPluginFormat);
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif // __JUCE_AUDIOUNITPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioUnitPluginFormat.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DirectXPluginFormat.h ***/
|
|
#ifndef __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__
|
|
#define __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__
|
|
|
|
#if JUCE_PLUGINHOST_DX && JUCE_WINDOWS
|
|
|
|
// Sorry, this file is just a placeholder at the moment!...
|
|
|
|
/**
|
|
Implements a plugin format manager for DirectX plugins.
|
|
*/
|
|
class JUCE_API DirectXPluginFormat : public AudioPluginFormat
|
|
{
|
|
public:
|
|
|
|
DirectXPluginFormat();
|
|
~DirectXPluginFormat();
|
|
|
|
String getName() const { return "DirectX"; }
|
|
void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier);
|
|
AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc);
|
|
bool fileMightContainThisPluginType (const String& fileOrIdentifier);
|
|
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; }
|
|
FileSearchPath getDefaultLocationsToSearch();
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectXPluginFormat);
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif // __JUCE_DIRECTXPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DirectXPluginFormat.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_LADSPAPluginFormat.h ***/
|
|
#ifndef __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__
|
|
#define __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__
|
|
|
|
#if JUCE_PLUGINHOST_LADSPA && JUCE_LINUX
|
|
|
|
// Sorry, this file is just a placeholder at the moment!...
|
|
|
|
/**
|
|
Implements a plugin format manager for DirectX plugins.
|
|
*/
|
|
class JUCE_API LADSPAPluginFormat : public AudioPluginFormat
|
|
{
|
|
public:
|
|
|
|
LADSPAPluginFormat();
|
|
~LADSPAPluginFormat();
|
|
|
|
String getName() const { return "LADSPA"; }
|
|
void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier);
|
|
AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc);
|
|
bool fileMightContainThisPluginType (const String& fileOrIdentifier);
|
|
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier) { return fileOrIdentifier; }
|
|
FileSearchPath getDefaultLocationsToSearch();
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LADSPAPluginFormat);
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif // __JUCE_LADSPAPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_LADSPAPluginFormat.h ***/
|
|
|
|
|
|
#endif
|
|
|
|
/*** Start of inlined file: juce_VSTMidiEventList.h ***/
|
|
#ifdef __aeffect__
|
|
|
|
#ifndef __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__
|
|
#define __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__
|
|
|
|
/** Holds a set of VSTMidiEvent objects and makes it easy to add
|
|
events to the list.
|
|
|
|
This is used by both the VST hosting code and the plugin wrapper.
|
|
*/
|
|
class VSTMidiEventList
|
|
{
|
|
public:
|
|
|
|
VSTMidiEventList()
|
|
: numEventsUsed (0), numEventsAllocated (0)
|
|
{
|
|
}
|
|
|
|
~VSTMidiEventList()
|
|
{
|
|
freeEvents();
|
|
}
|
|
|
|
void clear()
|
|
{
|
|
numEventsUsed = 0;
|
|
|
|
if (events != nullptr)
|
|
events->numEvents = 0;
|
|
}
|
|
|
|
void addEvent (const void* const midiData, const int numBytes, const int frameOffset)
|
|
{
|
|
ensureSize (numEventsUsed + 1);
|
|
|
|
VstMidiEvent* const e = (VstMidiEvent*) (events->events [numEventsUsed]);
|
|
events->numEvents = ++numEventsUsed;
|
|
|
|
if (numBytes <= 4)
|
|
{
|
|
if (e->type == kVstSysExType)
|
|
{
|
|
delete[] (((VstMidiSysexEvent*) e)->sysexDump);
|
|
e->type = kVstMidiType;
|
|
e->byteSize = sizeof (VstMidiEvent);
|
|
e->noteLength = 0;
|
|
e->noteOffset = 0;
|
|
e->detune = 0;
|
|
e->noteOffVelocity = 0;
|
|
}
|
|
|
|
e->deltaFrames = frameOffset;
|
|
memcpy (e->midiData, midiData, numBytes);
|
|
}
|
|
else
|
|
{
|
|
VstMidiSysexEvent* const se = (VstMidiSysexEvent*) e;
|
|
|
|
if (se->type == kVstSysExType)
|
|
delete[] se->sysexDump;
|
|
|
|
se->sysexDump = new char [numBytes];
|
|
memcpy (se->sysexDump, midiData, numBytes);
|
|
|
|
se->type = kVstSysExType;
|
|
se->byteSize = sizeof (VstMidiSysexEvent);
|
|
se->deltaFrames = frameOffset;
|
|
se->flags = 0;
|
|
se->dumpBytes = numBytes;
|
|
se->resvd1 = 0;
|
|
se->resvd2 = 0;
|
|
}
|
|
}
|
|
|
|
// Handy method to pull the events out of an event buffer supplied by the host
|
|
// or plugin.
|
|
static void addEventsToMidiBuffer (const VstEvents* events, MidiBuffer& dest)
|
|
{
|
|
for (int i = 0; i < events->numEvents; ++i)
|
|
{
|
|
const VstEvent* const e = events->events[i];
|
|
|
|
if (e != nullptr)
|
|
{
|
|
if (e->type == kVstMidiType)
|
|
{
|
|
dest.addEvent ((const JUCE_NAMESPACE::uint8*) ((const VstMidiEvent*) e)->midiData,
|
|
4, e->deltaFrames);
|
|
}
|
|
else if (e->type == kVstSysExType)
|
|
{
|
|
dest.addEvent ((const JUCE_NAMESPACE::uint8*) ((const VstMidiSysexEvent*) e)->sysexDump,
|
|
(int) ((const VstMidiSysexEvent*) e)->dumpBytes,
|
|
e->deltaFrames);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ensureSize (int numEventsNeeded)
|
|
{
|
|
if (numEventsNeeded > numEventsAllocated)
|
|
{
|
|
numEventsNeeded = (numEventsNeeded + 32) & ~31;
|
|
|
|
const int size = 20 + sizeof (VstEvent*) * numEventsNeeded;
|
|
|
|
if (events == nullptr)
|
|
events.calloc (size, 1);
|
|
else
|
|
events.realloc (size, 1);
|
|
|
|
for (int i = numEventsAllocated; i < numEventsNeeded; ++i)
|
|
events->events[i] = allocateVSTEvent();
|
|
|
|
numEventsAllocated = numEventsNeeded;
|
|
}
|
|
}
|
|
|
|
void freeEvents()
|
|
{
|
|
if (events != nullptr)
|
|
{
|
|
for (int i = numEventsAllocated; --i >= 0;)
|
|
freeVSTEvent (events->events[i]);
|
|
|
|
events.free();
|
|
numEventsUsed = 0;
|
|
numEventsAllocated = 0;
|
|
}
|
|
}
|
|
|
|
HeapBlock <VstEvents> events;
|
|
|
|
private:
|
|
int numEventsUsed, numEventsAllocated;
|
|
|
|
static VstEvent* allocateVSTEvent()
|
|
{
|
|
VstEvent* const e = (VstEvent*) ::calloc (1, sizeof (VstMidiEvent) > sizeof (VstMidiSysexEvent) ? sizeof (VstMidiEvent)
|
|
: sizeof (VstMidiSysexEvent));
|
|
e->type = kVstMidiType;
|
|
e->byteSize = sizeof (VstMidiEvent);
|
|
return e;
|
|
}
|
|
|
|
static void freeVSTEvent (VstEvent* e)
|
|
{
|
|
if (e->type == kVstSysExType)
|
|
delete[] (((VstMidiSysexEvent*) e)->sysexDump);
|
|
|
|
::free (e);
|
|
}
|
|
};
|
|
|
|
#endif // __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__
|
|
#endif // __JUCE_VSTMIDIEVENTLIST_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_VSTMidiEventList.h ***/
|
|
|
|
|
|
#ifndef __JUCE_VSTPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_VSTPluginFormat.h ***/
|
|
#ifndef __JUCE_VSTPLUGINFORMAT_JUCEHEADER__
|
|
#define __JUCE_VSTPLUGINFORMAT_JUCEHEADER__
|
|
|
|
#if JUCE_PLUGINHOST_VST
|
|
|
|
/**
|
|
Implements a plugin format manager for VSTs.
|
|
*/
|
|
class JUCE_API VSTPluginFormat : public AudioPluginFormat
|
|
{
|
|
public:
|
|
|
|
VSTPluginFormat();
|
|
~VSTPluginFormat();
|
|
|
|
String getName() const { return "VST"; }
|
|
void findAllTypesForFile (OwnedArray <PluginDescription>& results, const String& fileOrIdentifier);
|
|
AudioPluginInstance* createInstanceFromDescription (const PluginDescription& desc);
|
|
bool fileMightContainThisPluginType (const String& fileOrIdentifier);
|
|
String getNameOfPluginFromIdentifier (const String& fileOrIdentifier);
|
|
StringArray searchPathsForPlugins (const FileSearchPath& directoriesToSearch, bool recursive);
|
|
bool doesPluginStillExist (const PluginDescription& desc);
|
|
FileSearchPath getDefaultLocationsToSearch();
|
|
|
|
private:
|
|
|
|
void recursiveFileSearch (StringArray& results, const File& dir, const bool recursive);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (VSTPluginFormat);
|
|
};
|
|
|
|
#endif
|
|
#endif // __JUCE_VSTPLUGINFORMAT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_VSTPluginFormat.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPLUGINFORMAT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_AudioPluginFormatManager.h ***/
|
|
#ifndef __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__
|
|
#define __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__
|
|
|
|
/**
|
|
This maintains a list of known AudioPluginFormats.
|
|
|
|
@see AudioPluginFormat
|
|
*/
|
|
class JUCE_API AudioPluginFormatManager : public DeletedAtShutdown
|
|
{
|
|
public:
|
|
|
|
AudioPluginFormatManager();
|
|
|
|
/** Destructor. */
|
|
~AudioPluginFormatManager();
|
|
|
|
juce_DeclareSingleton_SingleThreaded (AudioPluginFormatManager, false);
|
|
|
|
/** Adds any formats that it knows about, e.g. VST.
|
|
*/
|
|
void addDefaultFormats();
|
|
|
|
/** Returns the number of types of format that are available.
|
|
|
|
Use getFormat() to get one of them.
|
|
*/
|
|
int getNumFormats();
|
|
|
|
/** Returns one of the available formats.
|
|
|
|
@see getNumFormats
|
|
*/
|
|
AudioPluginFormat* getFormat (int index);
|
|
|
|
/** Adds a format to the list.
|
|
|
|
The object passed in will be owned and deleted by the manager.
|
|
*/
|
|
void addFormat (AudioPluginFormat* format);
|
|
|
|
/** Tries to load the type for this description, by trying all the formats
|
|
that this manager knows about.
|
|
|
|
The caller is responsible for deleting the object that is returned.
|
|
|
|
If it can't load the plugin, it returns 0 and leaves a message in the
|
|
errorMessage string.
|
|
*/
|
|
AudioPluginInstance* createPluginInstance (const PluginDescription& description,
|
|
String& errorMessage) const;
|
|
|
|
/** Checks that the file or component for this plugin actually still exists.
|
|
|
|
(This won't try to load the plugin)
|
|
*/
|
|
bool doesPluginStillExist (const PluginDescription& description) const;
|
|
|
|
private:
|
|
|
|
OwnedArray <AudioPluginFormat> formats;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioPluginFormatManager);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPLUGINFORMATMANAGER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioPluginFormatManager.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPLUGININSTANCE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_KNOWNPLUGINLIST_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_KnownPluginList.h ***/
|
|
#ifndef __JUCE_KNOWNPLUGINLIST_JUCEHEADER__
|
|
#define __JUCE_KNOWNPLUGINLIST_JUCEHEADER__
|
|
|
|
|
|
/*** 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 isEnabled 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 isEnabled = 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 isEnabled = 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 isEnabled = 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** Class used to create a set of options to pass to the show() method.
|
|
You can chain together a series of calls to this class's methods to create
|
|
a set of whatever options you want to specify.
|
|
E.g. @code
|
|
PopupMenu menu;
|
|
...
|
|
menu.showMenu (PopupMenu::Options().withMaximumWidth (100),
|
|
.withMaximumNumColumns (3)
|
|
.withTargetComponent (myComp));
|
|
@endcode
|
|
*/
|
|
class JUCE_API Options
|
|
{
|
|
public:
|
|
Options();
|
|
|
|
const Options withTargetComponent (Component* targetComponent) const;
|
|
const Options withTargetScreenArea (const Rectangle<int>& targetArea) const;
|
|
const Options withMinimumWidth (int minWidth) const;
|
|
const Options withMaximumNumColumns (int maxNumColumns) const;
|
|
const Options withStandardItemHeight (int standardHeight) const;
|
|
const Options withItemThatMustBeVisible (int idOfItemToBeVisible) const;
|
|
|
|
private:
|
|
friend class PopupMenu;
|
|
Rectangle<int> targetArea;
|
|
Component* targetComponent;
|
|
int visibleItemID, minWidth, maxColumns, standardHeight;
|
|
};
|
|
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
/** 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 = nullptr);
|
|
|
|
/** 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<int>& screenAreaToAttachTo,
|
|
int itemIdThatMustBeVisible = 0,
|
|
int minimumWidth = 0,
|
|
int maximumNumColumns = 0,
|
|
int standardItemHeight = 0,
|
|
ModalComponentManager::Callback* callback = nullptr);
|
|
|
|
/** 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 = nullptr);
|
|
|
|
/** Displays and runs the menu modally, with a set of options.
|
|
*/
|
|
int showMenu (const Options& options);
|
|
#endif
|
|
|
|
/** Runs the menu asynchronously, with a user-provided callback that will receive the result. */
|
|
void showMenuAsync (const Options& options,
|
|
ModalComponentManager::Callback* callback);
|
|
|
|
/** 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 SingleThreadedReferenceCountedObject
|
|
{
|
|
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 noexcept { return isHighlighted; }
|
|
|
|
/** @internal */
|
|
bool isTriggeredAutomatically() const noexcept { 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 <Item>;
|
|
friend class OwnedArray <ItemComponent>;
|
|
friend class ScopedPointer <Window>;
|
|
|
|
OwnedArray <Item> items;
|
|
LookAndFeel* lookAndFeel;
|
|
bool separatorPending;
|
|
|
|
void addSeparatorIfPending();
|
|
Component* createWindow (const Options&, ApplicationCommandManager**) const;
|
|
int showWithOptionalCallback (const Options&, ModalComponentManager::Callback*, bool);
|
|
|
|
JUCE_LEAK_DETECTOR (PopupMenu);
|
|
};
|
|
|
|
#endif // __JUCE_POPUPMENU_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_PopupMenu.h ***/
|
|
|
|
/**
|
|
Manages a list of plugin types.
|
|
|
|
This can be easily edited, saved and loaded, and used to create instances of
|
|
the plugin types in it.
|
|
|
|
@see PluginListComponent
|
|
*/
|
|
class JUCE_API KnownPluginList : public ChangeBroadcaster
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty list.
|
|
*/
|
|
KnownPluginList();
|
|
|
|
/** Destructor. */
|
|
~KnownPluginList();
|
|
|
|
/** Clears the list. */
|
|
void clear();
|
|
|
|
/** Returns the number of types currently in the list.
|
|
@see getType
|
|
*/
|
|
int getNumTypes() const noexcept { return types.size(); }
|
|
|
|
/** Returns one of the types.
|
|
@see getNumTypes
|
|
*/
|
|
PluginDescription* getType (int index) const noexcept { return types [index]; }
|
|
|
|
/** Looks for a type in the list which comes from this file.
|
|
*/
|
|
PluginDescription* getTypeForFile (const String& fileOrIdentifier) const;
|
|
|
|
/** Looks for a type in the list which matches a plugin type ID.
|
|
|
|
The identifierString parameter must have been created by
|
|
PluginDescription::createIdentifierString().
|
|
*/
|
|
PluginDescription* getTypeForIdentifierString (const String& identifierString) const;
|
|
|
|
/** Adds a type manually from its description. */
|
|
bool addType (const PluginDescription& type);
|
|
|
|
/** Removes a type. */
|
|
void removeType (int index);
|
|
|
|
/** Looks for all types that can be loaded from a given file, and adds them
|
|
to the list.
|
|
|
|
If dontRescanIfAlreadyInList is true, then the file will only be loaded and
|
|
re-tested if it's not already in the list, or if the file's modification
|
|
time has changed since the list was created. If dontRescanIfAlreadyInList is
|
|
false, the file will always be reloaded and tested.
|
|
|
|
Returns true if any new types were added, and all the types found in this
|
|
file (even if it was already known and hasn't been re-scanned) get returned
|
|
in the array.
|
|
*/
|
|
bool scanAndAddFile (const String& possiblePluginFileOrIdentifier,
|
|
bool dontRescanIfAlreadyInList,
|
|
OwnedArray <PluginDescription>& typesFound,
|
|
AudioPluginFormat& formatToUse);
|
|
|
|
/** Returns true if the specified file is already known about and if it
|
|
hasn't been modified since our entry was created.
|
|
*/
|
|
bool isListingUpToDate (const String& possiblePluginFileOrIdentifier) const;
|
|
|
|
/** Scans and adds a bunch of files that might have been dragged-and-dropped.
|
|
|
|
If any types are found in the files, their descriptions are returned in the array.
|
|
*/
|
|
void scanAndAddDragAndDroppedFiles (const StringArray& filenames,
|
|
OwnedArray <PluginDescription>& typesFound);
|
|
|
|
/** Sort methods used to change the order of the plugins in the list.
|
|
*/
|
|
enum SortMethod
|
|
{
|
|
defaultOrder = 0,
|
|
sortAlphabetically,
|
|
sortByCategory,
|
|
sortByManufacturer,
|
|
sortByFileSystemLocation
|
|
};
|
|
|
|
/** Adds all the plugin types to a popup menu so that the user can select one.
|
|
|
|
Depending on the sort method, it may add sub-menus for categories,
|
|
manufacturers, etc.
|
|
|
|
Use getIndexChosenByMenu() to find out the type that was chosen.
|
|
*/
|
|
void addToMenu (PopupMenu& menu,
|
|
const SortMethod sortMethod) const;
|
|
|
|
/** Converts a menu item index that has been chosen into its index in this list.
|
|
|
|
Returns -1 if it's not an ID that was used.
|
|
|
|
@see addToMenu
|
|
*/
|
|
int getIndexChosenByMenu (int menuResultCode) const;
|
|
|
|
/** Sorts the list. */
|
|
void sort (const SortMethod method);
|
|
|
|
/** Creates some XML that can be used to store the state of this list.
|
|
*/
|
|
XmlElement* createXml() const;
|
|
|
|
/** Recreates the state of this list from its stored XML format.
|
|
*/
|
|
void recreateFromXml (const XmlElement& xml);
|
|
|
|
private:
|
|
|
|
OwnedArray <PluginDescription> types;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KnownPluginList);
|
|
};
|
|
|
|
#endif // __JUCE_KNOWNPLUGINLIST_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_KnownPluginList.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_PLUGINDESCRIPTION_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_PluginDirectoryScanner.h ***/
|
|
#ifndef __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__
|
|
#define __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__
|
|
|
|
/**
|
|
Scans a directory for plugins, and adds them to a KnownPluginList.
|
|
|
|
To use one of these, create it and call scanNextFile() repeatedly, until
|
|
it returns false.
|
|
*/
|
|
class JUCE_API PluginDirectoryScanner
|
|
{
|
|
public:
|
|
|
|
/**
|
|
Creates a scanner.
|
|
|
|
@param listToAddResultsTo this will get the new types added to it.
|
|
@param formatToLookFor this is the type of format that you want to look for
|
|
@param directoriesToSearch the path to search
|
|
@param searchRecursively true to search recursively
|
|
@param deadMansPedalFile if this isn't File::nonexistent, then it will
|
|
be used as a file to store the names of any plugins
|
|
that crash during initialisation. If there are
|
|
any plugins listed in it, then these will always
|
|
be scanned after all other possible files have
|
|
been tried - in this way, even if there's a few
|
|
dodgy plugins in your path, then a couple of rescans
|
|
will still manage to find all the proper plugins.
|
|
It's probably best to choose a file in the user's
|
|
application data directory (alongside your app's
|
|
settings file) for this. The file format it uses
|
|
is just a list of filenames of the modules that
|
|
failed.
|
|
*/
|
|
PluginDirectoryScanner (KnownPluginList& listToAddResultsTo,
|
|
AudioPluginFormat& formatToLookFor,
|
|
FileSearchPath directoriesToSearch,
|
|
bool searchRecursively,
|
|
const File& deadMansPedalFile);
|
|
|
|
/** Destructor. */
|
|
~PluginDirectoryScanner();
|
|
|
|
/** Tries the next likely-looking file.
|
|
|
|
If dontRescanIfAlreadyInList is true, then the file will only be loaded and
|
|
re-tested if it's not already in the list, or if the file's modification
|
|
time has changed since the list was created. If dontRescanIfAlreadyInList is
|
|
false, the file will always be reloaded and tested.
|
|
|
|
Returns false when there are no more files to try.
|
|
*/
|
|
bool scanNextFile (bool dontRescanIfAlreadyInList);
|
|
|
|
/** Skips over the next file without scanning it.
|
|
Returns false when there are no more files to try.
|
|
*/
|
|
bool skipNextFile();
|
|
|
|
/** Returns the description of the plugin that will be scanned during the next
|
|
call to scanNextFile().
|
|
|
|
This is handy if you want to show the user which file is currently getting
|
|
scanned.
|
|
*/
|
|
const String getNextPluginFileThatWillBeScanned() const;
|
|
|
|
/** Returns the estimated progress, between 0 and 1.
|
|
*/
|
|
float getProgress() const { return progress; }
|
|
|
|
/** This returns a list of all the filenames of things that looked like being
|
|
a plugin file, but which failed to open for some reason.
|
|
*/
|
|
const StringArray& getFailedFiles() const noexcept { return failedFiles; }
|
|
|
|
private:
|
|
|
|
KnownPluginList& list;
|
|
AudioPluginFormat& format;
|
|
StringArray filesOrIdentifiersToScan;
|
|
File deadMansPedalFile;
|
|
StringArray failedFiles;
|
|
int nextIndex;
|
|
float progress;
|
|
|
|
StringArray getDeadMansPedalFile();
|
|
void setDeadMansPedalFile (const StringArray& newContents);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginDirectoryScanner);
|
|
};
|
|
|
|
#endif // __JUCE_PLUGINDIRECTORYSCANNER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_PluginDirectoryScanner.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_PluginListComponent.h ***/
|
|
#ifndef __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_ListBox.h ***/
|
|
#ifndef __JUCE_LISTBOX_JUCEHEADER__
|
|
#define __JUCE_LISTBOX_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 = nullptr,
|
|
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) noexcept;
|
|
|
|
/** 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<int> 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 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept { 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) noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept { 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** Returns the number of milliseconds since the last time the button
|
|
went into the 'down' state.
|
|
*/
|
|
uint32 getMillisecondsSinceButtonDown() const noexcept;
|
|
|
|
/** 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 noexcept { return connectedEdgeFlags; }
|
|
|
|
/** Indicates whether the button adjoins another one on its left edge.
|
|
@see setConnectedEdges
|
|
*/
|
|
bool isConnectedOnLeft() const noexcept { return (connectedEdgeFlags & ConnectedOnLeft) != 0; }
|
|
|
|
/** Indicates whether the button adjoins another one on its right edge.
|
|
@see setConnectedEdges
|
|
*/
|
|
bool isConnectedOnRight() const noexcept { return (connectedEdgeFlags & ConnectedOnRight) != 0; }
|
|
|
|
/** Indicates whether the button adjoins another one on its top edge.
|
|
@see setConnectedEdges
|
|
*/
|
|
bool isConnectedOnTop() const noexcept { return (connectedEdgeFlags & ConnectedOnTop) != 0; }
|
|
|
|
/** Indicates whether the button adjoins another one on its bottom edge.
|
|
@see setConnectedEdges
|
|
*/
|
|
bool isConnectedOnBottom() const noexcept { 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 <KeyPress> shortcuts;
|
|
WeakReference<Component> keySource;
|
|
String text;
|
|
ListenerList <Listener> buttonListeners;
|
|
|
|
class RepeatTimer;
|
|
friend class RepeatTimer;
|
|
friend class ScopedPointer <RepeatTimer>;
|
|
ScopedPointer <RepeatTimer> 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 noexcept { 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 noexcept;
|
|
|
|
/** 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<double>& 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<double> getRangeLimit() const noexcept { return totalRange; }
|
|
|
|
/** Returns the lower value that the thumb can be set to.
|
|
|
|
This is the value set by setRangeLimits().
|
|
*/
|
|
double getMinimumRangeLimit() const noexcept { return totalRange.getStart(); }
|
|
|
|
/** Returns the upper value that the thumb can be set to.
|
|
|
|
This is the value set by setRangeLimits().
|
|
*/
|
|
double getMaximumRangeLimit() const noexcept { 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<double>& 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<double> getCurrentRange() const noexcept { return visibleRange; }
|
|
|
|
/** Returns the position of the top of the thumb.
|
|
@see getCurrentRange, setCurrentRangeStart
|
|
*/
|
|
double getCurrentRangeStart() const noexcept { return visibleRange.getStart(); }
|
|
|
|
/** Returns the current size of the thumb.
|
|
@see getCurrentRange, setCurrentRange
|
|
*/
|
|
double getCurrentRangeSize() const noexcept { 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 <double> 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<ScrollbarButton>;
|
|
ScopedPointer<ScrollbarButton> upButton, downButton;
|
|
ListenerList <Listener> 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, or null to remove
|
|
the current component.
|
|
@param deleteComponentWhenNoLongerNeeded if true, the component will be deleted
|
|
automatically when the viewport is deleted or when a different
|
|
component is added. If false, the caller must manage the lifetime
|
|
of the component
|
|
@see getViewedComponent
|
|
*/
|
|
void setViewedComponent (Component* newViewedComponent,
|
|
bool deleteComponentWhenNoLongerNeeded = true);
|
|
|
|
/** Returns the component that's currently being used inside the Viewport.
|
|
|
|
@see setViewedComponent
|
|
*/
|
|
Component* getViewedComponent() const noexcept { 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<int>& 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<int> getViewPosition() const noexcept { return lastVisibleArea.getPosition(); }
|
|
|
|
/** Returns the position within the child component of the top-left of its visible area.
|
|
@see getViewWidth, setViewPosition
|
|
*/
|
|
int getViewPositionX() const noexcept { return lastVisibleArea.getX(); }
|
|
|
|
/** Returns the position within the child component of the top-left of its visible area.
|
|
@see getViewHeight, setViewPosition
|
|
*/
|
|
int getViewPositionY() const noexcept { 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 noexcept { 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 noexcept { 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<int>& 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 noexcept { return showVScrollbar; }
|
|
|
|
/** True if the horizontal scrollbar is enabled.
|
|
@see setScrollBarsShown
|
|
*/
|
|
bool isHorizontalScrollBarShown() const noexcept { 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() noexcept { return &verticalScrollBar; }
|
|
|
|
/** Returns a pointer to the scrollbar component being used.
|
|
Handy if you need to customise the bar somehow.
|
|
*/
|
|
ScrollBar* getHorizontalScrollBar() noexcept { 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<Component> contentComp;
|
|
Rectangle<int> lastVisibleArea;
|
|
int scrollBarThickness;
|
|
int singleStepX, singleStepY;
|
|
bool showHScrollbar, showVScrollbar, deleteContent;
|
|
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 ***/
|
|
|
|
class ListViewport;
|
|
|
|
/**
|
|
A subclass of this is used to drive a ListBox.
|
|
|
|
@see ListBox
|
|
*/
|
|
class JUCE_API ListBoxModel
|
|
{
|
|
public:
|
|
|
|
/** Destructor. */
|
|
virtual ~ListBoxModel() {}
|
|
|
|
/** This has to return the number of items in the list.
|
|
|
|
@see ListBox::getNumRows()
|
|
*/
|
|
virtual int getNumRows() = 0;
|
|
|
|
/** This method must be implemented to draw a row of the list.
|
|
*/
|
|
virtual void paintListBoxItem (int rowNumber,
|
|
Graphics& g,
|
|
int width, int height,
|
|
bool rowIsSelected) = 0;
|
|
|
|
/** This is used to create or update a custom component to go in a row of the list.
|
|
|
|
Any row may contain a custom component, or can just be drawn with the paintListBoxItem() method
|
|
and handle mouse clicks with listBoxItemClicked().
|
|
|
|
This method will be called whenever a custom component might need to be updated - e.g.
|
|
when the table is changed, or TableListBox::updateContent() is called.
|
|
|
|
If you don't need a custom component for the specified row, then return 0.
|
|
|
|
If you do want a custom component, and the existingComponentToUpdate is null, then
|
|
this method must create a suitable new component and return it.
|
|
|
|
If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created
|
|
by this method. In this case, the method must either update it to make sure it's correctly representing
|
|
the given row (which may be different from the one that the component was created for), or it can
|
|
delete this component and return a new one.
|
|
|
|
The component that your method returns will be deleted by the ListBox when it is no longer needed.
|
|
*/
|
|
virtual Component* refreshComponentForRow (int rowNumber, bool isRowSelected,
|
|
Component* existingComponentToUpdate);
|
|
|
|
/** This can be overridden to react to the user clicking on a row.
|
|
|
|
@see listBoxItemDoubleClicked
|
|
*/
|
|
virtual void listBoxItemClicked (int row, const MouseEvent& e);
|
|
|
|
/** This can be overridden to react to the user double-clicking on a row.
|
|
|
|
@see listBoxItemClicked
|
|
*/
|
|
virtual void listBoxItemDoubleClicked (int row, const MouseEvent& e);
|
|
|
|
/** This can be overridden to react to the user double-clicking on a part of the list where
|
|
there are no rows.
|
|
|
|
@see listBoxItemClicked
|
|
*/
|
|
virtual void backgroundClicked();
|
|
|
|
/** Override this to be informed when rows are selected or deselected.
|
|
|
|
This will be called whenever a row is selected or deselected. If a range of
|
|
rows is selected all at once, this will just be called once for that event.
|
|
|
|
@param lastRowSelected the last row that the user selected. If no
|
|
rows are currently selected, this may be -1.
|
|
*/
|
|
virtual void selectedRowsChanged (int lastRowSelected);
|
|
|
|
/** Override this to be informed when the delete key is pressed.
|
|
|
|
If no rows are selected when they press the key, this won't be called.
|
|
|
|
@param lastRowSelected the last row that had been selected when they pressed the
|
|
key - if there are multiple selections, this might not be
|
|
very useful
|
|
*/
|
|
virtual void deleteKeyPressed (int lastRowSelected);
|
|
|
|
/** Override this to be informed when the return key is pressed.
|
|
|
|
If no rows are selected when they press the key, this won't be called.
|
|
|
|
@param lastRowSelected the last row that had been selected when they pressed the
|
|
key - if there are multiple selections, this might not be
|
|
very useful
|
|
*/
|
|
virtual void returnKeyPressed (int lastRowSelected);
|
|
|
|
/** Override this to be informed when the list is scrolled.
|
|
|
|
This might be caused by the user moving the scrollbar, or by programmatic changes
|
|
to the list position.
|
|
*/
|
|
virtual void listWasScrolled();
|
|
|
|
/** To allow rows from your list to be dragged-and-dropped, implement this method.
|
|
|
|
If this returns a non-null variant then when the user drags a row, the listbox will
|
|
try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger
|
|
a drag-and-drop operation, using this string as the source description, with the listbox
|
|
itself as the source component.
|
|
|
|
@see DragAndDropContainer::startDragging
|
|
*/
|
|
virtual const var getDragSourceDescription (const SparseSet<int>& currentlySelectedRows);
|
|
|
|
/** You can override this to provide tool tips for specific rows.
|
|
@see TooltipClient
|
|
*/
|
|
virtual const String getTooltipForRow (int row);
|
|
};
|
|
|
|
/**
|
|
A list of items that can be scrolled vertically.
|
|
|
|
To create a list, you'll need to create a subclass of ListBoxModel. This can
|
|
either paint each row of the list and respond to events via callbacks, or for
|
|
more specialised tasks, it can supply a custom component to fill each row.
|
|
|
|
@see ComboBox, TableListBox
|
|
*/
|
|
class JUCE_API ListBox : public Component,
|
|
public SettableTooltipClient
|
|
{
|
|
public:
|
|
|
|
/** Creates a ListBox.
|
|
|
|
The model pointer passed-in can be null, in which case you can set it later
|
|
with setModel().
|
|
*/
|
|
ListBox (const String& componentName = String::empty,
|
|
ListBoxModel* model = 0);
|
|
|
|
/** Destructor. */
|
|
~ListBox();
|
|
|
|
/** Changes the current data model to display. */
|
|
void setModel (ListBoxModel* newModel);
|
|
|
|
/** Returns the current list model. */
|
|
ListBoxModel* getModel() const noexcept { return model; }
|
|
|
|
/** Causes the list to refresh its content.
|
|
|
|
Call this when the number of rows in the list changes, or if you want it
|
|
to call refreshComponentForRow() on all the row components.
|
|
|
|
This must only be called from the main message thread.
|
|
*/
|
|
void updateContent();
|
|
|
|
/** Turns on multiple-selection of rows.
|
|
|
|
By default this is disabled.
|
|
|
|
When your row component gets clicked you'll need to call the
|
|
selectRowsBasedOnModifierKeys() method to tell the list that it's been
|
|
clicked and to get it to do the appropriate selection based on whether
|
|
the ctrl/shift keys are held down.
|
|
*/
|
|
void setMultipleSelectionEnabled (bool shouldBeEnabled);
|
|
|
|
/** Makes the list react to mouse moves by selecting the row that the mouse if over.
|
|
|
|
This function is here primarily for the ComboBox class to use, but might be
|
|
useful for some other purpose too.
|
|
*/
|
|
void setMouseMoveSelectsRows (bool shouldSelect);
|
|
|
|
/** Selects a row.
|
|
|
|
If the row is already selected, this won't do anything.
|
|
|
|
@param rowNumber the row to select
|
|
@param dontScrollToShowThisRow if true, the list's position won't change; if false and
|
|
the selected row is off-screen, it'll scroll to make
|
|
sure that row is on-screen
|
|
@param deselectOthersFirst if true and there are multiple selections, these will
|
|
first be deselected before this item is selected
|
|
@see isRowSelected, selectRowsBasedOnModifierKeys, flipRowSelection, deselectRow,
|
|
deselectAllRows, selectRangeOfRows
|
|
*/
|
|
void selectRow (int rowNumber,
|
|
bool dontScrollToShowThisRow = false,
|
|
bool deselectOthersFirst = true);
|
|
|
|
/** Selects a set of rows.
|
|
|
|
This will add these rows to the current selection, so you might need to
|
|
clear the current selection first with deselectAllRows()
|
|
|
|
@param firstRow the first row to select (inclusive)
|
|
@param lastRow the last row to select (inclusive)
|
|
*/
|
|
void selectRangeOfRows (int firstRow,
|
|
int lastRow);
|
|
|
|
/** Deselects a row.
|
|
|
|
If it's not currently selected, this will do nothing.
|
|
|
|
@see selectRow, deselectAllRows
|
|
*/
|
|
void deselectRow (int rowNumber);
|
|
|
|
/** Deselects any currently selected rows.
|
|
|
|
@see deselectRow
|
|
*/
|
|
void deselectAllRows();
|
|
|
|
/** Selects or deselects a row.
|
|
|
|
If the row's currently selected, this deselects it, and vice-versa.
|
|
*/
|
|
void flipRowSelection (int rowNumber);
|
|
|
|
/** Returns a sparse set indicating the rows that are currently selected.
|
|
|
|
@see setSelectedRows
|
|
*/
|
|
const SparseSet<int> getSelectedRows() const;
|
|
|
|
/** Sets the rows that should be selected, based on an explicit set of ranges.
|
|
|
|
If sendNotificationEventToModel is true, the ListBoxModel::selectedRowsChanged()
|
|
method will be called. If it's false, no notification will be sent to the model.
|
|
|
|
@see getSelectedRows
|
|
*/
|
|
void setSelectedRows (const SparseSet<int>& setOfRowsToBeSelected,
|
|
bool sendNotificationEventToModel = true);
|
|
|
|
/** Checks whether a row is selected.
|
|
*/
|
|
bool isRowSelected (int rowNumber) const;
|
|
|
|
/** Returns the number of rows that are currently selected.
|
|
|
|
@see getSelectedRow, isRowSelected, getLastRowSelected
|
|
*/
|
|
int getNumSelectedRows() const;
|
|
|
|
/** Returns the row number of a selected row.
|
|
|
|
This will return the row number of the Nth selected row. The row numbers returned will
|
|
be sorted in order from low to high.
|
|
|
|
@param index the index of the selected row to return, (from 0 to getNumSelectedRows() - 1)
|
|
@returns the row number, or -1 if the index was out of range or if there aren't any rows
|
|
selected
|
|
@see getNumSelectedRows, isRowSelected, getLastRowSelected
|
|
*/
|
|
int getSelectedRow (int index = 0) const;
|
|
|
|
/** Returns the last row that the user selected.
|
|
|
|
This isn't the same as the highest row number that is currently selected - if the user
|
|
had multiply-selected rows 10, 5 and then 6 in that order, this would return 6.
|
|
|
|
If nothing is selected, it will return -1.
|
|
*/
|
|
int getLastRowSelected() const;
|
|
|
|
/** Multiply-selects rows based on the modifier keys.
|
|
|
|
If no modifier keys are down, this will select the given row and
|
|
deselect any others.
|
|
|
|
If the ctrl (or command on the Mac) key is down, it'll flip the
|
|
state of the selected row.
|
|
|
|
If the shift key is down, it'll select up to the given row from the
|
|
last row selected.
|
|
|
|
@see selectRow
|
|
*/
|
|
void selectRowsBasedOnModifierKeys (int rowThatWasClickedOn,
|
|
const ModifierKeys& modifiers,
|
|
bool isMouseUpEvent);
|
|
|
|
/** Scrolls the list to a particular position.
|
|
|
|
The proportion is between 0 and 1.0, so 0 scrolls to the top of the list,
|
|
1.0 scrolls to the bottom.
|
|
|
|
If the total number of rows all fit onto the screen at once, then this
|
|
method won't do anything.
|
|
|
|
@see getVerticalPosition
|
|
*/
|
|
void setVerticalPosition (double newProportion);
|
|
|
|
/** Returns the current vertical position as a proportion of the total.
|
|
|
|
This can be used in conjunction with setVerticalPosition() to save and restore
|
|
the list's position. It returns a value in the range 0 to 1.
|
|
|
|
@see setVerticalPosition
|
|
*/
|
|
double getVerticalPosition() const;
|
|
|
|
/** Scrolls if necessary to make sure that a particular row is visible.
|
|
*/
|
|
void scrollToEnsureRowIsOnscreen (int row);
|
|
|
|
/** Returns a pointer to the scrollbar.
|
|
|
|
(Unlikely to be useful for most people).
|
|
*/
|
|
ScrollBar* getVerticalScrollBar() const noexcept;
|
|
|
|
/** Returns a pointer to the scrollbar.
|
|
|
|
(Unlikely to be useful for most people).
|
|
*/
|
|
ScrollBar* getHorizontalScrollBar() const noexcept;
|
|
|
|
/** Finds the row index that contains a given x,y position.
|
|
|
|
The position is relative to the ListBox's top-left.
|
|
|
|
If no row exists at this position, the method will return -1.
|
|
|
|
@see getComponentForRowNumber
|
|
*/
|
|
int getRowContainingPosition (int x, int y) const noexcept;
|
|
|
|
/** Finds a row index that would be the most suitable place to insert a new
|
|
item for a given position.
|
|
|
|
This is useful when the user is e.g. dragging and dropping onto the listbox,
|
|
because it lets you easily choose the best position to insert the item that
|
|
they drop, based on where they drop it.
|
|
|
|
If the position is out of range, this will return -1. If the position is
|
|
beyond the end of the list, it will return getNumRows() to indicate the end
|
|
of the list.
|
|
|
|
@see getComponentForRowNumber
|
|
*/
|
|
int getInsertionIndexForPosition (int x, int y) const noexcept;
|
|
|
|
/** Returns the position of one of the rows, relative to the top-left of
|
|
the listbox.
|
|
|
|
This may be off-screen, and the range of the row number that is passed-in is
|
|
not checked to see if it's a valid row.
|
|
*/
|
|
const Rectangle<int> getRowPosition (int rowNumber,
|
|
bool relativeToComponentTopLeft) const noexcept;
|
|
|
|
/** Finds the row component for a given row in the list.
|
|
|
|
The component returned will have been created using createRowComponent().
|
|
|
|
If the component for this row is off-screen or if the row is out-of-range,
|
|
this will return 0.
|
|
|
|
@see getRowContainingPosition
|
|
*/
|
|
Component* getComponentForRowNumber (int rowNumber) const noexcept;
|
|
|
|
/** Returns the row number that the given component represents.
|
|
|
|
If the component isn't one of the list's rows, this will return -1.
|
|
*/
|
|
int getRowNumberOfComponent (Component* rowComponent) const noexcept;
|
|
|
|
/** Returns the width of a row (which may be less than the width of this component
|
|
if there's a scrollbar).
|
|
*/
|
|
int getVisibleRowWidth() const noexcept;
|
|
|
|
/** Sets the height of each row in the list.
|
|
|
|
The default height is 22 pixels.
|
|
|
|
@see getRowHeight
|
|
*/
|
|
void setRowHeight (int newHeight);
|
|
|
|
/** Returns the height of a row in the list.
|
|
|
|
@see setRowHeight
|
|
*/
|
|
int getRowHeight() const noexcept { return rowHeight; }
|
|
|
|
/** Returns the number of rows actually visible.
|
|
|
|
This is the number of whole rows which will fit on-screen, so the value might
|
|
be more than the actual number of rows in the list.
|
|
*/
|
|
int getNumRowsOnScreen() const noexcept;
|
|
|
|
/** 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.
|
|
|
|
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
|
*/
|
|
enum ColourIds
|
|
{
|
|
backgroundColourId = 0x1002800, /**< The background colour to fill the list with.
|
|
Make this transparent if you don't want the background to be filled. */
|
|
outlineColourId = 0x1002810, /**< An optional colour to use to draw a border around the list.
|
|
Make this transparent to not have an outline. */
|
|
textColourId = 0x1002820 /**< The preferred colour to use for drawing text in the listbox. */
|
|
};
|
|
|
|
/** Sets the thickness of a border that will be drawn around the box.
|
|
|
|
To set the colour of the outline, use @code setColour (ListBox::outlineColourId, colourXYZ); @endcode
|
|
@see outlineColourId
|
|
*/
|
|
void setOutlineThickness (int outlineThickness);
|
|
|
|
/** Returns the thickness of outline that will be drawn around the listbox.
|
|
|
|
@see setOutlineColour
|
|
*/
|
|
int getOutlineThickness() const noexcept { return outlineThickness; }
|
|
|
|
/** Sets a component that the list should use as a header.
|
|
|
|
This will position the given component at the top of the list, maintaining the
|
|
height of the component passed-in, but rescaling it horizontally to match the
|
|
width of the items in the listbox.
|
|
|
|
The component will be deleted when setHeaderComponent() is called with a
|
|
different component, or when the listbox is deleted.
|
|
*/
|
|
void setHeaderComponent (Component* newHeaderComponent);
|
|
|
|
/** Changes the width of the rows in the list.
|
|
|
|
This can be used to make the list's row components wider than the list itself - the
|
|
width of the rows will be either the width of the list or this value, whichever is
|
|
greater, and if the rows become wider than the list, a horizontal scrollbar will
|
|
appear.
|
|
|
|
The default value for this is 0, which means that the rows will always
|
|
be the same width as the list.
|
|
*/
|
|
void setMinimumContentWidth (int newMinimumWidth);
|
|
|
|
/** Returns the space currently available for the row items, taking into account
|
|
borders, scrollbars, etc.
|
|
*/
|
|
int getVisibleContentWidth() const noexcept;
|
|
|
|
/** Repaints one of the rows.
|
|
|
|
This is a lightweight alternative to calling updateContent, and just causes a
|
|
repaint of the row's area.
|
|
*/
|
|
void repaintRow (int rowNumber) noexcept;
|
|
|
|
/** This fairly obscure method creates an image that just shows the currently
|
|
selected row components.
|
|
|
|
It's a handy method for doing drag-and-drop, as it can be passed to the
|
|
DragAndDropContainer for use as the drag image.
|
|
|
|
Note that it will make the row components temporarily invisible, so if you're
|
|
using custom components this could affect them if they're sensitive to that
|
|
sort of thing.
|
|
|
|
@see Component::createComponentSnapshot
|
|
*/
|
|
virtual const Image createSnapshotOfSelectedRows (int& x, int& y);
|
|
|
|
/** Returns the viewport that this ListBox uses.
|
|
|
|
You may need to use this to change parameters such as whether scrollbars
|
|
are shown, etc.
|
|
*/
|
|
Viewport* getViewport() const noexcept;
|
|
|
|
/** @internal */
|
|
bool keyPressed (const KeyPress& key);
|
|
/** @internal */
|
|
bool keyStateChanged (bool isKeyDown);
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void paintOverChildren (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void visibilityChanged();
|
|
/** @internal */
|
|
void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY);
|
|
/** @internal */
|
|
void mouseMove (const MouseEvent&);
|
|
/** @internal */
|
|
void mouseExit (const MouseEvent&);
|
|
/** @internal */
|
|
void mouseUp (const MouseEvent&);
|
|
/** @internal */
|
|
void colourChanged();
|
|
/** @internal */
|
|
void startDragAndDrop (const MouseEvent& e, const var& dragDescription, bool allowDraggingToOtherWindows = true);
|
|
|
|
private:
|
|
|
|
friend class ListViewport;
|
|
friend class TableListBox;
|
|
ListBoxModel* model;
|
|
ScopedPointer<ListViewport> viewport;
|
|
ScopedPointer<Component> headerComponent;
|
|
int totalItems, rowHeight, minimumRowWidth;
|
|
int outlineThickness;
|
|
int lastRowSelected;
|
|
bool mouseMoveSelects, multipleSelection, hasDoneInitialUpdate;
|
|
SparseSet <int> selected;
|
|
|
|
void selectRowInternal (int rowNumber,
|
|
bool dontScrollToShowThisRow,
|
|
bool deselectOthersFirst,
|
|
bool isMouseClick);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ListBox);
|
|
};
|
|
|
|
#endif // __JUCE_LISTBOX_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ListBox.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_TextButton.h ***/
|
|
#ifndef __JUCE_TEXTBUTTON_JUCEHEADER__
|
|
#define __JUCE_TEXTBUTTON_JUCEHEADER__
|
|
|
|
/**
|
|
A button that uses the standard lozenge-shaped background with a line of
|
|
text on it.
|
|
|
|
@see Button, DrawableButton
|
|
*/
|
|
class JUCE_API TextButton : public Button
|
|
{
|
|
public:
|
|
|
|
/** Creates a TextButton.
|
|
|
|
@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)
|
|
@param toolTip an optional string to use as a toolip
|
|
|
|
@see Button
|
|
*/
|
|
TextButton (const String& buttonName = String::empty,
|
|
const String& toolTip = String::empty);
|
|
|
|
/** Destructor. */
|
|
~TextButton();
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the button.
|
|
|
|
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
|
|
{
|
|
buttonColourId = 0x1000100, /**< The colour used to fill the button shape (when the button is toggled
|
|
'off'). The look-and-feel class might re-interpret this to add
|
|
effects, etc. */
|
|
buttonOnColourId = 0x1000101, /**< The colour used to fill the button shape (when the button is toggled
|
|
'on'). The look-and-feel class might re-interpret this to add
|
|
effects, etc. */
|
|
textColourOffId = 0x1000102, /**< The colour to use for the button's text when the button's toggle state is "off". */
|
|
textColourOnId = 0x1000103 /**< The colour to use for the button's text.when the button's toggle state is "on". */
|
|
};
|
|
|
|
/** Resizes the button to fit neatly around its current text.
|
|
|
|
If newHeight is >= 0, the button's height will be changed to this
|
|
value. If it's less than zero, its height will be unaffected.
|
|
*/
|
|
void changeWidthToFitText (int newHeight = -1);
|
|
|
|
/** This can be overridden to use different fonts than the default one.
|
|
|
|
Note that you'll need to set the font's size appropriately, too.
|
|
*/
|
|
virtual const Font getFont();
|
|
|
|
protected:
|
|
/** @internal */
|
|
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown);
|
|
/** @internal */
|
|
void colourChanged();
|
|
|
|
private:
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextButton);
|
|
};
|
|
|
|
#endif // __JUCE_TEXTBUTTON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TextButton.h ***/
|
|
|
|
/**
|
|
A component displaying a list of plugins, with options to scan for them,
|
|
add, remove and sort them.
|
|
*/
|
|
class JUCE_API PluginListComponent : public Component,
|
|
public ListBoxModel,
|
|
public ChangeListener,
|
|
public ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
public Timer
|
|
{
|
|
public:
|
|
|
|
/**
|
|
Creates the list component.
|
|
|
|
For info about the deadMansPedalFile, see the PluginDirectoryScanner constructor.
|
|
|
|
The properties file, if supplied, is used to store the user's last search paths.
|
|
*/
|
|
PluginListComponent (KnownPluginList& listToRepresent,
|
|
const File& deadMansPedalFile,
|
|
PropertiesFile* propertiesToUse);
|
|
|
|
/** Destructor. */
|
|
~PluginListComponent();
|
|
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
bool isInterestedInFileDrag (const StringArray& files);
|
|
/** @internal */
|
|
void filesDropped (const StringArray& files, int, int);
|
|
/** @internal */
|
|
int getNumRows();
|
|
/** @internal */
|
|
void paintListBoxItem (int row, Graphics& g, int width, int height, bool rowIsSelected);
|
|
/** @internal */
|
|
void deleteKeyPressed (int lastRowSelected);
|
|
/** @internal */
|
|
void buttonClicked (Button* b);
|
|
/** @internal */
|
|
void changeListenerCallback (ChangeBroadcaster*);
|
|
/** @internal */
|
|
void timerCallback();
|
|
|
|
private:
|
|
|
|
KnownPluginList& list;
|
|
File deadMansPedalFile;
|
|
ListBox listBox;
|
|
TextButton optionsButton;
|
|
PropertiesFile* propertiesToUse;
|
|
int typeToScan;
|
|
|
|
void scanFor (AudioPluginFormat* format);
|
|
static void optionsMenuStaticCallback (int result, PluginListComponent*);
|
|
void optionsMenuCallback (int result);
|
|
void updateList();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PluginListComponent);
|
|
};
|
|
|
|
#endif // __JUCE_PLUGINLISTCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_PluginListComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPLAYHEAD_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPROCESSOR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPROCESSOREDITOR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_AudioProcessorGraph.h ***/
|
|
#ifndef __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__
|
|
#define __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__
|
|
|
|
/**
|
|
A type of AudioProcessor which plays back a graph of other AudioProcessors.
|
|
|
|
Use one of these objects if you want to wire-up a set of AudioProcessors
|
|
and play back the result.
|
|
|
|
Processors can be added to the graph as "nodes" using addNode(), and once
|
|
added, you can connect any of their input or output channels to other
|
|
nodes using addConnection().
|
|
|
|
To play back a graph through an audio device, you might want to use an
|
|
AudioProcessorPlayer object.
|
|
*/
|
|
class JUCE_API AudioProcessorGraph : public AudioProcessor,
|
|
public AsyncUpdater
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty graph.
|
|
*/
|
|
AudioProcessorGraph();
|
|
|
|
/** Destructor.
|
|
Any processor objects that have been added to the graph will also be deleted.
|
|
*/
|
|
~AudioProcessorGraph();
|
|
|
|
/** Represents one of the nodes, or processors, in an AudioProcessorGraph.
|
|
|
|
To create a node, call AudioProcessorGraph::addNode().
|
|
*/
|
|
class JUCE_API Node : public ReferenceCountedObject
|
|
{
|
|
public:
|
|
|
|
/** The ID number assigned to this node.
|
|
This is assigned by the graph that owns it, and can't be changed.
|
|
*/
|
|
const uint32 nodeId;
|
|
|
|
/** The actual processor object that this node represents. */
|
|
AudioProcessor* getProcessor() const noexcept { return processor; }
|
|
|
|
/** A set of user-definable properties that are associated with this node.
|
|
|
|
This can be used to attach values to the node for whatever purpose seems
|
|
useful. For example, you might store an x and y position if your application
|
|
is displaying the nodes on-screen.
|
|
*/
|
|
NamedValueSet properties;
|
|
|
|
/** A convenient typedef for referring to a pointer to a node object.
|
|
*/
|
|
typedef ReferenceCountedObjectPtr <Node> Ptr;
|
|
|
|
private:
|
|
|
|
friend class AudioProcessorGraph;
|
|
|
|
const ScopedPointer<AudioProcessor> processor;
|
|
bool isPrepared;
|
|
|
|
Node (uint32 nodeId, AudioProcessor* processor) noexcept;
|
|
|
|
void prepare (double sampleRate, int blockSize, AudioProcessorGraph* graph);
|
|
void unprepare();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Node);
|
|
};
|
|
|
|
/** Represents a connection between two channels of two nodes in an AudioProcessorGraph.
|
|
|
|
To create a connection, use AudioProcessorGraph::addConnection().
|
|
*/
|
|
struct JUCE_API Connection
|
|
{
|
|
public:
|
|
|
|
Connection (uint32 sourceNodeId, int sourceChannelIndex,
|
|
uint32 destNodeId, int destChannelIndex) noexcept;
|
|
|
|
/** The ID number of the node which is the input source for this connection.
|
|
@see AudioProcessorGraph::getNodeForId
|
|
*/
|
|
uint32 sourceNodeId;
|
|
|
|
/** The index of the output channel of the source node from which this
|
|
connection takes its data.
|
|
|
|
If this value is the special number AudioProcessorGraph::midiChannelIndex, then
|
|
it is referring to the source node's midi output. Otherwise, it is the zero-based
|
|
index of an audio output channel in the source node.
|
|
*/
|
|
int sourceChannelIndex;
|
|
|
|
/** The ID number of the node which is the destination for this connection.
|
|
@see AudioProcessorGraph::getNodeForId
|
|
*/
|
|
uint32 destNodeId;
|
|
|
|
/** The index of the input channel of the destination node to which this
|
|
connection delivers its data.
|
|
|
|
If this value is the special number AudioProcessorGraph::midiChannelIndex, then
|
|
it is referring to the destination node's midi input. Otherwise, it is the zero-based
|
|
index of an audio input channel in the destination node.
|
|
*/
|
|
int destChannelIndex;
|
|
|
|
private:
|
|
|
|
JUCE_LEAK_DETECTOR (Connection);
|
|
};
|
|
|
|
/** Deletes all nodes and connections from this graph.
|
|
|
|
Any processor objects in the graph will be deleted.
|
|
*/
|
|
void clear();
|
|
|
|
/** Returns the number of nodes in the graph. */
|
|
int getNumNodes() const { return nodes.size(); }
|
|
|
|
/** Returns a pointer to one of the nodes in the graph.
|
|
|
|
This will return 0 if the index is out of range.
|
|
@see getNodeForId
|
|
*/
|
|
Node* getNode (const int index) const { return nodes [index]; }
|
|
|
|
/** Searches the graph for a node with the given ID number and returns it.
|
|
|
|
If no such node was found, this returns 0.
|
|
@see getNode
|
|
*/
|
|
Node* getNodeForId (const uint32 nodeId) const;
|
|
|
|
/** Adds a node to the graph.
|
|
|
|
This creates a new node in the graph, for the specified processor. Once you have
|
|
added a processor to the graph, the graph owns it and will delete it later when
|
|
it is no longer needed.
|
|
|
|
The optional nodeId parameter lets you specify an ID to use for the node, but
|
|
if the value is already in use, this new node will overwrite the old one.
|
|
|
|
If this succeeds, it returns a pointer to the newly-created node.
|
|
*/
|
|
Node* addNode (AudioProcessor* newProcessor, uint32 nodeId = 0);
|
|
|
|
/** Deletes a node within the graph which has the specified ID.
|
|
|
|
This will also delete any connections that are attached to this node.
|
|
*/
|
|
bool removeNode (uint32 nodeId);
|
|
|
|
/** Returns the number of connections in the graph. */
|
|
int getNumConnections() const { return connections.size(); }
|
|
|
|
/** Returns a pointer to one of the connections in the graph. */
|
|
const Connection* getConnection (int index) const { return connections [index]; }
|
|
|
|
/** Searches for a connection between some specified channels.
|
|
|
|
If no such connection is found, this returns 0.
|
|
*/
|
|
const Connection* getConnectionBetween (uint32 sourceNodeId,
|
|
int sourceChannelIndex,
|
|
uint32 destNodeId,
|
|
int destChannelIndex) const;
|
|
|
|
/** Returns true if there is a connection between any of the channels of
|
|
two specified nodes.
|
|
*/
|
|
bool isConnected (uint32 possibleSourceNodeId,
|
|
uint32 possibleDestNodeId) const;
|
|
|
|
/** Returns true if it would be legal to connect the specified points.
|
|
*/
|
|
bool canConnect (uint32 sourceNodeId, int sourceChannelIndex,
|
|
uint32 destNodeId, int destChannelIndex) const;
|
|
|
|
/** Attempts to connect two specified channels of two nodes.
|
|
|
|
If this isn't allowed (e.g. because you're trying to connect a midi channel
|
|
to an audio one or other such nonsense), then it'll return false.
|
|
*/
|
|
bool addConnection (uint32 sourceNodeId, int sourceChannelIndex,
|
|
uint32 destNodeId, int destChannelIndex);
|
|
|
|
/** Deletes the connection with the specified index.
|
|
|
|
Returns true if a connection was actually deleted.
|
|
*/
|
|
void removeConnection (int index);
|
|
|
|
/** Deletes any connection between two specified points.
|
|
|
|
Returns true if a connection was actually deleted.
|
|
*/
|
|
bool removeConnection (uint32 sourceNodeId, int sourceChannelIndex,
|
|
uint32 destNodeId, int destChannelIndex);
|
|
|
|
/** Removes all connections from the specified node.
|
|
*/
|
|
bool disconnectNode (uint32 nodeId);
|
|
|
|
/** Performs a sanity checks of all the connections.
|
|
|
|
This might be useful if some of the processors are doing things like changing
|
|
their channel counts, which could render some connections obsolete.
|
|
*/
|
|
bool removeIllegalConnections();
|
|
|
|
/** A special number that represents the midi channel of a node.
|
|
|
|
This is used as a channel index value if you want to refer to the midi input
|
|
or output instead of an audio channel.
|
|
*/
|
|
static const int midiChannelIndex;
|
|
|
|
/** A special type of AudioProcessor that can live inside an AudioProcessorGraph
|
|
in order to use the audio that comes into and out of the graph itself.
|
|
|
|
If you create an AudioGraphIOProcessor in "input" mode, it will act as a
|
|
node in the graph which delivers the audio that is coming into the parent
|
|
graph. This allows you to stream the data to other nodes and process the
|
|
incoming audio.
|
|
|
|
Likewise, one of these in "output" mode can be sent data which it will add to
|
|
the sum of data being sent to the graph's output.
|
|
|
|
@see AudioProcessorGraph
|
|
*/
|
|
class JUCE_API AudioGraphIOProcessor : public AudioPluginInstance
|
|
{
|
|
public:
|
|
/** Specifies the mode in which this processor will operate.
|
|
*/
|
|
enum IODeviceType
|
|
{
|
|
audioInputNode, /**< In this mode, the processor has output channels
|
|
representing all the audio input channels that are
|
|
coming into its parent audio graph. */
|
|
audioOutputNode, /**< In this mode, the processor has input channels
|
|
representing all the audio output channels that are
|
|
going out of its parent audio graph. */
|
|
midiInputNode, /**< In this mode, the processor has a midi output which
|
|
delivers the same midi data that is arriving at its
|
|
parent graph. */
|
|
midiOutputNode /**< In this mode, the processor has a midi input and
|
|
any data sent to it will be passed out of the parent
|
|
graph. */
|
|
};
|
|
|
|
/** Returns the mode of this processor. */
|
|
IODeviceType getType() const { return type; }
|
|
|
|
/** Returns the parent graph to which this processor belongs, or 0 if it
|
|
hasn't yet been added to one. */
|
|
AudioProcessorGraph* getParentGraph() const { return graph; }
|
|
|
|
/** True if this is an audio or midi input. */
|
|
bool isInput() const;
|
|
/** True if this is an audio or midi output. */
|
|
bool isOutput() const;
|
|
|
|
AudioGraphIOProcessor (const IODeviceType type);
|
|
~AudioGraphIOProcessor();
|
|
|
|
const String getName() const;
|
|
void fillInPluginDescription (PluginDescription& d) const;
|
|
|
|
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock);
|
|
void releaseResources();
|
|
void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages);
|
|
|
|
const String getInputChannelName (int channelIndex) const;
|
|
const String getOutputChannelName (int channelIndex) const;
|
|
bool isInputChannelStereoPair (int index) const;
|
|
bool isOutputChannelStereoPair (int index) const;
|
|
bool acceptsMidi() const;
|
|
bool producesMidi() const;
|
|
|
|
bool hasEditor() const;
|
|
AudioProcessorEditor* createEditor();
|
|
|
|
int getNumParameters();
|
|
const String getParameterName (int);
|
|
float getParameter (int);
|
|
const String getParameterText (int);
|
|
void setParameter (int, float);
|
|
|
|
int getNumPrograms();
|
|
int getCurrentProgram();
|
|
void setCurrentProgram (int);
|
|
const String getProgramName (int);
|
|
void changeProgramName (int, const String&);
|
|
|
|
void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData);
|
|
void setStateInformation (const void* data, int sizeInBytes);
|
|
|
|
/** @internal */
|
|
void setParentGraph (AudioProcessorGraph* graph);
|
|
|
|
private:
|
|
const IODeviceType type;
|
|
AudioProcessorGraph* graph;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioGraphIOProcessor);
|
|
};
|
|
|
|
// AudioProcessor methods:
|
|
|
|
const String getName() const;
|
|
|
|
void prepareToPlay (double sampleRate, int estimatedSamplesPerBlock);
|
|
void releaseResources();
|
|
void processBlock (AudioSampleBuffer& buffer, MidiBuffer& midiMessages);
|
|
|
|
const String getInputChannelName (int channelIndex) const;
|
|
const String getOutputChannelName (int channelIndex) const;
|
|
bool isInputChannelStereoPair (int index) const;
|
|
bool isOutputChannelStereoPair (int index) const;
|
|
|
|
bool acceptsMidi() const;
|
|
bool producesMidi() const;
|
|
|
|
bool hasEditor() const { return false; }
|
|
AudioProcessorEditor* createEditor() { return nullptr; }
|
|
|
|
int getNumParameters() { return 0; }
|
|
const String getParameterName (int) { return String::empty; }
|
|
float getParameter (int) { return 0; }
|
|
const String getParameterText (int) { return String::empty; }
|
|
void setParameter (int, float) { }
|
|
|
|
int getNumPrograms() { return 0; }
|
|
int getCurrentProgram() { return 0; }
|
|
void setCurrentProgram (int) { }
|
|
const String getProgramName (int) { return String::empty; }
|
|
void changeProgramName (int, const String&) { }
|
|
|
|
void getStateInformation (JUCE_NAMESPACE::MemoryBlock& destData);
|
|
void setStateInformation (const void* data, int sizeInBytes);
|
|
|
|
/** @internal */
|
|
void handleAsyncUpdate();
|
|
|
|
private:
|
|
|
|
ReferenceCountedArray <Node> nodes;
|
|
OwnedArray <Connection> connections;
|
|
uint32 lastNodeId;
|
|
AudioSampleBuffer renderingBuffers;
|
|
OwnedArray <MidiBuffer> midiBuffers;
|
|
|
|
CriticalSection renderLock;
|
|
Array<void*> renderingOps;
|
|
|
|
friend class AudioGraphIOProcessor;
|
|
AudioSampleBuffer* currentAudioInputBuffer;
|
|
AudioSampleBuffer currentAudioOutputBuffer;
|
|
MidiBuffer* currentMidiInputBuffer;
|
|
MidiBuffer currentMidiOutputBuffer;
|
|
|
|
void clearRenderingSequence();
|
|
void buildRenderingSequence();
|
|
|
|
bool isAnInputTo (uint32 possibleInputId, uint32 possibleDestinationId, int recursionCheck) const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorGraph);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPROCESSORGRAPH_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioProcessorGraph.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPROCESSORLISTENER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_AudioProcessorPlayer.h ***/
|
|
#ifndef __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__
|
|
#define __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__
|
|
|
|
/**
|
|
An AudioIODeviceCallback object which streams audio through an AudioProcessor.
|
|
|
|
To use one of these, just make it the callback used by your AudioIODevice, and
|
|
give it a processor to use by calling setProcessor().
|
|
|
|
It's also a MidiInputCallback, so you can connect it to both an audio and midi
|
|
input to send both streams through the processor.
|
|
|
|
@see AudioProcessor, AudioProcessorGraph
|
|
*/
|
|
class JUCE_API AudioProcessorPlayer : public AudioIODeviceCallback,
|
|
public MidiInputCallback
|
|
{
|
|
public:
|
|
|
|
/**
|
|
*/
|
|
AudioProcessorPlayer();
|
|
|
|
/** Destructor. */
|
|
virtual ~AudioProcessorPlayer();
|
|
|
|
/** Sets the processor that should be played.
|
|
|
|
The processor that is passed in will not be deleted or owned by this object.
|
|
To stop anything playing, pass in 0 to this method.
|
|
*/
|
|
void setProcessor (AudioProcessor* processorToPlay);
|
|
|
|
/** Returns the current audio processor that is being played.
|
|
*/
|
|
AudioProcessor* getCurrentProcessor() const { return processor; }
|
|
|
|
/** Returns a midi message collector that you can pass midi messages to if you
|
|
want them to be injected into the midi stream that is being sent to the
|
|
processor.
|
|
*/
|
|
MidiMessageCollector& getMidiMessageCollector() { return messageCollector; }
|
|
|
|
/** @internal */
|
|
void audioDeviceIOCallback (const float** inputChannelData,
|
|
int totalNumInputChannels,
|
|
float** outputChannelData,
|
|
int totalNumOutputChannels,
|
|
int numSamples);
|
|
/** @internal */
|
|
void audioDeviceAboutToStart (AudioIODevice* device);
|
|
/** @internal */
|
|
void audioDeviceStopped();
|
|
/** @internal */
|
|
void handleIncomingMidiMessage (MidiInput* source, const MidiMessage& message);
|
|
|
|
private:
|
|
|
|
AudioProcessor* processor;
|
|
CriticalSection lock;
|
|
double sampleRate;
|
|
int blockSize;
|
|
bool isPrepared;
|
|
|
|
int numInputChans, numOutputChans;
|
|
float* channels [128];
|
|
AudioSampleBuffer tempBuffer;
|
|
|
|
MidiBuffer incomingMidi;
|
|
MidiMessageCollector messageCollector;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioProcessorPlayer);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIOPROCESSORPLAYER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioProcessorPlayer.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_GenericAudioProcessorEditor.h ***/
|
|
#ifndef __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__
|
|
#define __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_PropertyPanel.h ***/
|
|
#ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__
|
|
#define __JUCE_PROPERTYPANEL_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_PropertyComponent.h ***/
|
|
#ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_PROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
class EditableProperty;
|
|
|
|
/**
|
|
A base class for a component that goes in a PropertyPanel and displays one of
|
|
an item's properties.
|
|
|
|
Subclasses of this are used to display a property in various forms, e.g. a
|
|
ChoicePropertyComponent shows its value as a combo box; a SliderPropertyComponent
|
|
shows its value as a slider; a TextPropertyComponent as a text box, etc.
|
|
|
|
A subclass must implement the refresh() method which will be called to tell the
|
|
component to update itself, and is also responsible for calling this it when the
|
|
item that it refers to is changed.
|
|
|
|
@see PropertyPanel, TextPropertyComponent, SliderPropertyComponent,
|
|
ChoicePropertyComponent, ButtonPropertyComponent, BooleanPropertyComponent
|
|
*/
|
|
class JUCE_API PropertyComponent : public Component,
|
|
public SettableTooltipClient
|
|
{
|
|
public:
|
|
|
|
/** Creates a PropertyComponent.
|
|
|
|
@param propertyName the name is stored as this component's name, and is
|
|
used as the name displayed next to this component in
|
|
a property panel
|
|
@param preferredHeight the height that the component should be given - some
|
|
items may need to be larger than a normal row height.
|
|
This value can also be set if a subclass changes the
|
|
preferredHeight member variable.
|
|
*/
|
|
PropertyComponent (const String& propertyName,
|
|
int preferredHeight = 25);
|
|
|
|
/** Destructor. */
|
|
~PropertyComponent();
|
|
|
|
/** Returns this item's preferred height.
|
|
|
|
This value is specified either in the constructor or by a subclass changing the
|
|
preferredHeight member variable.
|
|
*/
|
|
int getPreferredHeight() const noexcept { return preferredHeight; }
|
|
|
|
void setPreferredHeight (int newHeight) noexcept { preferredHeight = newHeight; }
|
|
|
|
/** Updates the property component if the item it refers to has changed.
|
|
|
|
A subclass must implement this method, and other objects may call it to
|
|
force it to refresh itself.
|
|
|
|
The subclass should be economical in the amount of work is done, so for
|
|
example it should check whether it really needs to do a repaint rather than
|
|
just doing one every time this method is called, as it may be called when
|
|
the value being displayed hasn't actually changed.
|
|
*/
|
|
virtual void refresh() = 0;
|
|
|
|
/** The default paint method fills the background and draws a label for the
|
|
item's name.
|
|
|
|
@see LookAndFeel::drawPropertyComponentBackground(), LookAndFeel::drawPropertyComponentLabel()
|
|
*/
|
|
void paint (Graphics& g);
|
|
|
|
/** The default resize method positions any child component to the right of this
|
|
one, based on the look and feel's default label size.
|
|
*/
|
|
void resized();
|
|
|
|
/** By default, this just repaints the component. */
|
|
void enablementChanged();
|
|
|
|
protected:
|
|
/** Used by the PropertyPanel to determine how high this component needs to be.
|
|
A subclass can update this value in its constructor but shouldn't alter it later
|
|
as changes won't necessarily be picked up.
|
|
*/
|
|
int preferredHeight;
|
|
|
|
private:
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyComponent);
|
|
};
|
|
|
|
#endif // __JUCE_PROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_PropertyComponent.h ***/
|
|
|
|
/**
|
|
A panel that holds a list of PropertyComponent objects.
|
|
|
|
This panel displays a list of PropertyComponents, and allows them to be organised
|
|
into collapsible sections.
|
|
|
|
To use, simply create one of these and add your properties to it with addProperties()
|
|
or addSection().
|
|
|
|
@see PropertyComponent
|
|
*/
|
|
class JUCE_API PropertyPanel : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty property panel. */
|
|
PropertyPanel();
|
|
|
|
/** Destructor. */
|
|
~PropertyPanel();
|
|
|
|
/** Deletes all property components from the panel.
|
|
*/
|
|
void clear();
|
|
|
|
/** Adds a set of properties to the panel.
|
|
|
|
The components in the list will be owned by this object and will be automatically
|
|
deleted later on when no longer needed.
|
|
|
|
These properties are added without them being inside a named section. If you
|
|
want them to be kept together in a collapsible section, use addSection() instead.
|
|
*/
|
|
void addProperties (const Array <PropertyComponent*>& newPropertyComponents);
|
|
|
|
/** Adds a set of properties to the panel.
|
|
|
|
These properties are added at the bottom of the list, under a section heading with
|
|
a plus/minus button that allows it to be opened and closed.
|
|
|
|
The components in the list will be owned by this object and will be automatically
|
|
deleted later on when no longer needed.
|
|
|
|
To add properies without them being in a section, use addProperties().
|
|
*/
|
|
void addSection (const String& sectionTitle,
|
|
const Array <PropertyComponent*>& newPropertyComponents,
|
|
bool shouldSectionInitiallyBeOpen = true);
|
|
|
|
/** Calls the refresh() method of all PropertyComponents in the panel */
|
|
void refreshAll() const;
|
|
|
|
/** Returns a list of all the names of sections in the panel.
|
|
|
|
These are the sections that have been added with addSection().
|
|
*/
|
|
StringArray getSectionNames() const;
|
|
|
|
/** Returns true if the section at this index is currently open.
|
|
|
|
The index is from 0 up to the number of items returned by getSectionNames().
|
|
*/
|
|
bool isSectionOpen (int sectionIndex) const;
|
|
|
|
/** Opens or closes one of the sections.
|
|
|
|
The index is from 0 up to the number of items returned by getSectionNames().
|
|
*/
|
|
void setSectionOpen (int sectionIndex, bool shouldBeOpen);
|
|
|
|
/** Enables or disables one of the sections.
|
|
|
|
The index is from 0 up to the number of items returned by getSectionNames().
|
|
*/
|
|
void setSectionEnabled (int sectionIndex, bool shouldBeEnabled);
|
|
|
|
/** Saves the current state of open/closed sections so it can be restored later.
|
|
|
|
The caller is responsible for deleting the object that is returned.
|
|
|
|
To restore this state, use restoreOpennessState().
|
|
|
|
@see restoreOpennessState
|
|
*/
|
|
XmlElement* getOpennessState() const;
|
|
|
|
/** Restores a previously saved arrangement of open/closed sections.
|
|
|
|
This will try to restore a snapshot of the panel's state that was created by
|
|
the getOpennessState() method. If any of the sections named in the original
|
|
XML aren't present, they will be ignored.
|
|
|
|
@see getOpennessState
|
|
*/
|
|
void restoreOpennessState (const XmlElement& newState);
|
|
|
|
/** Sets a message to be displayed when there are no properties in the panel.
|
|
|
|
The default message is "nothing selected".
|
|
*/
|
|
void setMessageWhenEmpty (const String& newMessage);
|
|
|
|
/** Returns the message that is displayed when there are no properties.
|
|
@see setMessageWhenEmpty
|
|
*/
|
|
const String& getMessageWhenEmpty() const;
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
|
|
private:
|
|
Viewport viewport;
|
|
class PropertyHolderComponent;
|
|
PropertyHolderComponent* propertyHolderComponent;
|
|
String messageWhenEmpty;
|
|
|
|
void updatePropHolderLayout() const;
|
|
void updatePropHolderLayout (int width) const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PropertyPanel);
|
|
};
|
|
|
|
#endif // __JUCE_PROPERTYPANEL_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_PropertyPanel.h ***/
|
|
|
|
/**
|
|
A type of UI component that displays the parameters of an AudioProcessor as
|
|
a simple list of sliders.
|
|
|
|
This can be used for showing an editor for a processor that doesn't supply
|
|
its own custom editor.
|
|
|
|
@see AudioProcessor
|
|
*/
|
|
class JUCE_API GenericAudioProcessorEditor : public AudioProcessorEditor
|
|
{
|
|
public:
|
|
|
|
GenericAudioProcessorEditor (AudioProcessor* owner);
|
|
~GenericAudioProcessorEditor();
|
|
|
|
void paint (Graphics& g);
|
|
void resized();
|
|
|
|
private:
|
|
|
|
PropertyPanel panel;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (GenericAudioProcessorEditor);
|
|
};
|
|
|
|
#endif // __JUCE_GENERICAUDIOPROCESSOREDITOR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_GenericAudioProcessorEditor.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SAMPLER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_Sampler.h ***/
|
|
#ifndef __JUCE_SAMPLER_JUCEHEADER__
|
|
#define __JUCE_SAMPLER_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_Synthesiser.h ***/
|
|
#ifndef __JUCE_SYNTHESISER_JUCEHEADER__
|
|
#define __JUCE_SYNTHESISER_JUCEHEADER__
|
|
|
|
/**
|
|
Describes one of the sounds that a Synthesiser can play.
|
|
|
|
A synthesiser can contain one or more sounds, and a sound can choose which
|
|
midi notes and channels can trigger it.
|
|
|
|
The SynthesiserSound is a passive class that just describes what the sound is -
|
|
the actual audio rendering for a sound is done by a SynthesiserVoice. This allows
|
|
more than one SynthesiserVoice to play the same sound at the same time.
|
|
|
|
@see Synthesiser, SynthesiserVoice
|
|
*/
|
|
class JUCE_API SynthesiserSound : public ReferenceCountedObject
|
|
{
|
|
protected:
|
|
|
|
SynthesiserSound();
|
|
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~SynthesiserSound();
|
|
|
|
/** Returns true if this sound should be played when a given midi note is pressed.
|
|
|
|
The Synthesiser will use this information when deciding which sounds to trigger
|
|
for a given note.
|
|
*/
|
|
virtual bool appliesToNote (const int midiNoteNumber) = 0;
|
|
|
|
/** Returns true if the sound should be triggered by midi events on a given channel.
|
|
|
|
The Synthesiser will use this information when deciding which sounds to trigger
|
|
for a given note.
|
|
*/
|
|
virtual bool appliesToChannel (const int midiChannel) = 0;
|
|
|
|
/**
|
|
*/
|
|
typedef ReferenceCountedObjectPtr <SynthesiserSound> Ptr;
|
|
|
|
private:
|
|
|
|
JUCE_LEAK_DETECTOR (SynthesiserSound);
|
|
};
|
|
|
|
/**
|
|
Represents a voice that a Synthesiser can use to play a SynthesiserSound.
|
|
|
|
A voice plays a single sound at a time, and a synthesiser holds an array of
|
|
voices so that it can play polyphonically.
|
|
|
|
@see Synthesiser, SynthesiserSound
|
|
*/
|
|
class JUCE_API SynthesiserVoice
|
|
{
|
|
public:
|
|
|
|
/** Creates a voice. */
|
|
SynthesiserVoice();
|
|
|
|
/** Destructor. */
|
|
virtual ~SynthesiserVoice();
|
|
|
|
/** Returns the midi note that this voice is currently playing.
|
|
|
|
Returns a value less than 0 if no note is playing.
|
|
*/
|
|
int getCurrentlyPlayingNote() const { return currentlyPlayingNote; }
|
|
|
|
/** Returns the sound that this voice is currently playing.
|
|
|
|
Returns 0 if it's not playing.
|
|
*/
|
|
SynthesiserSound::Ptr getCurrentlyPlayingSound() const { return currentlyPlayingSound; }
|
|
|
|
/** Must return true if this voice object is capable of playing the given sound.
|
|
|
|
If there are different classes of sound, and different classes of voice, a voice can
|
|
choose which ones it wants to take on.
|
|
|
|
A typical implementation of this method may just return true if there's only one type
|
|
of voice and sound, or it might check the type of the sound object passed-in and
|
|
see if it's one that it understands.
|
|
*/
|
|
virtual bool canPlaySound (SynthesiserSound* sound) = 0;
|
|
|
|
/** Called to start a new note.
|
|
|
|
This will be called during the rendering callback, so must be fast and thread-safe.
|
|
*/
|
|
virtual void startNote (const int midiNoteNumber,
|
|
const float velocity,
|
|
SynthesiserSound* sound,
|
|
const int currentPitchWheelPosition) = 0;
|
|
|
|
/** Called to stop a note.
|
|
|
|
This will be called during the rendering callback, so must be fast and thread-safe.
|
|
|
|
If allowTailOff is false or the voice doesn't want to tail-off, then it must stop all
|
|
sound immediately, and must call clearCurrentNote() to reset the state of this voice
|
|
and allow the synth to reassign it another sound.
|
|
|
|
If allowTailOff is true and the voice decides to do a tail-off, then it's allowed to
|
|
begin fading out its sound, and it can stop playing until it's finished. As soon as it
|
|
finishes playing (during the rendering callback), it must make sure that it calls
|
|
clearCurrentNote().
|
|
*/
|
|
virtual void stopNote (const bool allowTailOff) = 0;
|
|
|
|
/** Called to let the voice know that the pitch wheel has been moved.
|
|
|
|
This will be called during the rendering callback, so must be fast and thread-safe.
|
|
*/
|
|
virtual void pitchWheelMoved (const int newValue) = 0;
|
|
|
|
/** Called to let the voice know that a midi controller has been moved.
|
|
|
|
This will be called during the rendering callback, so must be fast and thread-safe.
|
|
*/
|
|
virtual void controllerMoved (const int controllerNumber,
|
|
const int newValue) = 0;
|
|
|
|
/** Renders the next block of data for this voice.
|
|
|
|
The output audio data must be added to the current contents of the buffer provided.
|
|
Only the region of the buffer between startSample and (startSample + numSamples)
|
|
should be altered by this method.
|
|
|
|
If the voice is currently silent, it should just return without doing anything.
|
|
|
|
If the sound that the voice is playing finishes during the course of this rendered
|
|
block, it must call clearCurrentNote(), to tell the synthesiser that it has finished.
|
|
|
|
The size of the blocks that are rendered can change each time it is called, and may
|
|
involve rendering as little as 1 sample at a time. In between rendering callbacks,
|
|
the voice's methods will be called to tell it about note and controller events.
|
|
*/
|
|
virtual void renderNextBlock (AudioSampleBuffer& outputBuffer,
|
|
int startSample,
|
|
int numSamples) = 0;
|
|
|
|
/** Returns true if the voice is currently playing a sound which is mapped to the given
|
|
midi channel.
|
|
|
|
If it's not currently playing, this will return false.
|
|
*/
|
|
bool isPlayingChannel (int midiChannel) const;
|
|
|
|
/** Changes the voice's reference sample rate.
|
|
|
|
The rate is set so that subclasses know the output rate and can set their pitch
|
|
accordingly.
|
|
|
|
This method is called by the synth, and subclasses can access the current rate with
|
|
the currentSampleRate member.
|
|
*/
|
|
void setCurrentPlaybackSampleRate (double newRate);
|
|
|
|
protected:
|
|
|
|
/** Returns the current target sample rate at which rendering is being done.
|
|
|
|
This is available for subclasses so they can pitch things correctly.
|
|
*/
|
|
double getSampleRate() const { return currentSampleRate; }
|
|
|
|
/** Resets the state of this voice after a sound has finished playing.
|
|
|
|
The subclass must call this when it finishes playing a note and becomes available
|
|
to play new ones.
|
|
|
|
It must either call it in the stopNote() method, or if the voice is tailing off,
|
|
then it should call it later during the renderNextBlock method, as soon as it
|
|
finishes its tail-off.
|
|
|
|
It can also be called at any time during the render callback if the sound happens
|
|
to have finished, e.g. if it's playing a sample and the sample finishes.
|
|
*/
|
|
void clearCurrentNote();
|
|
|
|
private:
|
|
|
|
friend class Synthesiser;
|
|
|
|
double currentSampleRate;
|
|
int currentlyPlayingNote;
|
|
uint32 noteOnTime;
|
|
SynthesiserSound::Ptr currentlyPlayingSound;
|
|
bool keyIsDown; // the voice may still be playing when the key is not down (i.e. sustain pedal)
|
|
bool sostenutoPedalDown;
|
|
|
|
JUCE_LEAK_DETECTOR (SynthesiserVoice);
|
|
};
|
|
|
|
/**
|
|
Base class for a musical device that can play sounds.
|
|
|
|
To create a synthesiser, you'll need to create a subclass of SynthesiserSound
|
|
to describe each sound available to your synth, and a subclass of SynthesiserVoice
|
|
which can play back one of these sounds.
|
|
|
|
Then you can use the addVoice() and addSound() methods to give the synthesiser a
|
|
set of sounds, and a set of voices it can use to play them. If you only give it
|
|
one voice it will be monophonic - the more voices it has, the more polyphony it'll
|
|
have available.
|
|
|
|
Then repeatedly call the renderNextBlock() method to produce the audio. Any midi
|
|
events that go in will be scanned for note on/off messages, and these are used to
|
|
start and stop the voices playing the appropriate sounds.
|
|
|
|
While it's playing, you can also cause notes to be triggered by calling the noteOn(),
|
|
noteOff() and other controller methods.
|
|
|
|
Before rendering, be sure to call the setCurrentPlaybackSampleRate() to tell it
|
|
what the target playback rate is. This value is passed on to the voices so that
|
|
they can pitch their output correctly.
|
|
*/
|
|
class JUCE_API Synthesiser
|
|
{
|
|
public:
|
|
|
|
/** Creates a new synthesiser.
|
|
|
|
You'll need to add some sounds and voices before it'll make any sound..
|
|
*/
|
|
Synthesiser();
|
|
|
|
/** Destructor. */
|
|
virtual ~Synthesiser();
|
|
|
|
/** Deletes all voices. */
|
|
void clearVoices();
|
|
|
|
/** Returns the number of voices that have been added. */
|
|
int getNumVoices() const { return voices.size(); }
|
|
|
|
/** Returns one of the voices that have been added. */
|
|
SynthesiserVoice* getVoice (int index) const;
|
|
|
|
/** Adds a new voice to the synth.
|
|
|
|
All the voices should be the same class of object and are treated equally.
|
|
|
|
The object passed in will be managed by the synthesiser, which will delete
|
|
it later on when no longer needed. The caller should not retain a pointer to the
|
|
voice.
|
|
*/
|
|
void addVoice (SynthesiserVoice* newVoice);
|
|
|
|
/** Deletes one of the voices. */
|
|
void removeVoice (int index);
|
|
|
|
/** Deletes all sounds. */
|
|
void clearSounds();
|
|
|
|
/** Returns the number of sounds that have been added to the synth. */
|
|
int getNumSounds() const { return sounds.size(); }
|
|
|
|
/** Returns one of the sounds. */
|
|
SynthesiserSound* getSound (int index) const { return sounds [index]; }
|
|
|
|
/** Adds a new sound to the synthesiser.
|
|
|
|
The object passed in is reference counted, so will be deleted when it is removed
|
|
from the synthesiser, and when no voices are still using it.
|
|
*/
|
|
void addSound (const SynthesiserSound::Ptr& newSound);
|
|
|
|
/** Removes and deletes one of the sounds. */
|
|
void removeSound (int index);
|
|
|
|
/** If set to true, then the synth will try to take over an existing voice if
|
|
it runs out and needs to play another note.
|
|
|
|
The value of this boolean is passed into findFreeVoice(), so the result will
|
|
depend on the implementation of this method.
|
|
*/
|
|
void setNoteStealingEnabled (bool shouldStealNotes);
|
|
|
|
/** Returns true if note-stealing is enabled.
|
|
@see setNoteStealingEnabled
|
|
*/
|
|
bool isNoteStealingEnabled() const { return shouldStealNotes; }
|
|
|
|
/** Triggers a note-on event.
|
|
|
|
The default method here will find all the sounds that want to be triggered by
|
|
this note/channel. For each sound, it'll try to find a free voice, and use the
|
|
voice to start playing the sound.
|
|
|
|
Subclasses might want to override this if they need a more complex algorithm.
|
|
|
|
This method will be called automatically according to the midi data passed into
|
|
renderNextBlock(), but may be called explicitly too.
|
|
|
|
The midiChannel parameter is the channel, between 1 and 16 inclusive.
|
|
*/
|
|
virtual void noteOn (int midiChannel,
|
|
int midiNoteNumber,
|
|
float velocity);
|
|
|
|
/** Triggers a note-off event.
|
|
|
|
This will turn off any voices that are playing a sound for the given note/channel.
|
|
|
|
If allowTailOff is true, the voices will be allowed to fade out the notes gracefully
|
|
(if they can do). If this is false, the notes will all be cut off immediately.
|
|
|
|
This method will be called automatically according to the midi data passed into
|
|
renderNextBlock(), but may be called explicitly too.
|
|
|
|
The midiChannel parameter is the channel, between 1 and 16 inclusive.
|
|
*/
|
|
virtual void noteOff (int midiChannel,
|
|
int midiNoteNumber,
|
|
bool allowTailOff);
|
|
|
|
/** Turns off all notes.
|
|
|
|
This will turn off any voices that are playing a sound on the given midi channel.
|
|
|
|
If midiChannel is 0 or less, then all voices will be turned off, regardless of
|
|
which channel they're playing. Otherwise it represents a valid midi channel, from
|
|
1 to 16 inclusive.
|
|
|
|
If allowTailOff is true, the voices will be allowed to fade out the notes gracefully
|
|
(if they can do). If this is false, the notes will all be cut off immediately.
|
|
|
|
This method will be called automatically according to the midi data passed into
|
|
renderNextBlock(), but may be called explicitly too.
|
|
*/
|
|
virtual void allNotesOff (int midiChannel,
|
|
bool allowTailOff);
|
|
|
|
/** Sends a pitch-wheel message.
|
|
|
|
This will send a pitch-wheel message to any voices that are playing sounds on
|
|
the given midi channel.
|
|
|
|
This method will be called automatically according to the midi data passed into
|
|
renderNextBlock(), but may be called explicitly too.
|
|
|
|
@param midiChannel the midi channel, from 1 to 16 inclusive
|
|
@param wheelValue the wheel position, from 0 to 0x3fff, as returned by MidiMessage::getPitchWheelValue()
|
|
*/
|
|
virtual void handlePitchWheel (int midiChannel,
|
|
int wheelValue);
|
|
|
|
/** Sends a midi controller message.
|
|
|
|
This will send a midi controller message to any voices that are playing sounds on
|
|
the given midi channel.
|
|
|
|
This method will be called automatically according to the midi data passed into
|
|
renderNextBlock(), but may be called explicitly too.
|
|
|
|
@param midiChannel the midi channel, from 1 to 16 inclusive
|
|
@param controllerNumber the midi controller type, as returned by MidiMessage::getControllerNumber()
|
|
@param controllerValue the midi controller value, between 0 and 127, as returned by MidiMessage::getControllerValue()
|
|
*/
|
|
virtual void handleController (int midiChannel,
|
|
int controllerNumber,
|
|
int controllerValue);
|
|
|
|
virtual void handleSustainPedal (int midiChannel, bool isDown);
|
|
virtual void handleSostenutoPedal (int midiChannel, bool isDown);
|
|
virtual void handleSoftPedal (int midiChannel, bool isDown);
|
|
|
|
/** Tells the synthesiser what the sample rate is for the audio it's being used to
|
|
render.
|
|
|
|
This value is propagated to the voices so that they can use it to render the correct
|
|
pitches.
|
|
*/
|
|
void setCurrentPlaybackSampleRate (double sampleRate);
|
|
|
|
/** Creates the next block of audio output.
|
|
|
|
This will process the next numSamples of data from all the voices, and add that output
|
|
to the audio block supplied, starting from the offset specified. Note that the
|
|
data will be added to the current contents of the buffer, so you should clear it
|
|
before calling this method if necessary.
|
|
|
|
The midi events in the inputMidi buffer are parsed for note and controller events,
|
|
and these are used to trigger the voices. Note that the startSample offset applies
|
|
both to the audio output buffer and the midi input buffer, so any midi events
|
|
with timestamps outside the specified region will be ignored.
|
|
*/
|
|
void renderNextBlock (AudioSampleBuffer& outputAudio,
|
|
const MidiBuffer& inputMidi,
|
|
int startSample,
|
|
int numSamples);
|
|
|
|
protected:
|
|
|
|
/** This is used to control access to the rendering callback and the note trigger methods. */
|
|
CriticalSection lock;
|
|
|
|
OwnedArray <SynthesiserVoice> voices;
|
|
ReferenceCountedArray <SynthesiserSound> sounds;
|
|
|
|
/** The last pitch-wheel values for each midi channel. */
|
|
int lastPitchWheelValues [16];
|
|
|
|
/** Searches through the voices to find one that's not currently playing, and which
|
|
can play the given sound.
|
|
|
|
Returns 0 if all voices are busy and stealing isn't enabled.
|
|
|
|
This can be overridden to implement custom voice-stealing algorithms.
|
|
*/
|
|
virtual SynthesiserVoice* findFreeVoice (SynthesiserSound* soundToPlay,
|
|
const bool stealIfNoneAvailable) const;
|
|
|
|
/** Starts a specified voice playing a particular sound.
|
|
|
|
You'll probably never need to call this, it's used internally by noteOn(), but
|
|
may be needed by subclasses for custom behaviours.
|
|
*/
|
|
void startVoice (SynthesiserVoice* voice,
|
|
SynthesiserSound* sound,
|
|
int midiChannel,
|
|
int midiNoteNumber,
|
|
float velocity);
|
|
|
|
private:
|
|
|
|
double sampleRate;
|
|
uint32 lastNoteOnCounter;
|
|
bool shouldStealNotes;
|
|
BigInteger sustainPedalsDown;
|
|
|
|
void handleMidiEvent (const MidiMessage& m);
|
|
void stopVoice (SynthesiserVoice* voice, bool allowTailOff);
|
|
|
|
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
|
// Note the new parameters for this method.
|
|
virtual int findFreeVoice (const bool) const { return 0; }
|
|
#endif
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Synthesiser);
|
|
};
|
|
|
|
#endif // __JUCE_SYNTHESISER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Synthesiser.h ***/
|
|
|
|
/**
|
|
A subclass of SynthesiserSound that represents a sampled audio clip.
|
|
|
|
This is a pretty basic sampler, and just attempts to load the whole audio stream
|
|
into memory.
|
|
|
|
To use it, create a Synthesiser, add some SamplerVoice objects to it, then
|
|
give it some SampledSound objects to play.
|
|
|
|
@see SamplerVoice, Synthesiser, SynthesiserSound
|
|
*/
|
|
class JUCE_API SamplerSound : public SynthesiserSound
|
|
{
|
|
public:
|
|
|
|
/** Creates a sampled sound from an audio reader.
|
|
|
|
This will attempt to load the audio from the source into memory and store
|
|
it in this object.
|
|
|
|
@param name a name for the sample
|
|
@param source the audio to load. This object can be safely deleted by the
|
|
caller after this constructor returns
|
|
@param midiNotes the set of midi keys that this sound should be played on. This
|
|
is used by the SynthesiserSound::appliesToNote() method
|
|
@param midiNoteForNormalPitch the midi note at which the sample should be played
|
|
with its natural rate. All other notes will be pitched
|
|
up or down relative to this one
|
|
@param attackTimeSecs the attack (fade-in) time, in seconds
|
|
@param releaseTimeSecs the decay (fade-out) time, in seconds
|
|
@param maxSampleLengthSeconds a maximum length of audio to read from the audio
|
|
source, in seconds
|
|
*/
|
|
SamplerSound (const String& name,
|
|
AudioFormatReader& source,
|
|
const BigInteger& midiNotes,
|
|
int midiNoteForNormalPitch,
|
|
double attackTimeSecs,
|
|
double releaseTimeSecs,
|
|
double maxSampleLengthSeconds);
|
|
|
|
/** Destructor. */
|
|
~SamplerSound();
|
|
|
|
/** Returns the sample's name */
|
|
const String& getName() const { return name; }
|
|
|
|
/** Returns the audio sample data.
|
|
This could be 0 if there was a problem loading it.
|
|
*/
|
|
AudioSampleBuffer* getAudioData() const { return data; }
|
|
|
|
bool appliesToNote (const int midiNoteNumber);
|
|
bool appliesToChannel (const int midiChannel);
|
|
|
|
private:
|
|
|
|
friend class SamplerVoice;
|
|
|
|
String name;
|
|
ScopedPointer <AudioSampleBuffer> data;
|
|
double sourceSampleRate;
|
|
BigInteger midiNotes;
|
|
int length, attackSamples, releaseSamples;
|
|
int midiRootNote;
|
|
|
|
JUCE_LEAK_DETECTOR (SamplerSound);
|
|
};
|
|
|
|
/**
|
|
A subclass of SynthesiserVoice that can play a SamplerSound.
|
|
|
|
To use it, create a Synthesiser, add some SamplerVoice objects to it, then
|
|
give it some SampledSound objects to play.
|
|
|
|
@see SamplerSound, Synthesiser, SynthesiserVoice
|
|
*/
|
|
class JUCE_API SamplerVoice : public SynthesiserVoice
|
|
{
|
|
public:
|
|
|
|
/** Creates a SamplerVoice.
|
|
*/
|
|
SamplerVoice();
|
|
|
|
/** Destructor. */
|
|
~SamplerVoice();
|
|
|
|
bool canPlaySound (SynthesiserSound* sound);
|
|
|
|
void startNote (const int midiNoteNumber,
|
|
const float velocity,
|
|
SynthesiserSound* sound,
|
|
const int currentPitchWheelPosition);
|
|
|
|
void stopNote (const bool allowTailOff);
|
|
|
|
void pitchWheelMoved (const int newValue);
|
|
void controllerMoved (const int controllerNumber,
|
|
const int newValue);
|
|
|
|
void renderNextBlock (AudioSampleBuffer& outputBuffer, int startSample, int numSamples);
|
|
|
|
private:
|
|
|
|
double pitchRatio;
|
|
double sourceSamplePosition;
|
|
float lgain, rgain, attackReleaseLevel, attackDelta, releaseDelta;
|
|
bool isInAttack, isInRelease;
|
|
|
|
JUCE_LEAK_DETECTOR (SamplerVoice);
|
|
};
|
|
|
|
#endif // __JUCE_SAMPLER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Sampler.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SYNTHESISER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ActionBroadcaster.h ***/
|
|
#ifndef __JUCE_ACTIONBROADCASTER_JUCEHEADER__
|
|
#define __JUCE_ACTIONBROADCASTER_JUCEHEADER__
|
|
|
|
/** Manages a list of ActionListeners, and can send them messages.
|
|
|
|
To quickly add methods to your class that can add/remove action
|
|
listeners and broadcast to them, you can derive from this.
|
|
|
|
@see ActionListener, ChangeListener
|
|
*/
|
|
class JUCE_API ActionBroadcaster
|
|
{
|
|
public:
|
|
|
|
/** Creates an ActionBroadcaster. */
|
|
ActionBroadcaster();
|
|
|
|
/** Destructor. */
|
|
virtual ~ActionBroadcaster();
|
|
|
|
/** Adds a listener to the list.
|
|
Trying to add a listener that's already on the list will have no effect.
|
|
*/
|
|
void addActionListener (ActionListener* listener);
|
|
|
|
/** Removes a listener from the list.
|
|
If the listener isn't on the list, this won't have any effect.
|
|
*/
|
|
void removeActionListener (ActionListener* listener);
|
|
|
|
/** Removes all listeners from the list. */
|
|
void removeAllActionListeners();
|
|
|
|
/** Broadcasts a message to all the registered listeners.
|
|
@see ActionListener::actionListenerCallback
|
|
*/
|
|
void sendActionMessage (const String& message) const;
|
|
|
|
private:
|
|
|
|
class CallbackReceiver : public MessageListener
|
|
{
|
|
public:
|
|
CallbackReceiver();
|
|
void handleMessage (const Message&);
|
|
|
|
ActionBroadcaster* owner;
|
|
};
|
|
|
|
friend class CallbackReceiver;
|
|
CallbackReceiver callback;
|
|
SortedSet <ActionListener*> actionListeners;
|
|
CriticalSection actionListenerLock;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (ActionBroadcaster);
|
|
};
|
|
|
|
#endif // __JUCE_ACTIONBROADCASTER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ActionBroadcaster.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_ACTIONLISTENER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_APPLEREMOTE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_AppleRemote.h ***/
|
|
#ifndef __JUCE_APPLEREMOTE_JUCEHEADER__
|
|
#define __JUCE_APPLEREMOTE_JUCEHEADER__
|
|
|
|
#if JUCE_MAC || DOXYGEN
|
|
/**
|
|
Receives events from an Apple IR remote control device (Only available in OSX!).
|
|
|
|
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_APPLEREMOTE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AppleRemote.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_ASYNCUPDATER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CALLBACKMESSAGE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CHANGEBROADCASTER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CHANGELISTENER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_InterprocessConnection.h ***/
|
|
#ifndef __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__
|
|
#define __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__
|
|
|
|
class InterprocessConnectionServer;
|
|
class MemoryBlock;
|
|
|
|
/**
|
|
Manages a simple two-way messaging connection to another process, using either
|
|
a socket or a named pipe as the transport medium.
|
|
|
|
To connect to a waiting socket or an open pipe, use the connectToSocket() or
|
|
connectToPipe() methods. If this succeeds, messages can be sent to the other end,
|
|
and incoming messages will result in a callback via the messageReceived()
|
|
method.
|
|
|
|
To open a pipe and wait for another client to connect to it, use the createPipe()
|
|
method.
|
|
|
|
To act as a socket server and create connections for one or more client, see the
|
|
InterprocessConnectionServer class.
|
|
|
|
@see InterprocessConnectionServer, Socket, NamedPipe
|
|
*/
|
|
class JUCE_API InterprocessConnection : public Thread,
|
|
private MessageListener
|
|
{
|
|
public:
|
|
|
|
/** Creates a connection.
|
|
|
|
Connections are created manually, connecting them with the connectToSocket()
|
|
or connectToPipe() methods, or they are created automatically by a InterprocessConnectionServer
|
|
when a client wants to connect.
|
|
|
|
@param callbacksOnMessageThread if true, callbacks to the connectionMade(),
|
|
connectionLost() and messageReceived() methods will
|
|
always be made using the message thread; if false,
|
|
these will be called immediately on the connection's
|
|
own thread.
|
|
@param magicMessageHeaderNumber a magic number to use in the header to check the
|
|
validity of the data blocks being sent and received. This
|
|
can be any number, but the sender and receiver must obviously
|
|
use matching values or they won't recognise each other.
|
|
*/
|
|
InterprocessConnection (bool callbacksOnMessageThread = true,
|
|
uint32 magicMessageHeaderNumber = 0xf2b49e2c);
|
|
|
|
/** Destructor. */
|
|
~InterprocessConnection();
|
|
|
|
/** Tries to connect this object to a socket.
|
|
|
|
For this to work, the machine on the other end needs to have a InterprocessConnectionServer
|
|
object waiting to receive client connections on this port number.
|
|
|
|
@param hostName the host computer, either a network address or name
|
|
@param portNumber the socket port number to try to connect to
|
|
@param timeOutMillisecs how long to keep trying before giving up
|
|
@returns true if the connection is established successfully
|
|
@see Socket
|
|
*/
|
|
bool connectToSocket (const String& hostName,
|
|
int portNumber,
|
|
int timeOutMillisecs);
|
|
|
|
/** Tries to connect the object to an existing named pipe.
|
|
|
|
For this to work, another process on the same computer must already have opened
|
|
an InterprocessConnection object and used createPipe() to create a pipe for this
|
|
to connect to.
|
|
|
|
You can optionally specify a timeout length to be passed to the NamedPipe::read() method.
|
|
|
|
@returns true if it connects successfully.
|
|
@see createPipe, NamedPipe
|
|
*/
|
|
bool connectToPipe (const String& pipeName,
|
|
int pipeReceiveMessageTimeoutMs = -1);
|
|
|
|
/** Tries to create a new pipe for other processes to connect to.
|
|
|
|
This creates a pipe with the given name, so that other processes can use
|
|
connectToPipe() to connect to the other end.
|
|
|
|
You can optionally specify a timeout length to be passed to the NamedPipe::read() method.
|
|
|
|
If another process is already using this pipe, this will fail and return false.
|
|
*/
|
|
bool createPipe (const String& pipeName,
|
|
int pipeReceiveMessageTimeoutMs = -1);
|
|
|
|
/** Disconnects and closes any currently-open sockets or pipes. */
|
|
void disconnect();
|
|
|
|
/** True if a socket or pipe is currently active. */
|
|
bool isConnected() const;
|
|
|
|
/** Returns the socket that this connection is using (or null if it uses a pipe). */
|
|
StreamingSocket* getSocket() const noexcept { return socket; }
|
|
|
|
/** Returns the pipe that this connection is using (or null if it uses a socket). */
|
|
NamedPipe* getPipe() const noexcept { return pipe; }
|
|
|
|
/** Returns the name of the machine at the other end of this connection.
|
|
|
|
This will return an empty string if the other machine isn't known for
|
|
some reason.
|
|
*/
|
|
String getConnectedHostName() const;
|
|
|
|
/** Tries to send a message to the other end of this connection.
|
|
|
|
This will fail if it's not connected, or if there's some kind of write error. If
|
|
it succeeds, the connection object at the other end will receive the message by
|
|
a callback to its messageReceived() method.
|
|
|
|
@see messageReceived
|
|
*/
|
|
bool sendMessage (const MemoryBlock& message);
|
|
|
|
/** Called when the connection is first connected.
|
|
|
|
If the connection was created with the callbacksOnMessageThread flag set, then
|
|
this will be called on the message thread; otherwise it will be called on a server
|
|
thread.
|
|
*/
|
|
virtual void connectionMade() = 0;
|
|
|
|
/** Called when the connection is broken.
|
|
|
|
If the connection was created with the callbacksOnMessageThread flag set, then
|
|
this will be called on the message thread; otherwise it will be called on a server
|
|
thread.
|
|
*/
|
|
virtual void connectionLost() = 0;
|
|
|
|
/** Called when a message arrives.
|
|
|
|
When the object at the other end of this connection sends us a message with sendMessage(),
|
|
this callback is used to deliver it to us.
|
|
|
|
If the connection was created with the callbacksOnMessageThread flag set, then
|
|
this will be called on the message thread; otherwise it will be called on a server
|
|
thread.
|
|
|
|
@see sendMessage
|
|
*/
|
|
virtual void messageReceived (const MemoryBlock& message) = 0;
|
|
|
|
private:
|
|
|
|
CriticalSection pipeAndSocketLock;
|
|
ScopedPointer <StreamingSocket> socket;
|
|
ScopedPointer <NamedPipe> pipe;
|
|
bool callbackConnectionState;
|
|
const bool useMessageThread;
|
|
const uint32 magicMessageHeader;
|
|
int pipeReceiveMessageTimeout;
|
|
|
|
friend class InterprocessConnectionServer;
|
|
|
|
void initialiseWithSocket (StreamingSocket* socket_);
|
|
void initialiseWithPipe (NamedPipe* pipe_);
|
|
|
|
void handleMessage (const Message& message);
|
|
|
|
void connectionMadeInt();
|
|
void connectionLostInt();
|
|
void deliverDataInt (const MemoryBlock& data);
|
|
|
|
bool readNextMessageInt();
|
|
void run();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InterprocessConnection);
|
|
};
|
|
|
|
#endif // __JUCE_INTERPROCESSCONNECTION_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_InterprocessConnection.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_InterprocessConnectionServer.h ***/
|
|
#ifndef __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__
|
|
#define __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__
|
|
|
|
/**
|
|
An object that waits for client sockets to connect to a port on this host, and
|
|
creates InterprocessConnection objects for each one.
|
|
|
|
To use this, create a class derived from it which implements the createConnectionObject()
|
|
method, so that it creates suitable connection objects for each client that tries
|
|
to connect.
|
|
|
|
@see InterprocessConnection
|
|
*/
|
|
class JUCE_API InterprocessConnectionServer : private Thread
|
|
{
|
|
public:
|
|
|
|
/** Creates an uninitialised server object.
|
|
*/
|
|
InterprocessConnectionServer();
|
|
|
|
/** Destructor. */
|
|
~InterprocessConnectionServer();
|
|
|
|
/** Starts an internal thread which listens on the given port number.
|
|
|
|
While this is running, in another process tries to connect with the
|
|
InterprocessConnection::connectToSocket() method, this object will call
|
|
createConnectionObject() to create a connection to that client.
|
|
|
|
Use stop() to stop the thread running.
|
|
|
|
@see createConnectionObject, stop
|
|
*/
|
|
bool beginWaitingForSocket (int portNumber);
|
|
|
|
/** Terminates the listener thread, if it's active.
|
|
|
|
@see beginWaitingForSocket
|
|
*/
|
|
void stop();
|
|
|
|
protected:
|
|
/** Creates a suitable connection object for a client process that wants to
|
|
connect to this one.
|
|
|
|
This will be called by the listener thread when a client process tries
|
|
to connect, and must return a new InterprocessConnection object that will
|
|
then run as this end of the connection.
|
|
|
|
@see InterprocessConnection
|
|
*/
|
|
virtual InterprocessConnection* createConnectionObject() = 0;
|
|
|
|
private:
|
|
|
|
ScopedPointer <StreamingSocket> socket;
|
|
|
|
void run();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (InterprocessConnectionServer);
|
|
};
|
|
|
|
#endif // __JUCE_INTERPROCESSCONNECTIONSERVER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_InterprocessConnectionServer.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_LISTENERLIST_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MESSAGE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MESSAGELISTENER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MESSAGEMANAGER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MessageManager.h ***/
|
|
#ifndef __JUCE_MESSAGEMANAGER_JUCEHEADER__
|
|
#define __JUCE_MESSAGEMANAGER_JUCEHEADER__
|
|
|
|
class Component;
|
|
class MessageManagerLock;
|
|
class ThreadPoolJob;
|
|
class ActionListener;
|
|
class ActionBroadcaster;
|
|
|
|
/** See MessageManager::callFunctionOnMessageThread() for use of this function type
|
|
*/
|
|
typedef void* (MessageCallbackFunction) (void* userData);
|
|
|
|
/** Delivers Message objects to MessageListeners, and handles the event-dispatch loop.
|
|
|
|
@see Message, MessageListener, MessageManagerLock, JUCEApplication
|
|
*/
|
|
class JUCE_API MessageManager
|
|
{
|
|
public:
|
|
|
|
/** Returns the global instance of the MessageManager. */
|
|
static MessageManager* getInstance();
|
|
|
|
/** Deletes the global MessageManager instance.
|
|
Does nothing if no instance had been created.
|
|
*/
|
|
static void deleteInstance();
|
|
|
|
/** Runs the event dispatch loop until a stop message is posted.
|
|
|
|
This method is only intended to be run by the application's startup routine,
|
|
as it blocks, and will only return after the stopDispatchLoop() method has been used.
|
|
|
|
@see stopDispatchLoop
|
|
*/
|
|
void runDispatchLoop();
|
|
|
|
/** Sends a signal that the dispatch loop should terminate.
|
|
|
|
After this is called, the runDispatchLoop() or runDispatchLoopUntil() methods
|
|
will be interrupted and will return.
|
|
|
|
@see runDispatchLoop
|
|
*/
|
|
void stopDispatchLoop();
|
|
|
|
/** Returns true if the stopDispatchLoop() method has been called.
|
|
*/
|
|
bool hasStopMessageBeenSent() const noexcept { return quitMessagePosted; }
|
|
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
/** Synchronously dispatches messages until a given time has elapsed.
|
|
|
|
Returns false if a quit message has been posted by a call to stopDispatchLoop(),
|
|
otherwise returns true.
|
|
*/
|
|
bool runDispatchLoopUntil (int millisecondsToRunFor);
|
|
#endif
|
|
|
|
/** Calls a function using the message-thread.
|
|
|
|
This can be used by any thread to cause this function to be called-back
|
|
by the message thread. If it's the message-thread that's calling this method,
|
|
then the function will just be called; if another thread is calling, a message
|
|
will be posted to the queue, and this method will block until that message
|
|
is delivered, the function is called, and the result is returned.
|
|
|
|
Be careful not to cause any deadlocks with this! It's easy to do - e.g. if the caller
|
|
thread has a critical section locked, which an unrelated message callback then tries to lock
|
|
before the message thread gets round to processing this callback.
|
|
|
|
@param callback the function to call - its signature must be @code
|
|
void* myCallbackFunction (void*) @endcode
|
|
@param userData a user-defined pointer that will be passed to the function that gets called
|
|
@returns the value that the callback function returns.
|
|
@see MessageManagerLock
|
|
*/
|
|
void* callFunctionOnMessageThread (MessageCallbackFunction* callback, void* userData);
|
|
|
|
/** Returns true if the caller-thread is the message thread. */
|
|
bool isThisTheMessageThread() const noexcept;
|
|
|
|
/** Called to tell the manager that the current thread is the one that's running the dispatch loop.
|
|
|
|
(Best to ignore this method unless you really know what you're doing..)
|
|
@see getCurrentMessageThread
|
|
*/
|
|
void setCurrentThreadAsMessageThread();
|
|
|
|
/** Returns the ID of the current message thread, as set by setCurrentMessageThread().
|
|
|
|
(Best to ignore this method unless you really know what you're doing..)
|
|
@see setCurrentMessageThread
|
|
*/
|
|
Thread::ThreadID getCurrentMessageThread() const noexcept { return messageThreadId; }
|
|
|
|
/** Returns true if the caller thread has currenltly got the message manager locked.
|
|
|
|
see the MessageManagerLock class for more info about this.
|
|
|
|
This will be true if the caller is the message thread, because that automatically
|
|
gains a lock while a message is being dispatched.
|
|
*/
|
|
bool currentThreadHasLockedMessageManager() const noexcept;
|
|
|
|
/** Sends a message to all other JUCE applications that are running.
|
|
|
|
@param messageText the string that will be passed to the actionListenerCallback()
|
|
method of the broadcast listeners in the other app.
|
|
@see registerBroadcastListener, ActionListener
|
|
*/
|
|
static void broadcastMessage (const String& messageText);
|
|
|
|
/** Registers a listener to get told about broadcast messages.
|
|
|
|
The actionListenerCallback() callback's string parameter
|
|
is the message passed into broadcastMessage().
|
|
|
|
@see broadcastMessage
|
|
*/
|
|
void registerBroadcastListener (ActionListener* listener);
|
|
|
|
/** Deregisters a broadcast listener. */
|
|
void deregisterBroadcastListener (ActionListener* listener);
|
|
|
|
#ifndef DOXYGEN
|
|
// Internal methods - do not use!
|
|
void deliverMessage (Message*);
|
|
void deliverBroadcastMessage (const String&);
|
|
~MessageManager() noexcept;
|
|
#endif
|
|
|
|
private:
|
|
|
|
MessageManager() noexcept;
|
|
|
|
friend class MessageListener;
|
|
friend class ChangeBroadcaster;
|
|
friend class ActionBroadcaster;
|
|
friend class CallbackMessage;
|
|
static MessageManager* instance;
|
|
|
|
SortedSet <const MessageListener*> messageListeners;
|
|
ScopedPointer <ActionBroadcaster> broadcaster;
|
|
|
|
friend class JUCEApplication;
|
|
bool quitMessagePosted, quitMessageReceived;
|
|
Thread::ThreadID messageThreadId;
|
|
|
|
friend class MessageManagerLock;
|
|
Thread::ThreadID volatile threadWithLock;
|
|
CriticalSection lockingLock;
|
|
|
|
void postMessageToQueue (Message* message);
|
|
static bool postMessageToSystemQueue (Message*);
|
|
static void* exitModalLoopCallback (void*);
|
|
static void doPlatformSpecificInitialisation();
|
|
static void doPlatformSpecificShutdown();
|
|
static bool dispatchNextMessageOnSystemQueue (bool returnIfNoPendingMessages);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MessageManager);
|
|
};
|
|
|
|
/** Used to make sure that the calling thread has exclusive access to the message loop.
|
|
|
|
Because it's not thread-safe to call any of the Component or other UI classes
|
|
from threads other than the message thread, one of these objects can be used to
|
|
lock the message loop and allow this to be done. The message thread will be
|
|
suspended for the lifetime of the MessageManagerLock object, so create one on
|
|
the stack like this: @code
|
|
void MyThread::run()
|
|
{
|
|
someData = 1234;
|
|
|
|
const MessageManagerLock mmLock;
|
|
// the event loop will now be locked so it's safe to make a few calls..
|
|
|
|
myComponent->setBounds (newBounds);
|
|
myComponent->repaint();
|
|
|
|
// ..the event loop will now be unlocked as the MessageManagerLock goes out of scope
|
|
}
|
|
@endcode
|
|
|
|
Obviously be careful not to create one of these and leave it lying around, or
|
|
your app will grind to a halt!
|
|
|
|
Another caveat is that using this in conjunction with other CriticalSections
|
|
can create lots of interesting ways of producing a deadlock! In particular, if
|
|
your message thread calls stopThread() for a thread that uses these locks,
|
|
you'll get an (occasional) deadlock..
|
|
|
|
@see MessageManager, MessageManager::currentThreadHasLockedMessageManager
|
|
*/
|
|
class JUCE_API MessageManagerLock
|
|
{
|
|
public:
|
|
|
|
/** Tries to acquire a lock on the message manager.
|
|
|
|
The constructor attempts to gain a lock on the message loop, and the lock will be
|
|
kept for the lifetime of this object.
|
|
|
|
Optionally, you can pass a thread object here, and while waiting to obtain the lock,
|
|
this method will keep checking whether the thread has been given the
|
|
Thread::signalThreadShouldExit() signal. If this happens, then it will return
|
|
without gaining the lock. If you pass a thread, you must check whether the lock was
|
|
successful by calling lockWasGained(). If this is false, your thread is being told to
|
|
die, so you should take evasive action.
|
|
|
|
If you pass zero for the thread object, it will wait indefinitely for the lock - be
|
|
careful when doing this, because it's very easy to deadlock if your message thread
|
|
attempts to call stopThread() on a thread just as that thread attempts to get the
|
|
message lock.
|
|
|
|
If the calling thread already has the lock, nothing will be done, so it's safe and
|
|
quick to use these locks recursively.
|
|
|
|
E.g.
|
|
@code
|
|
void run()
|
|
{
|
|
...
|
|
|
|
while (! threadShouldExit())
|
|
{
|
|
MessageManagerLock mml (Thread::getCurrentThread());
|
|
|
|
if (! mml.lockWasGained())
|
|
return; // another thread is trying to kill us!
|
|
|
|
..do some locked stuff here..
|
|
}
|
|
|
|
..and now the MM is now unlocked..
|
|
}
|
|
@endcode
|
|
|
|
*/
|
|
MessageManagerLock (Thread* threadToCheckForExitSignal = 0);
|
|
|
|
/** This has the same behaviour as the other constructor, but takes a ThreadPoolJob
|
|
instead of a thread.
|
|
|
|
See the MessageManagerLock (Thread*) constructor for details on how this works.
|
|
*/
|
|
MessageManagerLock (ThreadPoolJob* jobToCheckForExitSignal);
|
|
|
|
/** Releases the current thread's lock on the message manager.
|
|
|
|
Make sure this object is created and deleted by the same thread,
|
|
otherwise there are no guarantees what will happen!
|
|
*/
|
|
~MessageManagerLock() noexcept;
|
|
|
|
/** Returns true if the lock was successfully acquired.
|
|
(See the constructor that takes a Thread for more info).
|
|
*/
|
|
bool lockWasGained() const noexcept { return locked; }
|
|
|
|
private:
|
|
class BlockingMessage;
|
|
friend class ReferenceCountedObjectPtr<BlockingMessage>;
|
|
ReferenceCountedObjectPtr<BlockingMessage> blockingMessage;
|
|
bool locked;
|
|
|
|
void init (Thread* thread, ThreadPoolJob* job);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (MessageManagerLock);
|
|
};
|
|
|
|
#endif // __JUCE_MESSAGEMANAGER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MessageManager.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MULTITIMER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MultiTimer.h ***/
|
|
#ifndef __JUCE_MULTITIMER_JUCEHEADER__
|
|
#define __JUCE_MULTITIMER_JUCEHEADER__
|
|
|
|
/**
|
|
A type of timer class that can run multiple timers with different frequencies,
|
|
all of which share a single callback.
|
|
|
|
This class is very similar to the Timer class, but allows you run multiple
|
|
separate timers, where each one has a unique ID number. The methods in this
|
|
class are exactly equivalent to those in Timer, but with the addition of
|
|
this ID number.
|
|
|
|
To use it, you need to create a subclass of MultiTimer, implementing the
|
|
timerCallback() method. Then you can start timers with startTimer(), and
|
|
each time the callback is triggered, it passes in the ID of the timer that
|
|
caused it.
|
|
|
|
@see Timer
|
|
*/
|
|
class JUCE_API MultiTimer
|
|
{
|
|
protected:
|
|
|
|
/** Creates a MultiTimer.
|
|
|
|
When created, no timers are running, so use startTimer() to start things off.
|
|
*/
|
|
MultiTimer() noexcept;
|
|
|
|
/** Creates a copy of another timer.
|
|
|
|
Note that this timer will not contain any running timers, even if the one you're
|
|
copying from was running.
|
|
*/
|
|
MultiTimer (const MultiTimer& other) noexcept;
|
|
|
|
public:
|
|
|
|
/** Destructor. */
|
|
virtual ~MultiTimer();
|
|
|
|
/** The user-defined callback routine that actually gets called by each of the
|
|
timers that are running.
|
|
|
|
It's perfectly ok to call startTimer() or stopTimer() from within this
|
|
callback to change the subsequent intervals.
|
|
*/
|
|
virtual void timerCallback (int timerId) = 0;
|
|
|
|
/** Starts a 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 timerId a unique Id number that identifies the timer to
|
|
start. This is the id that will be passed back
|
|
to the timerCallback() method when this timer is
|
|
triggered
|
|
@param intervalInMilliseconds the interval to use (any values less than 1 will be
|
|
rounded up to 1)
|
|
*/
|
|
void startTimer (int timerId, int intervalInMilliseconds) noexcept;
|
|
|
|
/** Stops a timer.
|
|
|
|
If a timer has been started with the given ID number, it will be cancelled.
|
|
No more callbacks will be made for the specified timer 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 (int timerId) noexcept;
|
|
|
|
/** Checks whether a timer has been started for a specified ID.
|
|
|
|
@returns true if a timer with the given ID is running.
|
|
*/
|
|
bool isTimerRunning (int timerId) const noexcept;
|
|
|
|
/** Returns the interval for a specified timer ID.
|
|
|
|
@returns the timer's interval in milliseconds if it's running, or 0 if it's no timer
|
|
is running for the ID number specified.
|
|
*/
|
|
int getTimerInterval (int timerId) const noexcept;
|
|
|
|
private:
|
|
class MultiTimerCallback;
|
|
SpinLock timerListLock;
|
|
OwnedArray <MultiTimerCallback> timers;
|
|
|
|
MultiTimer& operator= (const MultiTimer&);
|
|
};
|
|
|
|
#endif // __JUCE_MULTITIMER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MultiTimer.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TIMER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_ARROWBUTTON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ArrowButton.h ***/
|
|
#ifndef __JUCE_ARROWBUTTON_JUCEHEADER__
|
|
#define __JUCE_ARROWBUTTON_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_DropShadowEffect.h ***/
|
|
#ifndef __JUCE_DROPSHADOWEFFECT_JUCEHEADER__
|
|
#define __JUCE_DROPSHADOWEFFECT_JUCEHEADER__
|
|
|
|
/**
|
|
An effect filter that adds a drop-shadow behind the image's content.
|
|
|
|
(This will only work on images/components that aren't opaque, of course).
|
|
|
|
When added to a component, this effect will draw a soft-edged
|
|
shadow based on what gets drawn inside it. The shadow will also
|
|
be applied to the component's children.
|
|
|
|
For speed, this doesn't use a proper gaussian blur, but cheats by
|
|
using a simple bilinear filter. If you need a really high-quality
|
|
shadow, check out ImageConvolutionKernel::createGaussianBlur()
|
|
|
|
@see Component::setComponentEffect
|
|
*/
|
|
class JUCE_API DropShadowEffect : public ImageEffectFilter
|
|
{
|
|
public:
|
|
|
|
/** Creates a default drop-shadow effect.
|
|
|
|
To customise the shadow's appearance, use the setShadowProperties()
|
|
method.
|
|
*/
|
|
DropShadowEffect();
|
|
|
|
/** Destructor. */
|
|
~DropShadowEffect();
|
|
|
|
/** Sets up parameters affecting the shadow's appearance.
|
|
|
|
@param newRadius the (approximate) radius of the blur used
|
|
@param newOpacity the opacity with which the shadow is rendered
|
|
@param newShadowOffsetX allows the shadow to be shifted in relation to the
|
|
component's contents
|
|
@param newShadowOffsetY allows the shadow to be shifted in relation to the
|
|
component's contents
|
|
*/
|
|
void setShadowProperties (float newRadius,
|
|
float newOpacity,
|
|
int newShadowOffsetX,
|
|
int newShadowOffsetY);
|
|
|
|
/** @internal */
|
|
void applyEffect (Image& sourceImage, Graphics& destContext, float alpha);
|
|
|
|
private:
|
|
|
|
int offsetX, offsetY;
|
|
float radius, opacity;
|
|
|
|
JUCE_LEAK_DETECTOR (DropShadowEffect);
|
|
};
|
|
|
|
#endif // __JUCE_DROPSHADOWEFFECT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DropShadowEffect.h ***/
|
|
|
|
/**
|
|
A button with an arrow in it.
|
|
|
|
@see Button
|
|
*/
|
|
class JUCE_API ArrowButton : public Button
|
|
{
|
|
public:
|
|
|
|
/** Creates an ArrowButton.
|
|
|
|
@param buttonName the name to give the button
|
|
@param arrowDirection the direction the arrow should point in, where 0.0 is
|
|
pointing right, 0.25 is down, 0.5 is left, 0.75 is up
|
|
@param arrowColour the colour to use for the arrow
|
|
*/
|
|
ArrowButton (const String& buttonName,
|
|
float arrowDirection,
|
|
const Colour& arrowColour);
|
|
|
|
/** Destructor. */
|
|
~ArrowButton();
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void paintButton (Graphics& g,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
/** @internal */
|
|
void buttonStateChanged();
|
|
|
|
private:
|
|
|
|
Colour colour;
|
|
DropShadowEffect shadow;
|
|
Path path;
|
|
int offset;
|
|
|
|
void updateShadowAndOffset();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ArrowButton);
|
|
};
|
|
|
|
#endif // __JUCE_ARROWBUTTON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ArrowButton.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_BUTTON_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAWABLEBUTTON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DrawableButton.h ***/
|
|
#ifndef __JUCE_DRAWABLEBUTTON_JUCEHEADER__
|
|
#define __JUCE_DRAWABLEBUTTON_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_Drawable.h ***/
|
|
#ifndef __JUCE_DRAWABLE_JUCEHEADER__
|
|
#define __JUCE_DRAWABLE_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_RelativeCoordinate.h ***/
|
|
#ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__
|
|
#define __JUCE_RELATIVECOORDINATE_JUCEHEADER__
|
|
|
|
/**
|
|
Expresses a coordinate as a dynamically evaluated expression.
|
|
|
|
@see RelativePoint, RelativeRectangle
|
|
*/
|
|
class JUCE_API RelativeCoordinate
|
|
{
|
|
public:
|
|
|
|
/** Creates a zero coordinate. */
|
|
RelativeCoordinate();
|
|
RelativeCoordinate (const Expression& expression);
|
|
RelativeCoordinate (const RelativeCoordinate& other);
|
|
RelativeCoordinate& operator= (const RelativeCoordinate& other);
|
|
|
|
/** Creates an absolute position from the parent origin on either the X or Y axis.
|
|
|
|
@param absoluteDistanceFromOrigin the distance from the origin
|
|
*/
|
|
RelativeCoordinate (double absoluteDistanceFromOrigin);
|
|
|
|
/** Recreates a coordinate from a string description.
|
|
The string will be parsed by ExpressionParser::parse().
|
|
@param stringVersion the expression to use
|
|
@see toString
|
|
*/
|
|
RelativeCoordinate (const String& stringVersion);
|
|
|
|
/** Destructor. */
|
|
~RelativeCoordinate();
|
|
|
|
bool operator== (const RelativeCoordinate& other) const noexcept;
|
|
bool operator!= (const RelativeCoordinate& other) const noexcept;
|
|
|
|
/** Calculates the absolute position of this coordinate.
|
|
|
|
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
|
|
be needed to calculate the result.
|
|
*/
|
|
double resolve (const Expression::Scope* evaluationScope) const;
|
|
|
|
/** Returns true if this coordinate uses the specified coord name at any level in its evaluation.
|
|
This will recursively check any coordinates upon which this one depends.
|
|
*/
|
|
bool references (const String& coordName, const Expression::Scope* evaluationScope) const;
|
|
|
|
/** Returns true if there's a recursive loop when trying to resolve this coordinate's position. */
|
|
bool isRecursive (const Expression::Scope* evaluationScope) const;
|
|
|
|
/** Returns true if this coordinate depends on any other coordinates for its position. */
|
|
bool isDynamic() const;
|
|
|
|
/** Changes the value of this coord to make it resolve to the specified position.
|
|
|
|
Calling this will leave the anchor points unchanged, but will set this coordinate's absolute
|
|
or relative position to whatever value is necessary to make its resultant position
|
|
match the position that is provided.
|
|
*/
|
|
void moveToAbsolute (double absoluteTargetPosition, const Expression::Scope* evaluationScope);
|
|
|
|
/** Returns the expression that defines this coordinate. */
|
|
const Expression& getExpression() const { return term; }
|
|
|
|
/** Returns a string which represents this coordinate.
|
|
For details of the string syntax, see the constructor notes.
|
|
*/
|
|
String toString() const;
|
|
|
|
/** A set of static strings that are commonly used by the RelativeCoordinate class.
|
|
|
|
As well as avoiding using string literals in your code, using these preset values
|
|
has the advantage that all instances of the same string will share the same, reference-counted
|
|
String object, so if you have thousands of points which all refer to the same
|
|
anchor points, this can save a significant amount of memory allocation.
|
|
*/
|
|
struct Strings
|
|
{
|
|
static const String parent; /**< "parent" */
|
|
static const String left; /**< "left" */
|
|
static const String right; /**< "right" */
|
|
static const String top; /**< "top" */
|
|
static const String bottom; /**< "bottom" */
|
|
static const String x; /**< "x" */
|
|
static const String y; /**< "y" */
|
|
static const String width; /**< "width" */
|
|
static const String height; /**< "height" */
|
|
};
|
|
|
|
struct StandardStrings
|
|
{
|
|
enum Type
|
|
{
|
|
left, right, top, bottom,
|
|
x, y, width, height,
|
|
parent,
|
|
unknown
|
|
};
|
|
|
|
static Type getTypeOf (const String& s) noexcept;
|
|
};
|
|
|
|
private:
|
|
|
|
Expression term;
|
|
};
|
|
|
|
#endif // __JUCE_RELATIVECOORDINATE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_RelativeCoordinate.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_RelativeCoordinatePositioner.h ***/
|
|
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
|
|
#define __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_RelativePoint.h ***/
|
|
#ifndef __JUCE_RELATIVEPOINT_JUCEHEADER__
|
|
#define __JUCE_RELATIVEPOINT_JUCEHEADER__
|
|
|
|
/**
|
|
An X-Y position stored as a pair of RelativeCoordinate values.
|
|
|
|
@see RelativeCoordinate, RelativeRectangle
|
|
*/
|
|
class JUCE_API RelativePoint
|
|
{
|
|
public:
|
|
/** Creates a point at the origin. */
|
|
RelativePoint();
|
|
|
|
/** Creates an absolute point, relative to the origin. */
|
|
RelativePoint (const Point<float>& absolutePoint);
|
|
|
|
/** Creates an absolute point, relative to the origin. */
|
|
RelativePoint (float absoluteX, float absoluteY);
|
|
|
|
/** Creates an absolute point from two coordinates. */
|
|
RelativePoint (const RelativeCoordinate& x, const RelativeCoordinate& y);
|
|
|
|
/** Creates a point from a stringified representation.
|
|
The string must contain a pair of coordinates, separated by space or a comma. The syntax for the coordinate
|
|
strings is explained in the RelativeCoordinate class.
|
|
@see toString
|
|
*/
|
|
RelativePoint (const String& stringVersion);
|
|
|
|
bool operator== (const RelativePoint& other) const noexcept;
|
|
bool operator!= (const RelativePoint& other) const noexcept;
|
|
|
|
/** Calculates the absolute position of this point.
|
|
|
|
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
|
|
be needed to calculate the result.
|
|
*/
|
|
const Point<float> resolve (const Expression::Scope* evaluationContext) const;
|
|
|
|
/** Changes the values of this point's coordinates to make it resolve to the specified position.
|
|
|
|
Calling this will leave any anchor points unchanged, but will set any absolute
|
|
or relative positions to whatever values are necessary to make the resultant position
|
|
match the position that is provided.
|
|
*/
|
|
void moveToAbsolute (const Point<float>& newPos, const Expression::Scope* evaluationContext);
|
|
|
|
/** Returns a string which represents this point.
|
|
This returns a comma-separated pair of coordinates. For details of the string syntax used by the
|
|
coordinates, see the RelativeCoordinate constructor notes.
|
|
The string that is returned can be passed to the RelativePoint constructor to recreate the point.
|
|
*/
|
|
String toString() const;
|
|
|
|
/** Returns true if this point depends on any other coordinates for its position. */
|
|
bool isDynamic() const;
|
|
|
|
// The actual X and Y coords...
|
|
RelativeCoordinate x, y;
|
|
};
|
|
|
|
#endif // __JUCE_RELATIVEPOINT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_RelativePoint.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_MarkerList.h ***/
|
|
#ifndef __JUCE_MARKERLIST_JUCEHEADER__
|
|
#define __JUCE_MARKERLIST_JUCEHEADER__
|
|
|
|
class Component;
|
|
|
|
/**
|
|
Holds a set of named marker points along a one-dimensional axis.
|
|
|
|
This class is used to store sets of X and Y marker points in components.
|
|
@see Component::getMarkers().
|
|
*/
|
|
class JUCE_API MarkerList
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty marker list. */
|
|
MarkerList();
|
|
/** Creates a copy of another marker list. */
|
|
MarkerList (const MarkerList& other);
|
|
/** Copies another marker list to this one. */
|
|
MarkerList& operator= (const MarkerList& other);
|
|
/** Destructor. */
|
|
~MarkerList();
|
|
|
|
/** Represents a marker in a MarkerList. */
|
|
class JUCE_API Marker
|
|
{
|
|
public:
|
|
/** Creates a copy of another Marker. */
|
|
Marker (const Marker& other);
|
|
/** Creates a Marker with a given name and position. */
|
|
Marker (const String& name, const RelativeCoordinate& position);
|
|
|
|
/** The marker's name. */
|
|
String name;
|
|
|
|
/** The marker's position.
|
|
|
|
The expression used to define the coordinate may use the names of other
|
|
markers, so that markers can be linked in arbitrary ways, but be careful
|
|
not to create recursive loops of markers whose positions are based on each
|
|
other! It can also refer to "parent.right" and "parent.bottom" so that you
|
|
can set markers which are relative to the size of the component that contains
|
|
them.
|
|
|
|
To resolve the coordinate, you can use the MarkerList::getMarkerPosition() method.
|
|
*/
|
|
RelativeCoordinate position;
|
|
|
|
/** Returns true if both the names and positions of these two markers match. */
|
|
bool operator== (const Marker&) const noexcept;
|
|
/** Returns true if either the name or position of these two markers differ. */
|
|
bool operator!= (const Marker&) const noexcept;
|
|
};
|
|
|
|
/** Returns the number of markers in the list. */
|
|
int getNumMarkers() const noexcept;
|
|
|
|
/** Returns one of the markers in the list, by its index. */
|
|
const Marker* getMarker (int index) const noexcept;
|
|
|
|
/** Returns a named marker, or 0 if no such name is found.
|
|
Note that name comparisons are case-sensitive.
|
|
*/
|
|
const Marker* getMarker (const String& name) const noexcept;
|
|
|
|
/** Evaluates the given marker and returns its absolute position.
|
|
The parent component must be supplied in case the marker's expression refers to
|
|
the size of its parent component.
|
|
*/
|
|
double getMarkerPosition (const Marker& marker, Component* parentComponent) const;
|
|
|
|
/** Sets the position of a marker.
|
|
|
|
If the name already exists, then the existing marker is moved; if it doesn't exist, then a
|
|
new marker is added.
|
|
*/
|
|
void setMarker (const String& name, const RelativeCoordinate& position);
|
|
|
|
/** Deletes the marker at the given list index. */
|
|
void removeMarker (int index);
|
|
|
|
/** Deletes the marker with the given name. */
|
|
void removeMarker (const String& name);
|
|
|
|
/** Returns true if all the markers in these two lists match exactly. */
|
|
bool operator== (const MarkerList& other) const noexcept;
|
|
/** Returns true if not all the markers in these two lists match exactly. */
|
|
bool operator!= (const MarkerList& other) const noexcept;
|
|
|
|
/**
|
|
A class for receiving events when changes are made to a MarkerList.
|
|
|
|
You can register a MarkerList::Listener with a MarkerList using the MarkerList::addListener()
|
|
method, and it will be called when markers are moved, added, or deleted.
|
|
|
|
@see MarkerList::addListener, MarkerList::removeListener
|
|
*/
|
|
class JUCE_API Listener
|
|
{
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~Listener() {}
|
|
|
|
/** Called when something in the given marker list changes. */
|
|
virtual void markersChanged (MarkerList* markerList) = 0;
|
|
|
|
/** Called when the given marker list is being deleted. */
|
|
virtual void markerListBeingDeleted (MarkerList* markerList);
|
|
};
|
|
|
|
/** Registers a listener that will be called when the markers are changed. */
|
|
void addListener (Listener* listener);
|
|
|
|
/** Deregisters a previously-registered listener. */
|
|
void removeListener (Listener* listener);
|
|
|
|
/** Synchronously calls markersChanged() on all the registered listeners. */
|
|
void markersHaveChanged();
|
|
|
|
/** Forms a wrapper around a ValueTree that can be used for storing a MarkerList. */
|
|
class ValueTreeWrapper
|
|
{
|
|
public:
|
|
ValueTreeWrapper (const ValueTree& state);
|
|
|
|
ValueTree& getState() noexcept { return state; }
|
|
int getNumMarkers() const;
|
|
ValueTree getMarkerState (int index) const;
|
|
ValueTree getMarkerState (const String& name) const;
|
|
bool containsMarker (const ValueTree& state) const;
|
|
MarkerList::Marker getMarker (const ValueTree& state) const;
|
|
void setMarker (const MarkerList::Marker& marker, UndoManager* undoManager);
|
|
void removeMarker (const ValueTree& state, UndoManager* undoManager);
|
|
|
|
void applyTo (MarkerList& markerList);
|
|
void readFrom (const MarkerList& markerList, UndoManager* undoManager);
|
|
|
|
static const Identifier markerTag, nameProperty, posProperty;
|
|
|
|
private:
|
|
ValueTree state;
|
|
};
|
|
|
|
private:
|
|
|
|
OwnedArray<Marker> markers;
|
|
ListenerList<Listener> listeners;
|
|
|
|
JUCE_LEAK_DETECTOR (MarkerList);
|
|
};
|
|
|
|
#endif // __JUCE_MARKERLIST_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MarkerList.h ***/
|
|
|
|
/**
|
|
Base class for Component::Positioners that are based upon relative coordinates.
|
|
*/
|
|
class JUCE_API RelativeCoordinatePositionerBase : public Component::Positioner,
|
|
public ComponentListener,
|
|
public MarkerList::Listener
|
|
{
|
|
public:
|
|
RelativeCoordinatePositionerBase (Component& component_);
|
|
~RelativeCoordinatePositionerBase();
|
|
|
|
void componentMovedOrResized (Component&, bool, bool);
|
|
void componentParentHierarchyChanged (Component&);
|
|
void componentChildrenChanged (Component& component);
|
|
void componentBeingDeleted (Component& component);
|
|
void markersChanged (MarkerList*);
|
|
void markerListBeingDeleted (MarkerList* markerList);
|
|
|
|
void apply();
|
|
|
|
bool addCoordinate (const RelativeCoordinate& coord);
|
|
bool addPoint (const RelativePoint& point);
|
|
|
|
/** Used for resolving a RelativeCoordinate expression in the context of a component. */
|
|
class ComponentScope : public Expression::Scope
|
|
{
|
|
public:
|
|
ComponentScope (Component& component_);
|
|
|
|
Expression getSymbolValue (const String& symbol) const;
|
|
void visitRelativeScope (const String& scopeName, Visitor& visitor) const;
|
|
String getScopeUID() const;
|
|
|
|
protected:
|
|
Component& component;
|
|
|
|
Component* findSiblingComponent (const String& componentID) const;
|
|
const MarkerList::Marker* findMarker (const String& name, MarkerList*& list) const;
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE (ComponentScope);
|
|
};
|
|
|
|
protected:
|
|
virtual bool registerCoordinates() = 0;
|
|
virtual void applyToComponentBounds() = 0;
|
|
|
|
private:
|
|
class DependencyFinderScope;
|
|
friend class DependencyFinderScope;
|
|
Array <Component*> sourceComponents;
|
|
Array <MarkerList*> sourceMarkerLists;
|
|
bool registeredOk;
|
|
|
|
void registerComponentListener (Component& comp);
|
|
void registerMarkerListListener (MarkerList* const list);
|
|
void unregisterListeners();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (RelativeCoordinatePositionerBase);
|
|
};
|
|
|
|
#endif // __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_RelativeCoordinatePositioner.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_ComponentBuilder.h ***/
|
|
#ifndef __JUCE_COMPONENTBUILDER_JUCEHEADER__
|
|
#define __JUCE_COMPONENTBUILDER_JUCEHEADER__
|
|
|
|
/**
|
|
Loads and maintains a tree of Components from a ValueTree that represents them.
|
|
|
|
To allow the state of a tree of components to be saved as a ValueTree and re-loaded,
|
|
this class lets you register a set of type-handlers for the different components that
|
|
are involved, and then uses these types to re-create a set of components from its
|
|
stored state.
|
|
|
|
Essentially, to use this, you need to create a ComponentBuilder with your ValueTree,
|
|
then use registerTypeHandler() to give it a set of type handlers that can cope with
|
|
all the items in your tree. Then you can call getComponent() to build the component.
|
|
Once you've got the component you can either take it and delete the ComponentBuilder
|
|
object, or if you keep the ComponentBuilder around, it'll monitor any changes in the
|
|
ValueTree and automatically update the component to reflect these changes.
|
|
*/
|
|
class JUCE_API ComponentBuilder : public ValueTree::Listener
|
|
{
|
|
public:
|
|
/** Creates a ComponentBuilder that will use the given state.
|
|
Once you've created your builder, you should use registerTypeHandler() to register some
|
|
type handlers for it, and then you can call createComponent() or getManagedComponent()
|
|
to get the actual component.
|
|
*/
|
|
explicit ComponentBuilder (const ValueTree& state);
|
|
|
|
/** Destructor. */
|
|
~ComponentBuilder();
|
|
|
|
/** Returns the ValueTree that this builder is working with. */
|
|
ValueTree& getState() noexcept { return state; }
|
|
|
|
/** Returns the ValueTree that this builder is working with. */
|
|
const ValueTree& getState() const noexcept { return state; }
|
|
|
|
/** Returns the builder's component (creating it if necessary).
|
|
|
|
The first time that this method is called, the builder will attempt to create a component
|
|
from the ValueTree, so you must have registered some suitable type handlers before calling
|
|
this. If there's a problem and the component can't be created, this method returns 0.
|
|
|
|
The component that is returned is owned by this ComponentBuilder, so you can put it inside
|
|
your own parent components, but don't delete it! The ComponentBuilder will delete it automatically
|
|
when the builder is destroyed. If you want to get a component that you can delete yourself,
|
|
call createComponent() instead.
|
|
|
|
The ComponentBuilder will update this component if any changes are made to the ValueTree, so if
|
|
there's a chance that the tree might change, be careful not to keep any pointers to sub-components,
|
|
as they may be changed or removed.
|
|
*/
|
|
Component* getManagedComponent();
|
|
|
|
/** Creates and returns a new instance of the component that the ValueTree represents.
|
|
The caller is responsible for using and deleting the object that is returned. Unlike
|
|
getManagedComponent(), the component that is returned will not be updated by the builder.
|
|
*/
|
|
Component* createComponent();
|
|
|
|
/**
|
|
The class is a base class for objects that manage the loading of a type of component
|
|
from a ValueTree.
|
|
|
|
To store and re-load a tree of components as a ValueTree, each component type must have
|
|
a TypeHandler to represent it.
|
|
|
|
@see ComponentBuilder::registerTypeHandler(), Drawable::registerDrawableTypeHandlers()
|
|
*/
|
|
class JUCE_API TypeHandler
|
|
{
|
|
public:
|
|
|
|
/** Creates a TypeHandler.
|
|
The valueTreeType must be the type name of the ValueTrees that this handler can parse.
|
|
*/
|
|
explicit TypeHandler (const Identifier& valueTreeType);
|
|
|
|
/** Destructor. */
|
|
virtual ~TypeHandler();
|
|
|
|
/** Returns the type of the ValueTrees that this handler can parse. */
|
|
const Identifier& getType() const noexcept { return valueTreeType; }
|
|
|
|
/** Returns the builder that this type is registered with. */
|
|
ComponentBuilder* getBuilder() const noexcept;
|
|
|
|
/** This method must create a new component from the given state, add it to the specified
|
|
parent component (which may be null), and return it.
|
|
|
|
The ValueTree will have been pre-checked to make sure that its type matches the type
|
|
that this handler supports.
|
|
|
|
There's no need to set the new Component's ID to match that of the state - the builder
|
|
will take care of that itself.
|
|
*/
|
|
virtual Component* addNewComponentFromState (const ValueTree& state, Component* parent) = 0;
|
|
|
|
/** This method must update an existing component from a new ValueTree state.
|
|
|
|
A component that has been created with addNewComponentFromState() may need to be updated
|
|
if the ValueTree changes, so this method is used to do that. Your implementation must do
|
|
whatever's necessary to update the component from the new state provided.
|
|
|
|
The ValueTree will have been pre-checked to make sure that its type matches the type
|
|
that this handler supports, and the component will have been created by this type's
|
|
addNewComponentFromState() method.
|
|
*/
|
|
virtual void updateComponentFromState (Component* component, const ValueTree& state) = 0;
|
|
|
|
private:
|
|
|
|
friend class ComponentBuilder;
|
|
ComponentBuilder* builder;
|
|
const Identifier valueTreeType;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TypeHandler);
|
|
};
|
|
|
|
/** Adds a type handler that the builder can use when trying to load components.
|
|
@see Drawable::registerDrawableTypeHandlers()
|
|
*/
|
|
void registerTypeHandler (TypeHandler* type);
|
|
|
|
/** Tries to find a registered type handler that can load a component from the given ValueTree. */
|
|
TypeHandler* getHandlerForState (const ValueTree& state) const;
|
|
|
|
/** Returns the number of registered type handlers.
|
|
@see getHandler, registerTypeHandler
|
|
*/
|
|
int getNumHandlers() const noexcept;
|
|
|
|
/** Returns one of the registered type handlers.
|
|
@see getNumHandlers, registerTypeHandler
|
|
*/
|
|
TypeHandler* getHandler (int index) const noexcept;
|
|
|
|
/** This class is used when references to images need to be stored in ValueTrees.
|
|
|
|
An instance of an ImageProvider provides a mechanism for converting an Image to/from
|
|
a reference, which may be a file, URL, ID string, or whatever system is appropriate in
|
|
your app.
|
|
|
|
When you're loading components from a ValueTree that may need a way of loading images, you
|
|
should call ComponentBuilder::setImageProvider() to supply a suitable provider before
|
|
trying to load the component.
|
|
|
|
@see ComponentBuilder::setImageProvider()
|
|
*/
|
|
class JUCE_API ImageProvider
|
|
{
|
|
public:
|
|
ImageProvider() {}
|
|
virtual ~ImageProvider() {}
|
|
|
|
/** Retrieves the image associated with this identifier, which could be any
|
|
kind of string, number, filename, etc.
|
|
|
|
The image that is returned will be owned by the caller, but it may come
|
|
from the ImageCache.
|
|
*/
|
|
virtual Image getImageForIdentifier (const var& imageIdentifier) = 0;
|
|
|
|
/** Returns an identifier to be used to refer to a given image.
|
|
This is used when a reference to an image is stored in a ValueTree.
|
|
*/
|
|
virtual var getIdentifierForImage (const Image& image) = 0;
|
|
};
|
|
|
|
/** Gives the builder an ImageProvider object that the type handlers can use when
|
|
loading images from stored references.
|
|
|
|
The object that is passed in is not owned by the builder, so the caller must delete
|
|
it when it is no longer needed, but not while the builder may still be using it. To
|
|
clear the image provider, just call setImageProvider (nullptr).
|
|
*/
|
|
void setImageProvider (ImageProvider* newImageProvider) noexcept;
|
|
|
|
/** Returns the current image provider that this builder is using, or 0 if none has been set. */
|
|
ImageProvider* getImageProvider() const noexcept;
|
|
|
|
/** Updates the children of a parent component by updating them from the children of
|
|
a given ValueTree.
|
|
*/
|
|
void updateChildComponents (Component& parent, const ValueTree& children);
|
|
|
|
/** An identifier for the property of the ValueTrees that is used to store a unique ID
|
|
for that component.
|
|
*/
|
|
static const Identifier idProperty;
|
|
|
|
/** @internal */
|
|
void valueTreePropertyChanged (ValueTree& treeWhosePropertyHasChanged, const Identifier& property);
|
|
/** @internal */
|
|
void valueTreeChildAdded (ValueTree& parentTree, ValueTree& childWhichHasBeenAdded);
|
|
/** @internal */
|
|
void valueTreeChildRemoved (ValueTree& parentTree, ValueTree& childWhichHasBeenRemoved);
|
|
/** @internal */
|
|
void valueTreeChildOrderChanged (ValueTree& parentTree);
|
|
/** @internal */
|
|
void valueTreeParentChanged (ValueTree& treeWhoseParentHasChanged);
|
|
|
|
private:
|
|
|
|
ValueTree state;
|
|
OwnedArray <TypeHandler> types;
|
|
ScopedPointer<Component> component;
|
|
ImageProvider* imageProvider;
|
|
#if JUCE_DEBUG
|
|
WeakReference<Component> componentRef;
|
|
#endif
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentBuilder);
|
|
};
|
|
|
|
#endif // __JUCE_COMPONENTBUILDER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ComponentBuilder.h ***/
|
|
|
|
class DrawableComposite;
|
|
|
|
/**
|
|
The base class for objects which can draw themselves, e.g. polygons, images, etc.
|
|
|
|
@see DrawableComposite, DrawableImage, DrawablePath, DrawableText
|
|
*/
|
|
class JUCE_API Drawable : public Component
|
|
{
|
|
protected:
|
|
|
|
/** The base class can't be instantiated directly.
|
|
|
|
@see DrawableComposite, DrawableImage, DrawablePath, DrawableText
|
|
*/
|
|
Drawable();
|
|
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~Drawable();
|
|
|
|
/** Creates a deep copy of this Drawable object.
|
|
|
|
Use this to create a new copy of this and any sub-objects in the tree.
|
|
*/
|
|
virtual Drawable* createCopy() const = 0;
|
|
|
|
/** Renders this Drawable object.
|
|
|
|
Note that the preferred way to render a drawable in future is by using it
|
|
as a component and adding it to a parent, so you might want to consider that
|
|
before using this method.
|
|
|
|
@see drawWithin
|
|
*/
|
|
void draw (Graphics& g, float opacity,
|
|
const AffineTransform& transform = AffineTransform::identity) const;
|
|
|
|
/** Renders the Drawable at a given offset within the Graphics context.
|
|
|
|
The co-ordinates passed-in are used to translate the object relative to its own
|
|
origin before drawing it - this is basically a quick way of saying:
|
|
|
|
@code
|
|
draw (g, AffineTransform::translation (x, y)).
|
|
@endcode
|
|
|
|
Note that the preferred way to render a drawable in future is by using it
|
|
as a component and adding it to a parent, so you might want to consider that
|
|
before using this method.
|
|
*/
|
|
void drawAt (Graphics& g, float x, float y, float opacity) const;
|
|
|
|
/** Renders the Drawable within a rectangle, scaling it to fit neatly inside without
|
|
changing its aspect-ratio.
|
|
|
|
The object can placed arbitrarily within the rectangle based on a Justification type,
|
|
and can either be made as big as possible, or just reduced to fit.
|
|
|
|
Note that the preferred way to render a drawable in future is by using it
|
|
as a component and adding it to a parent, so you might want to consider that
|
|
before using this method.
|
|
|
|
@param g the graphics context to render onto
|
|
@param destArea the target rectangle to fit the drawable into
|
|
@param placement defines the alignment and rescaling to use to fit
|
|
this object within the target rectangle.
|
|
@param opacity the opacity to use, in the range 0 to 1.0
|
|
*/
|
|
void drawWithin (Graphics& g,
|
|
const Rectangle<float>& destArea,
|
|
const RectanglePlacement& placement,
|
|
float opacity) const;
|
|
|
|
/** Resets any transformations on this drawable, and positions its origin within
|
|
its parent component.
|
|
*/
|
|
void setOriginWithOriginalSize (const Point<float>& originWithinParent);
|
|
|
|
/** Sets a transform for this drawable that will position it within the specified
|
|
area of its parent component.
|
|
*/
|
|
void setTransformToFit (const Rectangle<float>& areaInParent, const RectanglePlacement& placement);
|
|
|
|
/** Returns the DrawableComposite that contains this object, if there is one. */
|
|
DrawableComposite* getParent() const;
|
|
|
|
/** Tries to turn some kind of image file into a drawable.
|
|
|
|
The data could be an image that the ImageFileFormat class understands, or it
|
|
could be SVG.
|
|
*/
|
|
static Drawable* createFromImageData (const void* data, size_t numBytes);
|
|
|
|
/** Tries to turn a stream containing some kind of image data into a drawable.
|
|
|
|
The data could be an image that the ImageFileFormat class understands, or it
|
|
could be SVG.
|
|
*/
|
|
static Drawable* createFromImageDataStream (InputStream& dataSource);
|
|
|
|
/** Tries to turn a file containing some kind of image data into a drawable.
|
|
|
|
The data could be an image that the ImageFileFormat class understands, or it
|
|
could be SVG.
|
|
*/
|
|
static Drawable* createFromImageFile (const File& file);
|
|
|
|
/** Attempts to parse an SVG (Scalable Vector Graphics) document, and to turn this
|
|
into a Drawable tree.
|
|
|
|
The object returned must be deleted by the caller. If something goes wrong
|
|
while parsing, it may return 0.
|
|
|
|
SVG is a pretty large and complex spec, and this doesn't aim to be a full
|
|
implementation, but it can return the basic vector objects.
|
|
*/
|
|
static Drawable* createFromSVG (const XmlElement& svgDocument);
|
|
|
|
/** Tries to create a Drawable from a previously-saved ValueTree.
|
|
The ValueTree must have been created by the createValueTree() method.
|
|
If there are any images used within the drawable, you'll need to provide a valid
|
|
ImageProvider object that can be used to retrieve these images from whatever type
|
|
of identifier is used to represent them.
|
|
Internally, this uses a ComponentBuilder, and registerDrawableTypeHandlers().
|
|
*/
|
|
static Drawable* createFromValueTree (const ValueTree& tree, ComponentBuilder::ImageProvider* imageProvider);
|
|
|
|
/** Creates a ValueTree to represent this Drawable.
|
|
The ValueTree that is returned can be turned back into a Drawable with createFromValueTree().
|
|
If there are any images used in this drawable, you'll need to provide a valid ImageProvider
|
|
object that can be used to create storable representations of them.
|
|
*/
|
|
virtual ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const = 0;
|
|
|
|
/** Returns the area that this drawble covers.
|
|
The result is expressed in this drawable's own coordinate space, and does not take
|
|
into account any transforms that may be applied to the component.
|
|
*/
|
|
virtual Rectangle<float> getDrawableBounds() const = 0;
|
|
|
|
/** Internal class used to manage ValueTrees that represent Drawables. */
|
|
class ValueTreeWrapperBase
|
|
{
|
|
public:
|
|
ValueTreeWrapperBase (const ValueTree& state);
|
|
|
|
ValueTree& getState() noexcept { return state; }
|
|
|
|
String getID() const;
|
|
void setID (const String& newID);
|
|
|
|
ValueTree state;
|
|
};
|
|
|
|
/** Registers a set of ComponentBuilder::TypeHandler objects that can be used to
|
|
load all the different Drawable types from a saved state.
|
|
@see ComponentBuilder::registerTypeHandler()
|
|
*/
|
|
static void registerDrawableTypeHandlers (ComponentBuilder& componentBuilder);
|
|
|
|
protected:
|
|
|
|
friend class DrawableComposite;
|
|
friend class DrawableShape;
|
|
|
|
/** @internal */
|
|
void transformContextToCorrectOrigin (Graphics& g);
|
|
/** @internal */
|
|
void parentHierarchyChanged();
|
|
/** @internal */
|
|
void setBoundsToEnclose (const Rectangle<float>& area);
|
|
|
|
Point<int> originRelativeToComponent;
|
|
|
|
#ifndef DOXYGEN
|
|
/** Internal utility class used by Drawables. */
|
|
template <class DrawableType>
|
|
class Positioner : public RelativeCoordinatePositionerBase
|
|
{
|
|
public:
|
|
Positioner (DrawableType& component_)
|
|
: RelativeCoordinatePositionerBase (component_),
|
|
owner (component_)
|
|
{}
|
|
|
|
bool registerCoordinates() { return owner.registerCoordinates (*this); }
|
|
void applyToComponentBounds()
|
|
{
|
|
ComponentScope scope (getComponent());
|
|
owner.recalculateCoordinates (&scope);
|
|
}
|
|
|
|
void applyNewBounds (const Rectangle<int>&)
|
|
{
|
|
jassertfalse; // drawables can't be resized directly!
|
|
}
|
|
|
|
private:
|
|
DrawableType& owner;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Positioner);
|
|
};
|
|
#endif
|
|
|
|
private:
|
|
void nonConstDraw (Graphics& g, float opacity, const AffineTransform& transform);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Drawable);
|
|
};
|
|
|
|
#endif // __JUCE_DRAWABLE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Drawable.h ***/
|
|
|
|
/**
|
|
A button that displays a Drawable.
|
|
|
|
Up to three Drawable objects can be given to this button, to represent the
|
|
'normal', 'over' and 'down' states.
|
|
|
|
@see Button
|
|
*/
|
|
class JUCE_API DrawableButton : public Button
|
|
{
|
|
public:
|
|
|
|
enum ButtonStyle
|
|
{
|
|
ImageFitted, /**< The button will just display the images, but will resize and centre them to fit inside it. */
|
|
ImageRaw, /**< The button will just display the images in their normal size and position.
|
|
This leaves it up to the caller to make sure the images are the correct size and position for the button. */
|
|
ImageAboveTextLabel, /**< Draws the button as a text label across the bottom with the image resized and scaled to fit above it. */
|
|
ImageOnButtonBackground /**< Draws the button as a standard rounded-rectangle button with the image on top. */
|
|
};
|
|
|
|
/** Creates a DrawableButton.
|
|
|
|
After creating one of these, use setImages() to specify the drawables to use.
|
|
|
|
@param buttonName the name to give the component
|
|
@param buttonStyle the layout to use
|
|
|
|
@see ButtonStyle, setButtonStyle, setImages
|
|
*/
|
|
DrawableButton (const String& buttonName,
|
|
ButtonStyle buttonStyle);
|
|
|
|
/** Destructor. */
|
|
~DrawableButton();
|
|
|
|
/** Sets up the images to draw for the various button states.
|
|
|
|
The button will keep its own internal copies of these drawables.
|
|
|
|
@param normalImage the thing to draw for the button's 'normal' state. An internal copy
|
|
will be made of the object passed-in if it is non-zero.
|
|
@param overImage the thing to draw for the button's 'over' state - if this is
|
|
zero, the button's normal image will be used when the mouse is
|
|
over it. An internal copy will be made of the object passed-in
|
|
if it is non-zero.
|
|
@param downImage the thing to draw for the button's 'down' state - if this is
|
|
zero, the 'over' image will be used instead (or the normal image
|
|
as a last resort). An internal copy will be made of the object
|
|
passed-in if it is non-zero.
|
|
@param disabledImage an image to draw when the button is disabled. If this is zero,
|
|
the normal image will be drawn with a reduced opacity instead.
|
|
An internal copy will be made of the object passed-in if it is
|
|
non-zero.
|
|
@param normalImageOn same as the normalImage, but this is used when the button's toggle
|
|
state is 'on'. If this is 0, the normal image is used instead
|
|
@param overImageOn same as the overImage, but this is used when the button's toggle
|
|
state is 'on'. If this is 0, the normalImageOn is drawn instead
|
|
@param downImageOn same as the downImage, but this is used when the button's toggle
|
|
state is 'on'. If this is 0, the overImageOn is drawn instead
|
|
@param disabledImageOn same as the disabledImage, but this is used when the button's toggle
|
|
state is 'on'. If this is 0, the normal image will be drawn instead
|
|
with a reduced opacity
|
|
*/
|
|
void setImages (const Drawable* normalImage,
|
|
const Drawable* overImage = nullptr,
|
|
const Drawable* downImage = nullptr,
|
|
const Drawable* disabledImage = nullptr,
|
|
const Drawable* normalImageOn = nullptr,
|
|
const Drawable* overImageOn = nullptr,
|
|
const Drawable* downImageOn = nullptr,
|
|
const Drawable* disabledImageOn = nullptr);
|
|
|
|
/** Changes the button's style.
|
|
|
|
@see ButtonStyle
|
|
*/
|
|
void setButtonStyle (ButtonStyle newStyle);
|
|
|
|
/** Changes the button's background colours.
|
|
|
|
The toggledOffColour is the colour to use when the button's toggle state
|
|
is off, and toggledOnColour when it's on.
|
|
|
|
For an ImageOnly or ImageAboveTextLabel style, the background colour is
|
|
used to fill the background of the component.
|
|
|
|
For an ImageOnButtonBackground style, the colour is used to draw the
|
|
button's lozenge shape and exactly how the colour's used will depend
|
|
on the LookAndFeel.
|
|
*/
|
|
void setBackgroundColours (const Colour& toggledOffColour,
|
|
const Colour& toggledOnColour);
|
|
|
|
/** Returns the current background colour being used.
|
|
|
|
@see setBackgroundColour
|
|
*/
|
|
const Colour& getBackgroundColour() const noexcept;
|
|
|
|
/** Gives the button an optional amount of space around the edge of the drawable.
|
|
|
|
This will only apply to ImageFitted or ImageRaw styles, it won't affect the
|
|
ones on a button background. If the button is too small for the given gap, a
|
|
smaller gap will be used.
|
|
|
|
By default there's a gap of about 3 pixels.
|
|
*/
|
|
void setEdgeIndent (int numPixelsIndent);
|
|
|
|
/** Returns the image that the button is currently displaying. */
|
|
Drawable* getCurrentImage() const noexcept;
|
|
Drawable* getNormalImage() const noexcept;
|
|
Drawable* getOverImage() const noexcept;
|
|
Drawable* getDownImage() const noexcept;
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the link.
|
|
|
|
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
|
|
{
|
|
textColourId = 0x1004010, /**< The colour to use for the URL text. */
|
|
};
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void paintButton (Graphics& g,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
/** @internal */
|
|
void buttonStateChanged();
|
|
/** @internal */
|
|
void resized();
|
|
|
|
private:
|
|
|
|
ButtonStyle style;
|
|
ScopedPointer <Drawable> normalImage, overImage, downImage, disabledImage;
|
|
ScopedPointer <Drawable> normalImageOn, overImageOn, downImageOn, disabledImageOn;
|
|
Drawable* currentImage;
|
|
Colour backgroundOff, backgroundOn;
|
|
int edgeIndent;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DrawableButton);
|
|
};
|
|
|
|
#endif // __JUCE_DRAWABLEBUTTON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DrawableButton.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_HYPERLINKBUTTON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_HyperlinkButton.h ***/
|
|
#ifndef __JUCE_HYPERLINKBUTTON_JUCEHEADER__
|
|
#define __JUCE_HYPERLINKBUTTON_JUCEHEADER__
|
|
|
|
/**
|
|
A button showing an underlined weblink, that will launch the link
|
|
when it's clicked.
|
|
|
|
@see Button
|
|
*/
|
|
class JUCE_API HyperlinkButton : public Button
|
|
{
|
|
public:
|
|
|
|
/** Creates a HyperlinkButton.
|
|
|
|
@param linkText the text that will be displayed in the button - this is
|
|
also set as the Component's name, but the text can be
|
|
changed later with the Button::getButtonText() method
|
|
@param linkURL the URL to launch when the user clicks the button
|
|
*/
|
|
HyperlinkButton (const String& linkText,
|
|
const URL& linkURL);
|
|
|
|
/** Destructor. */
|
|
~HyperlinkButton();
|
|
|
|
/** Changes the font to use for the text.
|
|
|
|
If resizeToMatchComponentHeight is true, the font's height will be adjusted
|
|
to match the size of the component.
|
|
*/
|
|
void setFont (const Font& newFont,
|
|
bool resizeToMatchComponentHeight,
|
|
const Justification& justificationType = Justification::horizontallyCentred);
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the link.
|
|
|
|
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
|
|
{
|
|
textColourId = 0x1001f00, /**< The colour to use for the URL text. */
|
|
};
|
|
|
|
/** Changes the URL that the button will trigger. */
|
|
void setURL (const URL& newURL) noexcept;
|
|
|
|
/** Returns the URL that the button will trigger. */
|
|
const URL& getURL() const noexcept { return url; }
|
|
|
|
/** Resizes the button horizontally to fit snugly around the text.
|
|
|
|
This won't affect the button's height.
|
|
*/
|
|
void changeWidthToFitText();
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void clicked();
|
|
/** @internal */
|
|
void colourChanged();
|
|
/** @internal */
|
|
void paintButton (Graphics& g,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
private:
|
|
|
|
URL url;
|
|
Font font;
|
|
bool resizeFont;
|
|
Justification justification;
|
|
|
|
Font getFontToUse() const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HyperlinkButton);
|
|
};
|
|
|
|
#endif // __JUCE_HYPERLINKBUTTON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_HyperlinkButton.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_IMAGEBUTTON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ImageButton.h ***/
|
|
#ifndef __JUCE_IMAGEBUTTON_JUCEHEADER__
|
|
#define __JUCE_IMAGEBUTTON_JUCEHEADER__
|
|
|
|
/**
|
|
As the title suggests, this is a button containing an image.
|
|
|
|
The colour and transparency of the image can be set to vary when the
|
|
button state changes.
|
|
|
|
@see Button, ShapeButton, TextButton
|
|
*/
|
|
class JUCE_API ImageButton : public Button
|
|
{
|
|
public:
|
|
|
|
/** Creates an ImageButton.
|
|
|
|
Use setImage() to specify the image to use. The colours and opacities that
|
|
are specified here can be changed later using setDrawingOptions().
|
|
|
|
@param name the name to give the component
|
|
*/
|
|
explicit ImageButton (const String& name);
|
|
|
|
/** Destructor. */
|
|
~ImageButton();
|
|
|
|
/** Sets up the images to draw in various states.
|
|
|
|
@param resizeButtonNowToFitThisImage if true, the button will be immediately
|
|
resized to the same dimensions as the normal image
|
|
@param rescaleImagesWhenButtonSizeChanges if true, the image will be rescaled to fit the
|
|
button when the button's size changes
|
|
@param preserveImageProportions if true then any rescaling of the image to fit
|
|
the button will keep the image's x and y proportions
|
|
correct - i.e. it won't distort its shape, although
|
|
this might create gaps around the edges
|
|
@param normalImage the image to use when the button is in its normal state.
|
|
button no longer needs it.
|
|
@param imageOpacityWhenNormal the opacity to use when drawing the normal image.
|
|
@param overlayColourWhenNormal an overlay colour to use to fill the alpha channel of the
|
|
normal image - if this colour is transparent, no overlay
|
|
will be drawn. The overlay will be drawn over the top of the
|
|
image, so you can basically add a solid or semi-transparent
|
|
colour to the image to brighten or darken it
|
|
@param overImage the image to use when the mouse is over the button. If
|
|
you want to use the same image as was set in the normalImage
|
|
parameter, this value can be a null image.
|
|
@param imageOpacityWhenOver the opacity to use when drawing the image when the mouse
|
|
is over the button
|
|
@param overlayColourWhenOver an overlay colour to use to fill the alpha channel of the
|
|
image when the mouse is over - if this colour is transparent,
|
|
no overlay will be drawn
|
|
@param downImage an image to use when the button is pressed down. If set
|
|
to a null image, the 'over' image will be drawn instead (or the
|
|
normal image if there isn't an 'over' image either).
|
|
@param imageOpacityWhenDown the opacity to use when drawing the image when the button
|
|
is pressed
|
|
@param overlayColourWhenDown an overlay colour to use to fill the alpha channel of the
|
|
image when the button is pressed down - if this colour is
|
|
transparent, no overlay will be drawn
|
|
@param hitTestAlphaThreshold if set to zero, the mouse is considered to be over the button
|
|
whenever it's inside the button's bounding rectangle. If
|
|
set to values higher than 0, the mouse will only be
|
|
considered to be over the image when the value of the
|
|
image's alpha channel at that position is greater than
|
|
this level.
|
|
*/
|
|
void setImages (bool resizeButtonNowToFitThisImage,
|
|
bool rescaleImagesWhenButtonSizeChanges,
|
|
bool preserveImageProportions,
|
|
const Image& normalImage,
|
|
float imageOpacityWhenNormal,
|
|
const Colour& overlayColourWhenNormal,
|
|
const Image& overImage,
|
|
float imageOpacityWhenOver,
|
|
const Colour& overlayColourWhenOver,
|
|
const Image& downImage,
|
|
float imageOpacityWhenDown,
|
|
const Colour& overlayColourWhenDown,
|
|
float hitTestAlphaThreshold = 0.0f);
|
|
|
|
/** Returns the currently set 'normal' image. */
|
|
Image getNormalImage() const;
|
|
|
|
/** Returns the image that's drawn when the mouse is over the button.
|
|
|
|
If a valid 'over' image has been set, this will return it; otherwise it'll
|
|
just return the normal image.
|
|
*/
|
|
Image getOverImage() const;
|
|
|
|
/** Returns the image that's drawn when the button is held down.
|
|
|
|
If a valid 'down' image has been set, this will return it; otherwise it'll
|
|
return the 'over' image or normal image, depending on what's available.
|
|
*/
|
|
Image getDownImage() const;
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
bool hitTest (int x, int y);
|
|
/** @internal */
|
|
void paintButton (Graphics& g,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
private:
|
|
|
|
bool scaleImageToFit, preserveProportions;
|
|
unsigned char alphaThreshold;
|
|
int imageX, imageY, imageW, imageH;
|
|
Image normalImage, overImage, downImage;
|
|
float normalOpacity, overOpacity, downOpacity;
|
|
Colour normalOverlay, overOverlay, downOverlay;
|
|
|
|
Image getCurrentImage() const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageButton);
|
|
};
|
|
|
|
#endif // __JUCE_IMAGEBUTTON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ImageButton.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SHAPEBUTTON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ShapeButton.h ***/
|
|
#ifndef __JUCE_SHAPEBUTTON_JUCEHEADER__
|
|
#define __JUCE_SHAPEBUTTON_JUCEHEADER__
|
|
|
|
/**
|
|
A button that contains a filled shape.
|
|
|
|
@see Button, ImageButton, TextButton, ArrowButton
|
|
*/
|
|
class JUCE_API ShapeButton : public Button
|
|
{
|
|
public:
|
|
|
|
/** Creates a ShapeButton.
|
|
|
|
@param name a name to give the component - see Component::setName()
|
|
@param normalColour the colour to fill the shape with when the mouse isn't over
|
|
@param overColour the colour to use when the mouse is over the shape
|
|
@param downColour the colour to use when the button is in the pressed-down state
|
|
*/
|
|
ShapeButton (const String& name,
|
|
const Colour& normalColour,
|
|
const Colour& overColour,
|
|
const Colour& downColour);
|
|
|
|
/** Destructor. */
|
|
~ShapeButton();
|
|
|
|
/** Sets the shape to use.
|
|
|
|
@param newShape the shape to use
|
|
@param resizeNowToFitThisShape if true, the button will be resized to fit the shape's bounds
|
|
@param maintainShapeProportions if true, the shape's proportions will be kept fixed when
|
|
the button is resized
|
|
@param hasDropShadow if true, the button will be given a drop-shadow effect
|
|
*/
|
|
void setShape (const Path& newShape,
|
|
bool resizeNowToFitThisShape,
|
|
bool maintainShapeProportions,
|
|
bool hasDropShadow);
|
|
|
|
/** Set the colours to use for drawing the shape.
|
|
|
|
@param normalColour the colour to fill the shape with when the mouse isn't over
|
|
@param overColour the colour to use when the mouse is over the shape
|
|
@param downColour the colour to use when the button is in the pressed-down state
|
|
*/
|
|
void setColours (const Colour& normalColour,
|
|
const Colour& overColour,
|
|
const Colour& downColour);
|
|
|
|
/** Sets up an outline to draw around the shape.
|
|
|
|
@param outlineColour the colour to use
|
|
@param outlineStrokeWidth the thickness of line to draw
|
|
*/
|
|
void setOutline (const Colour& outlineColour,
|
|
float outlineStrokeWidth);
|
|
|
|
protected:
|
|
/** @internal */
|
|
void paintButton (Graphics& g,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
private:
|
|
|
|
Colour normalColour, overColour, downColour, outlineColour;
|
|
DropShadowEffect shadow;
|
|
Path shape;
|
|
bool maintainShapeProportions;
|
|
float outlineWidth;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ShapeButton);
|
|
};
|
|
|
|
#endif // __JUCE_SHAPEBUTTON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ShapeButton.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TEXTBUTTON_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOGGLEBUTTON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ToggleButton.h ***/
|
|
#ifndef __JUCE_TOGGLEBUTTON_JUCEHEADER__
|
|
#define __JUCE_TOGGLEBUTTON_JUCEHEADER__
|
|
|
|
/**
|
|
A button that can be toggled on/off.
|
|
|
|
All buttons can be toggle buttons, but this lets you create one of the
|
|
standard ones which has a tick-box and a text label next to it.
|
|
|
|
@see Button, DrawableButton, TextButton
|
|
*/
|
|
class JUCE_API ToggleButton : public Button
|
|
{
|
|
public:
|
|
|
|
/** Creates a ToggleButton.
|
|
|
|
@param buttonText 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 ToggleButton (const String& buttonText = String::empty);
|
|
|
|
/** Destructor. */
|
|
~ToggleButton();
|
|
|
|
/** Resizes the button to fit neatly around its current text.
|
|
|
|
The button's height won't be affected, only its width.
|
|
*/
|
|
void changeWidthToFitText();
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the button.
|
|
|
|
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
|
|
{
|
|
textColourId = 0x1006501 /**< The colour to use for the button's text. */
|
|
};
|
|
|
|
protected:
|
|
/** @internal */
|
|
void paintButton (Graphics& g,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
/** @internal */
|
|
void colourChanged();
|
|
|
|
private:
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToggleButton);
|
|
};
|
|
|
|
#endif // __JUCE_TOGGLEBUTTON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ToggleButton.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOOLBARBUTTON_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ToolbarButton.h ***/
|
|
#ifndef __JUCE_TOOLBARBUTTON_JUCEHEADER__
|
|
#define __JUCE_TOOLBARBUTTON_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_ToolbarItemComponent.h ***/
|
|
#ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_Toolbar.h ***/
|
|
#ifndef __JUCE_TOOLBAR_JUCEHEADER__
|
|
#define __JUCE_TOOLBAR_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_DragAndDropContainer.h ***/
|
|
#ifndef __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__
|
|
#define __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_DragAndDropTarget.h ***/
|
|
#ifndef __JUCE_DRAGANDDROPTARGET_JUCEHEADER__
|
|
#define __JUCE_DRAGANDDROPTARGET_JUCEHEADER__
|
|
|
|
/**
|
|
Components derived from this class can have things dropped onto them by a DragAndDropContainer.
|
|
|
|
To create a component that can receive things drag-and-dropped by a DragAndDropContainer,
|
|
derive your component from this class, and make sure that it is somewhere inside a
|
|
DragAndDropContainer component.
|
|
|
|
Note: If all that you need to do is to respond to files being drag-and-dropped from
|
|
the operating system onto your component, you don't need any of these classes: instead
|
|
see the FileDragAndDropTarget class.
|
|
|
|
@see DragAndDropContainer, FileDragAndDropTarget
|
|
*/
|
|
class JUCE_API DragAndDropTarget
|
|
{
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~DragAndDropTarget() {}
|
|
|
|
/** Contains details about the source of a drag-and-drop operation.
|
|
The contents of this
|
|
*/
|
|
class JUCE_API SourceDetails
|
|
{
|
|
public:
|
|
/** Creates a SourceDetails object from its various settings. */
|
|
SourceDetails (const var& description, Component* sourceComponent, const Point<int>& localPosition) noexcept;
|
|
|
|
/** A descriptor for the drag - this is set DragAndDropContainer::startDragging(). */
|
|
var description;
|
|
|
|
/** The component from the drag operation was started. */
|
|
WeakReference<Component> sourceComponent;
|
|
|
|
/** The local position of the mouse, relative to the target component.
|
|
Note that for calls such as isInterestedInDragSource(), this may be a null position.
|
|
*/
|
|
Point<int> localPosition;
|
|
};
|
|
|
|
/** Callback to check whether this target is interested in the type of object being
|
|
dragged.
|
|
|
|
@param dragSourceDetails contains information about the source of the drag operation.
|
|
@returns true if this component wants to receive the other callbacks regarging this
|
|
type of object; if it returns false, no other callbacks will be made.
|
|
*/
|
|
virtual bool isInterestedInDragSource (const SourceDetails& dragSourceDetails) = 0;
|
|
|
|
/** Callback to indicate that something is being dragged over this component.
|
|
|
|
This gets called when the user moves the mouse into this component while dragging
|
|
something.
|
|
|
|
Use this callback as a trigger to make your component repaint itself to give the
|
|
user feedback about whether the item can be dropped here or not.
|
|
|
|
@param dragSourceDetails contains information about the source of the drag operation.
|
|
@see itemDragExit
|
|
*/
|
|
virtual void itemDragEnter (const SourceDetails& dragSourceDetails);
|
|
|
|
/** Callback to indicate that the user is dragging something over this component.
|
|
|
|
This gets called when the user moves the mouse over this component while dragging
|
|
something. Normally overriding itemDragEnter() and itemDragExit() are enough, but
|
|
this lets you know what happens in-between.
|
|
|
|
@param dragSourceDetails contains information about the source of the drag operation.
|
|
*/
|
|
virtual void itemDragMove (const SourceDetails& dragSourceDetails);
|
|
|
|
/** Callback to indicate that something has been dragged off the edge of this component.
|
|
|
|
This gets called when the user moves the mouse out of this component while dragging
|
|
something.
|
|
|
|
If you've used itemDragEnter() to repaint your component and give feedback, use this
|
|
as a signal to repaint it in its normal state.
|
|
|
|
@param dragSourceDetails contains information about the source of the drag operation.
|
|
@see itemDragEnter
|
|
*/
|
|
virtual void itemDragExit (const SourceDetails& dragSourceDetails);
|
|
|
|
/** Callback to indicate that the user has dropped something onto this component.
|
|
|
|
When the user drops an item this get called, and you can use the description to
|
|
work out whether your object wants to deal with it or not.
|
|
|
|
Note that after this is called, the itemDragExit method may not be called, so you should
|
|
clean up in here if there's anything you need to do when the drag finishes.
|
|
|
|
@param dragSourceDetails contains information about the source of the drag operation.
|
|
*/
|
|
virtual void itemDropped (const SourceDetails& dragSourceDetails) = 0;
|
|
|
|
/** Overriding this allows the target to tell the drag container whether to
|
|
draw the drag image while the cursor is over it.
|
|
|
|
By default it returns true, but if you return false, then the normal drag
|
|
image will not be shown when the cursor is over this target.
|
|
*/
|
|
virtual bool shouldDrawDragImageWhenOver();
|
|
|
|
private:
|
|
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
|
// The parameters for these methods have changed - please update your code!
|
|
virtual void isInterestedInDragSource (const String&, Component*) {}
|
|
virtual int itemDragEnter (const String&, Component*, int, int) { return 0; }
|
|
virtual int itemDragMove (const String&, Component*, int, int) { return 0; }
|
|
virtual int itemDragExit (const String&, Component*) { return 0; }
|
|
virtual int itemDropped (const String&, Component*, int, int) { return 0; }
|
|
#endif
|
|
};
|
|
|
|
#endif // __JUCE_DRAGANDDROPTARGET_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DragAndDropTarget.h ***/
|
|
|
|
/**
|
|
Enables drag-and-drop behaviour for a component and all its sub-components.
|
|
|
|
For a component to be able to make or receive drag-and-drop events, one of its parent
|
|
components must derive from this class. It's probably best for the top-level
|
|
component to implement it.
|
|
|
|
Then to start a drag operation, any sub-component can just call the startDragging()
|
|
method, and this object will take over, tracking the mouse and sending appropriate
|
|
callbacks to any child components derived from DragAndDropTarget which the mouse
|
|
moves over.
|
|
|
|
Note: If all that you need to do is to respond to files being drag-and-dropped from
|
|
the operating system onto your component, you don't need any of these classes: you can do this
|
|
simply by overriding Component::filesDropped().
|
|
|
|
@see DragAndDropTarget
|
|
*/
|
|
class JUCE_API DragAndDropContainer
|
|
{
|
|
public:
|
|
|
|
/** Creates a DragAndDropContainer.
|
|
|
|
The object that derives from this class must also be a Component.
|
|
*/
|
|
DragAndDropContainer();
|
|
|
|
/** Destructor. */
|
|
virtual ~DragAndDropContainer();
|
|
|
|
/** Begins a drag-and-drop operation.
|
|
|
|
This starts a drag-and-drop operation - call it when the user drags the
|
|
mouse in your drag-source component, and this object will track mouse
|
|
movements until the user lets go of the mouse button, and will send
|
|
appropriate messages to DragAndDropTarget objects that the mouse moves
|
|
over.
|
|
|
|
findParentDragContainerFor() is a handy method to call to find the
|
|
drag container to use for a component.
|
|
|
|
@param sourceDescription a string or value to use as the description of the thing being dragged -
|
|
this will be passed to the objects that might be dropped-onto so they can
|
|
decide whether they want to handle it
|
|
@param sourceComponent the component that is being dragged
|
|
@param dragImage the image to drag around underneath the mouse. If this is a null image,
|
|
a snapshot of the sourceComponent will be used instead.
|
|
@param allowDraggingToOtherJuceWindows if true, the dragged component will appear as a desktop
|
|
window, and can be dragged to DragAndDropTargets that are the
|
|
children of components other than this one.
|
|
@param imageOffsetFromMouse if an image has been passed-in, this specifies the offset
|
|
at which the image should be drawn from the mouse. If it isn't
|
|
specified, then the image will be centred around the mouse. If
|
|
an image hasn't been passed-in, this will be ignored.
|
|
*/
|
|
void startDragging (const var& sourceDescription,
|
|
Component* sourceComponent,
|
|
const Image& dragImage = Image::null,
|
|
bool allowDraggingToOtherJuceWindows = false,
|
|
const Point<int>* imageOffsetFromMouse = nullptr);
|
|
|
|
/** Returns true if something is currently being dragged. */
|
|
bool isDragAndDropActive() const;
|
|
|
|
/** Returns the description of the thing that's currently being dragged.
|
|
|
|
If nothing's being dragged, this will return an empty string, otherwise it's the
|
|
string that was passed into startDragging().
|
|
|
|
@see startDragging
|
|
*/
|
|
String getCurrentDragDescription() const;
|
|
|
|
/** Utility to find the DragAndDropContainer for a given Component.
|
|
|
|
This will search up this component's parent hierarchy looking for the first
|
|
parent component which is a DragAndDropContainer.
|
|
|
|
It's useful when a component wants to call startDragging but doesn't know
|
|
the DragAndDropContainer it should to use.
|
|
|
|
Obviously this may return 0 if it doesn't find a suitable component.
|
|
*/
|
|
static DragAndDropContainer* findParentDragContainerFor (Component* childComponent);
|
|
|
|
/** This performs a synchronous drag-and-drop of a set of files to some external
|
|
application.
|
|
|
|
You can call this function in response to a mouseDrag callback, and it will
|
|
block, running its own internal message loop and tracking the mouse, while it
|
|
uses a native operating system drag-and-drop operation to move or copy some
|
|
files to another application.
|
|
|
|
@param files a list of filenames to drag
|
|
@param canMoveFiles if true, the app that receives the files is allowed to move the files to a new location
|
|
(if this is appropriate). If false, the receiver is expected to make a copy of them.
|
|
@returns true if the files were successfully dropped somewhere, or false if it
|
|
was interrupted
|
|
@see performExternalDragDropOfText
|
|
*/
|
|
static bool performExternalDragDropOfFiles (const StringArray& files, bool canMoveFiles);
|
|
|
|
/** This performs a synchronous drag-and-drop of a block of text to some external
|
|
application.
|
|
|
|
You can call this function in response to a mouseDrag callback, and it will
|
|
block, running its own internal message loop and tracking the mouse, while it
|
|
uses a native operating system drag-and-drop operation to move or copy some
|
|
text to another application.
|
|
|
|
@param text the text to copy
|
|
@returns true if the text was successfully dropped somewhere, or false if it
|
|
was interrupted
|
|
@see performExternalDragDropOfFiles
|
|
*/
|
|
static bool performExternalDragDropOfText (const String& text);
|
|
|
|
protected:
|
|
/** Override this if you want to be able to perform an external drag a set of files
|
|
when the user drags outside of this container component.
|
|
|
|
This method will be called when a drag operation moves outside the Juce-based window,
|
|
and if you want it to then perform a file drag-and-drop, add the filenames you want
|
|
to the array passed in, and return true.
|
|
|
|
@param sourceDetails information about the source of the drag operation
|
|
@param files on return, the filenames you want to drag
|
|
@param canMoveFiles on return, true if it's ok for the receiver to move the files; false if
|
|
it must make a copy of them (see the performExternalDragDropOfFiles() method)
|
|
@see performExternalDragDropOfFiles
|
|
*/
|
|
virtual bool shouldDropFilesWhenDraggedExternally (const DragAndDropTarget::SourceDetails& sourceDetails,
|
|
StringArray& files, bool& canMoveFiles);
|
|
|
|
private:
|
|
|
|
friend class DragImageComponent;
|
|
ScopedPointer <Component> dragImageComponent;
|
|
String currentDragDesc;
|
|
|
|
JUCE_DEPRECATED (virtual bool shouldDropFilesWhenDraggedExternally (const String&, Component*, StringArray&, bool&)) { return false; }
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DragAndDropContainer);
|
|
};
|
|
|
|
#endif // __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DragAndDropContainer.h ***/
|
|
|
|
class ToolbarItemComponent;
|
|
class ToolbarItemFactory;
|
|
|
|
/**
|
|
A toolbar component.
|
|
|
|
A toolbar contains a horizontal or vertical strip of ToolbarItemComponents,
|
|
and looks after their order and layout.
|
|
|
|
Items (icon buttons or other custom components) are added to a toolbar using a
|
|
ToolbarItemFactory - each type of item is given a unique ID number, and a
|
|
toolbar might contain more than one instance of a particular item type.
|
|
|
|
Toolbars can be interactively customised, allowing the user to drag the items
|
|
around, and to drag items onto or off the toolbar, using the ToolbarItemPalette
|
|
component as a source of new items.
|
|
|
|
@see ToolbarItemFactory, ToolbarItemComponent, ToolbarItemPalette
|
|
*/
|
|
class JUCE_API Toolbar : public Component,
|
|
public DragAndDropContainer,
|
|
public DragAndDropTarget,
|
|
private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty toolbar component.
|
|
|
|
To add some icons or other components to your toolbar, you'll need to
|
|
create a ToolbarItemFactory class that can create a suitable set of
|
|
ToolbarItemComponents.
|
|
|
|
@see ToolbarItemFactory, ToolbarItemComponents
|
|
*/
|
|
Toolbar();
|
|
|
|
/** Destructor.
|
|
|
|
Any items on the bar will be deleted when the toolbar is deleted.
|
|
*/
|
|
~Toolbar();
|
|
|
|
/** Changes the bar's orientation.
|
|
@see isVertical
|
|
*/
|
|
void setVertical (bool shouldBeVertical);
|
|
|
|
/** Returns true if the bar is set to be vertical, or false if it's horizontal.
|
|
|
|
You can change the bar's orientation with setVertical().
|
|
*/
|
|
bool isVertical() const noexcept { return vertical; }
|
|
|
|
/** Returns the depth of the bar.
|
|
|
|
If the bar is horizontal, this will return its height; if it's vertical, it
|
|
will return its width.
|
|
|
|
@see getLength
|
|
*/
|
|
int getThickness() const noexcept;
|
|
|
|
/** Returns the length of the bar.
|
|
|
|
If the bar is horizontal, this will return its width; if it's vertical, it
|
|
will return its height.
|
|
|
|
@see getThickness
|
|
*/
|
|
int getLength() const noexcept;
|
|
|
|
/** Deletes all items from the bar.
|
|
*/
|
|
void clear();
|
|
|
|
/** Adds an item to the toolbar.
|
|
|
|
The factory's ToolbarItemFactory::createItem() will be called by this method
|
|
to create the component that will actually be added to the bar.
|
|
|
|
The new item will be inserted at the specified index (if the index is -1, it
|
|
will be added to the right-hand or bottom end of the bar).
|
|
|
|
Once added, the component will be automatically deleted by this object when it
|
|
is no longer needed.
|
|
|
|
@see ToolbarItemFactory
|
|
*/
|
|
void addItem (ToolbarItemFactory& factory,
|
|
int itemId,
|
|
int insertIndex = -1);
|
|
|
|
/** Deletes one of the items from the bar.
|
|
*/
|
|
void removeToolbarItem (int itemIndex);
|
|
|
|
/** Returns the number of items currently on the toolbar.
|
|
|
|
@see getItemId, getItemComponent
|
|
*/
|
|
int getNumItems() const noexcept;
|
|
|
|
/** Returns the ID of the item with the given index.
|
|
|
|
If the index is less than zero or greater than the number of items,
|
|
this will return 0.
|
|
|
|
@see getNumItems
|
|
*/
|
|
int getItemId (int itemIndex) const noexcept;
|
|
|
|
/** Returns the component being used for the item with the given index.
|
|
|
|
If the index is less than zero or greater than the number of items,
|
|
this will return 0.
|
|
|
|
@see getNumItems
|
|
*/
|
|
ToolbarItemComponent* getItemComponent (int itemIndex) const noexcept;
|
|
|
|
/** Clears this toolbar and adds to it the default set of items that the specified
|
|
factory creates.
|
|
|
|
@see ToolbarItemFactory::getDefaultItemSet
|
|
*/
|
|
void addDefaultItems (ToolbarItemFactory& factoryToUse);
|
|
|
|
/** Options for the way items should be displayed.
|
|
@see setStyle, getStyle
|
|
*/
|
|
enum ToolbarItemStyle
|
|
{
|
|
iconsOnly, /**< Means that the toolbar should just contain icons. */
|
|
iconsWithText, /**< Means that the toolbar should have text labels under each icon. */
|
|
textOnly /**< Means that the toolbar only display text labels for each item. */
|
|
};
|
|
|
|
/** Returns the toolbar's current style.
|
|
@see ToolbarItemStyle, setStyle
|
|
*/
|
|
ToolbarItemStyle getStyle() const noexcept { return toolbarStyle; }
|
|
|
|
/** Changes the toolbar's current style.
|
|
@see ToolbarItemStyle, getStyle, ToolbarItemComponent::setStyle
|
|
*/
|
|
void setStyle (const ToolbarItemStyle& newStyle);
|
|
|
|
/** Flags used by the showCustomisationDialog() method. */
|
|
enum CustomisationFlags
|
|
{
|
|
allowIconsOnlyChoice = 1, /**< If this flag is specified, the customisation dialog can
|
|
show the "icons only" option on its choice of toolbar styles. */
|
|
allowIconsWithTextChoice = 2, /**< If this flag is specified, the customisation dialog can
|
|
show the "icons with text" option on its choice of toolbar styles. */
|
|
allowTextOnlyChoice = 4, /**< If this flag is specified, the customisation dialog can
|
|
show the "text only" option on its choice of toolbar styles. */
|
|
showResetToDefaultsButton = 8, /**< If this flag is specified, the customisation dialog can
|
|
show a button to reset the toolbar to its default set of items. */
|
|
|
|
allCustomisationOptionsEnabled = (allowIconsOnlyChoice | allowIconsWithTextChoice | allowTextOnlyChoice | showResetToDefaultsButton)
|
|
};
|
|
|
|
/** Pops up a modal dialog box that allows this toolbar to be customised by the user.
|
|
|
|
The dialog contains a ToolbarItemPalette and various controls for editing other
|
|
aspects of the toolbar. This method will block and run the dialog box modally,
|
|
returning when the user closes it.
|
|
|
|
The factory is used to determine the set of items that will be shown on the
|
|
palette.
|
|
|
|
The optionFlags parameter is a bitwise-or of values from the CustomisationFlags
|
|
enum.
|
|
|
|
@see ToolbarItemPalette
|
|
*/
|
|
void showCustomisationDialog (ToolbarItemFactory& factory,
|
|
int optionFlags = allCustomisationOptionsEnabled);
|
|
|
|
/** Turns on or off the toolbar's editing mode, in which its items can be
|
|
rearranged by the user.
|
|
|
|
(In most cases it's easier just to use showCustomisationDialog() instead of
|
|
trying to enable editing directly).
|
|
|
|
@see ToolbarItemPalette
|
|
*/
|
|
void setEditingActive (bool editingEnabled);
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the toolbar.
|
|
|
|
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 = 0x1003200, /**< A colour to use to fill the toolbar's background. For
|
|
more control over this, override LookAndFeel::paintToolbarBackground(). */
|
|
separatorColourId = 0x1003210, /**< A colour to use to draw the separator lines. */
|
|
|
|
buttonMouseOverBackgroundColourId = 0x1003220, /**< A colour used to paint the background of buttons when the mouse is
|
|
over them. */
|
|
buttonMouseDownBackgroundColourId = 0x1003230, /**< A colour used to paint the background of buttons when the mouse is
|
|
held down on them. */
|
|
|
|
labelTextColourId = 0x1003240, /**< A colour to use for drawing the text under buttons
|
|
when the style is set to iconsWithText or textOnly. */
|
|
|
|
editingModeOutlineColourId = 0x1003250 /**< A colour to use for an outline around buttons when
|
|
the customisation dialog is active and the mouse moves over them. */
|
|
};
|
|
|
|
/** Returns a string that represents the toolbar's current set of items.
|
|
|
|
This lets you later restore the same item layout using restoreFromString().
|
|
|
|
@see restoreFromString
|
|
*/
|
|
String toString() const;
|
|
|
|
/** Restores a set of items that was previously stored in a string by the toString()
|
|
method.
|
|
|
|
The factory object is used to create any item components that are needed.
|
|
|
|
@see toString
|
|
*/
|
|
bool restoreFromString (ToolbarItemFactory& factoryToUse,
|
|
const String& savedVersion);
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void buttonClicked (Button*);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent&);
|
|
/** @internal */
|
|
bool isInterestedInDragSource (const SourceDetails&);
|
|
/** @internal */
|
|
void itemDragMove (const SourceDetails&);
|
|
/** @internal */
|
|
void itemDragExit (const SourceDetails&);
|
|
/** @internal */
|
|
void itemDropped (const SourceDetails&);
|
|
/** @internal */
|
|
void updateAllItemPositions (bool animate);
|
|
/** @internal */
|
|
static ToolbarItemComponent* createItem (ToolbarItemFactory&, int itemId);
|
|
|
|
private:
|
|
|
|
ScopedPointer<Button> missingItemsButton;
|
|
bool vertical, isEditingActive;
|
|
ToolbarItemStyle toolbarStyle;
|
|
class MissingItemsComponent;
|
|
friend class MissingItemsComponent;
|
|
OwnedArray <ToolbarItemComponent> items;
|
|
|
|
friend class ItemDragAndDropOverlayComponent;
|
|
static const char* const toolbarDragDescriptor;
|
|
|
|
void addItemInternal (ToolbarItemFactory& factory, int itemId, int insertIndex);
|
|
|
|
ToolbarItemComponent* getNextActiveComponent (int index, int delta) const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Toolbar);
|
|
};
|
|
|
|
#endif // __JUCE_TOOLBAR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Toolbar.h ***/
|
|
|
|
class ItemDragAndDropOverlayComponent;
|
|
|
|
/**
|
|
A component that can be used as one of the items in a Toolbar.
|
|
|
|
Each of the items on a toolbar must be a component derived from ToolbarItemComponent,
|
|
and these objects are always created by a ToolbarItemFactory - see the ToolbarItemFactory
|
|
class for further info about creating them.
|
|
|
|
The ToolbarItemComponent class is actually a button, but can be used to hold non-button
|
|
components too. To do this, set the value of isBeingUsedAsAButton to false when
|
|
calling the constructor, and override contentAreaChanged(), in which you can position
|
|
any sub-components you need to add.
|
|
|
|
To add basic buttons without writing a special subclass, have a look at the
|
|
ToolbarButton class.
|
|
|
|
@see ToolbarButton, Toolbar, ToolbarItemFactory
|
|
*/
|
|
class JUCE_API ToolbarItemComponent : public Button
|
|
{
|
|
public:
|
|
|
|
/** Constructor.
|
|
|
|
@param itemId the ID of the type of toolbar item which this represents
|
|
@param labelText the text to display if the toolbar's style is set to
|
|
Toolbar::iconsWithText or Toolbar::textOnly
|
|
@param isBeingUsedAsAButton set this to false if you don't want the button
|
|
to draw itself with button over/down states when the mouse
|
|
moves over it or clicks
|
|
*/
|
|
ToolbarItemComponent (int itemId,
|
|
const String& labelText,
|
|
bool isBeingUsedAsAButton);
|
|
|
|
/** Destructor. */
|
|
~ToolbarItemComponent();
|
|
|
|
/** Returns the item type ID that this component represents.
|
|
This value is in the constructor.
|
|
*/
|
|
int getItemId() const noexcept { return itemId; }
|
|
|
|
/** Returns the toolbar that contains this component, or 0 if it's not currently
|
|
inside one.
|
|
*/
|
|
Toolbar* getToolbar() const;
|
|
|
|
/** Returns true if this component is currently inside a toolbar which is vertical.
|
|
@see Toolbar::isVertical
|
|
*/
|
|
bool isToolbarVertical() const;
|
|
|
|
/** Returns the current style setting of this item.
|
|
|
|
Styles are listed in the Toolbar::ToolbarItemStyle enum.
|
|
@see setStyle, Toolbar::getStyle
|
|
*/
|
|
Toolbar::ToolbarItemStyle getStyle() const noexcept { return toolbarStyle; }
|
|
|
|
/** Changes the current style setting of this item.
|
|
|
|
Styles are listed in the Toolbar::ToolbarItemStyle enum, and are automatically updated
|
|
by the toolbar that holds this item.
|
|
|
|
@see setStyle, Toolbar::setStyle
|
|
*/
|
|
virtual void setStyle (const Toolbar::ToolbarItemStyle& newStyle);
|
|
|
|
/** Returns the area of the component that should be used to display the button image or
|
|
other contents of the item.
|
|
|
|
This content area may change when the item's style changes, and may leave a space around the
|
|
edge of the component where the text label can be shown.
|
|
|
|
@see contentAreaChanged
|
|
*/
|
|
const Rectangle<int> getContentArea() const noexcept { return contentArea; }
|
|
|
|
/** This method must return the size criteria for this item, based on a given toolbar
|
|
size and orientation.
|
|
|
|
The preferredSize, minSize and maxSize values must all be set by your implementation
|
|
method. If the toolbar is horizontal, these will be the width of the item; for a vertical
|
|
toolbar, they refer to the item's height.
|
|
|
|
The preferredSize is the size that the component would like to be, and this must be
|
|
between the min and max sizes. For a fixed-size item, simply set all three variables to
|
|
the same value.
|
|
|
|
The toolbarThickness parameter tells you the depth of the toolbar - the same as calling
|
|
Toolbar::getThickness().
|
|
|
|
The isToolbarVertical parameter tells you whether the bar is oriented horizontally or
|
|
vertically.
|
|
*/
|
|
virtual bool getToolbarItemSizes (int toolbarThickness,
|
|
bool isToolbarVertical,
|
|
int& preferredSize,
|
|
int& minSize,
|
|
int& maxSize) = 0;
|
|
|
|
/** Your subclass should use this method to draw its content area.
|
|
|
|
The graphics object that is passed-in will have been clipped and had its origin
|
|
moved to fit the content area as specified get getContentArea(). The width and height
|
|
parameters are the width and height of the content area.
|
|
|
|
If the component you're writing isn't a button, you can just do nothing in this method.
|
|
*/
|
|
virtual void paintButtonArea (Graphics& g,
|
|
int width, int height,
|
|
bool isMouseOver, bool isMouseDown) = 0;
|
|
|
|
/** Callback to indicate that the content area of this item has changed.
|
|
|
|
This might be because the component was resized, or because the style changed and
|
|
the space needed for the text label is different.
|
|
|
|
See getContentArea() for a description of what the area is.
|
|
*/
|
|
virtual void contentAreaChanged (const Rectangle<int>& newBounds) = 0;
|
|
|
|
/** Editing modes.
|
|
These are used by setEditingMode(), but will be rarely needed in user code.
|
|
*/
|
|
enum ToolbarEditingMode
|
|
{
|
|
normalMode = 0, /**< Means that the component is active, inside a toolbar. */
|
|
editableOnToolbar, /**< Means that the component is on a toolbar, but the toolbar is in
|
|
customisation mode, and the items can be dragged around. */
|
|
editableOnPalette /**< Means that the component is on an new-item palette, so it can be
|
|
dragged onto a toolbar to add it to that bar.*/
|
|
};
|
|
|
|
/** Changes the editing mode of this component.
|
|
|
|
This is used by the ToolbarItemPalette and related classes for making the items draggable,
|
|
and is unlikely to be of much use in end-user-code.
|
|
*/
|
|
void setEditingMode (const ToolbarEditingMode newMode);
|
|
|
|
/** Returns the current editing mode of this component.
|
|
|
|
This is used by the ToolbarItemPalette and related classes for making the items draggable,
|
|
and is unlikely to be of much use in end-user-code.
|
|
*/
|
|
ToolbarEditingMode getEditingMode() const noexcept { return mode; }
|
|
|
|
/** @internal */
|
|
void paintButton (Graphics& g, bool isMouseOver, bool isMouseDown);
|
|
/** @internal */
|
|
void resized();
|
|
|
|
private:
|
|
friend class Toolbar;
|
|
friend class ItemDragAndDropOverlayComponent;
|
|
const int itemId;
|
|
ToolbarEditingMode mode;
|
|
Toolbar::ToolbarItemStyle toolbarStyle;
|
|
ScopedPointer <Component> overlayComp;
|
|
int dragOffsetX, dragOffsetY;
|
|
bool isActive, isBeingDragged, isBeingUsedAsAButton;
|
|
Rectangle<int> contentArea;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToolbarItemComponent);
|
|
};
|
|
|
|
#endif // __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ToolbarItemComponent.h ***/
|
|
|
|
/**
|
|
A type of button designed to go on a toolbar.
|
|
|
|
This simple button can have two Drawable objects specified - one for normal
|
|
use and another one (optionally) for the button's "on" state if it's a
|
|
toggle button.
|
|
|
|
@see Toolbar, ToolbarItemFactory, ToolbarItemComponent, Drawable, Button
|
|
*/
|
|
class JUCE_API ToolbarButton : public ToolbarItemComponent
|
|
{
|
|
public:
|
|
|
|
/** Creates a ToolbarButton.
|
|
|
|
@param itemId the ID for this toolbar item type. This is passed through to the
|
|
ToolbarItemComponent constructor
|
|
@param labelText the text to display on the button (if the toolbar is using a style
|
|
that shows text labels). This is passed through to the
|
|
ToolbarItemComponent constructor
|
|
@param normalImage a drawable object that the button should use as its icon. The object
|
|
that is passed-in here will be kept by this object and will be
|
|
deleted when no longer needed or when this button is deleted.
|
|
@param toggledOnImage a drawable object that the button can use as its icon if the button
|
|
is in a toggled-on state (see the Button::getToggleState() method). If
|
|
0 is passed-in here, then the normal image will be used instead, regardless
|
|
of the toggle state. The object that is passed-in here will be kept by
|
|
this object and will be deleted when no longer needed or when this button
|
|
is deleted.
|
|
*/
|
|
ToolbarButton (int itemId,
|
|
const String& labelText,
|
|
Drawable* normalImage,
|
|
Drawable* toggledOnImage);
|
|
|
|
/** Destructor. */
|
|
~ToolbarButton();
|
|
|
|
/** @internal */
|
|
bool getToolbarItemSizes (int toolbarDepth, bool isToolbarVertical, int& preferredSize,
|
|
int& minSize, int& maxSize);
|
|
/** @internal */
|
|
void paintButtonArea (Graphics& g, int width, int height, bool isMouseOver, bool isMouseDown);
|
|
/** @internal */
|
|
void contentAreaChanged (const Rectangle<int>& newBounds);
|
|
/** @internal */
|
|
void buttonStateChanged();
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void enablementChanged();
|
|
|
|
private:
|
|
|
|
ScopedPointer<Drawable> normalImage, toggledOnImage;
|
|
Drawable* currentImage;
|
|
|
|
void updateDrawable();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToolbarButton);
|
|
};
|
|
|
|
#endif // __JUCE_TOOLBARBUTTON_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ToolbarButton.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_CodeDocument.h ***/
|
|
#ifndef __JUCE_CODEDOCUMENT_JUCEHEADER__
|
|
#define __JUCE_CODEDOCUMENT_JUCEHEADER__
|
|
|
|
class CodeDocumentLine;
|
|
|
|
/**
|
|
A class for storing and manipulating a source code file.
|
|
|
|
When using a CodeEditorComponent, it takes one of these as its source object.
|
|
|
|
The CodeDocument stores its content as an array of lines, which makes it
|
|
quick to insert and delete.
|
|
|
|
@see CodeEditorComponent
|
|
*/
|
|
class JUCE_API CodeDocument
|
|
{
|
|
public:
|
|
/** Creates a new, empty document.
|
|
*/
|
|
CodeDocument();
|
|
|
|
/** Destructor. */
|
|
~CodeDocument();
|
|
|
|
/** A position in a code document.
|
|
|
|
Using this class you can find a position in a code document and quickly get its
|
|
character position, line, and index. By calling setPositionMaintained (true), the
|
|
position is automatically updated when text is inserted or deleted in the document,
|
|
so that it maintains its original place in the text.
|
|
*/
|
|
class JUCE_API Position
|
|
{
|
|
public:
|
|
/** Creates an uninitialised postion.
|
|
Don't attempt to call any methods on this until you've given it an owner document
|
|
to refer to!
|
|
*/
|
|
Position() noexcept;
|
|
|
|
/** Creates a position based on a line and index in a document.
|
|
|
|
Note that this index is NOT the column number, it's the number of characters from the
|
|
start of the line. The "column" number isn't quite the same, because if the line
|
|
contains any tab characters, the relationship of the index to its visual column depends on
|
|
the number of spaces per tab being used!
|
|
|
|
Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
|
|
they will be adjusted to keep them within its limits.
|
|
*/
|
|
Position (const CodeDocument* ownerDocument,
|
|
int line, int indexInLine) noexcept;
|
|
|
|
/** Creates a position based on a character index in a document.
|
|
This position is placed at the specified number of characters from the start of the
|
|
document. The line and column are auto-calculated.
|
|
|
|
If the position is beyond the range of the document, it'll be adjusted to keep it
|
|
inside.
|
|
*/
|
|
Position (const CodeDocument* ownerDocument,
|
|
int charactersFromStartOfDocument) noexcept;
|
|
|
|
/** Creates a copy of another position.
|
|
|
|
This will copy the position, but the new object will not be set to maintain its position,
|
|
even if the source object was set to do so.
|
|
*/
|
|
Position (const Position& other) noexcept;
|
|
|
|
/** Destructor. */
|
|
~Position();
|
|
|
|
Position& operator= (const Position& other);
|
|
bool operator== (const Position& other) const noexcept;
|
|
bool operator!= (const Position& other) const noexcept;
|
|
|
|
/** Points this object at a new position within the document.
|
|
|
|
If the position is beyond the range of the document, it'll be adjusted to keep it
|
|
inside.
|
|
@see getPosition, setLineAndIndex
|
|
*/
|
|
void setPosition (int charactersFromStartOfDocument);
|
|
|
|
/** Returns the position as the number of characters from the start of the document.
|
|
@see setPosition, getLineNumber, getIndexInLine
|
|
*/
|
|
int getPosition() const noexcept { return characterPos; }
|
|
|
|
/** Moves the position to a new line and index within the line.
|
|
|
|
Note that the index is NOT the column at which the position appears in an editor.
|
|
If the line contains any tab characters, the relationship of the index to its
|
|
visual position depends on the number of spaces per tab being used!
|
|
|
|
Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
|
|
they will be adjusted to keep them within its limits.
|
|
*/
|
|
void setLineAndIndex (int newLine, int newIndexInLine);
|
|
|
|
/** Returns the line number of this position.
|
|
The first line in the document is numbered zero, not one!
|
|
*/
|
|
int getLineNumber() const noexcept { return line; }
|
|
|
|
/** Returns the number of characters from the start of the line.
|
|
|
|
Note that this value is NOT the column at which the position appears in an editor.
|
|
If the line contains any tab characters, the relationship of the index to its
|
|
visual position depends on the number of spaces per tab being used!
|
|
*/
|
|
int getIndexInLine() const noexcept { return indexInLine; }
|
|
|
|
/** Allows the position to be automatically updated when the document changes.
|
|
|
|
If this is set to true, the positon will register with its document so that
|
|
when the document has text inserted or deleted, this position will be automatically
|
|
moved to keep it at the same position in the text.
|
|
*/
|
|
void setPositionMaintained (bool isMaintained);
|
|
|
|
/** Moves the position forwards or backwards by the specified number of characters.
|
|
@see movedBy
|
|
*/
|
|
void moveBy (int characterDelta);
|
|
|
|
/** Returns a position which is the same as this one, moved by the specified number of
|
|
characters.
|
|
@see moveBy
|
|
*/
|
|
const Position movedBy (int characterDelta) const;
|
|
|
|
/** Returns a position which is the same as this one, moved up or down by the specified
|
|
number of lines.
|
|
@see movedBy
|
|
*/
|
|
const Position movedByLines (int deltaLines) const;
|
|
|
|
/** Returns the character in the document at this position.
|
|
@see getLineText
|
|
*/
|
|
const juce_wchar getCharacter() const;
|
|
|
|
/** Returns the line from the document that this position is within.
|
|
@see getCharacter, getLineNumber
|
|
*/
|
|
String getLineText() const;
|
|
|
|
private:
|
|
CodeDocument* owner;
|
|
int characterPos, line, indexInLine;
|
|
bool positionMaintained;
|
|
};
|
|
|
|
/** Returns the full text of the document. */
|
|
String getAllContent() const;
|
|
|
|
/** Returns a section of the document's text. */
|
|
String getTextBetween (const Position& start, const Position& end) const;
|
|
|
|
/** Returns a line from the document. */
|
|
String getLine (int lineIndex) const noexcept;
|
|
|
|
/** Returns the number of characters in the document. */
|
|
int getNumCharacters() const noexcept;
|
|
|
|
/** Returns the number of lines in the document. */
|
|
int getNumLines() const noexcept { return lines.size(); }
|
|
|
|
/** Returns the number of characters in the longest line of the document. */
|
|
int getMaximumLineLength() noexcept;
|
|
|
|
/** Deletes a section of the text.
|
|
|
|
This operation is undoable.
|
|
*/
|
|
void deleteSection (const Position& startPosition, const Position& endPosition);
|
|
|
|
/** Inserts some text into the document at a given position.
|
|
|
|
This operation is undoable.
|
|
*/
|
|
void insertText (const Position& position, const String& text);
|
|
|
|
/** Clears the document and replaces it with some new text.
|
|
|
|
This operation is undoable - if you're trying to completely reset the document, you
|
|
might want to also call clearUndoHistory() and setSavePoint() after using this method.
|
|
*/
|
|
void replaceAllContent (const String& newContent);
|
|
|
|
/** Replaces the editor's contents with the contents of a stream.
|
|
This will also reset the undo history and save point marker.
|
|
*/
|
|
bool loadFromStream (InputStream& stream);
|
|
|
|
/** Writes the editor's current contents to a stream. */
|
|
bool writeToStream (OutputStream& stream);
|
|
|
|
/** Returns the preferred new-line characters for the document.
|
|
This will be either "\n", "\r\n", or (rarely) "\r".
|
|
@see setNewLineCharacters
|
|
*/
|
|
String getNewLineCharacters() const noexcept { return newLineChars; }
|
|
|
|
/** Sets the new-line characters that the document should use.
|
|
The string must be either "\n", "\r\n", or (rarely) "\r".
|
|
@see getNewLineCharacters
|
|
*/
|
|
void setNewLineCharacters (const String& newLine) noexcept;
|
|
|
|
/** Begins a new undo transaction.
|
|
|
|
The document itself will not call this internally, so relies on whatever is using the
|
|
document to periodically call this to break up the undo sequence into sensible chunks.
|
|
@see UndoManager::beginNewTransaction
|
|
*/
|
|
void newTransaction();
|
|
|
|
/** Undo the last operation.
|
|
@see UndoManager::undo
|
|
*/
|
|
void undo();
|
|
|
|
/** Redo the last operation.
|
|
@see UndoManager::redo
|
|
*/
|
|
void redo();
|
|
|
|
/** Clears the undo history.
|
|
@see UndoManager::clearUndoHistory
|
|
*/
|
|
void clearUndoHistory();
|
|
|
|
/** Returns the document's UndoManager */
|
|
UndoManager& getUndoManager() noexcept { return undoManager; }
|
|
|
|
/** Makes a note that the document's current state matches the one that is saved.
|
|
|
|
After this has been called, hasChangedSinceSavePoint() will return false until
|
|
the document has been altered, and then it'll start returning true. If the document is
|
|
altered, but then undone until it gets back to this state, hasChangedSinceSavePoint()
|
|
will again return false.
|
|
|
|
@see hasChangedSinceSavePoint
|
|
*/
|
|
void setSavePoint() noexcept;
|
|
|
|
/** Returns true if the state of the document differs from the state it was in when
|
|
setSavePoint() was last called.
|
|
|
|
@see setSavePoint
|
|
*/
|
|
bool hasChangedSinceSavePoint() const noexcept;
|
|
|
|
/** Searches for a word-break. */
|
|
const Position findWordBreakAfter (const Position& position) const noexcept;
|
|
|
|
/** Searches for a word-break. */
|
|
const Position findWordBreakBefore (const Position& position) const noexcept;
|
|
|
|
/** An object that receives callbacks from the CodeDocument when its text changes.
|
|
@see CodeDocument::addListener, CodeDocument::removeListener
|
|
*/
|
|
class JUCE_API Listener
|
|
{
|
|
public:
|
|
Listener() {}
|
|
virtual ~Listener() {}
|
|
|
|
/** Called by a CodeDocument when it is altered.
|
|
*/
|
|
virtual void codeDocumentChanged (const Position& affectedTextStart,
|
|
const Position& affectedTextEnd) = 0;
|
|
};
|
|
|
|
/** Registers a listener object to receive callbacks when the document changes.
|
|
If the listener is already registered, this method has no effect.
|
|
@see removeListener
|
|
*/
|
|
void addListener (Listener* listener) noexcept;
|
|
|
|
/** Deregisters a listener.
|
|
@see addListener
|
|
*/
|
|
void removeListener (Listener* listener) noexcept;
|
|
|
|
/** Iterates the text in a CodeDocument.
|
|
|
|
This class lets you read characters from a CodeDocument. It's designed to be used
|
|
by a SyntaxAnalyser object.
|
|
|
|
@see CodeDocument, SyntaxAnalyser
|
|
*/
|
|
class JUCE_API Iterator
|
|
{
|
|
public:
|
|
Iterator (CodeDocument* document);
|
|
Iterator (const Iterator& other);
|
|
Iterator& operator= (const Iterator& other) noexcept;
|
|
~Iterator() noexcept;
|
|
|
|
/** Reads the next character and returns it.
|
|
@see peekNextChar
|
|
*/
|
|
juce_wchar nextChar();
|
|
|
|
/** Reads the next character without advancing the current position. */
|
|
juce_wchar peekNextChar() const;
|
|
|
|
/** Advances the position by one character. */
|
|
void skip();
|
|
|
|
/** Returns the position of the next character as its position within the
|
|
whole document.
|
|
*/
|
|
int getPosition() const noexcept { return position; }
|
|
|
|
/** Skips over any whitespace characters until the next character is non-whitespace. */
|
|
void skipWhitespace();
|
|
|
|
/** Skips forward until the next character will be the first character on the next line */
|
|
void skipToEndOfLine();
|
|
|
|
/** Returns the line number of the next character. */
|
|
int getLine() const noexcept { return line; }
|
|
|
|
/** Returns true if the iterator has reached the end of the document. */
|
|
bool isEOF() const noexcept;
|
|
|
|
private:
|
|
CodeDocument* document;
|
|
mutable String::CharPointerType charPointer;
|
|
int line, position;
|
|
};
|
|
|
|
private:
|
|
|
|
friend class CodeDocumentInsertAction;
|
|
friend class CodeDocumentDeleteAction;
|
|
friend class Iterator;
|
|
friend class Position;
|
|
|
|
OwnedArray <CodeDocumentLine> lines;
|
|
Array <Position*> positionsToMaintain;
|
|
UndoManager undoManager;
|
|
int currentActionIndex, indexOfSavedState;
|
|
int maximumLineLength;
|
|
ListenerList <Listener> listeners;
|
|
String newLineChars;
|
|
|
|
void sendListenerChangeMessage (int startLine, int endLine);
|
|
|
|
void insert (const String& text, int insertPos, bool undoable);
|
|
void remove (int startPos, int endPos, bool undoable);
|
|
void checkLastLineStatus();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeDocument);
|
|
};
|
|
|
|
#endif // __JUCE_CODEDOCUMENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CodeDocument.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_CodeEditorComponent.h ***/
|
|
#ifndef __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_TextInputTarget.h ***/
|
|
#ifndef __JUCE_TEXTINPUTTARGET_JUCEHEADER__
|
|
#define __JUCE_TEXTINPUTTARGET_JUCEHEADER__
|
|
|
|
/**
|
|
An abstract base class which can be implemented by components that function 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<int> getHighlightedRegion() const = 0;
|
|
|
|
/** Sets the currently-selected text region. */
|
|
virtual void setHighlightedRegion (const Range<int>& newRange) = 0;
|
|
|
|
/** Sets a number of temporarily underlined sections.
|
|
This is needed by MS Windows input method UI.
|
|
*/
|
|
virtual void setTemporaryUnderlining (const Array <Range<int> >& underlinedRegions) = 0;
|
|
|
|
/** Returns a specified sub-section of the text. */
|
|
virtual const String getTextInRange (const Range<int>& range) const = 0;
|
|
|
|
/** Inserts some text, overwriting the selected text region, if there is one. */
|
|
virtual void insertTextAtCaret (const String& textToInsert) = 0;
|
|
|
|
/** Returns the position of the caret, relative to the component's origin. */
|
|
virtual const Rectangle<int> getCaretRectangle() = 0;
|
|
};
|
|
|
|
#endif // __JUCE_TEXTINPUTTARGET_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TextInputTarget.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_CaretComponent.h ***/
|
|
#ifndef __JUCE_CARETCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_CARETCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
*/
|
|
class JUCE_API CaretComponent : public Component,
|
|
public Timer
|
|
{
|
|
public:
|
|
|
|
/** Creates the caret component.
|
|
The keyFocusOwner is an optional component which the caret will check, making
|
|
itself visible only when the keyFocusOwner has keyboard focus.
|
|
*/
|
|
CaretComponent (Component* keyFocusOwner);
|
|
|
|
/** Destructor. */
|
|
~CaretComponent();
|
|
|
|
/** Sets the caret's position to place it next to the given character.
|
|
The area is the rectangle containing the entire character that the caret is
|
|
positioned on, so by default a vertical-line caret may choose to just show itself
|
|
at the left of this area. You can override this method to customise its size.
|
|
This method will also force the caret to reset its timer and become visible (if
|
|
appropriate), so that as it moves, you can see where it is.
|
|
*/
|
|
virtual void setCaretPosition (const Rectangle<int>& characterArea);
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the caret.
|
|
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
|
|
{
|
|
caretColourId = 0x1000204, /**< The colour with which to draw the caret. */
|
|
};
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void timerCallback();
|
|
|
|
private:
|
|
Component* owner;
|
|
bool shouldBeShown() const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (CaretComponent);
|
|
};
|
|
|
|
#endif // __JUCE_CARETCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CaretComponent.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_CodeTokeniser.h ***/
|
|
#ifndef __JUCE_CODETOKENISER_JUCEHEADER__
|
|
#define __JUCE_CODETOKENISER_JUCEHEADER__
|
|
|
|
/**
|
|
A base class for tokenising code so that the syntax can be displayed in a
|
|
code editor.
|
|
|
|
@see CodeDocument, CodeEditorComponent
|
|
*/
|
|
class JUCE_API CodeTokeniser
|
|
{
|
|
public:
|
|
CodeTokeniser() {}
|
|
virtual ~CodeTokeniser() {}
|
|
|
|
/** Reads the next token from the source and returns its token type.
|
|
|
|
This must leave the source pointing to the first character in the
|
|
next token.
|
|
*/
|
|
virtual int readNextToken (CodeDocument::Iterator& source) = 0;
|
|
|
|
/** Returns a list of the names of the token types this analyser uses.
|
|
|
|
The index in this list must match the token type numbers that are
|
|
returned by readNextToken().
|
|
*/
|
|
virtual StringArray getTokenTypes() = 0;
|
|
|
|
/** Returns a suggested syntax highlighting colour for a specified
|
|
token type.
|
|
*/
|
|
virtual const Colour getDefaultColour (int tokenType) = 0;
|
|
|
|
private:
|
|
|
|
JUCE_LEAK_DETECTOR (CodeTokeniser);
|
|
};
|
|
|
|
#endif // __JUCE_CODETOKENISER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CodeTokeniser.h ***/
|
|
|
|
/**
|
|
A text editor component designed specifically for source code.
|
|
|
|
This is designed to handle syntax highlighting and fast editing of very large
|
|
files.
|
|
*/
|
|
class JUCE_API CodeEditorComponent : public Component,
|
|
public TextInputTarget,
|
|
public Timer,
|
|
public ScrollBar::Listener,
|
|
public CodeDocument::Listener,
|
|
public AsyncUpdater
|
|
{
|
|
public:
|
|
|
|
/** Creates an editor for a document.
|
|
|
|
The tokeniser object is optional - pass 0 to disable syntax highlighting.
|
|
The object that you pass in is not owned or deleted by the editor - you must
|
|
make sure that it doesn't get deleted while this component is still using it.
|
|
|
|
@see CodeDocument
|
|
*/
|
|
CodeEditorComponent (CodeDocument& document,
|
|
CodeTokeniser* codeTokeniser);
|
|
|
|
/** Destructor. */
|
|
~CodeEditorComponent();
|
|
|
|
/** Returns the code document that this component is editing. */
|
|
CodeDocument& getDocument() const noexcept { return document; }
|
|
|
|
/** Loads the given content into the document.
|
|
This will completely reset the CodeDocument object, clear its undo history,
|
|
and fill it with this text.
|
|
*/
|
|
void loadContent (const String& newContent);
|
|
|
|
/** Returns the standard character width. */
|
|
float getCharWidth() const noexcept { return charWidth; }
|
|
|
|
/** Returns the height of a line of text, in pixels. */
|
|
int getLineHeight() const noexcept { return lineHeight; }
|
|
|
|
/** Returns the number of whole lines visible on the screen,
|
|
This doesn't include a cut-off line that might be visible at the bottom if the
|
|
component's height isn't an exact multiple of the line-height.
|
|
*/
|
|
int getNumLinesOnScreen() const noexcept { return linesOnScreen; }
|
|
|
|
/** Returns the number of whole columns visible on the screen.
|
|
This doesn't include any cut-off columns at the right-hand edge.
|
|
*/
|
|
int getNumColumnsOnScreen() const noexcept { return columnsOnScreen; }
|
|
|
|
/** Returns the current caret position. */
|
|
const CodeDocument::Position getCaretPos() const { return caretPos; }
|
|
|
|
/** Returns the position of the caret, relative to the editor's origin. */
|
|
const Rectangle<int> getCaretRectangle();
|
|
|
|
/** Moves the caret.
|
|
If selecting is true, the section of the document between the current
|
|
caret position and the new one will become selected. If false, any currently
|
|
selected region will be deselected.
|
|
*/
|
|
void moveCaretTo (const CodeDocument::Position& newPos, bool selecting);
|
|
|
|
/** Returns the on-screen position of a character in the document.
|
|
The rectangle returned is relative to this component's top-left origin.
|
|
*/
|
|
const Rectangle<int> getCharacterBounds (const CodeDocument::Position& pos) const;
|
|
|
|
/** Finds the character at a given on-screen position.
|
|
The co-ordinates are relative to this component's top-left origin.
|
|
*/
|
|
const CodeDocument::Position getPositionAt (int x, int y);
|
|
|
|
bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting);
|
|
bool moveCaretRight (bool moveInWholeWordSteps, bool selecting);
|
|
bool moveCaretUp (bool selecting);
|
|
bool moveCaretDown (bool selecting);
|
|
bool scrollDown();
|
|
bool scrollUp();
|
|
bool pageUp (bool selecting);
|
|
bool pageDown (bool selecting);
|
|
bool moveCaretToTop (bool selecting);
|
|
bool moveCaretToStartOfLine (bool selecting);
|
|
bool moveCaretToEnd (bool selecting);
|
|
bool moveCaretToEndOfLine (bool selecting);
|
|
bool deleteBackwards (bool moveInWholeWordSteps);
|
|
bool deleteForwards (bool moveInWholeWordSteps);
|
|
bool copyToClipboard();
|
|
bool cutToClipboard();
|
|
bool pasteFromClipboard();
|
|
bool undo();
|
|
bool redo();
|
|
|
|
bool selectAll();
|
|
void deselectAll();
|
|
|
|
void scrollToLine (int newFirstLineOnScreen);
|
|
void scrollBy (int deltaLines);
|
|
void scrollToColumn (int newFirstColumnOnScreen);
|
|
void scrollToKeepCaretOnScreen();
|
|
|
|
void insertTextAtCaret (const String& textToInsert);
|
|
void insertTabAtCaret();
|
|
|
|
const Range<int> getHighlightedRegion() const;
|
|
void setHighlightedRegion (const Range<int>& newRange);
|
|
const String getTextInRange (const Range<int>& range) const;
|
|
|
|
/** Changes the current tab settings.
|
|
This lets you change the tab size and whether pressing the tab key inserts a
|
|
tab character, or its equivalent number of spaces.
|
|
*/
|
|
void setTabSize (int numSpacesPerTab, bool insertSpacesInsteadOfTabCharacters);
|
|
|
|
/** Returns the current number of spaces per tab.
|
|
@see setTabSize
|
|
*/
|
|
int getTabSize() const noexcept { return spacesPerTab; }
|
|
|
|
/** Returns true if the tab key will insert spaces instead of actual tab characters.
|
|
@see setTabSize
|
|
*/
|
|
bool areSpacesInsertedForTabs() const { return useSpacesForTabs; }
|
|
|
|
/** Changes the font.
|
|
Make sure you only use a fixed-width font, or this component will look pretty nasty!
|
|
*/
|
|
void setFont (const Font& newFont);
|
|
|
|
/** Returns the font that the editor is using. */
|
|
const Font& getFont() const noexcept { return font; }
|
|
|
|
/** Resets the syntax highlighting colours to the default ones provided by the
|
|
code tokeniser.
|
|
@see CodeTokeniser::getDefaultColour
|
|
*/
|
|
void resetToDefaultColours();
|
|
|
|
/** Changes one of the syntax highlighting colours.
|
|
The token type values are dependent on the tokeniser being used - use
|
|
CodeTokeniser::getTokenTypes() to get a list of the token types.
|
|
@see getColourForTokenType
|
|
*/
|
|
void setColourForTokenType (int tokenType, const Colour& colour);
|
|
|
|
/** Returns one of the syntax highlighting colours.
|
|
The token type values are dependent on the tokeniser being used - use
|
|
CodeTokeniser::getTokenTypes() to get a list of the token types.
|
|
@see setColourForTokenType
|
|
*/
|
|
const Colour getColourForTokenType (int tokenType) const;
|
|
|
|
/** 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 = 0x1004500, /**< A colour to use to fill the editor's background. */
|
|
highlightColourId = 0x1004502, /**< The colour to use for the highlighted background under
|
|
selected text. */
|
|
defaultTextColourId = 0x1004503 /**< The colour to use for text when no syntax colouring is
|
|
enabled. */
|
|
};
|
|
|
|
/** Changes the size of the scrollbars. */
|
|
void setScrollbarThickness (int thickness);
|
|
|
|
/** Returns the thickness of the scrollbars. */
|
|
int getScrollbarThickness() const noexcept { return scrollbarThickness; }
|
|
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
bool keyPressed (const KeyPress& key);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseUp (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDoubleClick (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY);
|
|
/** @internal */
|
|
void focusGained (FocusChangeType cause);
|
|
/** @internal */
|
|
void focusLost (FocusChangeType cause);
|
|
/** @internal */
|
|
void timerCallback();
|
|
/** @internal */
|
|
void scrollBarMoved (ScrollBar* scrollBarThatHasMoved, double newRangeStart);
|
|
/** @internal */
|
|
void handleAsyncUpdate();
|
|
/** @internal */
|
|
void codeDocumentChanged (const CodeDocument::Position& affectedTextStart,
|
|
const CodeDocument::Position& affectedTextEnd);
|
|
/** @internal */
|
|
bool isTextInputActive() const;
|
|
/** @internal */
|
|
void setTemporaryUnderlining (const Array <Range<int> >&);
|
|
|
|
private:
|
|
|
|
CodeDocument& document;
|
|
|
|
Font font;
|
|
int firstLineOnScreen, gutter, spacesPerTab;
|
|
float charWidth;
|
|
int lineHeight, linesOnScreen, columnsOnScreen;
|
|
int scrollbarThickness, columnToTryToMaintain;
|
|
bool useSpacesForTabs;
|
|
double xOffset;
|
|
|
|
CodeDocument::Position caretPos;
|
|
CodeDocument::Position selectionStart, selectionEnd;
|
|
|
|
ScopedPointer<CaretComponent> caret;
|
|
ScrollBar verticalScrollBar, horizontalScrollBar;
|
|
|
|
enum DragType
|
|
{
|
|
notDragging,
|
|
draggingSelectionStart,
|
|
draggingSelectionEnd
|
|
};
|
|
|
|
DragType dragType;
|
|
|
|
CodeTokeniser* codeTokeniser;
|
|
Array <Colour> coloursForTokenCategories;
|
|
|
|
class CodeEditorLine;
|
|
OwnedArray <CodeEditorLine> lines;
|
|
void rebuildLineTokens();
|
|
|
|
OwnedArray <CodeDocument::Iterator> cachedIterators;
|
|
void clearCachedIterators (int firstLineToBeInvalid);
|
|
void updateCachedIterators (int maxLineNum);
|
|
void getIteratorForPosition (int position, CodeDocument::Iterator& result);
|
|
void moveLineDelta (int delta, bool selecting);
|
|
|
|
void updateCaretPosition();
|
|
void updateScrollBars();
|
|
void scrollToLineInternal (int line);
|
|
void scrollToColumnInternal (double column);
|
|
void newTransaction();
|
|
void cut();
|
|
|
|
int indexToColumn (int line, int index) const noexcept;
|
|
int columnToIndex (int line, int column) const noexcept;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeEditorComponent);
|
|
};
|
|
|
|
#endif // __JUCE_CODEEDITORCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CodeEditorComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_CODETOKENISER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_CPlusPlusCodeTokeniser.h ***/
|
|
#ifndef __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__
|
|
#define __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__
|
|
|
|
/**
|
|
A simple lexical analyser for syntax colouring of C++ code.
|
|
|
|
@see SyntaxAnalyser, CodeEditorComponent, CodeDocument
|
|
*/
|
|
class JUCE_API CPlusPlusCodeTokeniser : public CodeTokeniser
|
|
{
|
|
public:
|
|
|
|
CPlusPlusCodeTokeniser();
|
|
~CPlusPlusCodeTokeniser();
|
|
|
|
enum TokenType
|
|
{
|
|
tokenType_error = 0,
|
|
tokenType_comment,
|
|
tokenType_builtInKeyword,
|
|
tokenType_identifier,
|
|
tokenType_integerLiteral,
|
|
tokenType_floatLiteral,
|
|
tokenType_stringLiteral,
|
|
tokenType_operator,
|
|
tokenType_bracket,
|
|
tokenType_punctuation,
|
|
tokenType_preprocessor
|
|
};
|
|
|
|
int readNextToken (CodeDocument::Iterator& source);
|
|
StringArray getTokenTypes();
|
|
const Colour getDefaultColour (int tokenType);
|
|
|
|
/** This is a handy method for checking whether a string is a c++ reserved keyword. */
|
|
static bool isReservedKeyword (const String& token) noexcept;
|
|
|
|
private:
|
|
|
|
JUCE_LEAK_DETECTOR (CPlusPlusCodeTokeniser);
|
|
};
|
|
|
|
#endif // __JUCE_CPLUSPLUSCODETOKENISER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CPlusPlusCodeTokeniser.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMBOBOX_JUCEHEADER__
|
|
|
|
/*** 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__
|
|
|
|
/**
|
|
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 caret != nullptr; }
|
|
|
|
/** 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. */
|
|
|
|
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);
|
|
|
|
/** Called when the user presses the return key. */
|
|
virtual void textEditorReturnKeyPressed (TextEditor& editor);
|
|
|
|
/** Called when the user presses the escape key. */
|
|
virtual void textEditorEscapeKeyPressed (TextEditor& editor);
|
|
|
|
/** Called when the text editor loses focus. */
|
|
virtual void textEditorFocusLost (TextEditor& editor);
|
|
};
|
|
|
|
/** 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. */
|
|
String getText() const;
|
|
|
|
/** Returns a section of the contents of the editor. */
|
|
const String getTextInRange (const Range<int>& 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 caret 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.
|
|
This doesn't copy the deleted section to the clipboard - if you need to do that, call copy() first.
|
|
@see copy, paste, SystemClipboard
|
|
*/
|
|
void cut();
|
|
|
|
/** Copies the currently selected region to the clipboard.
|
|
@see cut, paste, SystemClipboard
|
|
*/
|
|
void copy();
|
|
|
|
/** Pastes the contents of the clipboard into the editor at the caret 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<int> getCaretRectangle();
|
|
|
|
/** Selects a section of the text. */
|
|
void setHighlightedRegion (const Range<int>& newSelection);
|
|
|
|
/** Returns the range of characters that are selected.
|
|
If nothing is selected, this will return an empty range.
|
|
@see setHighlightedRegion
|
|
*/
|
|
const Range<int> getHighlightedRegion() const { return selection; }
|
|
|
|
/** Returns the section of text that is currently selected. */
|
|
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<int>& border);
|
|
|
|
/** Returns the size of border around the edge of the component.
|
|
|
|
@see setBorder
|
|
*/
|
|
const BorderSize<int> getBorder() const;
|
|
|
|
/** Used to disable the auto-scrolling which keeps the caret visible.
|
|
|
|
If true (the default), the editor will scroll when the caret moves offscreen. If
|
|
set to false, it won't.
|
|
*/
|
|
void setScrollToShowCursor (bool shouldScrollToShowCaret);
|
|
|
|
/** @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 */
|
|
void lookAndFeelChanged();
|
|
/** @internal */
|
|
bool isTextInputActive() const;
|
|
/** @internal */
|
|
void setTemporaryUnderlining (const Array <Range<int> >&);
|
|
|
|
bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting);
|
|
bool moveCaretRight (bool moveInWholeWordSteps, bool selecting);
|
|
bool moveCaretUp (bool selecting);
|
|
bool moveCaretDown (bool selecting);
|
|
bool pageUp (bool selecting);
|
|
bool pageDown (bool selecting);
|
|
bool scrollDown();
|
|
bool scrollUp();
|
|
bool moveCaretToTop (bool selecting);
|
|
bool moveCaretToStartOfLine (bool selecting);
|
|
bool moveCaretToEnd (bool selecting);
|
|
bool moveCaretToEndOfLine (bool selecting);
|
|
bool deleteBackwards (bool moveInWholeWordSteps);
|
|
bool deleteForwards (bool moveInWholeWordSteps);
|
|
bool copyToClipboard();
|
|
bool cutToClipboard();
|
|
bool pasteFromClipboard();
|
|
bool selectAll();
|
|
bool undo();
|
|
bool redo();
|
|
|
|
/** 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 moveCaretTo (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> viewport;
|
|
TextHolderComponent* textHolder;
|
|
BorderSize<int> borderSize;
|
|
|
|
bool readOnly : 1;
|
|
bool multiline : 1;
|
|
bool wordWrap : 1;
|
|
bool returnKeyStartsNewLine : 1;
|
|
bool popupMenuEnabled : 1;
|
|
bool selectAllTextWhenFocused : 1;
|
|
bool scrollbarVisible : 1;
|
|
bool wasFocused : 1;
|
|
bool keepCaretOnScreen : 1;
|
|
bool tabKeyUsed : 1;
|
|
bool menuActive : 1;
|
|
bool valueTextNeedsUpdating : 1;
|
|
|
|
UndoManager undoManager;
|
|
ScopedPointer<CaretComponent> caret;
|
|
int maxTextLength;
|
|
Range<int> selection;
|
|
int leftIndent, topIndent;
|
|
unsigned int lastTransactionTime;
|
|
Font currentFont;
|
|
mutable int totalNumChars;
|
|
int caretPosition;
|
|
Array <UniformTextSection*> sections;
|
|
String textToShowWhenEmpty;
|
|
Colour colourForTextWhenEmpty;
|
|
juce_wchar passwordCharacter;
|
|
Value textValue;
|
|
|
|
enum
|
|
{
|
|
notDragging,
|
|
draggingSelectionStart,
|
|
draggingSelectionEnd
|
|
} dragType;
|
|
|
|
String allowedCharacters;
|
|
ListenerList <Listener> listeners;
|
|
Array <Range<int> > underlinedSections;
|
|
|
|
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 <UniformTextSection*>& sections);
|
|
void remove (const Range<int>& range, UndoManager* um, int caretPositionToMoveTo);
|
|
void getCharPosition (int index, float& x, float& y, float& lineHeight) const;
|
|
void updateCaretPosition();
|
|
void updateValueFromText();
|
|
void textWasChangedByValue();
|
|
int indexAtPosition (float x, float y);
|
|
int findWordBreakAfter (int position) const;
|
|
int findWordBreakBefore (int position) const;
|
|
bool moveCaretWithTransation (int newPos, bool selecting);
|
|
friend class TextHolderComponent;
|
|
friend class TextEditorViewport;
|
|
void drawContent (Graphics& g);
|
|
void updateTextHolderSize();
|
|
float getWordWrapWidth() const;
|
|
void timerCallbackInt();
|
|
void repaintText (const Range<int>& range);
|
|
void scrollByLines (int deltaLines);
|
|
bool undoOrRedo (bool shouldUndo);
|
|
UndoManager* getUndoManager() noexcept;
|
|
|
|
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.
|
|
*/
|
|
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 noexcept;
|
|
|
|
/** 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 noexcept { 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 noexcept { return horizontalBorderSize; }
|
|
|
|
/** Returns the size of the vertical gap being left around the text.
|
|
*/
|
|
int getVerticalBorderSize() const noexcept { 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 noexcept { 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 noexcept { 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 noexcept { return editSingleClick; }
|
|
|
|
/** Returns true if this option was set using setEditable(). */
|
|
bool isEditableOnDoubleClick() const noexcept { return editDoubleClick; }
|
|
|
|
/** Returns true if this option has been set in a call to setEditable(). */
|
|
bool doesLossOfFocusDiscardChanges() const noexcept { return lossOfFocusDiscardsChanges; }
|
|
|
|
/** Returns true if the user can edit this label's text. */
|
|
bool isEditable() const noexcept { 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 noexcept;
|
|
|
|
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<TextEditor> editor;
|
|
ListenerList<Listener> listeners;
|
|
WeakReference<Component> ownerComponent;
|
|
int horizontalBorderSize, verticalBorderSize;
|
|
float minimumHorizontalScale;
|
|
bool editSingleClick : 1;
|
|
bool editDoubleClick : 1;
|
|
bool lossOfFocusDiscardsChanges : 1;
|
|
bool leftOfOwnerComp : 1;
|
|
|
|
bool updateFromTextEditorContents (TextEditor&);
|
|
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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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);
|
|
|
|
/** Returns true if the given item is enabled. */
|
|
bool isItemEnabled (int itemId) const noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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)
|
|
*/
|
|
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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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 noexcept;
|
|
|
|
/** 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
|
|
*/
|
|
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
|
|
*/
|
|
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
|
|
*/
|
|
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 noexcept;
|
|
bool isRealItem() const noexcept;
|
|
|
|
String name;
|
|
int itemId;
|
|
bool isEnabled : 1, isHeading : 1;
|
|
};
|
|
|
|
OwnedArray <ItemInfo> items;
|
|
Value currentId;
|
|
int lastCurrentId;
|
|
bool isButtonDown, separatorPending, menuActive, textIsCustom;
|
|
ListenerList <Listener> listeners;
|
|
ScopedPointer<Label> label;
|
|
String textWhenNothingSelected, noChoicesMessage;
|
|
|
|
ItemInfo* getItemForId (int itemId) const noexcept;
|
|
ItemInfo* getItemForIndex (int index) const noexcept;
|
|
bool selectIfEnabled (int index);
|
|
static void popupMenuFinishedCallback (int, ComboBox*);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComboBox);
|
|
};
|
|
|
|
/** This typedef is just for compatibility with old code - newer code should use the ComboBox::Listener class directly. */
|
|
typedef ComboBox::Listener ComboBoxListener;
|
|
|
|
#if JUCE_VC6
|
|
#undef Listener
|
|
#endif
|
|
|
|
#endif // __JUCE_COMBOBOX_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ComboBox.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_IMAGECOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ImageComponent.h ***/
|
|
#ifndef __JUCE_IMAGECOMPONENT_JUCEHEADER__
|
|
#define __JUCE_IMAGECOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component that simply displays an image.
|
|
|
|
Use setImage to give it an image, and it'll display it - simple as that!
|
|
*/
|
|
class JUCE_API ImageComponent : public Component,
|
|
public SettableTooltipClient
|
|
{
|
|
public:
|
|
|
|
/** Creates an ImageComponent. */
|
|
ImageComponent (const String& componentName = String::empty);
|
|
|
|
/** Destructor. */
|
|
~ImageComponent();
|
|
|
|
/** Sets the image that should be displayed. */
|
|
void setImage (const Image& newImage);
|
|
|
|
/** Sets the image that should be displayed, and its placement within the component. */
|
|
void setImage (const Image& newImage,
|
|
const RectanglePlacement& placementToUse);
|
|
|
|
/** Returns the current image. */
|
|
const Image& getImage() const;
|
|
|
|
/** Sets the method of positioning that will be used to fit the image within the component's bounds.
|
|
By default the positioning is centred, and will fit the image inside the component's bounds
|
|
whilst keeping its aspect ratio correct, but you can change it to whatever layout you need.
|
|
*/
|
|
void setImagePlacement (const RectanglePlacement& newPlacement);
|
|
|
|
/** Returns the current image placement. */
|
|
const RectanglePlacement getImagePlacement() const;
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
|
|
private:
|
|
Image image;
|
|
RectanglePlacement placement;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageComponent);
|
|
};
|
|
|
|
#endif // __JUCE_IMAGECOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ImageComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_LABEL_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_LISTBOX_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_PROGRESSBAR_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ProgressBar.h ***/
|
|
#ifndef __JUCE_PROGRESSBAR_JUCEHEADER__
|
|
#define __JUCE_PROGRESSBAR_JUCEHEADER__
|
|
|
|
/**
|
|
A progress bar component.
|
|
|
|
To use this, just create one and make it visible. It'll run its own timer
|
|
to keep an eye on a variable that you give it, and will automatically
|
|
redraw itself when the variable changes.
|
|
|
|
For an easy way of running a background task with a dialog box showing its
|
|
progress, see the ThreadWithProgressWindow class.
|
|
|
|
@see ThreadWithProgressWindow
|
|
*/
|
|
class JUCE_API ProgressBar : public Component,
|
|
public SettableTooltipClient,
|
|
private Timer
|
|
{
|
|
public:
|
|
|
|
/** Creates a ProgressBar.
|
|
|
|
@param progress pass in a reference to a double that you're going to
|
|
update with your task's progress. The ProgressBar will
|
|
monitor the value of this variable and will redraw itself
|
|
when the value changes. The range is from 0 to 1.0. Obviously
|
|
you'd better be careful not to delete this variable while the
|
|
ProgressBar still exists!
|
|
*/
|
|
explicit ProgressBar (double& progress);
|
|
|
|
/** Destructor. */
|
|
~ProgressBar();
|
|
|
|
/** Turns the percentage display on or off.
|
|
|
|
By default this is on, and the progress bar will display a text string showing
|
|
its current percentage.
|
|
*/
|
|
void setPercentageDisplay (bool shouldDisplayPercentage);
|
|
|
|
/** Gives the progress bar a string to display inside it.
|
|
|
|
If you call this, it will turn off the percentage display.
|
|
@see setPercentageDisplay
|
|
*/
|
|
void setTextToDisplay (const String& text);
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the bar.
|
|
|
|
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 = 0x1001900, /**< The background colour, behind the bar. */
|
|
foregroundColourId = 0x1001a00, /**< The colour to use to draw the bar itself. LookAndFeel
|
|
classes will probably use variations on this colour. */
|
|
};
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void lookAndFeelChanged();
|
|
/** @internal */
|
|
void visibilityChanged();
|
|
/** @internal */
|
|
void colourChanged();
|
|
|
|
private:
|
|
double& progress;
|
|
double currentValue;
|
|
bool displayPercentage;
|
|
String displayedMessage, currentMessage;
|
|
uint32 lastCallbackTime;
|
|
|
|
void timerCallback();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ProgressBar);
|
|
};
|
|
|
|
#endif // __JUCE_PROGRESSBAR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ProgressBar.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SLIDER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_Slider.h ***/
|
|
#ifndef __JUCE_SLIDER_JUCEHEADER__
|
|
#define __JUCE_SLIDER_JUCEHEADER__
|
|
|
|
#if JUCE_VC6
|
|
#define Listener LabelListener
|
|
#endif
|
|
|
|
/**
|
|
A slider control for changing a value.
|
|
|
|
The slider can be horizontal, vertical, or rotary, and can optionally have
|
|
a text-box inside it to show an editable display of the current value.
|
|
|
|
To use it, create a Slider object and use the setSliderStyle() method
|
|
to set up the type you want. To set up the text-entry box, use setTextBoxStyle().
|
|
|
|
To define the values that it can be set to, see the setRange() and setValue() methods.
|
|
|
|
There are also lots of custom tweaks you can do by subclassing and overriding
|
|
some of the virtual methods, such as changing the scaling, changing the format of
|
|
the text display, custom ways of limiting the values, etc.
|
|
|
|
You can register Slider::Listener objects with a slider, and they'll be called when
|
|
the value changes.
|
|
|
|
@see Slider::Listener
|
|
*/
|
|
class JUCE_API Slider : public Component,
|
|
public SettableTooltipClient,
|
|
public AsyncUpdater,
|
|
public ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
public LabelListener,
|
|
public ValueListener
|
|
{
|
|
public:
|
|
|
|
/** Creates a slider.
|
|
|
|
When created, you'll need to set up the slider's style and range with setSliderStyle(),
|
|
setRange(), etc.
|
|
*/
|
|
explicit Slider (const String& componentName = String::empty);
|
|
|
|
/** Destructor. */
|
|
~Slider();
|
|
|
|
/** The types of slider available.
|
|
|
|
@see setSliderStyle, setRotaryParameters
|
|
*/
|
|
enum SliderStyle
|
|
{
|
|
LinearHorizontal, /**< A traditional horizontal slider. */
|
|
LinearVertical, /**< A traditional vertical slider. */
|
|
LinearBar, /**< A horizontal bar slider with the text label drawn on top of it. */
|
|
Rotary, /**< A rotary control that you move by dragging the mouse in a circular motion, like a knob.
|
|
@see setRotaryParameters */
|
|
RotaryHorizontalDrag, /**< A rotary control that you move by dragging the mouse left-to-right.
|
|
@see setRotaryParameters */
|
|
RotaryVerticalDrag, /**< A rotary control that you move by dragging the mouse up-and-down.
|
|
@see setRotaryParameters */
|
|
IncDecButtons, /**< A pair of buttons that increment or decrement the slider's value by the increment set in setRange(). */
|
|
|
|
TwoValueHorizontal, /**< A horizontal slider that has two thumbs instead of one, so it can show a minimum and maximum value.
|
|
@see setMinValue, setMaxValue */
|
|
TwoValueVertical, /**< A vertical slider that has two thumbs instead of one, so it can show a minimum and maximum value.
|
|
@see setMinValue, setMaxValue */
|
|
|
|
ThreeValueHorizontal, /**< A horizontal slider that has three thumbs instead of one, so it can show a minimum and maximum
|
|
value, with the current value being somewhere between them.
|
|
@see setMinValue, setMaxValue */
|
|
ThreeValueVertical, /**< A vertical slider that has three thumbs instead of one, so it can show a minimum and maximum
|
|
value, with the current value being somewhere between them.
|
|
@see setMinValue, setMaxValue */
|
|
};
|
|
|
|
/** Changes the type of slider interface being used.
|
|
|
|
@param newStyle the type of interface
|
|
@see setRotaryParameters, setVelocityBasedMode,
|
|
*/
|
|
void setSliderStyle (SliderStyle newStyle);
|
|
|
|
/** Returns the slider's current style.
|
|
|
|
@see setSliderStyle
|
|
*/
|
|
SliderStyle getSliderStyle() const noexcept { return style; }
|
|
|
|
/** Changes the properties of a rotary slider.
|
|
|
|
@param startAngleRadians the angle (in radians, clockwise from the top) at which
|
|
the slider's minimum value is represented
|
|
@param endAngleRadians the angle (in radians, clockwise from the top) at which
|
|
the slider's maximum value is represented. This must be
|
|
greater than startAngleRadians
|
|
@param stopAtEnd if true, then when the slider is dragged around past the
|
|
minimum or maximum, it'll stop there; if false, it'll wrap
|
|
back to the opposite value
|
|
*/
|
|
void setRotaryParameters (float startAngleRadians,
|
|
float endAngleRadians,
|
|
bool stopAtEnd);
|
|
|
|
/** Sets the distance the mouse has to move to drag the slider across
|
|
the full extent of its range.
|
|
|
|
This only applies when in modes like RotaryHorizontalDrag, where it's using
|
|
relative mouse movements to adjust the slider.
|
|
*/
|
|
void setMouseDragSensitivity (int distanceForFullScaleDrag);
|
|
|
|
/** Returns the current sensitivity value set by setMouseDragSensitivity(). */
|
|
int getMouseDragSensitivity() const noexcept { return pixelsForFullDragExtent; }
|
|
|
|
/** Changes the way the the mouse is used when dragging the slider.
|
|
|
|
If true, this will turn on velocity-sensitive dragging, so that
|
|
the faster the mouse moves, the bigger the movement to the slider. This
|
|
helps when making accurate adjustments if the slider's range is quite large.
|
|
|
|
If false, the slider will just try to snap to wherever the mouse is.
|
|
*/
|
|
void setVelocityBasedMode (bool isVelocityBased);
|
|
|
|
/** Returns true if velocity-based mode is active.
|
|
@see setVelocityBasedMode
|
|
*/
|
|
bool getVelocityBasedMode() const noexcept { return isVelocityBased; }
|
|
|
|
/** Changes aspects of the scaling used when in velocity-sensitive mode.
|
|
|
|
These apply when you've used setVelocityBasedMode() to turn on velocity mode,
|
|
or if you're holding down ctrl.
|
|
|
|
@param sensitivity higher values than 1.0 increase the range of acceleration used
|
|
@param threshold the minimum number of pixels that the mouse needs to move for it
|
|
to be treated as a movement
|
|
@param offset values greater than 0.0 increase the minimum speed that will be used when
|
|
the threshold is reached
|
|
@param userCanPressKeyToSwapMode if true, then the user can hold down the ctrl or command
|
|
key to toggle velocity-sensitive mode
|
|
*/
|
|
void setVelocityModeParameters (double sensitivity = 1.0,
|
|
int threshold = 1,
|
|
double offset = 0.0,
|
|
bool userCanPressKeyToSwapMode = true);
|
|
|
|
/** Returns the velocity sensitivity setting.
|
|
@see setVelocityModeParameters
|
|
*/
|
|
double getVelocitySensitivity() const noexcept { return velocityModeSensitivity; }
|
|
|
|
/** Returns the velocity threshold setting.
|
|
@see setVelocityModeParameters
|
|
*/
|
|
int getVelocityThreshold() const noexcept { return velocityModeThreshold; }
|
|
|
|
/** Returns the velocity offset setting.
|
|
@see setVelocityModeParameters
|
|
*/
|
|
double getVelocityOffset() const noexcept { return velocityModeOffset; }
|
|
|
|
/** Returns the velocity user key setting.
|
|
@see setVelocityModeParameters
|
|
*/
|
|
bool getVelocityModeIsSwappable() const noexcept { return userKeyOverridesVelocity; }
|
|
|
|
/** Sets up a skew factor to alter the way values are distributed.
|
|
|
|
You may want to use a range of values on the slider where more accuracy
|
|
is required towards one end of the range, so this will logarithmically
|
|
spread the values across the length of the slider.
|
|
|
|
If the factor is < 1.0, the lower end of the range will fill more of the
|
|
slider's length; if the factor is > 1.0, the upper end of the range
|
|
will be expanded instead. A factor of 1.0 doesn't skew it at all.
|
|
|
|
To set the skew position by using a mid-point, use the setSkewFactorFromMidPoint()
|
|
method instead.
|
|
|
|
@see getSkewFactor, setSkewFactorFromMidPoint
|
|
*/
|
|
void setSkewFactor (double factor);
|
|
|
|
/** Sets up a skew factor to alter the way values are distributed.
|
|
|
|
This allows you to specify the slider value that should appear in the
|
|
centre of the slider's visible range.
|
|
|
|
@see setSkewFactor, getSkewFactor
|
|
*/
|
|
void setSkewFactorFromMidPoint (double sliderValueToShowAtMidPoint);
|
|
|
|
/** Returns the current skew factor.
|
|
|
|
See setSkewFactor for more info.
|
|
|
|
@see setSkewFactor, setSkewFactorFromMidPoint
|
|
*/
|
|
double getSkewFactor() const noexcept { return skewFactor; }
|
|
|
|
/** Used by setIncDecButtonsMode().
|
|
*/
|
|
enum IncDecButtonMode
|
|
{
|
|
incDecButtonsNotDraggable,
|
|
incDecButtonsDraggable_AutoDirection,
|
|
incDecButtonsDraggable_Horizontal,
|
|
incDecButtonsDraggable_Vertical
|
|
};
|
|
|
|
/** When the style is IncDecButtons, this lets you turn on a mode where the mouse
|
|
can be dragged on the buttons to drag the values.
|
|
|
|
By default this is turned off. When enabled, clicking on the buttons still works
|
|
them as normal, but by holding down the mouse on a button and dragging it a little
|
|
distance, it flips into a mode where the value can be dragged. The drag direction can
|
|
either be set explicitly to be vertical or horizontal, or can be set to
|
|
incDecButtonsDraggable_AutoDirection so that it depends on whether the buttons
|
|
are side-by-side or above each other.
|
|
*/
|
|
void setIncDecButtonsMode (IncDecButtonMode mode);
|
|
|
|
/** The position of the slider's text-entry box.
|
|
|
|
@see setTextBoxStyle
|
|
*/
|
|
enum TextEntryBoxPosition
|
|
{
|
|
NoTextBox, /**< Doesn't display a text box. */
|
|
TextBoxLeft, /**< Puts the text box to the left of the slider, vertically centred. */
|
|
TextBoxRight, /**< Puts the text box to the right of the slider, vertically centred. */
|
|
TextBoxAbove, /**< Puts the text box above the slider, horizontally centred. */
|
|
TextBoxBelow /**< Puts the text box below the slider, horizontally centred. */
|
|
};
|
|
|
|
/** Changes the location and properties of the text-entry box.
|
|
|
|
@param newPosition where it should go (or NoTextBox to not have one at all)
|
|
@param isReadOnly if true, it's a read-only display
|
|
@param textEntryBoxWidth the width of the text-box in pixels. Make sure this leaves enough
|
|
room for the slider as well!
|
|
@param textEntryBoxHeight the height of the text-box in pixels. Make sure this leaves enough
|
|
room for the slider as well!
|
|
|
|
@see setTextBoxIsEditable, getValueFromText, getTextFromValue
|
|
*/
|
|
void setTextBoxStyle (TextEntryBoxPosition newPosition,
|
|
bool isReadOnly,
|
|
int textEntryBoxWidth,
|
|
int textEntryBoxHeight);
|
|
|
|
/** Returns the status of the text-box.
|
|
@see setTextBoxStyle
|
|
*/
|
|
const TextEntryBoxPosition getTextBoxPosition() const noexcept { return textBoxPos; }
|
|
|
|
/** Returns the width used for the text-box.
|
|
@see setTextBoxStyle
|
|
*/
|
|
int getTextBoxWidth() const noexcept { return textBoxWidth; }
|
|
|
|
/** Returns the height used for the text-box.
|
|
@see setTextBoxStyle
|
|
*/
|
|
int getTextBoxHeight() const noexcept { return textBoxHeight; }
|
|
|
|
/** Makes the text-box editable.
|
|
|
|
By default this is true, and the user can enter values into the textbox,
|
|
but it can be turned off if that's not suitable.
|
|
|
|
@see setTextBoxStyle, getValueFromText, getTextFromValue
|
|
*/
|
|
void setTextBoxIsEditable (bool shouldBeEditable);
|
|
|
|
/** Returns true if the text-box is read-only.
|
|
@see setTextBoxStyle
|
|
*/
|
|
bool isTextBoxEditable() const { return editableText; }
|
|
|
|
/** If the text-box is editable, this will give it the focus so that the user can
|
|
type directly into it.
|
|
|
|
This is basically the effect as the user clicking on it.
|
|
*/
|
|
void showTextBox();
|
|
|
|
/** If the text-box currently has focus and is being edited, this resets it and takes keyboard
|
|
focus away from it.
|
|
|
|
@param discardCurrentEditorContents if true, the slider's value will be left
|
|
unchanged; if false, the current contents of the
|
|
text editor will be used to set the slider position
|
|
before it is hidden.
|
|
*/
|
|
void hideTextBox (bool discardCurrentEditorContents);
|
|
|
|
/** Changes the slider's current value.
|
|
|
|
This will trigger a callback to Slider::Listener::sliderValueChanged() for any listeners
|
|
that are registered, and will synchronously call the valueChanged() method in case subclasses
|
|
want to handle it.
|
|
|
|
@param newValue the new value to set - this will be restricted by the
|
|
minimum and maximum range, and will be snapped to the
|
|
nearest interval if one has been set
|
|
@param sendUpdateMessage if false, a change to the value will not trigger a call to
|
|
any Slider::Listeners or the valueChanged() method
|
|
@param sendMessageSynchronously if true, then a call to the Slider::Listeners will be made
|
|
synchronously; if false, it will be asynchronous
|
|
*/
|
|
void setValue (double newValue,
|
|
bool sendUpdateMessage = true,
|
|
bool sendMessageSynchronously = false);
|
|
|
|
/** Returns the slider's current value. */
|
|
double getValue() const;
|
|
|
|
/** Returns the Value object that represents the slider's current position.
|
|
You can use this Value object to connect the slider's position 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 Value, getMaxValue, getMinValueObject
|
|
*/
|
|
Value& getValueObject() { return currentValue; }
|
|
|
|
/** Sets the limits that the slider's value can take.
|
|
|
|
@param newMinimum the lowest value allowed
|
|
@param newMaximum the highest value allowed
|
|
@param newInterval the steps in which the value is allowed to increase - if this
|
|
is not zero, the value will always be (newMinimum + (newInterval * an integer)).
|
|
*/
|
|
void setRange (double newMinimum,
|
|
double newMaximum,
|
|
double newInterval = 0);
|
|
|
|
/** Returns the current maximum value.
|
|
@see setRange
|
|
*/
|
|
double getMaximum() const { return maximum; }
|
|
|
|
/** Returns the current minimum value.
|
|
@see setRange
|
|
*/
|
|
double getMinimum() const { return minimum; }
|
|
|
|
/** Returns the current step-size for values.
|
|
@see setRange
|
|
*/
|
|
double getInterval() const { return interval; }
|
|
|
|
/** For a slider with two or three thumbs, this returns the lower of its values.
|
|
|
|
For a two-value slider, the values are controlled with getMinValue() and getMaxValue().
|
|
A slider with three values also uses the normal getValue() and setValue() methods to
|
|
control the middle value.
|
|
|
|
@see setMinValue, getMaxValue, TwoValueHorizontal, TwoValueVertical, ThreeValueHorizontal, ThreeValueVertical
|
|
*/
|
|
double getMinValue() const;
|
|
|
|
/** For a slider with two or three thumbs, this returns the lower of its values.
|
|
You can use this Value object to connect the slider's position 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 Value, getMinValue, getMaxValueObject
|
|
*/
|
|
Value& getMinValueObject() noexcept { return valueMin; }
|
|
|
|
/** For a slider with two or three thumbs, this sets the lower of its values.
|
|
|
|
This will trigger a callback to Slider::Listener::sliderValueChanged() for any listeners
|
|
that are registered, and will synchronously call the valueChanged() method in case subclasses
|
|
want to handle it.
|
|
|
|
@param newValue the new value to set - this will be restricted by the
|
|
minimum and maximum range, and will be snapped to the nearest
|
|
interval if one has been set.
|
|
@param sendUpdateMessage if false, a change to the value will not trigger a call to
|
|
any Slider::Listeners or the valueChanged() method
|
|
@param sendMessageSynchronously if true, then a call to the Slider::Listeners will be made
|
|
synchronously; if false, it will be asynchronous
|
|
@param allowNudgingOfOtherValues if false, this value will be restricted to being below the
|
|
max value (in a two-value slider) or the mid value (in a three-value
|
|
slider). If false, then if this value goes beyond those values,
|
|
it will push them along with it.
|
|
@see getMinValue, setMaxValue, setValue
|
|
*/
|
|
void setMinValue (double newValue,
|
|
bool sendUpdateMessage = true,
|
|
bool sendMessageSynchronously = false,
|
|
bool allowNudgingOfOtherValues = false);
|
|
|
|
/** For a slider with two or three thumbs, this returns the higher of its values.
|
|
|
|
For a two-value slider, the values are controlled with getMinValue() and getMaxValue().
|
|
A slider with three values also uses the normal getValue() and setValue() methods to
|
|
control the middle value.
|
|
|
|
@see getMinValue, TwoValueHorizontal, TwoValueVertical, ThreeValueHorizontal, ThreeValueVertical
|
|
*/
|
|
double getMaxValue() const;
|
|
|
|
/** For a slider with two or three thumbs, this returns the higher of its values.
|
|
You can use this Value object to connect the slider's position 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 Value, getMaxValue, getMinValueObject
|
|
*/
|
|
Value& getMaxValueObject() noexcept { return valueMax; }
|
|
|
|
/** For a slider with two or three thumbs, this sets the lower of its values.
|
|
|
|
This will trigger a callback to Slider::Listener::sliderValueChanged() for any listeners
|
|
that are registered, and will synchronously call the valueChanged() method in case subclasses
|
|
want to handle it.
|
|
|
|
@param newValue the new value to set - this will be restricted by the
|
|
minimum and maximum range, and will be snapped to the nearest
|
|
interval if one has been set.
|
|
@param sendUpdateMessage if false, a change to the value will not trigger a call to
|
|
any Slider::Listeners or the valueChanged() method
|
|
@param sendMessageSynchronously if true, then a call to the Slider::Listeners will be made
|
|
synchronously; if false, it will be asynchronous
|
|
@param allowNudgingOfOtherValues if false, this value will be restricted to being above the
|
|
min value (in a two-value slider) or the mid value (in a three-value
|
|
slider). If false, then if this value goes beyond those values,
|
|
it will push them along with it.
|
|
@see getMaxValue, setMinValue, setValue
|
|
*/
|
|
void setMaxValue (double newValue,
|
|
bool sendUpdateMessage = true,
|
|
bool sendMessageSynchronously = false,
|
|
bool allowNudgingOfOtherValues = false);
|
|
|
|
/** For a slider with two or three thumbs, this sets the minimum and maximum thumb positions.
|
|
|
|
This will trigger a callback to Slider::Listener::sliderValueChanged() for any listeners
|
|
that are registered, and will synchronously call the valueChanged() method in case subclasses
|
|
want to handle it.
|
|
|
|
@param newMinValue the new minimum value to set - this will be snapped to the
|
|
nearest interval if one has been set.
|
|
@param newMaxValue the new minimum value to set - this will be snapped to the
|
|
nearest interval if one has been set.
|
|
@param sendUpdateMessage if false, a change to the value will not trigger a call to
|
|
any Slider::Listeners or the valueChanged() method
|
|
@param sendMessageSynchronously if true, then a call to the Slider::Listeners will be made
|
|
synchronously; if false, it will be asynchronous
|
|
@see setMaxValue, setMinValue, setValue
|
|
*/
|
|
void setMinAndMaxValues (double newMinValue, double newMaxValue,
|
|
bool sendUpdateMessage = true,
|
|
bool sendMessageSynchronously = false);
|
|
|
|
/** A class for receiving callbacks from a Slider.
|
|
|
|
To be told when a slider's value changes, you can register a Slider::Listener
|
|
object using Slider::addListener().
|
|
|
|
@see Slider::addListener, Slider::removeListener
|
|
*/
|
|
class JUCE_API Listener
|
|
{
|
|
public:
|
|
|
|
/** Destructor. */
|
|
virtual ~Listener() {}
|
|
|
|
/** Called when the slider's value is changed.
|
|
|
|
This may be caused by dragging it, or by typing in its text entry box,
|
|
or by a call to Slider::setValue().
|
|
|
|
You can find out the new value using Slider::getValue().
|
|
|
|
@see Slider::valueChanged
|
|
*/
|
|
virtual void sliderValueChanged (Slider* slider) = 0;
|
|
|
|
/** Called when the slider is about to be dragged.
|
|
|
|
This is called when a drag begins, then it's followed by multiple calls
|
|
to sliderValueChanged(), and then sliderDragEnded() is called after the
|
|
user lets go.
|
|
|
|
@see sliderDragEnded, Slider::startedDragging
|
|
*/
|
|
virtual void sliderDragStarted (Slider* slider);
|
|
|
|
/** Called after a drag operation has finished.
|
|
|
|
@see sliderDragStarted, Slider::stoppedDragging
|
|
*/
|
|
virtual void sliderDragEnded (Slider* slider);
|
|
};
|
|
|
|
/** Adds a listener to be called when this slider's value changes. */
|
|
void addListener (Listener* listener);
|
|
|
|
/** Removes a previously-registered listener. */
|
|
void removeListener (Listener* listener);
|
|
|
|
/** This lets you choose whether double-clicking moves the slider to a given position.
|
|
|
|
By default this is turned off, but it's handy if you want a double-click to act
|
|
as a quick way of resetting a slider. Just pass in the value you want it to
|
|
go to when double-clicked.
|
|
|
|
@see getDoubleClickReturnValue
|
|
*/
|
|
void setDoubleClickReturnValue (bool isDoubleClickEnabled,
|
|
double valueToSetOnDoubleClick);
|
|
|
|
/** Returns the values last set by setDoubleClickReturnValue() method.
|
|
|
|
Sets isEnabled to true if double-click is enabled, and returns the value
|
|
that was set.
|
|
|
|
@see setDoubleClickReturnValue
|
|
*/
|
|
double getDoubleClickReturnValue (bool& isEnabled) const;
|
|
|
|
/** Tells the slider whether to keep sending change messages while the user
|
|
is dragging the slider.
|
|
|
|
If set to true, a change message will only be sent when the user has
|
|
dragged the slider and let go. If set to false (the default), then messages
|
|
will be continuously sent as they drag it while the mouse button is still
|
|
held down.
|
|
*/
|
|
void setChangeNotificationOnlyOnRelease (bool onlyNotifyOnRelease);
|
|
|
|
/** This lets you change whether the slider thumb jumps to the mouse position
|
|
when you click.
|
|
|
|
By default, this is true. If it's false, then the slider moves with relative
|
|
motion when you drag it.
|
|
|
|
This only applies to linear bars, and won't affect two- or three- value
|
|
sliders.
|
|
*/
|
|
void setSliderSnapsToMousePosition (bool shouldSnapToMouse);
|
|
|
|
/** If enabled, this gives the slider a pop-up bubble which appears while the
|
|
slider is being dragged.
|
|
|
|
This can be handy if your slider doesn't have a text-box, so that users can
|
|
see the value just when they're changing it.
|
|
|
|
If you pass a component as the parentComponentToUse parameter, the pop-up
|
|
bubble will be added as a child of that component when it's needed. If you
|
|
pass 0, the pop-up will be placed on the desktop instead (note that it's a
|
|
transparent window, so if you're using an OS that can't do transparent windows
|
|
you'll have to add it to a parent component instead).
|
|
*/
|
|
void setPopupDisplayEnabled (bool isEnabled,
|
|
Component* parentComponentToUse);
|
|
|
|
/** If this is set to true, then right-clicking on the slider will pop-up
|
|
a menu to let the user change the way it works.
|
|
|
|
By default this is turned off, but when turned on, the menu will include
|
|
things like velocity sensitivity, and for rotary sliders, whether they
|
|
use a linear or rotary mouse-drag to move them.
|
|
*/
|
|
void setPopupMenuEnabled (bool menuEnabled);
|
|
|
|
/** This can be used to stop the mouse scroll-wheel from moving the slider.
|
|
|
|
By default it's enabled.
|
|
*/
|
|
void setScrollWheelEnabled (bool enabled);
|
|
|
|
/** Returns a number to indicate which thumb is currently being dragged by the
|
|
mouse.
|
|
|
|
This will return 0 for the main thumb, 1 for the minimum-value thumb, 2 for
|
|
the maximum-value thumb, or -1 if none is currently down.
|
|
*/
|
|
int getThumbBeingDragged() const noexcept { return sliderBeingDragged; }
|
|
|
|
/** Callback to indicate that the user is about to start dragging the slider.
|
|
|
|
@see Slider::Listener::sliderDragStarted
|
|
*/
|
|
virtual void startedDragging();
|
|
|
|
/** Callback to indicate that the user has just stopped dragging the slider.
|
|
|
|
@see Slider::Listener::sliderDragEnded
|
|
*/
|
|
virtual void stoppedDragging();
|
|
|
|
/** Callback to indicate that the user has just moved the slider.
|
|
|
|
@see Slider::Listener::sliderValueChanged
|
|
*/
|
|
virtual void valueChanged();
|
|
|
|
/** Subclasses can override this to convert a text string to a value.
|
|
|
|
When the user enters something into the text-entry box, this method is
|
|
called to convert it to a value.
|
|
|
|
The default routine just tries to convert it to a double.
|
|
|
|
@see getTextFromValue
|
|
*/
|
|
virtual double getValueFromText (const String& text);
|
|
|
|
/** Turns the slider's current value into a text string.
|
|
|
|
Subclasses can override this to customise the formatting of the text-entry box.
|
|
|
|
The default implementation just turns the value into a string, using
|
|
a number of decimal places based on the range interval. If a suffix string
|
|
has been set using setTextValueSuffix(), this will be appended to the text.
|
|
|
|
@see getValueFromText
|
|
*/
|
|
virtual const String getTextFromValue (double value);
|
|
|
|
/** Sets a suffix to append to the end of the numeric value when it's displayed as
|
|
a string.
|
|
|
|
This is used by the default implementation of getTextFromValue(), and is just
|
|
appended to the numeric value. For more advanced formatting, you can override
|
|
getTextFromValue() and do something else.
|
|
*/
|
|
void setTextValueSuffix (const String& suffix);
|
|
|
|
/** Returns the suffix that was set by setTextValueSuffix(). */
|
|
String getTextValueSuffix() const;
|
|
|
|
/** Allows a user-defined mapping of distance along the slider to its value.
|
|
|
|
The default implementation for this performs the skewing operation that
|
|
can be set up in the setSkewFactor() method. Override it if you need
|
|
some kind of custom mapping instead, but make sure you also implement the
|
|
inverse function in valueToProportionOfLength().
|
|
|
|
@param proportion a value 0 to 1.0, indicating a distance along the slider
|
|
@returns the slider value that is represented by this position
|
|
@see valueToProportionOfLength
|
|
*/
|
|
virtual double proportionOfLengthToValue (double proportion);
|
|
|
|
/** Allows a user-defined mapping of value to the position of the slider along its length.
|
|
|
|
The default implementation for this performs the skewing operation that
|
|
can be set up in the setSkewFactor() method. Override it if you need
|
|
some kind of custom mapping instead, but make sure you also implement the
|
|
inverse function in proportionOfLengthToValue().
|
|
|
|
@param value a valid slider value, between the range of values specified in
|
|
setRange()
|
|
@returns a value 0 to 1.0 indicating the distance along the slider that
|
|
represents this value
|
|
@see proportionOfLengthToValue
|
|
*/
|
|
virtual double valueToProportionOfLength (double value);
|
|
|
|
/** Returns the X or Y coordinate of a value along the slider's length.
|
|
|
|
If the slider is horizontal, this will be the X coordinate of the given
|
|
value, relative to the left of the slider. If it's vertical, then this will
|
|
be the Y coordinate, relative to the top of the slider.
|
|
|
|
If the slider is rotary, this will throw an assertion and return 0. If the
|
|
value is out-of-range, it will be constrained to the length of the slider.
|
|
*/
|
|
float getPositionOfValue (double value);
|
|
|
|
/** This can be overridden to allow the slider to snap to user-definable values.
|
|
|
|
If overridden, it will be called when the user tries to move the slider to
|
|
a given position, and allows a subclass to sanity-check this value, possibly
|
|
returning a different value to use instead.
|
|
|
|
@param attemptedValue the value the user is trying to enter
|
|
@param userIsDragging true if the user is dragging with the mouse; false if
|
|
they are entering the value using the text box
|
|
@returns the value to use instead
|
|
*/
|
|
virtual double snapValue (double attemptedValue, bool userIsDragging);
|
|
|
|
/** This can be called to force the text box to update its contents.
|
|
|
|
(Not normally needed, as this is done automatically).
|
|
*/
|
|
void updateText();
|
|
|
|
/** True if the slider moves horizontally. */
|
|
bool isHorizontal() const;
|
|
/** True if the slider moves vertically. */
|
|
bool isVertical() const;
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the slider.
|
|
|
|
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 = 0x1001200, /**< A colour to use to fill the slider's background. */
|
|
thumbColourId = 0x1001300, /**< The colour to draw the thumb with. It's up to the look
|
|
and feel class how this is used. */
|
|
trackColourId = 0x1001310, /**< The colour to draw the groove that the thumb moves along. */
|
|
rotarySliderFillColourId = 0x1001311, /**< For rotary sliders, this colour fills the outer curve. */
|
|
rotarySliderOutlineColourId = 0x1001312, /**< For rotary sliders, this colour is used to draw the outer curve's outline. */
|
|
|
|
textBoxTextColourId = 0x1001400, /**< The colour for the text in the text-editor box used for editing the value. */
|
|
textBoxBackgroundColourId = 0x1001500, /**< The background colour for the text-editor box. */
|
|
textBoxHighlightColourId = 0x1001600, /**< The text highlight colour for the text-editor box. */
|
|
textBoxOutlineColourId = 0x1001700 /**< The colour to use for a border around the text-editor box. */
|
|
};
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void labelTextChanged (Label*);
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @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 */
|
|
void modifierKeysChanged (const ModifierKeys& modifiers);
|
|
/** @internal */
|
|
void buttonClicked (Button* button);
|
|
/** @internal */
|
|
void lookAndFeelChanged();
|
|
/** @internal */
|
|
void enablementChanged();
|
|
/** @internal */
|
|
void focusOfChildComponentChanged (FocusChangeType cause);
|
|
/** @internal */
|
|
void handleAsyncUpdate();
|
|
/** @internal */
|
|
void colourChanged();
|
|
/** @internal */
|
|
void valueChanged (Value& value);
|
|
|
|
/** Returns the best number of decimal places to use when displaying numbers.
|
|
This is calculated from the slider's interval setting.
|
|
*/
|
|
int getNumDecimalPlacesToDisplay() const noexcept { return numDecimalPlaces; }
|
|
|
|
private:
|
|
|
|
ListenerList <Listener> listeners;
|
|
Value currentValue, valueMin, valueMax;
|
|
double lastCurrentValue, lastValueMin, lastValueMax;
|
|
double minimum, maximum, interval, doubleClickReturnValue;
|
|
double valueWhenLastDragged, valueOnMouseDown, skewFactor, lastAngle;
|
|
double velocityModeSensitivity, velocityModeOffset, minMaxDiff;
|
|
int velocityModeThreshold;
|
|
float rotaryStart, rotaryEnd;
|
|
int numDecimalPlaces;
|
|
Point<int> mousePosWhenLastDragged;
|
|
int mouseDragStartX, mouseDragStartY;
|
|
int sliderRegionStart, sliderRegionSize;
|
|
int sliderBeingDragged;
|
|
int pixelsForFullDragExtent;
|
|
Rectangle<int> sliderRect;
|
|
String textSuffix;
|
|
|
|
SliderStyle style;
|
|
TextEntryBoxPosition textBoxPos;
|
|
int textBoxWidth, textBoxHeight;
|
|
IncDecButtonMode incDecButtonMode;
|
|
|
|
bool editableText : 1, doubleClickToValue : 1;
|
|
bool isVelocityBased : 1, userKeyOverridesVelocity : 1, rotaryStop : 1;
|
|
bool incDecButtonsSideBySide : 1, sendChangeOnlyOnRelease : 1, popupDisplayEnabled : 1;
|
|
bool menuEnabled : 1, menuShown : 1, mouseWasHidden : 1, incDecDragged : 1;
|
|
bool scrollWheelEnabled : 1, snapsToMousePos : 1;
|
|
ScopedPointer<Label> valueBox;
|
|
ScopedPointer<Button> incButton, decButton;
|
|
|
|
class PopupDisplayComponent;
|
|
friend class PopupDisplayComponent;
|
|
friend class ScopedPointer <PopupDisplayComponent>;
|
|
ScopedPointer <PopupDisplayComponent> popupDisplay;
|
|
Component* parentForPopupDisplay;
|
|
|
|
float getLinearSliderPos (double value);
|
|
void restoreMouseIfHidden();
|
|
void sendDragStart();
|
|
void sendDragEnd();
|
|
double constrainedValue (double value) const;
|
|
void triggerChangeMessage (bool synchronous);
|
|
bool incDecDragDirectionIsHorizontal() const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Slider);
|
|
};
|
|
|
|
/** This typedef is just for compatibility with old code - newer code should use the Slider::Listener class directly. */
|
|
typedef Slider::Listener SliderListener;
|
|
|
|
#if JUCE_VC6
|
|
#undef Listener
|
|
#endif
|
|
|
|
#endif // __JUCE_SLIDER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_Slider.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_TableHeaderComponent.h ***/
|
|
#ifndef __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component that displays a strip of column headings for a table, and allows these
|
|
to be resized, dragged around, etc.
|
|
|
|
This is just the component that goes at the top of a table. You can use it
|
|
directly for custom components, or to create a simple table, use the
|
|
TableListBox class.
|
|
|
|
To use one of these, create it and use addColumn() to add all the columns that you need.
|
|
Each column must be given a unique ID number that's used to refer to it.
|
|
|
|
@see TableListBox, TableHeaderComponent::Listener
|
|
*/
|
|
class JUCE_API TableHeaderComponent : public Component,
|
|
private AsyncUpdater
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty table header.
|
|
*/
|
|
TableHeaderComponent();
|
|
|
|
/** Destructor. */
|
|
~TableHeaderComponent();
|
|
|
|
/** A combination of these flags are passed into the addColumn() method to specify
|
|
the properties of a column.
|
|
*/
|
|
enum ColumnPropertyFlags
|
|
{
|
|
visible = 1, /**< If this is set, the column will be shown; if not, it will be hidden until the user enables it with the pop-up menu. */
|
|
resizable = 2, /**< If this is set, the column can be resized by dragging it. */
|
|
draggable = 4, /**< If this is set, the column can be dragged around to change its order in the table. */
|
|
appearsOnColumnMenu = 8, /**< If this is set, the column will be shown on the pop-up menu allowing it to be hidden/shown. */
|
|
sortable = 16, /**< If this is set, then clicking on the column header will set it to be the sort column, and clicking again will reverse the order. */
|
|
sortedForwards = 32, /**< If this is set, the column is currently the one by which the table is sorted (forwards). */
|
|
sortedBackwards = 64, /**< If this is set, the column is currently the one by which the table is sorted (backwards). */
|
|
|
|
/** This set of default flags is used as the default parameter value in addColumn(). */
|
|
defaultFlags = (visible | resizable | draggable | appearsOnColumnMenu | sortable),
|
|
|
|
/** A quick way of combining flags for a column that's not resizable. */
|
|
notResizable = (visible | draggable | appearsOnColumnMenu | sortable),
|
|
|
|
/** A quick way of combining flags for a column that's not resizable or sortable. */
|
|
notResizableOrSortable = (visible | draggable | appearsOnColumnMenu),
|
|
|
|
/** A quick way of combining flags for a column that's not sortable. */
|
|
notSortable = (visible | resizable | draggable | appearsOnColumnMenu)
|
|
};
|
|
|
|
/** Adds a column to the table.
|
|
|
|
This will add a column, and asynchronously call the tableColumnsChanged() method of any
|
|
registered listeners.
|
|
|
|
@param columnName the name of the new column. It's ok to have two or more columns with the same name
|
|
@param columnId an ID for this column. The ID can be any number apart from 0, but every column must have
|
|
a unique ID. This is used to identify the column later on, after the user may have
|
|
changed the order that they appear in
|
|
@param width the initial width of the column, in pixels
|
|
@param maximumWidth a maximum width that the column can take when the user is resizing it. This only applies
|
|
if the 'resizable' flag is specified for this column
|
|
@param minimumWidth a minimum width that the column can take when the user is resizing it. This only applies
|
|
if the 'resizable' flag is specified for this column
|
|
@param propertyFlags a combination of some of the values from the ColumnPropertyFlags enum, to define the
|
|
properties of this column
|
|
@param insertIndex the index at which the column should be added. A value of 0 puts it at the start (left-hand side)
|
|
and -1 puts it at the end (right-hand size) of the table. Note that the index the index within
|
|
all columns, not just the index amongst those that are currently visible
|
|
*/
|
|
void addColumn (const String& columnName,
|
|
int columnId,
|
|
int width,
|
|
int minimumWidth = 30,
|
|
int maximumWidth = -1,
|
|
int propertyFlags = defaultFlags,
|
|
int insertIndex = -1);
|
|
|
|
/** Removes a column with the given ID.
|
|
|
|
If there is such a column, this will asynchronously call the tableColumnsChanged() method of any
|
|
registered listeners.
|
|
*/
|
|
void removeColumn (int columnIdToRemove);
|
|
|
|
/** Deletes all columns from the table.
|
|
|
|
If there are any columns to remove, this will asynchronously call the tableColumnsChanged() method of any
|
|
registered listeners.
|
|
*/
|
|
void removeAllColumns();
|
|
|
|
/** Returns the number of columns in the table.
|
|
|
|
If onlyCountVisibleColumns is true, this will return the number of visible columns; otherwise it'll
|
|
return the total number of columns, including hidden ones.
|
|
|
|
@see isColumnVisible
|
|
*/
|
|
int getNumColumns (bool onlyCountVisibleColumns) const;
|
|
|
|
/** Returns the name for a column.
|
|
@see setColumnName
|
|
*/
|
|
String getColumnName (int columnId) const;
|
|
|
|
/** Changes the name of a column. */
|
|
void setColumnName (int columnId, const String& newName);
|
|
|
|
/** Moves a column to a different index in the table.
|
|
|
|
@param columnId the column to move
|
|
@param newVisibleIndex the target index for it, from 0 to the number of columns currently visible.
|
|
*/
|
|
void moveColumn (int columnId, int newVisibleIndex);
|
|
|
|
/** Returns the width of one of the columns.
|
|
*/
|
|
int getColumnWidth (int columnId) const;
|
|
|
|
/** Changes the width of a column.
|
|
|
|
This will cause an asynchronous callback to the tableColumnsResized() method of any registered listeners.
|
|
*/
|
|
void setColumnWidth (int columnId, int newWidth);
|
|
|
|
/** Shows or hides a column.
|
|
|
|
This can cause an asynchronous callback to the tableColumnsChanged() method of any registered listeners.
|
|
@see isColumnVisible
|
|
*/
|
|
void setColumnVisible (int columnId, bool shouldBeVisible);
|
|
|
|
/** Returns true if this column is currently visible.
|
|
@see setColumnVisible
|
|
*/
|
|
bool isColumnVisible (int columnId) const;
|
|
|
|
/** Changes the column which is the sort column.
|
|
|
|
This can cause an asynchronous callback to the tableSortOrderChanged() method of any registered listeners.
|
|
|
|
If this method doesn't actually change the column ID, then no re-sort will take place (you can
|
|
call reSortTable() to force a re-sort to happen if you've modified the table's contents).
|
|
|
|
@see getSortColumnId, isSortedForwards, reSortTable
|
|
*/
|
|
void setSortColumnId (int columnId, bool sortForwards);
|
|
|
|
/** Returns the column ID by which the table is currently sorted, or 0 if it is unsorted.
|
|
|
|
@see setSortColumnId, isSortedForwards
|
|
*/
|
|
int getSortColumnId() const;
|
|
|
|
/** Returns true if the table is currently sorted forwards, or false if it's backwards.
|
|
@see setSortColumnId
|
|
*/
|
|
bool isSortedForwards() const;
|
|
|
|
/** Triggers a re-sort of the table according to the current sort-column.
|
|
|
|
If you modifiy the table's contents, you can call this to signal that the table needs
|
|
to be re-sorted.
|
|
|
|
(This doesn't do any sorting synchronously - it just asynchronously sends a call to the
|
|
tableSortOrderChanged() method of any listeners).
|
|
*/
|
|
void reSortTable();
|
|
|
|
/** Returns the total width of all the visible columns in the table.
|
|
*/
|
|
int getTotalWidth() const;
|
|
|
|
/** Returns the index of a given column.
|
|
|
|
If there's no such column ID, this will return -1.
|
|
|
|
If onlyCountVisibleColumns is true, this will return the index amoungst the visible columns;
|
|
otherwise it'll return the index amongst all the columns, including any hidden ones.
|
|
*/
|
|
int getIndexOfColumnId (int columnId, bool onlyCountVisibleColumns) const;
|
|
|
|
/** Returns the ID of the column at a given index.
|
|
|
|
If onlyCountVisibleColumns is true, this will count the index amoungst the visible columns;
|
|
otherwise it'll count it amongst all the columns, including any hidden ones.
|
|
|
|
If the index is out-of-range, it'll return 0.
|
|
*/
|
|
int getColumnIdOfIndex (int index, bool onlyCountVisibleColumns) const;
|
|
|
|
/** Returns the rectangle containing of one of the columns.
|
|
|
|
The index is an index from 0 to the number of columns that are currently visible (hidden
|
|
ones are not counted). It returns a rectangle showing the position of the column relative
|
|
to this component's top-left. If the index is out-of-range, an empty rectangle is retrurned.
|
|
*/
|
|
const Rectangle<int> getColumnPosition (int index) const;
|
|
|
|
/** Finds the column ID at a given x-position in the component.
|
|
|
|
If there is a column at this point this returns its ID, or if not, it will return 0.
|
|
*/
|
|
int getColumnIdAtX (int xToFind) const;
|
|
|
|
/** If set to true, this indicates that the columns should be expanded or shrunk to fill the
|
|
entire width of the component.
|
|
|
|
By default this is disabled. Turning it on also means that when resizing a column, those
|
|
on the right will be squashed to fit.
|
|
*/
|
|
void setStretchToFitActive (bool shouldStretchToFit);
|
|
|
|
/** Returns true if stretch-to-fit has been enabled.
|
|
@see setStretchToFitActive
|
|
*/
|
|
bool isStretchToFitActive() const;
|
|
|
|
/** If stretch-to-fit is enabled, this will resize all the columns to make them fit into the
|
|
specified width, keeping their relative proportions the same.
|
|
|
|
If the minimum widths of the columns are too wide to fit into this space, it may
|
|
actually end up wider.
|
|
*/
|
|
void resizeAllColumnsToFit (int targetTotalWidth);
|
|
|
|
/** Enables or disables the pop-up menu.
|
|
|
|
The default menu allows the user to show or hide columns. You can add custom
|
|
items to this menu by overloading the addMenuItems() and reactToMenuItem() methods.
|
|
|
|
By default the menu is enabled.
|
|
|
|
@see isPopupMenuActive, addMenuItems, reactToMenuItem
|
|
*/
|
|
void setPopupMenuActive (bool hasMenu);
|
|
|
|
/** Returns true if the pop-up menu is enabled.
|
|
@see setPopupMenuActive
|
|
*/
|
|
bool isPopupMenuActive() const;
|
|
|
|
/** Returns a string that encapsulates the table's current layout.
|
|
|
|
This can be restored later using restoreFromString(). It saves the order of
|
|
the columns, the currently-sorted column, and the widths.
|
|
|
|
@see restoreFromString
|
|
*/
|
|
String toString() const;
|
|
|
|
/** Restores the state of the table, based on a string previously created with
|
|
toString().
|
|
|
|
@see toString
|
|
*/
|
|
void restoreFromString (const String& storedVersion);
|
|
|
|
/**
|
|
Receives events from a TableHeaderComponent when columns are resized, moved, etc.
|
|
|
|
You can register one of these objects for table events using TableHeaderComponent::addListener()
|
|
and TableHeaderComponent::removeListener().
|
|
|
|
@see TableHeaderComponent
|
|
*/
|
|
class JUCE_API Listener
|
|
{
|
|
public:
|
|
|
|
Listener() {}
|
|
|
|
/** Destructor. */
|
|
virtual ~Listener() {}
|
|
|
|
/** This is called when some of the table's columns are added, removed, hidden,
|
|
or rearranged.
|
|
*/
|
|
virtual void tableColumnsChanged (TableHeaderComponent* tableHeader) = 0;
|
|
|
|
/** This is called when one or more of the table's columns are resized.
|
|
*/
|
|
virtual void tableColumnsResized (TableHeaderComponent* tableHeader) = 0;
|
|
|
|
/** This is called when the column by which the table should be sorted is changed.
|
|
*/
|
|
virtual void tableSortOrderChanged (TableHeaderComponent* tableHeader) = 0;
|
|
|
|
/** This is called when the user begins or ends dragging one of the columns around.
|
|
|
|
When the user starts dragging a column, this is called with the ID of that
|
|
column. When they finish dragging, it is called again with 0 as the ID.
|
|
*/
|
|
virtual void tableColumnDraggingChanged (TableHeaderComponent* tableHeader,
|
|
int columnIdNowBeingDragged);
|
|
};
|
|
|
|
/** Adds a listener to be informed about things that happen to the header. */
|
|
void addListener (Listener* newListener);
|
|
|
|
/** Removes a previously-registered listener. */
|
|
void removeListener (Listener* listenerToRemove);
|
|
|
|
/** This can be overridden to handle a mouse-click on one of the column headers.
|
|
|
|
The default implementation will use this click to call getSortColumnId() and
|
|
change the sort order.
|
|
*/
|
|
virtual void columnClicked (int columnId, const ModifierKeys& mods);
|
|
|
|
/** This can be overridden to add custom items to the pop-up menu.
|
|
|
|
If you override this, you should call the superclass's method to add its
|
|
column show/hide items, if you want them on the menu as well.
|
|
|
|
Then to handle the result, override reactToMenuItem().
|
|
|
|
@see reactToMenuItem
|
|
*/
|
|
virtual void addMenuItems (PopupMenu& menu, int columnIdClicked);
|
|
|
|
/** Override this to handle any custom items that you have added to the
|
|
pop-up menu with an addMenuItems() override.
|
|
|
|
If the menuReturnId isn't one of your own custom menu items, you'll need to
|
|
call TableHeaderComponent::reactToMenuItem() to allow the base class to
|
|
handle the items that it had added.
|
|
|
|
@see addMenuItems
|
|
*/
|
|
virtual void reactToMenuItem (int menuReturnId, int columnIdClicked);
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void mouseMove (const MouseEvent&);
|
|
/** @internal */
|
|
void mouseEnter (const MouseEvent&);
|
|
/** @internal */
|
|
void mouseExit (const MouseEvent&);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent&);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent&);
|
|
/** @internal */
|
|
void mouseUp (const MouseEvent&);
|
|
/** @internal */
|
|
const MouseCursor getMouseCursor();
|
|
|
|
/** Can be overridden for more control over the pop-up menu behaviour. */
|
|
virtual void showColumnChooserMenu (int columnIdClicked);
|
|
|
|
private:
|
|
struct ColumnInfo
|
|
{
|
|
String name;
|
|
int id, propertyFlags, width, minimumWidth, maximumWidth;
|
|
double lastDeliberateWidth;
|
|
|
|
bool isVisible() const;
|
|
};
|
|
|
|
OwnedArray <ColumnInfo> columns;
|
|
Array <Listener*> listeners;
|
|
ScopedPointer <Component> dragOverlayComp;
|
|
|
|
bool columnsChanged, columnsResized, sortChanged, menuActive, stretchToFit;
|
|
int columnIdBeingResized, columnIdBeingDragged, initialColumnWidth;
|
|
int columnIdUnderMouse, draggingColumnOffset, draggingColumnOriginalIndex, lastDeliberateWidth;
|
|
|
|
ColumnInfo* getInfoForId (int columnId) const;
|
|
int visibleIndexToTotalIndex (int visibleIndex) const;
|
|
void sendColumnsChanged();
|
|
void handleAsyncUpdate();
|
|
void beginDrag (const MouseEvent&);
|
|
void endDrag (int finalIndex);
|
|
int getResizeDraggerAt (int mouseX) const;
|
|
void updateColumnUnderMouse (int x, int y);
|
|
void resizeColumnsToFit (int firstColumnIndex, int targetTotalWidth);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TableHeaderComponent);
|
|
};
|
|
|
|
/** This typedef is just for compatibility with old code - newer code should use the TableHeaderComponent::Listener class directly. */
|
|
typedef TableHeaderComponent::Listener TableHeaderListener;
|
|
|
|
#endif // __JUCE_TABLEHEADERCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TableHeaderComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TABLELISTBOX_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_TableListBox.h ***/
|
|
#ifndef __JUCE_TABLELISTBOX_JUCEHEADER__
|
|
#define __JUCE_TABLELISTBOX_JUCEHEADER__
|
|
|
|
/**
|
|
One of these is used by a TableListBox as the data model for the table's contents.
|
|
|
|
The virtual methods that you override in this class take care of drawing the
|
|
table cells, and reacting to events.
|
|
|
|
@see TableListBox
|
|
*/
|
|
class JUCE_API TableListBoxModel
|
|
{
|
|
public:
|
|
|
|
TableListBoxModel() {}
|
|
|
|
/** Destructor. */
|
|
virtual ~TableListBoxModel() {}
|
|
|
|
/** This must return the number of rows currently in the table.
|
|
|
|
If the number of rows changes, you must call TableListBox::updateContent() to
|
|
cause it to refresh the list.
|
|
*/
|
|
virtual int getNumRows() = 0;
|
|
|
|
/** This must draw the background behind one of the rows in the table.
|
|
|
|
The graphics context has its origin at the row's top-left, and your method
|
|
should fill the area specified by the width and height parameters.
|
|
*/
|
|
virtual void paintRowBackground (Graphics& g,
|
|
int rowNumber,
|
|
int width, int height,
|
|
bool rowIsSelected) = 0;
|
|
|
|
/** This must draw one of the cells.
|
|
|
|
The graphics context's origin will already be set to the top-left of the cell,
|
|
whose size is specified by (width, height).
|
|
*/
|
|
virtual void paintCell (Graphics& g,
|
|
int rowNumber,
|
|
int columnId,
|
|
int width, int height,
|
|
bool rowIsSelected) = 0;
|
|
|
|
/** This is used to create or update a custom component to go in a cell.
|
|
|
|
Any cell may contain a custom component, or can just be drawn with the paintCell() method
|
|
and handle mouse clicks with cellClicked().
|
|
|
|
This method will be called whenever a custom component might need to be updated - e.g.
|
|
when the table is changed, or TableListBox::updateContent() is called.
|
|
|
|
If you don't need a custom component for the specified cell, then return 0.
|
|
|
|
If you do want a custom component, and the existingComponentToUpdate is null, then
|
|
this method must create a new component suitable for the cell, and return it.
|
|
|
|
If the existingComponentToUpdate is non-null, it will be a pointer to a component previously created
|
|
by this method. In this case, the method must either update it to make sure it's correctly representing
|
|
the given cell (which may be different from the one that the component was created for), or it can
|
|
delete this component and return a new one.
|
|
*/
|
|
virtual Component* refreshComponentForCell (int rowNumber, int columnId, bool isRowSelected,
|
|
Component* existingComponentToUpdate);
|
|
|
|
/** This callback is made when the user clicks on one of the cells in the table.
|
|
|
|
The mouse event's coordinates will be relative to the entire table row.
|
|
@see cellDoubleClicked, backgroundClicked
|
|
*/
|
|
virtual void cellClicked (int rowNumber, int columnId, const MouseEvent& e);
|
|
|
|
/** This callback is made when the user clicks on one of the cells in the table.
|
|
|
|
The mouse event's coordinates will be relative to the entire table row.
|
|
@see cellClicked, backgroundClicked
|
|
*/
|
|
virtual void cellDoubleClicked (int rowNumber, int columnId, const MouseEvent& e);
|
|
|
|
/** This can be overridden to react to the user double-clicking on a part of the list where
|
|
there are no rows.
|
|
|
|
@see cellClicked
|
|
*/
|
|
virtual void backgroundClicked();
|
|
|
|
/** This callback is made when the table's sort order is changed.
|
|
|
|
This could be because the user has clicked a column header, or because the
|
|
TableHeaderComponent::setSortColumnId() method was called.
|
|
|
|
If you implement this, your method should re-sort the table using the given
|
|
column as the key.
|
|
*/
|
|
virtual void sortOrderChanged (int newSortColumnId, bool isForwards);
|
|
|
|
/** Returns the best width for one of the columns.
|
|
|
|
If you implement this method, you should measure the width of all the items
|
|
in this column, and return the best size.
|
|
|
|
Returning 0 means that the column shouldn't be changed.
|
|
|
|
This is used by TableListBox::autoSizeColumn() and TableListBox::autoSizeAllColumns().
|
|
*/
|
|
virtual int getColumnAutoSizeWidth (int columnId);
|
|
|
|
/** Returns a tooltip for a particular cell in the table.
|
|
*/
|
|
virtual const String getCellTooltip (int rowNumber, int columnId);
|
|
|
|
/** Override this to be informed when rows are selected or deselected.
|
|
|
|
@see ListBox::selectedRowsChanged()
|
|
*/
|
|
virtual void selectedRowsChanged (int lastRowSelected);
|
|
|
|
/** Override this to be informed when the delete key is pressed.
|
|
|
|
@see ListBox::deleteKeyPressed()
|
|
*/
|
|
virtual void deleteKeyPressed (int lastRowSelected);
|
|
|
|
/** Override this to be informed when the return key is pressed.
|
|
|
|
@see ListBox::returnKeyPressed()
|
|
*/
|
|
virtual void returnKeyPressed (int lastRowSelected);
|
|
|
|
/** Override this to be informed when the list is scrolled.
|
|
|
|
This might be caused by the user moving the scrollbar, or by programmatic changes
|
|
to the list position.
|
|
*/
|
|
virtual void listWasScrolled();
|
|
|
|
/** To allow rows from your table to be dragged-and-dropped, implement this method.
|
|
|
|
If this returns a non-null variant then when the user drags a row, the table will try to
|
|
find a DragAndDropContainer in its parent hierarchy, and will use it to trigger a
|
|
drag-and-drop operation, using this string as the source description, and the listbox
|
|
itself as the source component.
|
|
|
|
@see getDragSourceCustomData, DragAndDropContainer::startDragging
|
|
*/
|
|
virtual const var getDragSourceDescription (const SparseSet<int>& currentlySelectedRows);
|
|
};
|
|
|
|
/**
|
|
A table of cells, using a TableHeaderComponent as its header.
|
|
|
|
This component makes it easy to create a table by providing a TableListBoxModel as
|
|
the data source.
|
|
|
|
@see TableListBoxModel, TableHeaderComponent
|
|
*/
|
|
class JUCE_API TableListBox : public ListBox,
|
|
private ListBoxModel,
|
|
private TableHeaderComponent::Listener
|
|
{
|
|
public:
|
|
|
|
/** Creates a TableListBox.
|
|
|
|
The model pointer passed-in can be null, in which case you can set it later
|
|
with setModel().
|
|
*/
|
|
TableListBox (const String& componentName = String::empty,
|
|
TableListBoxModel* model = 0);
|
|
|
|
/** Destructor. */
|
|
~TableListBox();
|
|
|
|
/** Changes the TableListBoxModel that is being used for this table.
|
|
*/
|
|
void setModel (TableListBoxModel* newModel);
|
|
|
|
/** Returns the model currently in use. */
|
|
TableListBoxModel* getModel() const { return model; }
|
|
|
|
/** Returns the header component being used in this table. */
|
|
TableHeaderComponent& getHeader() const { return *header; }
|
|
|
|
/** Sets the header component to use for the table.
|
|
The table will take ownership of the component that you pass in, and will delete it
|
|
when it's no longer needed.
|
|
*/
|
|
void setHeader (TableHeaderComponent* newHeader);
|
|
|
|
/** Changes the height of the table header component.
|
|
@see getHeaderHeight
|
|
*/
|
|
void setHeaderHeight (int newHeight);
|
|
|
|
/** Returns the height of the table header.
|
|
@see setHeaderHeight
|
|
*/
|
|
int getHeaderHeight() const;
|
|
|
|
/** Resizes a column to fit its contents.
|
|
|
|
This uses TableListBoxModel::getColumnAutoSizeWidth() to find the best width,
|
|
and applies that to the column.
|
|
|
|
@see autoSizeAllColumns, TableHeaderComponent::setColumnWidth
|
|
*/
|
|
void autoSizeColumn (int columnId);
|
|
|
|
/** Calls autoSizeColumn() for all columns in the table. */
|
|
void autoSizeAllColumns();
|
|
|
|
/** Enables or disables the auto size options on the popup menu.
|
|
|
|
By default, these are enabled.
|
|
*/
|
|
void setAutoSizeMenuOptionShown (bool shouldBeShown);
|
|
|
|
/** True if the auto-size options should be shown on the menu.
|
|
@see setAutoSizeMenuOptionsShown
|
|
*/
|
|
bool isAutoSizeMenuOptionShown() const;
|
|
|
|
/** Returns the position of one of the cells in the table.
|
|
|
|
If relativeToComponentTopLeft is true, the co-ordinates are relative to
|
|
the table component's top-left. The row number isn't checked to see if it's
|
|
in-range, but the column ID must exist or this will return an empty rectangle.
|
|
|
|
If relativeToComponentTopLeft is false, the co-ords are relative to the
|
|
top-left of the table's top-left cell.
|
|
*/
|
|
const Rectangle<int> getCellPosition (int columnId, int rowNumber,
|
|
bool relativeToComponentTopLeft) const;
|
|
|
|
/** Returns the component that currently represents a given cell.
|
|
If the component for this cell is off-screen or if the position is out-of-range,
|
|
this may return 0.
|
|
@see getCellPosition
|
|
*/
|
|
Component* getCellComponent (int columnId, int rowNumber) const;
|
|
|
|
/** Scrolls horizontally if necessary to make sure that a particular column is visible.
|
|
|
|
@see ListBox::scrollToEnsureRowIsOnscreen
|
|
*/
|
|
void scrollToEnsureColumnIsOnscreen (int columnId);
|
|
|
|
/** @internal */
|
|
int getNumRows();
|
|
/** @internal */
|
|
void paintListBoxItem (int, Graphics&, int, int, bool);
|
|
/** @internal */
|
|
Component* refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate);
|
|
/** @internal */
|
|
void selectedRowsChanged (int lastRowSelected);
|
|
/** @internal */
|
|
void deleteKeyPressed (int currentSelectedRow);
|
|
/** @internal */
|
|
void returnKeyPressed (int currentSelectedRow);
|
|
/** @internal */
|
|
void backgroundClicked();
|
|
/** @internal */
|
|
void listWasScrolled();
|
|
/** @internal */
|
|
void tableColumnsChanged (TableHeaderComponent*);
|
|
/** @internal */
|
|
void tableColumnsResized (TableHeaderComponent*);
|
|
/** @internal */
|
|
void tableSortOrderChanged (TableHeaderComponent*);
|
|
/** @internal */
|
|
void tableColumnDraggingChanged (TableHeaderComponent*, int);
|
|
/** @internal */
|
|
void resized();
|
|
|
|
private:
|
|
|
|
TableHeaderComponent* header;
|
|
TableListBoxModel* model;
|
|
int columnIdNowBeingDragged;
|
|
bool autoSizeOptionsShown;
|
|
|
|
void updateColumnComponents() const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TableListBox);
|
|
};
|
|
|
|
#endif // __JUCE_TABLELISTBOX_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TableListBox.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TEXTEDITOR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOOLBAR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOOLBARITEMCOMPONENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ToolbarItemFactory.h ***/
|
|
#ifndef __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__
|
|
#define __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__
|
|
|
|
/**
|
|
A factory object which can create ToolbarItemComponent objects.
|
|
|
|
A subclass of ToolbarItemFactory publishes a set of types of toolbar item
|
|
that it can create.
|
|
|
|
Each type of item is identified by a unique ID, and multiple instances of an
|
|
item type can exist at once (even on the same toolbar, e.g. spacers or separator
|
|
bars).
|
|
|
|
@see Toolbar, ToolbarItemComponent, ToolbarButton
|
|
*/
|
|
class JUCE_API ToolbarItemFactory
|
|
{
|
|
public:
|
|
|
|
ToolbarItemFactory();
|
|
|
|
/** Destructor. */
|
|
virtual ~ToolbarItemFactory();
|
|
|
|
/** A set of reserved item ID values, used for the built-in item types.
|
|
*/
|
|
enum SpecialItemIds
|
|
{
|
|
separatorBarId = -1, /**< The item ID for a vertical (or horizontal) separator bar that
|
|
can be placed between sets of items to break them into groups. */
|
|
spacerId = -2, /**< The item ID for a fixed-width space that can be placed between
|
|
items.*/
|
|
flexibleSpacerId = -3 /**< The item ID for a gap that pushes outwards against the things on
|
|
either side of it, filling any available space. */
|
|
};
|
|
|
|
/** Must return a list of the IDs for all the item types that this factory can create.
|
|
|
|
The ids should be added to the array that is passed-in.
|
|
|
|
An item ID can be any integer you choose, except for 0, which is considered a null ID,
|
|
and the predefined IDs in the SpecialItemIds enum.
|
|
|
|
You should also add the built-in types (separatorBarId, spacerId and flexibleSpacerId)
|
|
to this list if you want your toolbar to be able to contain those items.
|
|
|
|
The list returned here is used by the ToolbarItemPalette class to obtain its list
|
|
of available items, and their order on the palette will reflect the order in which
|
|
they appear on this list.
|
|
|
|
@see ToolbarItemPalette
|
|
*/
|
|
virtual void getAllToolbarItemIds (Array <int>& ids) = 0;
|
|
|
|
/** Must return the set of items that should be added to a toolbar as its default set.
|
|
|
|
This method is used by Toolbar::addDefaultItems() to determine which items to
|
|
create.
|
|
|
|
The items that your method adds to the array that is passed-in will be added to the
|
|
toolbar in the same order. Items can appear in the list more than once.
|
|
*/
|
|
virtual void getDefaultItemSet (Array <int>& ids) = 0;
|
|
|
|
/** Must create an instance of one of the items that the factory lists in its
|
|
getAllToolbarItemIds() method.
|
|
|
|
The itemId parameter can be any of the values listed by your getAllToolbarItemIds()
|
|
method, except for the built-in item types from the SpecialItemIds enum, which
|
|
are created internally by the toolbar code.
|
|
|
|
Try not to keep a pointer to the object that is returned, as it will be deleted
|
|
automatically by the toolbar, and remember that multiple instances of the same
|
|
item type are likely to exist at the same time.
|
|
*/
|
|
virtual ToolbarItemComponent* createItem (int itemId) = 0;
|
|
};
|
|
|
|
#endif // __JUCE_TOOLBARITEMFACTORY_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ToolbarItemFactory.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ToolbarItemPalette.h ***/
|
|
#ifndef __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__
|
|
#define __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__
|
|
|
|
/**
|
|
A component containing a list of toolbar items, which the user can drag onto
|
|
a toolbar to add them.
|
|
|
|
You can use this class directly, but it's a lot easier to call Toolbar::showCustomisationDialog(),
|
|
which automatically shows one of these in a dialog box with lots of extra controls.
|
|
|
|
@see Toolbar
|
|
*/
|
|
class JUCE_API ToolbarItemPalette : public Component,
|
|
public DragAndDropContainer
|
|
{
|
|
public:
|
|
|
|
/** Creates a palette of items for a given factory, with the aim of adding them
|
|
to the specified toolbar.
|
|
|
|
The ToolbarItemFactory::getAllToolbarItemIds() method is used to create the
|
|
set of items that are shown in this palette.
|
|
|
|
The toolbar and factory must not be deleted while this object exists.
|
|
*/
|
|
ToolbarItemPalette (ToolbarItemFactory& factory,
|
|
Toolbar* toolbar);
|
|
|
|
/** Destructor. */
|
|
~ToolbarItemPalette();
|
|
|
|
/** @internal */
|
|
void resized();
|
|
|
|
private:
|
|
ToolbarItemFactory& factory;
|
|
Toolbar* toolbar;
|
|
Viewport viewport;
|
|
OwnedArray <ToolbarItemComponent> items;
|
|
|
|
friend class Toolbar;
|
|
void replaceComponent (ToolbarItemComponent* comp);
|
|
void addComponent (int itemId, int index);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ToolbarItemPalette);
|
|
};
|
|
|
|
#endif // __JUCE_TOOLBARITEMPALETTE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ToolbarItemPalette.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TREEVIEW_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_TreeView.h ***/
|
|
#ifndef __JUCE_TREEVIEW_JUCEHEADER__
|
|
#define __JUCE_TREEVIEW_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_FileDragAndDropTarget.h ***/
|
|
#ifndef __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__
|
|
#define __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__
|
|
|
|
/**
|
|
Components derived from this class can have files dropped onto them by an external application.
|
|
|
|
@see DragAndDropContainer
|
|
*/
|
|
class JUCE_API FileDragAndDropTarget
|
|
{
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~FileDragAndDropTarget() {}
|
|
|
|
/** Callback to check whether this target is interested in the set of files being offered.
|
|
|
|
Note that this will be called repeatedly when the user is dragging the mouse around over your
|
|
component, so don't do anything time-consuming in here, like opening the files to have a look
|
|
inside them!
|
|
|
|
@param files the set of (absolute) pathnames of the files that the user is dragging
|
|
@returns true if this component wants to receive the other callbacks regarging this
|
|
type of object; if it returns false, no other callbacks will be made.
|
|
*/
|
|
virtual bool isInterestedInFileDrag (const StringArray& files) = 0;
|
|
|
|
/** Callback to indicate that some files are being dragged over this component.
|
|
|
|
This gets called when the user moves the mouse into this component while dragging.
|
|
|
|
Use this callback as a trigger to make your component repaint itself to give the
|
|
user feedback about whether the files can be dropped here or not.
|
|
|
|
@param files the set of (absolute) pathnames of the files that the user is dragging
|
|
@param x the mouse x position, relative to this component
|
|
@param y the mouse y position, relative to this component
|
|
*/
|
|
virtual void fileDragEnter (const StringArray& files, int x, int y);
|
|
|
|
/** Callback to indicate that the user is dragging some files over this component.
|
|
|
|
This gets called when the user moves the mouse over this component while dragging.
|
|
Normally overriding itemDragEnter() and itemDragExit() are enough, but
|
|
this lets you know what happens in-between.
|
|
|
|
@param files the set of (absolute) pathnames of the files that the user is dragging
|
|
@param x the mouse x position, relative to this component
|
|
@param y the mouse y position, relative to this component
|
|
*/
|
|
virtual void fileDragMove (const StringArray& files, int x, int y);
|
|
|
|
/** Callback to indicate that the mouse has moved away from this component.
|
|
|
|
This gets called when the user moves the mouse out of this component while dragging
|
|
the files.
|
|
|
|
If you've used fileDragEnter() to repaint your component and give feedback, use this
|
|
as a signal to repaint it in its normal state.
|
|
|
|
@param files the set of (absolute) pathnames of the files that the user is dragging
|
|
*/
|
|
virtual void fileDragExit (const StringArray& files);
|
|
|
|
/** Callback to indicate that the user has dropped the files onto this component.
|
|
|
|
When the user drops the files, this get called, and you can use the files in whatever
|
|
way is appropriate.
|
|
|
|
Note that after this is called, the fileDragExit method may not be called, so you should
|
|
clean up in here if there's anything you need to do when the drag finishes.
|
|
|
|
@param files the set of (absolute) pathnames of the files that the user is dragging
|
|
@param x the mouse x position, relative to this component
|
|
@param y the mouse y position, relative to this component
|
|
*/
|
|
virtual void filesDropped (const StringArray& files, int x, int y) = 0;
|
|
};
|
|
|
|
#endif // __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileDragAndDropTarget.h ***/
|
|
|
|
class TreeView;
|
|
|
|
/**
|
|
An item in a treeview.
|
|
|
|
A TreeViewItem can either be a leaf-node in the tree, or it can contain its
|
|
own sub-items.
|
|
|
|
To implement an item that contains sub-items, override the itemOpennessChanged()
|
|
method so that when it is opened, it adds the new sub-items to itself using the
|
|
addSubItem method. Depending on the nature of the item it might choose to only
|
|
do this the first time it's opened, or it might want to refresh itself each time.
|
|
It also has the option of deleting its sub-items when it is closed, or leaving them
|
|
in place.
|
|
*/
|
|
class JUCE_API TreeViewItem
|
|
{
|
|
public:
|
|
|
|
/** Constructor. */
|
|
TreeViewItem();
|
|
|
|
/** Destructor. */
|
|
virtual ~TreeViewItem();
|
|
|
|
/** Returns the number of sub-items that have been added to this item.
|
|
|
|
Note that this doesn't mean much if the node isn't open.
|
|
|
|
@see getSubItem, mightContainSubItems, addSubItem
|
|
*/
|
|
int getNumSubItems() const noexcept;
|
|
|
|
/** Returns one of the item's sub-items.
|
|
|
|
Remember that the object returned might get deleted at any time when its parent
|
|
item is closed or refreshed, depending on the nature of the items you're using.
|
|
|
|
@see getNumSubItems
|
|
*/
|
|
TreeViewItem* getSubItem (int index) const noexcept;
|
|
|
|
/** Removes any sub-items. */
|
|
void clearSubItems();
|
|
|
|
/** Adds a sub-item.
|
|
|
|
@param newItem the object to add to the item's sub-item list. Once added, these can be
|
|
found using getSubItem(). When the items are later removed with
|
|
removeSubItem() (or when this item is deleted), they will be deleted.
|
|
@param insertPosition the index which the new item should have when it's added. If this
|
|
value is less than 0, the item will be added to the end of the list.
|
|
*/
|
|
void addSubItem (TreeViewItem* newItem, int insertPosition = -1);
|
|
|
|
/** Removes one of the sub-items.
|
|
|
|
@param index the item to remove
|
|
@param deleteItem if true, the item that is removed will also be deleted.
|
|
*/
|
|
void removeSubItem (int index, bool deleteItem = true);
|
|
|
|
/** Returns the TreeView to which this item belongs. */
|
|
TreeView* getOwnerView() const noexcept { return ownerView; }
|
|
|
|
/** Returns the item within which this item is contained. */
|
|
TreeViewItem* getParentItem() const noexcept { return parentItem; }
|
|
|
|
/** True if this item is currently open in the treeview. */
|
|
bool isOpen() const noexcept;
|
|
|
|
/** Opens or closes the item.
|
|
|
|
When opened or closed, the item's itemOpennessChanged() method will be called,
|
|
and a subclass should use this callback to create and add any sub-items that
|
|
it needs to.
|
|
|
|
@see itemOpennessChanged, mightContainSubItems
|
|
*/
|
|
void setOpen (bool shouldBeOpen);
|
|
|
|
/** True if this item is currently selected.
|
|
|
|
Use this when painting the node, to decide whether to draw it as selected or not.
|
|
*/
|
|
bool isSelected() const noexcept;
|
|
|
|
/** Selects or deselects the item.
|
|
|
|
This will cause a callback to itemSelectionChanged()
|
|
*/
|
|
void setSelected (bool shouldBeSelected,
|
|
bool deselectOtherItemsFirst);
|
|
|
|
/** Returns the rectangle that this item occupies.
|
|
|
|
If relativeToTreeViewTopLeft is true, the co-ordinates are relative to the
|
|
top-left of the TreeView comp, so this will depend on the scroll-position of
|
|
the tree. If false, it is relative to the top-left of the topmost item in the
|
|
tree (so this would be unaffected by scrolling the view).
|
|
*/
|
|
const Rectangle<int> getItemPosition (bool relativeToTreeViewTopLeft) const noexcept;
|
|
|
|
/** Sends a signal to the treeview to make it refresh itself.
|
|
|
|
Call this if your items have changed and you want the tree to update to reflect
|
|
this.
|
|
*/
|
|
void treeHasChanged() const noexcept;
|
|
|
|
/** Sends a repaint message to redraw just this item.
|
|
|
|
Note that you should only call this if you want to repaint a superficial change. If
|
|
you're altering the tree's nodes, you should instead call treeHasChanged().
|
|
*/
|
|
void repaintItem() const;
|
|
|
|
/** Returns the row number of this item in the tree.
|
|
|
|
The row number of an item will change according to which items are open.
|
|
|
|
@see TreeView::getNumRowsInTree(), TreeView::getItemOnRow()
|
|
*/
|
|
int getRowNumberInTree() const noexcept;
|
|
|
|
/** Returns true if all the item's parent nodes are open.
|
|
|
|
This is useful to check whether the item might actually be visible or not.
|
|
*/
|
|
bool areAllParentsOpen() const noexcept;
|
|
|
|
/** Changes whether lines are drawn to connect any sub-items to this item.
|
|
|
|
By default, line-drawing is turned on.
|
|
*/
|
|
void setLinesDrawnForSubItems (bool shouldDrawLines) noexcept;
|
|
|
|
/** Tells the tree whether this item can potentially be opened.
|
|
|
|
If your item could contain sub-items, this should return true; if it returns
|
|
false then the tree will not try to open the item. This determines whether or
|
|
not the item will be drawn with a 'plus' button next to it.
|
|
*/
|
|
virtual bool mightContainSubItems() = 0;
|
|
|
|
/** Returns a string to uniquely identify this item.
|
|
|
|
If you're planning on using the TreeView::getOpennessState() method, then
|
|
these strings will be used to identify which nodes are open. The string
|
|
should be unique amongst the item's sibling items, but it's ok for there
|
|
to be duplicates at other levels of the tree.
|
|
|
|
If you're not going to store the state, then it's ok not to bother implementing
|
|
this method.
|
|
*/
|
|
virtual const String getUniqueName() const;
|
|
|
|
/** Called when an item is opened or closed.
|
|
|
|
When setOpen() is called and the item has specified that it might
|
|
have sub-items with the mightContainSubItems() method, this method
|
|
is called to let the item create or manage its sub-items.
|
|
|
|
So when this is called with isNowOpen set to true (i.e. when the item is being
|
|
opened), a subclass might choose to use clearSubItems() and addSubItem() to
|
|
refresh its sub-item list.
|
|
|
|
When this is called with isNowOpen set to false, the subclass might want
|
|
to use clearSubItems() to save on space, or it might choose to leave them,
|
|
depending on the nature of the tree.
|
|
|
|
You could also use this callback as a trigger to start a background process
|
|
which asynchronously creates sub-items and adds them, if that's more
|
|
appropriate for the task in hand.
|
|
|
|
@see mightContainSubItems
|
|
*/
|
|
virtual void itemOpennessChanged (bool isNowOpen);
|
|
|
|
/** Must return the width required by this item.
|
|
|
|
If your item needs to have a particular width in pixels, return that value; if
|
|
you'd rather have it just fill whatever space is available in the treeview,
|
|
return -1.
|
|
|
|
If all your items return -1, no horizontal scrollbar will be shown, but if any
|
|
items have fixed widths and extend beyond the width of the treeview, a
|
|
scrollbar will appear.
|
|
|
|
Each item can be a different width, but if they change width, you should call
|
|
treeHasChanged() to update the tree.
|
|
*/
|
|
virtual int getItemWidth() const { return -1; }
|
|
|
|
/** Must return the height required by this item.
|
|
|
|
This is the height in pixels that the item will take up. Items in the tree
|
|
can be different heights, but if they change height, you should call
|
|
treeHasChanged() to update the tree.
|
|
*/
|
|
virtual int getItemHeight() const { return 20; }
|
|
|
|
/** You can override this method to return false if you don't want to allow the
|
|
user to select this item.
|
|
*/
|
|
virtual bool canBeSelected() const { return true; }
|
|
|
|
/** Creates a component that will be used to represent this item.
|
|
|
|
You don't have to implement this method - if it returns 0 then no component
|
|
will be used for the item, and you can just draw it using the paintItem()
|
|
callback. But if you do return a component, it will be positioned in the
|
|
treeview so that it can be used to represent this item.
|
|
|
|
The component returned will be managed by the treeview, so always return
|
|
a new component, and don't keep a reference to it, as the treeview will
|
|
delete it later when it goes off the screen or is no longer needed. Also
|
|
bear in mind that if the component keeps a reference to the item that
|
|
created it, that item could be deleted before the component. Its position
|
|
and size will be completely managed by the tree, so don't attempt to move it
|
|
around.
|
|
|
|
Something you may want to do with your component is to give it a pointer to
|
|
the TreeView that created it. This is perfectly safe, and there's no danger
|
|
of it becoming a dangling pointer because the TreeView will always delete
|
|
the component before it is itself deleted.
|
|
|
|
As long as you stick to these rules you can return whatever kind of
|
|
component you like. It's most useful if you're doing things like drag-and-drop
|
|
of items, or want to use a Label component to edit item names, etc.
|
|
*/
|
|
virtual Component* createItemComponent() { return nullptr; }
|
|
|
|
/** Draws the item's contents.
|
|
|
|
You can choose to either implement this method and draw each item, or you
|
|
can use createItemComponent() to create a component that will represent the
|
|
item.
|
|
|
|
If all you need in your tree is to be able to draw the items and detect when
|
|
the user selects or double-clicks one of them, it's probably enough to
|
|
use paintItem(), itemClicked() and itemDoubleClicked(). If you need more
|
|
complicated interactions, you may need to use createItemComponent() instead.
|
|
|
|
@param g the graphics context to draw into
|
|
@param width the width of the area available for drawing
|
|
@param height the height of the area available for drawing
|
|
*/
|
|
virtual void paintItem (Graphics& g, int width, int height);
|
|
|
|
/** Draws the item's open/close button.
|
|
|
|
If you don't implement this method, the default behaviour is to
|
|
call LookAndFeel::drawTreeviewPlusMinusBox(), but you can override
|
|
it for custom effects.
|
|
*/
|
|
virtual void paintOpenCloseButton (Graphics& g, int width, int height, bool isMouseOver);
|
|
|
|
/** Called when the user clicks on this item.
|
|
|
|
If you're using createItemComponent() to create a custom component for the
|
|
item, the mouse-clicks might not make it through to the treeview, but this
|
|
is how you find out about clicks when just drawing each item individually.
|
|
|
|
The associated mouse-event details are passed in, so you can find out about
|
|
which button, where it was, etc.
|
|
|
|
@see itemDoubleClicked
|
|
*/
|
|
virtual void itemClicked (const MouseEvent& e);
|
|
|
|
/** Called when the user double-clicks on this item.
|
|
|
|
If you're using createItemComponent() to create a custom component for the
|
|
item, the mouse-clicks might not make it through to the treeview, but this
|
|
is how you find out about clicks when just drawing each item individually.
|
|
|
|
The associated mouse-event details are passed in, so you can find out about
|
|
which button, where it was, etc.
|
|
|
|
If not overridden, the base class method here will open or close the item as
|
|
if the 'plus' button had been clicked.
|
|
|
|
@see itemClicked
|
|
*/
|
|
virtual void itemDoubleClicked (const MouseEvent& e);
|
|
|
|
/** Called when the item is selected or deselected.
|
|
|
|
Use this if you want to do something special when the item's selectedness
|
|
changes. By default it'll get repainted when this happens.
|
|
*/
|
|
virtual void itemSelectionChanged (bool isNowSelected);
|
|
|
|
/** The item can return a tool tip string here if it wants to.
|
|
@see TooltipClient
|
|
*/
|
|
virtual const String getTooltip();
|
|
|
|
/** To allow items from your treeview to be dragged-and-dropped, implement this method.
|
|
|
|
If this returns a non-null variant then when the user drags an item, the treeview will
|
|
try to find a DragAndDropContainer in its parent hierarchy, and will use it to trigger
|
|
a drag-and-drop operation, using this string as the source description, with the treeview
|
|
itself as the source component.
|
|
|
|
If you need more complex drag-and-drop behaviour, you can use custom components for
|
|
the items, and use those to trigger the drag.
|
|
|
|
To accept drag-and-drop in your tree, see isInterestedInDragSource(),
|
|
isInterestedInFileDrag(), etc.
|
|
|
|
@see DragAndDropContainer::startDragging
|
|
*/
|
|
virtual const var getDragSourceDescription();
|
|
|
|
/** If you want your item to be able to have files drag-and-dropped onto it, implement this
|
|
method and return true.
|
|
|
|
If you return true and allow some files to be dropped, you'll also need to implement the
|
|
filesDropped() method to do something with them.
|
|
|
|
Note that this will be called often, so make your implementation very quick! There's
|
|
certainly no time to try opening the files and having a think about what's inside them!
|
|
|
|
For responding to internal drag-and-drop of other types of object, see isInterestedInDragSource().
|
|
@see FileDragAndDropTarget::isInterestedInFileDrag, isInterestedInDragSource
|
|
*/
|
|
virtual bool isInterestedInFileDrag (const StringArray& files);
|
|
|
|
/** When files are dropped into this item, this callback is invoked.
|
|
|
|
For this to work, you'll need to have also implemented isInterestedInFileDrag().
|
|
The insertIndex value indicates where in the list of sub-items the files were dropped.
|
|
If files are dropped onto an area of the tree where there are no visible items, this
|
|
method is called on the root item of the tree, with an insert index of 0.
|
|
@see FileDragAndDropTarget::filesDropped, isInterestedInFileDrag
|
|
*/
|
|
virtual void filesDropped (const StringArray& files, int insertIndex);
|
|
|
|
/** If you want your item to act as a DragAndDropTarget, implement this method and return true.
|
|
|
|
If you implement this method, you'll also need to implement itemDropped() in order to handle
|
|
the items when they are dropped.
|
|
To respond to drag-and-drop of files from external applications, see isInterestedInFileDrag().
|
|
@see DragAndDropTarget::isInterestedInDragSource, itemDropped
|
|
*/
|
|
virtual bool isInterestedInDragSource (const DragAndDropTarget::SourceDetails& dragSourceDetails);
|
|
|
|
/** When a things are dropped into this item, this callback is invoked.
|
|
|
|
For this to work, you need to have also implemented isInterestedInDragSource().
|
|
The insertIndex value indicates where in the list of sub-items the new items should be placed.
|
|
If files are dropped onto an area of the tree where there are no visible items, this
|
|
method is called on the root item of the tree, with an insert index of 0.
|
|
@see isInterestedInDragSource, DragAndDropTarget::itemDropped
|
|
*/
|
|
virtual void itemDropped (const DragAndDropTarget::SourceDetails& dragSourceDetails, int insertIndex);
|
|
|
|
/** Sets a flag to indicate that the item wants to be allowed
|
|
to draw all the way across to the left edge of the treeview.
|
|
|
|
By default this is false, which means that when the paintItem()
|
|
method is called, its graphics context is clipped to only allow
|
|
drawing within the item's rectangle. If this flag is set to true,
|
|
then the graphics context isn't clipped on its left side, so it
|
|
can draw all the way across to the left margin. Note that the
|
|
context will still have its origin in the same place though, so
|
|
the coordinates of anything to its left will be negative. It's
|
|
mostly useful if you want to draw a wider bar behind the
|
|
highlighted item.
|
|
*/
|
|
void setDrawsInLeftMargin (bool canDrawInLeftMargin) noexcept;
|
|
|
|
/** Saves the current state of open/closed nodes so it can be restored later.
|
|
|
|
This takes a snapshot of which sub-nodes have been explicitly opened or closed,
|
|
and records it as XML. To identify node objects it uses the
|
|
TreeViewItem::getUniqueName() method to create named paths. This
|
|
means that the same state of open/closed nodes can be restored to a
|
|
completely different instance of the tree, as long as it contains nodes
|
|
whose unique names are the same.
|
|
|
|
You'd normally want to use TreeView::getOpennessState() rather than call it
|
|
for a specific item, but this can be handy if you need to briefly save the state
|
|
for a section of the tree.
|
|
|
|
The caller is responsible for deleting the object that is returned.
|
|
@see TreeView::getOpennessState, restoreOpennessState
|
|
*/
|
|
XmlElement* getOpennessState() const noexcept;
|
|
|
|
/** Restores the openness of this item and all its sub-items from a saved state.
|
|
|
|
See TreeView::restoreOpennessState for more details.
|
|
|
|
You'd normally want to use TreeView::restoreOpennessState() rather than call it
|
|
for a specific item, but this can be handy if you need to briefly save the state
|
|
for a section of the tree.
|
|
|
|
@see TreeView::restoreOpennessState, getOpennessState
|
|
*/
|
|
void restoreOpennessState (const XmlElement& xml) noexcept;
|
|
|
|
/** Returns the index of this item in its parent's sub-items. */
|
|
int getIndexInParent() const noexcept;
|
|
|
|
/** Returns true if this item is the last of its parent's sub-itens. */
|
|
bool isLastOfSiblings() const noexcept;
|
|
|
|
/** Creates a string that can be used to uniquely retrieve this item in the tree.
|
|
|
|
The string that is returned can be passed to TreeView::findItemFromIdentifierString().
|
|
The string takes the form of a path, constructed from the getUniqueName() of this
|
|
item and all its parents, so these must all be correctly implemented for it to work.
|
|
@see TreeView::findItemFromIdentifierString, getUniqueName
|
|
*/
|
|
String getItemIdentifierString() const;
|
|
|
|
/**
|
|
This handy class takes a copy of a TreeViewItem's openness when you create it,
|
|
and restores that openness state when its destructor is called.
|
|
|
|
This can very handy when you're refreshing sub-items - e.g.
|
|
@code
|
|
void MyTreeViewItem::updateChildItems()
|
|
{
|
|
OpennessRestorer openness (*this); // saves the openness state here..
|
|
|
|
clearSubItems();
|
|
|
|
// add a bunch of sub-items here which may or may not be the same as the ones that
|
|
// were previously there
|
|
addSubItem (...
|
|
|
|
// ..and at this point, the old openness is restored, so any items that haven't
|
|
// changed will have their old openness retained.
|
|
}
|
|
@endcode
|
|
*/
|
|
class OpennessRestorer
|
|
{
|
|
public:
|
|
OpennessRestorer (TreeViewItem& treeViewItem);
|
|
~OpennessRestorer();
|
|
|
|
private:
|
|
TreeViewItem& treeViewItem;
|
|
ScopedPointer <XmlElement> oldOpenness;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpennessRestorer);
|
|
};
|
|
|
|
private:
|
|
|
|
TreeView* ownerView;
|
|
TreeViewItem* parentItem;
|
|
OwnedArray <TreeViewItem> subItems;
|
|
int y, itemHeight, totalHeight, itemWidth, totalWidth;
|
|
int uid;
|
|
bool selected : 1;
|
|
bool redrawNeeded : 1;
|
|
bool drawLinesInside : 1;
|
|
bool drawsInLeftMargin : 1;
|
|
unsigned int openness : 2;
|
|
|
|
friend class TreeView;
|
|
friend class TreeViewContentComponent;
|
|
|
|
void updatePositions (int newY);
|
|
int getIndentX() const noexcept;
|
|
void setOwnerView (TreeView*) noexcept;
|
|
void paintRecursively (Graphics&, int width);
|
|
TreeViewItem* getTopLevelItem() noexcept;
|
|
TreeViewItem* findItemRecursively (int y) noexcept;
|
|
TreeViewItem* getDeepestOpenParentItem() noexcept;
|
|
int getNumRows() const noexcept;
|
|
TreeViewItem* getItemOnRow (int index) noexcept;
|
|
void deselectAllRecursively();
|
|
int countSelectedItemsRecursively (int depth) const noexcept;
|
|
TreeViewItem* getSelectedItemWithIndex (int index) noexcept;
|
|
TreeViewItem* getNextVisibleItem (bool recurse) const noexcept;
|
|
TreeViewItem* findItemFromIdentifierString (const String&);
|
|
|
|
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
|
// The parameters for these methods have changed - please update your code!
|
|
virtual void isInterestedInDragSource (const String&, Component*) {}
|
|
virtual int itemDropped (const String&, Component*, int) { return 0; }
|
|
#endif
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeViewItem);
|
|
};
|
|
|
|
/**
|
|
A tree-view component.
|
|
|
|
Use one of these to hold and display a structure of TreeViewItem objects.
|
|
|
|
*/
|
|
class JUCE_API TreeView : public Component,
|
|
public SettableTooltipClient,
|
|
public FileDragAndDropTarget,
|
|
public DragAndDropTarget,
|
|
private AsyncUpdater
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty treeview.
|
|
|
|
Once you've got a treeview component, you'll need to give it something to
|
|
display, using the setRootItem() method.
|
|
*/
|
|
TreeView (const String& componentName = String::empty);
|
|
|
|
/** Destructor. */
|
|
~TreeView();
|
|
|
|
/** Sets the item that is displayed in the treeview.
|
|
|
|
A tree has a single root item which contains as many sub-items as it needs. If
|
|
you want the tree to contain a number of root items, you should still use a single
|
|
root item above these, but hide it using setRootItemVisible().
|
|
|
|
You can pass in 0 to this method to clear the tree and remove its current root item.
|
|
|
|
The object passed in will not be deleted by the treeview, it's up to the caller
|
|
to delete it when no longer needed. BUT make absolutely sure that you don't delete
|
|
this item until you've removed it from the tree, either by calling setRootItem (nullptr),
|
|
or by deleting the tree first. You can also use deleteRootItem() as a quick way
|
|
to delete it.
|
|
*/
|
|
void setRootItem (TreeViewItem* newRootItem);
|
|
|
|
/** Returns the tree's root item.
|
|
|
|
This will be the last object passed to setRootItem(), or 0 if none has been set.
|
|
*/
|
|
TreeViewItem* getRootItem() const noexcept { return rootItem; }
|
|
|
|
/** This will remove and delete the current root item.
|
|
|
|
It's a convenient way of deleting the item and calling setRootItem (nullptr).
|
|
*/
|
|
void deleteRootItem();
|
|
|
|
/** Changes whether the tree's root item is shown or not.
|
|
|
|
If the root item is hidden, only its sub-items will be shown in the treeview - this
|
|
lets you make the tree look as if it's got many root items. If it's hidden, this call
|
|
will also make sure the root item is open (otherwise the treeview would look empty).
|
|
*/
|
|
void setRootItemVisible (bool shouldBeVisible);
|
|
|
|
/** Returns true if the root item is visible.
|
|
|
|
@see setRootItemVisible
|
|
*/
|
|
bool isRootItemVisible() const noexcept { return rootItemVisible; }
|
|
|
|
/** Sets whether items are open or closed by default.
|
|
|
|
Normally, items are closed until the user opens them, but you can use this
|
|
to make them default to being open until explicitly closed.
|
|
|
|
@see areItemsOpenByDefault
|
|
*/
|
|
void setDefaultOpenness (bool isOpenByDefault);
|
|
|
|
/** Returns true if the tree's items default to being open.
|
|
|
|
@see setDefaultOpenness
|
|
*/
|
|
bool areItemsOpenByDefault() const noexcept { return defaultOpenness; }
|
|
|
|
/** This sets a flag to indicate that the tree can be used for multi-selection.
|
|
|
|
You can always select multiple items internally by calling the
|
|
TreeViewItem::setSelected() method, but this flag indicates whether the user
|
|
is allowed to multi-select by clicking on the tree.
|
|
|
|
By default it is disabled.
|
|
|
|
@see isMultiSelectEnabled
|
|
*/
|
|
void setMultiSelectEnabled (bool canMultiSelect);
|
|
|
|
/** Returns whether multi-select has been enabled for the tree.
|
|
|
|
@see setMultiSelectEnabled
|
|
*/
|
|
bool isMultiSelectEnabled() const noexcept { return multiSelectEnabled; }
|
|
|
|
/** Sets a flag to indicate whether to hide the open/close buttons.
|
|
|
|
@see areOpenCloseButtonsVisible
|
|
*/
|
|
void setOpenCloseButtonsVisible (bool shouldBeVisible);
|
|
|
|
/** Returns whether open/close buttons are shown.
|
|
|
|
@see setOpenCloseButtonsVisible
|
|
*/
|
|
bool areOpenCloseButtonsVisible() const noexcept { return openCloseButtonsVisible; }
|
|
|
|
/** Deselects any items that are currently selected. */
|
|
void clearSelectedItems();
|
|
|
|
/** Returns the number of items that are currently selected.
|
|
If maximumDepthToSearchTo is >= 0, it lets you specify a maximum depth to which the
|
|
tree will be recursed.
|
|
@see getSelectedItem, clearSelectedItems
|
|
*/
|
|
int getNumSelectedItems (int maximumDepthToSearchTo = -1) const noexcept;
|
|
|
|
/** Returns one of the selected items in the tree.
|
|
|
|
@param index the index, 0 to (getNumSelectedItems() - 1)
|
|
*/
|
|
TreeViewItem* getSelectedItem (int index) const noexcept;
|
|
|
|
/** Returns the number of rows the tree is using.
|
|
|
|
This will depend on which items are open.
|
|
|
|
@see TreeViewItem::getRowNumberInTree()
|
|
*/
|
|
int getNumRowsInTree() const;
|
|
|
|
/** Returns the item on a particular row of the tree.
|
|
|
|
If the index is out of range, this will return 0.
|
|
|
|
@see getNumRowsInTree, TreeViewItem::getRowNumberInTree()
|
|
*/
|
|
TreeViewItem* getItemOnRow (int index) const;
|
|
|
|
/** Returns the item that contains a given y position.
|
|
The y is relative to the top of the TreeView component.
|
|
*/
|
|
TreeViewItem* getItemAt (int yPosition) const noexcept;
|
|
|
|
/** Tries to scroll the tree so that this item is on-screen somewhere. */
|
|
void scrollToKeepItemVisible (TreeViewItem* item);
|
|
|
|
/** Returns the treeview's Viewport object. */
|
|
Viewport* getViewport() const noexcept;
|
|
|
|
/** Returns the number of pixels by which each nested level of the tree is indented.
|
|
@see setIndentSize
|
|
*/
|
|
int getIndentSize() const noexcept { return indentSize; }
|
|
|
|
/** Changes the distance by which each nested level of the tree is indented.
|
|
@see getIndentSize
|
|
*/
|
|
void setIndentSize (int newIndentSize);
|
|
|
|
/** Searches the tree for an item with the specified identifier.
|
|
The identifer string must have been created by calling TreeViewItem::getItemIdentifierString().
|
|
If no such item exists, this will return false. If the item is found, all of its items
|
|
will be automatically opened.
|
|
*/
|
|
TreeViewItem* findItemFromIdentifierString (const String& identifierString) const;
|
|
|
|
/** Saves the current state of open/closed nodes so it can be restored later.
|
|
|
|
This takes a snapshot of which nodes have been explicitly opened or closed,
|
|
and records it as XML. To identify node objects it uses the
|
|
TreeViewItem::getUniqueName() method to create named paths. This
|
|
means that the same state of open/closed nodes can be restored to a
|
|
completely different instance of the tree, as long as it contains nodes
|
|
whose unique names are the same.
|
|
|
|
The caller is responsible for deleting the object that is returned.
|
|
|
|
@param alsoIncludeScrollPosition if this is true, the state will also
|
|
include information about where the
|
|
tree has been scrolled to vertically,
|
|
so this can also be restored
|
|
@see restoreOpennessState
|
|
*/
|
|
XmlElement* getOpennessState (bool alsoIncludeScrollPosition) const;
|
|
|
|
/** Restores a previously saved arrangement of open/closed nodes.
|
|
|
|
This will try to restore a snapshot of the tree's state that was created by
|
|
the getOpennessState() method. If any of the nodes named in the original
|
|
XML aren't present in this tree, they will be ignored.
|
|
|
|
If restoreStoredSelection is true, it will also try to re-select any items that
|
|
were selected in the stored state.
|
|
|
|
@see getOpennessState
|
|
*/
|
|
void restoreOpennessState (const XmlElement& newState,
|
|
bool restoreStoredSelection);
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the treeview.
|
|
|
|
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 = 0x1000500, /**< A background colour to fill the component with. */
|
|
linesColourId = 0x1000501, /**< The colour to draw the lines with.*/
|
|
dragAndDropIndicatorColourId = 0x1000502 /**< The colour to use for the drag-and-drop target position indicator. */
|
|
};
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
bool keyPressed (const KeyPress& key);
|
|
/** @internal */
|
|
void colourChanged();
|
|
/** @internal */
|
|
void enablementChanged();
|
|
/** @internal */
|
|
bool isInterestedInFileDrag (const StringArray& files);
|
|
/** @internal */
|
|
void fileDragEnter (const StringArray& files, int x, int y);
|
|
/** @internal */
|
|
void fileDragMove (const StringArray& files, int x, int y);
|
|
/** @internal */
|
|
void fileDragExit (const StringArray& files);
|
|
/** @internal */
|
|
void filesDropped (const StringArray& files, int x, int y);
|
|
/** @internal */
|
|
bool isInterestedInDragSource (const SourceDetails&);
|
|
/** @internal */
|
|
void itemDragEnter (const SourceDetails&);
|
|
/** @internal */
|
|
void itemDragMove (const SourceDetails&);
|
|
/** @internal */
|
|
void itemDragExit (const SourceDetails&);
|
|
/** @internal */
|
|
void itemDropped (const SourceDetails&);
|
|
|
|
private:
|
|
friend class TreeViewItem;
|
|
friend class TreeViewContentComponent;
|
|
class TreeViewport;
|
|
class InsertPointHighlight;
|
|
class TargetGroupHighlight;
|
|
friend class ScopedPointer<TreeViewport>;
|
|
friend class ScopedPointer<InsertPointHighlight>;
|
|
friend class ScopedPointer<TargetGroupHighlight>;
|
|
ScopedPointer<TreeViewport> viewport;
|
|
CriticalSection nodeAlterationLock;
|
|
TreeViewItem* rootItem;
|
|
ScopedPointer<InsertPointHighlight> dragInsertPointHighlight;
|
|
ScopedPointer<TargetGroupHighlight> dragTargetGroupHighlight;
|
|
int indentSize;
|
|
bool defaultOpenness : 1;
|
|
bool needsRecalculating : 1;
|
|
bool rootItemVisible : 1;
|
|
bool multiSelectEnabled : 1;
|
|
bool openCloseButtonsVisible : 1;
|
|
|
|
void itemsChanged() noexcept;
|
|
void handleAsyncUpdate();
|
|
void moveSelectedRow (int delta);
|
|
void updateButtonUnderMouse (const MouseEvent& e);
|
|
void showDragHighlight (TreeViewItem* item, int insertIndex, int x, int y) noexcept;
|
|
void hideDragHighlight() noexcept;
|
|
void handleDrag (const StringArray& files, const SourceDetails&);
|
|
void handleDrop (const StringArray& files, const SourceDetails&);
|
|
TreeViewItem* getInsertPosition (int& x, int& y, int& insertIndex,
|
|
const StringArray& files, const SourceDetails&) const noexcept;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeView);
|
|
};
|
|
|
|
#endif // __JUCE_TREEVIEW_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TreeView.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DirectoryContentsDisplayComponent.h ***/
|
|
#ifndef __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_DirectoryContentsList.h ***/
|
|
#ifndef __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__
|
|
#define __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_FileFilter.h ***/
|
|
#ifndef __JUCE_FILEFILTER_JUCEHEADER__
|
|
#define __JUCE_FILEFILTER_JUCEHEADER__
|
|
|
|
/**
|
|
Interface for deciding which files are suitable for something.
|
|
|
|
For example, this is used by DirectoryContentsList to select which files
|
|
go into the list.
|
|
|
|
@see WildcardFileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
|
|
*/
|
|
class JUCE_API FileFilter
|
|
{
|
|
public:
|
|
|
|
/** Creates a filter with the given description.
|
|
|
|
The description can be returned later with the getDescription() method.
|
|
*/
|
|
FileFilter (const String& filterDescription);
|
|
|
|
/** Destructor. */
|
|
virtual ~FileFilter();
|
|
|
|
/** Returns the description that the filter was created with. */
|
|
const String& getDescription() const noexcept;
|
|
|
|
/** Should return true if this file is suitable for inclusion in whatever context
|
|
the object is being used.
|
|
*/
|
|
virtual bool isFileSuitable (const File& file) const = 0;
|
|
|
|
/** Should return true if this directory is suitable for inclusion in whatever context
|
|
the object is being used.
|
|
*/
|
|
virtual bool isDirectorySuitable (const File& file) const = 0;
|
|
|
|
protected:
|
|
|
|
String description;
|
|
};
|
|
|
|
#endif // __JUCE_FILEFILTER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileFilter.h ***/
|
|
|
|
/**
|
|
A class to asynchronously scan for details about the files in a directory.
|
|
|
|
This keeps a list of files and some information about them, using a background
|
|
thread to scan for more files. As files are found, it broadcasts change messages
|
|
to tell any listeners.
|
|
|
|
@see FileListComponent, FileBrowserComponent
|
|
*/
|
|
class JUCE_API DirectoryContentsList : public ChangeBroadcaster,
|
|
public TimeSliceClient
|
|
{
|
|
public:
|
|
|
|
/** Creates a directory list.
|
|
|
|
To set the directory it should point to, use setDirectory(), which will
|
|
also start it scanning for files on the background thread.
|
|
|
|
When the background thread finds and adds new files to this list, the
|
|
ChangeBroadcaster class will send a change message, so you can register
|
|
listeners and update them when the list changes.
|
|
|
|
@param fileFilter an optional filter to select which files are
|
|
included in the list. If this is 0, then all files
|
|
and directories are included. Make sure that the
|
|
filter doesn't get deleted during the lifetime of this
|
|
object
|
|
@param threadToUse a thread object that this list can use
|
|
to scan for files as a background task. Make sure
|
|
that the thread you give it has been started, or you
|
|
won't get any files!
|
|
*/
|
|
DirectoryContentsList (const FileFilter* fileFilter,
|
|
TimeSliceThread& threadToUse);
|
|
|
|
/** Destructor. */
|
|
~DirectoryContentsList();
|
|
|
|
/** Sets the directory to look in for files.
|
|
|
|
If the directory that's passed in is different to the current one, this will
|
|
also start the background thread scanning it for files.
|
|
*/
|
|
void setDirectory (const File& directory,
|
|
bool includeDirectories,
|
|
bool includeFiles);
|
|
|
|
/** Returns the directory that's currently being used. */
|
|
const File& getDirectory() const;
|
|
|
|
/** Clears the list, and stops the thread scanning for files. */
|
|
void clear();
|
|
|
|
/** Clears the list and restarts scanning the directory for files. */
|
|
void refresh();
|
|
|
|
/** True if the background thread hasn't yet finished scanning for files. */
|
|
bool isStillLoading() const;
|
|
|
|
/** Tells the list whether or not to ignore hidden files.
|
|
|
|
By default these are ignored.
|
|
*/
|
|
void setIgnoresHiddenFiles (bool shouldIgnoreHiddenFiles);
|
|
|
|
/** Returns true if hidden files are ignored.
|
|
@see setIgnoresHiddenFiles
|
|
*/
|
|
bool ignoresHiddenFiles() const;
|
|
|
|
/** Contains cached information about one of the files in a DirectoryContentsList.
|
|
*/
|
|
struct FileInfo
|
|
{
|
|
|
|
/** The filename.
|
|
|
|
This isn't a full pathname, it's just the last part of the path, same as you'd
|
|
get from File::getFileName().
|
|
|
|
To get the full pathname, use DirectoryContentsList::getDirectory().getChildFile (filename).
|
|
*/
|
|
String filename;
|
|
|
|
/** File size in bytes. */
|
|
int64 fileSize;
|
|
|
|
/** File modification time.
|
|
|
|
As supplied by File::getLastModificationTime().
|
|
*/
|
|
Time modificationTime;
|
|
|
|
/** File creation time.
|
|
|
|
As supplied by File::getCreationTime().
|
|
*/
|
|
Time creationTime;
|
|
|
|
/** True if the file is a directory. */
|
|
bool isDirectory;
|
|
|
|
/** True if the file is read-only. */
|
|
bool isReadOnly;
|
|
};
|
|
|
|
/** Returns the number of files currently available in the list.
|
|
|
|
The info about one of these files can be retrieved with getFileInfo() or
|
|
getFile().
|
|
|
|
Obviously as the background thread runs and scans the directory for files, this
|
|
number will change.
|
|
|
|
@see getFileInfo, getFile
|
|
*/
|
|
int getNumFiles() const;
|
|
|
|
/** Returns the cached information about one of the files in the list.
|
|
|
|
If the index is in-range, this will return true and will copy the file's details
|
|
to the structure that is passed-in.
|
|
|
|
If it returns false, then the index wasn't in range, and the structure won't
|
|
be affected.
|
|
|
|
@see getNumFiles, getFile
|
|
*/
|
|
bool getFileInfo (int index, FileInfo& resultInfo) const;
|
|
|
|
/** Returns one of the files in the list.
|
|
|
|
@param index should be less than getNumFiles(). If this is out-of-range, the
|
|
return value will be File::nonexistent
|
|
@see getNumFiles, getFileInfo
|
|
*/
|
|
File getFile (int index) const;
|
|
|
|
/** Returns the file filter being used.
|
|
|
|
The filter is specified in the constructor.
|
|
*/
|
|
const FileFilter* getFilter() const { return fileFilter; }
|
|
|
|
/** @internal */
|
|
int useTimeSlice();
|
|
/** @internal */
|
|
TimeSliceThread& getTimeSliceThread() { return thread; }
|
|
/** @internal */
|
|
static int compareElements (const DirectoryContentsList::FileInfo* first,
|
|
const DirectoryContentsList::FileInfo* second);
|
|
|
|
private:
|
|
File root;
|
|
const FileFilter* fileFilter;
|
|
TimeSliceThread& thread;
|
|
int fileTypeFlags;
|
|
|
|
CriticalSection fileListLock;
|
|
OwnedArray <FileInfo> files;
|
|
|
|
ScopedPointer <DirectoryIterator> fileFindHandle;
|
|
bool volatile shouldStop;
|
|
|
|
void changed();
|
|
bool checkNextFile (bool& hasChanged);
|
|
bool addFile (const File& file, bool isDir,
|
|
const int64 fileSize, const Time& modTime,
|
|
const Time& creationTime, bool isReadOnly);
|
|
void setTypeFlags (int newFlags);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryContentsList);
|
|
};
|
|
|
|
#endif // __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DirectoryContentsList.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_FileBrowserListener.h ***/
|
|
#ifndef __JUCE_FILEBROWSERLISTENER_JUCEHEADER__
|
|
#define __JUCE_FILEBROWSERLISTENER_JUCEHEADER__
|
|
|
|
/**
|
|
A listener for user selection events in a file browser.
|
|
|
|
This is used by a FileBrowserComponent or FileListComponent.
|
|
*/
|
|
class JUCE_API FileBrowserListener
|
|
{
|
|
public:
|
|
|
|
/** Destructor. */
|
|
virtual ~FileBrowserListener();
|
|
|
|
/** Callback when the user selects a different file in the browser. */
|
|
virtual void selectionChanged() = 0;
|
|
|
|
/** Callback when the user clicks on a file in the browser. */
|
|
virtual void fileClicked (const File& file, const MouseEvent& e) = 0;
|
|
|
|
/** Callback when the user double-clicks on a file in the browser. */
|
|
virtual void fileDoubleClicked (const File& file) = 0;
|
|
};
|
|
|
|
#endif // __JUCE_FILEBROWSERLISTENER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileBrowserListener.h ***/
|
|
|
|
/**
|
|
A base class for components that display a list of the files in a directory.
|
|
|
|
@see DirectoryContentsList
|
|
*/
|
|
class JUCE_API DirectoryContentsDisplayComponent
|
|
{
|
|
public:
|
|
|
|
/** Creates a DirectoryContentsDisplayComponent for a given list of files. */
|
|
DirectoryContentsDisplayComponent (DirectoryContentsList& listToShow);
|
|
|
|
/** Destructor. */
|
|
virtual ~DirectoryContentsDisplayComponent();
|
|
|
|
/** Returns the number of files the user has got selected.
|
|
@see getSelectedFile
|
|
*/
|
|
virtual int getNumSelectedFiles() const = 0;
|
|
|
|
/** Returns one of the files that the user has currently selected.
|
|
The index should be in the range 0 to (getNumSelectedFiles() - 1).
|
|
@see getNumSelectedFiles
|
|
*/
|
|
virtual const File getSelectedFile (int index) const = 0;
|
|
|
|
/** Deselects any selected files. */
|
|
virtual void deselectAllFiles() = 0;
|
|
|
|
/** Scrolls this view to the top. */
|
|
virtual void scrollToTop() = 0;
|
|
|
|
/** Adds a listener to be told when files are selected or clicked.
|
|
@see removeListener
|
|
*/
|
|
void addListener (FileBrowserListener* listener);
|
|
|
|
/** Removes a listener.
|
|
@see addListener
|
|
*/
|
|
void removeListener (FileBrowserListener* listener);
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the list.
|
|
|
|
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
|
|
{
|
|
highlightColourId = 0x1000540, /**< The colour to use to fill a highlighted row of the list. */
|
|
textColourId = 0x1000541, /**< The colour for the text. */
|
|
};
|
|
|
|
/** @internal */
|
|
void sendSelectionChangeMessage();
|
|
/** @internal */
|
|
void sendDoubleClickMessage (const File& file);
|
|
/** @internal */
|
|
void sendMouseClickMessage (const File& file, const MouseEvent& e);
|
|
|
|
protected:
|
|
|
|
DirectoryContentsList& fileList;
|
|
ListenerList <FileBrowserListener> listeners;
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectoryContentsDisplayComponent);
|
|
};
|
|
|
|
#endif // __JUCE_DIRECTORYCONTENTSDISPLAYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DirectoryContentsDisplayComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DIRECTORYCONTENTSLIST_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FileBrowserComponent.h ***/
|
|
#ifndef __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_FilePreviewComponent.h ***/
|
|
#ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
Base class for components that live inside a file chooser dialog box and
|
|
show previews of the files that get selected.
|
|
|
|
One of these allows special extra information to be displayed for files
|
|
in a dialog box as the user selects them. Each time the current file or
|
|
directory is changed, the selectedFileChanged() method will be called
|
|
to allow it to update itself appropriately.
|
|
|
|
@see FileChooser, ImagePreviewComponent
|
|
*/
|
|
class JUCE_API FilePreviewComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a FilePreviewComponent. */
|
|
FilePreviewComponent();
|
|
|
|
/** Destructor. */
|
|
~FilePreviewComponent();
|
|
|
|
/** Called to indicate that the user's currently selected file has changed.
|
|
|
|
@param newSelectedFile the newly selected file or directory, which may be
|
|
File::nonexistent if none is selected.
|
|
*/
|
|
virtual void selectedFileChanged (const File& newSelectedFile) = 0;
|
|
|
|
private:
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilePreviewComponent);
|
|
};
|
|
|
|
#endif // __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FilePreviewComponent.h ***/
|
|
|
|
/**
|
|
A component for browsing and selecting a file or directory to open or save.
|
|
|
|
This contains a FileListComponent and adds various boxes and controls for
|
|
navigating and selecting a file. It can work in different modes so that it can
|
|
be used for loading or saving a file, or for choosing a directory.
|
|
|
|
@see FileChooserDialogBox, FileChooser, FileListComponent
|
|
*/
|
|
class JUCE_API FileBrowserComponent : public Component,
|
|
public ChangeBroadcaster,
|
|
private FileBrowserListener,
|
|
private TextEditorListener,
|
|
private ButtonListener,
|
|
private ComboBoxListener, // (can't use ComboBox::Listener due to idiotic VC2005 bug)
|
|
private FileFilter
|
|
{
|
|
public:
|
|
|
|
/** Various options for the browser.
|
|
|
|
A combination of these is passed into the FileBrowserComponent constructor.
|
|
*/
|
|
enum FileChooserFlags
|
|
{
|
|
openMode = 1, /**< specifies that the component should allow the user to
|
|
choose an existing file with the intention of opening it. */
|
|
saveMode = 2, /**< specifies that the component should allow the user to specify
|
|
the name of a file that will be used to save something. */
|
|
canSelectFiles = 4, /**< specifies that the user can select files (can be used in
|
|
conjunction with canSelectDirectories). */
|
|
canSelectDirectories = 8, /**< specifies that the user can select directories (can be used in
|
|
conjuction with canSelectFiles). */
|
|
canSelectMultipleItems = 16, /**< specifies that the user can select multiple items. */
|
|
useTreeView = 32, /**< specifies that a tree-view should be shown instead of a file list. */
|
|
filenameBoxIsReadOnly = 64 /**< specifies that the user can't type directly into the filename box. */
|
|
};
|
|
|
|
/** Creates a FileBrowserComponent.
|
|
|
|
@param flags A combination of flags from the FileChooserFlags enumeration,
|
|
used to specify the component's behaviour. The flags must contain
|
|
either openMode or saveMode, and canSelectFiles and/or
|
|
canSelectDirectories.
|
|
@param initialFileOrDirectory The file or directory that should be selected when
|
|
the component begins. If this is File::nonexistent,
|
|
a default directory will be chosen.
|
|
@param fileFilter an optional filter to use to determine which files
|
|
are shown. If this is 0 then all files are displayed. Note
|
|
that a pointer is kept internally to this object, so
|
|
make sure that it is not deleted before the browser object
|
|
is deleted.
|
|
@param previewComp an optional preview component that will be used to
|
|
show previews of files that the user selects
|
|
*/
|
|
FileBrowserComponent (int flags,
|
|
const File& initialFileOrDirectory,
|
|
const FileFilter* fileFilter,
|
|
FilePreviewComponent* previewComp);
|
|
|
|
/** Destructor. */
|
|
~FileBrowserComponent();
|
|
|
|
/** Returns the number of files that the user has got selected.
|
|
If multiple select isn't active, this will only be 0 or 1. To get the complete
|
|
list of files they've chosen, pass an index to getCurrentFile().
|
|
*/
|
|
int getNumSelectedFiles() const noexcept;
|
|
|
|
/** Returns one of the files that the user has chosen.
|
|
If the box has multi-select enabled, the index lets you specify which of the files
|
|
to get - see getNumSelectedFiles() to find out how many files were chosen.
|
|
@see getHighlightedFile
|
|
*/
|
|
File getSelectedFile (int index) const noexcept;
|
|
|
|
/** Deselects any files that are currently selected.
|
|
*/
|
|
void deselectAllFiles();
|
|
|
|
/** Returns true if the currently selected file(s) are usable.
|
|
|
|
This can be used to decide whether the user can press "ok" for the
|
|
current file. What it does depends on the mode, so for example in an "open"
|
|
mode, this only returns true if a file has been selected and if it exists.
|
|
In a "save" mode, a non-existent file would also be valid.
|
|
*/
|
|
bool currentFileIsValid() const;
|
|
|
|
/** This returns the last item in the view that the user has highlighted.
|
|
This may be different from getCurrentFile(), which returns the value
|
|
that is shown in the filename box, and if there are multiple selections,
|
|
this will only return one of them.
|
|
@see getSelectedFile
|
|
*/
|
|
File getHighlightedFile() const noexcept;
|
|
|
|
/** Returns the directory whose contents are currently being shown in the listbox. */
|
|
const File& getRoot() const;
|
|
|
|
/** Changes the directory that's being shown in the listbox. */
|
|
void setRoot (const File& newRootDirectory);
|
|
|
|
/** Equivalent to pressing the "up" button to browse the parent directory. */
|
|
void goUp();
|
|
|
|
/** Refreshes the directory that's currently being listed. */
|
|
void refresh();
|
|
|
|
/** Changes the filter that's being used to sift the files. */
|
|
void setFileFilter (const FileFilter* newFileFilter);
|
|
|
|
/** Returns a verb to describe what should happen when the file is accepted.
|
|
|
|
E.g. if browsing in "load file" mode, this will be "Open", if in "save file"
|
|
mode, it'll be "Save", etc.
|
|
*/
|
|
virtual const String getActionVerb() const;
|
|
|
|
/** Returns true if the saveMode flag was set when this component was created.
|
|
*/
|
|
bool isSaveMode() const noexcept;
|
|
|
|
/** Adds a listener to be told when the user selects and clicks on files.
|
|
|
|
@see removeListener
|
|
*/
|
|
void addListener (FileBrowserListener* listener);
|
|
|
|
/** Removes a listener.
|
|
|
|
@see addListener
|
|
*/
|
|
void removeListener (FileBrowserListener* listener);
|
|
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void buttonClicked (Button* b);
|
|
/** @internal */
|
|
void comboBoxChanged (ComboBox*);
|
|
/** @internal */
|
|
void textEditorTextChanged (TextEditor& editor);
|
|
/** @internal */
|
|
void textEditorReturnKeyPressed (TextEditor& editor);
|
|
/** @internal */
|
|
void textEditorEscapeKeyPressed (TextEditor& editor);
|
|
/** @internal */
|
|
void textEditorFocusLost (TextEditor& editor);
|
|
/** @internal */
|
|
bool keyPressed (const KeyPress& key);
|
|
/** @internal */
|
|
void selectionChanged();
|
|
/** @internal */
|
|
void fileClicked (const File& f, const MouseEvent& e);
|
|
/** @internal */
|
|
void fileDoubleClicked (const File& f);
|
|
/** @internal */
|
|
bool isFileSuitable (const File& file) const;
|
|
/** @internal */
|
|
bool isDirectorySuitable (const File&) const;
|
|
|
|
/** @internal */
|
|
FilePreviewComponent* getPreviewComponent() const noexcept;
|
|
|
|
protected:
|
|
/** Returns a list of names and paths for the default places the user might want to look.
|
|
Use an empty string to indicate a section break.
|
|
*/
|
|
virtual void getRoots (StringArray& rootNames, StringArray& rootPaths);
|
|
|
|
/** Updates the items in the dropdown list of recent paths with the values from getRoots(). */
|
|
void resetRecentPaths();
|
|
|
|
private:
|
|
|
|
ScopedPointer <DirectoryContentsList> fileList;
|
|
const FileFilter* fileFilter;
|
|
|
|
int flags;
|
|
File currentRoot;
|
|
Array<File> chosenFiles;
|
|
ListenerList <FileBrowserListener> listeners;
|
|
|
|
ScopedPointer<DirectoryContentsDisplayComponent> fileListComponent;
|
|
FilePreviewComponent* previewComp;
|
|
ComboBox currentPathBox;
|
|
TextEditor filenameBox;
|
|
Label fileLabel;
|
|
ScopedPointer<Button> goUpButton;
|
|
|
|
TimeSliceThread thread;
|
|
|
|
void sendListenerChangeMessage();
|
|
bool isFileOrDirSuitable (const File& f) const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileBrowserComponent);
|
|
};
|
|
|
|
#endif // __JUCE_FILEBROWSERCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileBrowserComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILEBROWSERLISTENER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILECHOOSER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FileChooser.h ***/
|
|
#ifndef __JUCE_FILECHOOSER_JUCEHEADER__
|
|
#define __JUCE_FILECHOOSER_JUCEHEADER__
|
|
|
|
/**
|
|
Creates a dialog box to choose a file or directory to load or save.
|
|
|
|
To use a FileChooser:
|
|
- create one (as a local stack variable is the neatest way)
|
|
- call one of its browseFor.. methods
|
|
- if this returns true, the user has selected a file, so you can retrieve it
|
|
with the getResult() method.
|
|
|
|
e.g. @code
|
|
void loadMooseFile()
|
|
{
|
|
FileChooser myChooser ("Please select the moose you want to load...",
|
|
File::getSpecialLocation (File::userHomeDirectory),
|
|
"*.moose");
|
|
|
|
if (myChooser.browseForFileToOpen())
|
|
{
|
|
File mooseFile (myChooser.getResult());
|
|
|
|
loadMoose (mooseFile);
|
|
}
|
|
}
|
|
@endcode
|
|
*/
|
|
class JUCE_API FileChooser
|
|
{
|
|
public:
|
|
|
|
/** Creates a FileChooser.
|
|
|
|
After creating one of these, use one of the browseFor... methods to display it.
|
|
|
|
@param dialogBoxTitle a text string to display in the dialog box to
|
|
tell the user what's going on
|
|
@param initialFileOrDirectory the file or directory that should be selected when
|
|
the dialog box opens. If this parameter is set to
|
|
File::nonexistent, a sensible default directory
|
|
will be used instead.
|
|
@param filePatternsAllowed a set of file patterns to specify which files can be
|
|
selected - each pattern should be separated by a
|
|
comma or semi-colon, e.g. "*" or "*.jpg;*.gif". An
|
|
empty string means that all files are allowed
|
|
@param useOSNativeDialogBox if true, then a native dialog box will be used if
|
|
possible; if false, then a Juce-based browser dialog
|
|
box will always be used
|
|
@see browseForFileToOpen, browseForFileToSave, browseForDirectory
|
|
*/
|
|
FileChooser (const String& dialogBoxTitle,
|
|
const File& initialFileOrDirectory = File::nonexistent,
|
|
const String& filePatternsAllowed = String::empty,
|
|
bool useOSNativeDialogBox = true);
|
|
|
|
/** Destructor. */
|
|
~FileChooser();
|
|
|
|
/** Shows a dialog box to choose a file to open.
|
|
|
|
This will display the dialog box modally, using an "open file" mode, so that
|
|
it won't allow non-existent files or directories to be chosen.
|
|
|
|
@param previewComponent an optional component to display inside the dialog
|
|
box to show special info about the files that the user
|
|
is browsing. The component will not be deleted by this
|
|
object, so the caller must take care of it.
|
|
@returns true if the user selected a file, in which case, use the getResult()
|
|
method to find out what it was. Returns false if they cancelled instead.
|
|
@see browseForFileToSave, browseForDirectory
|
|
*/
|
|
bool browseForFileToOpen (FilePreviewComponent* previewComponent = 0);
|
|
|
|
/** Same as browseForFileToOpen, but allows the user to select multiple files.
|
|
|
|
The files that are returned can be obtained by calling getResults(). See
|
|
browseForFileToOpen() for more info about the behaviour of this method.
|
|
*/
|
|
bool browseForMultipleFilesToOpen (FilePreviewComponent* previewComponent = 0);
|
|
|
|
/** Shows a dialog box to choose a file to save.
|
|
|
|
This will display the dialog box modally, using an "save file" mode, so it
|
|
will allow non-existent files to be chosen, but not directories.
|
|
|
|
@param warnAboutOverwritingExistingFiles if true, the dialog box will ask
|
|
the user if they're sure they want to overwrite a file that already
|
|
exists
|
|
@returns true if the user chose a file and pressed 'ok', in which case, use
|
|
the getResult() method to find out what the file was. Returns false
|
|
if they cancelled instead.
|
|
@see browseForFileToOpen, browseForDirectory
|
|
*/
|
|
bool browseForFileToSave (bool warnAboutOverwritingExistingFiles);
|
|
|
|
/** Shows a dialog box to choose a directory.
|
|
|
|
This will display the dialog box modally, using an "open directory" mode, so it
|
|
will only allow directories to be returned, not files.
|
|
|
|
@returns true if the user chose a directory and pressed 'ok', in which case, use
|
|
the getResult() method to find out what they chose. Returns false
|
|
if they cancelled instead.
|
|
@see browseForFileToOpen, browseForFileToSave
|
|
*/
|
|
bool browseForDirectory();
|
|
|
|
/** Same as browseForFileToOpen, but allows the user to select multiple files and directories.
|
|
|
|
The files that are returned can be obtained by calling getResults(). See
|
|
browseForFileToOpen() for more info about the behaviour of this method.
|
|
*/
|
|
bool browseForMultipleFilesOrDirectories (FilePreviewComponent* previewComponent = 0);
|
|
|
|
/** Returns the last file that was chosen by one of the browseFor methods.
|
|
|
|
After calling the appropriate browseFor... method, this method lets you
|
|
find out what file or directory they chose.
|
|
|
|
Note that the file returned is only valid if the browse method returned true (i.e.
|
|
if the user pressed 'ok' rather than cancelling).
|
|
|
|
If you're using a multiple-file select, then use the getResults() method instead,
|
|
to obtain the list of all files chosen.
|
|
|
|
@see getResults
|
|
*/
|
|
File getResult() const;
|
|
|
|
/** Returns a list of all the files that were chosen during the last call to a
|
|
browse method.
|
|
|
|
This array may be empty if no files were chosen, or can contain multiple entries
|
|
if multiple files were chosen.
|
|
|
|
@see getResult
|
|
*/
|
|
const Array<File>& getResults() const;
|
|
|
|
private:
|
|
|
|
String title, filters;
|
|
File startingFile;
|
|
Array<File> results;
|
|
bool useNativeDialogBox;
|
|
|
|
bool showDialog (bool selectsDirectories, bool selectsFiles, bool isSave,
|
|
bool warnAboutOverwritingExistingFiles, bool selectMultipleFiles,
|
|
FilePreviewComponent* previewComponent);
|
|
|
|
static void showPlatformDialog (Array<File>& results, const String& title, const File& file,
|
|
const String& filters, bool selectsDirectories, bool selectsFiles,
|
|
bool isSave, bool warnAboutOverwritingExistingFiles, bool selectMultipleFiles,
|
|
FilePreviewComponent* previewComponent);
|
|
|
|
JUCE_LEAK_DETECTOR (FileChooser);
|
|
};
|
|
|
|
#endif // __JUCE_FILECHOOSER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileChooser.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FileChooserDialogBox.h ***/
|
|
#ifndef __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__
|
|
#define __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_ResizableWindow.h ***/
|
|
#ifndef __JUCE_RESIZABLEWINDOW_JUCEHEADER__
|
|
#define __JUCE_RESIZABLEWINDOW_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_TopLevelWindow.h ***/
|
|
#ifndef __JUCE_TOPLEVELWINDOW_JUCEHEADER__
|
|
#define __JUCE_TOPLEVELWINDOW_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_DropShadower.h ***/
|
|
#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__
|
|
#define __JUCE_DROPSHADOWER_JUCEHEADER__
|
|
|
|
/**
|
|
Adds a drop-shadow to a component.
|
|
|
|
This object creates and manages a set of components which sit around a
|
|
component, creating a gaussian shadow around it. The components will track
|
|
the position of the component and if it's brought to the front they'll also
|
|
follow this.
|
|
|
|
For desktop windows you don't need to use this class directly - just
|
|
set the Component::windowHasDropShadow flag when calling
|
|
Component::addToDesktop(), and the system will create one of these if it's
|
|
needed (which it obviously isn't on the Mac, for example).
|
|
*/
|
|
class JUCE_API DropShadower : public ComponentListener
|
|
{
|
|
public:
|
|
|
|
/** Creates a DropShadower.
|
|
|
|
@param alpha the opacity of the shadows, from 0 to 1.0
|
|
@param xOffset the horizontal displacement of the shadow, in pixels
|
|
@param yOffset the vertical displacement of the shadow, in pixels
|
|
@param blurRadius the radius of the blur to use for creating the shadow
|
|
*/
|
|
DropShadower (float alpha = 0.5f,
|
|
int xOffset = 1,
|
|
int yOffset = 5,
|
|
float blurRadius = 10.0f);
|
|
|
|
/** Destructor. */
|
|
virtual ~DropShadower();
|
|
|
|
/** Attaches the DropShadower to the component you want to shadow. */
|
|
void setOwner (Component* componentToFollow);
|
|
|
|
/** @internal */
|
|
void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized);
|
|
/** @internal */
|
|
void componentBroughtToFront (Component& component);
|
|
/** @internal */
|
|
void componentParentHierarchyChanged (Component& component);
|
|
/** @internal */
|
|
void componentVisibilityChanged (Component& component);
|
|
|
|
private:
|
|
|
|
Component* owner;
|
|
OwnedArray<Component> shadowWindows;
|
|
Image shadowImageSections[12];
|
|
const int xOffset, yOffset;
|
|
const float alpha, blurRadius;
|
|
bool reentrant;
|
|
|
|
void updateShadows();
|
|
void setShadowImage (const Image& src, int num, int w, int h, int sx, int sy);
|
|
void bringShadowWindowsToFront();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DropShadower);
|
|
};
|
|
|
|
#endif // __JUCE_DROPSHADOWER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DropShadower.h ***/
|
|
|
|
/**
|
|
A base class for top-level windows.
|
|
|
|
This class is used for components that are considered a major part of your
|
|
application - e.g. ResizableWindow, DocumentWindow, DialogWindow, AlertWindow,
|
|
etc. Things like menus that pop up briefly aren't derived from it.
|
|
|
|
A TopLevelWindow is probably on the desktop, but this isn't mandatory - it
|
|
could itself be the child of another component.
|
|
|
|
The class manages a list of all instances of top-level windows that are in use,
|
|
and each one is also given the concept of being "active". The active window is
|
|
one that is actively being used by the user. This isn't quite the same as the
|
|
component with the keyboard focus, because there may be a popup menu or other
|
|
temporary window which gets keyboard focus while the active top level window is
|
|
unchanged.
|
|
|
|
A top-level window also has an optional drop-shadow.
|
|
|
|
@see ResizableWindow, DocumentWindow, DialogWindow
|
|
*/
|
|
class JUCE_API TopLevelWindow : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a TopLevelWindow.
|
|
|
|
@param name the name to give the component
|
|
@param addToDesktop if true, the window will be automatically added to the
|
|
desktop; if false, you can use it as a child component
|
|
*/
|
|
TopLevelWindow (const String& name, bool addToDesktop);
|
|
|
|
/** Destructor. */
|
|
~TopLevelWindow();
|
|
|
|
/** True if this is currently the TopLevelWindow that is actively being used.
|
|
|
|
This isn't quite the same as having keyboard focus, because the focus may be
|
|
on a child component or a temporary pop-up menu, etc, while this window is
|
|
still considered to be active.
|
|
|
|
@see activeWindowStatusChanged
|
|
*/
|
|
bool isActiveWindow() const noexcept { return windowIsActive_; }
|
|
|
|
/** This will set the bounds of the window so that it's centred in front of another
|
|
window.
|
|
|
|
If your app has a few windows open and want to pop up a dialog box for one of
|
|
them, you can use this to show it in front of the relevent parent window, which
|
|
is a bit neater than just having it appear in the middle of the screen.
|
|
|
|
If componentToCentreAround is 0, then the currently active TopLevelWindow will
|
|
be used instead. If no window is focused, it'll just default to the middle of the
|
|
screen.
|
|
*/
|
|
void centreAroundComponent (Component* componentToCentreAround,
|
|
int width, int height);
|
|
|
|
/** Turns the drop-shadow on and off. */
|
|
void setDropShadowEnabled (bool useShadow);
|
|
|
|
/** True if drop-shadowing is enabled. */
|
|
bool isDropShadowEnabled() const noexcept { return useDropShadow; }
|
|
|
|
/** Sets whether an OS-native title bar will be used, or a Juce one.
|
|
|
|
@see isUsingNativeTitleBar
|
|
*/
|
|
void setUsingNativeTitleBar (bool useNativeTitleBar);
|
|
|
|
/** Returns true if the window is currently using an OS-native title bar.
|
|
|
|
@see setUsingNativeTitleBar
|
|
*/
|
|
bool isUsingNativeTitleBar() const noexcept { return useNativeTitleBar && isOnDesktop(); }
|
|
|
|
/** Returns the number of TopLevelWindow objects currently in use.
|
|
|
|
@see getTopLevelWindow
|
|
*/
|
|
static int getNumTopLevelWindows() noexcept;
|
|
|
|
/** Returns one of the TopLevelWindow objects currently in use.
|
|
|
|
The index is 0 to (getNumTopLevelWindows() - 1).
|
|
*/
|
|
static TopLevelWindow* getTopLevelWindow (int index) noexcept;
|
|
|
|
/** Returns the currently-active top level window.
|
|
|
|
There might not be one, of course, so this can return 0.
|
|
*/
|
|
static TopLevelWindow* getActiveTopLevelWindow() noexcept;
|
|
|
|
/** @internal */
|
|
virtual void addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = nullptr);
|
|
|
|
protected:
|
|
|
|
/** This callback happens when this window becomes active or inactive.
|
|
|
|
@see isActiveWindow
|
|
*/
|
|
virtual void activeWindowStatusChanged();
|
|
|
|
/** @internal */
|
|
void focusOfChildComponentChanged (FocusChangeType cause);
|
|
/** @internal */
|
|
void parentHierarchyChanged();
|
|
/** @internal */
|
|
virtual int getDesktopWindowStyleFlags() const;
|
|
/** @internal */
|
|
void recreateDesktopWindow();
|
|
/** @internal */
|
|
void visibilityChanged();
|
|
|
|
private:
|
|
friend class TopLevelWindowManager;
|
|
bool useDropShadow, useNativeTitleBar, windowIsActive_;
|
|
ScopedPointer <DropShadower> shadower;
|
|
|
|
void setWindowActive (bool isNowActive);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TopLevelWindow);
|
|
};
|
|
|
|
#endif // __JUCE_TOPLEVELWINDOW_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TopLevelWindow.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_ComponentDragger.h ***/
|
|
#ifndef __JUCE_COMPONENTDRAGGER_JUCEHEADER__
|
|
#define __JUCE_COMPONENTDRAGGER_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_ComponentBoundsConstrainer.h ***/
|
|
#ifndef __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__
|
|
#define __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__
|
|
|
|
/**
|
|
A class that imposes restrictions on a Component's size or position.
|
|
|
|
This is used by classes such as ResizableCornerComponent,
|
|
ResizableBorderComponent and ResizableWindow.
|
|
|
|
The base class can impose some basic size and position limits, but you can
|
|
also subclass this for custom uses.
|
|
|
|
@see ResizableCornerComponent, ResizableBorderComponent, ResizableWindow
|
|
*/
|
|
class JUCE_API ComponentBoundsConstrainer
|
|
{
|
|
public:
|
|
|
|
/** When first created, the object will not impose any restrictions on the components. */
|
|
ComponentBoundsConstrainer() noexcept;
|
|
|
|
/** Destructor. */
|
|
virtual ~ComponentBoundsConstrainer();
|
|
|
|
/** Imposes a minimum width limit. */
|
|
void setMinimumWidth (int minimumWidth) noexcept;
|
|
|
|
/** Returns the current minimum width. */
|
|
int getMinimumWidth() const noexcept { return minW; }
|
|
|
|
/** Imposes a maximum width limit. */
|
|
void setMaximumWidth (int maximumWidth) noexcept;
|
|
|
|
/** Returns the current maximum width. */
|
|
int getMaximumWidth() const noexcept { return maxW; }
|
|
|
|
/** Imposes a minimum height limit. */
|
|
void setMinimumHeight (int minimumHeight) noexcept;
|
|
|
|
/** Returns the current minimum height. */
|
|
int getMinimumHeight() const noexcept { return minH; }
|
|
|
|
/** Imposes a maximum height limit. */
|
|
void setMaximumHeight (int maximumHeight) noexcept;
|
|
|
|
/** Returns the current maximum height. */
|
|
int getMaximumHeight() const noexcept { return maxH; }
|
|
|
|
/** Imposes a minimum width and height limit. */
|
|
void setMinimumSize (int minimumWidth,
|
|
int minimumHeight) noexcept;
|
|
|
|
/** Imposes a maximum width and height limit. */
|
|
void setMaximumSize (int maximumWidth,
|
|
int maximumHeight) noexcept;
|
|
|
|
/** Set all the maximum and minimum dimensions. */
|
|
void setSizeLimits (int minimumWidth,
|
|
int minimumHeight,
|
|
int maximumWidth,
|
|
int maximumHeight) noexcept;
|
|
|
|
/** Sets the amount by which the component is allowed to go off-screen.
|
|
|
|
The values indicate how many pixels must remain on-screen when dragged off
|
|
one of its parent's edges, so e.g. if minimumWhenOffTheTop is set to 10, then
|
|
when the component goes off the top of the screen, its y-position will be
|
|
clipped so that there are always at least 10 pixels on-screen. In other words,
|
|
the lowest y-position it can take would be (10 - the component's height).
|
|
|
|
If you pass 0 or less for one of these amounts, the component is allowed
|
|
to move beyond that edge completely, with no restrictions at all.
|
|
|
|
If you pass a very large number (i.e. larger that the dimensions of the
|
|
component itself), then the component won't be allowed to overlap that
|
|
edge at all. So e.g. setting minimumWhenOffTheLeft to 0xffffff will mean that
|
|
the component will bump into the left side of the screen and go no further.
|
|
*/
|
|
void setMinimumOnscreenAmounts (int minimumWhenOffTheTop,
|
|
int minimumWhenOffTheLeft,
|
|
int minimumWhenOffTheBottom,
|
|
int minimumWhenOffTheRight) noexcept;
|
|
|
|
/** Returns the minimum distance the bounds can be off-screen. @see setMinimumOnscreenAmounts */
|
|
int getMinimumWhenOffTheTop() const noexcept { return minOffTop; }
|
|
/** Returns the minimum distance the bounds can be off-screen. @see setMinimumOnscreenAmounts */
|
|
int getMinimumWhenOffTheLeft() const noexcept { return minOffLeft; }
|
|
/** Returns the minimum distance the bounds can be off-screen. @see setMinimumOnscreenAmounts */
|
|
int getMinimumWhenOffTheBottom() const noexcept { return minOffBottom; }
|
|
/** Returns the minimum distance the bounds can be off-screen. @see setMinimumOnscreenAmounts */
|
|
int getMinimumWhenOffTheRight() const noexcept { return minOffRight; }
|
|
|
|
/** Specifies a width-to-height ratio that the resizer should always maintain.
|
|
|
|
If the value is 0, no aspect ratio is enforced. If it's non-zero, the width
|
|
will always be maintained as this multiple of the height.
|
|
|
|
@see setResizeLimits
|
|
*/
|
|
void setFixedAspectRatio (double widthOverHeight) noexcept;
|
|
|
|
/** Returns the aspect ratio that was set with setFixedAspectRatio().
|
|
|
|
If no aspect ratio is being enforced, this will return 0.
|
|
*/
|
|
double getFixedAspectRatio() const noexcept;
|
|
|
|
/** This callback changes the given co-ordinates to impose whatever the current
|
|
constraints are set to be.
|
|
|
|
@param bounds the target position that should be examined and adjusted
|
|
@param previousBounds the component's current size
|
|
@param limits the region in which the component can be positioned
|
|
@param isStretchingTop whether the top edge of the component is being resized
|
|
@param isStretchingLeft whether the left edge of the component is being resized
|
|
@param isStretchingBottom whether the bottom edge of the component is being resized
|
|
@param isStretchingRight whether the right edge of the component is being resized
|
|
*/
|
|
virtual void checkBounds (Rectangle<int>& bounds,
|
|
const Rectangle<int>& previousBounds,
|
|
const Rectangle<int>& limits,
|
|
bool isStretchingTop,
|
|
bool isStretchingLeft,
|
|
bool isStretchingBottom,
|
|
bool isStretchingRight);
|
|
|
|
/** This callback happens when the resizer is about to start dragging. */
|
|
virtual void resizeStart();
|
|
|
|
/** This callback happens when the resizer has finished dragging. */
|
|
virtual void resizeEnd();
|
|
|
|
/** Checks the given bounds, and then sets the component to the corrected size. */
|
|
void setBoundsForComponent (Component* component,
|
|
const Rectangle<int>& bounds,
|
|
bool isStretchingTop,
|
|
bool isStretchingLeft,
|
|
bool isStretchingBottom,
|
|
bool isStretchingRight);
|
|
|
|
/** Performs a check on the current size of a component, and moves or resizes
|
|
it if it fails the constraints.
|
|
*/
|
|
void checkComponentBounds (Component* component);
|
|
|
|
/** Called by setBoundsForComponent() to apply a new constrained size to a
|
|
component.
|
|
|
|
By default this just calls setBounds(), but it virtual in case it's needed for
|
|
extremely cunning purposes.
|
|
*/
|
|
virtual void applyBoundsToComponent (Component* component,
|
|
const Rectangle<int>& bounds);
|
|
|
|
private:
|
|
|
|
int minW, maxW, minH, maxH;
|
|
int minOffTop, minOffLeft, minOffBottom, minOffRight;
|
|
double aspectRatio;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentBoundsConstrainer);
|
|
};
|
|
|
|
#endif // __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ComponentBoundsConstrainer.h ***/
|
|
|
|
/**
|
|
An object to take care of the logic for dragging components around with the mouse.
|
|
|
|
Very easy to use - in your mouseDown() callback, call startDraggingComponent(),
|
|
then in your mouseDrag() callback, call dragComponent().
|
|
|
|
When starting a drag, you can give it a ComponentBoundsConstrainer to use
|
|
to limit the component's position and keep it on-screen.
|
|
|
|
e.g. @code
|
|
class MyDraggableComp
|
|
{
|
|
ComponentDragger myDragger;
|
|
|
|
void mouseDown (const MouseEvent& e)
|
|
{
|
|
myDragger.startDraggingComponent (this, e);
|
|
}
|
|
|
|
void mouseDrag (const MouseEvent& e)
|
|
{
|
|
myDragger.dragComponent (this, e, nullptr);
|
|
}
|
|
};
|
|
@endcode
|
|
*/
|
|
class JUCE_API ComponentDragger
|
|
{
|
|
public:
|
|
|
|
/** Creates a ComponentDragger. */
|
|
ComponentDragger();
|
|
|
|
/** Destructor. */
|
|
virtual ~ComponentDragger();
|
|
|
|
/** Call this from your component's mouseDown() method, to prepare for dragging.
|
|
|
|
@param componentToDrag the component that you want to drag
|
|
@param e the mouse event that is triggering the drag
|
|
@see dragComponent
|
|
*/
|
|
void startDraggingComponent (Component* componentToDrag,
|
|
const MouseEvent& e);
|
|
|
|
/** Call this from your mouseDrag() callback to move the component.
|
|
|
|
This will move the component, but will first check the validity of the
|
|
component's new position using the checkPosition() method, which you
|
|
can override if you need to enforce special positioning limits on the
|
|
component.
|
|
|
|
@param componentToDrag the component that you want to drag
|
|
@param e the current mouse-drag event
|
|
@param constrainer an optional constrainer object that should be used
|
|
to apply limits to the component's position. Pass
|
|
null if you don't want to contrain the movement.
|
|
@see startDraggingComponent
|
|
*/
|
|
void dragComponent (Component* componentToDrag,
|
|
const MouseEvent& e,
|
|
ComponentBoundsConstrainer* constrainer);
|
|
|
|
private:
|
|
|
|
Point<int> mouseDownWithinTarget;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentDragger);
|
|
};
|
|
|
|
#endif // __JUCE_COMPONENTDRAGGER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ComponentDragger.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_ResizableBorderComponent.h ***/
|
|
#ifndef __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component that resizes its parent component when dragged.
|
|
|
|
This component forms a frame around the edge of a component, allowing it to
|
|
be dragged by the edges or corners to resize it - like the way windows are
|
|
resized in MSWindows or Linux.
|
|
|
|
To use it, just add it to your component, making it fill the entire parent component
|
|
(there's a mouse hit-test that only traps mouse-events which land around the
|
|
edge of the component, so it's even ok to put it on top of any other components
|
|
you're using). Make sure you rescale the resizer component to fill the parent
|
|
each time the parent's size changes.
|
|
|
|
@see ResizableCornerComponent
|
|
*/
|
|
class JUCE_API ResizableBorderComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a resizer.
|
|
|
|
Pass in the target component which you want to be resized when this one is
|
|
dragged.
|
|
|
|
The target component will usually be a parent of the resizer component, but this
|
|
isn't mandatory.
|
|
|
|
Remember that when the target component is resized, it'll need to move and
|
|
resize this component to keep it in place, as this won't happen automatically.
|
|
|
|
If the constrainer parameter is non-zero, then this object will be used to enforce
|
|
limits on the size and position that the component can be stretched to. Make sure
|
|
that the constrainer isn't deleted while still in use by this object.
|
|
|
|
@see ComponentBoundsConstrainer
|
|
*/
|
|
ResizableBorderComponent (Component* componentToResize,
|
|
ComponentBoundsConstrainer* constrainer);
|
|
|
|
/** Destructor. */
|
|
~ResizableBorderComponent();
|
|
|
|
/** Specifies how many pixels wide the draggable edges of this component are.
|
|
|
|
@see getBorderThickness
|
|
*/
|
|
void setBorderThickness (const BorderSize<int>& newBorderSize);
|
|
|
|
/** Returns the number of pixels wide that the draggable edges of this component are.
|
|
|
|
@see setBorderThickness
|
|
*/
|
|
const BorderSize<int> getBorderThickness() const;
|
|
|
|
/** Represents the different sections of a resizable border, which allow it to
|
|
resized in different ways.
|
|
*/
|
|
class Zone
|
|
{
|
|
public:
|
|
|
|
enum Zones
|
|
{
|
|
centre = 0,
|
|
left = 1,
|
|
top = 2,
|
|
right = 4,
|
|
bottom = 8
|
|
};
|
|
|
|
/** Creates a Zone from a combination of the flags in \enum Zones. */
|
|
explicit Zone (int zoneFlags = 0) noexcept;
|
|
Zone (const Zone& other) noexcept;
|
|
Zone& operator= (const Zone& other) noexcept;
|
|
|
|
bool operator== (const Zone& other) const noexcept;
|
|
bool operator!= (const Zone& other) const noexcept;
|
|
|
|
/** Given a point within a rectangle with a resizable border, this returns the
|
|
zone that the point lies within.
|
|
*/
|
|
static const Zone fromPositionOnBorder (const Rectangle<int>& totalSize,
|
|
const BorderSize<int>& border,
|
|
const Point<int>& position);
|
|
|
|
/** Returns an appropriate mouse-cursor for this resize zone. */
|
|
const MouseCursor getMouseCursor() const noexcept;
|
|
|
|
/** Returns true if dragging this zone will move the enire object without resizing it. */
|
|
bool isDraggingWholeObject() const noexcept { return zone == centre; }
|
|
/** Returns true if dragging this zone will move the object's left edge. */
|
|
bool isDraggingLeftEdge() const noexcept { return (zone & left) != 0; }
|
|
/** Returns true if dragging this zone will move the object's right edge. */
|
|
bool isDraggingRightEdge() const noexcept { return (zone & right) != 0; }
|
|
/** Returns true if dragging this zone will move the object's top edge. */
|
|
bool isDraggingTopEdge() const noexcept { return (zone & top) != 0; }
|
|
/** Returns true if dragging this zone will move the object's bottom edge. */
|
|
bool isDraggingBottomEdge() const noexcept { return (zone & bottom) != 0; }
|
|
|
|
/** Resizes this rectangle by the given amount, moving just the edges that this zone
|
|
applies to.
|
|
*/
|
|
template <typename ValueType>
|
|
const Rectangle<ValueType> resizeRectangleBy (Rectangle<ValueType> original,
|
|
const Point<ValueType>& distance) const noexcept
|
|
{
|
|
if (isDraggingWholeObject())
|
|
return original + distance;
|
|
|
|
if (isDraggingLeftEdge())
|
|
original.setLeft (jmin (original.getRight(), original.getX() + distance.getX()));
|
|
|
|
if (isDraggingRightEdge())
|
|
original.setWidth (jmax (ValueType(), original.getWidth() + distance.getX()));
|
|
|
|
if (isDraggingTopEdge())
|
|
original.setTop (jmin (original.getBottom(), original.getY() + distance.getY()));
|
|
|
|
if (isDraggingBottomEdge())
|
|
original.setHeight (jmax (ValueType(), original.getHeight() + distance.getY()));
|
|
|
|
return original;
|
|
}
|
|
|
|
/** Returns the raw flags for this zone. */
|
|
int getZoneFlags() const noexcept { return zone; }
|
|
|
|
private:
|
|
|
|
int zone;
|
|
};
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void mouseEnter (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseMove (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseUp (const MouseEvent& e);
|
|
/** @internal */
|
|
bool hitTest (int x, int y);
|
|
|
|
private:
|
|
WeakReference<Component> component;
|
|
ComponentBoundsConstrainer* constrainer;
|
|
BorderSize<int> borderSize;
|
|
Rectangle<int> originalBounds;
|
|
Zone mouseZone;
|
|
|
|
void updateMouseZone (const MouseEvent& e);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResizableBorderComponent);
|
|
};
|
|
|
|
#endif // __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ResizableBorderComponent.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_ResizableCornerComponent.h ***/
|
|
#ifndef __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__
|
|
|
|
/** A component that resizes a parent component when dragged.
|
|
|
|
This is the small triangular stripey resizer component you get in the bottom-right
|
|
of windows (more commonly on the Mac than Windows). Put one in the corner of
|
|
a larger component and it will automatically resize its parent when it gets dragged
|
|
around.
|
|
|
|
@see ResizableFrameComponent
|
|
*/
|
|
class JUCE_API ResizableCornerComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a resizer.
|
|
|
|
Pass in the target component which you want to be resized when this one is
|
|
dragged.
|
|
|
|
The target component will usually be a parent of the resizer component, but this
|
|
isn't mandatory.
|
|
|
|
Remember that when the target component is resized, it'll need to move and
|
|
resize this component to keep it in place, as this won't happen automatically.
|
|
|
|
If the constrainer parameter is non-zero, then this object will be used to enforce
|
|
limits on the size and position that the component can be stretched to. Make sure
|
|
that the constrainer isn't deleted while still in use by this object. If you
|
|
pass a zero in here, no limits will be put on the sizes it can be stretched to.
|
|
|
|
@see ComponentBoundsConstrainer
|
|
*/
|
|
ResizableCornerComponent (Component* componentToResize,
|
|
ComponentBoundsConstrainer* constrainer);
|
|
|
|
/** Destructor. */
|
|
~ResizableCornerComponent();
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseUp (const MouseEvent& e);
|
|
/** @internal */
|
|
bool hitTest (int x, int y);
|
|
|
|
private:
|
|
|
|
WeakReference<Component> component;
|
|
ComponentBoundsConstrainer* constrainer;
|
|
Rectangle<int> originalBounds;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResizableCornerComponent);
|
|
};
|
|
|
|
#endif // __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ResizableCornerComponent.h ***/
|
|
|
|
/**
|
|
A base class for top-level windows that can be dragged around and resized.
|
|
|
|
To add content to the window, use its setContentOwned() or setContentNonOwned() methods
|
|
to give it a component that will remain positioned inside it (leaving a gap around
|
|
the edges for a border).
|
|
|
|
It's not advisable to add child components directly to a ResizableWindow: put them
|
|
inside your content component instead. And overriding methods like resized(), moved(), etc
|
|
is also not recommended - instead override these methods for your content component.
|
|
(If for some obscure reason you do need to override these methods, always remember to
|
|
call the super-class's resized() method too, otherwise it'll fail to lay out the window
|
|
decorations correctly).
|
|
|
|
By default resizing isn't enabled - use the setResizable() method to enable it and
|
|
to choose the style of resizing to use.
|
|
|
|
@see TopLevelWindow
|
|
*/
|
|
class JUCE_API ResizableWindow : public TopLevelWindow
|
|
{
|
|
public:
|
|
|
|
/** Creates a ResizableWindow.
|
|
|
|
This constructor doesn't specify a background colour, so the LookAndFeel's default
|
|
background colour will be used.
|
|
|
|
@param name the name to give the component
|
|
@param addToDesktop if true, the window will be automatically added to the
|
|
desktop; if false, you can use it as a child component
|
|
*/
|
|
ResizableWindow (const String& name,
|
|
bool addToDesktop);
|
|
|
|
/** Creates a ResizableWindow.
|
|
|
|
@param name the name to give the component
|
|
@param backgroundColour the colour to use for filling the window's background.
|
|
@param addToDesktop if true, the window will be automatically added to the
|
|
desktop; if false, you can use it as a child component
|
|
*/
|
|
ResizableWindow (const String& name,
|
|
const Colour& backgroundColour,
|
|
bool addToDesktop);
|
|
|
|
/** Destructor.
|
|
If a content component has been set with setContentOwned(), it will be deleted.
|
|
*/
|
|
~ResizableWindow();
|
|
|
|
/** Returns the colour currently being used for the window's background.
|
|
|
|
As a convenience the window will fill itself with this colour, but you
|
|
can override the paint() method if you need more customised behaviour.
|
|
|
|
This method is the same as retrieving the colour for ResizableWindow::backgroundColourId.
|
|
|
|
@see setBackgroundColour
|
|
*/
|
|
const Colour getBackgroundColour() const noexcept;
|
|
|
|
/** Changes the colour currently being used for the window's background.
|
|
|
|
As a convenience the window will fill itself with this colour, but you
|
|
can override the paint() method if you need more customised behaviour.
|
|
|
|
Note that the opaque state of this window is altered by this call to reflect
|
|
the opacity of the colour passed-in. On window systems which can't support
|
|
semi-transparent windows this might cause problems, (though it's unlikely you'll
|
|
be using this class as a base for a semi-transparent component anyway).
|
|
|
|
You can also use the ResizableWindow::backgroundColourId colour id to set
|
|
this colour.
|
|
|
|
@see getBackgroundColour
|
|
*/
|
|
void setBackgroundColour (const Colour& newColour);
|
|
|
|
/** Make the window resizable or fixed.
|
|
|
|
@param shouldBeResizable whether it's resizable at all
|
|
@param useBottomRightCornerResizer if true, it'll add a ResizableCornerComponent at the
|
|
bottom-right; if false, it'll use a ResizableBorderComponent
|
|
around the edge
|
|
@see setResizeLimits, isResizable
|
|
*/
|
|
void setResizable (bool shouldBeResizable,
|
|
bool useBottomRightCornerResizer);
|
|
|
|
/** True if resizing is enabled.
|
|
|
|
@see setResizable
|
|
*/
|
|
bool isResizable() const noexcept;
|
|
|
|
/** This sets the maximum and minimum sizes for the window.
|
|
|
|
If the window's current size is outside these limits, it will be resized to
|
|
make sure it's within them.
|
|
|
|
Calling setBounds() on the component will bypass any size checking - it's only when
|
|
the window is being resized by the user that these values are enforced.
|
|
|
|
@see setResizable, setFixedAspectRatio
|
|
*/
|
|
void setResizeLimits (int newMinimumWidth,
|
|
int newMinimumHeight,
|
|
int newMaximumWidth,
|
|
int newMaximumHeight) noexcept;
|
|
|
|
/** Returns the bounds constrainer object that this window is using.
|
|
|
|
You can access this to change its properties.
|
|
*/
|
|
ComponentBoundsConstrainer* getConstrainer() noexcept { return constrainer; }
|
|
|
|
/** Sets the bounds-constrainer object to use for resizing and dragging this window.
|
|
|
|
A pointer to the object you pass in will be kept, but it won't be deleted
|
|
by this object, so it's the caller's responsiblity to manage it.
|
|
|
|
If you pass 0, then no contraints will be placed on the positioning of the window.
|
|
*/
|
|
void setConstrainer (ComponentBoundsConstrainer* newConstrainer);
|
|
|
|
/** Calls the window's setBounds method, after first checking these bounds
|
|
with the current constrainer.
|
|
|
|
@see setConstrainer
|
|
*/
|
|
void setBoundsConstrained (const Rectangle<int>& bounds);
|
|
|
|
/** Returns true if the window is currently in full-screen mode.
|
|
|
|
@see setFullScreen
|
|
*/
|
|
bool isFullScreen() const;
|
|
|
|
/** Puts the window into full-screen mode, or restores it to its normal size.
|
|
|
|
If true, the window will become full-screen; if false, it will return to the
|
|
last size it was before being made full-screen.
|
|
|
|
@see isFullScreen
|
|
*/
|
|
void setFullScreen (bool shouldBeFullScreen);
|
|
|
|
/** Returns true if the window is currently minimised.
|
|
|
|
@see setMinimised
|
|
*/
|
|
bool isMinimised() const;
|
|
|
|
/** Minimises the window, or restores it to its previous position and size.
|
|
|
|
When being un-minimised, it'll return to the last position and size it
|
|
was in before being minimised.
|
|
|
|
@see isMinimised
|
|
*/
|
|
void setMinimised (bool shouldMinimise);
|
|
|
|
/** Adds the window to the desktop using the default flags. */
|
|
void addToDesktop();
|
|
|
|
/** Returns a string which encodes the window's current size and position.
|
|
|
|
This string will encapsulate the window's size, position, and whether it's
|
|
in full-screen mode. It's intended for letting your application save and
|
|
restore a window's position.
|
|
|
|
Use the restoreWindowStateFromString() to restore from a saved state.
|
|
|
|
@see restoreWindowStateFromString
|
|
*/
|
|
String getWindowStateAsString();
|
|
|
|
/** Restores the window to a previously-saved size and position.
|
|
|
|
This restores the window's size, positon and full-screen status from an
|
|
string that was previously created with the getWindowStateAsString()
|
|
method.
|
|
|
|
@returns false if the string wasn't a valid window state
|
|
@see getWindowStateAsString
|
|
*/
|
|
bool restoreWindowStateFromString (const String& previousState);
|
|
|
|
/** Returns the current content component.
|
|
|
|
This will be the component set by setContentOwned() or setContentNonOwned, or 0 if none
|
|
has yet been specified.
|
|
|
|
@see setContentOwned, setContentNonOwned
|
|
*/
|
|
Component* getContentComponent() const noexcept { return contentComponent; }
|
|
|
|
/** Changes the current content component.
|
|
|
|
This sets a component that will be placed in the centre of the ResizableWindow,
|
|
(leaving a space around the edge for the border).
|
|
|
|
You should never add components directly to a ResizableWindow (or any of its subclasses)
|
|
with addChildComponent(). Instead, add them to the content component.
|
|
|
|
@param newContentComponent the new component to use - this component will be deleted when it's
|
|
no longer needed (i.e. when the window is deleted or a new content
|
|
component is set for it). To set a component that this window will not
|
|
delete, call setContentNonOwned() instead.
|
|
@param resizeToFitWhenContentChangesSize if true, then the ResizableWindow will maintain its size
|
|
such that it always fits around the size of the content component. If false,
|
|
the new content will be resized to fit the current space available.
|
|
*/
|
|
void setContentOwned (Component* newContentComponent,
|
|
bool resizeToFitWhenContentChangesSize);
|
|
|
|
/** Changes the current content component.
|
|
|
|
This sets a component that will be placed in the centre of the ResizableWindow,
|
|
(leaving a space around the edge for the border).
|
|
|
|
You should never add components directly to a ResizableWindow (or any of its subclasses)
|
|
with addChildComponent(). Instead, add them to the content component.
|
|
|
|
@param newContentComponent the new component to use - this component will NOT be deleted by this
|
|
component, so it's the caller's responsibility to manage its lifetime (it's
|
|
ok to delete it while this window is still using it). To set a content
|
|
component that the window will delete, call setContentOwned() instead.
|
|
@param resizeToFitWhenContentChangesSize if true, then the ResizableWindow will maintain its size
|
|
such that it always fits around the size of the content component. If false,
|
|
the new content will be resized to fit the current space available.
|
|
*/
|
|
void setContentNonOwned (Component* newContentComponent,
|
|
bool resizeToFitWhenContentChangesSize);
|
|
|
|
/** Removes the current content component.
|
|
If the previous content component was added with setContentOwned(), it will also be deleted. If
|
|
it was added with setContentNonOwned(), it will simply be removed from this component.
|
|
*/
|
|
void clearContentComponent();
|
|
|
|
/** Changes the window so that the content component ends up with the specified size.
|
|
|
|
This is basically a setSize call on the window, but which adds on the borders,
|
|
so you can specify the content component's target size.
|
|
*/
|
|
void setContentComponentSize (int width, int height);
|
|
|
|
/** Returns the width of the frame to use around the window.
|
|
@see getContentComponentBorder
|
|
*/
|
|
virtual const BorderSize<int> getBorderThickness();
|
|
|
|
/** Returns the insets to use when positioning the content component.
|
|
@see getBorderThickness
|
|
*/
|
|
virtual const BorderSize<int> getContentComponentBorder();
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the window.
|
|
|
|
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 = 0x1005700, /**< A colour to use to fill the window's background. */
|
|
};
|
|
|
|
/** @deprecated - use setContentOwned() and setContentNonOwned() instead. */
|
|
JUCE_DEPRECATED (void setContentComponent (Component* newContentComponent,
|
|
bool deleteOldOne = true,
|
|
bool resizeToFit = false));
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */
|
|
void moved();
|
|
/** (if overriding this, make sure you call ResizableWindow::resized() in your subclass) */
|
|
void resized();
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent& e);
|
|
/** @internal */
|
|
void lookAndFeelChanged();
|
|
/** @internal */
|
|
void childBoundsChanged (Component* child);
|
|
/** @internal */
|
|
void parentSizeChanged();
|
|
/** @internal */
|
|
void visibilityChanged();
|
|
/** @internal */
|
|
void activeWindowStatusChanged();
|
|
/** @internal */
|
|
int getDesktopWindowStyleFlags() const;
|
|
|
|
#if JUCE_DEBUG
|
|
/** Overridden to warn people about adding components directly to this component
|
|
instead of using setContentOwned().
|
|
|
|
If you know what you're doing and are sure you really want to add a component, specify
|
|
a base-class method call to Component::addAndMakeVisible(), to side-step this warning.
|
|
*/
|
|
void addChildComponent (Component* child, int zOrder = -1);
|
|
/** Overridden to warn people about adding components directly to this component
|
|
instead of using setContentOwned().
|
|
|
|
If you know what you're doing and are sure you really want to add a component, specify
|
|
a base-class method call to Component::addAndMakeVisible(), to side-step this warning.
|
|
*/
|
|
void addAndMakeVisible (Component* child, int zOrder = -1);
|
|
#endif
|
|
|
|
ScopedPointer <ResizableCornerComponent> resizableCorner;
|
|
ScopedPointer <ResizableBorderComponent> resizableBorder;
|
|
|
|
private:
|
|
|
|
Component::SafePointer <Component> contentComponent;
|
|
bool ownsContentComponent, resizeToFitContent, fullscreen;
|
|
ComponentDragger dragger;
|
|
Rectangle<int> lastNonFullScreenPos;
|
|
ComponentBoundsConstrainer defaultConstrainer;
|
|
ComponentBoundsConstrainer* constrainer;
|
|
#if JUCE_DEBUG
|
|
bool hasBeenResized;
|
|
#endif
|
|
|
|
void initialise (bool addToDesktop);
|
|
void updateLastPos();
|
|
void setContent (Component* newComp, bool takeOwnership, bool resizeToFit);
|
|
|
|
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
|
// The parameters for these methods have changed - please update your code!
|
|
JUCE_DEPRECATED (void getBorderThickness (int& left, int& top, int& right, int& bottom));
|
|
JUCE_DEPRECATED (void getContentComponentBorder (int& left, int& top, int& right, int& bottom));
|
|
#endif
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResizableWindow);
|
|
};
|
|
|
|
#endif // __JUCE_RESIZABLEWINDOW_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ResizableWindow.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_GlyphArrangement.h ***/
|
|
#ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__
|
|
#define __JUCE_GLYPHARRANGEMENT_JUCEHEADER__
|
|
|
|
/**
|
|
A glyph from a particular font, with a particular size, style,
|
|
typeface and position.
|
|
|
|
You should rarely need to use this class directly - for most purposes, the
|
|
GlyphArrangement class will do what you need for text layout.
|
|
|
|
@see GlyphArrangement, Font
|
|
*/
|
|
class JUCE_API PositionedGlyph
|
|
{
|
|
public:
|
|
|
|
PositionedGlyph (const Font& font, juce_wchar character, int glyphNumber,
|
|
float anchorX, float baselineY, float width, bool isWhitespace);
|
|
|
|
PositionedGlyph (const PositionedGlyph& other);
|
|
PositionedGlyph& operator= (const PositionedGlyph& other);
|
|
~PositionedGlyph();
|
|
|
|
/** Returns the character the glyph represents. */
|
|
juce_wchar getCharacter() const noexcept { return character; }
|
|
/** Checks whether the glyph is actually empty. */
|
|
bool isWhitespace() const noexcept { return whitespace; }
|
|
|
|
/** Returns the position of the glyph's left-hand edge. */
|
|
float getLeft() const noexcept { return x; }
|
|
/** Returns the position of the glyph's right-hand edge. */
|
|
float getRight() const noexcept { return x + w; }
|
|
/** Returns the y position of the glyph's baseline. */
|
|
float getBaselineY() const noexcept { return y; }
|
|
/** Returns the y position of the top of the glyph. */
|
|
float getTop() const { return y - font.getAscent(); }
|
|
/** Returns the y position of the bottom of the glyph. */
|
|
float getBottom() const { return y + font.getDescent(); }
|
|
/** Returns the bounds of the glyph. */
|
|
Rectangle<float> getBounds() const { return Rectangle<float> (x, getTop(), w, font.getHeight()); }
|
|
|
|
/** Shifts the glyph's position by a relative amount. */
|
|
void moveBy (float deltaX, float deltaY);
|
|
|
|
/** Draws the glyph into a graphics context. */
|
|
void draw (const Graphics& g) const;
|
|
|
|
/** Draws the glyph into a graphics context, with an extra transform applied to it. */
|
|
void draw (const Graphics& g, const AffineTransform& transform) const;
|
|
|
|
/** Returns the path for this glyph.
|
|
|
|
@param path the glyph's outline will be appended to this path
|
|
*/
|
|
void createPath (Path& path) const;
|
|
|
|
/** Checks to see if a point lies within this glyph. */
|
|
bool hitTest (float x, float y) const;
|
|
|
|
private:
|
|
|
|
friend class GlyphArrangement;
|
|
Font font;
|
|
juce_wchar character;
|
|
int glyph;
|
|
float x, y, w;
|
|
bool whitespace;
|
|
|
|
JUCE_LEAK_DETECTOR (PositionedGlyph);
|
|
};
|
|
|
|
/**
|
|
A set of glyphs, each with a position.
|
|
|
|
You can create a GlyphArrangement, text to it and then draw it onto a
|
|
graphics context. It's used internally by the text methods in the
|
|
Graphics class, but can be used directly if more control is needed.
|
|
|
|
@see Font, PositionedGlyph
|
|
*/
|
|
class JUCE_API GlyphArrangement
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty arrangement. */
|
|
GlyphArrangement();
|
|
|
|
/** Takes a copy of another arrangement. */
|
|
GlyphArrangement (const GlyphArrangement& other);
|
|
|
|
/** Copies another arrangement onto this one.
|
|
To add another arrangement without clearing this one, use addGlyphArrangement().
|
|
*/
|
|
GlyphArrangement& operator= (const GlyphArrangement& other);
|
|
|
|
/** Destructor. */
|
|
~GlyphArrangement();
|
|
|
|
/** Returns the total number of glyphs in the arrangement. */
|
|
int getNumGlyphs() const noexcept { return glyphs.size(); }
|
|
|
|
/** Returns one of the glyphs from the arrangement.
|
|
|
|
@param index the glyph's index, from 0 to (getNumGlyphs() - 1). Be
|
|
careful not to pass an out-of-range index here, as it
|
|
doesn't do any bounds-checking.
|
|
*/
|
|
PositionedGlyph& getGlyph (int index) const;
|
|
|
|
/** Clears all text from the arrangement and resets it.
|
|
*/
|
|
void clear();
|
|
|
|
/** Appends a line of text to the arrangement.
|
|
|
|
This will add the text as a single line, where x is the left-hand edge of the
|
|
first character, and y is the position for the text's baseline.
|
|
|
|
If the text contains new-lines or carriage-returns, this will ignore them - use
|
|
addJustifiedText() to add multi-line arrangements.
|
|
*/
|
|
void addLineOfText (const Font& font,
|
|
const String& text,
|
|
float x, float y);
|
|
|
|
/** Adds a line of text, truncating it if it's wider than a specified size.
|
|
|
|
This is the same as addLineOfText(), but if the line's width exceeds the value
|
|
specified in maxWidthPixels, it will be truncated using either ellipsis (i.e. dots: "..."),
|
|
if useEllipsis is true, or if this is false, it will just drop any subsequent characters.
|
|
*/
|
|
void addCurtailedLineOfText (const Font& font,
|
|
const String& text,
|
|
float x, float y,
|
|
float maxWidthPixels,
|
|
bool useEllipsis);
|
|
|
|
/** Adds some multi-line text, breaking lines at word-boundaries if they are too wide.
|
|
|
|
This will add text to the arrangement, breaking it into new lines either where there
|
|
is a new-line or carriage-return character in the text, or where a line's width
|
|
exceeds the value set in maxLineWidth.
|
|
|
|
Each line that is added will be laid out using the flags set in horizontalLayout, so
|
|
the lines can be left- or right-justified, or centred horizontally in the space
|
|
between x and (x + maxLineWidth).
|
|
|
|
The y co-ordinate is the position of the baseline of the first line of text - subsequent
|
|
lines will be placed below it, separated by a distance of font.getHeight().
|
|
*/
|
|
void addJustifiedText (const Font& font,
|
|
const String& text,
|
|
float x, float y,
|
|
float maxLineWidth,
|
|
const Justification& horizontalLayout);
|
|
|
|
/** Tries to fit some text withing 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.
|
|
|
|
@see Graphics::drawFittedText
|
|
*/
|
|
void addFittedText (const Font& font,
|
|
const String& text,
|
|
float x, float y, float width, float height,
|
|
const Justification& layout,
|
|
int maximumLinesToUse,
|
|
float minimumHorizontalScale = 0.7f);
|
|
|
|
/** Appends another glyph arrangement to this one. */
|
|
void addGlyphArrangement (const GlyphArrangement& other);
|
|
|
|
/** Appends a custom glyph to the arrangement. */
|
|
void addGlyph (const PositionedGlyph& glyph);
|
|
|
|
/** Draws this glyph arrangement to a graphics context.
|
|
|
|
This uses cached bitmaps so is much faster than the draw (Graphics&, const AffineTransform&)
|
|
method, which renders the glyphs as filled vectors.
|
|
*/
|
|
void draw (const Graphics& g) const;
|
|
|
|
/** Draws this glyph arrangement to a graphics context.
|
|
|
|
This renders the paths as filled vectors, so is far slower than the draw (Graphics&)
|
|
method for non-transformed arrangements.
|
|
*/
|
|
void draw (const Graphics& g, const AffineTransform& transform) const;
|
|
|
|
/** Converts the set of glyphs into a path.
|
|
|
|
@param path the glyphs' outlines will be appended to this path
|
|
*/
|
|
void createPath (Path& path) const;
|
|
|
|
/** Looks for a glyph that contains the given co-ordinate.
|
|
|
|
@returns the index of the glyph, or -1 if none were found.
|
|
*/
|
|
int findGlyphIndexAt (float x, float y) const;
|
|
|
|
/** Finds the smallest rectangle that will enclose a subset of the glyphs.
|
|
|
|
@param startIndex the first glyph to test
|
|
@param numGlyphs the number of glyphs to include; if this is < 0, all glyphs after
|
|
startIndex will be included
|
|
@param includeWhitespace if true, the extent of any whitespace characters will also
|
|
be taken into account
|
|
*/
|
|
Rectangle<float> getBoundingBox (int startIndex, int numGlyphs, bool includeWhitespace) const;
|
|
|
|
/** Shifts a set of glyphs by a given amount.
|
|
|
|
@param startIndex the first glyph to transform
|
|
@param numGlyphs the number of glyphs to move; if this is < 0, all glyphs after
|
|
startIndex will be used
|
|
@param deltaX the amount to add to their x-positions
|
|
@param deltaY the amount to add to their y-positions
|
|
*/
|
|
void moveRangeOfGlyphs (int startIndex, int numGlyphs,
|
|
float deltaX, float deltaY);
|
|
|
|
/** Removes a set of glyphs from the arrangement.
|
|
|
|
@param startIndex the first glyph to remove
|
|
@param numGlyphs the number of glyphs to remove; if this is < 0, all glyphs after
|
|
startIndex will be deleted
|
|
*/
|
|
void removeRangeOfGlyphs (int startIndex, int numGlyphs);
|
|
|
|
/** Expands or compresses a set of glyphs horizontally.
|
|
|
|
@param startIndex the first glyph to transform
|
|
@param numGlyphs the number of glyphs to stretch; if this is < 0, all glyphs after
|
|
startIndex will be used
|
|
@param horizontalScaleFactor how much to scale their horizontal width by
|
|
*/
|
|
void stretchRangeOfGlyphs (int startIndex, int numGlyphs,
|
|
float horizontalScaleFactor);
|
|
|
|
/** Justifies a set of glyphs within a given space.
|
|
|
|
This moves the glyphs as a block so that the whole thing is located within the
|
|
given rectangle with the specified layout.
|
|
|
|
If the Justification::horizontallyJustified flag is specified, each line will
|
|
be stretched out to fill the specified width.
|
|
*/
|
|
void justifyGlyphs (int startIndex, int numGlyphs,
|
|
float x, float y, float width, float height,
|
|
const Justification& justification);
|
|
|
|
private:
|
|
|
|
OwnedArray <PositionedGlyph> glyphs;
|
|
|
|
int insertEllipsis (const Font&, float maxXPos, int startIndex, int endIndex);
|
|
int fitLineIntoSpace (int start, int numGlyphs, float x, float y, float w, float h, const Font&,
|
|
const Justification&, float minimumHorizontalScale);
|
|
void spreadOutLine (int start, int numGlyphs, float targetWidth);
|
|
|
|
JUCE_LEAK_DETECTOR (GlyphArrangement);
|
|
};
|
|
|
|
#endif // __JUCE_GLYPHARRANGEMENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_GlyphArrangement.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_AlertWindow.h ***/
|
|
#ifndef __JUCE_ALERTWINDOW_JUCEHEADER__
|
|
#define __JUCE_ALERTWINDOW_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_TextLayout.h ***/
|
|
#ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__
|
|
#define __JUCE_TEXTLAYOUT_JUCEHEADER__
|
|
|
|
class Graphics;
|
|
|
|
/**
|
|
A laid-out arrangement of text.
|
|
|
|
You can add text in different fonts to a TextLayout object, then call its
|
|
layout() method to word-wrap it into lines. The layout can then be drawn
|
|
using a graphics context.
|
|
|
|
It's handy if you've got a message to display, because you can format it,
|
|
measure the extent of the layout, and then create a suitably-sized window
|
|
to show it in.
|
|
|
|
@see Font, Graphics::drawFittedText, GlyphArrangement
|
|
*/
|
|
class JUCE_API TextLayout
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty text layout.
|
|
|
|
Text can then be appended using the appendText() method.
|
|
*/
|
|
TextLayout();
|
|
|
|
/** Creates a copy of another layout object. */
|
|
TextLayout (const TextLayout& other);
|
|
|
|
/** Creates a text layout from an initial string and font. */
|
|
TextLayout (const String& text, const Font& font);
|
|
|
|
/** Destructor. */
|
|
~TextLayout();
|
|
|
|
/** Copies another layout onto this one. */
|
|
TextLayout& operator= (const TextLayout& layoutToCopy);
|
|
|
|
/** Clears the layout, removing all its text. */
|
|
void clear();
|
|
|
|
/** Adds a string to the end of the arrangement.
|
|
|
|
The string will be broken onto new lines wherever it contains
|
|
carriage-returns or linefeeds. After adding it, you can call layout()
|
|
to wrap long lines into a paragraph and justify it.
|
|
*/
|
|
void appendText (const String& textToAppend,
|
|
const Font& fontToUse);
|
|
|
|
/** Replaces all the text with a new string.
|
|
|
|
This is equivalent to calling clear() followed by appendText().
|
|
*/
|
|
void setText (const String& newText,
|
|
const Font& fontToUse);
|
|
|
|
/** Returns true if the layout has not had any text added yet. */
|
|
bool isEmpty() const;
|
|
|
|
/** Breaks the text up to form a paragraph with the given width.
|
|
|
|
@param maximumWidth any text wider than this will be split
|
|
across multiple lines
|
|
@param justification how the lines are to be laid-out horizontally
|
|
@param attemptToBalanceLineLengths if true, it will try to split the lines at a
|
|
width that keeps all the lines of text at a
|
|
similar length - this is good when you're displaying
|
|
a short message and don't want it to get split
|
|
onto two lines with only a couple of words on
|
|
the second line, which looks untidy.
|
|
*/
|
|
void layout (int maximumWidth,
|
|
const Justification& justification,
|
|
bool attemptToBalanceLineLengths);
|
|
|
|
/** Returns the overall width of the entire text layout. */
|
|
int getWidth() const;
|
|
|
|
/** Returns the overall height of the entire text layout. */
|
|
int getHeight() const;
|
|
|
|
/** Returns the total number of lines of text. */
|
|
int getNumLines() const { return totalLines; }
|
|
|
|
/** Returns the width of a particular line of text.
|
|
|
|
@param lineNumber the line, from 0 to (getNumLines() - 1)
|
|
*/
|
|
int getLineWidth (int lineNumber) const;
|
|
|
|
/** Renders the text at a specified position using a graphics context.
|
|
*/
|
|
void draw (Graphics& g, int topLeftX, int topLeftY) const;
|
|
|
|
/** Renders the text within a specified rectangle using a graphics context.
|
|
|
|
The justification flags dictate how the block of text should be positioned
|
|
within the rectangle.
|
|
*/
|
|
void drawWithin (Graphics& g,
|
|
int x, int y, int w, int h,
|
|
const Justification& layoutFlags) const;
|
|
|
|
private:
|
|
|
|
class Token;
|
|
friend class OwnedArray <Token>;
|
|
OwnedArray <Token> tokens;
|
|
int totalLines;
|
|
|
|
JUCE_LEAK_DETECTOR (TextLayout);
|
|
};
|
|
|
|
#endif // __JUCE_TEXTLAYOUT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TextLayout.h ***/
|
|
|
|
/** A window that displays a message and has buttons for the user to react to it.
|
|
|
|
For simple dialog boxes with just a couple of buttons on them, there are
|
|
some static methods for running these.
|
|
|
|
For more complex dialogs, an AlertWindow can be created, then it can have some
|
|
buttons and components added to it, and its runModalLoop() method is then used to
|
|
show it. The value returned by runModalLoop() shows which button the
|
|
user pressed to dismiss the box.
|
|
|
|
@see ThreadWithProgressWindow
|
|
*/
|
|
class JUCE_API AlertWindow : public TopLevelWindow,
|
|
private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
{
|
|
public:
|
|
|
|
/** The type of icon to show in the dialog box. */
|
|
enum AlertIconType
|
|
{
|
|
NoIcon, /**< No icon will be shown on the dialog box. */
|
|
QuestionIcon, /**< A question-mark icon, for dialog boxes that need the
|
|
user to answer a question. */
|
|
WarningIcon, /**< An exclamation mark to indicate that the dialog is a
|
|
warning about something and shouldn't be ignored. */
|
|
InfoIcon /**< An icon that indicates that the dialog box is just
|
|
giving the user some information, which doesn't require
|
|
a response from them. */
|
|
};
|
|
|
|
/** Creates an AlertWindow.
|
|
|
|
@param title the headline to show at the top of the dialog box
|
|
@param message a longer, more descriptive message to show underneath the
|
|
headline
|
|
@param iconType the type of icon to display
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
*/
|
|
AlertWindow (const String& title,
|
|
const String& message,
|
|
AlertIconType iconType,
|
|
Component* associatedComponent = nullptr);
|
|
|
|
/** Destroys the AlertWindow */
|
|
~AlertWindow();
|
|
|
|
/** Returns the type of alert icon that was specified when the window
|
|
was created. */
|
|
AlertIconType getAlertType() const noexcept { return alertIconType; }
|
|
|
|
/** Changes the dialog box's message.
|
|
|
|
This will also resize the window to fit the new message if required.
|
|
*/
|
|
void setMessage (const String& message);
|
|
|
|
/** Adds a button to the window.
|
|
|
|
@param name the text to show on the button
|
|
@param returnValue the value that should be returned from runModalLoop()
|
|
if this is the button that the user presses.
|
|
@param shortcutKey1 an optional key that can be pressed to trigger this button
|
|
@param shortcutKey2 a second optional key that can be pressed to trigger this button
|
|
*/
|
|
void addButton (const String& name,
|
|
int returnValue,
|
|
const KeyPress& shortcutKey1 = KeyPress(),
|
|
const KeyPress& shortcutKey2 = KeyPress());
|
|
|
|
/** Returns the number of buttons that the window currently has. */
|
|
int getNumButtons() const;
|
|
|
|
/** Invokes a click of one of the buttons. */
|
|
void triggerButtonClick (const String& buttonName);
|
|
|
|
/** If set to true and the window contains no buttons, then pressing the escape key will make
|
|
the alert cancel its modal state.
|
|
By default this setting is true - turn it off if you don't want the box to respond to
|
|
the escape key. Note that it is ignored if you have any buttons, and in that case you
|
|
should give the buttons appropriate keypresses to trigger cancelling if you want to.
|
|
*/
|
|
void setEscapeKeyCancels (bool shouldEscapeKeyCancel);
|
|
|
|
/** Adds a textbox to the window for entering strings.
|
|
|
|
@param name an internal name for the text-box. This is the name to pass to
|
|
the getTextEditorContents() method to find out what the
|
|
user typed-in.
|
|
@param initialContents a string to show in the text box when it's first shown
|
|
@param onScreenLabel if this is non-empty, it will be displayed next to the
|
|
text-box to label it.
|
|
@param isPasswordBox if true, the text editor will display asterisks instead of
|
|
the actual text
|
|
@see getTextEditorContents
|
|
*/
|
|
void addTextEditor (const String& name,
|
|
const String& initialContents,
|
|
const String& onScreenLabel = String::empty,
|
|
bool isPasswordBox = false);
|
|
|
|
/** Returns the contents of a named textbox.
|
|
|
|
After showing an AlertWindow that contains a text editor, this can be
|
|
used to find out what the user has typed into it.
|
|
|
|
@param nameOfTextEditor the name of the text box that you're interested in
|
|
@see addTextEditor
|
|
*/
|
|
String getTextEditorContents (const String& nameOfTextEditor) const;
|
|
|
|
/** Returns a pointer to a textbox that was added with addTextEditor(). */
|
|
TextEditor* getTextEditor (const String& nameOfTextEditor) const;
|
|
|
|
/** Adds a drop-down list of choices to the box.
|
|
|
|
After the box has been shown, the getComboBoxComponent() method can
|
|
be used to find out which item the user picked.
|
|
|
|
@param name the label to use for the drop-down list
|
|
@param items the list of items to show in it
|
|
@param onScreenLabel if this is non-empty, it will be displayed next to the
|
|
combo-box to label it.
|
|
@see getComboBoxComponent
|
|
*/
|
|
void addComboBox (const String& name,
|
|
const StringArray& items,
|
|
const String& onScreenLabel = String::empty);
|
|
|
|
/** Returns a drop-down list that was added to the AlertWindow.
|
|
|
|
@param nameOfList the name that was passed into the addComboBox() method
|
|
when creating the drop-down
|
|
@returns the ComboBox component, or 0 if none was found for the given name.
|
|
*/
|
|
ComboBox* getComboBoxComponent (const String& nameOfList) const;
|
|
|
|
/** Adds a block of text.
|
|
|
|
This is handy for adding a multi-line note next to a textbox or combo-box,
|
|
to provide more details about what's going on.
|
|
*/
|
|
void addTextBlock (const String& text);
|
|
|
|
/** Adds a progress-bar to the window.
|
|
|
|
@param progressValue a variable that will be repeatedly checked while the
|
|
dialog box is visible, to see how far the process has
|
|
got. The value should be in the range 0 to 1.0
|
|
*/
|
|
void addProgressBarComponent (double& progressValue);
|
|
|
|
/** Adds a user-defined component to the dialog box.
|
|
|
|
@param component the component to add - its size should be set up correctly
|
|
before it is passed in. The caller is responsible for deleting
|
|
the component later on - the AlertWindow won't delete it.
|
|
*/
|
|
void addCustomComponent (Component* component);
|
|
|
|
/** Returns the number of custom components in the dialog box.
|
|
|
|
@see getCustomComponent, addCustomComponent
|
|
*/
|
|
int getNumCustomComponents() const;
|
|
|
|
/** Returns one of the custom components in the dialog box.
|
|
|
|
@param index a value 0 to (getNumCustomComponents() - 1). Out-of-range indexes
|
|
will return 0
|
|
@see getNumCustomComponents, addCustomComponent
|
|
*/
|
|
Component* getCustomComponent (int index) const;
|
|
|
|
/** Removes one of the custom components in the dialog box.
|
|
|
|
Note that this won't delete it, it just removes the component from the window
|
|
|
|
@param index a value 0 to (getNumCustomComponents() - 1). Out-of-range indexes
|
|
will return 0
|
|
@returns the component that was removed (or null)
|
|
@see getNumCustomComponents, addCustomComponent
|
|
*/
|
|
Component* removeCustomComponent (int index);
|
|
|
|
/** Returns true if the window contains any components other than just buttons.*/
|
|
bool containsAnyExtraComponents() const;
|
|
|
|
// easy-to-use message box functions:
|
|
|
|
/** Shows a dialog box that just has a message and a single button to get rid of it.
|
|
|
|
If the callback parameter is null, the box is shown modally, and the method will
|
|
block until the user has clicked the button (or pressed the escape or return keys).
|
|
If the callback parameter is non-null, the box will be displayed and placed into a
|
|
modal state, but this method will return immediately, and the callback will be invoked
|
|
later when the user dismisses the box.
|
|
|
|
@param iconType the type of icon to show
|
|
@param title the headline to show at the top of the box
|
|
@param message a longer, more descriptive message to show underneath the
|
|
headline
|
|
@param buttonText the text to show in the button - if this string is empty, the
|
|
default string "ok" (or a localised version) will be used.
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
*/
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
static void JUCE_CALLTYPE showMessageBox (AlertIconType iconType,
|
|
const String& title,
|
|
const String& message,
|
|
const String& buttonText = String::empty,
|
|
Component* associatedComponent = nullptr);
|
|
#endif
|
|
|
|
/** Shows a dialog box that just has a message and a single button to get rid of it.
|
|
|
|
If the callback parameter is null, the box is shown modally, and the method will
|
|
block until the user has clicked the button (or pressed the escape or return keys).
|
|
If the callback parameter is non-null, the box will be displayed and placed into a
|
|
modal state, but this method will return immediately, and the callback will be invoked
|
|
later when the user dismisses the box.
|
|
|
|
@param iconType the type of icon to show
|
|
@param title the headline to show at the top of the box
|
|
@param message a longer, more descriptive message to show underneath the
|
|
headline
|
|
@param buttonText the text to show in the button - if this string is empty, the
|
|
default string "ok" (or a localised version) will be used.
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
*/
|
|
static void JUCE_CALLTYPE showMessageBoxAsync (AlertIconType iconType,
|
|
const String& title,
|
|
const String& message,
|
|
const String& buttonText = String::empty,
|
|
Component* associatedComponent = nullptr);
|
|
|
|
/** Shows a dialog box with two buttons.
|
|
|
|
Ideal for ok/cancel or yes/no choices. The return key can also be used
|
|
to trigger the first button, and the escape key for the second button.
|
|
|
|
If the callback parameter is null, the box is shown modally, and the method will
|
|
block until the user has clicked the button (or pressed the escape or return keys).
|
|
If the callback parameter is non-null, the box will be displayed and placed into a
|
|
modal state, but this method will return immediately, and the callback will be invoked
|
|
later when the user dismisses the box.
|
|
|
|
@param iconType the type of icon to show
|
|
@param title the headline to show at the top of the box
|
|
@param message a longer, more descriptive message to show underneath the
|
|
headline
|
|
@param button1Text the text to show in the first button - if this string is
|
|
empty, the default string "ok" (or a localised version of it)
|
|
will be used.
|
|
@param button2Text the text to show in the second button - if this string is
|
|
empty, the default string "cancel" (or a localised version of it)
|
|
will be used.
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
@param callback if this is non-null, the menu will be launched asynchronously,
|
|
returning immediately, and the callback will receive a call to its
|
|
modalStateFinished() when the box is dismissed, with its parameter
|
|
being 1 if the ok button was pressed, or 0 for cancel, The callback object
|
|
will be owned and deleted by the system, so make sure that it works
|
|
safely and doesn't keep any references to objects that might be deleted
|
|
before it gets called.
|
|
@returns true if button 1 was clicked, false if it was button 2. If the callback parameter
|
|
is not null, the method always returns false, and the user's choice is delivered
|
|
later by the callback.
|
|
*/
|
|
static bool JUCE_CALLTYPE showOkCancelBox (AlertIconType iconType,
|
|
const String& title,
|
|
const String& message,
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
const String& button1Text = String::empty,
|
|
const String& button2Text = String::empty,
|
|
Component* associatedComponent = nullptr,
|
|
ModalComponentManager::Callback* callback = nullptr);
|
|
#else
|
|
const String& button1Text,
|
|
const String& button2Text,
|
|
Component* associatedComponent,
|
|
ModalComponentManager::Callback* callback);
|
|
#endif
|
|
|
|
/** Shows a dialog box with three buttons.
|
|
|
|
Ideal for yes/no/cancel boxes.
|
|
|
|
The escape key can be used to trigger the third button.
|
|
|
|
If the callback parameter is null, the box is shown modally, and the method will
|
|
block until the user has clicked the button (or pressed the escape or return keys).
|
|
If the callback parameter is non-null, the box will be displayed and placed into a
|
|
modal state, but this method will return immediately, and the callback will be invoked
|
|
later when the user dismisses the box.
|
|
|
|
@param iconType the type of icon to show
|
|
@param title the headline to show at the top of the box
|
|
@param message a longer, more descriptive message to show underneath the
|
|
headline
|
|
@param button1Text the text to show in the first button - if an empty string, then
|
|
"yes" will be used (or a localised version of it)
|
|
@param button2Text the text to show in the first button - if an empty string, then
|
|
"no" will be used (or a localised version of it)
|
|
@param button3Text the text to show in the first button - if an empty string, then
|
|
"cancel" will be used (or a localised version of it)
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
@param callback if this is non-null, the menu will be launched asynchronously,
|
|
returning immediately, and the callback will receive a call to its
|
|
modalStateFinished() when the box is dismissed, with its parameter
|
|
being 1 if the "yes" button was pressed, 2 for the "no" button, or 0
|
|
if it was cancelled, The callback object will be owned and deleted by the
|
|
system, so make sure that it works safely and doesn't keep any references
|
|
to objects that might be deleted before it gets called.
|
|
|
|
@returns If the callback parameter has been set, this returns 0. Otherwise, it
|
|
returns one of the following values:
|
|
- 0 if the third button was pressed (normally used for 'cancel')
|
|
- 1 if the first button was pressed (normally used for 'yes')
|
|
- 2 if the middle button was pressed (normally used for 'no')
|
|
*/
|
|
static int JUCE_CALLTYPE showYesNoCancelBox (AlertIconType iconType,
|
|
const String& title,
|
|
const String& message,
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
const String& button1Text = String::empty,
|
|
const String& button2Text = String::empty,
|
|
const String& button3Text = String::empty,
|
|
Component* associatedComponent = nullptr,
|
|
ModalComponentManager::Callback* callback = nullptr);
|
|
#else
|
|
const String& button1Text,
|
|
const String& button2Text,
|
|
const String& button3Text,
|
|
Component* associatedComponent,
|
|
ModalComponentManager::Callback* callback);
|
|
#endif
|
|
|
|
/** Shows an operating-system native dialog box.
|
|
|
|
@param title the title to use at the top
|
|
@param bodyText the longer message to show
|
|
@param isOkCancel if true, this will show an ok/cancel box, if false,
|
|
it'll show a box with just an ok button
|
|
@returns true if the ok button was pressed, false if they pressed cancel.
|
|
*/
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
static bool JUCE_CALLTYPE showNativeDialogBox (const String& title,
|
|
const String& bodyText,
|
|
bool isOkCancel);
|
|
#endif
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the alert box.
|
|
|
|
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 = 0x1001800, /**< The background colour for the window. */
|
|
textColourId = 0x1001810, /**< The colour for the text. */
|
|
outlineColourId = 0x1001820 /**< An optional colour to use to draw a border around the window. */
|
|
};
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent& e);
|
|
/** @internal */
|
|
bool keyPressed (const KeyPress& key);
|
|
/** @internal */
|
|
void buttonClicked (Button* button);
|
|
/** @internal */
|
|
void lookAndFeelChanged();
|
|
/** @internal */
|
|
void userTriedToCloseWindow();
|
|
/** @internal */
|
|
int getDesktopWindowStyleFlags() const;
|
|
|
|
private:
|
|
|
|
String text;
|
|
TextLayout textLayout;
|
|
AlertIconType alertIconType;
|
|
ComponentBoundsConstrainer constrainer;
|
|
ComponentDragger dragger;
|
|
Rectangle<int> textArea;
|
|
OwnedArray<TextButton> buttons;
|
|
OwnedArray<TextEditor> textBoxes;
|
|
OwnedArray<ComboBox> comboBoxes;
|
|
OwnedArray<ProgressBar> progressBars;
|
|
Array<Component*> customComps;
|
|
OwnedArray<Component> textBlocks;
|
|
Array<Component*> allComps;
|
|
StringArray textboxNames, comboBoxNames;
|
|
Font font;
|
|
Component* associatedComponent;
|
|
bool escapeKeyCancels;
|
|
|
|
void updateLayout (bool onlyIncreaseSize);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AlertWindow);
|
|
};
|
|
|
|
#endif // __JUCE_ALERTWINDOW_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AlertWindow.h ***/
|
|
|
|
/**
|
|
A file open/save dialog box.
|
|
|
|
This is a Juce-based file dialog box; to use a native file chooser, see the
|
|
FileChooser class.
|
|
|
|
To use one of these, create it and call its show() method. e.g.
|
|
|
|
@code
|
|
{
|
|
WildcardFileFilter wildcardFilter ("*.foo", String::empty, "Foo files");
|
|
|
|
FileBrowserComponent browser (FileBrowserComponent::canSelectFiles,
|
|
File::nonexistent,
|
|
&wildcardFilter,
|
|
nullptr);
|
|
|
|
FileChooserDialogBox dialogBox ("Open some kind of file",
|
|
"Please choose some kind of file that you want to open...",
|
|
browser,
|
|
false,
|
|
Colours::lightgrey);
|
|
|
|
if (dialogBox.show())
|
|
{
|
|
File selectedFile = browser.getSelectedFile (0);
|
|
|
|
...etc..
|
|
}
|
|
}
|
|
@endcode
|
|
|
|
@see FileChooser
|
|
*/
|
|
class JUCE_API FileChooserDialogBox : public ResizableWindow,
|
|
public ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
public FileBrowserListener
|
|
{
|
|
public:
|
|
|
|
/** Creates a file chooser box.
|
|
|
|
@param title the main title to show at the top of the box
|
|
@param instructions an optional longer piece of text to show below the title in
|
|
a smaller font, describing in more detail what's required.
|
|
@param browserComponent a FileBrowserComponent that will be shown inside this dialog
|
|
box. Make sure you delete this after (but not before!) the
|
|
dialog box has been deleted.
|
|
@param warnAboutOverwritingExistingFiles if true, then the user will be asked to confirm
|
|
if they try to select a file that already exists. (This
|
|
flag is only used when saving files)
|
|
@param backgroundColour the background colour for the top level window
|
|
|
|
@see FileBrowserComponent, FilePreviewComponent
|
|
*/
|
|
FileChooserDialogBox (const String& title,
|
|
const String& instructions,
|
|
FileBrowserComponent& browserComponent,
|
|
bool warnAboutOverwritingExistingFiles,
|
|
const Colour& backgroundColour);
|
|
|
|
/** Destructor. */
|
|
~FileChooserDialogBox();
|
|
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
/** Displays and runs the dialog box modally.
|
|
|
|
This will show the box with the specified size, returning true if the user
|
|
pressed 'ok', or false if they cancelled.
|
|
|
|
Leave the width or height as 0 to use the default size
|
|
*/
|
|
bool show (int width = 0, int height = 0);
|
|
|
|
/** Displays and runs the dialog box modally.
|
|
|
|
This will show the box with the specified size at the specified location,
|
|
returning true if the user pressed 'ok', or false if they cancelled.
|
|
|
|
Leave the width or height as 0 to use the default size.
|
|
*/
|
|
bool showAt (int x, int y, int width, int height);
|
|
#endif
|
|
|
|
/** Sets the size of this dialog box to its default and positions it either in the
|
|
centre of the screen, or centred around a component that is provided.
|
|
*/
|
|
void centreWithDefaultSize (Component* componentToCentreAround = 0);
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the box.
|
|
|
|
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
|
|
{
|
|
titleTextColourId = 0x1000850, /**< The colour to use to draw the box's title. */
|
|
};
|
|
|
|
/** @internal */
|
|
void buttonClicked (Button* button);
|
|
/** @internal */
|
|
void closeButtonPressed();
|
|
/** @internal */
|
|
void selectionChanged();
|
|
/** @internal */
|
|
void fileClicked (const File& file, const MouseEvent& e);
|
|
/** @internal */
|
|
void fileDoubleClicked (const File& file);
|
|
|
|
private:
|
|
class ContentComponent;
|
|
ContentComponent* content;
|
|
const bool warnAboutOverwritingExistingFiles;
|
|
|
|
void okButtonPressed();
|
|
void createNewFolder();
|
|
void createNewFolderConfirmed (const String& name);
|
|
|
|
static void okToOverwriteFileCallback (int result, FileChooserDialogBox*);
|
|
static void createNewFolderCallback (int result, FileChooserDialogBox*, Component::SafePointer<AlertWindow>);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileChooserDialogBox);
|
|
};
|
|
|
|
#endif // __JUCE_FILECHOOSERDIALOGBOX_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileChooserDialogBox.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILEFILTER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FileListComponent.h ***/
|
|
#ifndef __JUCE_FILELISTCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_FILELISTCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component that displays the files in a directory as a listbox.
|
|
|
|
This implements the DirectoryContentsDisplayComponent base class so that
|
|
it can be used in a FileBrowserComponent.
|
|
|
|
To attach a listener to it, use its DirectoryContentsDisplayComponent base
|
|
class and the FileBrowserListener class.
|
|
|
|
@see DirectoryContentsList, FileTreeComponent
|
|
*/
|
|
class JUCE_API FileListComponent : public ListBox,
|
|
public DirectoryContentsDisplayComponent,
|
|
private ListBoxModel,
|
|
private ChangeListener
|
|
{
|
|
public:
|
|
|
|
/** Creates a listbox to show the contents of a specified directory.
|
|
*/
|
|
FileListComponent (DirectoryContentsList& listToShow);
|
|
|
|
/** Destructor. */
|
|
~FileListComponent();
|
|
|
|
/** Returns the number of files the user has got selected.
|
|
@see getSelectedFile
|
|
*/
|
|
int getNumSelectedFiles() const;
|
|
|
|
/** Returns one of the files that the user has currently selected.
|
|
The index should be in the range 0 to (getNumSelectedFiles() - 1).
|
|
@see getNumSelectedFiles
|
|
*/
|
|
const File getSelectedFile (int index = 0) const;
|
|
|
|
/** Deselects any files that are currently selected. */
|
|
void deselectAllFiles();
|
|
|
|
/** Scrolls to the top of the list. */
|
|
void scrollToTop();
|
|
|
|
/** @internal */
|
|
void changeListenerCallback (ChangeBroadcaster*);
|
|
/** @internal */
|
|
int getNumRows();
|
|
/** @internal */
|
|
void paintListBoxItem (int, Graphics&, int, int, bool);
|
|
/** @internal */
|
|
Component* refreshComponentForRow (int rowNumber, bool isRowSelected, Component* existingComponentToUpdate);
|
|
/** @internal */
|
|
void selectedRowsChanged (int lastRowSelected);
|
|
/** @internal */
|
|
void deleteKeyPressed (int currentSelectedRow);
|
|
/** @internal */
|
|
void returnKeyPressed (int currentSelectedRow);
|
|
|
|
private:
|
|
|
|
File lastDirectory;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileListComponent);
|
|
};
|
|
|
|
#endif // __JUCE_FILELISTCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileListComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FilenameComponent.h ***/
|
|
#ifndef __JUCE_FILENAMECOMPONENT_JUCEHEADER__
|
|
#define __JUCE_FILENAMECOMPONENT_JUCEHEADER__
|
|
|
|
class FilenameComponent;
|
|
|
|
/**
|
|
Listens for events happening to a FilenameComponent.
|
|
|
|
Use FilenameComponent::addListener() and FilenameComponent::removeListener() to
|
|
register one of these objects for event callbacks when the filename is changed.
|
|
|
|
@see FilenameComponent
|
|
*/
|
|
class JUCE_API FilenameComponentListener
|
|
{
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~FilenameComponentListener() {}
|
|
|
|
/** This method is called after the FilenameComponent's file has been changed. */
|
|
virtual void filenameComponentChanged (FilenameComponent* fileComponentThatHasChanged) = 0;
|
|
};
|
|
|
|
/**
|
|
Shows a filename as an editable text box, with a 'browse' button and a
|
|
drop-down list for recently selected files.
|
|
|
|
A handy component for dialogue boxes where you want the user to be able to
|
|
select a file or directory.
|
|
|
|
Attach an FilenameComponentListener using the addListener() method, and it will
|
|
get called each time the user changes the filename, either by browsing for a file
|
|
and clicking 'ok', or by typing a new filename into the box and pressing return.
|
|
|
|
@see FileChooser, ComboBox
|
|
*/
|
|
class JUCE_API FilenameComponent : public Component,
|
|
public SettableTooltipClient,
|
|
public FileDragAndDropTarget,
|
|
private AsyncUpdater,
|
|
private ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
private ComboBoxListener
|
|
{
|
|
public:
|
|
|
|
/** Creates a FilenameComponent.
|
|
|
|
@param name the name for this component.
|
|
@param currentFile the file to initially show in the box
|
|
@param canEditFilename if true, the user can manually edit the filename; if false,
|
|
they can only change it by browsing for a new file
|
|
@param isDirectory if true, the file will be treated as a directory, and
|
|
an appropriate directory browser used
|
|
@param isForSaving if true, the file browser will allow non-existent files to
|
|
be picked, as the file is assumed to be used for saving rather
|
|
than loading
|
|
@param fileBrowserWildcard a wildcard pattern to use in the file browser - e.g. "*.txt;*.foo".
|
|
If an empty string is passed in, then the pattern is assumed to be "*"
|
|
@param enforcedSuffix if this is non-empty, it is treated as a suffix that will be added
|
|
to any filenames that are entered or chosen
|
|
@param textWhenNothingSelected the message to display in the box before any filename is entered. (This
|
|
will only appear if the initial file isn't valid)
|
|
*/
|
|
FilenameComponent (const String& name,
|
|
const File& currentFile,
|
|
bool canEditFilename,
|
|
bool isDirectory,
|
|
bool isForSaving,
|
|
const String& fileBrowserWildcard,
|
|
const String& enforcedSuffix,
|
|
const String& textWhenNothingSelected);
|
|
|
|
/** Destructor. */
|
|
~FilenameComponent();
|
|
|
|
/** Returns the currently displayed filename. */
|
|
File getCurrentFile() const;
|
|
|
|
/** Changes the current filename.
|
|
|
|
If addToRecentlyUsedList is true, the filename will also be added to the
|
|
drop-down list of recent files.
|
|
|
|
If sendChangeNotification is false, then the listeners won't be told of the
|
|
change.
|
|
*/
|
|
void setCurrentFile (File newFile,
|
|
bool addToRecentlyUsedList,
|
|
bool sendChangeNotification = true);
|
|
|
|
/** Changes whether the use can type into the filename box.
|
|
*/
|
|
void setFilenameIsEditable (bool shouldBeEditable);
|
|
|
|
/** Sets a file or directory to be the default starting point for the browser to show.
|
|
|
|
This is only used if the current file hasn't been set.
|
|
*/
|
|
void setDefaultBrowseTarget (const File& newDefaultDirectory);
|
|
|
|
/** Returns all the entries on the recent files list.
|
|
|
|
This can be used in conjunction with setRecentlyUsedFilenames() for saving the
|
|
state of this list.
|
|
|
|
@see setRecentlyUsedFilenames
|
|
*/
|
|
StringArray getRecentlyUsedFilenames() const;
|
|
|
|
/** Sets all the entries on the recent files list.
|
|
|
|
This can be used in conjunction with getRecentlyUsedFilenames() for saving the
|
|
state of this list.
|
|
|
|
@see getRecentlyUsedFilenames, addRecentlyUsedFile
|
|
*/
|
|
void setRecentlyUsedFilenames (const StringArray& filenames);
|
|
|
|
/** Adds an entry to the recently-used files dropdown list.
|
|
|
|
If the file is already in the list, it will be moved to the top. A limit
|
|
is also placed on the number of items that are kept in the list.
|
|
|
|
@see getRecentlyUsedFilenames, setRecentlyUsedFilenames, setMaxNumberOfRecentFiles
|
|
*/
|
|
void addRecentlyUsedFile (const File& file);
|
|
|
|
/** Changes the limit for the number of files that will be stored in the recent-file list.
|
|
*/
|
|
void setMaxNumberOfRecentFiles (int newMaximum);
|
|
|
|
/** Changes the text shown on the 'browse' button.
|
|
|
|
By default this button just says "..." but you can change it. The button itself
|
|
can be changed using the look-and-feel classes, so it might not actually have any
|
|
text on it.
|
|
*/
|
|
void setBrowseButtonText (const String& browseButtonText);
|
|
|
|
/** Adds a listener that will be called when the selected file is changed. */
|
|
void addListener (FilenameComponentListener* listener);
|
|
|
|
/** Removes a previously-registered listener. */
|
|
void removeListener (FilenameComponentListener* listener);
|
|
|
|
/** Gives the component a tooltip. */
|
|
void setTooltip (const String& newTooltip);
|
|
|
|
/** @internal */
|
|
void paintOverChildren (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void lookAndFeelChanged();
|
|
/** @internal */
|
|
bool isInterestedInFileDrag (const StringArray& files);
|
|
/** @internal */
|
|
void filesDropped (const StringArray& files, int, int);
|
|
/** @internal */
|
|
void fileDragEnter (const StringArray& files, int, int);
|
|
/** @internal */
|
|
void fileDragExit (const StringArray& files);
|
|
|
|
private:
|
|
|
|
ComboBox filenameBox;
|
|
String lastFilename;
|
|
ScopedPointer<Button> browseButton;
|
|
int maxRecentFiles;
|
|
bool isDir, isSaving, isFileDragOver;
|
|
String wildcard, enforcedSuffix, browseButtonText;
|
|
ListenerList <FilenameComponentListener> listeners;
|
|
File defaultBrowseFile;
|
|
|
|
void comboBoxChanged (ComboBox*);
|
|
void buttonClicked (Button* button);
|
|
void handleAsyncUpdate();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FilenameComponent);
|
|
};
|
|
|
|
#endif // __JUCE_FILENAMECOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FilenameComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILEPREVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FileSearchPathListComponent.h ***/
|
|
#ifndef __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
Shows a set of file paths in a list, allowing them to be added, removed or
|
|
re-ordered.
|
|
|
|
@see FileSearchPath
|
|
*/
|
|
class JUCE_API FileSearchPathListComponent : public Component,
|
|
public SettableTooltipClient,
|
|
public FileDragAndDropTarget,
|
|
private ButtonListener, // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
private ListBoxModel
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty FileSearchPathListComponent. */
|
|
FileSearchPathListComponent();
|
|
|
|
/** Destructor. */
|
|
~FileSearchPathListComponent();
|
|
|
|
/** Returns the path as it is currently shown. */
|
|
const FileSearchPath& getPath() const noexcept { return path; }
|
|
|
|
/** Changes the current path. */
|
|
void setPath (const FileSearchPath& newPath);
|
|
|
|
/** Sets a file or directory to be the default starting point for the browser to show.
|
|
|
|
This is only used if the current file hasn't been set.
|
|
*/
|
|
void setDefaultBrowseTarget (const File& newDefaultDirectory);
|
|
|
|
/** 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.
|
|
|
|
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
|
*/
|
|
enum ColourIds
|
|
{
|
|
backgroundColourId = 0x1004100, /**< The background colour to fill the component with.
|
|
Make this transparent if you don't want the background to be filled. */
|
|
};
|
|
|
|
/** @internal */
|
|
int getNumRows();
|
|
/** @internal */
|
|
void paintListBoxItem (int rowNumber, Graphics& g, int width, int height, bool rowIsSelected);
|
|
/** @internal */
|
|
void deleteKeyPressed (int lastRowSelected);
|
|
/** @internal */
|
|
void returnKeyPressed (int lastRowSelected);
|
|
/** @internal */
|
|
void listBoxItemDoubleClicked (int row, const MouseEvent&);
|
|
/** @internal */
|
|
void selectedRowsChanged (int lastRowSelected);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
bool isInterestedInFileDrag (const StringArray& files);
|
|
/** @internal */
|
|
void filesDropped (const StringArray& files, int, int);
|
|
/** @internal */
|
|
void buttonClicked (Button* button);
|
|
|
|
private:
|
|
|
|
FileSearchPath path;
|
|
File defaultBrowseTarget;
|
|
|
|
ListBox listBox;
|
|
TextButton addButton, removeButton, changeButton;
|
|
DrawableButton upButton, downButton;
|
|
|
|
void changed();
|
|
void updateButtons();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileSearchPathListComponent);
|
|
};
|
|
|
|
#endif // __JUCE_FILESEARCHPATHLISTCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileSearchPathListComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FileTreeComponent.h ***/
|
|
#ifndef __JUCE_FILETREECOMPONENT_JUCEHEADER__
|
|
#define __JUCE_FILETREECOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component that displays the files in a directory as a treeview.
|
|
|
|
This implements the DirectoryContentsDisplayComponent base class so that
|
|
it can be used in a FileBrowserComponent.
|
|
|
|
To attach a listener to it, use its DirectoryContentsDisplayComponent base
|
|
class and the FileBrowserListener class.
|
|
|
|
@see DirectoryContentsList, FileListComponent
|
|
*/
|
|
class JUCE_API FileTreeComponent : public TreeView,
|
|
public DirectoryContentsDisplayComponent
|
|
{
|
|
public:
|
|
|
|
/** Creates a listbox to show the contents of a specified directory.
|
|
*/
|
|
FileTreeComponent (DirectoryContentsList& listToShow);
|
|
|
|
/** Destructor. */
|
|
~FileTreeComponent();
|
|
|
|
/** Returns the number of files the user has got selected.
|
|
@see getSelectedFile
|
|
*/
|
|
int getNumSelectedFiles() const { return TreeView::getNumSelectedItems(); }
|
|
|
|
/** Returns one of the files that the user has currently selected.
|
|
The index should be in the range 0 to (getNumSelectedFiles() - 1).
|
|
@see getNumSelectedFiles
|
|
*/
|
|
const File getSelectedFile (int index = 0) const;
|
|
|
|
/** Deselects any files that are currently selected. */
|
|
void deselectAllFiles();
|
|
|
|
/** Scrolls the list to the top. */
|
|
void scrollToTop();
|
|
|
|
/** Setting a name for this allows tree items to be dragged.
|
|
|
|
The string that you pass in here will be returned by the getDragSourceDescription()
|
|
of the items in the tree. For more info, see TreeViewItem::getDragSourceDescription().
|
|
*/
|
|
void setDragAndDropDescription (const String& description);
|
|
|
|
/** Returns the last value that was set by setDragAndDropDescription().
|
|
*/
|
|
const String& getDragAndDropDescription() const noexcept { return dragAndDropDescription; }
|
|
|
|
private:
|
|
|
|
String dragAndDropDescription;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileTreeComponent);
|
|
};
|
|
|
|
#endif // __JUCE_FILETREECOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileTreeComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ImagePreviewComponent.h ***/
|
|
#ifndef __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A simple preview component that shows thumbnails of image files.
|
|
|
|
@see FileChooserDialogBox, FilePreviewComponent
|
|
*/
|
|
class JUCE_API ImagePreviewComponent : public FilePreviewComponent,
|
|
private Timer
|
|
{
|
|
public:
|
|
|
|
/** Creates an ImagePreviewComponent. */
|
|
ImagePreviewComponent();
|
|
|
|
/** Destructor. */
|
|
~ImagePreviewComponent();
|
|
|
|
/** @internal */
|
|
void selectedFileChanged (const File& newSelectedFile);
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void timerCallback();
|
|
|
|
private:
|
|
File fileToLoad;
|
|
Image currentThumbnail;
|
|
String currentDetails;
|
|
|
|
void getThumbSize (int& w, int& h) const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImagePreviewComponent);
|
|
};
|
|
|
|
#endif // __JUCE_IMAGEPREVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ImagePreviewComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_WildcardFileFilter.h ***/
|
|
#ifndef __JUCE_WILDCARDFILEFILTER_JUCEHEADER__
|
|
#define __JUCE_WILDCARDFILEFILTER_JUCEHEADER__
|
|
|
|
/**
|
|
A type of FileFilter that works by wildcard pattern matching.
|
|
|
|
This filter only allows files that match one of the specified patterns, but
|
|
allows all directories through.
|
|
|
|
@see FileFilter, DirectoryContentsList, FileListComponent, FileBrowserComponent
|
|
*/
|
|
class JUCE_API WildcardFileFilter : public FileFilter
|
|
{
|
|
public:
|
|
|
|
/**
|
|
Creates a wildcard filter for one or more patterns.
|
|
|
|
The wildcardPatterns parameter is a comma or semicolon-delimited set of
|
|
patterns, e.g. "*.wav;*.aiff" would look for files ending in either .wav
|
|
or .aiff.
|
|
|
|
Passing an empty string as a pattern will fail to match anything, so by leaving
|
|
either the file or directory pattern parameter empty means you can control
|
|
whether files or directories are found.
|
|
|
|
The description is a name to show the user in a list of possible patterns, so
|
|
for the wav/aiff example, your description might be "audio files".
|
|
*/
|
|
WildcardFileFilter (const String& fileWildcardPatterns,
|
|
const String& directoryWildcardPatterns,
|
|
const String& description);
|
|
|
|
/** Destructor. */
|
|
~WildcardFileFilter();
|
|
|
|
/** Returns true if the filename matches one of the patterns specified. */
|
|
bool isFileSuitable (const File& file) const;
|
|
|
|
/** This always returns true. */
|
|
bool isDirectorySuitable (const File& file) const;
|
|
|
|
private:
|
|
|
|
StringArray fileWildcards, directoryWildcards;
|
|
|
|
static void parse (const String& pattern, StringArray& result);
|
|
static bool match (const File& file, const StringArray& wildcards);
|
|
|
|
JUCE_LEAK_DETECTOR (WildcardFileFilter);
|
|
};
|
|
|
|
#endif // __JUCE_WILDCARDFILEFILTER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_WildcardFileFilter.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMPONENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMPONENTLISTENER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_DESKTOP_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MODALCOMPONENTMANAGER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CARETCOMPONENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_KEYBOARDFOCUSTRAVERSER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_KEYLISTENER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_KeyMappingEditorComponent.h ***/
|
|
#ifndef __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_KeyPressMappingSet.h ***/
|
|
#ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__
|
|
#define __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__
|
|
|
|
/**
|
|
Manages and edits a list of keypresses, which it uses to invoke the appropriate
|
|
command in a ApplicationCommandManager.
|
|
|
|
Normally, you won't actually create a KeyPressMappingSet directly, because
|
|
each ApplicationCommandManager contains its own KeyPressMappingSet, so typically
|
|
you'd create yourself an ApplicationCommandManager, and call its
|
|
ApplicationCommandManager::getKeyMappings() method to get a pointer to its
|
|
KeyPressMappingSet.
|
|
|
|
For one of these to actually use keypresses, you'll need to add it as a KeyListener
|
|
to the top-level component for which you want to handle keystrokes. So for example:
|
|
|
|
@code
|
|
class MyMainWindow : public Component
|
|
{
|
|
ApplicationCommandManager* myCommandManager;
|
|
|
|
public:
|
|
MyMainWindow()
|
|
{
|
|
myCommandManager = new ApplicationCommandManager();
|
|
|
|
// first, make sure the command manager has registered all the commands that its
|
|
// targets can perform..
|
|
myCommandManager->registerAllCommandsForTarget (myCommandTarget1);
|
|
myCommandManager->registerAllCommandsForTarget (myCommandTarget2);
|
|
|
|
// this will use the command manager to initialise the KeyPressMappingSet with
|
|
// the default keypresses that were specified when the targets added their commands
|
|
// to the manager.
|
|
myCommandManager->getKeyMappings()->resetToDefaultMappings();
|
|
|
|
// having set up the default key-mappings, you might now want to load the last set
|
|
// of mappings that the user configured.
|
|
myCommandManager->getKeyMappings()->restoreFromXml (lastSavedKeyMappingsXML);
|
|
|
|
// Now tell our top-level window to send any keypresses that arrive to the
|
|
// KeyPressMappingSet, which will use them to invoke the appropriate commands.
|
|
addKeyListener (myCommandManager->getKeyMappings());
|
|
}
|
|
|
|
...
|
|
}
|
|
@endcode
|
|
|
|
KeyPressMappingSet derives from ChangeBroadcaster so that interested parties can
|
|
register to be told when a command or mapping is added, removed, etc.
|
|
|
|
There's also a UI component called KeyMappingEditorComponent that can be used
|
|
to easily edit the key mappings.
|
|
|
|
@see Component::addKeyListener(), KeyMappingEditorComponent, ApplicationCommandManager
|
|
*/
|
|
class JUCE_API KeyPressMappingSet : public KeyListener,
|
|
public ChangeBroadcaster,
|
|
public FocusChangeListener
|
|
{
|
|
public:
|
|
|
|
/** Creates a KeyPressMappingSet for a given command manager.
|
|
|
|
Normally, you won't actually create a KeyPressMappingSet directly, because
|
|
each ApplicationCommandManager contains its own KeyPressMappingSet, so the
|
|
best thing to do is to create your ApplicationCommandManager, and use the
|
|
ApplicationCommandManager::getKeyMappings() method to access its mappings.
|
|
|
|
When a suitable keypress happens, the manager's invoke() method will be
|
|
used to invoke the appropriate command.
|
|
|
|
@see ApplicationCommandManager
|
|
*/
|
|
explicit KeyPressMappingSet (ApplicationCommandManager* commandManager);
|
|
|
|
/** Creates an copy of a KeyPressMappingSet. */
|
|
KeyPressMappingSet (const KeyPressMappingSet& other);
|
|
|
|
/** Destructor. */
|
|
~KeyPressMappingSet();
|
|
|
|
ApplicationCommandManager* getCommandManager() const noexcept { return commandManager; }
|
|
|
|
/** Returns a list of keypresses that are assigned to a particular command.
|
|
|
|
@param commandID the command's ID
|
|
*/
|
|
const Array <KeyPress> getKeyPressesAssignedToCommand (CommandID commandID) const;
|
|
|
|
/** Assigns a keypress to a command.
|
|
|
|
If the keypress is already assigned to a different command, it will first be
|
|
removed from that command, to avoid it triggering multiple functions.
|
|
|
|
@param commandID the ID of the command that you want to add a keypress to. If
|
|
this is 0, the keypress will be removed from anything that it
|
|
was previously assigned to, but not re-assigned
|
|
@param newKeyPress the new key-press
|
|
@param insertIndex if this is less than zero, the key will be appended to the
|
|
end of the list of keypresses; otherwise the new keypress will
|
|
be inserted into the existing list at this index
|
|
*/
|
|
void addKeyPress (CommandID commandID,
|
|
const KeyPress& newKeyPress,
|
|
int insertIndex = -1);
|
|
|
|
/** Reset all mappings to the defaults, as dictated by the ApplicationCommandManager.
|
|
|
|
@see resetToDefaultMapping
|
|
*/
|
|
void resetToDefaultMappings();
|
|
|
|
/** Resets all key-mappings to the defaults for a particular command.
|
|
|
|
@see resetToDefaultMappings
|
|
*/
|
|
void resetToDefaultMapping (CommandID commandID);
|
|
|
|
/** Removes all keypresses that are assigned to any commands. */
|
|
void clearAllKeyPresses();
|
|
|
|
/** Removes all keypresses that are assigned to a particular command. */
|
|
void clearAllKeyPresses (CommandID commandID);
|
|
|
|
/** Removes one of the keypresses that are assigned to a command.
|
|
|
|
See the getKeyPressesAssignedToCommand() for the list of keypresses to
|
|
which the keyPressIndex refers.
|
|
*/
|
|
void removeKeyPress (CommandID commandID, int keyPressIndex);
|
|
|
|
/** Removes a keypress from any command that it may be assigned to.
|
|
*/
|
|
void removeKeyPress (const KeyPress& keypress);
|
|
|
|
/** Returns true if the given command is linked to this key. */
|
|
bool containsMapping (CommandID commandID, const KeyPress& keyPress) const noexcept;
|
|
|
|
/** Looks for a command that corresponds to a keypress.
|
|
|
|
@returns the UID of the command or 0 if none was found
|
|
*/
|
|
CommandID findCommandForKeyPress (const KeyPress& keyPress) const noexcept;
|
|
|
|
/** Tries to recreate the mappings from a previously stored state.
|
|
|
|
The XML passed in must have been created by the createXml() method.
|
|
|
|
If the stored state makes any reference to commands that aren't
|
|
currently available, these will be ignored.
|
|
|
|
If the set of mappings being loaded was a set of differences (using createXml (true)),
|
|
then this will call resetToDefaultMappings() and then merge the saved mappings
|
|
on top. If the saved set was created with createXml (false), then this method
|
|
will first clear all existing mappings and load the saved ones as a complete set.
|
|
|
|
@returns true if it manages to load the XML correctly
|
|
@see createXml
|
|
*/
|
|
bool restoreFromXml (const XmlElement& xmlVersion);
|
|
|
|
/** Creates an XML representation of the current mappings.
|
|
|
|
This will produce a lump of XML that can be later reloaded using
|
|
restoreFromXml() to recreate the current mapping state.
|
|
|
|
The object that is returned must be deleted by the caller.
|
|
|
|
@param saveDifferencesFromDefaultSet if this is false, then all keypresses
|
|
will be saved into the XML. If it's true, then the XML will
|
|
only store the differences between the current mappings and
|
|
the default mappings you'd get from calling resetToDefaultMappings().
|
|
The advantage of saving a set of differences from the default is that
|
|
if you change the default mappings (in a new version of your app, for
|
|
example), then these will be merged into a user's saved preferences.
|
|
|
|
@see restoreFromXml
|
|
*/
|
|
XmlElement* createXml (bool saveDifferencesFromDefaultSet) const;
|
|
|
|
/** @internal */
|
|
bool keyPressed (const KeyPress& key, Component* originatingComponent);
|
|
/** @internal */
|
|
bool keyStateChanged (bool isKeyDown, Component* originatingComponent);
|
|
/** @internal */
|
|
void globalFocusChanged (Component* focusedComponent);
|
|
|
|
private:
|
|
|
|
ApplicationCommandManager* commandManager;
|
|
|
|
struct CommandMapping
|
|
{
|
|
CommandID commandID;
|
|
Array <KeyPress> keypresses;
|
|
bool wantsKeyUpDownCallbacks;
|
|
};
|
|
|
|
OwnedArray <CommandMapping> mappings;
|
|
|
|
struct KeyPressTime
|
|
{
|
|
KeyPress key;
|
|
uint32 timeWhenPressed;
|
|
};
|
|
|
|
OwnedArray <KeyPressTime> keysDown;
|
|
|
|
void handleMessage (const Message& message);
|
|
|
|
void invokeCommand (const CommandID commandID,
|
|
const KeyPress& keyPress,
|
|
const bool isKeyDown,
|
|
const int millisecsSinceKeyPressed,
|
|
Component* const originatingComponent) const;
|
|
|
|
KeyPressMappingSet& operator= (const KeyPressMappingSet&);
|
|
JUCE_LEAK_DETECTOR (KeyPressMappingSet);
|
|
};
|
|
|
|
#endif // __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_KeyPressMappingSet.h ***/
|
|
|
|
/**
|
|
A component to allow editing of the keymaps stored by a KeyPressMappingSet
|
|
object.
|
|
|
|
@see KeyPressMappingSet
|
|
*/
|
|
class JUCE_API KeyMappingEditorComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a KeyMappingEditorComponent.
|
|
|
|
@param mappingSet this is the set of mappings to display and edit. Make sure the
|
|
mappings object is not deleted before this component!
|
|
@param showResetToDefaultButton if true, then at the bottom of the list, the
|
|
component will include a 'reset to defaults' button.
|
|
*/
|
|
KeyMappingEditorComponent (KeyPressMappingSet& mappingSet,
|
|
bool showResetToDefaultButton);
|
|
|
|
/** Destructor. */
|
|
virtual ~KeyMappingEditorComponent();
|
|
|
|
/** Sets up the colours to use for parts of the component.
|
|
|
|
@param mainBackground colour to use for most of the background
|
|
@param textColour colour to use for the text
|
|
*/
|
|
void setColours (const Colour& mainBackground,
|
|
const Colour& textColour);
|
|
|
|
/** Returns the KeyPressMappingSet that this component is acting upon. */
|
|
KeyPressMappingSet& getMappings() const noexcept { return mappings; }
|
|
|
|
/** Can be overridden if some commands need to be excluded from the list.
|
|
|
|
By default this will use the KeyPressMappingSet's shouldCommandBeVisibleInEditor()
|
|
method to decide what to return, but you can override it to handle special cases.
|
|
*/
|
|
virtual bool shouldCommandBeIncluded (CommandID commandID);
|
|
|
|
/** Can be overridden to indicate that some commands are shown as read-only.
|
|
|
|
By default this will use the KeyPressMappingSet's shouldCommandBeReadOnlyInEditor()
|
|
method to decide what to return, but you can override it to handle special cases.
|
|
*/
|
|
virtual bool isCommandReadOnly (CommandID commandID);
|
|
|
|
/** This can be overridden to let you change the format of the string used
|
|
to describe a keypress.
|
|
|
|
This is handy if you're using non-standard KeyPress objects, e.g. for custom
|
|
keys that are triggered by something else externally. If you override the
|
|
method, be sure to let the base class's method handle keys you're not
|
|
interested in.
|
|
*/
|
|
virtual const String getDescriptionForKeyPress (const KeyPress& key);
|
|
|
|
/** 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.
|
|
|
|
To change the colours of the menu that pops up
|
|
|
|
@see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
|
|
*/
|
|
enum ColourIds
|
|
{
|
|
backgroundColourId = 0x100ad00, /**< The background colour to fill the editor background. */
|
|
textColourId = 0x100ad01, /**< The colour for the text. */
|
|
};
|
|
|
|
/** @internal */
|
|
void parentHierarchyChanged();
|
|
/** @internal */
|
|
void resized();
|
|
|
|
private:
|
|
|
|
KeyPressMappingSet& mappings;
|
|
TreeView tree;
|
|
TextButton resetButton;
|
|
|
|
class TopLevelItem;
|
|
class ChangeKeyButton;
|
|
class MappingItem;
|
|
class CategoryItem;
|
|
class ItemComponent;
|
|
friend class TopLevelItem;
|
|
friend class OwnedArray <ChangeKeyButton>;
|
|
friend class ScopedPointer<TopLevelItem>;
|
|
ScopedPointer<TopLevelItem> treeItem;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KeyMappingEditorComponent);
|
|
};
|
|
|
|
#endif // __JUCE_KEYMAPPINGEDITORCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_KeyMappingEditorComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_KEYPRESS_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_KEYPRESSMAPPINGSET_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MODIFIERKEYS_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_TextEditorKeyMapper.h ***/
|
|
#ifndef __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__
|
|
#define __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__
|
|
|
|
/** This class is used to invoke a range of text-editor navigation methods on
|
|
an object, based upon a keypress event.
|
|
|
|
It's currently used internally by the TextEditor and CodeEditorComponent.
|
|
*/
|
|
template <class CallbackClass>
|
|
struct TextEditorKeyMapper
|
|
{
|
|
/** Checks the keypress and invokes one of a range of navigation functions that
|
|
the target class must implement, based on the key event.
|
|
*/
|
|
static bool invokeKeyFunction (CallbackClass& target, const KeyPress& key)
|
|
{
|
|
const bool isShiftDown = key.getModifiers().isShiftDown();
|
|
const bool ctrlOrAltDown = key.getModifiers().isCtrlDown() || key.getModifiers().isAltDown();
|
|
|
|
if (key == KeyPress (KeyPress::downKey, ModifierKeys::ctrlModifier, 0)
|
|
&& target.scrollUp())
|
|
return true;
|
|
|
|
if (key == KeyPress (KeyPress::upKey, ModifierKeys::ctrlModifier, 0)
|
|
&& target.scrollDown())
|
|
return true;
|
|
|
|
#if JUCE_MAC
|
|
if (key.getModifiers().isCommandDown())
|
|
{
|
|
if (key.isKeyCode (KeyPress::upKey))
|
|
return target.moveCaretToTop (isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::downKey))
|
|
return target.moveCaretToEnd (isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::leftKey))
|
|
return target.moveCaretToStartOfLine (isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::rightKey))
|
|
return target.moveCaretToEndOfLine (isShiftDown);
|
|
}
|
|
#endif
|
|
|
|
if (key.isKeyCode (KeyPress::upKey))
|
|
return target.moveCaretUp (isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::downKey))
|
|
return target.moveCaretDown (isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::leftKey))
|
|
return target.moveCaretLeft (ctrlOrAltDown, isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::rightKey))
|
|
return target.moveCaretRight (ctrlOrAltDown, isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::pageUpKey))
|
|
return target.pageUp (isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::pageDownKey))
|
|
return target.pageDown (isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::homeKey))
|
|
return ctrlOrAltDown ? target.moveCaretToTop (isShiftDown)
|
|
: target.moveCaretToStartOfLine (isShiftDown);
|
|
|
|
if (key.isKeyCode (KeyPress::endKey))
|
|
return ctrlOrAltDown ? target.moveCaretToEnd (isShiftDown)
|
|
: target.moveCaretToEndOfLine (isShiftDown);
|
|
|
|
if (key == KeyPress ('c', ModifierKeys::commandModifier, 0)
|
|
|| key == KeyPress (KeyPress::insertKey, ModifierKeys::ctrlModifier, 0))
|
|
return target.copyToClipboard();
|
|
|
|
if (key == KeyPress ('x', ModifierKeys::commandModifier, 0)
|
|
|| key == KeyPress (KeyPress::deleteKey, ModifierKeys::shiftModifier, 0))
|
|
return target.cutToClipboard();
|
|
|
|
if (key == KeyPress ('v', ModifierKeys::commandModifier, 0)
|
|
|| key == KeyPress (KeyPress::insertKey, ModifierKeys::shiftModifier, 0))
|
|
return target.pasteFromClipboard();
|
|
|
|
if (key.isKeyCode (KeyPress::backspaceKey))
|
|
return target.deleteBackwards (ctrlOrAltDown);
|
|
|
|
if (key.isKeyCode (KeyPress::deleteKey))
|
|
return target.deleteForwards (ctrlOrAltDown);
|
|
|
|
if (key == KeyPress ('a', ModifierKeys::commandModifier, 0))
|
|
return target.selectAll();
|
|
|
|
if (key == KeyPress ('z', ModifierKeys::commandModifier, 0))
|
|
return target.undo();
|
|
|
|
if (key == KeyPress ('y', ModifierKeys::commandModifier, 0)
|
|
|| key == KeyPress ('z', ModifierKeys::commandModifier | ModifierKeys::shiftModifier, 0))
|
|
return target.redo();
|
|
|
|
return false;
|
|
}
|
|
};
|
|
|
|
#endif // __JUCE_TEXTEDITORKEYMAPPER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TextEditorKeyMapper.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TEXTINPUTTARGET_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMPONENTANIMATOR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMPONENTBOUNDSCONSTRAINER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMPONENTBUILDER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMPONENTMOVEMENTWATCHER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ComponentMovementWatcher.h ***/
|
|
#ifndef __JUCE_COMPONENTMOVEMENTWATCHER_JUCEHEADER__
|
|
#define __JUCE_COMPONENTMOVEMENTWATCHER_JUCEHEADER__
|
|
|
|
/** An object that watches for any movement of a component or any of its parent components.
|
|
|
|
This makes it easy to check when a component is moved relative to its top-level
|
|
peer window. The normal Component::moved() method is only called when a component
|
|
moves relative to its immediate parent, and sometimes you want to know if any of
|
|
components higher up the tree have moved (which of course will affect the overall
|
|
position of all their sub-components).
|
|
|
|
It also includes a callback that lets you know when the top-level peer is changed.
|
|
|
|
This class is used by specialised components like OpenGLComponent or QuickTimeComponent
|
|
because they need to keep their custom windows in the right place and respond to
|
|
changes in the peer.
|
|
*/
|
|
class JUCE_API ComponentMovementWatcher : public ComponentListener
|
|
{
|
|
public:
|
|
|
|
/** Creates a ComponentMovementWatcher to watch a given target component. */
|
|
ComponentMovementWatcher (Component* component);
|
|
|
|
/** Destructor. */
|
|
~ComponentMovementWatcher();
|
|
|
|
/** This callback happens when the component that is being watched is moved
|
|
relative to its top-level peer window, or when it is resized. */
|
|
virtual void componentMovedOrResized (bool wasMoved, bool wasResized) = 0;
|
|
|
|
/** This callback happens when the component's top-level peer is changed. */
|
|
virtual void componentPeerChanged() = 0;
|
|
|
|
/** This callback happens when the component's visibility state changes, possibly due to
|
|
one of its parents being made visible or invisible.
|
|
*/
|
|
virtual void componentVisibilityChanged() = 0;
|
|
|
|
/** @internal */
|
|
void componentParentHierarchyChanged (Component& component);
|
|
/** @internal */
|
|
void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized);
|
|
/** @internal */
|
|
void componentBeingDeleted (Component& component);
|
|
/** @internal */
|
|
void componentVisibilityChanged (Component& component);
|
|
|
|
private:
|
|
|
|
WeakReference<Component> component;
|
|
uint32 lastPeerID;
|
|
Array <Component*> registeredParentComps;
|
|
bool reentrant, wasShowing;
|
|
Rectangle<int> lastBounds;
|
|
|
|
void unregister();
|
|
void registerWithParentComps();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentMovementWatcher);
|
|
};
|
|
|
|
#endif // __JUCE_COMPONENTMOVEMENTWATCHER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ComponentMovementWatcher.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_GROUPCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_GroupComponent.h ***/
|
|
#ifndef __JUCE_GROUPCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_GROUPCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component that draws an outline around itself and has an optional title at
|
|
the top, for drawing an outline around a group of controls.
|
|
|
|
*/
|
|
class JUCE_API GroupComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a GroupComponent.
|
|
|
|
@param componentName the name to give the component
|
|
@param labelText the text to show at the top of the outline
|
|
*/
|
|
GroupComponent (const String& componentName = String::empty,
|
|
const String& labelText = String::empty);
|
|
|
|
/** Destructor. */
|
|
~GroupComponent();
|
|
|
|
/** Changes the text that's shown at the top of the component. */
|
|
void setText (const String& newText);
|
|
|
|
/** Returns the currently displayed text label. */
|
|
String getText() const;
|
|
|
|
/** Sets the positioning of the text label.
|
|
|
|
(The default is Justification::left)
|
|
|
|
@see getTextLabelPosition
|
|
*/
|
|
void setTextLabelPosition (const Justification& justification);
|
|
|
|
/** Returns the current text label position.
|
|
|
|
@see setTextLabelPosition
|
|
*/
|
|
const Justification getTextLabelPosition() const noexcept { return justification; }
|
|
|
|
/** 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
|
|
{
|
|
outlineColourId = 0x1005400, /**< The colour to use for drawing the line around the edge. */
|
|
textColourId = 0x1005410 /**< The colour to use to draw the text label. */
|
|
};
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void enablementChanged();
|
|
/** @internal */
|
|
void colourChanged();
|
|
|
|
private:
|
|
String text;
|
|
Justification justification;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (GroupComponent);
|
|
};
|
|
|
|
#endif // __JUCE_GROUPCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_GroupComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MULTIDOCUMENTPANEL_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MultiDocumentPanel.h ***/
|
|
#ifndef __JUCE_MULTIDOCUMENTPANEL_JUCEHEADER__
|
|
#define __JUCE_MULTIDOCUMENTPANEL_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_TabbedComponent.h ***/
|
|
#ifndef __JUCE_TABBEDCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_TABBEDCOMPONENT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_TabbedButtonBar.h ***/
|
|
#ifndef __JUCE_TABBEDBUTTONBAR_JUCEHEADER__
|
|
#define __JUCE_TABBEDBUTTONBAR_JUCEHEADER__
|
|
|
|
class TabbedButtonBar;
|
|
|
|
/** In a TabbedButtonBar, this component is used for each of the buttons.
|
|
|
|
If you want to create a TabbedButtonBar with custom tab components, derive
|
|
your component from this class, and override the TabbedButtonBar::createTabButton()
|
|
method to create it instead of the default one.
|
|
|
|
@see TabbedButtonBar
|
|
*/
|
|
class JUCE_API TabBarButton : public Button
|
|
{
|
|
public:
|
|
|
|
/** Creates the tab button. */
|
|
TabBarButton (const String& name, TabbedButtonBar& ownerBar);
|
|
|
|
/** Destructor. */
|
|
~TabBarButton();
|
|
|
|
/** Chooses the best length for the tab, given the specified depth.
|
|
|
|
If the tab is horizontal, this should return its width, and the depth
|
|
specifies its height. If it's vertical, it should return the height, and
|
|
the depth is actually its width.
|
|
*/
|
|
virtual int getBestTabLength (int depth);
|
|
|
|
void paintButton (Graphics& g, bool isMouseOverButton, bool isButtonDown);
|
|
void clicked (const ModifierKeys& mods);
|
|
bool hitTest (int x, int y);
|
|
|
|
protected:
|
|
|
|
friend class TabbedButtonBar;
|
|
TabbedButtonBar& owner;
|
|
int overlapPixels;
|
|
DropShadowEffect shadow;
|
|
|
|
/** Returns an area of the component that's safe to draw in.
|
|
|
|
This deals with the orientation of the tabs, which affects which side is
|
|
touching the tabbed box's content component.
|
|
*/
|
|
const Rectangle<int> getActiveArea();
|
|
|
|
/** Returns this tab's index in its tab bar. */
|
|
int getIndex() const;
|
|
|
|
private:
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabBarButton);
|
|
};
|
|
|
|
/**
|
|
A vertical or horizontal bar containing tabs that you can select.
|
|
|
|
You can use one of these to generate things like a dialog box that has
|
|
tabbed pages you can flip between. Attach a ChangeListener to the
|
|
button bar to be told when the user changes the page.
|
|
|
|
An easier method than doing this is to use a TabbedComponent, which
|
|
contains its own TabbedButtonBar and which takes care of the layout
|
|
and other housekeeping.
|
|
|
|
@see TabbedComponent
|
|
*/
|
|
class JUCE_API TabbedButtonBar : public Component,
|
|
public ChangeBroadcaster
|
|
{
|
|
public:
|
|
|
|
/** The placement of the tab-bar
|
|
|
|
@see setOrientation, getOrientation
|
|
*/
|
|
enum Orientation
|
|
{
|
|
TabsAtTop,
|
|
TabsAtBottom,
|
|
TabsAtLeft,
|
|
TabsAtRight
|
|
};
|
|
|
|
/** Creates a TabbedButtonBar with a given placement.
|
|
|
|
You can change the orientation later if you need to.
|
|
*/
|
|
TabbedButtonBar (Orientation orientation);
|
|
|
|
/** Destructor. */
|
|
~TabbedButtonBar();
|
|
|
|
/** Changes the bar's orientation.
|
|
|
|
This won't change the bar's actual size - you'll need to do that yourself,
|
|
but this determines which direction the tabs go in, and which side they're
|
|
stuck to.
|
|
*/
|
|
void setOrientation (Orientation orientation);
|
|
|
|
/** Returns the current orientation.
|
|
|
|
@see setOrientation
|
|
*/
|
|
Orientation getOrientation() const noexcept { return orientation; }
|
|
|
|
/** Changes the minimum scale factor to which the tabs can be compressed when trying to
|
|
fit a lot of tabs on-screen.
|
|
*/
|
|
void setMinimumTabScaleFactor (double newMinimumScale);
|
|
|
|
/** Deletes all the tabs from the bar.
|
|
|
|
@see addTab
|
|
*/
|
|
void clearTabs();
|
|
|
|
/** Adds a tab to the bar.
|
|
|
|
Tabs are added in left-to-right reading order.
|
|
|
|
If this is the first tab added, it'll also be automatically selected.
|
|
*/
|
|
void addTab (const String& tabName,
|
|
const Colour& tabBackgroundColour,
|
|
int insertIndex = -1);
|
|
|
|
/** Changes the name of one of the tabs. */
|
|
void setTabName (int tabIndex,
|
|
const String& newName);
|
|
|
|
/** Gets rid of one of the tabs. */
|
|
void removeTab (int tabIndex);
|
|
|
|
/** Moves a tab to a new index in the list.
|
|
|
|
Pass -1 as the index to move it to the end of the list.
|
|
*/
|
|
void moveTab (int currentIndex, int newIndex);
|
|
|
|
/** Returns the number of tabs in the bar. */
|
|
int getNumTabs() const;
|
|
|
|
/** Returns a list of all the tab names in the bar. */
|
|
StringArray getTabNames() const;
|
|
|
|
/** Changes the currently selected tab.
|
|
|
|
This will send a change message and cause a synchronous callback to
|
|
the currentTabChanged() method. (But if the given tab is already selected,
|
|
nothing will be done).
|
|
|
|
To deselect all the tabs, use an index of -1.
|
|
*/
|
|
void setCurrentTabIndex (int newTabIndex, bool sendChangeMessage = true);
|
|
|
|
/** Returns the name of the currently selected tab.
|
|
|
|
This could be an empty string if none are selected.
|
|
*/
|
|
String getCurrentTabName() const;
|
|
|
|
/** Returns the index of the currently selected tab.
|
|
|
|
This could return -1 if none are selected.
|
|
*/
|
|
int getCurrentTabIndex() const noexcept { return currentTabIndex; }
|
|
|
|
/** Returns the button for a specific tab.
|
|
|
|
The button that is returned may be deleted later by this component, so don't hang
|
|
on to the pointer that is returned. A null pointer may be returned if the index is
|
|
out of range.
|
|
*/
|
|
TabBarButton* getTabButton (int index) const;
|
|
|
|
/** Returns the index of a TabBarButton if it belongs to this bar. */
|
|
int indexOfTabButton (const TabBarButton* button) const;
|
|
|
|
/** Callback method to indicate the selected tab has been changed.
|
|
|
|
@see setCurrentTabIndex
|
|
*/
|
|
virtual void currentTabChanged (int newCurrentTabIndex,
|
|
const String& newCurrentTabName);
|
|
|
|
/** Callback method to indicate that the user has right-clicked on a tab.
|
|
|
|
(Or ctrl-clicked on the Mac)
|
|
*/
|
|
virtual void popupMenuClickOnTab (int tabIndex, const String& tabName);
|
|
|
|
/** Returns the colour of a tab.
|
|
|
|
This is the colour that was specified in addTab().
|
|
*/
|
|
const Colour getTabBackgroundColour (int tabIndex);
|
|
|
|
/** Changes the background colour of a tab.
|
|
|
|
@see addTab, getTabBackgroundColour
|
|
*/
|
|
void setTabBackgroundColour (int tabIndex, const Colour& newColour);
|
|
|
|
/** 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
|
|
{
|
|
tabOutlineColourId = 0x1005812, /**< The colour to use to draw an outline around the tabs. */
|
|
tabTextColourId = 0x1005813, /**< The colour to use to draw the tab names. If this isn't specified,
|
|
the look and feel will choose an appropriate colour. */
|
|
frontOutlineColourId = 0x1005814, /**< The colour to use to draw an outline around the currently-selected tab. */
|
|
frontTextColourId = 0x1005815, /**< The colour to use to draw the currently-selected tab name. If
|
|
this isn't specified, the look and feel will choose an appropriate
|
|
colour. */
|
|
};
|
|
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void lookAndFeelChanged();
|
|
|
|
protected:
|
|
|
|
/** This creates one of the tabs.
|
|
|
|
If you need to use custom tab components, you can override this method and
|
|
return your own class instead of the default.
|
|
*/
|
|
virtual TabBarButton* createTabButton (const String& tabName, int tabIndex);
|
|
|
|
private:
|
|
Orientation orientation;
|
|
|
|
struct TabInfo
|
|
{
|
|
ScopedPointer<TabBarButton> component;
|
|
String name;
|
|
Colour colour;
|
|
};
|
|
|
|
OwnedArray <TabInfo> tabs;
|
|
|
|
double minimumScale;
|
|
int currentTabIndex;
|
|
|
|
class BehindFrontTabComp;
|
|
friend class BehindFrontTabComp;
|
|
friend class ScopedPointer<BehindFrontTabComp>;
|
|
ScopedPointer<BehindFrontTabComp> behindFrontTab;
|
|
ScopedPointer<Button> extraTabsButton;
|
|
|
|
void showExtraItemsMenu();
|
|
static void extraItemsMenuCallback (int, TabbedButtonBar*);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedButtonBar);
|
|
};
|
|
|
|
#endif // __JUCE_TABBEDBUTTONBAR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TabbedButtonBar.h ***/
|
|
|
|
/**
|
|
A component with a TabbedButtonBar along one of its sides.
|
|
|
|
This makes it easy to create a set of tabbed pages, just add a bunch of tabs
|
|
with addTab(), and this will take care of showing the pages for you when the
|
|
user clicks on a different tab.
|
|
|
|
@see TabbedButtonBar
|
|
*/
|
|
class JUCE_API TabbedComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a TabbedComponent, specifying where the tabs should be placed.
|
|
|
|
Once created, add some tabs with the addTab() method.
|
|
*/
|
|
explicit TabbedComponent (TabbedButtonBar::Orientation orientation);
|
|
|
|
/** Destructor. */
|
|
~TabbedComponent();
|
|
|
|
/** Changes the placement of the tabs.
|
|
|
|
This will rearrange the layout to place the tabs along the appropriate
|
|
side of this component, and will shift the content component accordingly.
|
|
|
|
@see TabbedButtonBar::setOrientation
|
|
*/
|
|
void setOrientation (TabbedButtonBar::Orientation orientation);
|
|
|
|
/** Returns the current tab placement.
|
|
|
|
@see setOrientation, TabbedButtonBar::getOrientation
|
|
*/
|
|
TabbedButtonBar::Orientation getOrientation() const noexcept;
|
|
|
|
/** Specifies how many pixels wide or high the tab-bar should be.
|
|
|
|
If the tabs are placed along the top or bottom, this specified the height
|
|
of the bar; if they're along the left or right edges, it'll be the width
|
|
of the bar.
|
|
*/
|
|
void setTabBarDepth (int newDepth);
|
|
|
|
/** Returns the current thickness of the tab bar.
|
|
|
|
@see setTabBarDepth
|
|
*/
|
|
int getTabBarDepth() const noexcept { return tabDepth; }
|
|
|
|
/** Specifies the thickness of an outline that should be drawn around the content component.
|
|
|
|
If this thickness is > 0, a line will be drawn around the three sides of the content
|
|
component which don't touch the tab-bar, and the content component will be inset by this amount.
|
|
|
|
To set the colour of the line, use setColour (outlineColourId, ...).
|
|
*/
|
|
void setOutline (int newThickness);
|
|
|
|
/** Specifies a gap to leave around the edge of the content component.
|
|
|
|
Each edge of the content component will be indented by the given number of pixels.
|
|
*/
|
|
void setIndent (int indentThickness);
|
|
|
|
/** Removes all the tabs from the bar.
|
|
|
|
@see TabbedButtonBar::clearTabs
|
|
*/
|
|
void clearTabs();
|
|
|
|
/** Adds a tab to the tab-bar.
|
|
|
|
The component passed in will be shown for the tab, and if deleteComponentWhenNotNeeded
|
|
is true, it will be deleted when the tab is removed or when this object is
|
|
deleted.
|
|
|
|
@see TabbedButtonBar::addTab
|
|
*/
|
|
void addTab (const String& tabName,
|
|
const Colour& tabBackgroundColour,
|
|
Component* contentComponent,
|
|
bool deleteComponentWhenNotNeeded,
|
|
int insertIndex = -1);
|
|
|
|
/** Changes the name of one of the tabs. */
|
|
void setTabName (int tabIndex, const String& newName);
|
|
|
|
/** Gets rid of one of the tabs. */
|
|
void removeTab (int tabIndex);
|
|
|
|
/** Returns the number of tabs in the bar. */
|
|
int getNumTabs() const;
|
|
|
|
/** Returns a list of all the tab names in the bar. */
|
|
StringArray getTabNames() const;
|
|
|
|
/** Returns the content component that was added for the given index.
|
|
|
|
Be sure not to use or delete the components that are returned, as this may interfere
|
|
with the TabbedComponent's use of them.
|
|
*/
|
|
Component* getTabContentComponent (int tabIndex) const noexcept;
|
|
|
|
/** Returns the colour of one of the tabs. */
|
|
const Colour getTabBackgroundColour (int tabIndex) const noexcept;
|
|
|
|
/** Changes the background colour of one of the tabs. */
|
|
void setTabBackgroundColour (int tabIndex, const Colour& newColour);
|
|
|
|
/** Changes the currently-selected tab.
|
|
|
|
To deselect all the tabs, pass -1 as the index.
|
|
|
|
@see TabbedButtonBar::setCurrentTabIndex
|
|
*/
|
|
void setCurrentTabIndex (int newTabIndex, bool sendChangeMessage = true);
|
|
|
|
/** Returns the index of the currently selected tab.
|
|
|
|
@see addTab, TabbedButtonBar::getCurrentTabIndex()
|
|
*/
|
|
int getCurrentTabIndex() const;
|
|
|
|
/** Returns the name of the currently selected tab.
|
|
|
|
@see addTab, TabbedButtonBar::getCurrentTabName()
|
|
*/
|
|
String getCurrentTabName() const;
|
|
|
|
/** Returns the current component that's filling the panel.
|
|
|
|
This will return 0 if there isn't one.
|
|
*/
|
|
Component* getCurrentContentComponent() const noexcept { return panelComponent; }
|
|
|
|
/** Callback method to indicate the selected tab has been changed.
|
|
|
|
@see setCurrentTabIndex
|
|
*/
|
|
virtual void currentTabChanged (int newCurrentTabIndex,
|
|
const String& newCurrentTabName);
|
|
|
|
/** Callback method to indicate that the user has right-clicked on a tab.
|
|
|
|
(Or ctrl-clicked on the Mac)
|
|
*/
|
|
virtual void popupMenuClickOnTab (int tabIndex,
|
|
const String& tabName);
|
|
|
|
/** Returns the tab button bar component that is being used.
|
|
*/
|
|
TabbedButtonBar& getTabbedButtonBar() const noexcept { return *tabs; }
|
|
|
|
/** 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 = 0x1005800, /**< The colour to fill the background behind the tabs. */
|
|
outlineColourId = 0x1005801, /**< The colour to use to draw an outline around the content.
|
|
(See setOutline) */
|
|
};
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void lookAndFeelChanged();
|
|
|
|
protected:
|
|
|
|
/** This creates one of the tab buttons.
|
|
|
|
If you need to use custom tab components, you can override this method and
|
|
return your own class instead of the default.
|
|
*/
|
|
virtual TabBarButton* createTabButton (const String& tabName, int tabIndex);
|
|
|
|
/** @internal */
|
|
ScopedPointer<TabbedButtonBar> tabs;
|
|
|
|
private:
|
|
|
|
Array <WeakReference<Component> > contentComponents;
|
|
WeakReference<Component> panelComponent;
|
|
int tabDepth;
|
|
int outlineThickness, edgeIndent;
|
|
|
|
class ButtonBar;
|
|
friend class ButtonBar;
|
|
void changeCallback (int newCurrentTabIndex, const String& newTabName);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TabbedComponent);
|
|
};
|
|
|
|
#endif // __JUCE_TABBEDCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TabbedComponent.h ***/
|
|
|
|
|
|
/*** Start of inlined file: juce_DocumentWindow.h ***/
|
|
#ifndef __JUCE_DOCUMENTWINDOW_JUCEHEADER__
|
|
#define __JUCE_DOCUMENTWINDOW_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_MenuBarModel.h ***/
|
|
#ifndef __JUCE_MENUBARMODEL_JUCEHEADER__
|
|
#define __JUCE_MENUBARMODEL_JUCEHEADER__
|
|
|
|
/**
|
|
A class for controlling MenuBar components.
|
|
|
|
This class is used to tell a MenuBar what menus to show, and to respond
|
|
to a menu being selected.
|
|
|
|
@see MenuBarModel::Listener, MenuBarComponent, PopupMenu
|
|
*/
|
|
class JUCE_API MenuBarModel : private AsyncUpdater,
|
|
private ApplicationCommandManagerListener
|
|
{
|
|
public:
|
|
|
|
MenuBarModel() noexcept;
|
|
|
|
/** Destructor. */
|
|
virtual ~MenuBarModel();
|
|
|
|
/** Call this when some of your menu items have changed.
|
|
|
|
This method will cause a callback to any MenuBarListener objects that
|
|
are registered with this model.
|
|
|
|
If this model is displaying items from an ApplicationCommandManager, you
|
|
can use the setApplicationCommandManagerToWatch() method to cause
|
|
change messages to be sent automatically when the ApplicationCommandManager
|
|
is changed.
|
|
|
|
@see addListener, removeListener, MenuBarListener
|
|
*/
|
|
void menuItemsChanged();
|
|
|
|
/** Tells the menu bar to listen to the specified command manager, and to update
|
|
itself when the commands change.
|
|
|
|
This will also allow it to flash a menu name when a command from that menu
|
|
is invoked using a keystroke.
|
|
*/
|
|
void setApplicationCommandManagerToWatch (ApplicationCommandManager* manager) noexcept;
|
|
|
|
/** A class to receive callbacks when a MenuBarModel changes.
|
|
|
|
@see MenuBarModel::addListener, MenuBarModel::removeListener, MenuBarModel::menuItemsChanged
|
|
*/
|
|
class JUCE_API Listener
|
|
{
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~Listener() {}
|
|
|
|
/** This callback is made when items are changed in the menu bar model.
|
|
*/
|
|
virtual void menuBarItemsChanged (MenuBarModel* menuBarModel) = 0;
|
|
|
|
/** This callback is made when an application command is invoked that
|
|
is represented by one of the items in the menu bar model.
|
|
*/
|
|
virtual void menuCommandInvoked (MenuBarModel* menuBarModel,
|
|
const ApplicationCommandTarget::InvocationInfo& info) = 0;
|
|
};
|
|
|
|
/** Registers a listener for callbacks when the menu items in this model change.
|
|
|
|
The listener object will get callbacks when this object's menuItemsChanged()
|
|
method is called.
|
|
|
|
@see removeListener
|
|
*/
|
|
void addListener (Listener* listenerToAdd) noexcept;
|
|
|
|
/** Removes a listener.
|
|
|
|
@see addListener
|
|
*/
|
|
void removeListener (Listener* listenerToRemove) noexcept;
|
|
|
|
/** This method must return a list of the names of the menus. */
|
|
virtual const StringArray getMenuBarNames() = 0;
|
|
|
|
/** This should return the popup menu to display for a given top-level menu.
|
|
|
|
@param topLevelMenuIndex the index of the top-level menu to show
|
|
@param menuName the name of the top-level menu item to show
|
|
*/
|
|
virtual const PopupMenu getMenuForIndex (int topLevelMenuIndex,
|
|
const String& menuName) = 0;
|
|
|
|
/** This is called when a menu item has been clicked on.
|
|
|
|
@param menuItemID the item ID of the PopupMenu item that was selected
|
|
@param topLevelMenuIndex the index of the top-level menu from which the item was
|
|
chosen (just in case you've used duplicate ID numbers
|
|
on more than one of the popup menus)
|
|
*/
|
|
virtual void menuItemSelected (int menuItemID,
|
|
int topLevelMenuIndex) = 0;
|
|
|
|
#if JUCE_MAC || DOXYGEN
|
|
/** MAC ONLY - Sets the model that is currently being shown as the main
|
|
menu bar at the top of the screen on the Mac.
|
|
|
|
You can pass 0 to stop the current model being displayed. Be careful
|
|
not to delete a model while it is being used.
|
|
|
|
An optional extra menu can be specified, containing items to add to the top of
|
|
the apple menu. (Confusingly, the 'apple' menu isn't the one with a picture of
|
|
an apple, it's the one next to it, with your application's name at the top
|
|
and the services menu etc on it). When one of these items is selected, the
|
|
menu bar model will be used to invoke it, and in the menuItemSelected() callback
|
|
the topLevelMenuIndex parameter will be -1. If you pass in an extraAppleMenuItems
|
|
object then newMenuBarModel must be non-null.
|
|
*/
|
|
static void setMacMainMenu (MenuBarModel* newMenuBarModel,
|
|
const PopupMenu* extraAppleMenuItems = nullptr);
|
|
|
|
/** MAC ONLY - Returns the menu model that is currently being shown as
|
|
the main menu bar.
|
|
*/
|
|
static MenuBarModel* getMacMainMenu();
|
|
#endif
|
|
|
|
/** @internal */
|
|
void applicationCommandInvoked (const ApplicationCommandTarget::InvocationInfo& info);
|
|
/** @internal */
|
|
void applicationCommandListChanged();
|
|
/** @internal */
|
|
void handleAsyncUpdate();
|
|
|
|
private:
|
|
ApplicationCommandManager* manager;
|
|
ListenerList <Listener> listeners;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MenuBarModel);
|
|
};
|
|
|
|
/** This typedef is just for compatibility with old code - newer code should use the MenuBarModel::Listener class directly. */
|
|
typedef MenuBarModel::Listener MenuBarModelListener;
|
|
|
|
#endif // __JUCE_MENUBARMODEL_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MenuBarModel.h ***/
|
|
|
|
/**
|
|
A resizable window with a title bar and maximise, minimise and close buttons.
|
|
|
|
This subclass of ResizableWindow creates a fairly standard type of window with
|
|
a title bar and various buttons. The name of the component is shown in the
|
|
title bar, and an icon can optionally be specified with setIcon().
|
|
|
|
All the methods available to a ResizableWindow are also available to this,
|
|
so it can easily be made resizable, minimised, maximised, etc.
|
|
|
|
It's not advisable to add child components directly to a DocumentWindow: put them
|
|
inside your content component instead. And overriding methods like resized(), moved(), etc
|
|
is also not recommended - instead override these methods for your content component.
|
|
(If for some obscure reason you do need to override these methods, always remember to
|
|
call the super-class's resized() method too, otherwise it'll fail to lay out the window
|
|
decorations correctly).
|
|
|
|
You can also automatically add a menu bar to the window, using the setMenuBar()
|
|
method.
|
|
|
|
@see ResizableWindow, DialogWindow
|
|
*/
|
|
class JUCE_API DocumentWindow : public ResizableWindow
|
|
{
|
|
public:
|
|
|
|
/** The set of available button-types that can be put on the title bar.
|
|
|
|
@see setTitleBarButtonsRequired
|
|
*/
|
|
enum TitleBarButtons
|
|
{
|
|
minimiseButton = 1,
|
|
maximiseButton = 2,
|
|
closeButton = 4,
|
|
|
|
/** A combination of all the buttons above. */
|
|
allButtons = 7
|
|
};
|
|
|
|
/** Creates a DocumentWindow.
|
|
|
|
@param name the name to give the component - this is also
|
|
the title shown at the top of the window. To change
|
|
this later, use setName()
|
|
@param backgroundColour the colour to use for filling the window's background.
|
|
@param requiredButtons specifies which of the buttons (close, minimise, maximise)
|
|
should be shown on the title bar. This value is a bitwise
|
|
combination of values from the TitleBarButtons enum. Note
|
|
that it can be "allButtons" to get them all. You
|
|
can change this later with the setTitleBarButtonsRequired()
|
|
method, which can also specify where they are positioned.
|
|
@param addToDesktop if true, the window will be automatically added to the
|
|
desktop; if false, you can use it as a child component
|
|
@see TitleBarButtons
|
|
*/
|
|
DocumentWindow (const String& name,
|
|
const Colour& backgroundColour,
|
|
int requiredButtons,
|
|
bool addToDesktop = true);
|
|
|
|
/** Destructor.
|
|
If a content component has been set with setContentOwned(), it will be deleted.
|
|
*/
|
|
~DocumentWindow();
|
|
|
|
/** Changes the component's name.
|
|
|
|
(This is overridden from Component::setName() to cause a repaint, as
|
|
the name is what gets drawn across the window's title bar).
|
|
*/
|
|
void setName (const String& newName);
|
|
|
|
/** Sets an icon to show in the title bar, next to the title.
|
|
|
|
A copy is made internally of the image, so the caller can delete the
|
|
image after calling this. If 0 is passed-in, any existing icon will be
|
|
removed.
|
|
*/
|
|
void setIcon (const Image& imageToUse);
|
|
|
|
/** Changes the height of the title-bar. */
|
|
void setTitleBarHeight (int newHeight);
|
|
|
|
/** Returns the current title bar height. */
|
|
int getTitleBarHeight() const;
|
|
|
|
/** Changes the set of title-bar buttons being shown.
|
|
|
|
@param requiredButtons specifies which of the buttons (close, minimise, maximise)
|
|
should be shown on the title bar. This value is a bitwise
|
|
combination of values from the TitleBarButtons enum. Note
|
|
that it can be "allButtons" to get them all.
|
|
@param positionTitleBarButtonsOnLeft if true, the buttons should go at the
|
|
left side of the bar; if false, they'll be placed at the right
|
|
*/
|
|
void setTitleBarButtonsRequired (int requiredButtons,
|
|
bool positionTitleBarButtonsOnLeft);
|
|
|
|
/** Sets whether the title should be centred within the window.
|
|
|
|
If true, the title text is shown in the middle of the title-bar; if false,
|
|
it'll be shown at the left of the bar.
|
|
*/
|
|
void setTitleBarTextCentred (bool textShouldBeCentred);
|
|
|
|
/** Creates a menu inside this window.
|
|
|
|
@param menuBarModel this specifies a MenuBarModel that should be used to
|
|
generate the contents of a menu bar that will be placed
|
|
just below the title bar, and just above any content
|
|
component. If this value is zero, any existing menu bar
|
|
will be removed from the component; if non-zero, one will
|
|
be added if it's required.
|
|
@param menuBarHeight the height of the menu bar component, if one is needed. Pass a value of zero
|
|
or less to use the look-and-feel's default size.
|
|
*/
|
|
void setMenuBar (MenuBarModel* menuBarModel,
|
|
int menuBarHeight = 0);
|
|
|
|
/** Returns the current menu bar component, or null if there isn't one.
|
|
This is probably a MenuBarComponent, unless a custom one has been set using
|
|
setMenuBarComponent().
|
|
*/
|
|
Component* getMenuBarComponent() const noexcept;
|
|
|
|
/** Replaces the current menu bar with a custom component.
|
|
The component will be owned and deleted by the document window.
|
|
*/
|
|
void setMenuBarComponent (Component* newMenuBarComponent);
|
|
|
|
/** This method is called when the user tries to close the window.
|
|
|
|
This is triggered by the user clicking the close button, or using some other
|
|
OS-specific key shortcut or OS menu for getting rid of a window.
|
|
|
|
If the window is just a pop-up, you should override this closeButtonPressed()
|
|
method and make it delete the window in whatever way is appropriate for your
|
|
app. E.g. you might just want to call "delete this".
|
|
|
|
If your app is centred around this window such that the whole app should quit when
|
|
the window is closed, then you will probably want to use this method as an opportunity
|
|
to call JUCEApplication::quit(), and leave the window to be deleted later by your
|
|
JUCEApplication::shutdown() method. (Doing it this way means that your window will
|
|
still get cleaned-up if the app is quit by some other means (e.g. a cmd-Q on the mac
|
|
or closing it via the taskbar icon on Windows).
|
|
|
|
(Note that the DocumentWindow class overrides Component::userTriedToCloseWindow() and
|
|
redirects it to call this method, so any methods of closing the window that are
|
|
caught by userTriedToCloseWindow() will also end up here).
|
|
*/
|
|
virtual void closeButtonPressed();
|
|
|
|
/** Callback that is triggered when the minimise button is pressed.
|
|
|
|
The default implementation of this calls ResizableWindow::setMinimised(), but
|
|
you can override it to do more customised behaviour.
|
|
*/
|
|
virtual void minimiseButtonPressed();
|
|
|
|
/** Callback that is triggered when the maximise button is pressed, or when the
|
|
title-bar is double-clicked.
|
|
|
|
The default implementation of this calls ResizableWindow::setFullScreen(), but
|
|
you can override it to do more customised behaviour.
|
|
*/
|
|
virtual void maximiseButtonPressed();
|
|
|
|
/** Returns the close button, (or 0 if there isn't one). */
|
|
Button* getCloseButton() const noexcept;
|
|
|
|
/** Returns the minimise button, (or 0 if there isn't one). */
|
|
Button* getMinimiseButton() const noexcept;
|
|
|
|
/** Returns the maximise button, (or 0 if there isn't one). */
|
|
Button* getMaximiseButton() const noexcept;
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the window.
|
|
|
|
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
|
|
{
|
|
textColourId = 0x1005701, /**< The colour to draw any text with. It's up to the look
|
|
and feel class how this is used. */
|
|
};
|
|
|
|
#ifndef DOXYGEN
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void lookAndFeelChanged();
|
|
/** @internal */
|
|
const BorderSize<int> getBorderThickness();
|
|
/** @internal */
|
|
const BorderSize<int> getContentComponentBorder();
|
|
/** @internal */
|
|
void mouseDoubleClick (const MouseEvent& e);
|
|
/** @internal */
|
|
void userTriedToCloseWindow();
|
|
/** @internal */
|
|
void activeWindowStatusChanged();
|
|
/** @internal */
|
|
int getDesktopWindowStyleFlags() const;
|
|
/** @internal */
|
|
void parentHierarchyChanged();
|
|
/** @internal */
|
|
const Rectangle<int> getTitleBarArea();
|
|
#endif
|
|
|
|
private:
|
|
|
|
int titleBarHeight, menuBarHeight, requiredButtons;
|
|
bool positionTitleBarButtonsOnLeft, drawTitleTextCentred;
|
|
ScopedPointer <Button> titleBarButtons [3];
|
|
Image titleBarIcon;
|
|
ScopedPointer <Component> menuBar;
|
|
MenuBarModel* menuBarModel;
|
|
|
|
class ButtonListenerProxy;
|
|
friend class ScopedPointer <ButtonListenerProxy>;
|
|
ScopedPointer <ButtonListenerProxy> buttonListener;
|
|
|
|
void repaintTitleBar();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DocumentWindow);
|
|
};
|
|
|
|
#endif // __JUCE_DOCUMENTWINDOW_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DocumentWindow.h ***/
|
|
|
|
class MultiDocumentPanel;
|
|
class MDITabbedComponentInternal;
|
|
|
|
/**
|
|
This is a derivative of DocumentWindow that is used inside a MultiDocumentPanel
|
|
component.
|
|
|
|
It's like a normal DocumentWindow but has some extra functionality to make sure
|
|
everything works nicely inside a MultiDocumentPanel.
|
|
|
|
@see MultiDocumentPanel
|
|
*/
|
|
class JUCE_API MultiDocumentPanelWindow : public DocumentWindow
|
|
{
|
|
public:
|
|
|
|
/**
|
|
*/
|
|
MultiDocumentPanelWindow (const Colour& backgroundColour);
|
|
|
|
/** Destructor. */
|
|
~MultiDocumentPanelWindow();
|
|
|
|
/** @internal */
|
|
void maximiseButtonPressed();
|
|
/** @internal */
|
|
void closeButtonPressed();
|
|
/** @internal */
|
|
void activeWindowStatusChanged();
|
|
/** @internal */
|
|
void broughtToFront();
|
|
|
|
private:
|
|
|
|
void updateOrder();
|
|
MultiDocumentPanel* getOwner() const noexcept;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiDocumentPanelWindow);
|
|
};
|
|
|
|
/**
|
|
A component that contains a set of other components either in floating windows
|
|
or tabs.
|
|
|
|
This acts as a panel that can be used to hold a set of open document windows, with
|
|
different layout modes.
|
|
|
|
Use addDocument() and closeDocument() to add or remove components from the
|
|
panel - never use any of the Component methods to access the panel's child
|
|
components directly, as these are managed internally.
|
|
*/
|
|
class JUCE_API MultiDocumentPanel : public Component,
|
|
private ComponentListener
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty panel.
|
|
|
|
Use addDocument() and closeDocument() to add or remove components from the
|
|
panel - never use any of the Component methods to access the panel's child
|
|
components directly, as these are managed internally.
|
|
*/
|
|
MultiDocumentPanel();
|
|
|
|
/** Destructor.
|
|
|
|
When deleted, this will call closeAllDocuments (false) to make sure all its
|
|
components are deleted. If you need to make sure all documents are saved
|
|
before closing, then you should call closeAllDocuments (true) and check that
|
|
it returns true before deleting the panel.
|
|
*/
|
|
~MultiDocumentPanel();
|
|
|
|
/** Tries to close all the documents.
|
|
|
|
If checkItsOkToCloseFirst is true, then the tryToCloseDocument() method will
|
|
be called for each open document, and any of these calls fails, this method
|
|
will stop and return false, leaving some documents still open.
|
|
|
|
If checkItsOkToCloseFirst is false, then all documents will be closed
|
|
unconditionally.
|
|
|
|
@see closeDocument
|
|
*/
|
|
bool closeAllDocuments (bool checkItsOkToCloseFirst);
|
|
|
|
/** Adds a document component to the panel.
|
|
|
|
If the number of documents would exceed the limit set by setMaximumNumDocuments() then
|
|
this will fail and return false. (If it does fail, the component passed-in will not be
|
|
deleted, even if deleteWhenRemoved was set to true).
|
|
|
|
The MultiDocumentPanel will deal with creating a window border to go around your component,
|
|
so just pass in the bare content component here, no need to give it a ResizableWindow
|
|
or DocumentWindow.
|
|
|
|
@param component the component to add
|
|
@param backgroundColour the background colour to use to fill the component's
|
|
window or tab
|
|
@param deleteWhenRemoved if true, then when the component is removed by closeDocument()
|
|
or closeAllDocuments(), then it will be deleted. If false, then
|
|
the caller must handle the component's deletion
|
|
*/
|
|
bool addDocument (Component* component,
|
|
const Colour& backgroundColour,
|
|
bool deleteWhenRemoved);
|
|
|
|
/** Closes one of the documents.
|
|
|
|
If checkItsOkToCloseFirst is true, then the tryToCloseDocument() method will
|
|
be called, and if it fails, this method will return false without closing the
|
|
document.
|
|
|
|
If checkItsOkToCloseFirst is false, then the documents will be closed
|
|
unconditionally.
|
|
|
|
The component will be deleted if the deleteWhenRemoved parameter was set to
|
|
true when it was added with addDocument.
|
|
|
|
@see addDocument, closeAllDocuments
|
|
*/
|
|
bool closeDocument (Component* component,
|
|
bool checkItsOkToCloseFirst);
|
|
|
|
/** Returns the number of open document windows.
|
|
|
|
@see getDocument
|
|
*/
|
|
int getNumDocuments() const noexcept;
|
|
|
|
/** Returns one of the open documents.
|
|
|
|
The order of the documents in this array may change when they are added, removed
|
|
or moved around.
|
|
|
|
@see getNumDocuments
|
|
*/
|
|
Component* getDocument (int index) const noexcept;
|
|
|
|
/** Returns the document component that is currently focused or on top.
|
|
|
|
If currently using floating windows, then this will be the component in the currently
|
|
active window, or the top component if none are active.
|
|
|
|
If it's currently in tabbed mode, then it'll return the component in the active tab.
|
|
|
|
@see setActiveDocument
|
|
*/
|
|
Component* getActiveDocument() const noexcept;
|
|
|
|
/** Makes one of the components active and brings it to the top.
|
|
|
|
@see getActiveDocument
|
|
*/
|
|
void setActiveDocument (Component* component);
|
|
|
|
/** Callback which gets invoked when the currently-active document changes. */
|
|
virtual void activeDocumentChanged();
|
|
|
|
/** Sets a limit on how many windows can be open at once.
|
|
|
|
If this is zero or less there's no limit (the default). addDocument() will fail
|
|
if this number is exceeded.
|
|
*/
|
|
void setMaximumNumDocuments (int maximumNumDocuments);
|
|
|
|
/** Sets an option to make the document fullscreen if there's only one document open.
|
|
|
|
If set to true, then if there's only one document, it'll fill the whole of this
|
|
component without tabs or a window border. If false, then tabs or a window
|
|
will always be shown, even if there's only one document. If there's more than
|
|
one document open, then this option makes no difference.
|
|
*/
|
|
void useFullscreenWhenOneDocument (bool shouldUseTabs);
|
|
|
|
/** Returns the result of the last time useFullscreenWhenOneDocument() was called.
|
|
*/
|
|
bool isFullscreenWhenOneDocument() const noexcept;
|
|
|
|
/** The different layout modes available. */
|
|
enum LayoutMode
|
|
{
|
|
FloatingWindows, /**< In this mode, there are overlapping DocumentWindow components for each document. */
|
|
MaximisedWindowsWithTabs /**< In this mode, a TabbedComponent is used to show one document at a time. */
|
|
};
|
|
|
|
/** Changes the panel's mode.
|
|
|
|
@see LayoutMode, getLayoutMode
|
|
*/
|
|
void setLayoutMode (LayoutMode newLayoutMode);
|
|
|
|
/** Returns the current layout mode. */
|
|
LayoutMode getLayoutMode() const noexcept { return mode; }
|
|
|
|
/** Sets the background colour for the whole panel.
|
|
|
|
Each document has its own background colour, but this is the one used to fill the areas
|
|
behind them.
|
|
*/
|
|
void setBackgroundColour (const Colour& newBackgroundColour);
|
|
|
|
/** Returns the current background colour.
|
|
|
|
@see setBackgroundColour
|
|
*/
|
|
const Colour& getBackgroundColour() const noexcept { return backgroundColour; }
|
|
|
|
/** A subclass must override this to say whether its currently ok for a document
|
|
to be closed.
|
|
|
|
This method is called by closeDocument() and closeAllDocuments() to indicate that
|
|
a document should be saved if possible, ready for it to be closed.
|
|
|
|
If this method returns true, then it means the document is ok and can be closed.
|
|
|
|
If it returns false, then it means that the closeDocument() method should stop
|
|
and not close.
|
|
|
|
Normally, you'd use this method to ask the user if they want to save any changes,
|
|
then return true if the save operation went ok. If the user cancelled the save
|
|
operation you could return false here to abort the close operation.
|
|
|
|
If your component is based on the FileBasedDocument class, then you'd probably want
|
|
to call FileBasedDocument::saveIfNeededAndUserAgrees() and return true if this returned
|
|
FileBasedDocument::savedOk
|
|
|
|
@see closeDocument, FileBasedDocument::saveIfNeededAndUserAgrees()
|
|
*/
|
|
virtual bool tryToCloseDocument (Component* component) = 0;
|
|
|
|
/** Creates a new window to be used for a document.
|
|
|
|
The default implementation of this just returns a basic MultiDocumentPanelWindow object,
|
|
but you might want to override it to return a custom component.
|
|
*/
|
|
virtual MultiDocumentPanelWindow* createNewDocumentWindow();
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void componentNameChanged (Component&);
|
|
|
|
private:
|
|
|
|
LayoutMode mode;
|
|
Array <Component*> components;
|
|
ScopedPointer<TabbedComponent> tabComponent;
|
|
Colour backgroundColour;
|
|
int maximumNumDocuments, numDocsBeforeTabsUsed;
|
|
|
|
friend class MultiDocumentPanelWindow;
|
|
friend class MDITabbedComponentInternal;
|
|
|
|
Component* getContainerComp (Component* c) const;
|
|
void updateOrder();
|
|
|
|
void addWindow (Component* component);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MultiDocumentPanel);
|
|
};
|
|
|
|
#endif // __JUCE_MULTIDOCUMENTPANEL_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MultiDocumentPanel.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_RESIZABLEBORDERCOMPONENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RESIZABLECORNERCOMPONENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RESIZABLEEDGECOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ResizableEdgeComponent.h ***/
|
|
#ifndef __JUCE_RESIZABLEEDGECOMPONENT_JUCEHEADER__
|
|
#define __JUCE_RESIZABLEEDGECOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component that resizes its parent component when dragged.
|
|
|
|
This component forms a bar along one edge of a component, allowing it to
|
|
be dragged by that edges to resize it.
|
|
|
|
To use it, just add it to your component, positioning it along the appropriate
|
|
edge. Make sure you reposition the resizer component each time the parent's size
|
|
changes, to keep it in the correct position.
|
|
|
|
@see ResizbleBorderComponent, ResizableCornerComponent
|
|
*/
|
|
class JUCE_API ResizableEdgeComponent : public Component
|
|
{
|
|
public:
|
|
|
|
enum Edge
|
|
{
|
|
leftEdge, /**< Indicates a vertical bar that can be dragged left/right to move the component's left-hand edge. */
|
|
rightEdge, /**< Indicates a vertical bar that can be dragged left/right to move the component's right-hand edge. */
|
|
topEdge, /**< Indicates a horizontal bar that can be dragged up/down to move the top of the component. */
|
|
bottomEdge /**< Indicates a horizontal bar that can be dragged up/down to move the bottom of the component. */
|
|
};
|
|
|
|
/** Creates a resizer bar.
|
|
|
|
Pass in the target component which you want to be resized when this one is
|
|
dragged. The target component will usually be this component's parent, but this
|
|
isn't mandatory.
|
|
|
|
Remember that when the target component is resized, it'll need to move and
|
|
resize this component to keep it in place, as this won't happen automatically.
|
|
|
|
If the constrainer parameter is non-zero, then this object will be used to enforce
|
|
limits on the size and position that the component can be stretched to. Make sure
|
|
that the constrainer isn't deleted while still in use by this object.
|
|
|
|
@see ComponentBoundsConstrainer
|
|
*/
|
|
ResizableEdgeComponent (Component* componentToResize,
|
|
ComponentBoundsConstrainer* constrainer,
|
|
Edge edgeToResize);
|
|
|
|
/** Destructor. */
|
|
~ResizableEdgeComponent();
|
|
|
|
bool isVertical() const noexcept;
|
|
|
|
protected:
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseUp (const MouseEvent& e);
|
|
|
|
private:
|
|
WeakReference<Component> component;
|
|
ComponentBoundsConstrainer* constrainer;
|
|
Rectangle<int> originalBounds;
|
|
const Edge edge;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ResizableEdgeComponent);
|
|
};
|
|
|
|
#endif // __JUCE_RESIZABLEEDGECOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ResizableEdgeComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SCROLLBAR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_StretchableLayoutManager.h ***/
|
|
#ifndef __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__
|
|
#define __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__
|
|
|
|
/**
|
|
For laying out a set of components, where the components have preferred sizes
|
|
and size limits, but where they are allowed to stretch to fill the available
|
|
space.
|
|
|
|
For example, if you have a component containing several other components, and
|
|
each one should be given a share of the total size, you could use one of these
|
|
to resize the child components when the parent component is resized. Then
|
|
you could add a StretchableLayoutResizerBar to easily let the user rescale them.
|
|
|
|
A StretchableLayoutManager operates only in one dimension, so if you have a set
|
|
of components stacked vertically on top of each other, you'd use one to manage their
|
|
heights. To build up complex arrangements of components, e.g. for applications
|
|
with multiple nested panels, you would use more than one StretchableLayoutManager.
|
|
E.g. by using two (one vertical, one horizontal), you could create a resizable
|
|
spreadsheet-style table.
|
|
|
|
E.g.
|
|
@code
|
|
class MyComp : public Component
|
|
{
|
|
StretchableLayoutManager myLayout;
|
|
|
|
MyComp()
|
|
{
|
|
myLayout.setItemLayout (0, // for item 0
|
|
50, 100, // must be between 50 and 100 pixels in size
|
|
-0.6); // and its preferred size is 60% of the total available space
|
|
|
|
myLayout.setItemLayout (1, // for item 1
|
|
-0.2, -0.6, // size must be between 20% and 60% of the available space
|
|
50); // and its preferred size is 50 pixels
|
|
}
|
|
|
|
void resized()
|
|
{
|
|
// make a list of two of our child components that we want to reposition
|
|
Component* comps[] = { myComp1, myComp2 };
|
|
|
|
// this will position the 2 components, one above the other, to fit
|
|
// vertically into the rectangle provided.
|
|
myLayout.layOutComponents (comps, 2,
|
|
0, 0, getWidth(), getHeight(),
|
|
true);
|
|
}
|
|
};
|
|
@endcode
|
|
|
|
@see StretchableLayoutResizerBar
|
|
*/
|
|
class JUCE_API StretchableLayoutManager
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty layout.
|
|
|
|
You'll need to add some item properties to the layout before it can be used
|
|
to resize things - see setItemLayout().
|
|
*/
|
|
StretchableLayoutManager();
|
|
|
|
/** Destructor. */
|
|
~StretchableLayoutManager();
|
|
|
|
/** For a numbered item, this sets its size limits and preferred size.
|
|
|
|
@param itemIndex the index of the item to change.
|
|
@param minimumSize the minimum size that this item is allowed to be - a positive number
|
|
indicates an absolute size in pixels. A negative number indicates a
|
|
proportion of the available space (e.g -0.5 is 50%)
|
|
@param maximumSize the maximum size that this item is allowed to be - a positive number
|
|
indicates an absolute size in pixels. A negative number indicates a
|
|
proportion of the available space
|
|
@param preferredSize the size that this item would like to be, if there's enough room. A
|
|
positive number indicates an absolute size in pixels. A negative number
|
|
indicates a proportion of the available space
|
|
@see getItemLayout
|
|
*/
|
|
void setItemLayout (int itemIndex,
|
|
double minimumSize,
|
|
double maximumSize,
|
|
double preferredSize);
|
|
|
|
/** For a numbered item, this returns its size limits and preferred size.
|
|
|
|
@param itemIndex the index of the item.
|
|
@param minimumSize the minimum size that this item is allowed to be - a positive number
|
|
indicates an absolute size in pixels. A negative number indicates a
|
|
proportion of the available space (e.g -0.5 is 50%)
|
|
@param maximumSize the maximum size that this item is allowed to be - a positive number
|
|
indicates an absolute size in pixels. A negative number indicates a
|
|
proportion of the available space
|
|
@param preferredSize the size that this item would like to be, if there's enough room. A
|
|
positive number indicates an absolute size in pixels. A negative number
|
|
indicates a proportion of the available space
|
|
@returns false if the item's properties hadn't been set
|
|
@see setItemLayout
|
|
*/
|
|
bool getItemLayout (int itemIndex,
|
|
double& minimumSize,
|
|
double& maximumSize,
|
|
double& preferredSize) const;
|
|
|
|
/** Clears all the properties that have been set with setItemLayout() and resets
|
|
this object to its initial state.
|
|
*/
|
|
void clearAllItems();
|
|
|
|
/** Takes a set of components that correspond to the layout's items, and positions
|
|
them to fill a space.
|
|
|
|
This will try to give each item its preferred size, whether that's a relative size
|
|
or an absolute one.
|
|
|
|
@param components an array of components that correspond to each of the
|
|
numbered items that the StretchableLayoutManager object
|
|
has been told about with setItemLayout()
|
|
@param numComponents the number of components in the array that is passed-in. This
|
|
should be the same as the number of items this object has been
|
|
told about.
|
|
@param x the left of the rectangle in which the components should
|
|
be laid out
|
|
@param y the top of the rectangle in which the components should
|
|
be laid out
|
|
@param width the width of the rectangle in which the components should
|
|
be laid out
|
|
@param height the height of the rectangle in which the components should
|
|
be laid out
|
|
@param vertically if true, the components will be positioned in a vertical stack,
|
|
so that they fill the height of the rectangle. If false, they
|
|
will be placed side-by-side in a horizontal line, filling the
|
|
available width
|
|
@param resizeOtherDimension if true, this means that the components will have their
|
|
other dimension resized to fit the space - i.e. if the 'vertically'
|
|
parameter is true, their x-positions and widths are adjusted to fit
|
|
the x and width parameters; if 'vertically' is false, their y-positions
|
|
and heights are adjusted to fit the y and height parameters.
|
|
*/
|
|
void layOutComponents (Component** components,
|
|
int numComponents,
|
|
int x, int y, int width, int height,
|
|
bool vertically,
|
|
bool resizeOtherDimension);
|
|
|
|
/** Returns the current position of one of the items.
|
|
|
|
This is only a valid call after layOutComponents() has been called, as it
|
|
returns the last position that this item was placed at. If the layout was
|
|
vertical, the value returned will be the y position of the top of the item,
|
|
relative to the top of the rectangle in which the items were placed (so for
|
|
example, item 0 will always have position of 0, even in the rectangle passed
|
|
in to layOutComponents() wasn't at y = 0). If the layout was done horizontally,
|
|
the position returned is the item's left-hand position, again relative to the
|
|
x position of the rectangle used.
|
|
|
|
@see getItemCurrentSize, setItemPosition
|
|
*/
|
|
int getItemCurrentPosition (int itemIndex) const;
|
|
|
|
/** Returns the current size of one of the items.
|
|
|
|
This is only meaningful after layOutComponents() has been called, as it
|
|
returns the last size that this item was given. If the layout was done
|
|
vertically, it'll return the item's height in pixels; if it was horizontal,
|
|
it'll return its width.
|
|
|
|
@see getItemCurrentRelativeSize
|
|
*/
|
|
int getItemCurrentAbsoluteSize (int itemIndex) const;
|
|
|
|
/** Returns the current size of one of the items.
|
|
|
|
This is only meaningful after layOutComponents() has been called, as it
|
|
returns the last size that this item was given. If the layout was done
|
|
vertically, it'll return a negative value representing the item's height relative
|
|
to the last size used for laying the components out; if the layout was done
|
|
horizontally it'll be the proportion of its width.
|
|
|
|
@see getItemCurrentAbsoluteSize
|
|
*/
|
|
double getItemCurrentRelativeSize (int itemIndex) const;
|
|
|
|
/** Moves one of the items, shifting along any other items as necessary in
|
|
order to get it to the desired position.
|
|
|
|
Calling this method will also update the preferred sizes of the items it
|
|
shuffles along, so that they reflect their new positions.
|
|
|
|
(This is the method that a StretchableLayoutResizerBar uses to shift the items
|
|
about when it's dragged).
|
|
|
|
@param itemIndex the item to move
|
|
@param newPosition the absolute position that you'd like this item to move
|
|
to. The item might not be able to always reach exactly this position,
|
|
because other items may have minimum sizes that constrain how
|
|
far it can go
|
|
*/
|
|
void setItemPosition (int itemIndex,
|
|
int newPosition);
|
|
|
|
private:
|
|
|
|
struct ItemLayoutProperties
|
|
{
|
|
int itemIndex;
|
|
int currentSize;
|
|
double minSize, maxSize, preferredSize;
|
|
};
|
|
|
|
OwnedArray <ItemLayoutProperties> items;
|
|
int totalSize;
|
|
|
|
static int sizeToRealSize (double size, int totalSpace);
|
|
ItemLayoutProperties* getInfoFor (int itemIndex) const;
|
|
void setTotalSize (int newTotalSize);
|
|
int fitComponentsIntoSpace (int startIndex, int endIndex, int availableSpace, int startPos);
|
|
int getMinimumSizeOfItems (int startIndex, int endIndex) const;
|
|
int getMaximumSizeOfItems (int startIndex, int endIndex) const;
|
|
void updatePrefSizesToMatchCurrentPositions();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StretchableLayoutManager);
|
|
};
|
|
|
|
#endif // __JUCE_STRETCHABLELAYOUTMANAGER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_StretchableLayoutManager.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_StretchableLayoutResizerBar.h ***/
|
|
#ifndef __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__
|
|
#define __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__
|
|
|
|
/**
|
|
A component that acts as one of the vertical or horizontal bars you see being
|
|
used to resize panels in a window.
|
|
|
|
One of these acts with a StretchableLayoutManager to resize the other components.
|
|
|
|
@see StretchableLayoutManager
|
|
*/
|
|
class JUCE_API StretchableLayoutResizerBar : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a resizer bar for use on a specified layout.
|
|
|
|
@param layoutToUse the layout that will be affected when this bar
|
|
is dragged
|
|
@param itemIndexInLayout the item index in the layout that corresponds to
|
|
this bar component. You'll need to set up the item
|
|
properties in a suitable way for a divider bar, e.g.
|
|
for an 8-pixel wide bar which, you could call
|
|
myLayout->setItemLayout (barIndex, 8, 8, 8)
|
|
@param isBarVertical true if it's an upright bar that you drag left and
|
|
right; false for a horizontal one that you drag up and
|
|
down
|
|
*/
|
|
StretchableLayoutResizerBar (StretchableLayoutManager* layoutToUse,
|
|
int itemIndexInLayout,
|
|
bool isBarVertical);
|
|
|
|
/** Destructor. */
|
|
~StretchableLayoutResizerBar();
|
|
|
|
/** This is called when the bar is dragged.
|
|
|
|
This method must update the positions of any components whose position is
|
|
determined by the StretchableLayoutManager, because they might have just
|
|
moved.
|
|
|
|
The default implementation calls the resized() method of this component's
|
|
parent component, because that's often where you're likely to apply the
|
|
layout, but it can be overridden for more specific needs.
|
|
*/
|
|
virtual void hasBeenMoved();
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent& e);
|
|
|
|
private:
|
|
|
|
StretchableLayoutManager* layout;
|
|
int itemIndex, mouseDownPos;
|
|
bool isVertical;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StretchableLayoutResizerBar);
|
|
};
|
|
|
|
#endif // __JUCE_STRETCHABLELAYOUTRESIZERBAR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_StretchableLayoutResizerBar.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_StretchableObjectResizer.h ***/
|
|
#ifndef __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__
|
|
#define __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__
|
|
|
|
/**
|
|
A utility class for fitting a set of objects whose sizes can vary between
|
|
a minimum and maximum size, into a space.
|
|
|
|
This is a trickier algorithm than it would first seem, so I've put it in this
|
|
class to allow it to be shared by various bits of code.
|
|
|
|
To use it, create one of these objects, call addItem() to add the list of items
|
|
you need, then call resizeToFit(), which will change all their sizes. You can
|
|
then retrieve the new sizes with getItemSize() and getNumItems().
|
|
|
|
It's currently used by the TableHeaderComponent for stretching out the table
|
|
headings to fill the table's width.
|
|
*/
|
|
class StretchableObjectResizer
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty object resizer. */
|
|
StretchableObjectResizer();
|
|
|
|
/** Destructor. */
|
|
~StretchableObjectResizer();
|
|
|
|
/** Adds an item to the list.
|
|
|
|
The order parameter lets you specify groups of items that are resized first when some
|
|
space needs to be found. Those items with an order of 0 will be the first ones to be
|
|
resized, and if that doesn't provide enough space to meet the requirements, the algorithm
|
|
will then try resizing the items with an order of 1, then 2, and so on.
|
|
*/
|
|
void addItem (double currentSize,
|
|
double minSize,
|
|
double maxSize,
|
|
int order = 0);
|
|
|
|
/** Resizes all the items to fit this amount of space.
|
|
|
|
This will attempt to fit them in without exceeding each item's miniumum and
|
|
maximum sizes. In cases where none of the items can be expanded or enlarged any
|
|
further, the final size may be greater or less than the size passed in.
|
|
|
|
After calling this method, you can retrieve the new sizes with the getItemSize()
|
|
method.
|
|
*/
|
|
void resizeToFit (double targetSize);
|
|
|
|
/** Returns the number of items that have been added. */
|
|
int getNumItems() const noexcept { return items.size(); }
|
|
|
|
/** Returns the size of one of the items. */
|
|
double getItemSize (int index) const noexcept;
|
|
|
|
private:
|
|
|
|
struct Item
|
|
{
|
|
double size;
|
|
double minSize;
|
|
double maxSize;
|
|
int order;
|
|
};
|
|
|
|
OwnedArray <Item> items;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StretchableObjectResizer);
|
|
};
|
|
|
|
#endif // __JUCE_STRETCHABLEOBJECTRESIZER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_StretchableObjectResizer.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TABBEDBUTTONBAR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TABBEDCOMPONENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_VIEWPORT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_LookAndFeel.h ***/
|
|
#ifndef __JUCE_LOOKANDFEEL_JUCEHEADER__
|
|
#define __JUCE_LOOKANDFEEL_JUCEHEADER__
|
|
|
|
class ToggleButton;
|
|
class TextButton;
|
|
class AlertWindow;
|
|
class TextLayout;
|
|
class ScrollBar;
|
|
class BubbleComponent;
|
|
class ComboBox;
|
|
class Button;
|
|
class FilenameComponent;
|
|
class DocumentWindow;
|
|
class ResizableWindow;
|
|
class GroupComponent;
|
|
class MenuBarComponent;
|
|
class DropShadower;
|
|
class GlyphArrangement;
|
|
class PropertyComponent;
|
|
class TableHeaderComponent;
|
|
class Toolbar;
|
|
class ToolbarItemComponent;
|
|
class PopupMenu;
|
|
class ProgressBar;
|
|
class FileBrowserComponent;
|
|
class DirectoryContentsDisplayComponent;
|
|
class FilePreviewComponent;
|
|
class ImageButton;
|
|
class CallOutBox;
|
|
class Drawable;
|
|
class CaretComponent;
|
|
|
|
/**
|
|
LookAndFeel objects define the appearance of all the JUCE widgets, and subclasses
|
|
can be used to apply different 'skins' to the application.
|
|
|
|
*/
|
|
class JUCE_API LookAndFeel
|
|
{
|
|
public:
|
|
|
|
/** Creates the default JUCE look and feel. */
|
|
LookAndFeel();
|
|
|
|
/** Destructor. */
|
|
virtual ~LookAndFeel();
|
|
|
|
/** Returns the current default look-and-feel for a component to use when it
|
|
hasn't got one explicitly set.
|
|
|
|
@see setDefaultLookAndFeel
|
|
*/
|
|
static LookAndFeel& getDefaultLookAndFeel() noexcept;
|
|
|
|
/** Changes the default look-and-feel.
|
|
|
|
@param newDefaultLookAndFeel the new look-and-feel object to use - if this is
|
|
set to null, it will revert to using the default one. The
|
|
object passed-in must be deleted by the caller when
|
|
it's no longer needed.
|
|
@see getDefaultLookAndFeel
|
|
*/
|
|
static void setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel) noexcept;
|
|
|
|
/** 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, it will just return Colours::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.
|
|
|
|
If you're looking up a colour for use in drawing a component, it's usually
|
|
best not to call this directly, but to use the Component::findColour() method
|
|
instead. That will first check whether a suitable colour has been registered
|
|
directly with the component, and will fall-back on calling the component's
|
|
LookAndFeel's findColour() method if none is found.
|
|
|
|
@see setColour, Component::findColour, Component::setColour
|
|
*/
|
|
const Colour findColour (int colourId) const noexcept;
|
|
|
|
/** Registers a colour to be used for a particular purpose.
|
|
|
|
For more details, see the comments for findColour().
|
|
|
|
@see findColour, Component::findColour, Component::setColour
|
|
*/
|
|
void setColour (int colourId, const Colour& colour) noexcept;
|
|
|
|
/** Returns true if the specified colour ID has been explicitly set using the
|
|
setColour() method.
|
|
*/
|
|
bool isColourSpecified (int colourId) const noexcept;
|
|
|
|
virtual const Typeface::Ptr getTypefaceForFont (const Font& font);
|
|
|
|
/** Allows you to change the default sans-serif font.
|
|
|
|
If you need to supply your own Typeface object for any of the default fonts, rather
|
|
than just supplying the name (e.g. if you want to use an embedded font), then
|
|
you should instead override getTypefaceForFont() to create and return the typeface.
|
|
*/
|
|
void setDefaultSansSerifTypefaceName (const String& newName);
|
|
|
|
/** Override this to get the chance to swap a component's mouse cursor for a
|
|
customised one.
|
|
*/
|
|
virtual const MouseCursor getMouseCursorFor (Component& component);
|
|
|
|
/** Draws the lozenge-shaped background for a standard button. */
|
|
virtual void drawButtonBackground (Graphics& g,
|
|
Button& button,
|
|
const Colour& backgroundColour,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
virtual const Font getFontForTextButton (TextButton& button);
|
|
|
|
/** Draws the text for a TextButton. */
|
|
virtual void drawButtonText (Graphics& g,
|
|
TextButton& button,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
/** Draws the contents of a standard ToggleButton. */
|
|
virtual void drawToggleButton (Graphics& g,
|
|
ToggleButton& button,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
virtual void changeToggleButtonWidthToFitText (ToggleButton& button);
|
|
|
|
virtual void drawTickBox (Graphics& g,
|
|
Component& component,
|
|
float x, float y, float w, float h,
|
|
bool ticked,
|
|
bool isEnabled,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
/* AlertWindow handling..
|
|
*/
|
|
virtual AlertWindow* createAlertWindow (const String& title,
|
|
const String& message,
|
|
const String& button1,
|
|
const String& button2,
|
|
const String& button3,
|
|
AlertWindow::AlertIconType iconType,
|
|
int numButtons,
|
|
Component* associatedComponent);
|
|
|
|
virtual void drawAlertBox (Graphics& g,
|
|
AlertWindow& alert,
|
|
const Rectangle<int>& textArea,
|
|
TextLayout& textLayout);
|
|
|
|
virtual int getAlertBoxWindowFlags();
|
|
|
|
virtual int getAlertWindowButtonHeight();
|
|
|
|
virtual const Font getAlertWindowMessageFont();
|
|
virtual const Font getAlertWindowFont();
|
|
|
|
void setUsingNativeAlertWindows (bool shouldUseNativeAlerts);
|
|
bool isUsingNativeAlertWindows();
|
|
|
|
/** Draws a progress bar.
|
|
|
|
If the progress value is less than 0 or greater than 1.0, this should draw a spinning
|
|
bar that fills the whole space (i.e. to say that the app is still busy but the progress
|
|
isn't known). It can use the current time as a basis for playing an animation.
|
|
|
|
(Used by progress bars in AlertWindow).
|
|
*/
|
|
virtual void drawProgressBar (Graphics& g, ProgressBar& progressBar,
|
|
int width, int height,
|
|
double progress, const String& textToShow);
|
|
|
|
// Draws a small image that spins to indicate that something's happening..
|
|
// This method should use the current time to animate itself, so just keep
|
|
// repainting it every so often.
|
|
virtual void drawSpinningWaitAnimation (Graphics& g, const Colour& colour,
|
|
int x, int y, int w, int h);
|
|
|
|
/** Draws one of the buttons on a scrollbar.
|
|
|
|
@param g the context to draw into
|
|
@param scrollbar the bar itself
|
|
@param width the width of the button
|
|
@param height the height of the button
|
|
@param buttonDirection the direction of the button, where 0 = up, 1 = right, 2 = down, 3 = left
|
|
@param isScrollbarVertical true if it's a vertical bar, false if horizontal
|
|
@param isMouseOverButton whether the mouse is currently over the button (also true if it's held down)
|
|
@param isButtonDown whether the mouse button's held down
|
|
*/
|
|
virtual void drawScrollbarButton (Graphics& g,
|
|
ScrollBar& scrollbar,
|
|
int width, int height,
|
|
int buttonDirection,
|
|
bool isScrollbarVertical,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
/** Draws the thumb area of a scrollbar.
|
|
|
|
@param g the context to draw into
|
|
@param scrollbar the bar itself
|
|
@param x the x position of the left edge of the thumb area to draw in
|
|
@param y the y position of the top edge of the thumb area to draw in
|
|
@param width the width of the thumb area to draw in
|
|
@param height the height of the thumb area to draw in
|
|
@param isScrollbarVertical true if it's a vertical bar, false if horizontal
|
|
@param thumbStartPosition for vertical bars, the y co-ordinate of the top of the
|
|
thumb, or its x position for horizontal bars
|
|
@param thumbSize for vertical bars, the height of the thumb, or its width for
|
|
horizontal bars. This may be 0 if the thumb shouldn't be drawn.
|
|
@param isMouseOver whether the mouse is over the thumb area, also true if the mouse is
|
|
currently dragging the thumb
|
|
@param isMouseDown whether the mouse is currently dragging the scrollbar
|
|
*/
|
|
virtual void drawScrollbar (Graphics& g,
|
|
ScrollBar& scrollbar,
|
|
int x, int y,
|
|
int width, int height,
|
|
bool isScrollbarVertical,
|
|
int thumbStartPosition,
|
|
int thumbSize,
|
|
bool isMouseOver,
|
|
bool isMouseDown);
|
|
|
|
/** Returns the component effect to use for a scrollbar */
|
|
virtual ImageEffectFilter* getScrollbarEffect();
|
|
|
|
/** Returns the minimum length in pixels to use for a scrollbar thumb. */
|
|
virtual int getMinimumScrollbarThumbSize (ScrollBar& scrollbar);
|
|
|
|
/** Returns the default thickness to use for a scrollbar. */
|
|
virtual int getDefaultScrollbarWidth();
|
|
|
|
/** Returns the length in pixels to use for a scrollbar button. */
|
|
virtual int getScrollbarButtonSize (ScrollBar& scrollbar);
|
|
|
|
/** Returns a tick shape for use in yes/no boxes, etc. */
|
|
virtual const Path getTickShape (float height);
|
|
/** Returns a cross shape for use in yes/no boxes, etc. */
|
|
virtual const Path getCrossShape (float height);
|
|
|
|
/** Draws the + or - box in a treeview. */
|
|
virtual void drawTreeviewPlusMinusBox (Graphics& g, int x, int y, int w, int h, bool isPlus, bool isMouseOver);
|
|
|
|
virtual void fillTextEditorBackground (Graphics& g, int width, int height, TextEditor& textEditor);
|
|
virtual void drawTextEditorOutline (Graphics& g, int width, int height, TextEditor& textEditor);
|
|
|
|
virtual CaretComponent* createCaretComponent (Component* keyFocusOwner);
|
|
|
|
// These return a pointer to an internally cached drawable - make sure you don't keep
|
|
// a copy of this pointer anywhere, as it may become invalid in the future.
|
|
virtual const Drawable* getDefaultFolderImage();
|
|
virtual const Drawable* getDefaultDocumentFileImage();
|
|
|
|
virtual void createFileChooserHeaderText (const String& title,
|
|
const String& instructions,
|
|
GlyphArrangement& destArrangement,
|
|
int width);
|
|
|
|
virtual void drawFileBrowserRow (Graphics& g, int width, int height,
|
|
const String& filename, Image* icon,
|
|
const String& fileSizeDescription,
|
|
const String& fileTimeDescription,
|
|
bool isDirectory,
|
|
bool isItemSelected,
|
|
int itemIndex,
|
|
DirectoryContentsDisplayComponent& component);
|
|
|
|
virtual Button* createFileBrowserGoUpButton();
|
|
|
|
virtual void layoutFileBrowserComponent (FileBrowserComponent& browserComp,
|
|
DirectoryContentsDisplayComponent* fileListComponent,
|
|
FilePreviewComponent* previewComp,
|
|
ComboBox* currentPathBox,
|
|
TextEditor* filenameBox,
|
|
Button* goUpButton);
|
|
|
|
virtual void drawBubble (Graphics& g,
|
|
float tipX, float tipY,
|
|
float boxX, float boxY, float boxW, float boxH);
|
|
|
|
/** Fills the background of a popup menu component. */
|
|
virtual void drawPopupMenuBackground (Graphics& g, int width, int height);
|
|
|
|
/** Draws one of the items in a popup menu. */
|
|
virtual void drawPopupMenuItem (Graphics& g,
|
|
int width, int height,
|
|
bool isSeparator,
|
|
bool isActive,
|
|
bool isHighlighted,
|
|
bool isTicked,
|
|
bool hasSubMenu,
|
|
const String& text,
|
|
const String& shortcutKeyText,
|
|
Image* image,
|
|
const Colour* const textColour);
|
|
|
|
/** Returns the size and style of font to use in popup menus. */
|
|
virtual const Font getPopupMenuFont();
|
|
|
|
virtual void drawPopupMenuUpDownArrow (Graphics& g,
|
|
int width, int height,
|
|
bool isScrollUpArrow);
|
|
|
|
/** Finds the best size for an item in a popup menu. */
|
|
virtual void getIdealPopupMenuItemSize (const String& text,
|
|
bool isSeparator,
|
|
int standardMenuItemHeight,
|
|
int& idealWidth,
|
|
int& idealHeight);
|
|
|
|
virtual int getMenuWindowFlags();
|
|
|
|
virtual void drawMenuBarBackground (Graphics& g, int width, int height,
|
|
bool isMouseOverBar,
|
|
MenuBarComponent& menuBar);
|
|
|
|
virtual int getMenuBarItemWidth (MenuBarComponent& menuBar, int itemIndex, const String& itemText);
|
|
|
|
virtual const Font getMenuBarFont (MenuBarComponent& menuBar, int itemIndex, const String& itemText);
|
|
|
|
virtual void drawMenuBarItem (Graphics& g,
|
|
int width, int height,
|
|
int itemIndex,
|
|
const String& itemText,
|
|
bool isMouseOverItem,
|
|
bool isMenuOpen,
|
|
bool isMouseOverBar,
|
|
MenuBarComponent& menuBar);
|
|
|
|
virtual void drawComboBox (Graphics& g, int width, int height,
|
|
bool isButtonDown,
|
|
int buttonX, int buttonY,
|
|
int buttonW, int buttonH,
|
|
ComboBox& box);
|
|
|
|
virtual const Font getComboBoxFont (ComboBox& box);
|
|
|
|
virtual Label* createComboBoxTextBox (ComboBox& box);
|
|
|
|
virtual void positionComboBoxText (ComboBox& box, Label& labelToPosition);
|
|
|
|
virtual void drawLabel (Graphics& g, Label& label);
|
|
|
|
virtual void drawLinearSlider (Graphics& g,
|
|
int x, int y,
|
|
int width, int height,
|
|
float sliderPos,
|
|
float minSliderPos,
|
|
float maxSliderPos,
|
|
const Slider::SliderStyle style,
|
|
Slider& slider);
|
|
|
|
virtual void drawLinearSliderBackground (Graphics& g,
|
|
int x, int y,
|
|
int width, int height,
|
|
float sliderPos,
|
|
float minSliderPos,
|
|
float maxSliderPos,
|
|
const Slider::SliderStyle style,
|
|
Slider& slider);
|
|
|
|
virtual void drawLinearSliderThumb (Graphics& g,
|
|
int x, int y,
|
|
int width, int height,
|
|
float sliderPos,
|
|
float minSliderPos,
|
|
float maxSliderPos,
|
|
const Slider::SliderStyle style,
|
|
Slider& slider);
|
|
|
|
virtual int getSliderThumbRadius (Slider& slider);
|
|
|
|
virtual void drawRotarySlider (Graphics& g,
|
|
int x, int y,
|
|
int width, int height,
|
|
float sliderPosProportional,
|
|
float rotaryStartAngle,
|
|
float rotaryEndAngle,
|
|
Slider& slider);
|
|
|
|
virtual Button* createSliderButton (bool isIncrement);
|
|
virtual Label* createSliderTextBox (Slider& slider);
|
|
|
|
virtual ImageEffectFilter* getSliderEffect();
|
|
|
|
virtual void getTooltipSize (const String& tipText, int& width, int& height);
|
|
|
|
virtual void drawTooltip (Graphics& g, const String& text, int width, int height);
|
|
|
|
virtual Button* createFilenameComponentBrowseButton (const String& text);
|
|
|
|
virtual void layoutFilenameComponent (FilenameComponent& filenameComp,
|
|
ComboBox* filenameBox, Button* browseButton);
|
|
|
|
virtual void drawCornerResizer (Graphics& g,
|
|
int w, int h,
|
|
bool isMouseOver,
|
|
bool isMouseDragging);
|
|
|
|
virtual void drawResizableFrame (Graphics& g,
|
|
int w, int h,
|
|
const BorderSize<int>& borders);
|
|
|
|
virtual void fillResizableWindowBackground (Graphics& g, int w, int h,
|
|
const BorderSize<int>& border,
|
|
ResizableWindow& window);
|
|
|
|
virtual void drawResizableWindowBorder (Graphics& g,
|
|
int w, int h,
|
|
const BorderSize<int>& border,
|
|
ResizableWindow& window);
|
|
|
|
virtual void drawDocumentWindowTitleBar (DocumentWindow& window,
|
|
Graphics& g, int w, int h,
|
|
int titleSpaceX, int titleSpaceW,
|
|
const Image* icon,
|
|
bool drawTitleTextOnLeft);
|
|
|
|
virtual Button* createDocumentWindowButton (int buttonType);
|
|
|
|
virtual void positionDocumentWindowButtons (DocumentWindow& window,
|
|
int titleBarX, int titleBarY,
|
|
int titleBarW, int titleBarH,
|
|
Button* minimiseButton,
|
|
Button* maximiseButton,
|
|
Button* closeButton,
|
|
bool positionTitleBarButtonsOnLeft);
|
|
|
|
virtual int getDefaultMenuBarHeight();
|
|
|
|
virtual DropShadower* createDropShadowerForComponent (Component* component);
|
|
|
|
virtual void drawStretchableLayoutResizerBar (Graphics& g,
|
|
int w, int h,
|
|
bool isVerticalBar,
|
|
bool isMouseOver,
|
|
bool isMouseDragging);
|
|
|
|
virtual void drawGroupComponentOutline (Graphics& g, int w, int h,
|
|
const String& text,
|
|
const Justification& position,
|
|
GroupComponent& group);
|
|
|
|
virtual void createTabButtonShape (Path& p,
|
|
int width, int height,
|
|
int tabIndex,
|
|
const String& text,
|
|
Button& button,
|
|
TabbedButtonBar::Orientation orientation,
|
|
bool isMouseOver,
|
|
bool isMouseDown,
|
|
bool isFrontTab);
|
|
|
|
virtual void fillTabButtonShape (Graphics& g,
|
|
const Path& path,
|
|
const Colour& preferredBackgroundColour,
|
|
int tabIndex,
|
|
const String& text,
|
|
Button& button,
|
|
TabbedButtonBar::Orientation orientation,
|
|
bool isMouseOver,
|
|
bool isMouseDown,
|
|
bool isFrontTab);
|
|
|
|
virtual void drawTabButtonText (Graphics& g,
|
|
int x, int y, int w, int h,
|
|
const Colour& preferredBackgroundColour,
|
|
int tabIndex,
|
|
const String& text,
|
|
Button& button,
|
|
TabbedButtonBar::Orientation orientation,
|
|
bool isMouseOver,
|
|
bool isMouseDown,
|
|
bool isFrontTab);
|
|
|
|
virtual int getTabButtonOverlap (int tabDepth);
|
|
virtual int getTabButtonSpaceAroundImage();
|
|
|
|
virtual int getTabButtonBestWidth (int tabIndex,
|
|
const String& text,
|
|
int tabDepth,
|
|
Button& button);
|
|
|
|
virtual void drawTabButton (Graphics& g,
|
|
int w, int h,
|
|
const Colour& preferredColour,
|
|
int tabIndex,
|
|
const String& text,
|
|
Button& button,
|
|
TabbedButtonBar::Orientation orientation,
|
|
bool isMouseOver,
|
|
bool isMouseDown,
|
|
bool isFrontTab);
|
|
|
|
virtual void drawTabAreaBehindFrontButton (Graphics& g,
|
|
int w, int h,
|
|
TabbedButtonBar& tabBar,
|
|
TabbedButtonBar::Orientation orientation);
|
|
|
|
virtual Button* createTabBarExtrasButton();
|
|
|
|
virtual void drawImageButton (Graphics& g, Image* image,
|
|
int imageX, int imageY, int imageW, int imageH,
|
|
const Colour& overlayColour,
|
|
float imageOpacity,
|
|
ImageButton& button);
|
|
|
|
virtual void drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header);
|
|
|
|
virtual void drawTableHeaderColumn (Graphics& g, const String& columnName, int columnId,
|
|
int width, int height,
|
|
bool isMouseOver, bool isMouseDown,
|
|
int columnFlags);
|
|
|
|
virtual void paintToolbarBackground (Graphics& g, int width, int height, Toolbar& toolbar);
|
|
|
|
virtual Button* createToolbarMissingItemsButton (Toolbar& toolbar);
|
|
|
|
virtual void paintToolbarButtonBackground (Graphics& g, int width, int height,
|
|
bool isMouseOver, bool isMouseDown,
|
|
ToolbarItemComponent& component);
|
|
|
|
virtual void paintToolbarButtonLabel (Graphics& g, int x, int y, int width, int height,
|
|
const String& text, ToolbarItemComponent& component);
|
|
|
|
virtual void drawPropertyPanelSectionHeader (Graphics& g, const String& name,
|
|
bool isOpen, int width, int height);
|
|
|
|
virtual void drawPropertyComponentBackground (Graphics& g, int width, int height,
|
|
PropertyComponent& component);
|
|
|
|
virtual void drawPropertyComponentLabel (Graphics& g, int width, int height,
|
|
PropertyComponent& component);
|
|
|
|
virtual const Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component);
|
|
|
|
virtual void drawCallOutBoxBackground (CallOutBox& box, Graphics& g, const Path& path);
|
|
|
|
virtual void drawLevelMeter (Graphics& g, int width, int height, float level);
|
|
|
|
virtual void drawKeymapChangeButton (Graphics& g, int width, int height, Button& button, const String& keyDescription);
|
|
|
|
/** Plays the system's default 'beep' noise, to alert the user about something very important.
|
|
*/
|
|
virtual void playAlertSound();
|
|
|
|
/** Utility function to draw a shiny, glassy circle (for round LED-type buttons). */
|
|
static void drawGlassSphere (Graphics& g,
|
|
float x, float y,
|
|
float diameter,
|
|
const Colour& colour,
|
|
float outlineThickness) noexcept;
|
|
|
|
static void drawGlassPointer (Graphics& g,
|
|
float x, float y,
|
|
float diameter,
|
|
const Colour& colour, float outlineThickness,
|
|
int direction) noexcept;
|
|
|
|
/** Utility function to draw a shiny, glassy oblong (for text buttons). */
|
|
static void drawGlassLozenge (Graphics& g,
|
|
float x, float y,
|
|
float width, float height,
|
|
const Colour& colour,
|
|
float outlineThickness,
|
|
float cornerSize,
|
|
bool flatOnLeft, bool flatOnRight,
|
|
bool flatOnTop, bool flatOnBottom) noexcept;
|
|
|
|
static Drawable* loadDrawableFromData (const void* data, size_t numBytes);
|
|
|
|
private:
|
|
|
|
friend class WeakReference<LookAndFeel>;
|
|
WeakReference<LookAndFeel>::Master weakReferenceMaster;
|
|
const WeakReference<LookAndFeel>::SharedRef& getWeakReference();
|
|
|
|
Array <int> colourIds;
|
|
Array <Colour> colours;
|
|
|
|
// default typeface names
|
|
String defaultSans, defaultSerif, defaultFixed;
|
|
|
|
ScopedPointer<Drawable> folderImage, documentImage;
|
|
|
|
bool useNativeAlertWindows;
|
|
|
|
void drawShinyButtonShape (Graphics& g,
|
|
float x, float y, float w, float h, float maxCornerSize,
|
|
const Colour& baseColour,
|
|
float strokeWidth,
|
|
bool flatOnLeft,
|
|
bool flatOnRight,
|
|
bool flatOnTop,
|
|
bool flatOnBottom) noexcept;
|
|
|
|
// This has been deprecated - see the new parameter list..
|
|
virtual int drawFileBrowserRow (Graphics&, int, int, const String&, Image*, const String&, const String&, bool, bool, int) { return 0; }
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeel);
|
|
};
|
|
|
|
#endif // __JUCE_LOOKANDFEEL_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_LookAndFeel.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_OldSchoolLookAndFeel.h ***/
|
|
#ifndef __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__
|
|
#define __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__
|
|
|
|
/**
|
|
The original Juce look-and-feel.
|
|
|
|
*/
|
|
class JUCE_API OldSchoolLookAndFeel : public LookAndFeel
|
|
{
|
|
public:
|
|
|
|
/** Creates the default JUCE look and feel. */
|
|
OldSchoolLookAndFeel();
|
|
|
|
/** Destructor. */
|
|
virtual ~OldSchoolLookAndFeel();
|
|
|
|
/** Draws the lozenge-shaped background for a standard button. */
|
|
virtual void drawButtonBackground (Graphics& g,
|
|
Button& button,
|
|
const Colour& backgroundColour,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
/** Draws the contents of a standard ToggleButton. */
|
|
virtual void drawToggleButton (Graphics& g,
|
|
ToggleButton& button,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
virtual void drawTickBox (Graphics& g,
|
|
Component& component,
|
|
float x, float y, float w, float h,
|
|
bool ticked,
|
|
bool isEnabled,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
virtual void drawProgressBar (Graphics& g, ProgressBar& progressBar,
|
|
int width, int height,
|
|
double progress, const String& textToShow);
|
|
|
|
virtual void drawScrollbarButton (Graphics& g,
|
|
ScrollBar& scrollbar,
|
|
int width, int height,
|
|
int buttonDirection,
|
|
bool isScrollbarVertical,
|
|
bool isMouseOverButton,
|
|
bool isButtonDown);
|
|
|
|
virtual void drawScrollbar (Graphics& g,
|
|
ScrollBar& scrollbar,
|
|
int x, int y,
|
|
int width, int height,
|
|
bool isScrollbarVertical,
|
|
int thumbStartPosition,
|
|
int thumbSize,
|
|
bool isMouseOver,
|
|
bool isMouseDown);
|
|
|
|
virtual ImageEffectFilter* getScrollbarEffect();
|
|
|
|
virtual void drawTextEditorOutline (Graphics& g,
|
|
int width, int height,
|
|
TextEditor& textEditor);
|
|
|
|
/** Fills the background of a popup menu component. */
|
|
virtual void drawPopupMenuBackground (Graphics& g, int width, int height);
|
|
|
|
virtual void drawMenuBarBackground (Graphics& g, int width, int height,
|
|
bool isMouseOverBar,
|
|
MenuBarComponent& menuBar);
|
|
|
|
virtual void drawComboBox (Graphics& g, int width, int height,
|
|
bool isButtonDown,
|
|
int buttonX, int buttonY,
|
|
int buttonW, int buttonH,
|
|
ComboBox& box);
|
|
|
|
virtual const Font getComboBoxFont (ComboBox& box);
|
|
|
|
virtual void drawLinearSlider (Graphics& g,
|
|
int x, int y,
|
|
int width, int height,
|
|
float sliderPos,
|
|
float minSliderPos,
|
|
float maxSliderPos,
|
|
const Slider::SliderStyle style,
|
|
Slider& slider);
|
|
|
|
virtual int getSliderThumbRadius (Slider& slider);
|
|
|
|
virtual Button* createSliderButton (bool isIncrement);
|
|
|
|
virtual ImageEffectFilter* getSliderEffect();
|
|
|
|
virtual void drawCornerResizer (Graphics& g,
|
|
int w, int h,
|
|
bool isMouseOver,
|
|
bool isMouseDragging);
|
|
|
|
virtual Button* createDocumentWindowButton (int buttonType);
|
|
|
|
virtual void positionDocumentWindowButtons (DocumentWindow& window,
|
|
int titleBarX, int titleBarY,
|
|
int titleBarW, int titleBarH,
|
|
Button* minimiseButton,
|
|
Button* maximiseButton,
|
|
Button* closeButton,
|
|
bool positionTitleBarButtonsOnLeft);
|
|
|
|
private:
|
|
|
|
DropShadowEffect scrollbarShadow;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OldSchoolLookAndFeel);
|
|
};
|
|
|
|
#endif // __JUCE_OLDSCHOOLLOOKANDFEEL_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_OldSchoolLookAndFeel.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MENUBARCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MenuBarComponent.h ***/
|
|
#ifndef __JUCE_MENUBARCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_MENUBARCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A menu bar component.
|
|
|
|
@see MenuBarModel
|
|
*/
|
|
class JUCE_API MenuBarComponent : public Component,
|
|
private MenuBarModel::Listener,
|
|
private Timer
|
|
{
|
|
public:
|
|
|
|
/** Creates a menu bar.
|
|
|
|
@param model the model object to use to control this bar. You can
|
|
pass 0 into this if you like, and set the model later
|
|
using the setModel() method
|
|
*/
|
|
MenuBarComponent (MenuBarModel* model);
|
|
|
|
/** Destructor. */
|
|
~MenuBarComponent();
|
|
|
|
/** Changes the model object to use to control the bar.
|
|
|
|
This can be a null pointer, in which case the bar will be empty. Don't delete the object
|
|
that is passed-in while it's still being used by this MenuBar.
|
|
*/
|
|
void setModel (MenuBarModel* newModel);
|
|
|
|
/** Returns the current menu bar model being used.
|
|
*/
|
|
MenuBarModel* getModel() const noexcept;
|
|
|
|
/** Pops up one of the menu items.
|
|
|
|
This lets you manually open one of the menus - it could be triggered by a
|
|
key shortcut, for example.
|
|
*/
|
|
void showMenu (int menuIndex);
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @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 */
|
|
void mouseMove (const MouseEvent& e);
|
|
/** @internal */
|
|
void handleCommandMessage (int commandId);
|
|
/** @internal */
|
|
bool keyPressed (const KeyPress& key);
|
|
/** @internal */
|
|
void menuBarItemsChanged (MenuBarModel* menuBarModel);
|
|
/** @internal */
|
|
void menuCommandInvoked (MenuBarModel* menuBarModel,
|
|
const ApplicationCommandTarget::InvocationInfo& info);
|
|
|
|
private:
|
|
|
|
MenuBarModel* model;
|
|
|
|
StringArray menuNames;
|
|
Array <int> xPositions;
|
|
int itemUnderMouse, currentPopupIndex, topLevelIndexClicked;
|
|
int lastMouseX, lastMouseY;
|
|
|
|
int getItemAt (int x, int y);
|
|
void setItemUnderMouse (int index);
|
|
void setOpenItem (int index);
|
|
void updateItemUnderMouse (int x, int y);
|
|
void timerCallback();
|
|
void repaintMenuItem (int index);
|
|
void menuDismissed (int topLevelIndex, int itemId);
|
|
static void menuBarMenuDismissedCallback (int, MenuBarComponent*, int);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MenuBarComponent);
|
|
};
|
|
|
|
#endif // __JUCE_MENUBARCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MenuBarComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MENUBARMODEL_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_POPUPMENU_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMPONENTDRAGGER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAGANDDROPCONTAINER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAGANDDROPTARGET_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILEDRAGANDDROPTARGET_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_LASSOCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_LassoComponent.h ***/
|
|
#ifndef __JUCE_LASSOCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_LASSOCOMPONENT_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_SelectedItemSet.h ***/
|
|
#ifndef __JUCE_SELECTEDITEMSET_JUCEHEADER__
|
|
#define __JUCE_SELECTEDITEMSET_JUCEHEADER__
|
|
|
|
/** Manages a list of selectable items.
|
|
|
|
Use one of these to keep a track of things that the user has highlighted, like
|
|
icons or things in a list.
|
|
|
|
The class is templated so that you can use it to hold either a set of pointers
|
|
to objects, or a set of ID numbers or handles, for cases where each item may
|
|
not always have a corresponding object.
|
|
|
|
To be informed when items are selected/deselected, register a ChangeListener with
|
|
this object.
|
|
|
|
@see SelectableObject
|
|
*/
|
|
template <class SelectableItemType>
|
|
class JUCE_API SelectedItemSet : public ChangeBroadcaster
|
|
{
|
|
public:
|
|
|
|
typedef SelectableItemType ItemType;
|
|
typedef PARAMETER_TYPE (SelectableItemType) ParameterType;
|
|
|
|
/** Creates an empty set. */
|
|
SelectedItemSet()
|
|
{
|
|
}
|
|
|
|
/** Creates a set based on an array of items. */
|
|
explicit SelectedItemSet (const Array <SelectableItemType>& items)
|
|
: selectedItems (items)
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another set. */
|
|
SelectedItemSet (const SelectedItemSet& other)
|
|
: selectedItems (other.selectedItems)
|
|
{
|
|
}
|
|
|
|
/** Creates a copy of another set. */
|
|
SelectedItemSet& operator= (const SelectedItemSet& other)
|
|
{
|
|
if (selectedItems != other.selectedItems)
|
|
{
|
|
selectedItems = other.selectedItems;
|
|
changed();
|
|
}
|
|
|
|
return *this;
|
|
}
|
|
|
|
/** Clears any other currently selected items, and selects this item.
|
|
|
|
If this item is already the only thing selected, no change notification
|
|
will be sent out.
|
|
|
|
@see addToSelection, addToSelectionBasedOnModifiers
|
|
*/
|
|
void selectOnly (ParameterType item)
|
|
{
|
|
if (isSelected (item))
|
|
{
|
|
for (int i = selectedItems.size(); --i >= 0;)
|
|
{
|
|
if (selectedItems.getUnchecked(i) != item)
|
|
{
|
|
deselect (selectedItems.getUnchecked(i));
|
|
i = jmin (i, selectedItems.size());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
deselectAll();
|
|
changed();
|
|
|
|
selectedItems.add (item);
|
|
itemSelected (item);
|
|
}
|
|
}
|
|
|
|
/** Selects an item.
|
|
|
|
If the item is already selected, no change notification will be sent out.
|
|
|
|
@see selectOnly, addToSelectionBasedOnModifiers
|
|
*/
|
|
void addToSelection (ParameterType item)
|
|
{
|
|
if (! isSelected (item))
|
|
{
|
|
changed();
|
|
|
|
selectedItems.add (item);
|
|
itemSelected (item);
|
|
}
|
|
}
|
|
|
|
/** Selects or deselects an item.
|
|
|
|
This will use the modifier keys to decide whether to deselect other items
|
|
first.
|
|
|
|
So if the shift key is held down, the item will be added without deselecting
|
|
anything (same as calling addToSelection() )
|
|
|
|
If no modifiers are down, the current selection will be cleared first (same
|
|
as calling selectOnly() )
|
|
|
|
If the ctrl (or command on the Mac) key is held down, the item will be toggled -
|
|
so it'll be added to the set unless it's already there, in which case it'll be
|
|
deselected.
|
|
|
|
If the items that you're selecting can also be dragged, you may need to use the
|
|
addToSelectionOnMouseDown() and addToSelectionOnMouseUp() calls to handle the
|
|
subtleties of this kind of usage.
|
|
|
|
@see selectOnly, addToSelection, addToSelectionOnMouseDown, addToSelectionOnMouseUp
|
|
*/
|
|
void addToSelectionBasedOnModifiers (ParameterType item,
|
|
const ModifierKeys& modifiers)
|
|
{
|
|
if (modifiers.isShiftDown())
|
|
{
|
|
addToSelection (item);
|
|
}
|
|
else if (modifiers.isCommandDown())
|
|
{
|
|
if (isSelected (item))
|
|
deselect (item);
|
|
else
|
|
addToSelection (item);
|
|
}
|
|
else
|
|
{
|
|
selectOnly (item);
|
|
}
|
|
}
|
|
|
|
/** Selects or deselects items that can also be dragged, based on a mouse-down event.
|
|
|
|
If you call addToSelectionOnMouseDown() at the start of your mouseDown event,
|
|
and then call addToSelectionOnMouseUp() at the end of your mouseUp event, this
|
|
makes it easy to handle multiple-selection of sets of objects that can also
|
|
be dragged.
|
|
|
|
For example, if you have several items already selected, and you click on
|
|
one of them (without dragging), then you'd expect this to deselect the other, and
|
|
just select the item you clicked on. But if you had clicked on this item and
|
|
dragged it, you'd have expected them all to stay selected.
|
|
|
|
When you call this method, you'll need to store the boolean result, because the
|
|
addToSelectionOnMouseUp() method will need to be know this value.
|
|
|
|
@see addToSelectionOnMouseUp, addToSelectionBasedOnModifiers
|
|
*/
|
|
bool addToSelectionOnMouseDown (ParameterType item,
|
|
const ModifierKeys& modifiers)
|
|
{
|
|
if (isSelected (item))
|
|
{
|
|
return ! modifiers.isPopupMenu();
|
|
}
|
|
else
|
|
{
|
|
addToSelectionBasedOnModifiers (item, modifiers);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/** Selects or deselects items that can also be dragged, based on a mouse-up event.
|
|
|
|
Call this during a mouseUp callback, when you have previously called the
|
|
addToSelectionOnMouseDown() method during your mouseDown event.
|
|
|
|
See addToSelectionOnMouseDown() for more info
|
|
|
|
@param item the item to select (or deselect)
|
|
@param modifiers the modifiers from the mouse-up event
|
|
@param wasItemDragged true if your item was dragged during the mouse click
|
|
@param resultOfMouseDownSelectMethod this is the boolean return value that came
|
|
back from the addToSelectionOnMouseDown() call that you
|
|
should have made during the matching mouseDown event
|
|
*/
|
|
void addToSelectionOnMouseUp (ParameterType item,
|
|
const ModifierKeys& modifiers,
|
|
const bool wasItemDragged,
|
|
const bool resultOfMouseDownSelectMethod)
|
|
{
|
|
if (resultOfMouseDownSelectMethod && ! wasItemDragged)
|
|
addToSelectionBasedOnModifiers (item, modifiers);
|
|
}
|
|
|
|
/** Deselects an item. */
|
|
void deselect (ParameterType item)
|
|
{
|
|
const int i = selectedItems.indexOf (item);
|
|
|
|
if (i >= 0)
|
|
{
|
|
changed();
|
|
itemDeselected (selectedItems.remove (i));
|
|
}
|
|
}
|
|
|
|
/** Deselects all items. */
|
|
void deselectAll()
|
|
{
|
|
if (selectedItems.size() > 0)
|
|
{
|
|
changed();
|
|
|
|
for (int i = selectedItems.size(); --i >= 0;)
|
|
{
|
|
itemDeselected (selectedItems.remove (i));
|
|
i = jmin (i, selectedItems.size());
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Returns the number of currently selected items.
|
|
|
|
@see getSelectedItem
|
|
*/
|
|
int getNumSelected() const noexcept
|
|
{
|
|
return selectedItems.size();
|
|
}
|
|
|
|
/** Returns one of the currently selected items.
|
|
|
|
Returns 0 if the index is out-of-range.
|
|
|
|
@see getNumSelected
|
|
*/
|
|
SelectableItemType getSelectedItem (const int index) const noexcept
|
|
{
|
|
return selectedItems [index];
|
|
}
|
|
|
|
/** True if this item is currently selected. */
|
|
bool isSelected (ParameterType item) const noexcept
|
|
{
|
|
return selectedItems.contains (item);
|
|
}
|
|
|
|
const Array <SelectableItemType>& getItemArray() const noexcept { return selectedItems; }
|
|
|
|
/** Can be overridden to do special handling when an item is selected.
|
|
|
|
For example, if the item is an object, you might want to call it and tell
|
|
it that it's being selected.
|
|
*/
|
|
virtual void itemSelected (SelectableItemType item) { (void) item; }
|
|
|
|
/** Can be overridden to do special handling when an item is deselected.
|
|
|
|
For example, if the item is an object, you might want to call it and tell
|
|
it that it's being deselected.
|
|
*/
|
|
virtual void itemDeselected (SelectableItemType item) { (void) item; }
|
|
|
|
/** Used internally, but can be called to force a change message to be sent to the ChangeListeners.
|
|
*/
|
|
void changed (const bool synchronous = false)
|
|
{
|
|
if (synchronous)
|
|
sendSynchronousChangeMessage();
|
|
else
|
|
sendChangeMessage();
|
|
}
|
|
|
|
private:
|
|
|
|
Array <SelectableItemType> selectedItems;
|
|
|
|
JUCE_LEAK_DETECTOR (SelectedItemSet <SelectableItemType>);
|
|
};
|
|
|
|
#endif // __JUCE_SELECTEDITEMSET_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_SelectedItemSet.h ***/
|
|
|
|
/**
|
|
A class used by the LassoComponent to manage the things that it selects.
|
|
|
|
This allows the LassoComponent to find out which items are within the lasso,
|
|
and to change the list of selected items.
|
|
|
|
@see LassoComponent, SelectedItemSet
|
|
*/
|
|
template <class SelectableItemType>
|
|
class LassoSource
|
|
{
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~LassoSource() {}
|
|
|
|
/** Returns the set of items that lie within a given lassoable region.
|
|
|
|
Your implementation of this method must find all the relevent items that lie
|
|
within the given rectangle. and add them to the itemsFound array.
|
|
|
|
The co-ordinates are relative to the top-left of the lasso component's parent
|
|
component. (i.e. they are the same as the size and position of the lasso
|
|
component itself).
|
|
*/
|
|
virtual void findLassoItemsInArea (Array <SelectableItemType>& itemsFound,
|
|
const Rectangle<int>& area) = 0;
|
|
|
|
/** Returns the SelectedItemSet that the lasso should update.
|
|
|
|
This set will be continuously updated by the LassoComponent as it gets
|
|
dragged around, so make sure that you've got a ChangeListener attached to
|
|
the set so that your UI objects will know when the selection changes and
|
|
be able to update themselves appropriately.
|
|
*/
|
|
virtual SelectedItemSet <SelectableItemType>& getLassoSelection() = 0;
|
|
};
|
|
|
|
/**
|
|
A component that acts as a rectangular selection region, which you drag with
|
|
the mouse to select groups of objects (in conjunction with a SelectedItemSet).
|
|
|
|
To use one of these:
|
|
|
|
- In your mouseDown or mouseDrag event, add the LassoComponent to your parent
|
|
component, and call its beginLasso() method, giving it a
|
|
suitable LassoSource object that it can use to find out which items are in
|
|
the active area.
|
|
|
|
- Each time your parent component gets a mouseDrag event, call dragLasso()
|
|
to update the lasso's position - it will use its LassoSource to calculate and
|
|
update the current selection.
|
|
|
|
- After the drag has finished and you get a mouseUp callback, you should call
|
|
endLasso() to clean up. This will make the lasso component invisible, and you
|
|
can remove it from the parent component, or delete it.
|
|
|
|
The class takes into account the modifier keys that are being held down while
|
|
the lasso is being dragged, so if shift is pressed, then any lassoed items will
|
|
be added to the original selection; if ctrl or command is pressed, they will be
|
|
xor'ed with any previously selected items.
|
|
|
|
@see LassoSource, SelectedItemSet
|
|
*/
|
|
template <class SelectableItemType>
|
|
class LassoComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a Lasso component.
|
|
|
|
The fill colour is used to fill the lasso'ed rectangle, and the outline
|
|
colour is used to draw a line around its edge.
|
|
*/
|
|
explicit LassoComponent (const int outlineThickness_ = 1)
|
|
: source (nullptr),
|
|
outlineThickness (outlineThickness_)
|
|
{
|
|
}
|
|
|
|
/** Destructor. */
|
|
~LassoComponent()
|
|
{
|
|
}
|
|
|
|
/** Call this in your mouseDown event, to initialise a drag.
|
|
|
|
Pass in a suitable LassoSource object which the lasso will use to find
|
|
the items and change the selection.
|
|
|
|
After using this method to initialise the lasso, repeatedly call dragLasso()
|
|
in your component's mouseDrag callback.
|
|
|
|
@see dragLasso, endLasso, LassoSource
|
|
*/
|
|
void beginLasso (const MouseEvent& e,
|
|
LassoSource <SelectableItemType>* const lassoSource)
|
|
{
|
|
jassert (source == nullptr); // this suggests that you didn't call endLasso() after the last drag...
|
|
jassert (lassoSource != nullptr); // the source can't be null!
|
|
jassert (getParentComponent() != nullptr); // you need to add this to a parent component for it to work!
|
|
|
|
source = lassoSource;
|
|
|
|
if (lassoSource != nullptr)
|
|
originalSelection = lassoSource->getLassoSelection().getItemArray();
|
|
|
|
setSize (0, 0);
|
|
dragStartPos = e.getMouseDownPosition();
|
|
}
|
|
|
|
/** Call this in your mouseDrag event, to update the lasso's position.
|
|
|
|
This must be repeatedly calling when the mouse is dragged, after you've
|
|
first initialised the lasso with beginLasso().
|
|
|
|
This method takes into account the modifier keys that are being held down, so
|
|
if shift is pressed, then the lassoed items will be added to any that were
|
|
previously selected; if ctrl or command is pressed, then they will be xor'ed
|
|
with previously selected items.
|
|
|
|
@see beginLasso, endLasso
|
|
*/
|
|
void dragLasso (const MouseEvent& e)
|
|
{
|
|
if (source != nullptr)
|
|
{
|
|
setBounds (Rectangle<int> (dragStartPos, e.getPosition()));
|
|
setVisible (true);
|
|
|
|
Array <SelectableItemType> itemsInLasso;
|
|
source->findLassoItemsInArea (itemsInLasso, getBounds());
|
|
|
|
if (e.mods.isShiftDown())
|
|
{
|
|
itemsInLasso.removeValuesIn (originalSelection); // to avoid duplicates
|
|
itemsInLasso.addArray (originalSelection);
|
|
}
|
|
else if (e.mods.isCommandDown() || e.mods.isAltDown())
|
|
{
|
|
Array <SelectableItemType> originalMinusNew (originalSelection);
|
|
originalMinusNew.removeValuesIn (itemsInLasso);
|
|
|
|
itemsInLasso.removeValuesIn (originalSelection);
|
|
itemsInLasso.addArray (originalMinusNew);
|
|
}
|
|
|
|
source->getLassoSelection() = SelectedItemSet <SelectableItemType> (itemsInLasso);
|
|
}
|
|
}
|
|
|
|
/** Call this in your mouseUp event, after the lasso has been dragged.
|
|
|
|
@see beginLasso, dragLasso
|
|
*/
|
|
void endLasso()
|
|
{
|
|
source = nullptr;
|
|
originalSelection.clear();
|
|
setVisible (false);
|
|
}
|
|
|
|
/** 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
|
|
{
|
|
lassoFillColourId = 0x1000440, /**< The colour to fill the lasso rectangle with. */
|
|
lassoOutlineColourId = 0x1000441, /**< The colour to draw the outline with. */
|
|
};
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g)
|
|
{
|
|
g.fillAll (findColour (lassoFillColourId));
|
|
|
|
g.setColour (findColour (lassoOutlineColourId));
|
|
g.drawRect (0, 0, getWidth(), getHeight(), outlineThickness);
|
|
|
|
// this suggests that you've left a lasso comp lying around after the
|
|
// mouse drag has finished.. Be careful to call endLasso() when you get a
|
|
// mouse-up event.
|
|
jassert (isMouseButtonDownAnywhere());
|
|
}
|
|
|
|
/** @internal */
|
|
bool hitTest (int, int) { return false; }
|
|
|
|
private:
|
|
|
|
Array <SelectableItemType> originalSelection;
|
|
LassoSource <SelectableItemType>* source;
|
|
int outlineThickness;
|
|
Point<int> dragStartPos;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LassoComponent);
|
|
};
|
|
|
|
#endif // __JUCE_LASSOCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_LassoComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MOUSECURSOR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MOUSEEVENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MouseInputSource.h ***/
|
|
#ifndef __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__
|
|
#define __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__
|
|
|
|
class MouseInputSourceInternal;
|
|
|
|
/**
|
|
Represents a linear source of mouse events from a mouse device or individual finger
|
|
in a multi-touch environment.
|
|
|
|
Each MouseEvent object contains a reference to the MouseInputSource that generated
|
|
it. In an environment with a single mouse for input, all events will come from the
|
|
same source, but in a multi-touch system, there may be multiple MouseInputSource
|
|
obects active, each representing a stream of events coming from a particular finger.
|
|
|
|
Events coming from a single MouseInputSource are always sent in a fixed and predictable
|
|
order: a mouseMove will never be called without a mouseEnter having been sent beforehand,
|
|
the only events that can happen between a mouseDown and its corresponding mouseUp are
|
|
mouseDrags, etc.
|
|
When there are multiple touches arriving from multiple MouseInputSources, their
|
|
event streams may arrive in an interleaved order, so you should use the getIndex()
|
|
method to find out which finger each event came from.
|
|
|
|
@see MouseEvent
|
|
*/
|
|
class JUCE_API MouseInputSource
|
|
{
|
|
public:
|
|
|
|
/** Creates a MouseInputSource.
|
|
You should never actually create a MouseInputSource in your own code - the
|
|
library takes care of managing these objects.
|
|
*/
|
|
MouseInputSource (int index, bool isMouseDevice);
|
|
|
|
/** Destructor. */
|
|
~MouseInputSource();
|
|
|
|
/** Returns true if this object represents a normal desk-based mouse device. */
|
|
bool isMouse() const;
|
|
|
|
/** Returns true if this object represents a source of touch events - i.e. a finger or stylus. */
|
|
bool isTouch() const;
|
|
|
|
/** Returns true if this source has an on-screen pointer that can hover over
|
|
items without clicking them.
|
|
*/
|
|
bool canHover() const;
|
|
|
|
/** Returns true if this source may have a scroll wheel. */
|
|
bool hasMouseWheel() const;
|
|
|
|
/** Returns this source's index in the global list of possible sources.
|
|
If the system only has a single mouse, there will only be a single MouseInputSource
|
|
with an index of 0.
|
|
|
|
If the system supports multi-touch input, then the index will represent a finger
|
|
number, starting from 0. When the first touch event begins, it will have finger
|
|
number 0, and then if a second touch happens while the first is still down, it
|
|
will have index 1, etc.
|
|
*/
|
|
int getIndex() const;
|
|
|
|
/** Returns true if this device is currently being pressed. */
|
|
bool isDragging() const;
|
|
|
|
/** Returns the last-known screen position of this source. */
|
|
Point<int> getScreenPosition() const;
|
|
|
|
/** Returns a set of modifiers that indicate which buttons are currently
|
|
held down on this device.
|
|
*/
|
|
ModifierKeys getCurrentModifiers() const;
|
|
|
|
/** Returns the component that was last known to be under this pointer. */
|
|
Component* getComponentUnderMouse() const;
|
|
|
|
/** Tells the device to dispatch a mouse-move or mouse-drag event.
|
|
This is asynchronous - the event will occur on the message thread.
|
|
*/
|
|
void triggerFakeMove() const;
|
|
|
|
/** Returns the number of clicks that should be counted as belonging to the
|
|
current mouse event.
|
|
So the mouse is currently down and it's the second click of a double-click, this
|
|
will return 2.
|
|
*/
|
|
int getNumberOfMultipleClicks() const noexcept;
|
|
|
|
/** Returns the time at which the last mouse-down occurred. */
|
|
Time getLastMouseDownTime() const noexcept;
|
|
|
|
/** Returns the screen position at which the last mouse-down occurred. */
|
|
Point<int> getLastMouseDownPosition() const noexcept;
|
|
|
|
/** Returns true if this mouse is currently down, and if it has been dragged more
|
|
than a couple of pixels from the place it was pressed.
|
|
*/
|
|
bool hasMouseMovedSignificantlySincePressed() const noexcept;
|
|
|
|
/** Returns true if this input source uses a visible mouse cursor. */
|
|
bool hasMouseCursor() const noexcept;
|
|
|
|
/** Changes the mouse cursor, (if there is one). */
|
|
void showMouseCursor (const MouseCursor& cursor);
|
|
|
|
/** Hides the mouse cursor (if there is one). */
|
|
void hideCursor();
|
|
|
|
/** Un-hides the mouse cursor if it was hidden by hideCursor(). */
|
|
void revealCursor();
|
|
|
|
/** Forces an update of the mouse cursor for whatever component it's currently over. */
|
|
void forceMouseCursorUpdate();
|
|
|
|
/** Returns true if this mouse can be moved indefinitely in any direction without running out of space. */
|
|
bool canDoUnboundedMovement() const noexcept;
|
|
|
|
/** Allows the mouse to move beyond the edges of the screen.
|
|
|
|
Calling this method when the mouse button is currently pressed will remove the cursor
|
|
from the screen and allow the mouse to (seem to) move beyond the edges of the screen.
|
|
|
|
This means that the co-ordinates returned to mouseDrag() will be unbounded, and this
|
|
can be used for things like custom slider controls or dragging objects around, where
|
|
movement would be otherwise be limited by the mouse hitting the edges of the screen.
|
|
|
|
The unbounded mode is automatically turned off when the mouse button is released, or
|
|
it can be turned off explicitly by calling this method again.
|
|
|
|
@param isEnabled whether to turn this mode on or off
|
|
@param keepCursorVisibleUntilOffscreen if set to false, the cursor will immediately be
|
|
hidden; if true, it will only be hidden when it
|
|
is moved beyond the edge of the screen
|
|
*/
|
|
void enableUnboundedMouseMovement (bool isEnabled, bool keepCursorVisibleUntilOffscreen = false);
|
|
|
|
/** @internal */
|
|
void handleEvent (ComponentPeer* peer, const Point<int>& positionWithinPeer, int64 time, const ModifierKeys& mods);
|
|
/** @internal */
|
|
void handleWheel (ComponentPeer* peer, const Point<int>& positionWithinPeer, int64 time, float x, float y);
|
|
|
|
private:
|
|
|
|
friend class Desktop;
|
|
friend class ComponentPeer;
|
|
friend class MouseInputSourceInternal;
|
|
ScopedPointer<MouseInputSourceInternal> pimpl;
|
|
|
|
static Point<int> getCurrentMousePosition();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MouseInputSource);
|
|
};
|
|
|
|
#endif // __JUCE_MOUSEINPUTSOURCE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MouseInputSource.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_MOUSELISTENER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOOLTIPCLIENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MARKERLIST_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RELATIVECOORDINATE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RELATIVECOORDINATEPOSITIONER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_RelativeParallelogram.h ***/
|
|
#ifndef __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__
|
|
#define __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__
|
|
|
|
/**
|
|
A parallelogram defined by three RelativePoint positions.
|
|
|
|
@see RelativePoint, RelativeCoordinate
|
|
*/
|
|
class JUCE_API RelativeParallelogram
|
|
{
|
|
public:
|
|
|
|
RelativeParallelogram();
|
|
RelativeParallelogram (const Rectangle<float>& simpleRectangle);
|
|
RelativeParallelogram (const RelativePoint& topLeft, const RelativePoint& topRight, const RelativePoint& bottomLeft);
|
|
RelativeParallelogram (const String& topLeft, const String& topRight, const String& bottomLeft);
|
|
~RelativeParallelogram();
|
|
|
|
void resolveThreePoints (Point<float>* points, Expression::Scope* scope) const;
|
|
void resolveFourCorners (Point<float>* points, Expression::Scope* scope) const;
|
|
const Rectangle<float> getBounds (Expression::Scope* scope) const;
|
|
void getPath (Path& path, Expression::Scope* scope) const;
|
|
const AffineTransform resetToPerpendicular (Expression::Scope* scope);
|
|
bool isDynamic() const;
|
|
|
|
bool operator== (const RelativeParallelogram& other) const noexcept;
|
|
bool operator!= (const RelativeParallelogram& other) const noexcept;
|
|
|
|
static const Point<float> getInternalCoordForPoint (const Point<float>* parallelogramCorners, Point<float> point) noexcept;
|
|
static const Point<float> getPointForInternalCoord (const Point<float>* parallelogramCorners, const Point<float>& internalPoint) noexcept;
|
|
static const Rectangle<float> getBoundingBox (const Point<float>* parallelogramCorners) noexcept;
|
|
|
|
RelativePoint topLeft, topRight, bottomLeft;
|
|
};
|
|
|
|
#endif // __JUCE_RELATIVEPARALLELOGRAM_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_RelativeParallelogram.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_RELATIVEPOINT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RELATIVEPOINTPATH_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_RelativePointPath.h ***/
|
|
#ifndef __JUCE_RELATIVEPOINTPATH_JUCEHEADER__
|
|
#define __JUCE_RELATIVEPOINTPATH_JUCEHEADER__
|
|
|
|
class DrawablePath;
|
|
|
|
/**
|
|
A path object that consists of RelativePoint coordinates rather than the normal fixed ones.
|
|
|
|
One of these paths can be converted into a Path object for drawing and manipulation, but
|
|
unlike a Path, its points can be dynamic instead of just fixed.
|
|
|
|
@see RelativePoint, RelativeCoordinate
|
|
*/
|
|
class JUCE_API RelativePointPath
|
|
{
|
|
public:
|
|
|
|
RelativePointPath();
|
|
RelativePointPath (const RelativePointPath& other);
|
|
explicit RelativePointPath (const Path& path);
|
|
~RelativePointPath();
|
|
|
|
bool operator== (const RelativePointPath& other) const noexcept;
|
|
bool operator!= (const RelativePointPath& other) const noexcept;
|
|
|
|
/** Resolves this points in this path and adds them to a normal Path object. */
|
|
void createPath (Path& path, Expression::Scope* scope) const;
|
|
|
|
/** Returns true if the path contains any non-fixed points. */
|
|
bool containsAnyDynamicPoints() const;
|
|
|
|
/** Quickly swaps the contents of this path with another. */
|
|
void swapWith (RelativePointPath& other) noexcept;
|
|
|
|
/** The types of element that may be contained in this path.
|
|
@see RelativePointPath::ElementBase
|
|
*/
|
|
enum ElementType
|
|
{
|
|
nullElement,
|
|
startSubPathElement,
|
|
closeSubPathElement,
|
|
lineToElement,
|
|
quadraticToElement,
|
|
cubicToElement
|
|
};
|
|
|
|
/** Base class for the elements that make up a RelativePointPath.
|
|
*/
|
|
class JUCE_API ElementBase
|
|
{
|
|
public:
|
|
ElementBase (ElementType type);
|
|
virtual ~ElementBase() {}
|
|
virtual ValueTree createTree() const = 0;
|
|
virtual void addToPath (Path& path, Expression::Scope*) const = 0;
|
|
virtual RelativePoint* getControlPoints (int& numPoints) = 0;
|
|
virtual ElementBase* clone() const = 0;
|
|
bool isDynamic();
|
|
|
|
const ElementType type;
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE (ElementBase);
|
|
};
|
|
|
|
class JUCE_API StartSubPath : public ElementBase
|
|
{
|
|
public:
|
|
StartSubPath (const RelativePoint& pos);
|
|
ValueTree createTree() const;
|
|
void addToPath (Path& path, Expression::Scope*) const;
|
|
RelativePoint* getControlPoints (int& numPoints);
|
|
ElementBase* clone() const;
|
|
|
|
RelativePoint startPos;
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE (StartSubPath);
|
|
};
|
|
|
|
class JUCE_API CloseSubPath : public ElementBase
|
|
{
|
|
public:
|
|
CloseSubPath();
|
|
ValueTree createTree() const;
|
|
void addToPath (Path& path, Expression::Scope*) const;
|
|
RelativePoint* getControlPoints (int& numPoints);
|
|
ElementBase* clone() const;
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE (CloseSubPath);
|
|
};
|
|
|
|
class JUCE_API LineTo : public ElementBase
|
|
{
|
|
public:
|
|
LineTo (const RelativePoint& endPoint);
|
|
ValueTree createTree() const;
|
|
void addToPath (Path& path, Expression::Scope*) const;
|
|
RelativePoint* getControlPoints (int& numPoints);
|
|
ElementBase* clone() const;
|
|
|
|
RelativePoint endPoint;
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE (LineTo);
|
|
};
|
|
|
|
class JUCE_API QuadraticTo : public ElementBase
|
|
{
|
|
public:
|
|
QuadraticTo (const RelativePoint& controlPoint, const RelativePoint& endPoint);
|
|
ValueTree createTree() const;
|
|
void addToPath (Path& path, Expression::Scope*) const;
|
|
RelativePoint* getControlPoints (int& numPoints);
|
|
ElementBase* clone() const;
|
|
|
|
RelativePoint controlPoints[2];
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE (QuadraticTo);
|
|
};
|
|
|
|
class JUCE_API CubicTo : public ElementBase
|
|
{
|
|
public:
|
|
CubicTo (const RelativePoint& controlPoint1, const RelativePoint& controlPoint2, const RelativePoint& endPoint);
|
|
ValueTree createTree() const;
|
|
void addToPath (Path& path, Expression::Scope*) const;
|
|
RelativePoint* getControlPoints (int& numPoints);
|
|
ElementBase* clone() const;
|
|
|
|
RelativePoint controlPoints[3];
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE (CubicTo);
|
|
};
|
|
|
|
void addElement (ElementBase* newElement);
|
|
|
|
OwnedArray <ElementBase> elements;
|
|
bool usesNonZeroWinding;
|
|
|
|
private:
|
|
class Positioner;
|
|
friend class Positioner;
|
|
bool containsDynamicPoints;
|
|
|
|
void applyTo (DrawablePath& path) const;
|
|
|
|
RelativePointPath& operator= (const RelativePointPath&);
|
|
JUCE_LEAK_DETECTOR (RelativePointPath);
|
|
};
|
|
|
|
#endif // __JUCE_RELATIVEPOINTPATH_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_RelativePointPath.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_RELATIVERECTANGLE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_RelativeRectangle.h ***/
|
|
#ifndef __JUCE_RELATIVERECTANGLE_JUCEHEADER__
|
|
#define __JUCE_RELATIVERECTANGLE_JUCEHEADER__
|
|
|
|
class Component;
|
|
|
|
/**
|
|
An rectangle stored as a set of RelativeCoordinate values.
|
|
|
|
The rectangle's top, left, bottom and right edge positions are each stored as a RelativeCoordinate.
|
|
|
|
@see RelativeCoordinate, RelativePoint
|
|
*/
|
|
class JUCE_API RelativeRectangle
|
|
{
|
|
public:
|
|
|
|
/** Creates a zero-size rectangle at the origin. */
|
|
RelativeRectangle();
|
|
|
|
/** Creates an absolute rectangle, relative to the origin. */
|
|
explicit RelativeRectangle (const Rectangle<float>& rect);
|
|
|
|
/** Creates a rectangle from four coordinates. */
|
|
RelativeRectangle (const RelativeCoordinate& left, const RelativeCoordinate& right,
|
|
const RelativeCoordinate& top, const RelativeCoordinate& bottom);
|
|
|
|
/** Creates a rectangle from a stringified representation.
|
|
The string must contain a sequence of 4 coordinates, separated by commas, in the order
|
|
left, top, right, bottom. The syntax for the coordinate strings is explained in the
|
|
RelativeCoordinate class.
|
|
@see toString
|
|
*/
|
|
explicit RelativeRectangle (const String& stringVersion);
|
|
|
|
bool operator== (const RelativeRectangle& other) const noexcept;
|
|
bool operator!= (const RelativeRectangle& other) const noexcept;
|
|
|
|
/** Calculates the absolute position of this rectangle.
|
|
|
|
You'll need to provide a suitable Expression::Scope for looking up any coordinates that may
|
|
be needed to calculate the result.
|
|
*/
|
|
const Rectangle<float> resolve (const Expression::Scope* scope) const;
|
|
|
|
/** Changes the values of this rectangle's coordinates to make it resolve to the specified position.
|
|
|
|
Calling this will leave any anchor points unchanged, but will set any absolute
|
|
or relative positions to whatever values are necessary to make the resultant position
|
|
match the position that is provided.
|
|
*/
|
|
void moveToAbsolute (const Rectangle<float>& newPos, const Expression::Scope* scope);
|
|
|
|
/** Returns true if this rectangle depends on any external symbols for its position.
|
|
Coordinates that refer to symbols based on "this" are assumed not to be dynamic.
|
|
*/
|
|
bool isDynamic() const;
|
|
|
|
/** Returns a string which represents this point.
|
|
This returns a comma-separated list of coordinates, in the order left, top, right, bottom. For details of
|
|
the string syntax used by the coordinates, see the RelativeCoordinate constructor notes.
|
|
The string that is returned can be passed to the RelativeRectangle constructor to recreate the rectangle.
|
|
*/
|
|
String toString() const;
|
|
|
|
/** Renames a symbol if it is used by any of the coordinates.
|
|
This calls Expression::withRenamedSymbol() on the rectangle's coordinates.
|
|
*/
|
|
void renameSymbol (const Expression::Symbol& oldSymbol, const String& newName, const Expression::Scope& scope);
|
|
|
|
/** Creates and sets an appropriate Component::Positioner object for the given component, which will
|
|
keep it positioned with this rectangle.
|
|
*/
|
|
void applyToComponent (Component& component) const;
|
|
|
|
// The actual rectangle coords...
|
|
RelativeCoordinate left, right, top, bottom;
|
|
};
|
|
|
|
#endif // __JUCE_RELATIVERECTANGLE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_RelativeRectangle.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_BooleanPropertyComponent.h ***/
|
|
#ifndef __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A PropertyComponent that contains an on/off toggle button.
|
|
|
|
This type of property component can be used if you have a boolean value to
|
|
toggle on/off.
|
|
|
|
@see PropertyComponent
|
|
*/
|
|
class JUCE_API BooleanPropertyComponent : public PropertyComponent,
|
|
private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
{
|
|
protected:
|
|
|
|
/** Creates a button component.
|
|
|
|
If you use this constructor, you must override the getState() and setState()
|
|
methods.
|
|
|
|
@param propertyName the property name to be passed to the PropertyComponent
|
|
@param buttonTextWhenTrue the text shown in the button when the value is true
|
|
@param buttonTextWhenFalse the text shown in the button when the value is false
|
|
*/
|
|
BooleanPropertyComponent (const String& propertyName,
|
|
const String& buttonTextWhenTrue,
|
|
const String& buttonTextWhenFalse);
|
|
|
|
public:
|
|
/** Creates a button component.
|
|
|
|
@param valueToControl a Value object that this property should refer to.
|
|
@param propertyName the property name to be passed to the PropertyComponent
|
|
@param buttonText the text shown in the ToggleButton component
|
|
*/
|
|
BooleanPropertyComponent (const Value& valueToControl,
|
|
const String& propertyName,
|
|
const String& buttonText);
|
|
|
|
/** Destructor. */
|
|
~BooleanPropertyComponent();
|
|
|
|
/** Called to change the state of the boolean value. */
|
|
virtual void setState (bool newState);
|
|
|
|
/** Must return the current value of the property. */
|
|
virtual bool getState() const;
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void refresh();
|
|
/** @internal */
|
|
void buttonClicked (Button*);
|
|
|
|
private:
|
|
ToggleButton button;
|
|
String onText, offText;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BooleanPropertyComponent);
|
|
};
|
|
|
|
#endif // __JUCE_BOOLEANPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_BooleanPropertyComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ButtonPropertyComponent.h ***/
|
|
#ifndef __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A PropertyComponent that contains a button.
|
|
|
|
This type of property component can be used if you need a button to trigger some
|
|
kind of action.
|
|
|
|
@see PropertyComponent
|
|
*/
|
|
class JUCE_API ButtonPropertyComponent : public PropertyComponent,
|
|
private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
{
|
|
public:
|
|
|
|
/** Creates a button component.
|
|
|
|
@param propertyName the property name to be passed to the PropertyComponent
|
|
@param triggerOnMouseDown this is passed to the Button::setTriggeredOnMouseDown() method
|
|
*/
|
|
ButtonPropertyComponent (const String& propertyName,
|
|
bool triggerOnMouseDown);
|
|
|
|
/** Destructor. */
|
|
~ButtonPropertyComponent();
|
|
|
|
/** Called when the user clicks the button.
|
|
*/
|
|
virtual void buttonClicked() = 0;
|
|
|
|
/** Returns the string that should be displayed in the button.
|
|
|
|
If you need to change this string, call refresh() to update the component.
|
|
*/
|
|
virtual const String getButtonText() const = 0;
|
|
|
|
/** @internal */
|
|
void refresh();
|
|
/** @internal */
|
|
void buttonClicked (Button*);
|
|
|
|
private:
|
|
TextButton button;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ButtonPropertyComponent);
|
|
};
|
|
|
|
#endif // __JUCE_BUTTONPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ButtonPropertyComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ChoicePropertyComponent.h ***/
|
|
#ifndef __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A PropertyComponent that shows its value as a combo box.
|
|
|
|
This type of property component contains a list of options and has a
|
|
combo box to choose one.
|
|
|
|
Your subclass's constructor must add some strings to the choices StringArray
|
|
and these are shown in the list.
|
|
|
|
The getIndex() method will be called to find out which option is the currently
|
|
selected one. If you call refresh() it will call getIndex() to check whether
|
|
the value has changed, and will update the combo box if needed.
|
|
|
|
If the user selects a different item from the list, setIndex() will be
|
|
called to let your class process this.
|
|
|
|
@see PropertyComponent, PropertyPanel
|
|
*/
|
|
class JUCE_API ChoicePropertyComponent : public PropertyComponent,
|
|
private ComboBoxListener // (can't use ComboBox::Listener due to idiotic VC2005 bug)
|
|
{
|
|
protected:
|
|
/** Creates the component.
|
|
|
|
Your subclass's constructor must add a list of options to the choices
|
|
member variable.
|
|
*/
|
|
ChoicePropertyComponent (const String& propertyName);
|
|
|
|
public:
|
|
/** Creates the component.
|
|
|
|
@param valueToControl the value that the combo box will read and control
|
|
@param propertyName the name of the property
|
|
@param choices the list of possible values that the drop-down list will contain
|
|
@param correspondingValues a list of values corresponding to each item in the 'choices' StringArray.
|
|
These are the values that will be read and written to the
|
|
valueToControl value. This array must contain the same number of items
|
|
as the choices array
|
|
*/
|
|
ChoicePropertyComponent (const Value& valueToControl,
|
|
const String& propertyName,
|
|
const StringArray& choices,
|
|
const Array <var>& correspondingValues);
|
|
|
|
/** Destructor. */
|
|
~ChoicePropertyComponent();
|
|
|
|
/** Called when the user selects an item from the combo box.
|
|
|
|
Your subclass must use this callback to update the value that this component
|
|
represents. The index is the index of the chosen item in the choices
|
|
StringArray.
|
|
*/
|
|
virtual void setIndex (int newIndex);
|
|
|
|
/** Returns the index of the item that should currently be shown.
|
|
|
|
This is the index of the item in the choices StringArray that will be
|
|
shown.
|
|
*/
|
|
virtual int getIndex() const;
|
|
|
|
/** Returns the list of options. */
|
|
const StringArray& getChoices() const;
|
|
|
|
/** @internal */
|
|
void refresh();
|
|
/** @internal */
|
|
void comboBoxChanged (ComboBox*);
|
|
|
|
protected:
|
|
/** The list of options that will be shown in the combo box.
|
|
|
|
Your subclass must populate this array in its constructor. If any empty
|
|
strings are added, these will be replaced with horizontal separators (see
|
|
ComboBox::addSeparator() for more info).
|
|
*/
|
|
StringArray choices;
|
|
|
|
private:
|
|
ComboBox comboBox;
|
|
bool isCustomClass;
|
|
|
|
class RemapperValueSource;
|
|
void createComboBox();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChoicePropertyComponent);
|
|
};
|
|
|
|
#endif // __JUCE_CHOICEPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ChoicePropertyComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_PROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_PROPERTYPANEL_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_SliderPropertyComponent.h ***/
|
|
#ifndef __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A PropertyComponent that shows its value as a slider.
|
|
|
|
@see PropertyComponent, Slider
|
|
*/
|
|
class JUCE_API SliderPropertyComponent : public PropertyComponent,
|
|
private SliderListener // (can't use Slider::Listener due to idiotic VC2005 bug)
|
|
{
|
|
protected:
|
|
|
|
/** Creates the property component.
|
|
|
|
The ranges, interval and skew factor are passed to the Slider component.
|
|
|
|
If you need to customise the slider in other ways, your constructor can
|
|
access the slider member variable and change it directly.
|
|
*/
|
|
SliderPropertyComponent (const String& propertyName,
|
|
double rangeMin,
|
|
double rangeMax,
|
|
double interval,
|
|
double skewFactor = 1.0);
|
|
|
|
public:
|
|
|
|
/** Creates the property component.
|
|
|
|
The ranges, interval and skew factor are passed to the Slider component.
|
|
|
|
If you need to customise the slider in other ways, your constructor can
|
|
access the slider member variable and change it directly.
|
|
*/
|
|
SliderPropertyComponent (const Value& valueToControl,
|
|
const String& propertyName,
|
|
double rangeMin,
|
|
double rangeMax,
|
|
double interval,
|
|
double skewFactor = 1.0);
|
|
|
|
/** Destructor. */
|
|
~SliderPropertyComponent();
|
|
|
|
/** Called when the user moves the slider to change its value.
|
|
|
|
Your subclass must use this method to update whatever item this property
|
|
represents.
|
|
*/
|
|
virtual void setValue (double newValue);
|
|
|
|
/** Returns the value that the slider should show. */
|
|
virtual double getValue() const;
|
|
|
|
/** @internal */
|
|
void refresh();
|
|
/** @internal */
|
|
void sliderValueChanged (Slider*);
|
|
|
|
protected:
|
|
/** The slider component being used in this component.
|
|
Your subclass has access to this in case it needs to customise it in some way.
|
|
*/
|
|
Slider slider;
|
|
|
|
private:
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SliderPropertyComponent);
|
|
};
|
|
|
|
#endif // __JUCE_SLIDERPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_SliderPropertyComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_TextPropertyComponent.h ***/
|
|
#ifndef __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A PropertyComponent that shows its value as editable text.
|
|
|
|
@see PropertyComponent
|
|
*/
|
|
class JUCE_API TextPropertyComponent : public PropertyComponent
|
|
{
|
|
protected:
|
|
|
|
/** Creates a text property component.
|
|
|
|
The maxNumChars is used to set the length of string allowable, and isMultiLine
|
|
sets whether the text editor allows carriage returns.
|
|
|
|
@see TextEditor
|
|
*/
|
|
TextPropertyComponent (const String& propertyName,
|
|
int maxNumChars,
|
|
bool isMultiLine);
|
|
|
|
public:
|
|
/** Creates a text property component.
|
|
|
|
The maxNumChars is used to set the length of string allowable, and isMultiLine
|
|
sets whether the text editor allows carriage returns.
|
|
|
|
@see TextEditor
|
|
*/
|
|
TextPropertyComponent (const Value& valueToControl,
|
|
const String& propertyName,
|
|
int maxNumChars,
|
|
bool isMultiLine);
|
|
|
|
/** Destructor. */
|
|
~TextPropertyComponent();
|
|
|
|
/** Called when the user edits the text.
|
|
|
|
Your subclass must use this callback to change the value of whatever item
|
|
this property component represents.
|
|
*/
|
|
virtual void setText (const String& newText);
|
|
|
|
/** Returns the text that should be shown in the text editor.
|
|
*/
|
|
virtual const String getText() const;
|
|
|
|
/** @internal */
|
|
void refresh();
|
|
/** @internal */
|
|
void textWasEdited();
|
|
|
|
private:
|
|
ScopedPointer<Label> textEditor;
|
|
|
|
void createEditor (int maxNumChars, bool isMultiLine);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TextPropertyComponent);
|
|
};
|
|
|
|
#endif // __JUCE_TEXTPROPERTYCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_TextPropertyComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ActiveXControlComponent.h ***/
|
|
#ifndef __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__
|
|
|
|
#if JUCE_WINDOWS || DOXYGEN
|
|
|
|
/**
|
|
A Windows-specific class that can create and embed an ActiveX control inside
|
|
itself.
|
|
|
|
To use it, create one of these, put it in place and make sure it's visible in a
|
|
window, then use createControl() to instantiate an ActiveX control. The control
|
|
will then be moved and resized to follow the movements of this component.
|
|
|
|
Of course, since the control is a heavyweight window, it'll obliterate any
|
|
juce components that may overlap this component, but that's life.
|
|
*/
|
|
class JUCE_API ActiveXControlComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Create an initially-empty container. */
|
|
ActiveXControlComponent();
|
|
|
|
/** Destructor. */
|
|
~ActiveXControlComponent();
|
|
|
|
/** Tries to create an ActiveX control and embed it in this peer.
|
|
|
|
The peer controlIID is a pointer to an IID structure - it's treated
|
|
as a void* because when including the Juce headers, you might not always
|
|
have included windows.h first, in which case IID wouldn't be defined.
|
|
|
|
e.g. @code
|
|
const IID myIID = __uuidof (QTControl);
|
|
myControlComp->createControl (&myIID);
|
|
@endcode
|
|
*/
|
|
bool createControl (const void* controlIID);
|
|
|
|
/** Deletes the ActiveX control, if one has been created.
|
|
*/
|
|
void deleteControl();
|
|
|
|
/** Returns true if a control is currently in use. */
|
|
bool isControlOpen() const noexcept { return control != nullptr; }
|
|
|
|
/** Does a QueryInterface call on the embedded control object.
|
|
|
|
This allows you to cast the control to whatever type of COM object you need.
|
|
|
|
The iid parameter is a pointer to an IID structure - it's treated
|
|
as a void* because when including the Juce headers, you might not always
|
|
have included windows.h first, in which case IID wouldn't be defined, but
|
|
you should just pass a pointer to an IID.
|
|
|
|
e.g. @code
|
|
const IID iid = __uuidof (IOleWindow);
|
|
|
|
IOleWindow* oleWindow = (IOleWindow*) myControlComp->queryInterface (&iid);
|
|
|
|
if (oleWindow != nullptr)
|
|
{
|
|
HWND hwnd;
|
|
oleWindow->GetWindow (&hwnd);
|
|
|
|
...
|
|
|
|
oleWindow->Release();
|
|
}
|
|
@endcode
|
|
*/
|
|
void* queryInterface (const void* iid) const;
|
|
|
|
/** Set this to false to stop mouse events being allowed through to the control.
|
|
*/
|
|
void setMouseEventsAllowed (bool eventsCanReachControl);
|
|
|
|
/** Returns true if mouse events are allowed to get through to the control.
|
|
*/
|
|
bool areMouseEventsAllowed() const noexcept { return mouseEventsAllowed; }
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void* originalWndProc;
|
|
|
|
private:
|
|
class Pimpl;
|
|
friend class Pimpl;
|
|
friend class ScopedPointer <Pimpl>;
|
|
ScopedPointer <Pimpl> control;
|
|
bool mouseEventsAllowed;
|
|
|
|
void setControlBounds (const Rectangle<int>& bounds) const;
|
|
void setControlVisible (bool b) const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveXControlComponent);
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif // __JUCE_ACTIVEXCONTROLCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ActiveXControlComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_AudioDeviceSelectorComponent.h ***/
|
|
#ifndef __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component containing controls to let the user change the audio settings of
|
|
an AudioDeviceManager object.
|
|
|
|
Very easy to use - just create one of these and show it to the user.
|
|
|
|
@see AudioDeviceManager
|
|
*/
|
|
class JUCE_API AudioDeviceSelectorComponent : public Component,
|
|
public ComboBoxListener, // (can't use ComboBox::Listener due to idiotic VC2005 bug)
|
|
public ButtonListener,
|
|
public ChangeListener
|
|
{
|
|
public:
|
|
|
|
/** Creates the component.
|
|
|
|
If your app needs only output channels, you might ask for a maximum of 0 input
|
|
channels, and the component won't display any options for choosing the input
|
|
channels. And likewise if you're doing an input-only app.
|
|
|
|
@param deviceManager the device manager that this component should control
|
|
@param minAudioInputChannels the minimum number of audio input channels that the application needs
|
|
@param maxAudioInputChannels the maximum number of audio input channels that the application needs
|
|
@param minAudioOutputChannels the minimum number of audio output channels that the application needs
|
|
@param maxAudioOutputChannels the maximum number of audio output channels that the application needs
|
|
@param showMidiInputOptions if true, the component will allow the user to select which midi inputs are enabled
|
|
@param showMidiOutputSelector if true, the component will let the user choose a default midi output device
|
|
@param showChannelsAsStereoPairs if true, channels will be treated as pairs; if false, channels will be
|
|
treated as a set of separate mono channels.
|
|
@param hideAdvancedOptionsWithButton if true, only the minimum amount of UI components
|
|
are shown, with an "advanced" button that shows the rest of them
|
|
*/
|
|
AudioDeviceSelectorComponent (AudioDeviceManager& deviceManager,
|
|
const int minAudioInputChannels,
|
|
const int maxAudioInputChannels,
|
|
const int minAudioOutputChannels,
|
|
const int maxAudioOutputChannels,
|
|
const bool showMidiInputOptions,
|
|
const bool showMidiOutputSelector,
|
|
const bool showChannelsAsStereoPairs,
|
|
const bool hideAdvancedOptionsWithButton);
|
|
|
|
/** Destructor */
|
|
~AudioDeviceSelectorComponent();
|
|
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void comboBoxChanged (ComboBox*);
|
|
/** @internal */
|
|
void buttonClicked (Button*);
|
|
/** @internal */
|
|
void changeListenerCallback (ChangeBroadcaster*);
|
|
/** @internal */
|
|
void childBoundsChanged (Component*);
|
|
|
|
private:
|
|
|
|
AudioDeviceManager& deviceManager;
|
|
ScopedPointer<ComboBox> deviceTypeDropDown;
|
|
ScopedPointer<Label> deviceTypeDropDownLabel;
|
|
ScopedPointer<Component> audioDeviceSettingsComp;
|
|
String audioDeviceSettingsCompType;
|
|
const int minOutputChannels, maxOutputChannels, minInputChannels, maxInputChannels;
|
|
const bool showChannelsAsStereoPairs;
|
|
const bool hideAdvancedOptionsWithButton;
|
|
|
|
class MidiInputSelectorComponentListBox;
|
|
friend class ScopedPointer<MidiInputSelectorComponentListBox>;
|
|
ScopedPointer<MidiInputSelectorComponentListBox> midiInputsList;
|
|
ScopedPointer<ComboBox> midiOutputSelector;
|
|
ScopedPointer<Label> midiInputsLabel, midiOutputLabel;
|
|
|
|
void updateAllControls();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AudioDeviceSelectorComponent);
|
|
};
|
|
|
|
#endif // __JUCE_AUDIODEVICESELECTORCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_AudioDeviceSelectorComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_BUBBLECOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_BubbleComponent.h ***/
|
|
#ifndef __JUCE_BUBBLECOMPONENT_JUCEHEADER__
|
|
#define __JUCE_BUBBLECOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component for showing a message or other graphics inside a speech-bubble-shaped
|
|
outline, pointing at a location on the screen.
|
|
|
|
This is a base class that just draws and positions the bubble shape, but leaves
|
|
the drawing of any content up to a subclass. See BubbleMessageComponent for a subclass
|
|
that draws a text message.
|
|
|
|
To use it, create your subclass, then either add it to a parent component or
|
|
put it on the desktop with addToDesktop (0), use setPosition() to
|
|
resize and position it, then make it visible.
|
|
|
|
@see BubbleMessageComponent
|
|
*/
|
|
class JUCE_API BubbleComponent : public Component
|
|
{
|
|
protected:
|
|
|
|
/** Creates a BubbleComponent.
|
|
|
|
Your subclass will need to implement the getContentSize() and paintContent()
|
|
methods to draw the bubble's contents.
|
|
*/
|
|
BubbleComponent();
|
|
|
|
public:
|
|
/** Destructor. */
|
|
~BubbleComponent();
|
|
|
|
/** A list of permitted placements for the bubble, relative to the co-ordinates
|
|
at which it should be pointing.
|
|
|
|
@see setAllowedPlacement
|
|
*/
|
|
enum BubblePlacement
|
|
{
|
|
above = 1,
|
|
below = 2,
|
|
left = 4,
|
|
right = 8
|
|
};
|
|
|
|
/** Tells the bubble which positions it's allowed to put itself in, relative to the
|
|
point at which it's pointing.
|
|
|
|
By default when setPosition() is called, the bubble will place itself either
|
|
above, below, left, or right of the target area. You can pass in a bitwise-'or' of
|
|
the values in BubblePlacement to restrict this choice.
|
|
|
|
E.g. if you only want your bubble to appear above or below the target area,
|
|
use setAllowedPlacement (above | below);
|
|
|
|
@see BubblePlacement
|
|
*/
|
|
void setAllowedPlacement (int newPlacement);
|
|
|
|
/** Moves and resizes the bubble to point at a given component.
|
|
|
|
This will resize the bubble to fit its content, then find a position for it
|
|
so that it's next to, but doesn't overlap the given component.
|
|
|
|
It'll put itself either above, below, or to the side of the component depending
|
|
on where there's the most space, honouring any restrictions that were set
|
|
with setAllowedPlacement().
|
|
*/
|
|
void setPosition (Component* componentToPointTo);
|
|
|
|
/** Moves and resizes the bubble to point at a given point.
|
|
|
|
This will resize the bubble to fit its content, then position it
|
|
so that the tip of the bubble points to the given co-ordinate. The co-ordinates
|
|
are relative to either the bubble component's parent component if it has one, or
|
|
they are screen co-ordinates if not.
|
|
|
|
It'll put itself either above, below, or to the side of this point, depending
|
|
on where there's the most space, honouring any restrictions that were set
|
|
with setAllowedPlacement().
|
|
*/
|
|
void setPosition (int arrowTipX,
|
|
int arrowTipY);
|
|
|
|
/** Moves and resizes the bubble to point at a given rectangle.
|
|
|
|
This will resize the bubble to fit its content, then find a position for it
|
|
so that it's next to, but doesn't overlap the given rectangle. The rectangle's
|
|
co-ordinates are relative to either the bubble component's parent component
|
|
if it has one, or they are screen co-ordinates if not.
|
|
|
|
It'll put itself either above, below, or to the side of the component depending
|
|
on where there's the most space, honouring any restrictions that were set
|
|
with setAllowedPlacement().
|
|
*/
|
|
void setPosition (const Rectangle<int>& rectangleToPointTo);
|
|
|
|
protected:
|
|
|
|
/** Subclasses should override this to return the size of the content they
|
|
want to draw inside the bubble.
|
|
*/
|
|
virtual void getContentSize (int& width, int& height) = 0;
|
|
|
|
/** Subclasses should override this to draw their bubble's contents.
|
|
|
|
The graphics object's clip region and the dimensions passed in here are
|
|
set up to paint just the rectangle inside the bubble.
|
|
*/
|
|
virtual void paintContent (Graphics& g, int width, int height) = 0;
|
|
|
|
public:
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
|
|
private:
|
|
Rectangle<int> content;
|
|
int side, allowablePlacements;
|
|
float arrowTipX, arrowTipY;
|
|
DropShadowEffect shadow;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleComponent);
|
|
};
|
|
|
|
#endif // __JUCE_BUBBLECOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_BubbleComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_BubbleMessageComponent.h ***/
|
|
#ifndef __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__
|
|
#define __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A speech-bubble component that displays a short message.
|
|
|
|
This can be used to show a message with the tail of the speech bubble
|
|
pointing to a particular component or location on the screen.
|
|
|
|
@see BubbleComponent
|
|
*/
|
|
class JUCE_API BubbleMessageComponent : public BubbleComponent,
|
|
private Timer
|
|
{
|
|
public:
|
|
|
|
/** Creates a bubble component.
|
|
|
|
After creating one a BubbleComponent, do the following:
|
|
- add it to an appropriate parent component, or put it on the
|
|
desktop with Component::addToDesktop (0).
|
|
- use the showAt() method to show a message.
|
|
- it will make itself invisible after it times-out (and can optionally
|
|
also delete itself), or you can reuse it somewhere else by calling
|
|
showAt() again.
|
|
*/
|
|
BubbleMessageComponent (int fadeOutLengthMs = 150);
|
|
|
|
/** Destructor. */
|
|
~BubbleMessageComponent();
|
|
|
|
/** Shows a message bubble at a particular position.
|
|
|
|
This shows the bubble with its stem pointing to the given location
|
|
(co-ordinates being relative to its parent component).
|
|
|
|
For details about exactly how it decides where to position itself, see
|
|
BubbleComponent::updatePosition().
|
|
|
|
@param x the x co-ordinate of end of the bubble's tail
|
|
@param y the y co-ordinate of end of the bubble's tail
|
|
@param message the text to display
|
|
@param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself
|
|
from its parent compnent. If this is 0 or less, it
|
|
will stay there until manually removed.
|
|
@param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a
|
|
mouse button is pressed (anywhere on the screen)
|
|
@param deleteSelfAfterUse if true, then the component will delete itself after
|
|
it becomes invisible
|
|
*/
|
|
void showAt (int x, int y,
|
|
const String& message,
|
|
int numMillisecondsBeforeRemoving,
|
|
bool removeWhenMouseClicked = true,
|
|
bool deleteSelfAfterUse = false);
|
|
|
|
/** Shows a message bubble next to a particular component.
|
|
|
|
This shows the bubble with its stem pointing at the given component.
|
|
|
|
For details about exactly how it decides where to position itself, see
|
|
BubbleComponent::updatePosition().
|
|
|
|
@param component the component that you want to point at
|
|
@param message the text to display
|
|
@param numMillisecondsBeforeRemoving how long to leave it on the screen before removing itself
|
|
from its parent compnent. If this is 0 or less, it
|
|
will stay there until manually removed.
|
|
@param removeWhenMouseClicked if this is true, the bubble will disappear as soon as a
|
|
mouse button is pressed (anywhere on the screen)
|
|
@param deleteSelfAfterUse if true, then the component will delete itself after
|
|
it becomes invisible
|
|
*/
|
|
void showAt (Component* component,
|
|
const String& message,
|
|
int numMillisecondsBeforeRemoving,
|
|
bool removeWhenMouseClicked = true,
|
|
bool deleteSelfAfterUse = false);
|
|
|
|
/** @internal */
|
|
void getContentSize (int& w, int& h);
|
|
/** @internal */
|
|
void paintContent (Graphics& g, int w, int h);
|
|
/** @internal */
|
|
void timerCallback();
|
|
|
|
private:
|
|
|
|
int fadeOutLength, mouseClickCounter;
|
|
TextLayout textLayout;
|
|
int64 expiryTime;
|
|
bool deleteAfterUse;
|
|
|
|
void init (int numMillisecondsBeforeRemoving,
|
|
bool removeWhenMouseClicked,
|
|
bool deleteSelfAfterUse);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleMessageComponent);
|
|
};
|
|
|
|
#endif // __JUCE_BUBBLEMESSAGECOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_BubbleMessageComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ColourSelector.h ***/
|
|
#ifndef __JUCE_COLOURSELECTOR_JUCEHEADER__
|
|
#define __JUCE_COLOURSELECTOR_JUCEHEADER__
|
|
|
|
/**
|
|
A component that lets the user choose a colour.
|
|
|
|
This shows RGB sliders and a colourspace that the user can pick colours from.
|
|
|
|
This class is also a ChangeBroadcaster, so listeners can register to be told
|
|
when the colour changes.
|
|
*/
|
|
class JUCE_API ColourSelector : public Component,
|
|
public ChangeBroadcaster,
|
|
protected SliderListener
|
|
{
|
|
public:
|
|
|
|
/** Options for the type of selector to show. These are passed into the constructor. */
|
|
enum ColourSelectorOptions
|
|
{
|
|
showAlphaChannel = 1 << 0, /**< if set, the colour's alpha channel can be changed as well as its RGB. */
|
|
|
|
showColourAtTop = 1 << 1, /**< if set, a swatch of the colour is shown at the top of the component. */
|
|
showSliders = 1 << 2, /**< if set, RGB sliders are shown at the bottom of the component. */
|
|
showColourspace = 1 << 3 /**< if set, a big HSV selector is shown. */
|
|
};
|
|
|
|
/** Creates a ColourSelector object.
|
|
|
|
The flags are a combination of values from the ColourSelectorOptions enum, specifying
|
|
which of the selector's features should be visible.
|
|
|
|
The edgeGap value specifies the amount of space to leave around the edge.
|
|
|
|
gapAroundColourSpaceComponent indicates how much of a gap to put around the
|
|
colourspace and hue selector components.
|
|
*/
|
|
ColourSelector (int sectionsToShow = (showAlphaChannel | showColourAtTop | showSliders | showColourspace),
|
|
int edgeGap = 4,
|
|
int gapAroundColourSpaceComponent = 7);
|
|
|
|
/** Destructor. */
|
|
~ColourSelector();
|
|
|
|
/** Returns the colour that the user has currently selected.
|
|
|
|
The ColourSelector class is also a ChangeBroadcaster, so listeners can
|
|
register to be told when the colour changes.
|
|
|
|
@see setCurrentColour
|
|
*/
|
|
const Colour getCurrentColour() const;
|
|
|
|
/** Changes the colour that is currently being shown.
|
|
*/
|
|
void setCurrentColour (const Colour& newColour);
|
|
|
|
/** Tells the selector how many preset colour swatches you want to have on the component.
|
|
|
|
To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
|
|
setSwatchColour(), to return the number of colours you want, and to set and retrieve
|
|
their values.
|
|
*/
|
|
virtual int getNumSwatches() const;
|
|
|
|
/** Called by the selector to find out the colour of one of the swatches.
|
|
|
|
Your subclass should return the colour of the swatch with the given index.
|
|
|
|
To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
|
|
setSwatchColour(), to return the number of colours you want, and to set and retrieve
|
|
their values.
|
|
*/
|
|
virtual const Colour getSwatchColour (int index) const;
|
|
|
|
/** Called by the selector when the user puts a new colour into one of the swatches.
|
|
|
|
Your subclass should change the colour of the swatch with the given index.
|
|
|
|
To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
|
|
setSwatchColour(), to return the number of colours you want, and to set and retrieve
|
|
their values.
|
|
*/
|
|
virtual void setSwatchColour (int index, const Colour& newColour) const;
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the keyboard.
|
|
|
|
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 = 0x1007000, /**< the colour used to fill the component's background. */
|
|
labelTextColourId = 0x1007001 /**< the colour used for the labels next to the sliders. */
|
|
};
|
|
|
|
private:
|
|
|
|
class ColourSpaceView;
|
|
class HueSelectorComp;
|
|
class SwatchComponent;
|
|
friend class ColourSpaceView;
|
|
friend class ScopedPointer<ColourSpaceView>;
|
|
friend class HueSelectorComp;
|
|
friend class ScopedPointer<HueSelectorComp>;
|
|
|
|
Colour colour;
|
|
float h, s, v;
|
|
ScopedPointer<Slider> sliders[4];
|
|
ScopedPointer<ColourSpaceView> colourSpace;
|
|
ScopedPointer<HueSelectorComp> hueSelector;
|
|
OwnedArray <SwatchComponent> swatchComponents;
|
|
const int flags;
|
|
int edgeGap;
|
|
Rectangle<int> previewArea;
|
|
|
|
void setHue (float newH);
|
|
void setSV (float newS, float newV);
|
|
void updateHSV();
|
|
void update();
|
|
void sliderValueChanged (Slider*);
|
|
void paint (Graphics& g);
|
|
void resized();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourSelector);
|
|
|
|
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE
|
|
// This constructor is here temporarily to prevent old code compiling, because the parameters
|
|
// have changed - if you get an error here, update your code to use the new constructor instead..
|
|
ColourSelector (bool);
|
|
#endif
|
|
};
|
|
|
|
#endif // __JUCE_COLOURSELECTOR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ColourSelector.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DirectShowComponent.h ***/
|
|
#ifndef __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
|
|
|
|
#if JUCE_DIRECTSHOW || DOXYGEN
|
|
|
|
/**
|
|
A window that can play back a DirectShow video.
|
|
|
|
@note Controller is not implemented
|
|
*/
|
|
class JUCE_API DirectShowComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** DirectShow video renderer type.
|
|
|
|
See MSDN for adivce about choosing the right renderer.
|
|
*/
|
|
enum VideoRendererType
|
|
{
|
|
dshowDefault, /**< VMR7 for Windows XP, EVR for Windows Vista and later */
|
|
dshowVMR7, /**< Video Mixing Renderer 7 */
|
|
dshowEVR /**< Enhanced Video Renderer */
|
|
};
|
|
|
|
/** Creates a DirectShowComponent, initially blank.
|
|
|
|
Use the loadMovie() method to load a video once you've added the
|
|
component to a window, (or put it on the desktop as a heavyweight window).
|
|
Loading a video when the component isn't visible can cause problems, as
|
|
DirectShow needs a window handle to initialise properly.
|
|
|
|
@see VideoRendererType
|
|
*/
|
|
DirectShowComponent (VideoRendererType type = dshowDefault);
|
|
|
|
/** Destructor. */
|
|
~DirectShowComponent();
|
|
|
|
/** Returns true if DirectShow is installed and working on this machine. */
|
|
static bool isDirectShowAvailable();
|
|
|
|
/** Tries to load a DirectShow video from a file or URL into the player.
|
|
|
|
It's best to call this function once you've added the component to a window,
|
|
(or put it on the desktop as a heavyweight window). Loading a video when the
|
|
component isn't visible can cause problems, because DirectShow needs a window
|
|
handle to do its stuff.
|
|
|
|
@param fileOrURLPath the file or URL path to open
|
|
@returns true if the video opens successfully
|
|
*/
|
|
bool loadMovie (const String& fileOrURLPath);
|
|
|
|
/** Tries to load a DirectShow video from a file into the player.
|
|
|
|
It's best to call this function once you've added the component to a window,
|
|
(or put it on the desktop as a heavyweight window). Loading a video when the
|
|
component isn't visible can cause problems, because DirectShow needs a window
|
|
handle to do its stuff.
|
|
|
|
@param videoFile the video file to open
|
|
@returns true if the video opens successfully
|
|
*/
|
|
bool loadMovie (const File& videoFile);
|
|
|
|
/** Tries to load a DirectShow video from a URL into the player.
|
|
|
|
It's best to call this function once you've added the component to a window,
|
|
(or put it on the desktop as a heavyweight window). Loading a video when the
|
|
component isn't visible can cause problems, because DirectShow needs a window
|
|
handle to do its stuff.
|
|
|
|
@param videoURL the video URL to open
|
|
@returns true if the video opens successfully
|
|
*/
|
|
bool loadMovie (const URL& videoURL);
|
|
|
|
/** Closes the video, if one is open. */
|
|
void closeMovie();
|
|
|
|
/** Returns the file path or URL from which the video file was loaded.
|
|
If there isn't one, this returns an empty string.
|
|
*/
|
|
File getCurrentMoviePath() const;
|
|
|
|
/** Returns true if there's currently a video open. */
|
|
bool isMovieOpen() const;
|
|
|
|
/** Returns the length of the video, in seconds. */
|
|
double getMovieDuration() const;
|
|
|
|
/** Returns the video's natural size, in pixels.
|
|
|
|
You can use this to resize the component to show the video at its preferred
|
|
scale.
|
|
|
|
If no video is loaded, the size returned will be 0 x 0.
|
|
*/
|
|
void getMovieNormalSize (int& width, int& height) const;
|
|
|
|
/** This will position the component within a given area, keeping its aspect
|
|
ratio correct according to the video's normal size.
|
|
|
|
The component will be made as large as it can go within the space, and will
|
|
be aligned according to the justification value if this means there are gaps at
|
|
the top or sides.
|
|
|
|
@note Not implemented
|
|
*/
|
|
void setBoundsWithCorrectAspectRatio (const Rectangle<int>& spaceToFitWithin,
|
|
const RectanglePlacement& placement);
|
|
|
|
/** Starts the video playing. */
|
|
void play();
|
|
|
|
/** Stops the video playing. */
|
|
void stop();
|
|
|
|
/** Returns true if the video is currently playing. */
|
|
bool isPlaying() const;
|
|
|
|
/** Moves the video's position back to the start. */
|
|
void goToStart();
|
|
|
|
/** Sets the video's position to a given time. */
|
|
void setPosition (double seconds);
|
|
|
|
/** Returns the current play position of the video. */
|
|
double getPosition() const;
|
|
|
|
/** Changes the video playback rate.
|
|
|
|
A value of 1 is normal speed, greater values play it proportionately faster,
|
|
smaller values play it slower.
|
|
*/
|
|
void setSpeed (float newSpeed);
|
|
|
|
/** Changes the video's playback volume.
|
|
|
|
@param newVolume the volume in the range 0 (silent) to 1.0 (full)
|
|
*/
|
|
void setMovieVolume (float newVolume);
|
|
|
|
/** Returns the video's playback volume.
|
|
|
|
@returns the volume in the range 0 (silent) to 1.0 (full)
|
|
*/
|
|
float getMovieVolume() const;
|
|
|
|
/** Tells the video whether it should loop. */
|
|
void setLooping (bool shouldLoop);
|
|
|
|
/** Returns true if the video is currently looping.
|
|
|
|
@see setLooping
|
|
*/
|
|
bool isLooping() const;
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
|
|
private:
|
|
|
|
String videoPath;
|
|
bool videoLoaded, looping;
|
|
|
|
class DirectShowContext;
|
|
friend class DirectShowContext;
|
|
friend class ScopedPointer <DirectShowContext>;
|
|
ScopedPointer <DirectShowContext> context;
|
|
|
|
class DirectShowComponentWatcher;
|
|
friend class DirectShowComponentWatcher;
|
|
friend class ScopedPointer <DirectShowComponentWatcher>;
|
|
ScopedPointer <DirectShowComponentWatcher> componentWatcher;
|
|
|
|
bool needToUpdateViewport, needToRecreateNativeWindow;
|
|
|
|
void updateContextPosition();
|
|
void showContext (bool shouldBeVisible);
|
|
void recreateNativeWindowAsync();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DirectShowComponent);
|
|
};
|
|
|
|
#endif
|
|
#endif // __JUCE_DIRECTSHOWCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DirectShowComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DROPSHADOWER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_MidiKeyboardComponent.h ***/
|
|
#ifndef __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__
|
|
|
|
/**
|
|
A component that displays a piano keyboard, whose notes can be clicked on.
|
|
|
|
This component will mimic a physical midi keyboard, showing the current state of
|
|
a MidiKeyboardState object. When the on-screen keys are clicked on, it will play these
|
|
notes by calling the noteOn() and noteOff() methods of its MidiKeyboardState object.
|
|
|
|
Another feature is that the computer keyboard can also be used to play notes. By
|
|
default it maps the top two rows of a standard querty keyboard to the notes, but
|
|
these can be remapped if needed. It will only respond to keypresses when it has
|
|
the keyboard focus, so to disable this feature you can call setWantsKeyboardFocus (false).
|
|
|
|
The component is also a ChangeBroadcaster, so if you want to be informed when the
|
|
keyboard is scrolled, you can register a ChangeListener for callbacks.
|
|
|
|
@see MidiKeyboardState
|
|
*/
|
|
class JUCE_API MidiKeyboardComponent : public Component,
|
|
public MidiKeyboardStateListener,
|
|
public ChangeBroadcaster,
|
|
private Timer,
|
|
private AsyncUpdater
|
|
{
|
|
public:
|
|
|
|
/** The direction of the keyboard.
|
|
|
|
@see setOrientation
|
|
*/
|
|
enum Orientation
|
|
{
|
|
horizontalKeyboard,
|
|
verticalKeyboardFacingLeft,
|
|
verticalKeyboardFacingRight,
|
|
};
|
|
|
|
/** Creates a MidiKeyboardComponent.
|
|
|
|
@param state the midi keyboard model that this component will represent
|
|
@param orientation whether the keyboard is horizonal or vertical
|
|
*/
|
|
MidiKeyboardComponent (MidiKeyboardState& state,
|
|
Orientation orientation);
|
|
|
|
/** Destructor. */
|
|
~MidiKeyboardComponent();
|
|
|
|
/** Changes the velocity used in midi note-on messages that are triggered by clicking
|
|
on the component.
|
|
|
|
Values are 0 to 1.0, where 1.0 is the heaviest.
|
|
|
|
@see setMidiChannel
|
|
*/
|
|
void setVelocity (float velocity, bool useMousePositionForVelocity);
|
|
|
|
/** Changes the midi channel number that will be used for events triggered by clicking
|
|
on the component.
|
|
|
|
The channel must be between 1 and 16 (inclusive). This is the channel that will be
|
|
passed on to the MidiKeyboardState::noteOn() method when the user clicks the component.
|
|
|
|
Although this is the channel used for outgoing events, the component can display
|
|
incoming events from more than one channel - see setMidiChannelsToDisplay()
|
|
|
|
@see setVelocity
|
|
*/
|
|
void setMidiChannel (int midiChannelNumber);
|
|
|
|
/** Returns the midi channel that the keyboard is using for midi messages.
|
|
|
|
@see setMidiChannel
|
|
*/
|
|
int getMidiChannel() const noexcept { return midiChannel; }
|
|
|
|
/** Sets a mask to indicate which incoming midi channels should be represented by
|
|
key movements.
|
|
|
|
The mask is a set of bits, where bit 0 = midi channel 1, bit 1 = midi channel 2, etc.
|
|
|
|
If the MidiKeyboardState has a key down for any of the channels whose bits are set
|
|
in this mask, the on-screen keys will also go down.
|
|
|
|
By default, this mask is set to 0xffff (all channels displayed).
|
|
|
|
@see setMidiChannel
|
|
*/
|
|
void setMidiChannelsToDisplay (int midiChannelMask);
|
|
|
|
/** Returns the current set of midi channels represented by the component.
|
|
|
|
This is the value that was set with setMidiChannelsToDisplay().
|
|
*/
|
|
int getMidiChannelsToDisplay() const noexcept { return midiInChannelMask; }
|
|
|
|
/** Changes the width used to draw the white keys. */
|
|
void setKeyWidth (float widthInPixels);
|
|
|
|
/** Returns the width that was set by setKeyWidth(). */
|
|
float getKeyWidth() const noexcept { return keyWidth; }
|
|
|
|
/** Changes the keyboard's current direction. */
|
|
void setOrientation (Orientation newOrientation);
|
|
|
|
/** Returns the keyboard's current direction. */
|
|
const Orientation getOrientation() const noexcept { return orientation; }
|
|
|
|
/** Sets the range of midi notes that the keyboard will be limited to.
|
|
|
|
By default the range is 0 to 127 (inclusive), but you can limit this if you
|
|
only want a restricted set of the keys to be shown.
|
|
|
|
Note that the values here are inclusive and must be between 0 and 127.
|
|
*/
|
|
void setAvailableRange (int lowestNote,
|
|
int highestNote);
|
|
|
|
/** Returns the first note in the available range.
|
|
|
|
@see setAvailableRange
|
|
*/
|
|
int getRangeStart() const noexcept { return rangeStart; }
|
|
|
|
/** Returns the last note in the available range.
|
|
|
|
@see setAvailableRange
|
|
*/
|
|
int getRangeEnd() const noexcept { return rangeEnd; }
|
|
|
|
/** If the keyboard extends beyond the size of the component, this will scroll
|
|
it to show the given key at the start.
|
|
|
|
Whenever the keyboard's position is changed, this will use the ChangeBroadcaster
|
|
base class to send a callback to any ChangeListeners that have been registered.
|
|
*/
|
|
void setLowestVisibleKey (int noteNumber);
|
|
|
|
/** Returns the number of the first key shown in the component.
|
|
|
|
@see setLowestVisibleKey
|
|
*/
|
|
int getLowestVisibleKey() const noexcept { return firstKey; }
|
|
|
|
/** Returns the length of the black notes.
|
|
|
|
This will be their vertical or horizontal length, depending on the keyboard's orientation.
|
|
*/
|
|
int getBlackNoteLength() const noexcept { return blackNoteLength; }
|
|
|
|
/** If set to true, then scroll buttons will appear at either end of the keyboard
|
|
if there are too many notes to fit them all in the component at once.
|
|
*/
|
|
void setScrollButtonsVisible (bool canScroll);
|
|
|
|
/** A set of colour IDs to use to change the colour of various aspects of the keyboard.
|
|
|
|
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
|
|
{
|
|
whiteNoteColourId = 0x1005000,
|
|
blackNoteColourId = 0x1005001,
|
|
keySeparatorLineColourId = 0x1005002,
|
|
mouseOverKeyOverlayColourId = 0x1005003, /**< This colour will be overlaid on the normal note colour. */
|
|
keyDownOverlayColourId = 0x1005004, /**< This colour will be overlaid on the normal note colour. */
|
|
textLabelColourId = 0x1005005,
|
|
upDownButtonBackgroundColourId = 0x1005006,
|
|
upDownButtonArrowColourId = 0x1005007
|
|
};
|
|
|
|
/** Returns the position within the component of the left-hand edge of a key.
|
|
|
|
Depending on the keyboard's orientation, this may be a horizontal or vertical
|
|
distance, in either direction.
|
|
*/
|
|
int getKeyStartPosition (const int midiNoteNumber) const;
|
|
|
|
/** Deletes all key-mappings.
|
|
|
|
@see setKeyPressForNote
|
|
*/
|
|
void clearKeyMappings();
|
|
|
|
/** Maps a key-press to a given note.
|
|
|
|
@param key the key that should trigger the note
|
|
@param midiNoteOffsetFromC how many semitones above C the triggered note should
|
|
be. The actual midi note that gets played will be
|
|
this value + (12 * the current base octave). To change
|
|
the base octave, see setKeyPressBaseOctave()
|
|
*/
|
|
void setKeyPressForNote (const KeyPress& key,
|
|
int midiNoteOffsetFromC);
|
|
|
|
/** Removes any key-mappings for a given note.
|
|
|
|
For a description of what the note number means, see setKeyPressForNote().
|
|
*/
|
|
void removeKeyPressForNote (int midiNoteOffsetFromC);
|
|
|
|
/** Changes the base note above which key-press-triggered notes are played.
|
|
|
|
The set of key-mappings that trigger notes can be moved up and down to cover
|
|
the entire scale using this method.
|
|
|
|
The value passed in is an octave number between 0 and 10 (inclusive), and
|
|
indicates which C is the base note to which the key-mapped notes are
|
|
relative.
|
|
*/
|
|
void setKeyPressBaseOctave (int newOctaveNumber);
|
|
|
|
/** This sets the octave number which is shown as the octave number for middle C.
|
|
|
|
This affects only the default implementation of getWhiteNoteText(), which
|
|
passes this octave number to MidiMessage::getMidiNoteName() in order to
|
|
get the note text. See MidiMessage::getMidiNoteName() for more info about
|
|
the parameter.
|
|
|
|
By default this value is set to 3.
|
|
|
|
@see getOctaveForMiddleC
|
|
*/
|
|
void setOctaveForMiddleC (int octaveNumForMiddleC);
|
|
|
|
/** This returns the value set by setOctaveForMiddleC().
|
|
@see setOctaveForMiddleC
|
|
*/
|
|
int getOctaveForMiddleC() const noexcept { return octaveNumForMiddleC; }
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void mouseMove (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDrag (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseDown (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseUp (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseEnter (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseExit (const MouseEvent& e);
|
|
/** @internal */
|
|
void mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY);
|
|
/** @internal */
|
|
void timerCallback();
|
|
/** @internal */
|
|
bool keyStateChanged (bool isKeyDown);
|
|
/** @internal */
|
|
void focusLost (FocusChangeType cause);
|
|
/** @internal */
|
|
void handleNoteOn (MidiKeyboardState* source, int midiChannel, int midiNoteNumber, float velocity);
|
|
/** @internal */
|
|
void handleNoteOff (MidiKeyboardState* source, int midiChannel, int midiNoteNumber);
|
|
/** @internal */
|
|
void handleAsyncUpdate();
|
|
/** @internal */
|
|
void colourChanged();
|
|
|
|
protected:
|
|
|
|
/** Draws a white note in the given rectangle.
|
|
|
|
isOver indicates whether the mouse is over the key, isDown indicates whether the key is
|
|
currently pressed down.
|
|
|
|
When doing this, be sure to note the keyboard's orientation.
|
|
*/
|
|
virtual void drawWhiteNote (int midiNoteNumber,
|
|
Graphics& g,
|
|
int x, int y, int w, int h,
|
|
bool isDown, bool isOver,
|
|
const Colour& lineColour,
|
|
const Colour& textColour);
|
|
|
|
/** Draws a black note in the given rectangle.
|
|
|
|
isOver indicates whether the mouse is over the key, isDown indicates whether the key is
|
|
currently pressed down.
|
|
|
|
When doing this, be sure to note the keyboard's orientation.
|
|
*/
|
|
virtual void drawBlackNote (int midiNoteNumber,
|
|
Graphics& g,
|
|
int x, int y, int w, int h,
|
|
bool isDown, bool isOver,
|
|
const Colour& noteFillColour);
|
|
|
|
/** Allows text to be drawn on the white notes.
|
|
|
|
By default this is used to label the C in each octave, but could be used for other things.
|
|
|
|
@see setOctaveForMiddleC
|
|
*/
|
|
virtual const String getWhiteNoteText (const int midiNoteNumber);
|
|
|
|
/** Draws the up and down buttons that change the base note. */
|
|
virtual void drawUpDownButton (Graphics& g, int w, int h,
|
|
const bool isMouseOver,
|
|
const bool isButtonPressed,
|
|
const bool movesOctavesUp);
|
|
|
|
/** Callback when the mouse is clicked on a key.
|
|
|
|
You could use this to do things like handle right-clicks on keys, etc.
|
|
|
|
Return true if you want the click to trigger the note, or false if you
|
|
want to handle it yourself and not have the note played.
|
|
|
|
@see mouseDraggedToKey
|
|
*/
|
|
virtual bool mouseDownOnKey (int midiNoteNumber, const MouseEvent& e);
|
|
|
|
/** Callback when the mouse is dragged from one key onto another.
|
|
|
|
@see mouseDownOnKey
|
|
*/
|
|
virtual void mouseDraggedToKey (int midiNoteNumber, const MouseEvent& e);
|
|
|
|
/** Calculates the positon of a given midi-note.
|
|
|
|
This can be overridden to create layouts with custom key-widths.
|
|
|
|
@param midiNoteNumber the note to find
|
|
@param keyWidth the desired width in pixels of one key - see setKeyWidth()
|
|
@param x the x position of the left-hand edge of the key (this method
|
|
always works in terms of a horizontal keyboard)
|
|
@param w the width of the key
|
|
*/
|
|
virtual void getKeyPosition (int midiNoteNumber, float keyWidth,
|
|
int& x, int& w) const;
|
|
|
|
private:
|
|
|
|
friend class MidiKeyboardUpDownButton;
|
|
|
|
MidiKeyboardState& state;
|
|
int xOffset, blackNoteLength;
|
|
float keyWidth;
|
|
Orientation orientation;
|
|
|
|
int midiChannel, midiInChannelMask;
|
|
float velocity;
|
|
int noteUnderMouse, mouseDownNote;
|
|
BigInteger keysPressed, keysCurrentlyDrawnDown;
|
|
|
|
int rangeStart, rangeEnd, firstKey;
|
|
bool canScroll, mouseDragging, useMousePositionForVelocity;
|
|
ScopedPointer<Button> scrollDown, scrollUp;
|
|
|
|
Array <KeyPress> keyPresses;
|
|
Array <int> keyPressNotes;
|
|
int keyMappingOctave;
|
|
int octaveNumForMiddleC;
|
|
|
|
static const uint8 whiteNotes[];
|
|
static const uint8 blackNotes[];
|
|
|
|
void getKeyPos (int midiNoteNumber, int& x, int& w) const;
|
|
int xyToNote (const Point<int>& pos, float& mousePositionVelocity);
|
|
int remappedXYToNote (const Point<int>& pos, float& mousePositionVelocity) const;
|
|
void resetAnyKeysInUse();
|
|
void updateNoteUnderMouse (const Point<int>& pos);
|
|
void repaintNote (const int midiNoteNumber);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MidiKeyboardComponent);
|
|
};
|
|
|
|
#endif // __JUCE_MIDIKEYBOARDCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_MidiKeyboardComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_NSVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_NSViewComponent.h ***/
|
|
#ifndef __JUCE_NSVIEWCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_NSVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
#if ! DOXYGEN
|
|
class NSViewComponentInternal;
|
|
#endif
|
|
|
|
#if JUCE_MAC || DOXYGEN
|
|
|
|
/**
|
|
A Mac-specific class that can create and embed an NSView inside itself.
|
|
|
|
To use it, create one of these, put it in place and make sure it's visible in a
|
|
window, then use setView() to assign an NSView to it. The view will then be
|
|
moved and resized to follow the movements of this component.
|
|
|
|
Of course, since the view is a native object, it'll obliterate any
|
|
juce components that may overlap this component, but that's life.
|
|
*/
|
|
class JUCE_API NSViewComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Create an initially-empty container. */
|
|
NSViewComponent();
|
|
|
|
/** Destructor. */
|
|
~NSViewComponent();
|
|
|
|
/** Assigns an NSView to this peer.
|
|
|
|
The view will be retained and released by this component for as long as
|
|
it is needed. To remove the current view, just call setView (nullptr).
|
|
|
|
Note: a void* is used here to avoid including the cocoa headers as
|
|
part of the juce.h, but the method expects an NSView*.
|
|
*/
|
|
void setView (void* nsView);
|
|
|
|
/** Returns the current NSView.
|
|
|
|
Note: a void* is returned here to avoid including the cocoa headers as
|
|
a requirement of juce.h, so you should just cast the object to an NSView*.
|
|
*/
|
|
void* getView() const;
|
|
|
|
/** Resizes this component to fit the view that it contains. */
|
|
void resizeToFitView();
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
|
|
private:
|
|
friend class NSViewComponentInternal;
|
|
ScopedPointer <NSViewComponentInternal> info;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewComponent);
|
|
};
|
|
|
|
#endif
|
|
|
|
#endif // __JUCE_NSVIEWCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_NSViewComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_OpenGLComponent.h ***/
|
|
#ifndef __JUCE_OPENGLCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_OPENGLCOMPONENT_JUCEHEADER__
|
|
|
|
// this is used to disable OpenGL, and is defined in juce_Config.h
|
|
#if JUCE_OPENGL || DOXYGEN
|
|
|
|
/**
|
|
Represents the various properties of an OpenGL bitmap format.
|
|
|
|
@see OpenGLComponent::setPixelFormat
|
|
*/
|
|
class JUCE_API OpenGLPixelFormat
|
|
{
|
|
public:
|
|
|
|
/** Creates an OpenGLPixelFormat.
|
|
|
|
The default constructor just initialises the object as a simple 8-bit
|
|
RGBA format.
|
|
*/
|
|
OpenGLPixelFormat (int bitsPerRGBComponent = 8,
|
|
int alphaBits = 8,
|
|
int depthBufferBits = 16,
|
|
int stencilBufferBits = 0);
|
|
|
|
OpenGLPixelFormat (const OpenGLPixelFormat&);
|
|
OpenGLPixelFormat& operator= (const OpenGLPixelFormat&);
|
|
bool operator== (const OpenGLPixelFormat&) const;
|
|
|
|
int redBits; /**< The number of bits per pixel to use for the red channel. */
|
|
int greenBits; /**< The number of bits per pixel to use for the green channel. */
|
|
int blueBits; /**< The number of bits per pixel to use for the blue channel. */
|
|
int alphaBits; /**< The number of bits per pixel to use for the alpha channel. */
|
|
|
|
int depthBufferBits; /**< The number of bits per pixel to use for a depth buffer. */
|
|
int stencilBufferBits; /**< The number of bits per pixel to use for a stencil buffer. */
|
|
|
|
int accumulationBufferRedBits; /**< The number of bits per pixel to use for an accumulation buffer's red channel. */
|
|
int accumulationBufferGreenBits; /**< The number of bits per pixel to use for an accumulation buffer's green channel. */
|
|
int accumulationBufferBlueBits; /**< The number of bits per pixel to use for an accumulation buffer's blue channel. */
|
|
int accumulationBufferAlphaBits; /**< The number of bits per pixel to use for an accumulation buffer's alpha channel. */
|
|
|
|
uint8 fullSceneAntiAliasingNumSamples; /**< The number of samples to use in full-scene anti-aliasing (if available). */
|
|
|
|
/** Returns a list of all the pixel formats that can be used in this system.
|
|
|
|
A reference component is needed in case there are multiple screens with different
|
|
capabilities - in which case, the one that the component is on will be used.
|
|
*/
|
|
static void getAvailablePixelFormats (Component* component,
|
|
OwnedArray <OpenGLPixelFormat>& results);
|
|
|
|
private:
|
|
|
|
JUCE_LEAK_DETECTOR (OpenGLPixelFormat);
|
|
};
|
|
|
|
/**
|
|
A base class for types of OpenGL context.
|
|
|
|
An OpenGLComponent will supply its own context for drawing in its window.
|
|
*/
|
|
class JUCE_API OpenGLContext
|
|
{
|
|
public:
|
|
|
|
/** Destructor. */
|
|
virtual ~OpenGLContext();
|
|
|
|
/** Makes this context the currently active one. */
|
|
virtual bool makeActive() const noexcept = 0;
|
|
/** If this context is currently active, it is disactivated. */
|
|
virtual bool makeInactive() const noexcept = 0;
|
|
/** Returns true if this context is currently active. */
|
|
virtual bool isActive() const noexcept = 0;
|
|
|
|
/** Swaps the buffers (if the context can do this). */
|
|
virtual void swapBuffers() = 0;
|
|
|
|
/** Sets whether the context checks the vertical sync before swapping.
|
|
|
|
The value is the number of frames to allow between buffer-swapping. This is
|
|
fairly system-dependent, but 0 turns off syncing, 1 makes it swap on frame-boundaries,
|
|
and greater numbers indicate that it should swap less often.
|
|
|
|
Returns true if it sets the value successfully.
|
|
*/
|
|
virtual bool setSwapInterval (int numFramesPerSwap) = 0;
|
|
|
|
/** Returns the current swap-sync interval.
|
|
See setSwapInterval() for info about the value returned.
|
|
*/
|
|
virtual int getSwapInterval() const = 0;
|
|
|
|
/** Returns the pixel format being used by this context. */
|
|
virtual const OpenGLPixelFormat getPixelFormat() const = 0;
|
|
|
|
/** For windowed contexts, this moves the context within the bounds of
|
|
its parent window.
|
|
*/
|
|
virtual void updateWindowPosition (const Rectangle<int>& bounds) = 0;
|
|
|
|
/** For windowed contexts, this triggers a repaint of the window.
|
|
|
|
(Not relevent on all platforms).
|
|
*/
|
|
virtual void repaint() = 0;
|
|
|
|
/** Returns an OS-dependent handle to the raw GL context.
|
|
|
|
On win32, this will be a HGLRC; on the Mac, an AGLContext; on Linux,
|
|
a GLXContext.
|
|
*/
|
|
virtual void* getRawContext() const noexcept = 0;
|
|
|
|
/** Deletes the context.
|
|
|
|
This must only be called on the message thread, or will deadlock.
|
|
On background threads, call getCurrentContext()->deleteContext(), but be careful not
|
|
to call any other OpenGL function afterwards.
|
|
This doesn't touch other resources, such as window handles, etc.
|
|
You'll probably never have to call this method directly.
|
|
*/
|
|
virtual void deleteContext() = 0;
|
|
|
|
/** Returns the context that's currently in active use by the calling thread.
|
|
|
|
Returns 0 if there isn't an active context.
|
|
*/
|
|
static OpenGLContext* getCurrentContext();
|
|
|
|
protected:
|
|
|
|
OpenGLContext() noexcept;
|
|
|
|
private:
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLContext);
|
|
};
|
|
|
|
/**
|
|
A component that contains an OpenGL canvas.
|
|
|
|
Override this, add it to whatever component you want to, and use the renderOpenGL()
|
|
method to draw its contents.
|
|
|
|
*/
|
|
class JUCE_API OpenGLComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Used to select the type of openGL API to use, if more than one choice is available
|
|
on a particular platform.
|
|
*/
|
|
enum OpenGLType
|
|
{
|
|
openGLDefault = 0,
|
|
|
|
#if JUCE_IOS
|
|
openGLES1, /**< On the iPhone, this selects openGL ES 1.0 */
|
|
openGLES2 /**< On the iPhone, this selects openGL ES 2.0 */
|
|
#endif
|
|
};
|
|
|
|
/** Creates an OpenGLComponent.
|
|
If useBackgroundThread is true, the component will launch a background thread
|
|
to do the rendering. If false, then renderOpenGL() will be called as part of the
|
|
normal paint() method.
|
|
*/
|
|
OpenGLComponent (OpenGLType type = openGLDefault,
|
|
bool useBackgroundThread = false);
|
|
|
|
/** Destructor. */
|
|
~OpenGLComponent();
|
|
|
|
/** Changes the pixel format used by this component.
|
|
|
|
@see OpenGLPixelFormat::getAvailablePixelFormats()
|
|
*/
|
|
void setPixelFormat (const OpenGLPixelFormat& formatToUse);
|
|
|
|
/** Returns the pixel format that this component is currently using. */
|
|
const OpenGLPixelFormat getPixelFormat() const;
|
|
|
|
/** Specifies an OpenGL context which should be shared with the one that this
|
|
component is using.
|
|
|
|
This is an OpenGL feature that lets two contexts share their texture data.
|
|
|
|
Note that this pointer is stored by the component, and when the component
|
|
needs to recreate its internal context for some reason, the same context
|
|
will be used again to share lists. So if you pass a context in here,
|
|
don't delete the context while this component is still using it! You can
|
|
call shareWith (nullptr) to stop this component from sharing with it.
|
|
*/
|
|
void shareWith (OpenGLContext* contextToShareListsWith);
|
|
|
|
/** Returns the context that this component is sharing with.
|
|
@see shareWith
|
|
*/
|
|
OpenGLContext* getShareContext() const noexcept { return contextToShareListsWith; }
|
|
|
|
/** Flips the openGL buffers over. */
|
|
void swapBuffers();
|
|
|
|
/** Returns true if the component is performing the rendering on a background thread.
|
|
This property is specified in the constructor.
|
|
*/
|
|
bool isUsingDedicatedThread() const noexcept { return useThread; }
|
|
|
|
/** This replaces the normal paint() callback - use it to draw your openGL stuff.
|
|
|
|
When this is called, makeCurrentContextActive() will already have been called
|
|
for you, so you just need to draw.
|
|
*/
|
|
virtual void renderOpenGL() = 0;
|
|
|
|
/** This method is called when the component creates a new OpenGL context.
|
|
|
|
A new context may be created when the component is first used, or when it
|
|
is moved to a different window, or when the window is hidden and re-shown,
|
|
etc.
|
|
|
|
You can use this callback as an opportunity to set up things like textures
|
|
that your context needs.
|
|
|
|
New contexts are created on-demand by the makeCurrentContextActive() method - so
|
|
if the context is deleted, e.g. by changing the pixel format or window, no context
|
|
will be created until the next call to makeCurrentContextActive(), which will
|
|
synchronously create one and call this method. This means that if you're using
|
|
a non-GUI thread for rendering, you can make sure this method is be called by
|
|
your renderer thread.
|
|
|
|
When this callback happens, the context will already have been made current
|
|
using the makeCurrentContextActive() method, so there's no need to call it
|
|
again in your code.
|
|
*/
|
|
virtual void newOpenGLContextCreated() = 0;
|
|
|
|
/** This method is called when the component shuts down its OpenGL context.
|
|
|
|
You can use this callback to delete textures and any other OpenGL objects you
|
|
created in the component's context. Be aware: if you are using a render
|
|
thread, this may be called on the thread.
|
|
|
|
When this callback happens, the context will have been made current
|
|
using the makeCurrentContextActive() method, so there's no need to call it
|
|
again in your code.
|
|
*/
|
|
virtual void releaseOpenGLContext() {}
|
|
|
|
/** Returns the context that will draw into this component.
|
|
|
|
This may return 0 if the component is currently invisible or hasn't currently
|
|
got a context. The context object can be deleted and a new one created during
|
|
the lifetime of this component, and there may be times when it doesn't have one.
|
|
|
|
@see newOpenGLContextCreated()
|
|
*/
|
|
OpenGLContext* getCurrentContext() const noexcept { return context; }
|
|
|
|
/** Makes this component the current openGL context.
|
|
|
|
You might want to use this in things like your resize() method, before calling
|
|
GL commands.
|
|
|
|
If this returns false, then the context isn't active, so you should avoid
|
|
making any calls.
|
|
|
|
This call may actually create a context if one isn't currently initialised. If
|
|
it does this, it will also synchronously call the newOpenGLContextCreated()
|
|
method to let you initialise it as necessary.
|
|
|
|
@see OpenGLContext::makeActive
|
|
*/
|
|
bool makeCurrentContextActive();
|
|
|
|
/** Stops the current component being the active OpenGL context.
|
|
|
|
This is the opposite of makeCurrentContextActive()
|
|
|
|
@see OpenGLContext::makeInactive
|
|
*/
|
|
void makeCurrentContextInactive();
|
|
|
|
/** Returns true if this component's context is the active openGL context for the
|
|
current thread.
|
|
|
|
@see OpenGLContext::isActive
|
|
*/
|
|
bool isActiveContext() const noexcept;
|
|
|
|
/** Calls the rendering callback, and swaps the buffers afterwards.
|
|
This is called automatically by paint() when the component needs to be rendered.
|
|
Returns true if the operation succeeded.
|
|
*/
|
|
virtual bool renderAndSwapBuffers();
|
|
|
|
/** This returns a critical section that can be used to lock the current context.
|
|
|
|
Because the context that is used by this component can change, e.g. when the
|
|
component is shown or hidden, then if you're rendering to it on a background
|
|
thread, this allows you to lock the context for the duration of your rendering
|
|
routine.
|
|
*/
|
|
CriticalSection& getContextLock() noexcept { return contextLock; }
|
|
|
|
/** Delete the context.
|
|
You should only need to call this if you've written a custom thread - if so, make
|
|
sure that your thread calls this before it terminates.
|
|
*/
|
|
void deleteContext();
|
|
|
|
/** Returns the native handle of an embedded heavyweight window, if there is one.
|
|
|
|
E.g. On windows, this will return the HWND of the sub-window containing
|
|
the opengl context, on the mac it'll be the NSOpenGLView.
|
|
*/
|
|
void* getNativeWindowHandle() const;
|
|
|
|
protected:
|
|
/** Kicks off a thread to start rendering.
|
|
The default implementation creates and manages an internal thread that tries
|
|
to render at around 50fps, but this can be overloaded to create a custom thread.
|
|
*/
|
|
virtual void startRenderThread();
|
|
|
|
/** Cleans up the rendering thread.
|
|
Used to shut down the thread that was started by startRenderThread(). If you've
|
|
created a custom thread, then you should overload this to clean it up and delete it.
|
|
*/
|
|
virtual void stopRenderThread();
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
|
|
private:
|
|
const OpenGLType type;
|
|
|
|
class OpenGLComponentRenderThread;
|
|
friend class OpenGLComponentRenderThread;
|
|
friend class ScopedPointer <OpenGLComponentRenderThread>;
|
|
ScopedPointer <OpenGLComponentRenderThread> renderThread;
|
|
|
|
class OpenGLComponentWatcher;
|
|
friend class OpenGLComponentWatcher;
|
|
friend class ScopedPointer <OpenGLComponentWatcher>;
|
|
ScopedPointer <OpenGLComponentWatcher> componentWatcher;
|
|
ScopedPointer <OpenGLContext> context;
|
|
OpenGLContext* contextToShareListsWith;
|
|
|
|
CriticalSection contextLock;
|
|
OpenGLPixelFormat preferredPixelFormat;
|
|
bool needToUpdateViewport, needToDeleteContext, threadStarted;
|
|
const bool useThread;
|
|
|
|
OpenGLContext* createContext();
|
|
void updateContext();
|
|
void updateContextPosition();
|
|
void stopBackgroundThread();
|
|
void recreateContextAsync();
|
|
void internalRepaint (int x, int y, int w, int h);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OpenGLComponent);
|
|
};
|
|
|
|
#endif
|
|
#endif // __JUCE_OPENGLCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_OpenGLComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_PreferencesPanel.h ***/
|
|
#ifndef __JUCE_PREFERENCESPANEL_JUCEHEADER__
|
|
#define __JUCE_PREFERENCESPANEL_JUCEHEADER__
|
|
|
|
/**
|
|
A component with a set of buttons at the top for changing between pages of
|
|
preferences.
|
|
|
|
This is just a handy way of writing a Mac-style preferences panel where you
|
|
have a row of buttons along the top for the different preference categories,
|
|
each button having an icon above its name. Clicking these will show an
|
|
appropriate prefs page below it.
|
|
|
|
You can either put one of these inside your own component, or just use the
|
|
showInDialogBox() method to show it in a window and run it modally.
|
|
|
|
To use it, just add a set of named pages with the addSettingsPage() method,
|
|
and implement the createComponentForPage() method to create suitable components
|
|
for each of these pages.
|
|
*/
|
|
class JUCE_API PreferencesPanel : public Component,
|
|
private ButtonListener // (can't use Button::Listener due to idiotic VC2005 bug)
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty panel.
|
|
|
|
Use addSettingsPage() to add some pages to it in your constructor.
|
|
*/
|
|
PreferencesPanel();
|
|
|
|
/** Destructor. */
|
|
~PreferencesPanel();
|
|
|
|
/** Creates a page using a set of drawables to define the page's icon.
|
|
|
|
Note that the other version of this method is much easier if you're using
|
|
an image instead of a custom drawable.
|
|
|
|
@param pageTitle the name of this preferences page - you'll need to
|
|
make sure your createComponentForPage() method creates
|
|
a suitable component when it is passed this name
|
|
@param normalIcon the drawable to display in the page's button normally
|
|
@param overIcon the drawable to display in the page's button when the mouse is over
|
|
@param downIcon the drawable to display in the page's button when the button is down
|
|
@see DrawableButton
|
|
*/
|
|
void addSettingsPage (const String& pageTitle,
|
|
const Drawable* normalIcon,
|
|
const Drawable* overIcon,
|
|
const Drawable* downIcon);
|
|
|
|
/** Creates a page using a set of drawables to define the page's icon.
|
|
|
|
The other version of this method gives you more control over the icon, but this
|
|
one is much easier if you're just loading it from a file.
|
|
|
|
@param pageTitle the name of this preferences page - you'll need to
|
|
make sure your createComponentForPage() method creates
|
|
a suitable component when it is passed this name
|
|
@param imageData a block of data containing an image file, e.g. a jpeg, png or gif.
|
|
For this to look good, you'll probably want to use a nice
|
|
transparent png file.
|
|
@param imageDataSize the size of the image data, in bytes
|
|
*/
|
|
void addSettingsPage (const String& pageTitle,
|
|
const void* imageData,
|
|
int imageDataSize);
|
|
|
|
/** Utility method to display this panel in a DialogWindow.
|
|
|
|
Calling this will create a DialogWindow containing this panel with the
|
|
given size and title, and will run it modally, returning when the user
|
|
closes the dialog box.
|
|
*/
|
|
void showInDialogBox (const String& dialogTitle,
|
|
int dialogWidth,
|
|
int dialogHeight,
|
|
const Colour& backgroundColour = Colours::white);
|
|
|
|
/** Subclasses must override this to return a component for each preferences page.
|
|
|
|
The subclass should return a pointer to a new component representing the named
|
|
page, which the panel will then display.
|
|
|
|
The panel will delete the component later when the user goes to another page
|
|
or deletes the panel.
|
|
*/
|
|
virtual Component* createComponentForPage (const String& pageName) = 0;
|
|
|
|
/** Changes the current page being displayed. */
|
|
void setCurrentPage (const String& pageName);
|
|
|
|
/** Returns the size of the buttons shown along the top. */
|
|
int getButtonSize() const noexcept;
|
|
|
|
/** Changes the size of the buttons shown along the top. */
|
|
void setButtonSize (int newSize);
|
|
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void buttonClicked (Button* button);
|
|
|
|
private:
|
|
|
|
String currentPageName;
|
|
ScopedPointer <Component> currentPage;
|
|
OwnedArray<DrawableButton> buttons;
|
|
int buttonSize;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreferencesPanel);
|
|
};
|
|
|
|
#endif // __JUCE_PREFERENCESPANEL_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_PreferencesPanel.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_QuickTimeMovieComponent.h ***/
|
|
#ifndef __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__
|
|
#define __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__
|
|
|
|
// (NB: This stuff mustn't go inside the "#if QUICKTIME" block, or it'll break the
|
|
// amalgamated build)
|
|
#ifndef DOXYGEN
|
|
#if JUCE_WINDOWS
|
|
|
|
typedef ActiveXControlComponent QTCompBaseClass;
|
|
#elif JUCE_MAC
|
|
|
|
typedef NSViewComponent QTCompBaseClass;
|
|
#endif
|
|
#endif
|
|
|
|
// this is used to disable QuickTime, and is defined in juce_Config.h
|
|
#if JUCE_QUICKTIME || DOXYGEN
|
|
|
|
/**
|
|
A window that can play back a QuickTime movie.
|
|
|
|
*/
|
|
class JUCE_API QuickTimeMovieComponent : public QTCompBaseClass
|
|
{
|
|
public:
|
|
|
|
/** Creates a QuickTimeMovieComponent, initially blank.
|
|
|
|
Use the loadMovie() method to load a movie once you've added the
|
|
component to a window, (or put it on the desktop as a heavyweight window).
|
|
Loading a movie when the component isn't visible can cause problems, as
|
|
QuickTime needs a window handle to initialise properly.
|
|
*/
|
|
QuickTimeMovieComponent();
|
|
|
|
/** Destructor. */
|
|
~QuickTimeMovieComponent();
|
|
|
|
/** Returns true if QT is installed and working on this machine.
|
|
*/
|
|
static bool isQuickTimeAvailable() noexcept;
|
|
|
|
/** Tries to load a QuickTime movie from a file into the player.
|
|
|
|
It's best to call this function once you've added the component to a window,
|
|
(or put it on the desktop as a heavyweight window). Loading a movie when the
|
|
component isn't visible can cause problems, because QuickTime needs a window
|
|
handle to do its stuff.
|
|
|
|
@param movieFile the .mov file to open
|
|
@param isControllerVisible whether to show a controller bar at the bottom
|
|
@returns true if the movie opens successfully
|
|
*/
|
|
bool loadMovie (const File& movieFile,
|
|
bool isControllerVisible);
|
|
|
|
/** Tries to load a QuickTime movie from a URL into the player.
|
|
|
|
It's best to call this function once you've added the component to a window,
|
|
(or put it on the desktop as a heavyweight window). Loading a movie when the
|
|
component isn't visible can cause problems, because QuickTime needs a window
|
|
handle to do its stuff.
|
|
|
|
@param movieURL the .mov file to open
|
|
@param isControllerVisible whether to show a controller bar at the bottom
|
|
@returns true if the movie opens successfully
|
|
*/
|
|
bool loadMovie (const URL& movieURL,
|
|
bool isControllerVisible);
|
|
|
|
/** Tries to load a QuickTime movie from a stream into the player.
|
|
|
|
It's best to call this function once you've added the component to a window,
|
|
(or put it on the desktop as a heavyweight window). Loading a movie when the
|
|
component isn't visible can cause problems, because QuickTime needs a window
|
|
handle to do its stuff.
|
|
|
|
@param movieStream a stream containing a .mov file. The component may try
|
|
to read the whole stream before playing, rather than
|
|
streaming from it.
|
|
@param isControllerVisible whether to show a controller bar at the bottom
|
|
@returns true if the movie opens successfully
|
|
*/
|
|
bool loadMovie (InputStream* movieStream,
|
|
bool isControllerVisible);
|
|
|
|
/** Closes the movie, if one is open. */
|
|
void closeMovie();
|
|
|
|
/** Returns the movie file that is currently open.
|
|
|
|
If there isn't one, this returns File::nonexistent
|
|
*/
|
|
File getCurrentMovieFile() const;
|
|
|
|
/** Returns true if there's currently a movie open. */
|
|
bool isMovieOpen() const;
|
|
|
|
/** Returns the length of the movie, in seconds. */
|
|
double getMovieDuration() const;
|
|
|
|
/** Returns the movie's natural size, in pixels.
|
|
|
|
You can use this to resize the component to show the movie at its preferred
|
|
scale.
|
|
|
|
If no movie is loaded, the size returned will be 0 x 0.
|
|
*/
|
|
void getMovieNormalSize (int& width, int& height) const;
|
|
|
|
/** This will position the component within a given area, keeping its aspect
|
|
ratio correct according to the movie's normal size.
|
|
|
|
The component will be made as large as it can go within the space, and will
|
|
be aligned according to the justification value if this means there are gaps at
|
|
the top or sides.
|
|
*/
|
|
void setBoundsWithCorrectAspectRatio (const Rectangle<int>& spaceToFitWithin,
|
|
const RectanglePlacement& placement);
|
|
|
|
/** Starts the movie playing. */
|
|
void play();
|
|
|
|
/** Stops the movie playing. */
|
|
void stop();
|
|
|
|
/** Returns true if the movie is currently playing. */
|
|
bool isPlaying() const;
|
|
|
|
/** Moves the movie's position back to the start. */
|
|
void goToStart();
|
|
|
|
/** Sets the movie's position to a given time. */
|
|
void setPosition (double seconds);
|
|
|
|
/** Returns the current play position of the movie. */
|
|
double getPosition() const;
|
|
|
|
/** Changes the movie playback rate.
|
|
|
|
A value of 1 is normal speed, greater values play it proportionately faster,
|
|
smaller values play it slower.
|
|
*/
|
|
void setSpeed (float newSpeed);
|
|
|
|
/** Changes the movie's playback volume.
|
|
|
|
@param newVolume the volume in the range 0 (silent) to 1.0 (full)
|
|
*/
|
|
void setMovieVolume (float newVolume);
|
|
|
|
/** Returns the movie's playback volume.
|
|
|
|
@returns the volume in the range 0 (silent) to 1.0 (full)
|
|
*/
|
|
float getMovieVolume() const;
|
|
|
|
/** Tells the movie whether it should loop. */
|
|
void setLooping (bool shouldLoop);
|
|
|
|
/** Returns true if the movie is currently looping.
|
|
|
|
@see setLooping
|
|
*/
|
|
bool isLooping() const;
|
|
|
|
/** True if the native QuickTime controller bar is shown in the window.
|
|
|
|
@see loadMovie
|
|
*/
|
|
bool isControllerVisible() const;
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
|
|
private:
|
|
|
|
File movieFile;
|
|
bool movieLoaded, controllerVisible, looping;
|
|
|
|
#if JUCE_WINDOWS
|
|
void parentHierarchyChanged();
|
|
void visibilityChanged();
|
|
|
|
void createControlIfNeeded();
|
|
bool isControlCreated() const;
|
|
|
|
class Pimpl;
|
|
friend class ScopedPointer <Pimpl>;
|
|
ScopedPointer <Pimpl> pimpl;
|
|
#else
|
|
void* movie;
|
|
#endif
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (QuickTimeMovieComponent);
|
|
};
|
|
|
|
#endif
|
|
#endif // __JUCE_QUICKTIMEMOVIECOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_QuickTimeMovieComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SCOPEDXLOCK_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ScopedXLock.h ***/
|
|
#ifndef __JUCE_SCOPEDXLOCK_JUCEHEADER__
|
|
#define __JUCE_SCOPEDXLOCK_JUCEHEADER__
|
|
|
|
#if JUCE_LINUX || DOXYGEN
|
|
|
|
/** A handy class that uses XLockDisplay and XUnlockDisplay to lock the X server
|
|
using RAII (Only available in Linux!).
|
|
*/
|
|
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
|
|
#endif // __JUCE_SCOPEDXLOCK_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ScopedXLock.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_SystemTrayIconComponent.h ***/
|
|
#ifndef __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__
|
|
|
|
#if JUCE_WINDOWS || JUCE_LINUX || DOXYGEN
|
|
|
|
/**
|
|
On Windows only, this component sits in the taskbar tray as a small icon.
|
|
|
|
To use it, just create one of these components, but don't attempt to make it
|
|
visible, add it to a parent, or put it on the desktop.
|
|
|
|
You can then call setIconImage() to create an icon for it in the taskbar.
|
|
|
|
To change the icon's tooltip, you can use setIconTooltip().
|
|
|
|
To respond to mouse-events, you can override the normal mouseDown(),
|
|
mouseUp(), mouseDoubleClick() and mouseMove() methods, and although the x, y
|
|
position will not be valid, you can use this to respond to clicks. Traditionally
|
|
you'd use a left-click to show your application's window, and a right-click
|
|
to show a pop-up menu.
|
|
*/
|
|
class JUCE_API SystemTrayIconComponent : public Component
|
|
{
|
|
public:
|
|
|
|
SystemTrayIconComponent();
|
|
|
|
/** Destructor. */
|
|
~SystemTrayIconComponent();
|
|
|
|
/** Changes the image shown in the taskbar.
|
|
*/
|
|
void setIconImage (const Image& newImage);
|
|
|
|
/** Changes the tooltip that Windows shows above the icon. */
|
|
void setIconTooltip (const String& tooltip);
|
|
|
|
#if JUCE_LINUX
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
#endif
|
|
|
|
private:
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SystemTrayIconComponent);
|
|
};
|
|
|
|
#endif
|
|
#endif // __JUCE_SYSTEMTRAYICONCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_SystemTrayIconComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_WebBrowserComponent.h ***/
|
|
#ifndef __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__
|
|
#define __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__
|
|
|
|
#if JUCE_WEB_BROWSER || DOXYGEN
|
|
|
|
#if ! DOXYGEN
|
|
class WebBrowserComponentInternal;
|
|
#endif
|
|
|
|
/**
|
|
A component that displays an embedded web browser.
|
|
|
|
The browser itself will be platform-dependent. On the Mac, probably Safari, on
|
|
Windows, probably IE.
|
|
|
|
*/
|
|
class JUCE_API WebBrowserComponent : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a WebBrowserComponent.
|
|
|
|
Once it's created and visible, send the browser to a URL using goToURL().
|
|
|
|
@param unloadPageWhenBrowserIsHidden if this is true, then when the browser
|
|
component is taken offscreen, it'll clear the current page
|
|
and replace it with a blank page - this can be handy to stop
|
|
the browser using resources in the background when it's not
|
|
actually being used.
|
|
*/
|
|
explicit WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true);
|
|
|
|
/** Destructor. */
|
|
~WebBrowserComponent();
|
|
|
|
/** Sends the browser to a particular URL.
|
|
|
|
@param url the URL to go to.
|
|
@param headers an optional set of parameters to put in the HTTP header. If
|
|
you supply this, it should be a set of string in the form
|
|
"HeaderKey: HeaderValue"
|
|
@param postData an optional block of data that will be attached to the HTTP
|
|
POST request
|
|
*/
|
|
void goToURL (const String& url,
|
|
const StringArray* headers = nullptr,
|
|
const MemoryBlock* postData = nullptr);
|
|
|
|
/** Stops the current page loading.
|
|
*/
|
|
void stop();
|
|
|
|
/** Sends the browser back one page.
|
|
*/
|
|
void goBack();
|
|
|
|
/** Sends the browser forward one page.
|
|
*/
|
|
void goForward();
|
|
|
|
/** Refreshes the browser.
|
|
*/
|
|
void refresh();
|
|
|
|
/** This callback is called when the browser is about to navigate
|
|
to a new location.
|
|
|
|
You can override this method to perform some action when the user
|
|
tries to go to a particular URL. To allow the operation to carry on,
|
|
return true, or return false to stop the navigation happening.
|
|
*/
|
|
virtual bool pageAboutToLoad (const String& newURL);
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void parentHierarchyChanged();
|
|
/** @internal */
|
|
void visibilityChanged();
|
|
|
|
private:
|
|
|
|
WebBrowserComponentInternal* browser;
|
|
bool blankPageShown, unloadPageWhenBrowserIsHidden;
|
|
String lastURL;
|
|
StringArray lastHeaders;
|
|
MemoryBlock lastPostData;
|
|
|
|
void reloadLastURL();
|
|
void checkWindowAssociation();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebBrowserComponent);
|
|
};
|
|
|
|
#endif
|
|
#endif // __JUCE_WEBBROWSERCOMPONENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_WebBrowserComponent.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_ALERTWINDOW_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CALLOUTBOX_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_CallOutBox.h ***/
|
|
#ifndef __JUCE_CALLOUTBOX_JUCEHEADER__
|
|
#define __JUCE_CALLOUTBOX_JUCEHEADER__
|
|
|
|
/**
|
|
A box with a small arrow that can be used as a temporary pop-up window to show
|
|
extra controls when a button or other component is clicked.
|
|
|
|
Using one of these is similar to having a popup menu attached to a button or
|
|
other component - but it looks fancier, and has an arrow that can indicate the
|
|
object that it applies to.
|
|
|
|
Normally, you'd create one of these on the stack and run it modally, e.g.
|
|
|
|
@code
|
|
void mouseUp (const MouseEvent& e)
|
|
{
|
|
MyContentComponent content;
|
|
content.setSize (300, 300);
|
|
|
|
CallOutBox callOut (content, *this, nullptr);
|
|
callOut.runModalLoop();
|
|
}
|
|
@endcode
|
|
|
|
The call-out will resize and position itself when the content changes size.
|
|
*/
|
|
class JUCE_API CallOutBox : public Component
|
|
{
|
|
public:
|
|
|
|
/** Creates a CallOutBox.
|
|
|
|
@param contentComponent the component to display inside the call-out. This should
|
|
already have a size set (although the call-out will also
|
|
update itself when the component's size is changed later).
|
|
Obviously this component must not be deleted until the
|
|
call-out box has been deleted.
|
|
@param componentToPointTo the component that the call-out's arrow should point towards
|
|
@param parentComponent if non-zero, this is the component to add the call-out to. If
|
|
this is zero, the call-out will be added to the desktop.
|
|
*/
|
|
CallOutBox (Component& contentComponent,
|
|
Component& componentToPointTo,
|
|
Component* parentComponent);
|
|
|
|
/** Destructor. */
|
|
~CallOutBox();
|
|
|
|
/** Changes the length of the arrow. */
|
|
void setArrowSize (float newSize);
|
|
|
|
/** Updates the position and size of the box.
|
|
|
|
You shouldn't normally need to call this, unless you need more precise control over the
|
|
layout.
|
|
|
|
@param newAreaToPointTo the rectangle to make the box's arrow point to
|
|
@param newAreaToFitIn the area within which the box's position should be constrained
|
|
*/
|
|
void updatePosition (const Rectangle<int>& newAreaToPointTo,
|
|
const Rectangle<int>& newAreaToFitIn);
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void resized();
|
|
/** @internal */
|
|
void moved();
|
|
/** @internal */
|
|
void childBoundsChanged (Component*);
|
|
/** @internal */
|
|
bool hitTest (int x, int y);
|
|
/** @internal */
|
|
void inputAttemptWhenModal();
|
|
/** @internal */
|
|
bool keyPressed (const KeyPress& key);
|
|
/** @internal */
|
|
void handleCommandMessage (int commandId);
|
|
|
|
private:
|
|
|
|
int borderSpace;
|
|
float arrowSize;
|
|
Component& content;
|
|
Path outline;
|
|
Point<float> targetPoint;
|
|
Rectangle<int> availableArea, targetArea;
|
|
Image background;
|
|
|
|
void refreshPath();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CallOutBox);
|
|
};
|
|
|
|
#endif // __JUCE_CALLOUTBOX_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CallOutBox.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_COMPONENTPEER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ComponentPeer.h ***/
|
|
#ifndef __JUCE_COMPONENTPEER_JUCEHEADER__
|
|
#define __JUCE_COMPONENTPEER_JUCEHEADER__
|
|
|
|
class ComponentBoundsConstrainer;
|
|
|
|
/**
|
|
The Component class uses a ComponentPeer internally to create and manage a real
|
|
operating-system window.
|
|
|
|
This is an abstract base class - the platform specific code contains implementations of
|
|
it for the various platforms.
|
|
|
|
User-code should very rarely need to have any involvement with this class.
|
|
|
|
@see Component::createNewPeer
|
|
*/
|
|
class JUCE_API ComponentPeer
|
|
{
|
|
public:
|
|
|
|
/** A combination of these flags is passed to the ComponentPeer constructor. */
|
|
enum StyleFlags
|
|
{
|
|
windowAppearsOnTaskbar = (1 << 0), /**< Indicates that the window should have a corresponding
|
|
entry on the taskbar (ignored on MacOSX) */
|
|
windowIsTemporary = (1 << 1), /**< Indicates that the window is a temporary popup, like a menu,
|
|
tooltip, etc. */
|
|
windowIgnoresMouseClicks = (1 << 2), /**< Indicates that the window should let mouse clicks pass
|
|
through it (may not be possible on some platforms). */
|
|
windowHasTitleBar = (1 << 3), /**< Indicates that the window should have a normal OS-specific
|
|
title bar and frame\. if not specified, the window will be
|
|
borderless. */
|
|
windowIsResizable = (1 << 4), /**< Indicates that the window should have a resizable border. */
|
|
windowHasMinimiseButton = (1 << 5), /**< Indicates that if the window has a title bar, it should have a
|
|
minimise button on it. */
|
|
windowHasMaximiseButton = (1 << 6), /**< Indicates that if the window has a title bar, it should have a
|
|
maximise button on it. */
|
|
windowHasCloseButton = (1 << 7), /**< Indicates that if the window has a title bar, it should have a
|
|
close button on it. */
|
|
windowHasDropShadow = (1 << 8), /**< Indicates that the window should have a drop-shadow (this may
|
|
not be possible on all platforms). */
|
|
windowRepaintedExplictly = (1 << 9), /**< Not intended for public use - this tells a window not to
|
|
do its own repainting, but only to repaint when the
|
|
performAnyPendingRepaintsNow() method is called. */
|
|
windowIgnoresKeyPresses = (1 << 10), /**< Tells the window not to catch any keypresses. This can
|
|
be used for things like plugin windows, to stop them interfering
|
|
with the host's shortcut keys */
|
|
windowIsSemiTransparent = (1 << 31) /**< Not intended for public use - makes a window transparent. */
|
|
|
|
};
|
|
|
|
/** Creates a peer.
|
|
|
|
The component is the one that we intend to represent, and the style flags are
|
|
a combination of the values in the StyleFlags enum
|
|
*/
|
|
ComponentPeer (Component* component, int styleFlags);
|
|
|
|
/** Destructor. */
|
|
virtual ~ComponentPeer();
|
|
|
|
/** Returns the component being represented by this peer. */
|
|
Component* getComponent() const noexcept { return component; }
|
|
|
|
/** Returns the set of style flags that were set when the window was created.
|
|
|
|
@see Component::addToDesktop
|
|
*/
|
|
int getStyleFlags() const noexcept { return styleFlags; }
|
|
|
|
/** Returns a unique ID for this peer.
|
|
Each peer that is created is given a different ID.
|
|
*/
|
|
uint32 getUniqueID() const noexcept { return uniqueID; }
|
|
|
|
/** Returns the raw handle to whatever kind of window is being used.
|
|
|
|
On windows, this is probably a HWND, on the mac, it's likely to be a WindowRef,
|
|
but rememeber there's no guarantees what you'll get back.
|
|
*/
|
|
virtual void* getNativeHandle() const = 0;
|
|
|
|
/** Shows or hides the window. */
|
|
virtual void setVisible (bool shouldBeVisible) = 0;
|
|
|
|
/** Changes the title of the window. */
|
|
virtual void setTitle (const String& title) = 0;
|
|
|
|
/** Moves the window without changing its size.
|
|
|
|
If the native window is contained in another window, then the co-ordinates are
|
|
relative to the parent window's origin, not the screen origin.
|
|
|
|
This should result in a callback to handleMovedOrResized().
|
|
*/
|
|
virtual void setPosition (int x, int y) = 0;
|
|
|
|
/** Resizes the window without changing its position.
|
|
|
|
This should result in a callback to handleMovedOrResized().
|
|
*/
|
|
virtual void setSize (int w, int h) = 0;
|
|
|
|
/** Moves and resizes the window.
|
|
|
|
If the native window is contained in another window, then the co-ordinates are
|
|
relative to the parent window's origin, not the screen origin.
|
|
|
|
This should result in a callback to handleMovedOrResized().
|
|
*/
|
|
virtual void setBounds (int x, int y, int w, int h, bool isNowFullScreen) = 0;
|
|
|
|
/** Returns the current position and size of the window.
|
|
|
|
If the native window is contained in another window, then the co-ordinates are
|
|
relative to the parent window's origin, not the screen origin.
|
|
*/
|
|
virtual const Rectangle<int> getBounds() const = 0;
|
|
|
|
/** Returns the x-position of this window, relative to the screen's origin. */
|
|
virtual const Point<int> getScreenPosition() const = 0;
|
|
|
|
/** Converts a position relative to the top-left of this component to screen co-ordinates. */
|
|
virtual const Point<int> localToGlobal (const Point<int>& relativePosition) = 0;
|
|
|
|
/** Converts a rectangle relative to the top-left of this component to screen co-ordinates. */
|
|
virtual const Rectangle<int> localToGlobal (const Rectangle<int>& relativePosition);
|
|
|
|
/** Converts a screen co-ordinate to a position relative to the top-left of this component. */
|
|
virtual const Point<int> globalToLocal (const Point<int>& screenPosition) = 0;
|
|
|
|
/** Converts a screen area to a position relative to the top-left of this component. */
|
|
virtual const Rectangle<int> globalToLocal (const Rectangle<int>& screenPosition);
|
|
|
|
/** Minimises the window. */
|
|
virtual void setMinimised (bool shouldBeMinimised) = 0;
|
|
|
|
/** True if the window is currently minimised. */
|
|
virtual bool isMinimised() const = 0;
|
|
|
|
/** Enable/disable fullscreen mode for the window. */
|
|
virtual void setFullScreen (bool shouldBeFullScreen) = 0;
|
|
|
|
/** True if the window is currently full-screen. */
|
|
virtual bool isFullScreen() const = 0;
|
|
|
|
/** Sets the size to restore to if fullscreen mode is turned off. */
|
|
void setNonFullScreenBounds (const Rectangle<int>& newBounds) noexcept;
|
|
|
|
/** Returns the size to restore to if fullscreen mode is turned off. */
|
|
const Rectangle<int>& getNonFullScreenBounds() const noexcept;
|
|
|
|
/** Attempts to change the icon associated with this window.
|
|
*/
|
|
virtual void setIcon (const Image& newIcon) = 0;
|
|
|
|
/** Sets a constrainer to use if the peer can resize itself.
|
|
|
|
The constrainer won't be deleted by this object, so the caller must manage its lifetime.
|
|
*/
|
|
void setConstrainer (ComponentBoundsConstrainer* newConstrainer) noexcept;
|
|
|
|
/** Returns the current constrainer, if one has been set. */
|
|
ComponentBoundsConstrainer* getConstrainer() const noexcept { return constrainer; }
|
|
|
|
/** Checks if a point is in the window.
|
|
|
|
Coordinates are relative to the top-left of this window. If trueIfInAChildWindow
|
|
is false, then this returns false if the point is actually inside a child of this
|
|
window.
|
|
*/
|
|
virtual bool contains (const Point<int>& position, bool trueIfInAChildWindow) const = 0;
|
|
|
|
/** Returns the size of the window frame that's around this window.
|
|
|
|
Whether or not the window has a normal window frame depends on the flags
|
|
that were set when the window was created by Component::addToDesktop()
|
|
*/
|
|
virtual const BorderSize<int> getFrameSize() const = 0;
|
|
|
|
/** This is called when the window's bounds change.
|
|
|
|
A peer implementation must call this when the window is moved and resized, so that
|
|
this method can pass the message on to the component.
|
|
*/
|
|
void handleMovedOrResized();
|
|
|
|
/** This is called if the screen resolution changes.
|
|
|
|
A peer implementation must call this if the monitor arrangement changes or the available
|
|
screen size changes.
|
|
*/
|
|
void handleScreenSizeChange();
|
|
|
|
/** This is called to repaint the component into the given context. */
|
|
void handlePaint (LowLevelGraphicsContext& contextToPaintTo);
|
|
|
|
/** Sets this window to either be always-on-top or normal.
|
|
|
|
Some kinds of window might not be able to do this, so should return false.
|
|
*/
|
|
virtual bool setAlwaysOnTop (bool alwaysOnTop) = 0;
|
|
|
|
/** Brings the window to the top, optionally also giving it focus. */
|
|
virtual void toFront (bool makeActive) = 0;
|
|
|
|
/** Moves the window to be just behind another one. */
|
|
virtual void toBehind (ComponentPeer* other) = 0;
|
|
|
|
/** Called when the window is brought to the front, either by the OS or by a call
|
|
to toFront().
|
|
*/
|
|
void handleBroughtToFront();
|
|
|
|
/** True if the window has the keyboard focus. */
|
|
virtual bool isFocused() const = 0;
|
|
|
|
/** Tries to give the window keyboard focus. */
|
|
virtual void grabFocus() = 0;
|
|
|
|
/** Called when the window gains keyboard focus. */
|
|
void handleFocusGain();
|
|
/** Called when the window loses keyboard focus. */
|
|
void handleFocusLoss();
|
|
|
|
Component* getLastFocusedSubcomponent() const noexcept;
|
|
|
|
/** Called when a key is pressed.
|
|
|
|
For keycode info, see the KeyPress class.
|
|
Returns true if the keystroke was used.
|
|
*/
|
|
bool handleKeyPress (int keyCode, juce_wchar textCharacter);
|
|
|
|
/** Called whenever a key is pressed or released.
|
|
Returns true if the keystroke was used.
|
|
*/
|
|
bool handleKeyUpOrDown (bool isKeyDown);
|
|
|
|
/** Called whenever a modifier key is pressed or released. */
|
|
void handleModifierKeysChange();
|
|
|
|
/** Tells the window that text input may be required at the given position.
|
|
This may cause things like a virtual on-screen keyboard to appear, depending
|
|
on the OS.
|
|
*/
|
|
virtual void textInputRequired (const Point<int>& position) = 0;
|
|
|
|
/** If there's some kind of OS input-method in progress, this should dismiss it. */
|
|
virtual void dismissPendingTextInput();
|
|
|
|
/** Returns the currently focused TextInputTarget, or null if none is found. */
|
|
TextInputTarget* findCurrentTextInputTarget();
|
|
|
|
/** Invalidates a region of the window to be repainted asynchronously. */
|
|
virtual void repaint (const Rectangle<int>& area) = 0;
|
|
|
|
/** This can be called (from the message thread) to cause the immediate redrawing
|
|
of any areas of this window that need repainting.
|
|
|
|
You shouldn't ever really need to use this, it's mainly for special purposes
|
|
like supporting audio plugins where the host's event loop is out of our control.
|
|
*/
|
|
virtual void performAnyPendingRepaintsNow() = 0;
|
|
|
|
/** Changes the window's transparency. */
|
|
virtual void setAlpha (float newAlpha) = 0;
|
|
|
|
void handleMouseEvent (int touchIndex, const Point<int>& positionWithinPeer, const ModifierKeys& newMods, int64 time);
|
|
void handleMouseWheel (int touchIndex, const Point<int>& positionWithinPeer, int64 time, float x, float y);
|
|
|
|
void handleUserClosingWindow();
|
|
|
|
bool handleFileDragMove (const StringArray& files, const Point<int>& position);
|
|
bool handleFileDragExit (const StringArray& files);
|
|
bool handleFileDragDrop (const StringArray& files, const Point<int>& position);
|
|
|
|
/** Resets the masking region.
|
|
|
|
The subclass should call this every time it's about to call the handlePaint
|
|
method.
|
|
|
|
@see addMaskedRegion
|
|
*/
|
|
void clearMaskedRegion();
|
|
|
|
/** Adds a rectangle to the set of areas not to paint over.
|
|
|
|
A component can call this on its peer during its paint() method, to signal
|
|
that the painting code should ignore a given region. The reason
|
|
for this is to stop embedded windows (such as OpenGL) getting painted over.
|
|
|
|
The masked region is cleared each time before a paint happens, so a component
|
|
will have to make sure it calls this every time it's painted.
|
|
*/
|
|
void addMaskedRegion (int x, int y, int w, int h);
|
|
|
|
/** Returns the number of currently-active peers.
|
|
|
|
@see getPeer
|
|
*/
|
|
static int getNumPeers() noexcept;
|
|
|
|
/** Returns one of the currently-active peers.
|
|
|
|
@see getNumPeers
|
|
*/
|
|
static ComponentPeer* getPeer (int index) noexcept;
|
|
|
|
/** Checks if this peer object is valid.
|
|
|
|
@see getNumPeers
|
|
*/
|
|
static bool isValidPeer (const ComponentPeer* peer) noexcept;
|
|
|
|
virtual StringArray getAvailableRenderingEngines();
|
|
virtual int getCurrentRenderingEngine() const;
|
|
virtual void setCurrentRenderingEngine (int index);
|
|
|
|
protected:
|
|
|
|
Component* const component;
|
|
const int styleFlags;
|
|
RectangleList maskedRegion;
|
|
Rectangle<int> lastNonFullscreenBounds;
|
|
uint32 lastPaintTime;
|
|
ComponentBoundsConstrainer* constrainer;
|
|
|
|
static void updateCurrentModifiers() noexcept;
|
|
|
|
private:
|
|
|
|
WeakReference<Component> lastFocusedComponent, dragAndDropTargetComponent;
|
|
Component* lastDragAndDropCompUnderMouse;
|
|
const uint32 uniqueID;
|
|
bool fakeMouseMessageSent : 1, isWindowMinimised : 1;
|
|
|
|
friend class Component;
|
|
friend class Desktop;
|
|
static ComponentPeer* getPeerFor (const Component* component) noexcept;
|
|
|
|
void setLastDragDropTarget (Component* comp);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ComponentPeer);
|
|
};
|
|
|
|
#endif // __JUCE_COMPONENTPEER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ComponentPeer.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DIALOGWINDOW_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DialogWindow.h ***/
|
|
#ifndef __JUCE_DIALOGWINDOW_JUCEHEADER__
|
|
#define __JUCE_DIALOGWINDOW_JUCEHEADER__
|
|
|
|
/**
|
|
A dialog-box style window.
|
|
|
|
This class is a convenient way of creating a DocumentWindow with a close button
|
|
that can be triggered by pressing the escape key.
|
|
|
|
Any of the methods available to a DocumentWindow or ResizableWindow are also
|
|
available to this, so it can be made resizable, have a menu bar, etc.
|
|
|
|
To add items to the box, see the ResizableWindow::setContentOwned() or
|
|
ResizableWindow::setContentNonOwned() methods. Don't add components directly to this
|
|
class - always put them in a content component!
|
|
|
|
You'll need to override the DocumentWindow::closeButtonPressed() method to handle
|
|
the user clicking the close button - for more info, see the DocumentWindow
|
|
help.
|
|
|
|
@see DocumentWindow, ResizableWindow
|
|
*/
|
|
class JUCE_API DialogWindow : public DocumentWindow
|
|
{
|
|
public:
|
|
|
|
/** Creates a DialogWindow.
|
|
|
|
@param name the name to give the component - this is also
|
|
the title shown at the top of the window. To change
|
|
this later, use setName()
|
|
@param backgroundColour the colour to use for filling the window's background.
|
|
@param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
|
|
close button to be triggered
|
|
@param addToDesktop if true, the window will be automatically added to the
|
|
desktop; if false, you can use it as a child component
|
|
*/
|
|
DialogWindow (const String& name,
|
|
const Colour& backgroundColour,
|
|
bool escapeKeyTriggersCloseButton,
|
|
bool addToDesktop = true);
|
|
|
|
/** Destructor.
|
|
If a content component has been set with setContentOwned(), it will be deleted.
|
|
*/
|
|
~DialogWindow();
|
|
|
|
/** Easy way of quickly showing a dialog box containing a given component.
|
|
|
|
This will open and display a DialogWindow containing a given component, making it
|
|
modal, but returning immediately to allow the dialog to finish in its own time. If
|
|
you want to block and run a modal loop until the dialog is dismissed, use showModalDialog()
|
|
instead.
|
|
|
|
To close the dialog programatically, you should call exitModalState (returnValue) on
|
|
the DialogWindow that is created. To find a pointer to this window from your
|
|
contentComponent, you can do something like this:
|
|
@code
|
|
Dialogwindow* dw = contentComponent->findParentComponentOfClass ((DialogWindow*) nullptr);
|
|
|
|
if (dw != nullptr)
|
|
dw->exitModalState (1234);
|
|
@endcode
|
|
|
|
@param dialogTitle the dialog box's title
|
|
@param contentComponent the content component for the dialog box. Make sure
|
|
that this has been set to the size you want it to
|
|
be before calling this method. The component won't
|
|
be deleted by this call, so you can re-use it or delete
|
|
it afterwards
|
|
@param componentToCentreAround if this is non-zero, it indicates a component that
|
|
you'd like to show this dialog box in front of. See the
|
|
DocumentWindow::centreAroundComponent() method for more
|
|
info on this parameter
|
|
@param backgroundColour a colour to use for the dialog box's background colour
|
|
@param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
|
|
close button to be triggered
|
|
@param shouldBeResizable if true, the dialog window has either a resizable border, or
|
|
a corner resizer
|
|
@param useBottomRightCornerResizer if shouldBeResizable is true, this indicates whether
|
|
to use a border or corner resizer component. See ResizableWindow::setResizable()
|
|
*/
|
|
static void showDialog (const String& dialogTitle,
|
|
Component* contentComponent,
|
|
Component* componentToCentreAround,
|
|
const Colour& backgroundColour,
|
|
bool escapeKeyTriggersCloseButton,
|
|
bool shouldBeResizable = false,
|
|
bool useBottomRightCornerResizer = false);
|
|
|
|
/** Easy way of quickly showing a dialog box containing a given component.
|
|
|
|
This will open and display a DialogWindow containing a given component, returning
|
|
when the user clicks its close button.
|
|
|
|
It returns the value that was returned by the dialog box's runModalLoop() call.
|
|
|
|
To close the dialog programatically, you should call exitModalState (returnValue) on
|
|
the DialogWindow that is created. To find a pointer to this window from your
|
|
contentComponent, you can do something like this:
|
|
@code
|
|
Dialogwindow* dw = contentComponent->findParentComponentOfClass ((DialogWindow*) nullptr);
|
|
|
|
if (dw != nullptr)
|
|
dw->exitModalState (1234);
|
|
@endcode
|
|
|
|
@param dialogTitle the dialog box's title
|
|
@param contentComponent the content component for the dialog box. Make sure
|
|
that this has been set to the size you want it to
|
|
be before calling this method. The component won't
|
|
be deleted by this call, so you can re-use it or delete
|
|
it afterwards
|
|
@param componentToCentreAround if this is non-zero, it indicates a component that
|
|
you'd like to show this dialog box in front of. See the
|
|
DocumentWindow::centreAroundComponent() method for more
|
|
info on this parameter
|
|
@param backgroundColour a colour to use for the dialog box's background colour
|
|
@param escapeKeyTriggersCloseButton if true, then pressing the escape key will cause the
|
|
close button to be triggered
|
|
@param shouldBeResizable if true, the dialog window has either a resizable border, or
|
|
a corner resizer
|
|
@param useBottomRightCornerResizer if shouldBeResizable is true, this indicates whether
|
|
to use a border or corner resizer component. See ResizableWindow::setResizable()
|
|
*/
|
|
#if JUCE_MODAL_LOOPS_PERMITTED || DOXYGEN
|
|
static int showModalDialog (const String& dialogTitle,
|
|
Component* contentComponent,
|
|
Component* componentToCentreAround,
|
|
const Colour& backgroundColour,
|
|
bool escapeKeyTriggersCloseButton,
|
|
bool shouldBeResizable = false,
|
|
bool useBottomRightCornerResizer = false);
|
|
#endif
|
|
|
|
protected:
|
|
/** @internal */
|
|
void resized();
|
|
|
|
private:
|
|
|
|
bool escapeKeyTriggersCloseButton;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DialogWindow);
|
|
};
|
|
|
|
#endif // __JUCE_DIALOGWINDOW_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DialogWindow.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DOCUMENTWINDOW_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_NATIVEMESSAGEBOX_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_NativeMessageBox.h ***/
|
|
#ifndef __JUCE_NATIVEMESSAGEBOX_JUCEHEADER__
|
|
#define __JUCE_NATIVEMESSAGEBOX_JUCEHEADER__
|
|
|
|
class NativeMessageBox
|
|
{
|
|
public:
|
|
/** Shows a dialog box that just has a message and a single 'ok' button to close it.
|
|
|
|
If the callback parameter is null, the box is shown modally, and the method will
|
|
block until the user has clicked the button (or pressed the escape or return keys).
|
|
If the callback parameter is non-null, the box will be displayed and placed into a
|
|
modal state, but this method will return immediately, and the callback will be invoked
|
|
later when the user dismisses the box.
|
|
|
|
@param iconType the type of icon to show
|
|
@param title the headline to show at the top of the box
|
|
@param message a longer, more descriptive message to show underneath the title
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
*/
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
static void JUCE_CALLTYPE showMessageBox (AlertWindow::AlertIconType iconType,
|
|
const String& title,
|
|
const String& message,
|
|
Component* associatedComponent = nullptr);
|
|
#endif
|
|
|
|
/** Shows a dialog box that just has a message and a single 'ok' button to close it.
|
|
|
|
If the callback parameter is null, the box is shown modally, and the method will
|
|
block until the user has clicked the button (or pressed the escape or return keys).
|
|
If the callback parameter is non-null, the box will be displayed and placed into a
|
|
modal state, but this method will return immediately, and the callback will be invoked
|
|
later when the user dismisses the box.
|
|
|
|
@param iconType the type of icon to show
|
|
@param title the headline to show at the top of the box
|
|
@param message a longer, more descriptive message to show underneath the title
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
*/
|
|
static void JUCE_CALLTYPE showMessageBoxAsync (AlertWindow::AlertIconType iconType,
|
|
const String& title,
|
|
const String& message,
|
|
Component* associatedComponent = nullptr);
|
|
|
|
/** Shows a dialog box with two buttons.
|
|
|
|
Ideal for ok/cancel or yes/no choices. The return key can also be used
|
|
to trigger the first button, and the escape key for the second button.
|
|
|
|
If the callback parameter is null, the box is shown modally, and the method will
|
|
block until the user has clicked the button (or pressed the escape or return keys).
|
|
If the callback parameter is non-null, the box will be displayed and placed into a
|
|
modal state, but this method will return immediately, and the callback will be invoked
|
|
later when the user dismisses the box.
|
|
|
|
@param iconType the type of icon to show
|
|
@param title the headline to show at the top of the box
|
|
@param message a longer, more descriptive message to show underneath the title
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
@param callback if this is non-null, the menu will be launched asynchronously,
|
|
returning immediately, and the callback will receive a call to its
|
|
modalStateFinished() when the box is dismissed, with its parameter
|
|
being 1 if the ok button was pressed, or 0 for cancel, The callback object
|
|
will be owned and deleted by the system, so make sure that it works
|
|
safely and doesn't keep any references to objects that might be deleted
|
|
before it gets called.
|
|
@returns true if button 1 was clicked, false if it was button 2. If the callback parameter
|
|
is not null, the method always returns false, and the user's choice is delivered
|
|
later by the callback.
|
|
*/
|
|
static bool JUCE_CALLTYPE showOkCancelBox (AlertWindow::AlertIconType iconType,
|
|
const String& title,
|
|
const String& message,
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
Component* associatedComponent = nullptr,
|
|
ModalComponentManager::Callback* callback = nullptr);
|
|
#else
|
|
Component* associatedComponent,
|
|
ModalComponentManager::Callback* callback);
|
|
#endif
|
|
|
|
/** Shows a dialog box with three buttons.
|
|
|
|
Ideal for yes/no/cancel boxes.
|
|
|
|
The escape key can be used to trigger the third button.
|
|
|
|
If the callback parameter is null, the box is shown modally, and the method will
|
|
block until the user has clicked the button (or pressed the escape or return keys).
|
|
If the callback parameter is non-null, the box will be displayed and placed into a
|
|
modal state, but this method will return immediately, and the callback will be invoked
|
|
later when the user dismisses the box.
|
|
|
|
@param iconType the type of icon to show
|
|
@param title the headline to show at the top of the box
|
|
@param message a longer, more descriptive message to show underneath the title
|
|
@param associatedComponent if this is non-null, it specifies the component that the
|
|
alert window should be associated with. Depending on the look
|
|
and feel, this might be used for positioning of the alert window.
|
|
@param callback if this is non-null, the menu will be launched asynchronously,
|
|
returning immediately, and the callback will receive a call to its
|
|
modalStateFinished() when the box is dismissed, with its parameter
|
|
being 1 if the "yes" button was pressed, 2 for the "no" button, or 0
|
|
if it was cancelled, The callback object will be owned and deleted by the
|
|
system, so make sure that it works safely and doesn't keep any references
|
|
to objects that might be deleted before it gets called.
|
|
|
|
@returns If the callback parameter has been set, this returns 0. Otherwise, it returns one
|
|
of the following values:
|
|
- 0 if 'cancel' was pressed
|
|
- 1 if 'yes' was pressed
|
|
- 2 if 'no' was pressed
|
|
*/
|
|
static int JUCE_CALLTYPE showYesNoCancelBox (AlertWindow::AlertIconType iconType,
|
|
const String& title,
|
|
const String& message,
|
|
#if JUCE_MODAL_LOOPS_PERMITTED
|
|
Component* associatedComponent = nullptr,
|
|
ModalComponentManager::Callback* callback = nullptr);
|
|
#else
|
|
Component* associatedComponent,
|
|
ModalComponentManager::Callback* callback);
|
|
#endif
|
|
};
|
|
|
|
#endif // __JUCE_NATIVEMESSAGEBOX_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_NativeMessageBox.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_RESIZABLEWINDOW_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_SPLASHSCREEN_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_SplashScreen.h ***/
|
|
#ifndef __JUCE_SPLASHSCREEN_JUCEHEADER__
|
|
#define __JUCE_SPLASHSCREEN_JUCEHEADER__
|
|
|
|
/** A component for showing a splash screen while your app starts up.
|
|
|
|
This will automatically position itself, and delete itself when the app has
|
|
finished initialising (it uses the JUCEApplication::isInitialising() to detect
|
|
this).
|
|
|
|
To use it, just create one of these in your JUCEApplication::initialise() method,
|
|
call its show() method and let the object delete itself later.
|
|
|
|
E.g. @code
|
|
|
|
void MyApp::initialise (const String& commandLine)
|
|
{
|
|
SplashScreen* splash = new SplashScreen();
|
|
|
|
splash->show ("welcome to my app",
|
|
ImageCache::getFromFile (File ("/foobar/splash.jpg")),
|
|
4000, false);
|
|
|
|
.. no need to delete the splash screen - it'll do that itself.
|
|
}
|
|
|
|
@endcode
|
|
*/
|
|
class JUCE_API SplashScreen : public Component,
|
|
public Timer,
|
|
private DeletedAtShutdown
|
|
{
|
|
public:
|
|
|
|
/** Creates a SplashScreen object.
|
|
|
|
After creating one of these (or your subclass of it), call one of the show()
|
|
methods to display it.
|
|
*/
|
|
SplashScreen();
|
|
|
|
/** Destructor. */
|
|
~SplashScreen();
|
|
|
|
/** Creates a SplashScreen object that will display an image.
|
|
|
|
As soon as this is called, the SplashScreen will be displayed in the centre of the
|
|
screen. This method will also dispatch any pending messages to make sure that when
|
|
it returns, the splash screen has been completely drawn, and your initialisation
|
|
code can carry on.
|
|
|
|
@param title the name to give the component
|
|
@param backgroundImage an image to draw on the component. The component's size
|
|
will be set to the size of this image, and if the image is
|
|
semi-transparent, the component will be made semi-transparent
|
|
too. This image will be deleted (or released from the ImageCache
|
|
if that's how it was created) by the splash screen object when
|
|
it is itself deleted.
|
|
@param minimumTimeToDisplayFor how long (in milliseconds) the splash screen
|
|
should stay visible for. If the initialisation takes longer than
|
|
this time, the splash screen will wait for it to finish before
|
|
disappearing, but if initialisation is very quick, this lets
|
|
you make sure that people get a good look at your splash.
|
|
@param useDropShadow if true, the window will have a drop shadow
|
|
@param removeOnMouseClick if true, the window will go away as soon as the user clicks
|
|
the mouse (anywhere)
|
|
*/
|
|
void show (const String& title,
|
|
const Image& backgroundImage,
|
|
int minimumTimeToDisplayFor,
|
|
bool useDropShadow,
|
|
bool removeOnMouseClick = true);
|
|
|
|
/** Creates a SplashScreen object with a specified size.
|
|
|
|
For a custom splash screen, you can use this method to display it at a certain size
|
|
and then override the paint() method yourself to do whatever's necessary.
|
|
|
|
As soon as this is called, the SplashScreen will be displayed in the centre of the
|
|
screen. This method will also dispatch any pending messages to make sure that when
|
|
it returns, the splash screen has been completely drawn, and your initialisation
|
|
code can carry on.
|
|
|
|
@param title the name to give the component
|
|
@param width the width to use
|
|
@param height the height to use
|
|
@param minimumTimeToDisplayFor how long (in milliseconds) the splash screen
|
|
should stay visible for. If the initialisation takes longer than
|
|
this time, the splash screen will wait for it to finish before
|
|
disappearing, but if initialisation is very quick, this lets
|
|
you make sure that people get a good look at your splash.
|
|
@param useDropShadow if true, the window will have a drop shadow
|
|
@param removeOnMouseClick if true, the window will go away as soon as the user clicks
|
|
the mouse (anywhere)
|
|
*/
|
|
void show (const String& title,
|
|
int width,
|
|
int height,
|
|
int minimumTimeToDisplayFor,
|
|
bool useDropShadow,
|
|
bool removeOnMouseClick = true);
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
void timerCallback();
|
|
|
|
private:
|
|
|
|
Image backgroundImage;
|
|
Time earliestTimeToDelete;
|
|
int originalClickCounter;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SplashScreen);
|
|
};
|
|
|
|
#endif // __JUCE_SPLASHSCREEN_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_SplashScreen.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ThreadWithProgressWindow.h ***/
|
|
#ifndef __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__
|
|
#define __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__
|
|
|
|
/**
|
|
A thread that automatically pops up a modal dialog box with a progress bar
|
|
and cancel button while it's busy running.
|
|
|
|
These are handy for performing some sort of task while giving the user feedback
|
|
about how long there is to go, etc.
|
|
|
|
E.g. @code
|
|
class MyTask : public ThreadWithProgressWindow
|
|
{
|
|
public:
|
|
MyTask() : ThreadWithProgressWindow ("busy...", true, true)
|
|
{
|
|
}
|
|
|
|
~MyTask()
|
|
{
|
|
}
|
|
|
|
void run()
|
|
{
|
|
for (int i = 0; i < thingsToDo; ++i)
|
|
{
|
|
// must check this as often as possible, because this is
|
|
// how we know if the user's pressed 'cancel'
|
|
if (threadShouldExit())
|
|
break;
|
|
|
|
// this will update the progress bar on the dialog box
|
|
setProgress (i / (double) thingsToDo);
|
|
|
|
// ... do the business here...
|
|
}
|
|
}
|
|
};
|
|
|
|
void doTheTask()
|
|
{
|
|
MyTask m;
|
|
|
|
if (m.runThread())
|
|
{
|
|
// thread finished normally..
|
|
}
|
|
else
|
|
{
|
|
// user pressed the cancel button..
|
|
}
|
|
}
|
|
|
|
@endcode
|
|
|
|
@see Thread, AlertWindow
|
|
*/
|
|
class JUCE_API ThreadWithProgressWindow : public Thread,
|
|
private Timer
|
|
{
|
|
public:
|
|
|
|
/** Creates the thread.
|
|
|
|
Initially, the dialog box won't be visible, it'll only appear when the
|
|
runThread() method is called.
|
|
|
|
@param windowTitle the title to go at the top of the dialog box
|
|
@param hasProgressBar whether the dialog box should have a progress bar (see
|
|
setProgress() )
|
|
@param hasCancelButton whether the dialog box should have a cancel button
|
|
@param timeOutMsWhenCancelling when 'cancel' is pressed, this is how long to wait for
|
|
the thread to stop before killing it forcibly (see
|
|
Thread::stopThread() )
|
|
@param cancelButtonText the text that should be shown in the cancel button
|
|
(if it has one)
|
|
*/
|
|
ThreadWithProgressWindow (const String& windowTitle,
|
|
bool hasProgressBar,
|
|
bool hasCancelButton,
|
|
int timeOutMsWhenCancelling = 10000,
|
|
const String& cancelButtonText = "Cancel");
|
|
|
|
/** Destructor. */
|
|
~ThreadWithProgressWindow();
|
|
|
|
/** Starts the thread and waits for it to finish.
|
|
|
|
This will start the thread, make the dialog box appear, and wait until either
|
|
the thread finishes normally, or until the cancel button is pressed.
|
|
|
|
Before returning, the dialog box will be hidden.
|
|
|
|
@param threadPriority the priority to use when starting the thread - see
|
|
Thread::startThread() for values
|
|
@returns true if the thread finished normally; false if the user pressed cancel
|
|
*/
|
|
bool runThread (int threadPriority = 5);
|
|
|
|
/** The thread should call this periodically to update the position of the progress bar.
|
|
|
|
@param newProgress the progress, from 0.0 to 1.0
|
|
@see setStatusMessage
|
|
*/
|
|
void setProgress (double newProgress);
|
|
|
|
/** The thread can call this to change the message that's displayed in the dialog box.
|
|
*/
|
|
void setStatusMessage (const String& newStatusMessage);
|
|
|
|
/** Returns the AlertWindow that is being used.
|
|
*/
|
|
AlertWindow* getAlertWindow() const noexcept { return alertWindow; }
|
|
|
|
private:
|
|
|
|
void timerCallback();
|
|
|
|
double progress;
|
|
ScopedPointer <AlertWindow> alertWindow;
|
|
String message;
|
|
CriticalSection messageLock;
|
|
const int timeOutMsWhenCancelling;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ThreadWithProgressWindow);
|
|
};
|
|
|
|
#endif // __JUCE_THREADWITHPROGRESSWINDOW_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ThreadWithProgressWindow.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOOLTIPWINDOW_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TOPLEVELWINDOW_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COLOUR_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COLOURGRADIENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_COLOURS_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_PIXELFORMATS_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_EDGETABLE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_EdgeTable.h ***/
|
|
#ifndef __JUCE_EDGETABLE_JUCEHEADER__
|
|
#define __JUCE_EDGETABLE_JUCEHEADER__
|
|
|
|
class Path;
|
|
class Image;
|
|
|
|
/**
|
|
A table of horizontal scan-line segments - used for rasterising Paths.
|
|
|
|
@see Path, Graphics
|
|
*/
|
|
class JUCE_API EdgeTable
|
|
{
|
|
public:
|
|
|
|
/** Creates an edge table containing a path.
|
|
|
|
A table is created with a fixed vertical range, and only sections of the path
|
|
which lie within this range will be added to the table.
|
|
|
|
@param clipLimits only the region of the path that lies within this area will be added
|
|
@param pathToAdd the path to add to the table
|
|
@param transform a transform to apply to the path being added
|
|
*/
|
|
EdgeTable (const Rectangle<int>& clipLimits,
|
|
const Path& pathToAdd,
|
|
const AffineTransform& transform);
|
|
|
|
/** Creates an edge table containing a rectangle. */
|
|
EdgeTable (const Rectangle<int>& rectangleToAdd);
|
|
|
|
/** Creates an edge table containing a rectangle list. */
|
|
EdgeTable (const RectangleList& rectanglesToAdd);
|
|
|
|
/** Creates an edge table containing a rectangle. */
|
|
EdgeTable (const Rectangle<float>& rectangleToAdd);
|
|
|
|
/** Creates a copy of another edge table. */
|
|
EdgeTable (const EdgeTable& other);
|
|
|
|
/** Copies from another edge table. */
|
|
EdgeTable& operator= (const EdgeTable& other);
|
|
|
|
/** Destructor. */
|
|
~EdgeTable();
|
|
|
|
void clipToRectangle (const Rectangle<int>& r);
|
|
void excludeRectangle (const Rectangle<int>& r);
|
|
void clipToEdgeTable (const EdgeTable& other);
|
|
void clipLineToMask (int x, int y, const uint8* mask, int maskStride, int numPixels);
|
|
bool isEmpty() noexcept;
|
|
const Rectangle<int>& getMaximumBounds() const noexcept { return bounds; }
|
|
void translate (float dx, int dy) noexcept;
|
|
|
|
/** Reduces the amount of space the table has allocated.
|
|
|
|
This will shrink the table down to use as little memory as possible - useful for
|
|
read-only tables that get stored and re-used for rendering.
|
|
*/
|
|
void optimiseTable();
|
|
|
|
/** Iterates the lines in the table, for rendering.
|
|
|
|
This function will iterate each line in the table, and call a user-defined class
|
|
to render each pixel or continuous line of pixels that the table contains.
|
|
|
|
@param iterationCallback this templated class must contain the following methods:
|
|
@code
|
|
inline void setEdgeTableYPos (int y);
|
|
inline void handleEdgeTablePixel (int x, int alphaLevel) const;
|
|
inline void handleEdgeTablePixelFull (int x) const;
|
|
inline void handleEdgeTableLine (int x, int width, int alphaLevel) const;
|
|
inline void handleEdgeTableLineFull (int x, int width) const;
|
|
@endcode
|
|
(these don't necessarily have to be 'const', but it might help it go faster)
|
|
*/
|
|
template <class EdgeTableIterationCallback>
|
|
void iterate (EdgeTableIterationCallback& iterationCallback) const noexcept
|
|
{
|
|
const int* lineStart = table;
|
|
|
|
for (int y = 0; y < bounds.getHeight(); ++y)
|
|
{
|
|
const int* line = lineStart;
|
|
lineStart += lineStrideElements;
|
|
int numPoints = line[0];
|
|
|
|
if (--numPoints > 0)
|
|
{
|
|
int x = *++line;
|
|
jassert ((x >> 8) >= bounds.getX() && (x >> 8) < bounds.getRight());
|
|
int levelAccumulator = 0;
|
|
|
|
iterationCallback.setEdgeTableYPos (bounds.getY() + y);
|
|
|
|
while (--numPoints >= 0)
|
|
{
|
|
const int level = *++line;
|
|
jassert (isPositiveAndBelow (level, (int) 256));
|
|
const int endX = *++line;
|
|
jassert (endX >= x);
|
|
const int endOfRun = (endX >> 8);
|
|
|
|
if (endOfRun == (x >> 8))
|
|
{
|
|
// small segment within the same pixel, so just save it for the next
|
|
// time round..
|
|
levelAccumulator += (endX - x) * level;
|
|
}
|
|
else
|
|
{
|
|
// plot the fist pixel of this segment, including any accumulated
|
|
// levels from smaller segments that haven't been drawn yet
|
|
levelAccumulator += (0x100 - (x & 0xff)) * level;
|
|
levelAccumulator >>= 8;
|
|
x >>= 8;
|
|
|
|
if (levelAccumulator > 0)
|
|
{
|
|
if (levelAccumulator >= 255)
|
|
iterationCallback.handleEdgeTablePixelFull (x);
|
|
else
|
|
iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
|
|
}
|
|
|
|
// if there's a run of similar pixels, do it all in one go..
|
|
if (level > 0)
|
|
{
|
|
jassert (endOfRun <= bounds.getRight());
|
|
const int numPix = endOfRun - ++x;
|
|
|
|
if (numPix > 0)
|
|
iterationCallback.handleEdgeTableLine (x, numPix, level);
|
|
}
|
|
|
|
// save the bit at the end to be drawn next time round the loop.
|
|
levelAccumulator = (endX & 0xff) * level;
|
|
}
|
|
|
|
x = endX;
|
|
}
|
|
|
|
levelAccumulator >>= 8;
|
|
|
|
if (levelAccumulator > 0)
|
|
{
|
|
x >>= 8;
|
|
jassert (x >= bounds.getX() && x < bounds.getRight());
|
|
|
|
if (levelAccumulator >= 255)
|
|
iterationCallback.handleEdgeTablePixelFull (x);
|
|
else
|
|
iterationCallback.handleEdgeTablePixel (x, levelAccumulator);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private:
|
|
|
|
// table line format: number of points; point0 x, point0 levelDelta, point1 x, point1 levelDelta, etc
|
|
HeapBlock<int> table;
|
|
Rectangle<int> bounds;
|
|
int maxEdgesPerLine, lineStrideElements;
|
|
bool needToCheckEmptinesss;
|
|
|
|
void addEdgePoint (int x, int y, int winding);
|
|
void remapTableForNumEdges (int newNumEdgesPerLine);
|
|
void intersectWithEdgeTableLine (int y, const int* otherLine);
|
|
void clipEdgeTableLineToRange (int* line, int x1, int x2) noexcept;
|
|
void sanitiseLevels (bool useNonZeroWinding) noexcept;
|
|
static void copyEdgeTableData (int* dest, int destLineStride, const int* src, int srcLineStride, int numLines) noexcept;
|
|
|
|
JUCE_LEAK_DETECTOR (EdgeTable);
|
|
};
|
|
|
|
#endif // __JUCE_EDGETABLE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_EdgeTable.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILLTYPE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FillType.h ***/
|
|
#ifndef __JUCE_FILLTYPE_JUCEHEADER__
|
|
#define __JUCE_FILLTYPE_JUCEHEADER__
|
|
|
|
/**
|
|
Represents a colour or fill pattern to use for rendering paths.
|
|
|
|
This is used by the Graphics and DrawablePath classes as a way to encapsulate
|
|
a brush type. It can either be a solid colour, a gradient, or a tiled image.
|
|
|
|
@see Graphics::setFillType, DrawablePath::setFill
|
|
*/
|
|
class JUCE_API FillType
|
|
{
|
|
public:
|
|
|
|
/** Creates a default fill type, of solid black. */
|
|
FillType() noexcept;
|
|
|
|
/** Creates a fill type of a solid colour.
|
|
@see setColour
|
|
*/
|
|
FillType (const Colour& colour) noexcept;
|
|
|
|
/** Creates a gradient fill type.
|
|
@see setGradient
|
|
*/
|
|
FillType (const ColourGradient& gradient);
|
|
|
|
/** Creates a tiled image fill type. The transform allows you to set the scaling, offset
|
|
and rotation of the pattern.
|
|
@see setTiledImage
|
|
*/
|
|
FillType (const Image& image, const AffineTransform& transform) noexcept;
|
|
|
|
/** Creates a copy of another FillType. */
|
|
FillType (const FillType& other);
|
|
|
|
/** Makes a copy of another FillType. */
|
|
FillType& operator= (const FillType& other);
|
|
|
|
/** Destructor. */
|
|
~FillType() noexcept;
|
|
|
|
/** Returns true if this is a solid colour fill, and not a gradient or image. */
|
|
bool isColour() const noexcept { return gradient == nullptr && image.isNull(); }
|
|
|
|
/** Returns true if this is a gradient fill. */
|
|
bool isGradient() const noexcept { return gradient != nullptr; }
|
|
|
|
/** Returns true if this is a tiled image pattern fill. */
|
|
bool isTiledImage() const noexcept { return image.isValid(); }
|
|
|
|
/** Turns this object into a solid colour fill.
|
|
If the object was an image or gradient, those fields will no longer be valid. */
|
|
void setColour (const Colour& newColour) noexcept;
|
|
|
|
/** Turns this object into a gradient fill. */
|
|
void setGradient (const ColourGradient& newGradient);
|
|
|
|
/** Turns this object into a tiled image fill type. The transform allows you to set
|
|
the scaling, offset and rotation of the pattern.
|
|
*/
|
|
void setTiledImage (const Image& image, const AffineTransform& transform) noexcept;
|
|
|
|
/** Changes the opacity that should be used.
|
|
If the fill is a solid colour, this just changes the opacity of that colour. For
|
|
gradients and image tiles, it changes the opacity that will be used for them.
|
|
*/
|
|
void setOpacity (float newOpacity) noexcept;
|
|
|
|
/** Returns the current opacity to be applied to the colour, gradient, or image.
|
|
@see setOpacity
|
|
*/
|
|
float getOpacity() const noexcept { return colour.getFloatAlpha(); }
|
|
|
|
/** Returns true if this fill type is completely transparent. */
|
|
bool isInvisible() const noexcept;
|
|
|
|
/** The solid colour being used.
|
|
|
|
If the fill type is not a solid colour, the alpha channel of this colour indicates
|
|
the opacity that should be used for the fill, and the RGB channels are ignored.
|
|
*/
|
|
Colour colour;
|
|
|
|
/** Returns the gradient that should be used for filling.
|
|
This will be zero if the object is some other type of fill.
|
|
If a gradient is active, the overall opacity with which it should be applied
|
|
is indicated by the alpha channel of the colour variable.
|
|
*/
|
|
ScopedPointer <ColourGradient> gradient;
|
|
|
|
/** The image that should be used for tiling.
|
|
If an image fill is active, the overall opacity with which it should be applied
|
|
is indicated by the alpha channel of the colour variable.
|
|
*/
|
|
Image image;
|
|
|
|
/** The transform that should be applied to the image or gradient that's being drawn. */
|
|
AffineTransform transform;
|
|
|
|
bool operator== (const FillType& other) const;
|
|
bool operator!= (const FillType& other) const;
|
|
|
|
private:
|
|
JUCE_LEAK_DETECTOR (FillType);
|
|
};
|
|
|
|
#endif // __JUCE_FILLTYPE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FillType.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_GRAPHICSCONTEXT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_JUSTIFICATION_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_LowLevelGraphicsContext.h ***/
|
|
#ifndef __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__
|
|
#define __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__
|
|
|
|
/**
|
|
Interface class for graphics context objects, used internally by the Graphics class.
|
|
|
|
Users are not supposed to create instances of this class directly - do your drawing
|
|
via the Graphics object instead.
|
|
|
|
It's a base class for different types of graphics context, that may perform software-based
|
|
or OS-accelerated rendering.
|
|
|
|
E.g. the LowLevelGraphicsSoftwareRenderer renders onto an image in memory, but other
|
|
subclasses could render directly to a windows HDC, a Quartz context, or an OpenGL
|
|
context.
|
|
*/
|
|
class JUCE_API LowLevelGraphicsContext
|
|
{
|
|
protected:
|
|
|
|
LowLevelGraphicsContext();
|
|
|
|
public:
|
|
virtual ~LowLevelGraphicsContext();
|
|
|
|
/** Returns true if this device is vector-based, e.g. a printer. */
|
|
virtual bool isVectorDevice() const = 0;
|
|
|
|
/** Moves the origin to a new position.
|
|
|
|
The co-ords are relative to the current origin, and indicate the new position
|
|
of (0, 0).
|
|
*/
|
|
virtual void setOrigin (int x, int y) = 0;
|
|
virtual void addTransform (const AffineTransform& transform) = 0;
|
|
virtual float getScaleFactor() = 0;
|
|
|
|
virtual bool clipToRectangle (const Rectangle<int>& r) = 0;
|
|
virtual bool clipToRectangleList (const RectangleList& clipRegion) = 0;
|
|
virtual void excludeClipRectangle (const Rectangle<int>& r) = 0;
|
|
virtual void clipToPath (const Path& path, const AffineTransform& transform) = 0;
|
|
virtual void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform) = 0;
|
|
|
|
virtual bool clipRegionIntersects (const Rectangle<int>& r) = 0;
|
|
virtual const Rectangle<int> getClipBounds() const = 0;
|
|
virtual bool isClipEmpty() const = 0;
|
|
|
|
virtual void saveState() = 0;
|
|
virtual void restoreState() = 0;
|
|
|
|
virtual void beginTransparencyLayer (float opacity) = 0;
|
|
virtual void endTransparencyLayer() = 0;
|
|
|
|
virtual void setFill (const FillType& fillType) = 0;
|
|
virtual void setOpacity (float newOpacity) = 0;
|
|
virtual void setInterpolationQuality (Graphics::ResamplingQuality quality) = 0;
|
|
|
|
virtual void fillRect (const Rectangle<int>& r, bool replaceExistingContents) = 0;
|
|
virtual void fillPath (const Path& path, const AffineTransform& transform) = 0;
|
|
|
|
virtual void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles) = 0;
|
|
|
|
virtual void drawLine (const Line <float>& line) = 0;
|
|
virtual void drawVerticalLine (int x, float top, float bottom) = 0;
|
|
virtual void drawHorizontalLine (int y, float left, float right) = 0;
|
|
|
|
virtual void setFont (const Font& newFont) = 0;
|
|
virtual Font getFont() = 0;
|
|
virtual void drawGlyph (int glyphNumber, const AffineTransform& transform) = 0;
|
|
};
|
|
|
|
#endif // __JUCE_LOWLEVELGRAPHICSCONTEXT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_LowLevelGraphicsContext.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_LowLevelGraphicsPostScriptRenderer.h ***/
|
|
#ifndef __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__
|
|
#define __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__
|
|
|
|
/**
|
|
An implementation of LowLevelGraphicsContext that turns the drawing operations
|
|
into a PostScript document.
|
|
|
|
*/
|
|
class JUCE_API LowLevelGraphicsPostScriptRenderer : public LowLevelGraphicsContext
|
|
{
|
|
public:
|
|
|
|
LowLevelGraphicsPostScriptRenderer (OutputStream& resultingPostScript,
|
|
const String& documentTitle,
|
|
int totalWidth,
|
|
int totalHeight);
|
|
|
|
~LowLevelGraphicsPostScriptRenderer();
|
|
|
|
bool isVectorDevice() const;
|
|
void setOrigin (int x, int y);
|
|
void addTransform (const AffineTransform& transform);
|
|
float getScaleFactor();
|
|
|
|
bool clipToRectangle (const Rectangle<int>& r);
|
|
bool clipToRectangleList (const RectangleList& clipRegion);
|
|
void excludeClipRectangle (const Rectangle<int>& r);
|
|
void clipToPath (const Path& path, const AffineTransform& transform);
|
|
void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform);
|
|
|
|
void saveState();
|
|
void restoreState();
|
|
|
|
void beginTransparencyLayer (float opacity);
|
|
void endTransparencyLayer();
|
|
|
|
bool clipRegionIntersects (const Rectangle<int>& r);
|
|
const Rectangle<int> getClipBounds() const;
|
|
bool isClipEmpty() const;
|
|
|
|
void setFill (const FillType& fillType);
|
|
void setOpacity (float opacity);
|
|
void setInterpolationQuality (Graphics::ResamplingQuality quality);
|
|
|
|
void fillRect (const Rectangle<int>& r, bool replaceExistingContents);
|
|
void fillPath (const Path& path, const AffineTransform& transform);
|
|
|
|
void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles);
|
|
|
|
void drawLine (const Line <float>& line);
|
|
|
|
void drawVerticalLine (int x, float top, float bottom);
|
|
void drawHorizontalLine (int x, float top, float bottom);
|
|
|
|
Font getFont();
|
|
void setFont (const Font& newFont);
|
|
void drawGlyph (int glyphNumber, const AffineTransform& transform);
|
|
|
|
protected:
|
|
|
|
OutputStream& out;
|
|
int totalWidth, totalHeight;
|
|
bool needToClip;
|
|
Colour lastColour;
|
|
|
|
struct SavedState
|
|
{
|
|
SavedState();
|
|
~SavedState();
|
|
|
|
RectangleList clip;
|
|
int xOffset, yOffset;
|
|
FillType fillType;
|
|
Font font;
|
|
|
|
private:
|
|
SavedState& operator= (const SavedState&);
|
|
};
|
|
|
|
OwnedArray <SavedState> stateStack;
|
|
|
|
void writeClip();
|
|
void writeColour (const Colour& colour);
|
|
void writePath (const Path& path) const;
|
|
void writeXY (float x, float y) const;
|
|
void writeTransform (const AffineTransform& trans) const;
|
|
void writeImage (const Image& im, int sx, int sy, int maxW, int maxH) const;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LowLevelGraphicsPostScriptRenderer);
|
|
};
|
|
|
|
#endif // __JUCE_LOWLEVELGRAPHICSPOSTSCRIPTRENDERER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_LowLevelGraphicsPostScriptRenderer.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_LowLevelGraphicsSoftwareRenderer.h ***/
|
|
#ifndef __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__
|
|
#define __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__
|
|
|
|
/**
|
|
A lowest-common-denominator implementation of LowLevelGraphicsContext that does all
|
|
its rendering in memory.
|
|
|
|
User code is not supposed to create instances of this class directly - do all your
|
|
rendering via the Graphics class instead.
|
|
*/
|
|
class JUCE_API LowLevelGraphicsSoftwareRenderer : public LowLevelGraphicsContext
|
|
{
|
|
public:
|
|
|
|
LowLevelGraphicsSoftwareRenderer (const Image& imageToRenderOn);
|
|
LowLevelGraphicsSoftwareRenderer (const Image& imageToRenderOn, int xOffset, int yOffset, const RectangleList& initialClip);
|
|
~LowLevelGraphicsSoftwareRenderer();
|
|
|
|
bool isVectorDevice() const;
|
|
|
|
void setOrigin (int x, int y);
|
|
void addTransform (const AffineTransform& transform);
|
|
float getScaleFactor();
|
|
|
|
bool clipToRectangle (const Rectangle<int>& r);
|
|
bool clipToRectangleList (const RectangleList& clipRegion);
|
|
void excludeClipRectangle (const Rectangle<int>& r);
|
|
void clipToPath (const Path& path, const AffineTransform& transform);
|
|
void clipToImageAlpha (const Image& sourceImage, const AffineTransform& transform);
|
|
|
|
bool clipRegionIntersects (const Rectangle<int>& r);
|
|
const Rectangle<int> getClipBounds() const;
|
|
bool isClipEmpty() const;
|
|
|
|
void saveState();
|
|
void restoreState();
|
|
|
|
void beginTransparencyLayer (float opacity);
|
|
void endTransparencyLayer();
|
|
|
|
void setFill (const FillType& fillType);
|
|
void setOpacity (float opacity);
|
|
void setInterpolationQuality (Graphics::ResamplingQuality quality);
|
|
|
|
void fillRect (const Rectangle<int>& r, bool replaceExistingContents);
|
|
void fillPath (const Path& path, const AffineTransform& transform);
|
|
|
|
void drawImage (const Image& sourceImage, const AffineTransform& transform, bool fillEntireClipAsTiles);
|
|
|
|
void drawLine (const Line <float>& line);
|
|
|
|
void drawVerticalLine (int x, float top, float bottom);
|
|
void drawHorizontalLine (int x, float top, float bottom);
|
|
|
|
void setFont (const Font& newFont);
|
|
Font getFont();
|
|
void drawGlyph (int glyphNumber, float x, float y);
|
|
void drawGlyph (int glyphNumber, const AffineTransform& transform);
|
|
|
|
protected:
|
|
|
|
Image image;
|
|
|
|
class GlyphCache;
|
|
class CachedGlyph;
|
|
class SavedState;
|
|
friend class ScopedPointer <SavedState>;
|
|
friend class OwnedArray <SavedState>;
|
|
friend class OwnedArray <CachedGlyph>;
|
|
ScopedPointer <SavedState> currentState;
|
|
OwnedArray <SavedState> stateStack;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LowLevelGraphicsSoftwareRenderer);
|
|
};
|
|
|
|
#endif // __JUCE_LOWLEVELGRAPHICSSOFTWARERENDERER_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_LowLevelGraphicsSoftwareRenderer.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_RECTANGLEPLACEMENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAWABLE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DrawableComposite.h ***/
|
|
#ifndef __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__
|
|
#define __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__
|
|
|
|
/**
|
|
A drawable object which acts as a container for a set of other Drawables.
|
|
|
|
@see Drawable
|
|
*/
|
|
class JUCE_API DrawableComposite : public Drawable
|
|
{
|
|
public:
|
|
|
|
/** Creates a composite Drawable. */
|
|
DrawableComposite();
|
|
|
|
/** Creates a copy of a DrawableComposite. */
|
|
DrawableComposite (const DrawableComposite& other);
|
|
|
|
/** Destructor. */
|
|
~DrawableComposite();
|
|
|
|
/** Sets the parallelogram that defines the target position of the content rectangle when the drawable is rendered.
|
|
@see setContentArea
|
|
*/
|
|
void setBoundingBox (const RelativeParallelogram& newBoundingBox);
|
|
|
|
/** Returns the parallelogram that defines the target position of the content rectangle when the drawable is rendered.
|
|
@see setBoundingBox
|
|
*/
|
|
const RelativeParallelogram& getBoundingBox() const noexcept { return bounds; }
|
|
|
|
/** Changes the bounding box transform to match the content area, so that any sub-items will
|
|
be drawn at their untransformed positions.
|
|
*/
|
|
void resetBoundingBoxToContentArea();
|
|
|
|
/** Returns the main content rectangle.
|
|
The content area is actually defined by the markers named "left", "right", "top" and
|
|
"bottom", but this method is a shortcut that returns them all at once.
|
|
@see contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
|
|
*/
|
|
RelativeRectangle getContentArea() const;
|
|
|
|
/** Changes the main content area.
|
|
The content area is actually defined by the markers named "left", "right", "top" and
|
|
"bottom", but this method is a shortcut that sets them all at once.
|
|
@see setBoundingBox, contentLeftMarkerName, contentRightMarkerName, contentTopMarkerName, contentBottomMarkerName
|
|
*/
|
|
void setContentArea (const RelativeRectangle& newArea);
|
|
|
|
/** Resets the content area and the bounding transform to fit around the area occupied
|
|
by the child components (ignoring any markers).
|
|
*/
|
|
void resetContentAreaAndBoundingBoxToFitChildren();
|
|
|
|
/** The name of the marker that defines the left edge of the content area. */
|
|
static const char* const contentLeftMarkerName;
|
|
/** The name of the marker that defines the right edge of the content area. */
|
|
static const char* const contentRightMarkerName;
|
|
/** The name of the marker that defines the top edge of the content area. */
|
|
static const char* const contentTopMarkerName;
|
|
/** The name of the marker that defines the bottom edge of the content area. */
|
|
static const char* const contentBottomMarkerName;
|
|
|
|
/** @internal */
|
|
Drawable* createCopy() const;
|
|
/** @internal */
|
|
void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder);
|
|
/** @internal */
|
|
ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const;
|
|
/** @internal */
|
|
static const Identifier valueTreeType;
|
|
/** @internal */
|
|
Rectangle<float> getDrawableBounds() const;
|
|
/** @internal */
|
|
void childBoundsChanged (Component*);
|
|
/** @internal */
|
|
void childrenChanged();
|
|
/** @internal */
|
|
void parentHierarchyChanged();
|
|
/** @internal */
|
|
MarkerList* getMarkers (bool xAxis);
|
|
|
|
/** Internally-used class for wrapping a DrawableComposite's state into a ValueTree. */
|
|
class ValueTreeWrapper : public Drawable::ValueTreeWrapperBase
|
|
{
|
|
public:
|
|
ValueTreeWrapper (const ValueTree& state);
|
|
|
|
ValueTree getChildList() const;
|
|
ValueTree getChildListCreating (UndoManager* undoManager);
|
|
|
|
RelativeParallelogram getBoundingBox() const;
|
|
void setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager);
|
|
void resetBoundingBoxToContentArea (UndoManager* undoManager);
|
|
|
|
RelativeRectangle getContentArea() const;
|
|
void setContentArea (const RelativeRectangle& newArea, UndoManager* undoManager);
|
|
|
|
MarkerList::ValueTreeWrapper getMarkerList (bool xAxis) const;
|
|
MarkerList::ValueTreeWrapper getMarkerListCreating (bool xAxis, UndoManager* undoManager);
|
|
|
|
static const Identifier topLeft, topRight, bottomLeft;
|
|
|
|
private:
|
|
static const Identifier childGroupTag, markerGroupTagX, markerGroupTagY;
|
|
};
|
|
|
|
private:
|
|
|
|
RelativeParallelogram bounds;
|
|
MarkerList markersX, markersY;
|
|
bool updateBoundsReentrant;
|
|
|
|
friend class Drawable::Positioner<DrawableComposite>;
|
|
bool registerCoordinates (RelativeCoordinatePositionerBase&);
|
|
void recalculateCoordinates (Expression::Scope*);
|
|
|
|
void updateBoundsToFitChildren();
|
|
|
|
DrawableComposite& operator= (const DrawableComposite&);
|
|
JUCE_LEAK_DETECTOR (DrawableComposite);
|
|
};
|
|
|
|
#endif // __JUCE_DRAWABLECOMPOSITE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DrawableComposite.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DrawableImage.h ***/
|
|
#ifndef __JUCE_DRAWABLEIMAGE_JUCEHEADER__
|
|
#define __JUCE_DRAWABLEIMAGE_JUCEHEADER__
|
|
|
|
/**
|
|
A drawable object which is a bitmap image.
|
|
|
|
@see Drawable
|
|
*/
|
|
class JUCE_API DrawableImage : public Drawable
|
|
{
|
|
public:
|
|
|
|
DrawableImage();
|
|
DrawableImage (const DrawableImage& other);
|
|
|
|
/** Destructor. */
|
|
~DrawableImage();
|
|
|
|
/** Sets the image that this drawable will render. */
|
|
void setImage (const Image& imageToUse);
|
|
|
|
/** Returns the current image. */
|
|
const Image& getImage() const noexcept { return image; }
|
|
|
|
/** Sets the opacity to use when drawing the image. */
|
|
void setOpacity (float newOpacity);
|
|
|
|
/** Returns the image's opacity. */
|
|
float getOpacity() const noexcept { return opacity; }
|
|
|
|
/** Sets a colour to draw over the image's alpha channel.
|
|
|
|
By default this is transparent so isn't drawn, but if you set a non-transparent
|
|
colour here, then it will be overlaid on the image, using the image's alpha
|
|
channel as a mask.
|
|
|
|
This is handy for doing things like darkening or lightening an image by overlaying
|
|
it with semi-transparent black or white.
|
|
*/
|
|
void setOverlayColour (const Colour& newOverlayColour);
|
|
|
|
/** Returns the overlay colour. */
|
|
const Colour& getOverlayColour() const noexcept { return overlayColour; }
|
|
|
|
/** Sets the bounding box within which the image should be displayed. */
|
|
void setBoundingBox (const RelativeParallelogram& newBounds);
|
|
|
|
/** Returns the position to which the image's top-left corner should be remapped in the target
|
|
coordinate space when rendering this object.
|
|
@see setTransform
|
|
*/
|
|
const RelativeParallelogram& getBoundingBox() const noexcept { return bounds; }
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
bool hitTest (int x, int y);
|
|
/** @internal */
|
|
Drawable* createCopy() const;
|
|
/** @internal */
|
|
Rectangle<float> getDrawableBounds() const;
|
|
/** @internal */
|
|
void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder);
|
|
/** @internal */
|
|
ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const;
|
|
/** @internal */
|
|
static const Identifier valueTreeType;
|
|
|
|
/** Internally-used class for wrapping a DrawableImage's state into a ValueTree. */
|
|
class ValueTreeWrapper : public Drawable::ValueTreeWrapperBase
|
|
{
|
|
public:
|
|
ValueTreeWrapper (const ValueTree& state);
|
|
|
|
var getImageIdentifier() const;
|
|
void setImageIdentifier (const var& newIdentifier, UndoManager* undoManager);
|
|
Value getImageIdentifierValue (UndoManager* undoManager);
|
|
|
|
float getOpacity() const;
|
|
void setOpacity (float newOpacity, UndoManager* undoManager);
|
|
Value getOpacityValue (UndoManager* undoManager);
|
|
|
|
const Colour getOverlayColour() const;
|
|
void setOverlayColour (const Colour& newColour, UndoManager* undoManager);
|
|
Value getOverlayColourValue (UndoManager* undoManager);
|
|
|
|
RelativeParallelogram getBoundingBox() const;
|
|
void setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager);
|
|
|
|
static const Identifier opacity, overlay, image, topLeft, topRight, bottomLeft;
|
|
};
|
|
|
|
private:
|
|
|
|
Image image;
|
|
float opacity;
|
|
Colour overlayColour;
|
|
RelativeParallelogram bounds;
|
|
|
|
friend class Drawable::Positioner<DrawableImage>;
|
|
bool registerCoordinates (RelativeCoordinatePositionerBase&);
|
|
void recalculateCoordinates (Expression::Scope*);
|
|
|
|
DrawableImage& operator= (const DrawableImage&);
|
|
JUCE_LEAK_DETECTOR (DrawableImage);
|
|
};
|
|
|
|
#endif // __JUCE_DRAWABLEIMAGE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DrawableImage.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DrawablePath.h ***/
|
|
#ifndef __JUCE_DRAWABLEPATH_JUCEHEADER__
|
|
#define __JUCE_DRAWABLEPATH_JUCEHEADER__
|
|
|
|
|
|
/*** Start of inlined file: juce_DrawableShape.h ***/
|
|
#ifndef __JUCE_DRAWABLESHAPE_JUCEHEADER__
|
|
#define __JUCE_DRAWABLESHAPE_JUCEHEADER__
|
|
|
|
/**
|
|
A base class implementing common functionality for Drawable classes which
|
|
consist of some kind of filled and stroked outline.
|
|
|
|
@see DrawablePath, DrawableRectangle
|
|
*/
|
|
class JUCE_API DrawableShape : public Drawable
|
|
{
|
|
protected:
|
|
|
|
DrawableShape();
|
|
DrawableShape (const DrawableShape&);
|
|
|
|
public:
|
|
/** Destructor. */
|
|
~DrawableShape();
|
|
|
|
/** A FillType wrapper that allows the gradient coordinates to be implemented using RelativePoint.
|
|
*/
|
|
class RelativeFillType
|
|
{
|
|
public:
|
|
RelativeFillType();
|
|
RelativeFillType (const FillType& fill);
|
|
RelativeFillType (const RelativeFillType&);
|
|
RelativeFillType& operator= (const RelativeFillType&);
|
|
|
|
bool operator== (const RelativeFillType&) const;
|
|
bool operator!= (const RelativeFillType&) const;
|
|
|
|
bool isDynamic() const;
|
|
bool recalculateCoords (Expression::Scope* scope);
|
|
|
|
void writeTo (ValueTree& v, ComponentBuilder::ImageProvider*, UndoManager*) const;
|
|
bool readFrom (const ValueTree& v, ComponentBuilder::ImageProvider*);
|
|
|
|
FillType fill;
|
|
RelativePoint gradientPoint1, gradientPoint2, gradientPoint3;
|
|
};
|
|
|
|
/** Sets a fill type for the path.
|
|
This colour is used to fill the path - if you don't want the path to be
|
|
filled (e.g. if you're just drawing an outline), set this to a transparent
|
|
colour.
|
|
|
|
@see setPath, setStrokeFill
|
|
*/
|
|
void setFill (const FillType& newFill);
|
|
|
|
/** Sets a fill type for the path.
|
|
This colour is used to fill the path - if you don't want the path to be
|
|
filled (e.g. if you're just drawing an outline), set this to a transparent
|
|
colour.
|
|
|
|
@see setPath, setStrokeFill
|
|
*/
|
|
void setFill (const RelativeFillType& newFill);
|
|
|
|
/** Returns the current fill type.
|
|
@see setFill
|
|
*/
|
|
const RelativeFillType& getFill() const noexcept { return mainFill; }
|
|
|
|
/** Sets the fill type with which the outline will be drawn.
|
|
@see setFill
|
|
*/
|
|
void setStrokeFill (const FillType& newStrokeFill);
|
|
|
|
/** Sets the fill type with which the outline will be drawn.
|
|
@see setFill
|
|
*/
|
|
void setStrokeFill (const RelativeFillType& newStrokeFill);
|
|
|
|
/** Returns the current stroke fill.
|
|
@see setStrokeFill
|
|
*/
|
|
const RelativeFillType& getStrokeFill() const noexcept { return strokeFill; }
|
|
|
|
/** Changes the properties of the outline that will be drawn around the path.
|
|
If the stroke has 0 thickness, no stroke will be drawn.
|
|
@see setStrokeThickness, setStrokeColour
|
|
*/
|
|
void setStrokeType (const PathStrokeType& newStrokeType);
|
|
|
|
/** Changes the stroke thickness.
|
|
This is a shortcut for calling setStrokeType.
|
|
*/
|
|
void setStrokeThickness (float newThickness);
|
|
|
|
/** Returns the current outline style. */
|
|
const PathStrokeType& getStrokeType() const noexcept { return strokeType; }
|
|
|
|
/** @internal */
|
|
class FillAndStrokeState : public Drawable::ValueTreeWrapperBase
|
|
{
|
|
public:
|
|
FillAndStrokeState (const ValueTree& state);
|
|
|
|
ValueTree getFillState (const Identifier& fillOrStrokeType);
|
|
RelativeFillType getFill (const Identifier& fillOrStrokeType, ComponentBuilder::ImageProvider*) const;
|
|
void setFill (const Identifier& fillOrStrokeType, const RelativeFillType& newFill,
|
|
ComponentBuilder::ImageProvider*, UndoManager*);
|
|
|
|
PathStrokeType getStrokeType() const;
|
|
void setStrokeType (const PathStrokeType& newStrokeType, UndoManager*);
|
|
|
|
static const Identifier type, colour, colours, fill, stroke, path, jointStyle, capStyle, strokeWidth,
|
|
gradientPoint1, gradientPoint2, gradientPoint3, radial, imageId, imageOpacity;
|
|
};
|
|
|
|
/** @internal */
|
|
Rectangle<float> getDrawableBounds() const;
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
bool hitTest (int x, int y);
|
|
|
|
protected:
|
|
|
|
/** Called when the cached path should be updated. */
|
|
void pathChanged();
|
|
/** Called when the cached stroke should be updated. */
|
|
void strokeChanged();
|
|
/** True if there's a stroke with a non-zero thickness and non-transparent colour. */
|
|
bool isStrokeVisible() const noexcept;
|
|
/** Updates the details from a FillAndStrokeState object, returning true if something changed. */
|
|
void refreshFillTypes (const FillAndStrokeState& newState, ComponentBuilder::ImageProvider*);
|
|
/** Writes the stroke and fill details to a FillAndStrokeState object. */
|
|
void writeTo (FillAndStrokeState& state, ComponentBuilder::ImageProvider*, UndoManager*) const;
|
|
|
|
PathStrokeType strokeType;
|
|
Path path, strokePath;
|
|
|
|
private:
|
|
class RelativePositioner;
|
|
RelativeFillType mainFill, strokeFill;
|
|
ScopedPointer<RelativeCoordinatePositionerBase> mainFillPositioner, strokeFillPositioner;
|
|
|
|
void setFillInternal (RelativeFillType& fill, const RelativeFillType& newFill,
|
|
ScopedPointer<RelativeCoordinatePositionerBase>& positioner);
|
|
|
|
DrawableShape& operator= (const DrawableShape&);
|
|
};
|
|
|
|
#endif // __JUCE_DRAWABLESHAPE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DrawableShape.h ***/
|
|
|
|
/**
|
|
A drawable object which renders a filled or outlined shape.
|
|
|
|
For details on how to change the fill and stroke, see the DrawableShape class.
|
|
|
|
@see Drawable, DrawableShape
|
|
*/
|
|
class JUCE_API DrawablePath : public DrawableShape
|
|
{
|
|
public:
|
|
|
|
/** Creates a DrawablePath. */
|
|
DrawablePath();
|
|
DrawablePath (const DrawablePath& other);
|
|
|
|
/** Destructor. */
|
|
~DrawablePath();
|
|
|
|
/** Changes the path that will be drawn.
|
|
@see setFillColour, setStrokeType
|
|
*/
|
|
void setPath (const Path& newPath);
|
|
|
|
/** Sets the path using a RelativePointPath.
|
|
Calling this will set up a Component::Positioner to automatically update the path
|
|
if any of the points in the source path are dynamic.
|
|
*/
|
|
void setPath (const RelativePointPath& newPath);
|
|
|
|
/** Returns the current path. */
|
|
const Path& getPath() const;
|
|
|
|
/** Returns the current path for the outline. */
|
|
const Path& getStrokePath() const;
|
|
|
|
/** @internal */
|
|
Drawable* createCopy() const;
|
|
/** @internal */
|
|
void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder);
|
|
/** @internal */
|
|
ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const;
|
|
/** @internal */
|
|
static const Identifier valueTreeType;
|
|
|
|
/** Internally-used class for wrapping a DrawablePath's state into a ValueTree. */
|
|
class ValueTreeWrapper : public DrawableShape::FillAndStrokeState
|
|
{
|
|
public:
|
|
ValueTreeWrapper (const ValueTree& state);
|
|
|
|
bool usesNonZeroWinding() const;
|
|
void setUsesNonZeroWinding (bool b, UndoManager* undoManager);
|
|
|
|
class Element
|
|
{
|
|
public:
|
|
explicit Element (const ValueTree& state);
|
|
~Element();
|
|
|
|
const Identifier getType() const noexcept { return state.getType(); }
|
|
int getNumControlPoints() const noexcept;
|
|
|
|
RelativePoint getControlPoint (int index) const;
|
|
Value getControlPointValue (int index, UndoManager*) const;
|
|
RelativePoint getStartPoint() const;
|
|
RelativePoint getEndPoint() const;
|
|
void setControlPoint (int index, const RelativePoint& point, UndoManager*);
|
|
float getLength (Expression::Scope*) const;
|
|
|
|
ValueTreeWrapper getParent() const;
|
|
Element getPreviousElement() const;
|
|
|
|
String getModeOfEndPoint() const;
|
|
void setModeOfEndPoint (const String& newMode, UndoManager*);
|
|
|
|
void convertToLine (UndoManager*);
|
|
void convertToCubic (Expression::Scope*, UndoManager*);
|
|
void convertToPathBreak (UndoManager* undoManager);
|
|
ValueTree insertPoint (const Point<float>& targetPoint, Expression::Scope*, UndoManager*);
|
|
void removePoint (UndoManager* undoManager);
|
|
float findProportionAlongLine (const Point<float>& targetPoint, Expression::Scope*) const;
|
|
|
|
static const Identifier mode, startSubPathElement, closeSubPathElement,
|
|
lineToElement, quadraticToElement, cubicToElement;
|
|
static const char* cornerMode;
|
|
static const char* roundedMode;
|
|
static const char* symmetricMode;
|
|
|
|
ValueTree state;
|
|
};
|
|
|
|
ValueTree getPathState();
|
|
|
|
void readFrom (const RelativePointPath& path, UndoManager* undoManager);
|
|
void writeTo (RelativePointPath& path) const;
|
|
|
|
static const Identifier nonZeroWinding, point1, point2, point3;
|
|
};
|
|
|
|
private:
|
|
|
|
ScopedPointer<RelativePointPath> relativePath;
|
|
|
|
class RelativePositioner;
|
|
friend class RelativePositioner;
|
|
void applyRelativePath (const RelativePointPath&, Expression::Scope*);
|
|
|
|
DrawablePath& operator= (const DrawablePath&);
|
|
JUCE_LEAK_DETECTOR (DrawablePath);
|
|
};
|
|
|
|
#endif // __JUCE_DRAWABLEPATH_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DrawablePath.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAWABLERECTANGLE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DrawableRectangle.h ***/
|
|
#ifndef __JUCE_DRAWABLERECTANGLE_JUCEHEADER__
|
|
#define __JUCE_DRAWABLERECTANGLE_JUCEHEADER__
|
|
|
|
/**
|
|
A Drawable object which draws a rectangle.
|
|
|
|
For details on how to change the fill and stroke, see the DrawableShape class.
|
|
|
|
@see Drawable, DrawableShape
|
|
*/
|
|
class JUCE_API DrawableRectangle : public DrawableShape
|
|
{
|
|
public:
|
|
|
|
DrawableRectangle();
|
|
DrawableRectangle (const DrawableRectangle& other);
|
|
|
|
/** Destructor. */
|
|
~DrawableRectangle();
|
|
|
|
/** Sets the rectangle's bounds. */
|
|
void setRectangle (const RelativeParallelogram& newBounds);
|
|
|
|
/** Returns the rectangle's bounds. */
|
|
const RelativeParallelogram& getRectangle() const noexcept { return bounds; }
|
|
|
|
/** Returns the corner size to be used. */
|
|
const RelativePoint& getCornerSize() const noexcept { return cornerSize; }
|
|
|
|
/** Sets a new corner size for the rectangle */
|
|
void setCornerSize (const RelativePoint& newSize);
|
|
|
|
/** @internal */
|
|
Drawable* createCopy() const;
|
|
/** @internal */
|
|
void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder);
|
|
/** @internal */
|
|
ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const;
|
|
/** @internal */
|
|
static const Identifier valueTreeType;
|
|
|
|
/** Internally-used class for wrapping a DrawableRectangle's state into a ValueTree. */
|
|
class ValueTreeWrapper : public DrawableShape::FillAndStrokeState
|
|
{
|
|
public:
|
|
ValueTreeWrapper (const ValueTree& state);
|
|
|
|
RelativeParallelogram getRectangle() const;
|
|
void setRectangle (const RelativeParallelogram& newBounds, UndoManager*);
|
|
|
|
void setCornerSize (const RelativePoint& cornerSize, UndoManager*);
|
|
RelativePoint getCornerSize() const;
|
|
Value getCornerSizeValue (UndoManager*) const;
|
|
|
|
static const Identifier topLeft, topRight, bottomLeft, cornerSize;
|
|
};
|
|
|
|
private:
|
|
friend class Drawable::Positioner<DrawableRectangle>;
|
|
|
|
RelativeParallelogram bounds;
|
|
RelativePoint cornerSize;
|
|
|
|
void rebuildPath();
|
|
bool registerCoordinates (RelativeCoordinatePositionerBase&);
|
|
void recalculateCoordinates (Expression::Scope*);
|
|
|
|
DrawableRectangle& operator= (const DrawableRectangle&);
|
|
JUCE_LEAK_DETECTOR (DrawableRectangle);
|
|
};
|
|
|
|
#endif // __JUCE_DRAWABLERECTANGLE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DrawableRectangle.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAWABLESHAPE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_DrawableText.h ***/
|
|
#ifndef __JUCE_DRAWABLETEXT_JUCEHEADER__
|
|
#define __JUCE_DRAWABLETEXT_JUCEHEADER__
|
|
|
|
/**
|
|
A drawable object which renders a line of text.
|
|
|
|
@see Drawable
|
|
*/
|
|
class JUCE_API DrawableText : public Drawable
|
|
{
|
|
public:
|
|
|
|
/** Creates a DrawableText object. */
|
|
DrawableText();
|
|
DrawableText (const DrawableText& other);
|
|
|
|
/** Destructor. */
|
|
~DrawableText();
|
|
|
|
/** Sets the text to display.*/
|
|
void setText (const String& newText);
|
|
|
|
/** Sets the colour of the text. */
|
|
void setColour (const Colour& newColour);
|
|
|
|
/** Returns the current text colour. */
|
|
const Colour& getColour() const noexcept { return colour; }
|
|
|
|
/** Sets the font to use.
|
|
Note that the font height and horizontal scale are actually based upon the position
|
|
of the fontSizeAndScaleAnchor parameter to setBounds(). If applySizeAndScale is true, then
|
|
the height and scale control point will be moved to match the dimensions of the font supplied;
|
|
if it is false, then the new font's height and scale are ignored.
|
|
*/
|
|
void setFont (const Font& newFont, bool applySizeAndScale);
|
|
|
|
/** Changes the justification of the text within the bounding box. */
|
|
void setJustification (const Justification& newJustification);
|
|
|
|
/** Returns the parallelogram that defines the text bounding box. */
|
|
const RelativeParallelogram& getBoundingBox() const noexcept { return bounds; }
|
|
|
|
/** Sets the bounding box that contains the text. */
|
|
void setBoundingBox (const RelativeParallelogram& newBounds);
|
|
|
|
/** Returns the point within the bounds that defines the font's size and scale. */
|
|
const RelativePoint& getFontSizeControlPoint() const noexcept { return fontSizeControlPoint; }
|
|
|
|
/** Sets the control point that defines the font's height and horizontal scale.
|
|
This position is a point within the bounding box parallelogram, whose Y position (relative
|
|
to the parallelogram's origin and possibly distorted shape) specifies the font's height,
|
|
and its X defines the font's horizontal scale.
|
|
*/
|
|
void setFontSizeControlPoint (const RelativePoint& newPoint);
|
|
|
|
/** @internal */
|
|
void paint (Graphics& g);
|
|
/** @internal */
|
|
Drawable* createCopy() const;
|
|
/** @internal */
|
|
void refreshFromValueTree (const ValueTree& tree, ComponentBuilder& builder);
|
|
/** @internal */
|
|
ValueTree createValueTree (ComponentBuilder::ImageProvider* imageProvider) const;
|
|
/** @internal */
|
|
static const Identifier valueTreeType;
|
|
/** @internal */
|
|
Rectangle<float> getDrawableBounds() const;
|
|
|
|
/** Internally-used class for wrapping a DrawableText's state into a ValueTree. */
|
|
class ValueTreeWrapper : public Drawable::ValueTreeWrapperBase
|
|
{
|
|
public:
|
|
ValueTreeWrapper (const ValueTree& state);
|
|
|
|
String getText() const;
|
|
void setText (const String& newText, UndoManager* undoManager);
|
|
Value getTextValue (UndoManager* undoManager);
|
|
|
|
Colour getColour() const;
|
|
void setColour (const Colour& newColour, UndoManager* undoManager);
|
|
|
|
Justification getJustification() const;
|
|
void setJustification (const Justification& newJustification, UndoManager* undoManager);
|
|
|
|
Font getFont() const;
|
|
void setFont (const Font& newFont, UndoManager* undoManager);
|
|
Value getFontValue (UndoManager* undoManager);
|
|
|
|
RelativeParallelogram getBoundingBox() const;
|
|
void setBoundingBox (const RelativeParallelogram& newBounds, UndoManager* undoManager);
|
|
|
|
RelativePoint getFontSizeControlPoint() const;
|
|
void setFontSizeControlPoint (const RelativePoint& p, UndoManager* undoManager);
|
|
|
|
static const Identifier text, colour, font, justification, topLeft, topRight, bottomLeft, fontSizeAnchor;
|
|
};
|
|
|
|
private:
|
|
|
|
RelativeParallelogram bounds;
|
|
RelativePoint fontSizeControlPoint;
|
|
Point<float> resolvedPoints[3];
|
|
Font font, scaledFont;
|
|
String text;
|
|
Colour colour;
|
|
Justification justification;
|
|
|
|
friend class Drawable::Positioner<DrawableText>;
|
|
bool registerCoordinates (RelativeCoordinatePositionerBase&);
|
|
void recalculateCoordinates (Expression::Scope*);
|
|
void refreshBounds();
|
|
const AffineTransform getArrangementAndTransform (GlyphArrangement& glyphs) const;
|
|
|
|
DrawableText& operator= (const DrawableText&);
|
|
JUCE_LEAK_DETECTOR (DrawableText);
|
|
};
|
|
|
|
#endif // __JUCE_DRAWABLETEXT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_DrawableText.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DROPSHADOWEFFECT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_GLOWEFFECT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_GlowEffect.h ***/
|
|
#ifndef __JUCE_GLOWEFFECT_JUCEHEADER__
|
|
#define __JUCE_GLOWEFFECT_JUCEHEADER__
|
|
|
|
/**
|
|
A component effect that adds a coloured blur around the component's contents.
|
|
|
|
(This will only work on non-opaque components).
|
|
|
|
@see Component::setComponentEffect, DropShadowEffect
|
|
*/
|
|
class JUCE_API GlowEffect : public ImageEffectFilter
|
|
{
|
|
public:
|
|
|
|
/** Creates a default 'glow' effect.
|
|
|
|
To customise its appearance, use the setGlowProperties() method.
|
|
*/
|
|
GlowEffect();
|
|
|
|
/** Destructor. */
|
|
~GlowEffect();
|
|
|
|
/** Sets the glow's radius and colour.
|
|
|
|
The radius is how large the blur should be, and the colour is
|
|
used to render it (for a less intense glow, lower the colour's
|
|
opacity).
|
|
*/
|
|
void setGlowProperties (float newRadius,
|
|
const Colour& newColour);
|
|
|
|
/** @internal */
|
|
void applyEffect (Image& sourceImage, Graphics& destContext, float alpha);
|
|
|
|
private:
|
|
|
|
float radius;
|
|
Colour colour;
|
|
|
|
JUCE_LEAK_DETECTOR (GlowEffect);
|
|
};
|
|
|
|
#endif // __JUCE_GLOWEFFECT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_GlowEffect.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_IMAGEEFFECTFILTER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CUSTOMTYPEFACE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_CustomTypeface.h ***/
|
|
#ifndef __JUCE_CUSTOMTYPEFACE_JUCEHEADER__
|
|
#define __JUCE_CUSTOMTYPEFACE_JUCEHEADER__
|
|
|
|
class InputStream;
|
|
class OutputStream;
|
|
|
|
/**
|
|
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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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) noexcept;
|
|
|
|
/** 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 <int>& glyphs, Array<float>& xOffsets);
|
|
bool getOutlineForGlyph (int glyphNumber, Path& path);
|
|
EdgeTable* getEdgeTableForGlyph (int glyphNumber, const AffineTransform& transform);
|
|
|
|
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<GlyphInfo>;
|
|
OwnedArray <GlyphInfo> glyphs;
|
|
short lookupTable [128];
|
|
|
|
GlyphInfo* findGlyph (const juce_wchar character, bool loadIfNeeded) noexcept;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CustomTypeface);
|
|
};
|
|
|
|
#endif // __JUCE_CUSTOMTYPEFACE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CustomTypeface.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_FONT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_GLYPHARRANGEMENT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TEXTLAYOUT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_TYPEFACE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_AFFINETRANSFORM_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_BORDERSIZE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_LINE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_PATH_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_PATHITERATOR_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_PathIterator.h ***/
|
|
#ifndef __JUCE_PATHITERATOR_JUCEHEADER__
|
|
#define __JUCE_PATHITERATOR_JUCEHEADER__
|
|
|
|
/**
|
|
Flattens a Path object into a series of straight-line sections.
|
|
|
|
Use one of these to iterate through a Path object, and it will convert
|
|
all the curves into line sections so it's easy to render or perform
|
|
geometric operations on.
|
|
|
|
@see Path
|
|
*/
|
|
class JUCE_API PathFlatteningIterator
|
|
{
|
|
public:
|
|
|
|
/** Creates a PathFlatteningIterator.
|
|
|
|
After creation, use the next() method to initialise the fields in the
|
|
object with the first line's position.
|
|
|
|
@param path the path to iterate along
|
|
@param transform a transform to apply to each point in the path being iterated
|
|
@param tolerance the amount by which the curves are allowed to deviate from the lines
|
|
into which they are being broken down - a higher tolerance contains
|
|
less lines, so can be generated faster, but will be less smooth.
|
|
*/
|
|
PathFlatteningIterator (const Path& path,
|
|
const AffineTransform& transform = AffineTransform::identity,
|
|
float tolerance = defaultTolerance);
|
|
|
|
/** Destructor. */
|
|
~PathFlatteningIterator();
|
|
|
|
/** Fetches the next line segment from the path.
|
|
|
|
This will update the member variables x1, y1, x2, y2, subPathIndex and closesSubPath
|
|
so that they describe the new line segment.
|
|
|
|
@returns false when there are no more lines to fetch.
|
|
*/
|
|
bool next();
|
|
|
|
float x1; /**< The x position of the start of the current line segment. */
|
|
float y1; /**< The y position of the start of the current line segment. */
|
|
float x2; /**< The x position of the end of the current line segment. */
|
|
float y2; /**< The y position of the end of the current line segment. */
|
|
|
|
/** Indicates whether the current line segment is closing a sub-path.
|
|
|
|
If the current line is the one that connects the end of a sub-path
|
|
back to the start again, this will be true.
|
|
*/
|
|
bool closesSubPath;
|
|
|
|
/** The index of the current line within the current sub-path.
|
|
|
|
E.g. you can use this to see whether the line is the first one in the
|
|
subpath by seeing if it's 0.
|
|
*/
|
|
int subPathIndex;
|
|
|
|
/** Returns true if the current segment is the last in the current sub-path. */
|
|
bool isLastInSubpath() const noexcept;
|
|
|
|
/** This is the default value that should be used for the tolerance value (see the constructor parameters). */
|
|
static const float defaultTolerance;
|
|
|
|
private:
|
|
|
|
const Path& path;
|
|
const AffineTransform transform;
|
|
float* points;
|
|
const float toleranceSquared;
|
|
float subPathCloseX, subPathCloseY;
|
|
const bool isIdentityTransform;
|
|
|
|
HeapBlock <float> stackBase;
|
|
float* stackPos;
|
|
size_t index, stackSize;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PathFlatteningIterator);
|
|
};
|
|
|
|
#endif // __JUCE_PATHITERATOR_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_PathIterator.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_PATHSTROKETYPE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_POINT_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RECTANGLE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RECTANGLELIST_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_CAMERADEVICE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_CameraDevice.h ***/
|
|
#ifndef __JUCE_CAMERADEVICE_JUCEHEADER__
|
|
#define __JUCE_CAMERADEVICE_JUCEHEADER__
|
|
|
|
#if JUCE_USE_CAMERA || DOXYGEN
|
|
|
|
/**
|
|
Controls any video capture devices that might be available.
|
|
|
|
Use getAvailableDevices() to list the devices that are attached to the
|
|
system, then call openDevice to open one for use. Once you have a CameraDevice
|
|
object, you can get a viewer component from it, and use its methods to
|
|
stream to a file or capture still-frames.
|
|
*/
|
|
class JUCE_API CameraDevice
|
|
{
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~CameraDevice();
|
|
|
|
/** Returns a list of the available cameras on this machine.
|
|
|
|
You can open one of these devices by calling openDevice().
|
|
*/
|
|
static StringArray getAvailableDevices();
|
|
|
|
/** Opens a camera device.
|
|
|
|
The index parameter indicates which of the items returned by getAvailableDevices()
|
|
to open.
|
|
|
|
The size constraints allow the method to choose between different resolutions if
|
|
the camera supports this. If the resolution cam't be specified (e.g. on the Mac)
|
|
then these will be ignored.
|
|
*/
|
|
static CameraDevice* openDevice (int deviceIndex,
|
|
int minWidth = 128, int minHeight = 64,
|
|
int maxWidth = 1024, int maxHeight = 768);
|
|
|
|
/** Returns the name of this device */
|
|
String getName() const { return name; }
|
|
|
|
/** Creates a component that can be used to display a preview of the
|
|
video from this camera.
|
|
*/
|
|
Component* createViewerComponent();
|
|
|
|
/** Starts recording video to the specified file.
|
|
|
|
You should use getFileExtension() to find out the correct extension to
|
|
use for your filename.
|
|
|
|
If the file exists, it will be deleted before the recording starts.
|
|
|
|
This method may not start recording instantly, so if you need to know the
|
|
exact time at which the file begins, you can call getTimeOfFirstRecordedFrame()
|
|
after the recording has finished.
|
|
|
|
The quality parameter can be 0, 1, or 2, to indicate low, medium, or high. It may
|
|
or may not be used, depending on the driver.
|
|
*/
|
|
void startRecordingToFile (const File& file, int quality = 2);
|
|
|
|
/** Stops recording, after a call to startRecordingToFile().
|
|
*/
|
|
void stopRecording();
|
|
|
|
/** Returns the file extension that should be used for the files
|
|
that you pass to startRecordingToFile().
|
|
|
|
This may be platform-specific, e.g. ".mov" or ".avi".
|
|
*/
|
|
static String getFileExtension();
|
|
|
|
/** After calling stopRecording(), this method can be called to return the timestamp
|
|
of the first frame that was written to the file.
|
|
*/
|
|
Time getTimeOfFirstRecordedFrame() const;
|
|
|
|
/**
|
|
Receives callbacks with images from a CameraDevice.
|
|
|
|
@see CameraDevice::addListener
|
|
*/
|
|
class JUCE_API Listener
|
|
{
|
|
public:
|
|
Listener() {}
|
|
virtual ~Listener() {}
|
|
|
|
/** This method is called when a new image arrives.
|
|
|
|
This may be called by any thread, so be careful about thread-safety,
|
|
and make sure that you process the data as quickly as possible to
|
|
avoid glitching!
|
|
*/
|
|
virtual void imageReceived (const Image& image) = 0;
|
|
};
|
|
|
|
/** Adds a listener to receive images from the camera.
|
|
|
|
Be very careful not to delete the listener without first removing it by calling
|
|
removeListener().
|
|
*/
|
|
void addListener (Listener* listenerToAdd);
|
|
|
|
/** Removes a listener that was previously added with addListener().
|
|
*/
|
|
void removeListener (Listener* listenerToRemove);
|
|
|
|
protected:
|
|
#ifndef DOXYGEN
|
|
CameraDevice (const String& name, int index);
|
|
#endif
|
|
|
|
private:
|
|
void* internal;
|
|
bool isRecording;
|
|
String name;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CameraDevice);
|
|
};
|
|
|
|
/** This typedef is just for compatibility with old code - newer code should use the CameraDevice::Listener class directly. */
|
|
typedef CameraDevice::Listener CameraImageListener;
|
|
|
|
#endif
|
|
#endif // __JUCE_CAMERADEVICE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_CameraDevice.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_IMAGE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_IMAGECACHE_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ImageCache.h ***/
|
|
#ifndef __JUCE_IMAGECACHE_JUCEHEADER__
|
|
#define __JUCE_IMAGECACHE_JUCEHEADER__
|
|
|
|
/**
|
|
A global cache of images that have been loaded from files or memory.
|
|
|
|
If you're loading an image and may need to use the image in more than one
|
|
place, this is used to allow the same image to be shared rather than loading
|
|
multiple copies into memory.
|
|
|
|
Another advantage is that after images are released, they will be kept in
|
|
memory for a few seconds before it is actually deleted, so if you're repeatedly
|
|
loading/deleting the same image, it'll reduce the chances of having to reload it
|
|
each time.
|
|
|
|
@see Image, ImageFileFormat
|
|
*/
|
|
class JUCE_API ImageCache
|
|
{
|
|
public:
|
|
|
|
/** Loads an image from a file, (or just returns the image if it's already cached).
|
|
|
|
If the cache already contains an image that was loaded from this file,
|
|
that image will be returned. Otherwise, this method will try to load the
|
|
file, add it to the cache, and return it.
|
|
|
|
Remember that the image returned is shared, so drawing into it might
|
|
affect other things that are using it! If you want to draw on it, first
|
|
call Image::duplicateIfShared()
|
|
|
|
@param file the file to try to load
|
|
@returns the image, or null if it there was an error loading it
|
|
@see getFromMemory, getFromCache, ImageFileFormat::loadFrom
|
|
*/
|
|
static Image getFromFile (const File& file);
|
|
|
|
/** Loads an image from an in-memory image file, (or just returns the image if it's already cached).
|
|
|
|
If the cache already contains an image that was loaded from this block of memory,
|
|
that image will be returned. Otherwise, this method will try to load the
|
|
file, add it to the cache, and return it.
|
|
|
|
Remember that the image returned is shared, so drawing into it might
|
|
affect other things that are using it! If you want to draw on it, first
|
|
call Image::duplicateIfShared()
|
|
|
|
@param imageData the block of memory containing the image data
|
|
@param dataSize the data size in bytes
|
|
@returns the image, or an invalid image if it there was an error loading it
|
|
@see getFromMemory, getFromCache, ImageFileFormat::loadFrom
|
|
*/
|
|
static Image getFromMemory (const void* imageData, int dataSize);
|
|
|
|
/** Checks the cache for an image with a particular hashcode.
|
|
|
|
If there's an image in the cache with this hashcode, it will be returned,
|
|
otherwise it will return an invalid image.
|
|
|
|
@param hashCode the hash code that was associated with the image by addImageToCache()
|
|
@see addImageToCache
|
|
*/
|
|
static Image getFromHashCode (int64 hashCode);
|
|
|
|
/** Adds an image to the cache with a user-defined hash-code.
|
|
|
|
The image passed-in will be referenced (not copied) by the cache, so it's probably
|
|
a good idea not to draw into it after adding it, otherwise this will affect all
|
|
instances of it that may be in use.
|
|
|
|
@param image the image to add
|
|
@param hashCode the hash-code to associate with it
|
|
@see getFromHashCode
|
|
*/
|
|
static void addImageToCache (const Image& image, int64 hashCode);
|
|
|
|
/** Changes the amount of time before an unused image will be removed from the cache.
|
|
By default this is about 5 seconds.
|
|
*/
|
|
static void setCacheTimeout (int millisecs);
|
|
|
|
private:
|
|
|
|
class Pimpl;
|
|
friend class Pimpl;
|
|
|
|
ImageCache();
|
|
~ImageCache();
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (ImageCache);
|
|
};
|
|
|
|
#endif // __JUCE_IMAGECACHE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ImageCache.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ImageConvolutionKernel.h ***/
|
|
#ifndef __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__
|
|
#define __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__
|
|
|
|
/**
|
|
Represents a filter kernel to use in convoluting an image.
|
|
|
|
@see Image::applyConvolution
|
|
*/
|
|
class JUCE_API ImageConvolutionKernel
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty convulution kernel.
|
|
|
|
@param size the length of each dimension of the kernel, so e.g. if the size
|
|
is 5, it will create a 5x5 kernel
|
|
*/
|
|
ImageConvolutionKernel (int size);
|
|
|
|
/** Destructor. */
|
|
~ImageConvolutionKernel();
|
|
|
|
/** Resets all values in the kernel to zero. */
|
|
void clear();
|
|
|
|
/** Returns one of the kernel values. */
|
|
float getKernelValue (int x, int y) const noexcept;
|
|
|
|
/** Sets the value of a specific cell in the kernel.
|
|
|
|
The x and y parameters must be in the range 0 < x < getKernelSize().
|
|
|
|
@see setOverallSum
|
|
*/
|
|
void setKernelValue (int x, int y, float value) noexcept;
|
|
|
|
/** Rescales all values in the kernel to make the total add up to a fixed value.
|
|
|
|
This will multiply all values in the kernel by (desiredTotalSum / currentTotalSum).
|
|
*/
|
|
void setOverallSum (float desiredTotalSum);
|
|
|
|
/** Multiplies all values in the kernel by a value. */
|
|
void rescaleAllValues (float multiplier);
|
|
|
|
/** Intialises the kernel for a gaussian blur.
|
|
|
|
@param blurRadius this may be larger or smaller than the kernel's actual
|
|
size but this will obviously be wasteful or clip at the
|
|
edges. Ideally the kernel should be just larger than
|
|
(blurRadius * 2).
|
|
*/
|
|
void createGaussianBlur (float blurRadius);
|
|
|
|
/** Returns the size of the kernel.
|
|
|
|
E.g. if it's a 3x3 kernel, this returns 3.
|
|
*/
|
|
int getKernelSize() const { return size; }
|
|
|
|
/** Applies the kernel to an image.
|
|
|
|
@param destImage the image that will receive the resultant convoluted pixels.
|
|
@param sourceImage the source image to read from - this can be the same image as
|
|
the destination, but if different, it must be exactly the same
|
|
size and format.
|
|
@param destinationArea the region of the image to apply the filter to
|
|
*/
|
|
void applyToImage (Image& destImage,
|
|
const Image& sourceImage,
|
|
const Rectangle<int>& destinationArea) const;
|
|
|
|
private:
|
|
|
|
HeapBlock <float> values;
|
|
const int size;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ImageConvolutionKernel);
|
|
};
|
|
|
|
#endif // __JUCE_IMAGECONVOLUTIONKERNEL_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ImageConvolutionKernel.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_ImageFileFormat.h ***/
|
|
#ifndef __JUCE_IMAGEFILEFORMAT_JUCEHEADER__
|
|
#define __JUCE_IMAGEFILEFORMAT_JUCEHEADER__
|
|
|
|
/**
|
|
Base-class for codecs that can read and write image file formats such
|
|
as PNG, JPEG, etc.
|
|
|
|
This class also contains static methods to make it easy to load images
|
|
from files, streams or from memory.
|
|
|
|
@see Image, ImageCache
|
|
*/
|
|
class JUCE_API ImageFileFormat
|
|
{
|
|
protected:
|
|
|
|
/** Creates an ImageFormat. */
|
|
ImageFileFormat() {}
|
|
|
|
public:
|
|
/** Destructor. */
|
|
virtual ~ImageFileFormat() {}
|
|
|
|
/** Returns a description of this file format.
|
|
|
|
E.g. "JPEG", "PNG"
|
|
*/
|
|
virtual String getFormatName() = 0;
|
|
|
|
/** Returns true if the given stream seems to contain data that this format
|
|
understands.
|
|
|
|
The format class should only read the first few bytes of the stream and sniff
|
|
for header bytes that it understands.
|
|
|
|
@see decodeImage
|
|
*/
|
|
virtual bool canUnderstand (InputStream& input) = 0;
|
|
|
|
/** Tries to decode and return an image from the given stream.
|
|
|
|
This will be called for an image format after calling its canUnderStand() method
|
|
to see if it can handle the stream.
|
|
|
|
@param input the stream to read the data from. The stream will be positioned
|
|
at the start of the image data (but this may not necessarily
|
|
be position 0)
|
|
@returns the image that was decoded, or an invalid image if it fails.
|
|
@see loadFrom
|
|
*/
|
|
virtual Image decodeImage (InputStream& input) = 0;
|
|
|
|
/** Attempts to write an image to a stream.
|
|
|
|
To specify extra information like encoding quality, there will be appropriate parameters
|
|
in the subclasses of the specific file types.
|
|
|
|
@returns true if it nothing went wrong.
|
|
*/
|
|
virtual bool writeImageToStream (const Image& sourceImage,
|
|
OutputStream& destStream) = 0;
|
|
|
|
/** Tries the built-in decoders to see if it can find one to read this stream.
|
|
|
|
There are currently built-in decoders for PNG, JPEG and GIF formats.
|
|
|
|
The object that is returned should not be deleted by the caller.
|
|
|
|
@see canUnderstand, decodeImage, loadFrom
|
|
*/
|
|
static ImageFileFormat* findImageFormatForStream (InputStream& input);
|
|
|
|
/** Tries to load an image from a stream.
|
|
|
|
This will use the findImageFormatForStream() method to locate a suitable
|
|
codec, and use that to load the image.
|
|
|
|
@returns the image that was decoded, or an invalid image if it fails.
|
|
*/
|
|
static Image loadFrom (InputStream& input);
|
|
|
|
/** Tries to load an image from a file.
|
|
|
|
This will use the findImageFormatForStream() method to locate a suitable
|
|
codec, and use that to load the image.
|
|
|
|
@returns the image that was decoded, or an invalid image if it fails.
|
|
*/
|
|
static Image loadFrom (const File& file);
|
|
|
|
/** Tries to load an image from a block of raw image data.
|
|
|
|
This will use the findImageFormatForStream() method to locate a suitable
|
|
codec, and use that to load the image.
|
|
|
|
@returns the image that was decoded, or an invalid image if it fails.
|
|
*/
|
|
static Image loadFrom (const void* rawData,
|
|
const int numBytesOfData);
|
|
|
|
};
|
|
|
|
/**
|
|
A subclass of ImageFileFormat for reading and writing PNG files.
|
|
|
|
@see ImageFileFormat, JPEGImageFormat
|
|
*/
|
|
class JUCE_API PNGImageFormat : public ImageFileFormat
|
|
{
|
|
public:
|
|
|
|
PNGImageFormat();
|
|
~PNGImageFormat();
|
|
|
|
String getFormatName();
|
|
bool canUnderstand (InputStream& input);
|
|
Image decodeImage (InputStream& input);
|
|
bool writeImageToStream (const Image& sourceImage, OutputStream& destStream);
|
|
};
|
|
|
|
/**
|
|
A subclass of ImageFileFormat for reading and writing JPEG files.
|
|
|
|
@see ImageFileFormat, PNGImageFormat
|
|
*/
|
|
class JUCE_API JPEGImageFormat : public ImageFileFormat
|
|
{
|
|
public:
|
|
|
|
JPEGImageFormat();
|
|
~JPEGImageFormat();
|
|
|
|
/** Specifies the quality to be used when writing a JPEG file.
|
|
|
|
@param newQuality a value 0 to 1.0, where 0 is low quality, 1.0 is best, or
|
|
any negative value is "default" quality
|
|
*/
|
|
void setQuality (float newQuality);
|
|
|
|
String getFormatName();
|
|
bool canUnderstand (InputStream& input);
|
|
Image decodeImage (InputStream& input);
|
|
bool writeImageToStream (const Image& sourceImage, OutputStream& destStream);
|
|
|
|
private:
|
|
float quality;
|
|
};
|
|
|
|
/**
|
|
A subclass of ImageFileFormat for reading GIF files.
|
|
|
|
@see ImageFileFormat, PNGImageFormat, JPEGImageFormat
|
|
*/
|
|
class JUCE_API GIFImageFormat : public ImageFileFormat
|
|
{
|
|
public:
|
|
|
|
GIFImageFormat();
|
|
~GIFImageFormat();
|
|
|
|
String getFormatName();
|
|
bool canUnderstand (InputStream& input);
|
|
Image decodeImage (InputStream& input);
|
|
bool writeImageToStream (const Image& sourceImage, OutputStream& destStream);
|
|
};
|
|
|
|
#endif // __JUCE_IMAGEFILEFORMAT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_ImageFileFormat.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_DELETEDATSHUTDOWN_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_FILEBASEDDOCUMENT_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_FileBasedDocument.h ***/
|
|
#ifndef __JUCE_FILEBASEDDOCUMENT_JUCEHEADER__
|
|
#define __JUCE_FILEBASEDDOCUMENT_JUCEHEADER__
|
|
|
|
/**
|
|
A class to take care of the logic involved with the loading/saving of some kind
|
|
of document.
|
|
|
|
There's quite a lot of tedious logic involved in writing all the load/save/save-as
|
|
functions you need for documents that get saved to a file, so this class attempts
|
|
to abstract most of the boring stuff.
|
|
|
|
Your subclass should just implement all the pure virtual methods, and you can
|
|
then use the higher-level public methods to do the load/save dialogs, to warn the user
|
|
about overwriting files, etc.
|
|
|
|
The document object keeps track of whether it has changed since it was last saved or
|
|
loaded, so when you change something, call its changed() method. This will set a
|
|
flag so it knows it needs saving, and will also broadcast a change message using the
|
|
ChangeBroadcaster base class.
|
|
|
|
@see ChangeBroadcaster
|
|
*/
|
|
class JUCE_API FileBasedDocument : public ChangeBroadcaster
|
|
{
|
|
public:
|
|
/** Creates a FileBasedDocument.
|
|
|
|
@param fileExtension the extension to use when loading/saving files, e.g. ".doc"
|
|
@param fileWildCard the wildcard to use in file dialogs, e.g. "*.doc"
|
|
@param openFileDialogTitle the title to show on an open-file dialog, e.g. "Choose a file to open.."
|
|
@param saveFileDialogTitle the title to show on an save-file dialog, e.g. "Choose a file to save as.."
|
|
*/
|
|
FileBasedDocument (const String& fileExtension,
|
|
const String& fileWildCard,
|
|
const String& openFileDialogTitle,
|
|
const String& saveFileDialogTitle);
|
|
|
|
/** Destructor. */
|
|
virtual ~FileBasedDocument();
|
|
|
|
/** Returns true if the changed() method has been called since the file was
|
|
last saved or loaded.
|
|
|
|
@see resetChangedFlag, changed
|
|
*/
|
|
bool hasChangedSinceSaved() const { return changedSinceSave; }
|
|
|
|
/** Called to indicate that the document has changed and needs saving.
|
|
|
|
This method will also trigger a change message to be sent out using the
|
|
ChangeBroadcaster base class.
|
|
|
|
After calling the method, the hasChangedSinceSaved() method will return true, until
|
|
it is reset either by saving to a file or using the resetChangedFlag() method.
|
|
|
|
@see hasChangedSinceSaved, resetChangedFlag
|
|
*/
|
|
virtual void changed();
|
|
|
|
/** Sets the state of the 'changed' flag.
|
|
|
|
The 'changed' flag is set to true when the changed() method is called - use this method
|
|
to reset it or to set it without also broadcasting a change message.
|
|
|
|
@see changed, hasChangedSinceSaved
|
|
*/
|
|
void setChangedFlag (bool hasChanged);
|
|
|
|
/** Tries to open a file.
|
|
|
|
If the file opens correctly, the document's file (see the getFile() method) is set
|
|
to this new one; if it fails, the document's file is left unchanged, and optionally
|
|
a message box is shown telling the user there was an error.
|
|
|
|
@returns true if the new file loaded successfully
|
|
@see loadDocument, loadFromUserSpecifiedFile
|
|
*/
|
|
bool loadFrom (const File& fileToLoadFrom,
|
|
bool showMessageOnFailure);
|
|
|
|
/** Asks the user for a file and tries to load it.
|
|
|
|
This will pop up a dialog box using the title, file extension and
|
|
wildcard specified in the document's constructor, and asks the user
|
|
for a file. If they pick one, the loadFrom() method is used to
|
|
try to load it, optionally showing a message if it fails.
|
|
|
|
@returns true if a file was loaded; false if the user cancelled or if they
|
|
picked a file which failed to load correctly
|
|
@see loadFrom
|
|
*/
|
|
bool loadFromUserSpecifiedFile (bool showMessageOnFailure);
|
|
|
|
/** A set of possible outcomes of one of the save() methods
|
|
*/
|
|
enum SaveResult
|
|
{
|
|
savedOk = 0, /**< indicates that a file was saved successfully. */
|
|
userCancelledSave, /**< indicates that the user aborted the save operation. */
|
|
failedToWriteToFile /**< indicates that it tried to write to a file but this failed. */
|
|
};
|
|
|
|
/** Tries to save the document to the last file it was saved or loaded from.
|
|
|
|
This will always try to write to the file, even if the document isn't flagged as
|
|
having changed.
|
|
|
|
@param askUserForFileIfNotSpecified if there's no file currently specified and this is
|
|
true, it will prompt the user to pick a file, as if
|
|
saveAsInteractive() was called.
|
|
@param showMessageOnFailure if true it will show a warning message when if the
|
|
save operation fails
|
|
@see saveIfNeededAndUserAgrees, saveAs, saveAsInteractive
|
|
*/
|
|
SaveResult save (bool askUserForFileIfNotSpecified,
|
|
bool showMessageOnFailure);
|
|
|
|
/** If the file needs saving, it'll ask the user if that's what they want to do, and save
|
|
it if they say yes.
|
|
|
|
If you've got a document open and want to close it (e.g. to quit the app), this is the
|
|
method to call.
|
|
|
|
If the document doesn't need saving it'll return the value savedOk so
|
|
you can go ahead and delete the document.
|
|
|
|
If it does need saving it'll prompt the user, and if they say "discard changes" it'll
|
|
return savedOk, so again, you can safely delete the document.
|
|
|
|
If the user clicks "cancel", it'll return userCancelledSave, so if you can abort the
|
|
close-document operation.
|
|
|
|
And if they click "save changes", it'll try to save and either return savedOk, or
|
|
failedToWriteToFile if there was a problem.
|
|
|
|
@see save, saveAs, saveAsInteractive
|
|
*/
|
|
SaveResult saveIfNeededAndUserAgrees();
|
|
|
|
/** Tries to save the document to a specified file.
|
|
|
|
If this succeeds, it'll also change the document's internal file (as returned by
|
|
the getFile() method). If it fails, the file will be left unchanged.
|
|
|
|
@param newFile the file to try to write to
|
|
@param warnAboutOverwritingExistingFiles if true and the file exists, it'll ask
|
|
the user first if they want to overwrite it
|
|
@param askUserForFileIfNotSpecified if the file is non-existent and this is true, it'll
|
|
use the saveAsInteractive() method to ask the user for a
|
|
filename
|
|
@param showMessageOnFailure if true and the write operation fails, it'll show
|
|
a message box to warn the user
|
|
@see saveIfNeededAndUserAgrees, save, saveAsInteractive
|
|
*/
|
|
SaveResult saveAs (const File& newFile,
|
|
bool warnAboutOverwritingExistingFiles,
|
|
bool askUserForFileIfNotSpecified,
|
|
bool showMessageOnFailure);
|
|
|
|
/** Prompts the user for a filename and tries to save to it.
|
|
|
|
This will pop up a dialog box using the title, file extension and
|
|
wildcard specified in the document's constructor, and asks the user
|
|
for a file. If they pick one, the saveAs() method is used to try to save
|
|
to this file.
|
|
|
|
@param warnAboutOverwritingExistingFiles if true and the file exists, it'll ask
|
|
the user first if they want to overwrite it
|
|
@see saveIfNeededAndUserAgrees, save, saveAs
|
|
*/
|
|
SaveResult saveAsInteractive (bool warnAboutOverwritingExistingFiles);
|
|
|
|
/** Returns the file that this document was last successfully saved or loaded from.
|
|
|
|
When the document object is created, this will be set to File::nonexistent.
|
|
|
|
It is changed when one of the load or save methods is used, or when setFile()
|
|
is used to explicitly set it.
|
|
*/
|
|
const File& getFile() const { return documentFile; }
|
|
|
|
/** Sets the file that this document thinks it was loaded from.
|
|
|
|
This won't actually load anything - it just changes the file stored internally.
|
|
|
|
@see getFile
|
|
*/
|
|
void setFile (const File& newFile);
|
|
|
|
protected:
|
|
|
|
/** Overload this to return the title of the document.
|
|
|
|
This is used in message boxes, filenames and file choosers, so it should be
|
|
something sensible.
|
|
*/
|
|
virtual const String getDocumentTitle() = 0;
|
|
|
|
/** This method should try to load your document from the given file.
|
|
|
|
If it fails, it should return an error message. If it succeeds, it should return
|
|
an empty string.
|
|
*/
|
|
virtual const String loadDocument (const File& file) = 0;
|
|
|
|
/** This method should try to write your document to the given file.
|
|
|
|
If it fails, it should return an error message. If it succeeds, it should return
|
|
an empty string.
|
|
*/
|
|
virtual const String saveDocument (const File& file) = 0;
|
|
|
|
/** This is used for dialog boxes to make them open at the last folder you
|
|
were using.
|
|
|
|
getLastDocumentOpened() and setLastDocumentOpened() are used to store
|
|
the last document that was used - you might want to store this value
|
|
in a static variable, or even in your application's properties. It should
|
|
be a global setting rather than a property of this object.
|
|
|
|
This method works very well in conjunction with a RecentlyOpenedFilesList
|
|
object to manage your recent-files list.
|
|
|
|
As a default value, it's ok to return File::nonexistent, and the document
|
|
object will use a sensible one instead.
|
|
|
|
@see RecentlyOpenedFilesList
|
|
*/
|
|
virtual const File getLastDocumentOpened() = 0;
|
|
|
|
/** This is used for dialog boxes to make them open at the last folder you
|
|
were using.
|
|
|
|
getLastDocumentOpened() and setLastDocumentOpened() are used to store
|
|
the last document that was used - you might want to store this value
|
|
in a static variable, or even in your application's properties. It should
|
|
be a global setting rather than a property of this object.
|
|
|
|
This method works very well in conjunction with a RecentlyOpenedFilesList
|
|
object to manage your recent-files list.
|
|
|
|
@see RecentlyOpenedFilesList
|
|
*/
|
|
virtual void setLastDocumentOpened (const File& file) = 0;
|
|
|
|
private:
|
|
|
|
File documentFile;
|
|
bool changedSinceSave;
|
|
String fileExtension, fileWildcard, openFileDialogTitle, saveFileDialogTitle;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileBasedDocument);
|
|
};
|
|
|
|
#endif // __JUCE_FILEBASEDDOCUMENT_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_FileBasedDocument.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_PROPERTIESFILE_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_RECENTLYOPENEDFILESLIST_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_RecentlyOpenedFilesList.h ***/
|
|
#ifndef __JUCE_RECENTLYOPENEDFILESLIST_JUCEHEADER__
|
|
#define __JUCE_RECENTLYOPENEDFILESLIST_JUCEHEADER__
|
|
|
|
/**
|
|
Manages a set of files for use as a list of recently-opened documents.
|
|
|
|
This is a handy class for holding your list of recently-opened documents, with
|
|
helpful methods for things like purging any non-existent files, automatically
|
|
adding them to a menu, and making persistence easy.
|
|
|
|
@see File, FileBasedDocument
|
|
*/
|
|
class JUCE_API RecentlyOpenedFilesList
|
|
{
|
|
public:
|
|
|
|
/** Creates an empty list.
|
|
*/
|
|
RecentlyOpenedFilesList();
|
|
|
|
/** Destructor. */
|
|
~RecentlyOpenedFilesList();
|
|
|
|
/** Sets a limit for the number of files that will be stored in the list.
|
|
|
|
When addFile() is called, then if there is no more space in the list, the
|
|
least-recently added file will be dropped.
|
|
|
|
@see getMaxNumberOfItems
|
|
*/
|
|
void setMaxNumberOfItems (int newMaxNumber);
|
|
|
|
/** Returns the number of items that this list will store.
|
|
@see setMaxNumberOfItems
|
|
*/
|
|
int getMaxNumberOfItems() const noexcept { return maxNumberOfItems; }
|
|
|
|
/** Returns the number of files in the list.
|
|
|
|
The most recently added file is always at index 0.
|
|
*/
|
|
int getNumFiles() const;
|
|
|
|
/** Returns one of the files in the list.
|
|
|
|
The most recently added file is always at index 0.
|
|
*/
|
|
File getFile (int index) const;
|
|
|
|
/** Returns an array of all the absolute pathnames in the list.
|
|
*/
|
|
const StringArray& getAllFilenames() const noexcept { return files; }
|
|
|
|
/** Clears all the files from the list. */
|
|
void clear();
|
|
|
|
/** Adds a file to the list.
|
|
|
|
The file will be added at index 0. If this file is already in the list, it will
|
|
be moved up to index 0, but a file can only appear once in the list.
|
|
|
|
If the list already contains the maximum number of items that is permitted, the
|
|
least-recently added file will be dropped from the end.
|
|
*/
|
|
void addFile (const File& file);
|
|
|
|
/** Removes a file from the list. */
|
|
void removeFile (const File& file);
|
|
|
|
/** Checks each of the files in the list, removing any that don't exist.
|
|
|
|
You might want to call this after reloading a list of files, or before putting them
|
|
on a menu.
|
|
*/
|
|
void removeNonExistentFiles();
|
|
|
|
/** Adds entries to a menu, representing each of the files in the list.
|
|
|
|
This is handy for creating an "open recent file..." menu in your app. The
|
|
menu items are numbered consecutively starting with the baseItemId value,
|
|
and can either be added as complete pathnames, or just the last part of the
|
|
filename.
|
|
|
|
If dontAddNonExistentFiles is true, then each file will be checked and only those
|
|
that exist will be added.
|
|
|
|
If filesToAvoid is non-zero, then it is considered to be a zero-terminated array of
|
|
pointers to file objects. Any files that appear in this list will not be added to the
|
|
menu - the reason for this is that you might have a number of files already open, so
|
|
might not want these to be shown in the menu.
|
|
|
|
It returns the number of items that were added.
|
|
*/
|
|
int createPopupMenuItems (PopupMenu& menuToAddItemsTo,
|
|
int baseItemId,
|
|
bool showFullPaths,
|
|
bool dontAddNonExistentFiles,
|
|
const File** filesToAvoid = nullptr);
|
|
|
|
/** Returns a string that encapsulates all the files in the list.
|
|
|
|
The string that is returned can later be passed into restoreFromString() in
|
|
order to recreate the list. This is handy for persisting your list, e.g. in
|
|
a PropertiesFile object.
|
|
|
|
@see restoreFromString
|
|
*/
|
|
String toString() const;
|
|
|
|
/** Restores the list from a previously stringified version of the list.
|
|
|
|
Pass in a stringified version created with toString() in order to persist/restore
|
|
your list.
|
|
|
|
@see toString
|
|
*/
|
|
void restoreFromString (const String& stringifiedVersion);
|
|
|
|
private:
|
|
|
|
StringArray files;
|
|
int maxNumberOfItems;
|
|
|
|
JUCE_LEAK_DETECTOR (RecentlyOpenedFilesList);
|
|
};
|
|
|
|
#endif // __JUCE_RECENTLYOPENEDFILESLIST_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_RecentlyOpenedFilesList.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_SELECTEDITEMSET_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_SYSTEMCLIPBOARD_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_SystemClipboard.h ***/
|
|
#ifndef __JUCE_SYSTEMCLIPBOARD_JUCEHEADER__
|
|
#define __JUCE_SYSTEMCLIPBOARD_JUCEHEADER__
|
|
|
|
/**
|
|
Handles reading/writing to the system's clipboard.
|
|
*/
|
|
class JUCE_API SystemClipboard
|
|
{
|
|
public:
|
|
/** Copies a string of text onto the clipboard */
|
|
static void copyTextToClipboard (const String& text);
|
|
|
|
/** Gets the current clipboard's contents.
|
|
|
|
Obviously this might have come from another app, so could contain
|
|
anything..
|
|
*/
|
|
static String getTextFromClipboard();
|
|
};
|
|
|
|
#endif // __JUCE_SYSTEMCLIPBOARD_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_SystemClipboard.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_UNDOABLEACTION_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_UNDOMANAGER_JUCEHEADER__
|
|
|
|
#endif
|
|
#ifndef __JUCE_UNITTEST_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_UnitTest.h ***/
|
|
#ifndef __JUCE_UNITTEST_JUCEHEADER__
|
|
#define __JUCE_UNITTEST_JUCEHEADER__
|
|
|
|
class UnitTestRunner;
|
|
|
|
/**
|
|
This is a base class for classes that perform a unit test.
|
|
|
|
To write a test using this class, your code should look something like this:
|
|
|
|
@code
|
|
class MyTest : public UnitTest
|
|
{
|
|
public:
|
|
MyTest() : UnitTest ("Foobar testing") {}
|
|
|
|
void runTest()
|
|
{
|
|
beginTest ("Part 1");
|
|
|
|
expect (myFoobar.doesSomething());
|
|
expect (myFoobar.doesSomethingElse());
|
|
|
|
beginTest ("Part 2");
|
|
|
|
expect (myOtherFoobar.doesSomething());
|
|
expect (myOtherFoobar.doesSomethingElse());
|
|
|
|
...etc..
|
|
}
|
|
};
|
|
|
|
// Creating a static instance will automatically add the instance to the array
|
|
// returned by UnitTest::getAllTests(), so the test will be included when you call
|
|
// UnitTestRunner::runAllTests()
|
|
static MyTest test;
|
|
@endcode
|
|
|
|
To run a test, use the UnitTestRunner class.
|
|
|
|
@see UnitTestRunner
|
|
*/
|
|
class JUCE_API UnitTest
|
|
{
|
|
public:
|
|
|
|
/** Creates a test with the given name. */
|
|
explicit UnitTest (const String& name);
|
|
|
|
/** Destructor. */
|
|
virtual ~UnitTest();
|
|
|
|
/** Returns the name of the test. */
|
|
const String& getName() const noexcept { return name; }
|
|
|
|
/** Runs the test, using the specified UnitTestRunner.
|
|
You shouldn't need to call this method directly - use
|
|
UnitTestRunner::runTests() instead.
|
|
*/
|
|
void performTest (UnitTestRunner* runner);
|
|
|
|
/** Returns the set of all UnitTest objects that currently exist. */
|
|
static Array<UnitTest*>& getAllTests();
|
|
|
|
/** You can optionally implement this method to set up your test.
|
|
This method will be called before runTest().
|
|
*/
|
|
virtual void initialise();
|
|
|
|
/** You can optionally implement this method to clear up after your test has been run.
|
|
This method will be called after runTest() has returned.
|
|
*/
|
|
virtual void shutdown();
|
|
|
|
/** Implement this method in your subclass to actually run your tests.
|
|
|
|
The content of your implementation should call beginTest() and expect()
|
|
to perform the tests.
|
|
*/
|
|
virtual void runTest() = 0;
|
|
|
|
/** Tells the system that a new subsection of tests is beginning.
|
|
This should be called from your runTest() method, and may be called
|
|
as many times as you like, to demarcate different sets of tests.
|
|
*/
|
|
void beginTest (const String& testName);
|
|
|
|
/** Checks that the result of a test is true, and logs this result.
|
|
|
|
In your runTest() method, you should call this method for each condition that
|
|
you want to check, e.g.
|
|
|
|
@code
|
|
void runTest()
|
|
{
|
|
beginTest ("basic tests");
|
|
expect (x + y == 2);
|
|
expect (getThing() == someThing);
|
|
...etc...
|
|
}
|
|
@endcode
|
|
|
|
If testResult is true, a pass is logged; if it's false, a failure is logged.
|
|
If the failure message is specified, it will be written to the log if the test fails.
|
|
*/
|
|
void expect (bool testResult, const String& failureMessage = String::empty);
|
|
|
|
/** Compares two values, and if they don't match, prints out a message containing the
|
|
expected and actual result values.
|
|
*/
|
|
template <class ValueType>
|
|
void expectEquals (ValueType actual, ValueType expected, String failureMessage = String::empty)
|
|
{
|
|
const bool result = (actual == expected);
|
|
|
|
if (! result)
|
|
{
|
|
if (failureMessage.isNotEmpty())
|
|
failureMessage << " -- ";
|
|
|
|
failureMessage << "Expected value: " << expected << ", Actual value: " << actual;
|
|
}
|
|
|
|
expect (result, failureMessage);
|
|
}
|
|
|
|
/** Writes a message to the test log.
|
|
This can only be called from within your runTest() method.
|
|
*/
|
|
void logMessage (const String& message);
|
|
|
|
private:
|
|
|
|
const String name;
|
|
UnitTestRunner* runner;
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (UnitTest);
|
|
};
|
|
|
|
/**
|
|
Runs a set of unit tests.
|
|
|
|
You can instantiate one of these objects and use it to invoke tests on a set of
|
|
UnitTest objects.
|
|
|
|
By using a subclass of UnitTestRunner, you can intercept logging messages and
|
|
perform custom behaviour when each test completes.
|
|
|
|
@see UnitTest
|
|
*/
|
|
class JUCE_API UnitTestRunner
|
|
{
|
|
public:
|
|
|
|
/** */
|
|
UnitTestRunner();
|
|
|
|
/** Destructor. */
|
|
virtual ~UnitTestRunner();
|
|
|
|
/** Runs a set of tests.
|
|
|
|
The tests are performed in order, and the results are logged. To run all the
|
|
registered UnitTest objects that exist, use runAllTests().
|
|
*/
|
|
void runTests (const Array<UnitTest*>& tests, bool assertOnFailure);
|
|
|
|
/** Runs all the UnitTest objects that currently exist.
|
|
This calls runTests() for all the objects listed in UnitTest::getAllTests().
|
|
*/
|
|
void runAllTests (bool assertOnFailure);
|
|
|
|
/** Contains the results of a test.
|
|
|
|
One of these objects is instantiated each time UnitTest::beginTest() is called, and
|
|
it contains details of the number of subsequent UnitTest::expect() calls that are
|
|
made.
|
|
*/
|
|
struct TestResult
|
|
{
|
|
/** The main name of this test (i.e. the name of the UnitTest object being run). */
|
|
String unitTestName;
|
|
/** The name of the current subcategory (i.e. the name that was set when UnitTest::beginTest() was called). */
|
|
String subcategoryName;
|
|
|
|
/** The number of UnitTest::expect() calls that succeeded. */
|
|
int passes;
|
|
/** The number of UnitTest::expect() calls that failed. */
|
|
int failures;
|
|
|
|
/** A list of messages describing the failed tests. */
|
|
StringArray messages;
|
|
};
|
|
|
|
/** Returns the number of TestResult objects that have been performed.
|
|
@see getResult
|
|
*/
|
|
int getNumResults() const noexcept;
|
|
|
|
/** Returns one of the TestResult objects that describes a test that has been run.
|
|
@see getNumResults
|
|
*/
|
|
const TestResult* getResult (int index) const noexcept;
|
|
|
|
protected:
|
|
/** Called when the list of results changes.
|
|
You can override this to perform some sort of behaviour when results are added.
|
|
*/
|
|
virtual void resultsUpdated();
|
|
|
|
/** Logs a message about the current test progress.
|
|
By default this just writes the message to the Logger class, but you could override
|
|
this to do something else with the data.
|
|
*/
|
|
virtual void logMessage (const String& message);
|
|
|
|
private:
|
|
|
|
friend class UnitTest;
|
|
|
|
UnitTest* currentTest;
|
|
String currentSubCategory;
|
|
OwnedArray <TestResult, CriticalSection> results;
|
|
bool assertOnFailure;
|
|
|
|
void beginNewTest (UnitTest* test, const String& subCategory);
|
|
void endTest();
|
|
|
|
void addPass();
|
|
void addFail (const String& failureMessage);
|
|
|
|
JUCE_DECLARE_NON_COPYABLE (UnitTestRunner);
|
|
};
|
|
|
|
#endif // __JUCE_UNITTEST_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_UnitTest.h ***/
|
|
|
|
|
|
#endif
|
|
#ifndef __JUCE_WINDOWSREGISTRY_JUCEHEADER__
|
|
|
|
/*** Start of inlined file: juce_WindowsRegistry.h ***/
|
|
#ifndef __JUCE_WINDOWSREGISTRY_JUCEHEADER__
|
|
#define __JUCE_WINDOWSREGISTRY_JUCEHEADER__
|
|
|
|
#if JUCE_WINDOWS || DOXYGEN
|
|
|
|
/**
|
|
Contains some static helper functions for manipulating the MS Windows registry
|
|
(Only available on Windows, of course!)
|
|
*/
|
|
class WindowsRegistry
|
|
{
|
|
public:
|
|
|
|
/** 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 String getValue (const String& regValuePath,
|
|
const String& defaultValue = String::empty);
|
|
|
|
/** 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 setValue (const String& regValuePath,
|
|
const String& value);
|
|
|
|
/** Returns true if the given value exists in the registry. */
|
|
static bool valueExists (const String& regValuePath);
|
|
|
|
/** Deletes a registry value. */
|
|
static void deleteValue (const String& regValuePath);
|
|
|
|
/** Deletes a registry key (which is registry-talk for 'folder'). */
|
|
static void deleteKey (const String& regKeyPath);
|
|
|
|
/** Creates a file association in the registry.
|
|
|
|
This lets you set the executable 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);
|
|
|
|
private:
|
|
WindowsRegistry();
|
|
JUCE_DECLARE_NON_COPYABLE (WindowsRegistry);
|
|
};
|
|
|
|
#endif
|
|
#endif // __JUCE_WINDOWSREGISTRY_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce_WindowsRegistry.h ***/
|
|
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/*** End of inlined file: juce_app_includes.h ***/
|
|
|
|
|
|
#endif
|
|
|
|
#if JUCE_MSVC
|
|
#pragma warning (pop)
|
|
#pragma pack (pop)
|
|
#endif
|
|
|
|
END_JUCE_NAMESPACE
|
|
|
|
#ifndef DONT_SET_USING_JUCE_NAMESPACE
|
|
#ifdef JUCE_NAMESPACE
|
|
|
|
// this will obviously save a lot of typing, but can be disabled by
|
|
// defining DONT_SET_USING_JUCE_NAMESPACE, in case there are conflicts.
|
|
using namespace JUCE_NAMESPACE;
|
|
|
|
/* On the Mac, these symbols are defined in the Mac libraries, so
|
|
these macros make it easier to reference them without writing out
|
|
the namespace every time.
|
|
|
|
If you run into difficulties where these macros interfere with the contents
|
|
of 3rd party header files, you may need to use the juce_WithoutMacros.h file - see
|
|
the comments in that file for more information.
|
|
*/
|
|
#if (JUCE_MAC || JUCE_IOS) && ! JUCE_DONT_DEFINE_MACROS
|
|
#define Component JUCE_NAMESPACE::Component
|
|
#define MemoryBlock JUCE_NAMESPACE::MemoryBlock
|
|
#define Point JUCE_NAMESPACE::Point
|
|
#define Button JUCE_NAMESPACE::Button
|
|
#endif
|
|
|
|
/* "Rectangle" is defined in some of the newer windows header files, so this makes
|
|
it easier to use the juce version explicitly.
|
|
|
|
If you run into difficulties where this macro interferes with other 3rd party header
|
|
files, you may need to use the juce_WithoutMacros.h file - see the comments in that
|
|
file for more information.
|
|
*/
|
|
#if JUCE_WINDOWS && ! JUCE_DONT_DEFINE_MACROS
|
|
#define Rectangle JUCE_NAMESPACE::Rectangle
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
/* Easy autolinking to the right JUCE libraries under win32.
|
|
|
|
Note that this can be disabled by defining DONT_AUTOLINK_TO_JUCE_LIBRARY before
|
|
including this header file.
|
|
*/
|
|
#if JUCE_MSVC
|
|
|
|
#ifndef DONT_AUTOLINK_TO_JUCE_LIBRARY
|
|
|
|
/** If you want your application to link to Juce as a DLL instead of
|
|
a static library (on win32), just define the JUCE_DLL macro before
|
|
including juce.h
|
|
*/
|
|
#ifdef JUCE_DLL
|
|
#if JUCE_DEBUG
|
|
#define AUTOLINKEDLIB "JUCE_debug.lib"
|
|
#else
|
|
#define AUTOLINKEDLIB "JUCE.lib"
|
|
#endif
|
|
#else
|
|
#if JUCE_DEBUG
|
|
#ifdef _WIN64
|
|
#define AUTOLINKEDLIB "jucelib_static_x64_debug.lib"
|
|
#else
|
|
#define AUTOLINKEDLIB "jucelib_static_Win32_debug.lib"
|
|
#endif
|
|
#else
|
|
#ifdef _WIN64
|
|
#define AUTOLINKEDLIB "jucelib_static_x64.lib"
|
|
#else
|
|
#define AUTOLINKEDLIB "jucelib_static_Win32.lib"
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#pragma comment(lib, AUTOLINKEDLIB)
|
|
|
|
#if ! DONT_LIST_JUCE_AUTOLINKEDLIBS
|
|
#pragma message("JUCE! Library to link to: " AUTOLINKEDLIB)
|
|
#endif
|
|
|
|
// Auto-link the other win32 libs that are needed by library calls..
|
|
#if ! (defined (DONT_AUTOLINK_TO_WIN32_LIBRARIES) || defined (JUCE_DLL))
|
|
|
|
/*** Start of inlined file: juce_win32_AutoLinkLibraries.h ***/
|
|
// Auto-links to various win32 libs that are needed by library calls..
|
|
#pragma comment(lib, "kernel32.lib")
|
|
#pragma comment(lib, "user32.lib")
|
|
#pragma comment(lib, "shell32.lib")
|
|
#pragma comment(lib, "gdi32.lib")
|
|
#pragma comment(lib, "vfw32.lib")
|
|
#pragma comment(lib, "comdlg32.lib")
|
|
#pragma comment(lib, "winmm.lib")
|
|
#pragma comment(lib, "wininet.lib")
|
|
#pragma comment(lib, "ole32.lib")
|
|
#pragma comment(lib, "oleaut32.lib")
|
|
#pragma comment(lib, "advapi32.lib")
|
|
#pragma comment(lib, "ws2_32.lib")
|
|
#pragma comment(lib, "version.lib")
|
|
#pragma comment(lib, "shlwapi.lib")
|
|
#pragma comment(lib, "imm32.lib")
|
|
|
|
#ifdef _NATIVE_WCHAR_T_DEFINED
|
|
#ifdef _DEBUG
|
|
#pragma comment(lib, "comsuppwd.lib")
|
|
#else
|
|
#pragma comment(lib, "comsuppw.lib")
|
|
#endif
|
|
#else
|
|
#ifdef _DEBUG
|
|
#pragma comment(lib, "comsuppd.lib")
|
|
#else
|
|
#pragma comment(lib, "comsupp.lib")
|
|
#endif
|
|
#endif
|
|
|
|
#if JUCE_OPENGL
|
|
#pragma comment(lib, "OpenGL32.Lib")
|
|
#pragma comment(lib, "GlU32.Lib")
|
|
#endif
|
|
|
|
#if JUCE_QUICKTIME
|
|
#pragma comment (lib, "QTMLClient.lib")
|
|
#endif
|
|
|
|
#if JUCE_USE_CAMERA
|
|
#pragma comment (lib, "Strmiids.lib")
|
|
#pragma comment (lib, "wmvcore.lib")
|
|
#endif
|
|
|
|
#if JUCE_DIRECT2D
|
|
#pragma comment (lib, "Dwrite.lib")
|
|
#pragma comment (lib, "D2d1.lib")
|
|
#endif
|
|
|
|
#if JUCE_DIRECTSHOW
|
|
#pragma comment (lib, "strmiids.lib")
|
|
#endif
|
|
|
|
#if JUCE_MEDIAFOUNDATION
|
|
#pragma comment (lib, "mfuuid.lib")
|
|
#endif
|
|
|
|
/*** End of inlined file: juce_win32_AutoLinkLibraries.h ***/
|
|
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#endif // __JUCE_JUCEHEADER__
|
|
|
|
/*** End of inlined file: juce.h ***/
|
|
|
|
#endif // __JUCE_AMALGAMATED_TEMPLATE_JUCEHEADER__
|
|
|