@@ -0,0 +1,13 @@ | |||
#!/bin/bash | |||
JUCE_MODULES_DIR="/home/falktx/Personal/FOSS/GIT/distrho/libs/juce-2.0/source/modules" | |||
CARLA_MODULES_DIR="/home/falktx/Personal/FOSS/GIT/Carla/source/modules" | |||
MODULES=("juce_audio_basics juce_audio_devices juce_audio_formats juce_audio_processors juce_core juce_data_structures juce_events juce_graphics juce_gui_basics") | |||
for M in $MODULES; do | |||
echo $M; | |||
cp -r -v $JUCE_MODULES_DIR/$M/* $CARLA_MODULES_DIR/$M/ | |||
done | |||
find $CARLA_MODULES_DIR -name juce_module_info -delete |
@@ -96,7 +96,7 @@ MidiBuffer::MidiBuffer (const MidiMessage& message) noexcept | |||
void MidiBuffer::swapWith (MidiBuffer& other) noexcept { data.swapWith (other.data); } | |||
void MidiBuffer::clear() noexcept { data.clearQuick(); } | |||
void MidiBuffer::ensureSize (size_t minimumNumBytes) { data.ensureStorageAllocated (minimumNumBytes); } | |||
void MidiBuffer::ensureSize (size_t minimumNumBytes) { data.ensureStorageAllocated ((int) minimumNumBytes); } | |||
bool MidiBuffer::isEmpty() const noexcept { return data.size() == 0; } | |||
void MidiBuffer::clear (const int startSample, const int numSamples) | |||
@@ -104,7 +104,7 @@ void MidiBuffer::clear (const int startSample, const int numSamples) | |||
uint8* const start = MidiBufferHelpers::findEventAfter (data.begin(), data.end(), startSample - 1); | |||
uint8* const end = MidiBufferHelpers::findEventAfter (start, data.end(), startSample + numSamples - 1); | |||
data.removeRange (start - data.begin(), end - data.begin()); | |||
data.removeRange ((int) (start - data.begin()), (int) (end - data.begin())); | |||
} | |||
void MidiBuffer::addEvent (const MidiMessage& m, const int sampleNumber) | |||
@@ -121,7 +121,7 @@ void MidiBuffer::addEvent (const void* const newData, const int maxBytes, const | |||
const size_t newItemSize = (size_t) numBytes + sizeof (int32) + sizeof (uint16); | |||
const int offset = (int) (MidiBufferHelpers::findEventAfter (data.begin(), data.end(), sampleNumber) - data.begin()); | |||
data.insertMultiple (offset, 0, newItemSize); | |||
data.insertMultiple (offset, 0, (int) newItemSize); | |||
uint8* const d = data.begin() + offset; | |||
*reinterpret_cast<int32*> (d) = sampleNumber; | |||
@@ -221,9 +221,9 @@ bool MidiBuffer::Iterator::getNextEvent (MidiMessage& result, int& samplePositio | |||
return false; | |||
samplePosition = MidiBufferHelpers::getEventTime (data); | |||
const int numBytes = MidiBufferHelpers::getEventDataSize (data); | |||
result = MidiMessage (data + sizeof (int32) + sizeof (uint16), numBytes, samplePosition); | |||
data += sizeof (int32) + sizeof (uint16) + numBytes; | |||
const int itemSize = MidiBufferHelpers::getEventDataSize (data); | |||
result = MidiMessage (data + sizeof (int32) + sizeof (uint16), itemSize, samplePosition); | |||
data += sizeof (int32) + sizeof (uint16) + itemSize; | |||
return true; | |||
} |
@@ -1210,7 +1210,7 @@ private: | |||
static String hintToString (const void* hints, const char* type) | |||
{ | |||
char* const hint = snd_device_name_get_hint (hints, type); | |||
const String s (hint); | |||
const String s (String::fromUTF8 (hint)); | |||
::free (hint); | |||
return s; | |||
} | |||
@@ -155,9 +155,7 @@ public: | |||
bufferSize (512), | |||
numInputChans (0), | |||
numOutputChans (0), | |||
callbacksAllowed (true), | |||
numInputChannelInfos (0), | |||
numOutputChannelInfos (0) | |||
callbacksAllowed (true) | |||
{ | |||
jassert (deviceID != 0); | |||
@@ -199,9 +197,17 @@ public: | |||
tempOutputBuffers[i] = audioBuffer + count++ * tempBufSize; | |||
} | |||
struct CallbackDetailsForChannel | |||
{ | |||
int streamNum; | |||
int dataOffsetSamples; | |||
int dataStrideSamples; | |||
}; | |||
// returns the number of actual available channels | |||
void fillInChannelInfo (const bool input) | |||
StringArray getChannelInfo (const bool input, Array<CallbackDetailsForChannel>& newChannelInfo) const | |||
{ | |||
StringArray newNames; | |||
int chanNum = 0; | |||
UInt32 size; | |||
@@ -212,7 +218,7 @@ public: | |||
if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) | |||
{ | |||
HeapBlock <AudioBufferList> bufList; | |||
HeapBlock<AudioBufferList> bufList; | |||
bufList.calloc (size, 1); | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, bufList))) | |||
@@ -237,82 +243,35 @@ public: | |||
name = String::fromUTF8 (channelName, (int) nameSize); | |||
} | |||
if (input) | |||
if ((input ? activeInputChans : activeOutputChans) [chanNum]) | |||
{ | |||
if (activeInputChans[chanNum]) | |||
{ | |||
inputChannelInfo [numInputChannelInfos].streamNum = i; | |||
inputChannelInfo [numInputChannelInfos].dataOffsetSamples = (int) j; | |||
inputChannelInfo [numInputChannelInfos].dataStrideSamples = (int) b.mNumberChannels; | |||
++numInputChannelInfos; | |||
} | |||
if (name.isEmpty()) | |||
name << "Input " << (chanNum + 1); | |||
inChanNames.add (name); | |||
} | |||
else | |||
{ | |||
if (activeOutputChans[chanNum]) | |||
{ | |||
outputChannelInfo [numOutputChannelInfos].streamNum = i; | |||
outputChannelInfo [numOutputChannelInfos].dataOffsetSamples = (int) j; | |||
outputChannelInfo [numOutputChannelInfos].dataStrideSamples = (int) b.mNumberChannels; | |||
++numOutputChannelInfos; | |||
} | |||
if (name.isEmpty()) | |||
name << "Output " << (chanNum + 1); | |||
outChanNames.add (name); | |||
CallbackDetailsForChannel info = { i, (int) j, (int) b.mNumberChannels }; | |||
newChannelInfo.add (info); | |||
} | |||
if (name.isEmpty()) | |||
name << (input ? "Input " : "Output ") << (chanNum + 1); | |||
newNames.add (name); | |||
++chanNum; | |||
} | |||
} | |||
} | |||
} | |||
return newNames; | |||
} | |||
void updateDetailsFromDevice() | |||
Array<double> getSampleRatesFromDevice() const | |||
{ | |||
stopTimer(); | |||
if (deviceID == 0) | |||
return; | |||
const ScopedLock sl (callbackLock); | |||
Array<double> newSampleRates; | |||
String rates; | |||
AudioObjectPropertyAddress pa; | |||
pa.mScope = kAudioObjectPropertyScopeWildcard; | |||
pa.mElement = kAudioObjectPropertyElementMaster; | |||
UInt32 isAlive; | |||
UInt32 size = sizeof (isAlive); | |||
pa.mSelector = kAudioDevicePropertyDeviceIsAlive; | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &isAlive)) | |||
&& isAlive == 0) | |||
return; | |||
Float64 sr; | |||
size = sizeof (sr); | |||
pa.mSelector = kAudioDevicePropertyNominalSampleRate; | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &sr))) | |||
sampleRate = sr; | |||
UInt32 framesPerBuf; | |||
size = sizeof (framesPerBuf); | |||
pa.mSelector = kAudioDevicePropertyBufferFrameSize; | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &framesPerBuf))) | |||
{ | |||
bufferSize = (int) framesPerBuf; | |||
allocateTempBuffers(); | |||
} | |||
bufferSizes.clear(); | |||
pa.mSelector = kAudioDevicePropertyBufferFrameSizeRange; | |||
pa.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; | |||
UInt32 size = 0; | |||
if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) | |||
{ | |||
@@ -321,33 +280,42 @@ public: | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ranges))) | |||
{ | |||
bufferSizes.add ((int) (ranges[0].mMinimum + 15) & ~15); | |||
static const double possibleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 }; | |||
for (int i = 32; i < 2048; i += 32) | |||
for (int i = 0; i < numElementsInArray (possibleRates); ++i) | |||
{ | |||
for (int j = size / (int) sizeof (AudioValueRange); --j >= 0;) | |||
{ | |||
if (i >= ranges[j].mMinimum && i <= ranges[j].mMaximum) | |||
if (possibleRates[i] >= ranges[j].mMinimum - 2 && possibleRates[i] <= ranges[j].mMaximum + 2) | |||
{ | |||
bufferSizes.addIfNotAlreadyThere (i); | |||
newSampleRates.add (possibleRates[i]); | |||
rates << possibleRates[i] << ' '; | |||
break; | |||
} | |||
} | |||
} | |||
if (bufferSize > 0) | |||
bufferSizes.addIfNotAlreadyThere (bufferSize); | |||
} | |||
} | |||
if (bufferSizes.size() == 0 && bufferSize > 0) | |||
bufferSizes.add (bufferSize); | |||
if (newSampleRates.size() == 0 && sampleRate > 0) | |||
{ | |||
newSampleRates.add (sampleRate); | |||
rates << sampleRate; | |||
} | |||
JUCE_COREAUDIOLOG ("rates: " + rates); | |||
return newSampleRates; | |||
} | |||
sampleRates.clear(); | |||
const double possibleRates[] = { 44100.0, 48000.0, 88200.0, 96000.0, 176400.0, 192000.0 }; | |||
String rates; | |||
Array<int> getBufferSizesFromDevice() const | |||
{ | |||
Array<int> newBufferSizes; | |||
pa.mSelector = kAudioDevicePropertyAvailableNominalSampleRates; | |||
AudioObjectPropertyAddress pa; | |||
pa.mScope = kAudioObjectPropertyScopeWildcard; | |||
pa.mElement = kAudioObjectPropertyElementMaster; | |||
pa.mSelector = kAudioDevicePropertyBufferFrameSizeRange; | |||
UInt32 size = 0; | |||
if (OK (AudioObjectGetPropertyDataSize (deviceID, &pa, 0, 0, &size))) | |||
{ | |||
@@ -356,59 +324,98 @@ public: | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, ranges))) | |||
{ | |||
for (int i = 0; i < numElementsInArray (possibleRates); ++i) | |||
{ | |||
bool ok = false; | |||
newBufferSizes.add ((int) (ranges[0].mMinimum + 15) & ~15); | |||
for (int i = 32; i < 2048; i += 32) | |||
{ | |||
for (int j = size / (int) sizeof (AudioValueRange); --j >= 0;) | |||
if (possibleRates[i] >= ranges[j].mMinimum - 2 && possibleRates[i] <= ranges[j].mMaximum + 2) | |||
ok = true; | |||
if (ok) | |||
{ | |||
sampleRates.add (possibleRates[i]); | |||
rates << possibleRates[i] << ' '; | |||
if (i >= ranges[j].mMinimum && i <= ranges[j].mMaximum) | |||
{ | |||
newBufferSizes.addIfNotAlreadyThere (i); | |||
break; | |||
} | |||
} | |||
} | |||
if (bufferSize > 0) | |||
newBufferSizes.addIfNotAlreadyThere (bufferSize); | |||
} | |||
} | |||
if (sampleRates.size() == 0 && sampleRate > 0) | |||
{ | |||
sampleRates.add (sampleRate); | |||
rates << sampleRate; | |||
} | |||
if (newBufferSizes.size() == 0 && bufferSize > 0) | |||
newBufferSizes.add (bufferSize); | |||
JUCE_COREAUDIOLOG ("sr: " + rates); | |||
return newBufferSizes; | |||
} | |||
inputLatency = 0; | |||
outputLatency = 0; | |||
UInt32 lat; | |||
size = sizeof (lat); | |||
int getLatencyFromDevice (AudioObjectPropertyScope scope) const | |||
{ | |||
UInt32 lat = 0; | |||
UInt32 size = sizeof (lat); | |||
AudioObjectPropertyAddress pa; | |||
pa.mElement = kAudioObjectPropertyElementMaster; | |||
pa.mSelector = kAudioDevicePropertyLatency; | |||
pa.mScope = kAudioDevicePropertyScopeInput; | |||
if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr) | |||
inputLatency = (int) lat; | |||
pa.mScope = scope; | |||
AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat); | |||
return (int) lat; | |||
} | |||
pa.mScope = kAudioDevicePropertyScopeOutput; | |||
size = sizeof (lat); | |||
void updateDetailsFromDevice() | |||
{ | |||
stopTimer(); | |||
if (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &lat) == noErr) | |||
outputLatency = (int) lat; | |||
if (deviceID == 0) | |||
return; | |||
// this collects all the new details from the device without any locking, then | |||
// locks + swaps them afterwards. | |||
AudioObjectPropertyAddress pa; | |||
pa.mScope = kAudioObjectPropertyScopeWildcard; | |||
pa.mElement = kAudioObjectPropertyElementMaster; | |||
UInt32 isAlive; | |||
UInt32 size = sizeof (isAlive); | |||
pa.mSelector = kAudioDevicePropertyDeviceIsAlive; | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &isAlive)) && isAlive == 0) | |||
return; | |||
Float64 sr; | |||
size = sizeof (sr); | |||
pa.mSelector = kAudioDevicePropertyNominalSampleRate; | |||
if (OK (AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &sr))) | |||
sampleRate = sr; | |||
UInt32 framesPerBuf = bufferSize; | |||
size = sizeof (framesPerBuf); | |||
pa.mSelector = kAudioDevicePropertyBufferFrameSize; | |||
AudioObjectGetPropertyData (deviceID, &pa, 0, 0, &size, &framesPerBuf); | |||
Array<int> newBufferSizes (getBufferSizesFromDevice()); | |||
Array<double> newSampleRates (getSampleRatesFromDevice()); | |||
inputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeInput); | |||
outputLatency = getLatencyFromDevice (kAudioDevicePropertyScopeOutput); | |||
JUCE_COREAUDIOLOG ("lat: " + String (inputLatency) + " " + String (outputLatency)); | |||
inChanNames.clear(); | |||
outChanNames.clear(); | |||
Array<CallbackDetailsForChannel> newInChans, newOutChans; | |||
StringArray newInNames (getChannelInfo (true, newInChans)); | |||
StringArray newOutNames (getChannelInfo (false, newOutChans)); | |||
// after getting the new values, lock + apply them | |||
const ScopedLock sl (callbackLock); | |||
bufferSize = (int) framesPerBuf; | |||
allocateTempBuffers(); | |||
inputChannelInfo.calloc ((size_t) numInputChans + 2); | |||
numInputChannelInfos = 0; | |||
sampleRates.swapWith (newSampleRates); | |||
bufferSizes.swapWith (newBufferSizes); | |||
outputChannelInfo.calloc ((size_t) numOutputChans + 2); | |||
numOutputChannelInfos = 0; | |||
inChanNames.swapWith (newInNames); | |||
outChanNames.swapWith (newOutNames); | |||
fillInChannelInfo (true); | |||
fillInChannelInfo (false); | |||
inputChannelInfo.swapWith (newInChans); | |||
outputChannelInfo.swapWith (newOutChans); | |||
} | |||
//============================================================================== | |||
@@ -675,7 +682,7 @@ public: | |||
{ | |||
for (int i = numInputChans; --i >= 0;) | |||
{ | |||
const CallbackDetailsForChannel& info = inputChannelInfo[i]; | |||
const CallbackDetailsForChannel& info = inputChannelInfo.getReference(i); | |||
float* dest = tempInputBuffers [i]; | |||
const float* src = ((const float*) inInputData->mBuffers[info.streamNum].mData) | |||
+ info.dataOffsetSamples; | |||
@@ -720,7 +727,7 @@ public: | |||
for (int i = numOutputChans; --i >= 0;) | |||
{ | |||
const CallbackDetailsForChannel& info = outputChannelInfo[i]; | |||
const CallbackDetailsForChannel& info = outputChannelInfo.getReference(i); | |||
const float* src = tempOutputBuffers [i]; | |||
float* dest = ((float*) outOutputData->mBuffers[info.streamNum].mData) | |||
+ info.dataOffsetSamples; | |||
@@ -739,9 +746,9 @@ public: | |||
} | |||
else | |||
{ | |||
for (int i = jmin (numOutputChans, numOutputChannelInfos); --i >= 0;) | |||
for (int i = jmin (numOutputChans, outputChannelInfo.size()); --i >= 0;) | |||
{ | |||
const CallbackDetailsForChannel& info = outputChannelInfo[i]; | |||
const CallbackDetailsForChannel& info = outputChannelInfo.getReference(i); | |||
float* dest = ((float*) outOutputData->mBuffers[info.streamNum].mData) | |||
+ info.dataOffsetSamples; | |||
const int stride = info.dataStrideSamples; | |||
@@ -803,15 +810,7 @@ private: | |||
int numInputChans, numOutputChans; | |||
bool callbacksAllowed; | |||
struct CallbackDetailsForChannel | |||
{ | |||
int streamNum; | |||
int dataOffsetSamples; | |||
int dataStrideSamples; | |||
}; | |||
int numInputChannelInfos, numOutputChannelInfos; | |||
HeapBlock <CallbackDetailsForChannel> inputChannelInfo, outputChannelInfo; | |||
Array<CallbackDetailsForChannel> inputChannelInfo, outputChannelInfo; | |||
HeapBlock <float*> tempInputBuffers, tempOutputBuffers; | |||
//============================================================================== | |||
@@ -380,7 +380,7 @@ public: | |||
samplesToWrite = const_cast<const int**> (channels.getData()); | |||
} | |||
return FLAC__stream_encoder_process (encoder, (const FLAC__int32**) samplesToWrite, (size_t) numSamples) != 0; | |||
return FLAC__stream_encoder_process (encoder, (const FLAC__int32**) samplesToWrite, (unsigned) numSamples) != 0; | |||
} | |||
bool writeData (const void* const data, const int size) const | |||
@@ -186,7 +186,7 @@ public: | |||
{ | |||
float** dataIn = nullptr; | |||
const int samps = OggVorbisNamespace::ov_read_float (&ovFile, &dataIn, numToRead, &bitStream); | |||
const long samps = OggVorbisNamespace::ov_read_float (&ovFile, &dataIn, numToRead, &bitStream); | |||
if (samps <= 0) | |||
break; | |||
@@ -100,6 +100,18 @@ bool AudioFormatReader::read (int* const* destSamples, | |||
return true; | |||
} | |||
static void readChannels (AudioFormatReader& reader, | |||
int** const chans, AudioSampleBuffer* const buffer, | |||
const int startSample, const int numSamples, | |||
const int64 readerStartSample, const int numTargetChannels) | |||
{ | |||
for (int j = 0; j < numTargetChannels; ++j) | |||
chans[j] = reinterpret_cast<int*> (buffer->getSampleData (j, startSample)); | |||
chans[numTargetChannels] = nullptr; | |||
reader.read (chans, numTargetChannels, readerStartSample, numSamples, true); | |||
} | |||
void AudioFormatReader::read (AudioSampleBuffer* buffer, | |||
int startSample, | |||
int numSamples, | |||
@@ -113,49 +125,51 @@ void AudioFormatReader::read (AudioSampleBuffer* buffer, | |||
if (numSamples > 0) | |||
{ | |||
const int numTargetChannels = buffer->getNumChannels(); | |||
int* chans[3]; | |||
if (useReaderLeftChan == useReaderRightChan) | |||
if (numTargetChannels <= 2) | |||
{ | |||
chans[0] = reinterpret_cast<int*> (buffer->getSampleData (0, startSample)); | |||
chans[1] = (numChannels > 1 && numTargetChannels > 1) ? reinterpret_cast<int*> (buffer->getSampleData (1, startSample)) : nullptr; | |||
} | |||
else if (useReaderLeftChan || (numChannels == 1)) | |||
{ | |||
chans[0] = reinterpret_cast<int*> (buffer->getSampleData (0, startSample)); | |||
chans[1] = nullptr; | |||
} | |||
else if (useReaderRightChan) | |||
{ | |||
chans[0] = nullptr; | |||
chans[1] = reinterpret_cast<int*> (buffer->getSampleData (0, startSample)); | |||
} | |||
int* const dest0 = reinterpret_cast<int*> (buffer->getSampleData (0, startSample)); | |||
int* const dest1 = reinterpret_cast<int*> (numTargetChannels > 1 ? buffer->getSampleData (1, startSample) : nullptr); | |||
int* chans[3]; | |||
chans[2] = nullptr; | |||
if (useReaderLeftChan == useReaderRightChan) | |||
{ | |||
chans[0] = dest0; | |||
chans[1] = numChannels > 1 ? dest1 : nullptr; | |||
} | |||
else if (useReaderLeftChan || (numChannels == 1)) | |||
{ | |||
chans[0] = dest0; | |||
chans[1] = nullptr; | |||
} | |||
else if (useReaderRightChan) | |||
{ | |||
chans[0] = nullptr; | |||
chans[1] = dest0; | |||
} | |||
read (chans, 2, readerStartSample, numSamples, true); | |||
chans[2] = nullptr; | |||
read (chans, 2, readerStartSample, numSamples, true); | |||
if (! usesFloatingPointData) | |||
// if the target's stereo and the source is mono, dupe the first channel.. | |||
if (numTargetChannels > 1 && (chans[0] == nullptr || chans[1] == nullptr)) | |||
memcpy (dest1, dest0, sizeof (float) * (size_t) numSamples); | |||
} | |||
else if (numTargetChannels <= 64) | |||
{ | |||
for (int j = 0; j < 2; ++j) | |||
{ | |||
if (float* const d = reinterpret_cast <float*> (chans[j])) | |||
{ | |||
const float multiplier = 1.0f / 0x7fffffff; | |||
for (int i = 0; i < numSamples; ++i) | |||
d[i] = *reinterpret_cast<int*> (d + i) * multiplier; | |||
} | |||
} | |||
int* chans[65]; | |||
readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); | |||
} | |||
if (numTargetChannels > 1 && (chans[0] == nullptr || chans[1] == nullptr)) | |||
else | |||
{ | |||
// if this is a stereo buffer and the source was mono, dupe the first channel.. | |||
memcpy (buffer->getSampleData (1, startSample), | |||
buffer->getSampleData (0, startSample), | |||
sizeof (float) * (size_t) numSamples); | |||
HeapBlock<int*> chans (numTargetChannels); | |||
readChannels (*this, chans, buffer, startSample, numSamples, readerStartSample, numTargetChannels); | |||
} | |||
if (! usesFloatingPointData) | |||
for (int j = 0; j < numTargetChannels; ++j) | |||
if (float* const d = buffer->getSampleData (j, startSample)) | |||
FloatVectorOperations::convertFixedToFloat (d, reinterpret_cast<const int*> (d), 1.0f / 0x7fffffff, numSamples); | |||
} | |||
} | |||
@@ -733,7 +733,7 @@ public: | |||
return s; | |||
} | |||
void changeProgramName (int index, const String& newName) override | |||
void changeProgramName (int /*index*/, const String& /*newName*/) override | |||
{ | |||
jassertfalse; // xxx not implemented! | |||
} | |||
@@ -1005,8 +1005,8 @@ private: | |||
} | |||
//============================================================================== | |||
OSStatus renderGetInput (AudioUnitRenderActionFlags* ioActionFlags, | |||
const AudioTimeStamp* inTimeStamp, | |||
OSStatus renderGetInput (AudioUnitRenderActionFlags*, | |||
const AudioTimeStamp*, | |||
UInt32 inBusNumber, | |||
UInt32 inNumberFrames, | |||
AudioBufferList* ioData) const | |||
@@ -1147,7 +1147,7 @@ private: | |||
->renderGetInput (ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, ioData); | |||
} | |||
static OSStatus renderMidiOutputCallback (void* hostRef, const AudioTimeStamp* timeStamp, UInt32 midiOutNum, | |||
static OSStatus renderMidiOutputCallback (void* hostRef, const AudioTimeStamp*, UInt32 /*midiOutNum*/, | |||
const struct MIDIPacketList* pktlist) | |||
{ | |||
return static_cast<AudioUnitPluginInstance*> (hostRef)->renderMidiOutput (pktlist); | |||
@@ -1331,7 +1331,7 @@ public: | |||
startTimer (jmin (713, getTimerInterval() + 51)); | |||
} | |||
void childBoundsChanged (Component* child) override | |||
void childBoundsChanged (Component*) override | |||
{ | |||
setSize (wrapper.getWidth(), wrapper.getHeight()); | |||
startTimer (70); | |||
@@ -1675,8 +1675,8 @@ private: | |||
void setHostTimeFrameRate (long frameRateIndex, double frameRate, double currentTime) noexcept | |||
{ | |||
vstHostTime.flags |= kVstSmpteValid; | |||
vstHostTime.smpteFrameRate = frameRateIndex; | |||
vstHostTime.smpteOffset = (long) (currentTime * 80.0 * frameRate + 0.5); | |||
vstHostTime.smpteFrameRate = (VstInt32) frameRateIndex; | |||
vstHostTime.smpteOffset = (VstInt32) (currentTime * 80.0 * frameRate + 0.5); | |||
} | |||
bool restoreProgramSettings (const fxProgram* const prog) | |||
@@ -2510,7 +2510,7 @@ private: | |||
deleteWindow(); | |||
} | |||
HIViewRef attachView (WindowRef windowRef, HIViewRef rootView) override | |||
HIViewRef attachView (WindowRef windowRef, HIViewRef /*rootView*/) override | |||
{ | |||
owner.openPluginWindow (windowRef); | |||
return 0; | |||
@@ -37,10 +37,7 @@ | |||
#include "../juce_core/native/juce_BasicNativeHeaders.h" | |||
#include "juce_audio_processors.h" | |||
#if JUCE_MODULE_AVAILABLE_juce_gui_extra | |||
#include "../juce_gui_extra/juce_gui_extra.h" | |||
#endif | |||
#include "../juce_gui_extra/juce_gui_extra.h" | |||
//============================================================================== | |||
#if JUCE_MAC | |||
@@ -287,8 +287,8 @@ XmlElement* KnownPluginList::createXml() const | |||
{ | |||
XmlElement* const e = new XmlElement ("KNOWNPLUGINS"); | |||
for (int i = 0; i < types.size(); ++i) | |||
e->addChildElement (types.getUnchecked(i)->createXml()); | |||
for (int i = types.size(); --i >= 0;) | |||
e->prependChildElement (types.getUnchecked(i)->createXml()); | |||
for (int i = 0; i < blacklist.size(); ++i) | |||
e->createNewChildElement ("BLACKLISTED")->setAttribute ("id", blacklist[i]); | |||
@@ -56,6 +56,11 @@ namespace TokenTypes | |||
JUCE_DECLARE_JS_TOKEN (identifier, "$identifier") | |||
} | |||
#if JUCE_MSVC | |||
#pragma warning (push) | |||
#pragma warning (disable: 4702) | |||
#endif | |||
//============================================================================== | |||
struct JavascriptEngine::RootObject : public DynamicObject | |||
{ | |||
@@ -853,8 +858,8 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
bool matchToken (TokenType name, const size_t len) noexcept | |||
{ | |||
if (p.compareUpTo (String::CharPointerType (name), len) != 0) return false; | |||
p += len; return true; | |||
if (p.compareUpTo (CharPointer_ASCII (name), (int) len) != 0) return false; | |||
p += (int) len; return true; | |||
} | |||
void skipWhitespaceAndComments() | |||
@@ -1211,6 +1216,9 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
return parseSuffixes (s.release()); | |||
} | |||
if (matchIf (TokenTypes::plusplus)) return parsePostIncDec<AdditionOp> (input); | |||
if (matchIf (TokenTypes::minusminus)) return parsePostIncDec<SubtractionOp> (input); | |||
return input.release(); | |||
} | |||
@@ -1339,8 +1347,6 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
{ | |||
if (matchIf (TokenTypes::plus)) { ExpPtr b (parseMultiplyDivide()); a = new AdditionOp (location, a, b); } | |||
else if (matchIf (TokenTypes::minus)) { ExpPtr b (parseMultiplyDivide()); a = new SubtractionOp (location, a, b); } | |||
else if (matchIf (TokenTypes::plusplus)) a = parsePostIncDec<AdditionOp> (a); | |||
else if (matchIf (TokenTypes::minusminus)) a = parsePostIncDec<SubtractionOp> (a); | |||
else break; | |||
} | |||
@@ -1429,7 +1435,7 @@ struct JavascriptEngine::RootObject : public DynamicObject | |||
} | |||
static Identifier getClassName() { static const Identifier i ("Object"); return i; } | |||
static var dump (Args a) { DBG (JSON::toString (a.thisObject)); return var::undefined(); } | |||
static var dump (Args a) { DBG (JSON::toString (a.thisObject)); (void) a; return var::undefined(); } | |||
static var clone (Args a) { return a.thisObject.clone(); } | |||
}; | |||
@@ -1681,3 +1687,7 @@ var JavascriptEngine::callFunction (Identifier function, const var::NativeFuncti | |||
return var::undefined(); | |||
} | |||
#if JUCE_MSVC | |||
#pragma warning (pop) | |||
#endif |
@@ -265,7 +265,7 @@ void MemoryBlock::copyTo (void* const dst, int offset, size_t num) const noexcep | |||
String MemoryBlock::toString() const | |||
{ | |||
return String::fromUTF8 (data, size); | |||
return String::fromUTF8 (data, (int) size); | |||
} | |||
//============================================================================== | |||
@@ -220,7 +220,7 @@ public: | |||
initialised = true; | |||
} | |||
void didSendBodyData (int /*totalBytesWritten*/, int /*totalBytesExpected*/) | |||
void didSendBodyData (NSInteger /*totalBytesWritten*/, NSInteger /*totalBytesExpected*/) | |||
{ | |||
} | |||
@@ -114,8 +114,13 @@ bool WaitableEvent::wait (const int timeOutMillisecs) const noexcept | |||
void WaitableEvent::signal() const noexcept | |||
{ | |||
pthread_mutex_lock (&mutex); | |||
triggered = true; | |||
pthread_cond_broadcast (&condition); | |||
if (! triggered) | |||
{ | |||
triggered = true; | |||
pthread_cond_broadcast (&condition); | |||
} | |||
pthread_mutex_unlock (&mutex); | |||
} | |||
@@ -175,7 +175,7 @@ String InputStream::readString() | |||
} | |||
} | |||
return String::fromUTF8 (data, i); | |||
return String::fromUTF8 (data, (int) i); | |||
} | |||
String InputStream::readNextLine() | |||
@@ -36,7 +36,7 @@ | |||
*/ | |||
#define JUCE_MAJOR_VERSION 2 | |||
#define JUCE_MINOR_VERSION 1 | |||
#define JUCE_BUILDNUMBER 6 | |||
#define JUCE_BUILDNUMBER 7 | |||
/** Current Juce version number. | |||
@@ -524,41 +524,42 @@ juce_wchar String::operator[] (int index) const noexcept | |||
return text [index]; | |||
} | |||
int String::hashCode() const noexcept | |||
template <typename Type> | |||
struct HashGenerator | |||
{ | |||
int result = 0; | |||
template <typename CharPointer> | |||
static Type calculate (CharPointer t) noexcept | |||
{ | |||
Type result = Type(); | |||
for (CharPointerType t (text); ! t.isEmpty();) | |||
result = 31 * result + (int) t.getAndAdvance(); | |||
while (! t.isEmpty()) | |||
result = multiplier * result + t.getAndAdvance(); | |||
return result; | |||
} | |||
return result; | |||
} | |||
int64 String::hashCode64() const noexcept | |||
{ | |||
int64 result = 0; | |||
enum { multiplier = sizeof (Type) > 4 ? 101 : 31 }; | |||
}; | |||
for (CharPointerType t (text); ! t.isEmpty();) | |||
result = 101 * result + t.getAndAdvance(); | |||
return result; | |||
} | |||
int String::hashCode() const noexcept { return HashGenerator<int> ::calculate (text); } | |||
int64 String::hashCode64() const noexcept { return HashGenerator<int64> ::calculate (text); } | |||
std::size_t String::hash() const noexcept { return HashGenerator<std::size_t>::calculate (text); } | |||
//============================================================================== | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const String& s2) noexcept { return s1.compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const char* const s2) noexcept { return s1.compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const wchar_t* const s2) noexcept { return s1.compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF32 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const String& s2) noexcept { return s1.compare (s2) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const char* const s2) noexcept { return s1.compare (s2) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const wchar_t* const s2) noexcept { return s1.compare (s2) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const char* s2) noexcept { return s1.compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const char* s2) noexcept { return s1.compare (s2) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const wchar_t* s2) noexcept { return s1.compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const wchar_t* s2) noexcept { return s1.compare (s2) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF8 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF16 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator== (const String& s1, const CharPointer_UTF32 s2) noexcept { return s1.getCharPointer().compare (s2) == 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, const CharPointer_UTF32 s2) noexcept { return s1.getCharPointer().compare (s2) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator!= (const String& s1, StringRef s2) noexcept { return s1.getCharPointer().compare (s2.text) != 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator> (const String& s1, const String& s2) noexcept { return s1.compare (s2) > 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator< (const String& s1, const String& s2) noexcept { return s1.compare (s2) < 0; } | |||
JUCE_API bool JUCE_CALLTYPE operator>= (const String& s1, const String& s2) noexcept { return s1.compare (s2) >= 0; } | |||
@@ -180,6 +180,9 @@ public: | |||
/** Generates a probably-unique 64-bit hashcode from this string. */ | |||
int64 hashCode64() const noexcept; | |||
/** Generates a probably-unique hashcode from this string. */ | |||
std::size_t hash() const noexcept; | |||
/** Returns the number of characters in the string. */ | |||
int length() const noexcept; | |||
@@ -585,18 +585,36 @@ XmlElement* XmlElement::getChildByAttribute (StringRef attributeName, StringRef | |||
void XmlElement::addChildElement (XmlElement* const newNode) noexcept | |||
{ | |||
if (newNode != nullptr) | |||
{ | |||
// The element being added must not be a child of another node! | |||
jassert (newNode->nextListItem == nullptr); | |||
firstChildElement.append (newNode); | |||
} | |||
} | |||
void XmlElement::insertChildElement (XmlElement* const newNode, int indexToInsertAt) noexcept | |||
{ | |||
if (newNode != nullptr) | |||
{ | |||
removeChildElement (newNode, false); | |||
// The element being added must not be a child of another node! | |||
jassert (newNode->nextListItem == nullptr); | |||
firstChildElement.insertAtIndex (indexToInsertAt, newNode); | |||
} | |||
} | |||
void XmlElement::prependChildElement (XmlElement* newNode) noexcept | |||
{ | |||
if (newNode != nullptr) | |||
{ | |||
// The element being added must not be a child of another node! | |||
jassert (newNode->nextListItem == nullptr); | |||
firstChildElement.insertNext (newNode); | |||
} | |||
} | |||
XmlElement* XmlElement::createNewChildElement (const String& childTagName) | |||
{ | |||
XmlElement* const newElement = new XmlElement (childTagName); | |||
@@ -504,6 +504,10 @@ public: | |||
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. | |||
Note that due to the XmlElement using a singly-linked-list, prependChildElement() | |||
is an O(1) operation, but addChildElement() is an O(N) operation - so if | |||
you're adding large number of elements, you may prefer to do so in reverse order! | |||
@see getFirstChildElement, getNextElement, getNumChildElements, | |||
getChildElement, removeChildElement | |||
*/ | |||
@@ -515,14 +519,28 @@ public: | |||
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 newChildElement 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, | |||
void insertChildElement (XmlElement* newChildElement, | |||
int indexToInsertAt) noexcept; | |||
/** Inserts an element at the beginning of 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. | |||
Note that due to the XmlElement using a singly-linked-list, prependChildElement() | |||
is an O(1) operation, but addChildElement() is an O(N) operation - so if | |||
you're adding large number of elements, you may prefer to do so in reverse order! | |||
@see addChildElement, insertChildElement | |||
*/ | |||
void prependChildElement (XmlElement* newChildElement) noexcept; | |||
/** Creates a new element with the given name and returns it, after adding it | |||
as a child element. | |||
@@ -412,8 +412,9 @@ public: | |||
XmlElement* const xml = new XmlElement (type.toString()); | |||
properties.copyToXmlAttributes (*xml); | |||
for (int i = 0; i < children.size(); ++i) | |||
xml->addChildElement (children.getObjectPointerUnchecked(i)->createXml()); | |||
// (NB: it's faster to add nodes to XML elements in reverse order) | |||
for (int i = children.size(); --i >= 0;) | |||
xml->prependChildElement (children.getObjectPointerUnchecked(i)->createXml()); | |||
return xml; | |||
} | |||
@@ -89,7 +89,7 @@ public: | |||
#else | |||
#if JUCE_WINDOWS | |||
#if defined (WINAPI) || defined (_WINDOWS_) | |||
#if defined (WINAPI) || defined (_WINDOWS_) || defined(JUCE_MINGW) | |||
#define JUCE_MAIN_FUNCTION int __stdcall WinMain (HINSTANCE, HINSTANCE, const LPSTR, int) | |||
#elif defined (_UNICODE) | |||
#define JUCE_MAIN_FUNCTION int __stdcall WinMain (void*, void*, const wchar_t*, int) | |||
@@ -333,6 +333,18 @@ void MessageManager::broadcastMessage (const String& message) | |||
void repostCurrentNSEvent(); | |||
void repostCurrentNSEvent() | |||
{ | |||
NSEvent* e = [NSApp currentEvent]; | |||
[[NSOperationQueue mainQueue] addOperationWithBlock: ^{ [NSApp postEvent: e atStart: YES]; }]; | |||
struct EventReposter : public CallbackMessage | |||
{ | |||
EventReposter() : e ([[NSApp currentEvent] retain]) {} | |||
~EventReposter() { [e release]; } | |||
void messageCallback() override | |||
{ | |||
[NSApp postEvent: e atStart: YES]; | |||
} | |||
NSEvent* e; | |||
}; | |||
(new EventReposter())->post(); | |||
} |
@@ -155,9 +155,19 @@ void Typeface::setTypefaceCacheSize (int numFontsToCache) | |||
TypefaceCache::getInstance()->setSize (numFontsToCache); | |||
} | |||
#if JUCE_MODULE_AVAILABLE_juce_opengl | |||
extern void clearOpenGLGlyphCache(); | |||
#endif | |||
void Typeface::clearTypefaceCache() | |||
{ | |||
TypefaceCache::getInstance()->clear(); | |||
RenderingHelpers::SoftwareRendererSavedState::clearGlyphCache(); | |||
#if JUCE_MODULE_AVAILABLE_juce_opengl | |||
clearOpenGLGlyphCache(); | |||
#endif | |||
} | |||
//============================================================================== | |||
@@ -69,48 +69,45 @@ bool PathFlatteningIterator::next() | |||
float y3 = 0; | |||
float x4 = 0; | |||
float y4 = 0; | |||
float type; | |||
for (;;) | |||
{ | |||
float type; | |||
if (stackPos == stackBase) | |||
{ | |||
if (index >= path.numElements) | |||
{ | |||
return false; | |||
} | |||
else | |||
type = points [index++]; | |||
if (type != Path::closeSubPathMarker) | |||
{ | |||
type = points [index++]; | |||
x2 = points [index++]; | |||
y2 = points [index++]; | |||
if (type == Path::quadMarker) | |||
{ | |||
x3 = points [index++]; | |||
y3 = points [index++]; | |||
if (! isIdentityTransform) | |||
transform.transformPoints (x2, y2, x3, y3); | |||
} | |||
else if (type == Path::cubicMarker) | |||
{ | |||
x3 = points [index++]; | |||
y3 = points [index++]; | |||
x4 = points [index++]; | |||
y4 = points [index++]; | |||
if (type != Path::closeSubPathMarker) | |||
if (! isIdentityTransform) | |||
transform.transformPoints (x2, y2, x3, y3, x4, y4); | |||
} | |||
else | |||
{ | |||
x2 = points [index++]; | |||
y2 = points [index++]; | |||
if (type == Path::quadMarker) | |||
{ | |||
x3 = points [index++]; | |||
y3 = points [index++]; | |||
if (! isIdentityTransform) | |||
transform.transformPoints (x2, y2, x3, y3); | |||
} | |||
else if (type == Path::cubicMarker) | |||
{ | |||
x3 = points [index++]; | |||
y3 = points [index++]; | |||
x4 = points [index++]; | |||
y4 = points [index++]; | |||
if (! isIdentityTransform) | |||
transform.transformPoints (x2, y2, x3, y3, x4, y4); | |||
} | |||
else | |||
{ | |||
if (! isIdentityTransform) | |||
transform.transformPoint (x2, y2); | |||
} | |||
if (! isIdentityTransform) | |||
transform.transformPoint (x2, y2); | |||
} | |||
} | |||
} | |||
@@ -150,7 +147,8 @@ bool PathFlatteningIterator::next() | |||
return true; | |||
} | |||
else if (type == Path::quadMarker) | |||
if (type == Path::quadMarker) | |||
{ | |||
const size_t offset = (size_t) (stackPos - stackBase); | |||
@@ -190,61 +190,73 @@ public: | |||
Rectangle withZeroOrigin() const noexcept { return Rectangle (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 (pos.x, pos.y, newWidth, h); } | |||
Rectangle withWidth (ValueType newWidth) const noexcept { return Rectangle (pos.x, pos.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 (pos.x, pos.y, w, newHeight); } | |||
Rectangle withHeight (ValueType newHeight) const noexcept { return Rectangle (pos.x, pos.y, w, 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 (pos.x, pos.y, newWidth, newHeight); } | |||
Rectangle withSize (ValueType newWidth, const ValueType newHeight) const noexcept { return Rectangle (pos.x, pos.y, newWidth, 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(), pos.x + w - newLeft); pos.x = newLeft; } | |||
void setLeft (ValueType newLeft) noexcept { w = jmax (ValueType(), pos.x + w - newLeft); pos.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, pos.y, jmax (ValueType(), pos.x + w - newLeft), h); } | |||
Rectangle withLeft (ValueType newLeft) const noexcept { return Rectangle (newLeft, pos.y, jmax (ValueType(), pos.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(), pos.y + h - newTop); pos.y = newTop; } | |||
void setTop (ValueType newTop) noexcept { h = jmax (ValueType(), pos.y + h - newTop); pos.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 (pos.x, newTop, w, jmax (ValueType(), pos.y + h - newTop)); } | |||
Rectangle withTop (ValueType newTop) const noexcept { return Rectangle (pos.x, newTop, w, jmax (ValueType(), pos.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 { pos.x = jmin (pos.x, newRight); w = newRight - pos.x; } | |||
void setRight (ValueType newRight) noexcept { pos.x = jmin (pos.x, newRight); w = newRight - pos.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 (pos.x, newRight), pos.y, jmax (ValueType(), newRight - pos.x), h); } | |||
Rectangle withRight (ValueType newRight) const noexcept { return Rectangle (jmin (pos.x, newRight), pos.y, jmax (ValueType(), newRight - pos.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 { pos.y = jmin (pos.y, newBottom); h = newBottom - pos.y; } | |||
void setBottom (ValueType newBottom) noexcept { pos.y = jmin (pos.y, newBottom); h = newBottom - pos.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 (pos.x, jmin (pos.y, newBottom), w, jmax (ValueType(), newBottom - pos.y)); } | |||
Rectangle withBottom (ValueType newBottom) const noexcept { return Rectangle (pos.x, jmin (pos.y, newBottom), w, jmax (ValueType(), newBottom - pos.y)); } | |||
/** Returns a version of this rectangle with the given amount removed from its left-hand edge. */ | |||
Rectangle withTrimmedLeft (ValueType amountToRemove) const noexcept { return withLeft (pos.x + amountToRemove); } | |||
/** Returns a version of this rectangle with the given amount removed from its right-hand edge. */ | |||
Rectangle withTrimmedRight (ValueType amountToRemove) const noexcept { return withWidth (w - amountToRemove); } | |||
/** Returns a version of this rectangle with the given amount removed from its top edge. */ | |||
Rectangle withTrimmedTop (ValueType amountToRemove) const noexcept { return withTop (pos.y + amountToRemove); } | |||
/** Returns a version of this rectangle with the given amount removed from its bottom edge. */ | |||
Rectangle withTrimmedBottom (ValueType amountToRemove) const noexcept { return withHeight (h - amountToRemove); } | |||
//============================================================================== | |||
/** Moves the rectangle's position by adding amount to its x and y coordinates. */ | |||
@@ -142,7 +142,7 @@ class GlyphCache : private DeletedAtShutdown | |||
public: | |||
GlyphCache() | |||
{ | |||
addNewGlyphSlots (120); | |||
reset(); | |||
} | |||
~GlyphCache() | |||
@@ -207,6 +207,15 @@ public: | |||
glyph->draw (target, pos); | |||
} | |||
void reset() | |||
{ | |||
const ScopedWriteLock swl (lock); | |||
glyphs.clear(); | |||
addNewGlyphSlots (120); | |||
hits.set (0); | |||
misses.set (0); | |||
} | |||
private: | |||
friend struct ContainerDeletePolicy<CachedGlyphType>; | |||
OwnedArray<CachedGlyphType> glyphs; | |||
@@ -215,6 +224,8 @@ private: | |||
void addNewGlyphSlots (int num) | |||
{ | |||
glyphs.ensureStorageAllocated (glyphs.size() + num); | |||
while (--num >= 0) | |||
glyphs.add (new CachedGlyphType()); | |||
} | |||
@@ -2419,6 +2430,13 @@ public: | |||
} | |||
} | |||
typedef GlyphCache<CachedGlyphEdgeTable <SoftwareRendererSavedState>, SoftwareRendererSavedState> GlyphCacheType; | |||
static void clearGlyphCache() | |||
{ | |||
GlyphCacheType::getInstance().reset(); | |||
} | |||
//============================================================================== | |||
void drawGlyph (int glyphNumber, const AffineTransform& trans) | |||
{ | |||
@@ -2426,8 +2444,6 @@ public: | |||
{ | |||
if (trans.isOnlyTranslation() && ! transform.isRotated) | |||
{ | |||
typedef GlyphCache <CachedGlyphEdgeTable <SoftwareRendererSavedState>, SoftwareRendererSavedState> GlyphCacheType; | |||
GlyphCacheType& cache = GlyphCacheType::getInstance(); | |||
Point<float> pos (trans.getTranslationX(), trans.getTranslationY()); | |||
@@ -340,7 +340,7 @@ namespace CoreTextTypeLayout | |||
CFArrayRef lines = CTFrameGetLines (frame); | |||
const CFIndex numLines = CFArrayGetCount (lines); | |||
glyphLayout.ensureStorageAllocated (numLines); | |||
glyphLayout.ensureStorageAllocated ((int) numLines); | |||
for (CFIndex i = 0; i < numLines; ++i) | |||
{ | |||
@@ -309,7 +309,8 @@ void Button::internalClickCallback (const ModifierKeys& modifiers) | |||
{ | |||
if (clickTogglesState) | |||
setToggleState (radioGroupId != 0 || ! lastToggleState, sendNotification); | |||
else | |||
if (radioGroupId != 0 || ! clickTogglesState) | |||
sendClickMessage (modifiers); | |||
} | |||
@@ -355,6 +355,33 @@ public: | |||
// This method's parameters have changed - see the new version. | |||
JUCE_DEPRECATED (void setToggleState (bool, bool)); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
button-drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawButtonBackground (Graphics&, Button& button, const Colour& backgroundColour, | |||
bool isMouseOverButton, bool isButtonDown) = 0; | |||
virtual Font getTextButtonFont (TextButton& button) = 0; | |||
/** Draws the text for a TextButton. */ | |||
virtual void drawButtonText (Graphics&, TextButton&, bool isMouseOverButton, bool isButtonDown) = 0; | |||
/** Draws the contents of a standard ToggleButton. */ | |||
virtual void drawToggleButton (Graphics&, ToggleButton&, bool isMouseOverButton, bool isButtonDown) = 0; | |||
virtual void changeToggleButtonWidthToFitText (ToggleButton&) = 0; | |||
virtual void drawTickBox (Graphics&, Component&, float x, float y, float w, float h, | |||
bool ticked, bool isEnabled, bool isMouseOverButton, bool isButtonDown) = 0; | |||
virtual void drawDrawableButton (Graphics&, DrawableButton&, bool isMouseOverButton, bool isButtonDown) = 0; | |||
}; | |||
protected: | |||
//============================================================================== | |||
/** This method is called when the button has been clicked. | |||
@@ -124,6 +124,17 @@ public: | |||
*/ | |||
Image getDownImage() const; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawImageButton (Graphics&, Image*, | |||
int imageX, int imageY, int imageW, int imageH, | |||
const Colour& overlayColour, float imageOpacity, ImageButton&) = 0; | |||
}; | |||
protected: | |||
//============================================================================== | |||
/** @internal */ | |||
@@ -24,34 +24,32 @@ | |||
ShapeButton::ShapeButton (const String& t, Colour n, Colour o, Colour d) | |||
: Button (t), | |||
normalColour (n), | |||
overColour (o), | |||
downColour (d), | |||
normalColour (n), overColour (o), downColour (d), | |||
maintainShapeProportions (false), | |||
outlineWidth (0.0f) | |||
{ | |||
} | |||
ShapeButton::~ShapeButton() | |||
{ | |||
} | |||
ShapeButton::~ShapeButton() {} | |||
void ShapeButton::setColours (Colour newNormalColour, | |||
Colour newOverColour, | |||
Colour newDownColour) | |||
void ShapeButton::setColours (Colour newNormalColour, Colour newOverColour, Colour newDownColour) | |||
{ | |||
normalColour = newNormalColour; | |||
overColour = newOverColour; | |||
downColour = newDownColour; | |||
} | |||
void ShapeButton::setOutline (Colour newOutlineColour, | |||
const float newOutlineWidth) | |||
void ShapeButton::setOutline (Colour newOutlineColour, const float newOutlineWidth) | |||
{ | |||
outlineColour = newOutlineColour; | |||
outlineWidth = newOutlineWidth; | |||
} | |||
void ShapeButton::setBorderSize (BorderSize<int> newBorder) | |||
{ | |||
border = newBorder; | |||
} | |||
void ShapeButton::setShape (const Path& newShape, | |||
const bool resizeNowToFitThisShape, | |||
const bool maintainShapeProportions_, | |||
@@ -73,8 +71,8 @@ void ShapeButton::setShape (const Path& newShape, | |||
shape.applyTransform (AffineTransform::translation (-newBounds.getX(), | |||
-newBounds.getY())); | |||
setSize (1 + (int) (newBounds.getWidth() + outlineWidth), | |||
1 + (int) (newBounds.getHeight() + outlineWidth)); | |||
setSize (1 + (int) (newBounds.getWidth() + outlineWidth) + border.getLeftAndRight(), | |||
1 + (int) (newBounds.getHeight() + outlineWidth) + border.getTopAndBottom()); | |||
} | |||
repaint(); | |||
@@ -88,7 +86,7 @@ void ShapeButton::paintButton (Graphics& g, bool isMouseOverButton, bool isButto | |||
isButtonDown = false; | |||
} | |||
Rectangle<float> r (getLocalBounds().toFloat().reduced (outlineWidth * 0.5f)); | |||
Rectangle<float> r (border.subtractedFrom (getLocalBounds()).toFloat().reduced (outlineWidth * 0.5f)); | |||
if (getComponentEffect() != nullptr) | |||
r = r.reduced (2.0f); | |||
@@ -80,8 +80,12 @@ public: | |||
@param outlineColour the colour to use | |||
@param outlineStrokeWidth the thickness of line to draw | |||
*/ | |||
void setOutline (Colour outlineColour, | |||
float outlineStrokeWidth); | |||
void setOutline (Colour outlineColour, float outlineStrokeWidth); | |||
/** This lets you specify a border to be left around the edge of the button when | |||
drawing the shape. | |||
*/ | |||
void setBorderSize (BorderSize<int> border); | |||
/** @internal */ | |||
void paintButton (Graphics&, bool isMouseOverButton, bool isButtonDown) override; | |||
@@ -91,6 +95,7 @@ private: | |||
Colour normalColour, overColour, downColour, outlineColour; | |||
DropShadowEffect shadow; | |||
Path shape; | |||
BorderSize<int> border; | |||
bool maintainShapeProportions; | |||
float outlineWidth; | |||
@@ -89,7 +89,7 @@ LookAndFeel& Desktop::getDefaultLookAndFeel() noexcept | |||
if (currentLookAndFeel == nullptr) | |||
{ | |||
if (defaultLookAndFeel == nullptr) | |||
defaultLookAndFeel = new LookAndFeel(); | |||
defaultLookAndFeel = new LookAndFeel_V2(); | |||
currentLookAndFeel = defaultLookAndFeel; | |||
} | |||
@@ -56,6 +56,7 @@ void DirectoryContentsList::setDirectory (const File& directory, | |||
{ | |||
clear(); | |||
root = directory; | |||
changed(); | |||
// (this forces a refresh when setTypeFlags() is called, rather than triggering two refreshes) | |||
fileTypeFlags &= ~(File::findDirectories | File::findFiles); | |||
@@ -177,6 +177,42 @@ public: | |||
*/ | |||
static void getDefaultRoots (StringArray& rootNames, StringArray& rootPaths); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
various file-browser layout and drawing methods. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
// 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() = 0; | |||
virtual const Drawable* getDefaultDocumentFileImage() = 0; | |||
virtual AttributedString createFileChooserHeaderText (const String& title, | |||
const String& instructions) = 0; | |||
virtual void drawFileBrowserRow (Graphics&, int width, int height, | |||
const String& filename, | |||
Image* optionalIcon, | |||
const String& fileSizeDescription, | |||
const String& fileTimeDescription, | |||
bool isDirectory, | |||
bool isItemSelected, | |||
int itemIndex, | |||
DirectoryContentsDisplayComponent&) = 0; | |||
virtual Button* createFileBrowserGoUpButton() = 0; | |||
virtual void layoutFileBrowserComponent (FileBrowserComponent& browserComp, | |||
DirectoryContentsDisplayComponent* fileListComponent, | |||
FilePreviewComponent* previewComp, | |||
ComboBox* currentPathBox, | |||
TextEditor* filenameBox, | |||
Button* goUpButton) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void resized() override; | |||
@@ -180,6 +180,16 @@ public: | |||
/** Gives the component a tooltip. */ | |||
void setTooltip (const String& newTooltip) override; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual Button* createFilenameComponentBrowseButton (const String& text) = 0; | |||
virtual void layoutFilenameComponent (FilenameComponent&, ComboBox* filenameBox, Button* browseButton) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void paintOverChildren (Graphics&) override; | |||
@@ -198,6 +198,9 @@ extern bool juce_areThereAnyAlwaysOnTopWindows(); | |||
#include "layout/juce_TabbedComponent.cpp" | |||
#include "layout/juce_Viewport.cpp" | |||
#include "lookandfeel/juce_LookAndFeel.cpp" | |||
#include "lookandfeel/juce_LookAndFeel_V2.cpp" | |||
#include "lookandfeel/juce_LookAndFeel_V1.cpp" | |||
#include "lookandfeel/juce_LookAndFeel_V3.cpp" | |||
#include "menus/juce_MenuBarComponent.cpp" | |||
#include "menus/juce_MenuBarModel.cpp" | |||
#include "menus/juce_PopupMenu.cpp" | |||
@@ -113,6 +113,7 @@ class CaretComponent; | |||
class BubbleComponent; | |||
class KeyPressMappingSet; | |||
class ApplicationCommandManagerListener; | |||
class DrawableButton; | |||
#include "mouse/juce_MouseCursor.h" | |||
#include "mouse/juce_MouseListener.h" | |||
@@ -215,7 +216,6 @@ class ApplicationCommandManagerListener; | |||
#include "windows/juce_ThreadWithProgressWindow.h" | |||
#include "windows/juce_TooltipWindow.h" | |||
#include "layout/juce_MultiDocumentPanel.h" | |||
#include "lookandfeel/juce_LookAndFeel.h" | |||
#include "filebrowser/juce_FileFilter.h" | |||
#include "filebrowser/juce_WildcardFileFilter.h" | |||
#include "filebrowser/juce_FileBrowserListener.h" | |||
@@ -239,6 +239,10 @@ class ApplicationCommandManagerListener; | |||
#include "properties/juce_TextPropertyComponent.h" | |||
#include "application/juce_Application.h" | |||
#include "misc/juce_BubbleComponent.h" | |||
#include "lookandfeel/juce_LookAndFeel.h" | |||
#include "lookandfeel/juce_LookAndFeel_V2.h" | |||
#include "lookandfeel/juce_LookAndFeel_V1.h" | |||
#include "lookandfeel/juce_LookAndFeel_V3.h" | |||
} | |||
@@ -93,6 +93,16 @@ public: | |||
/** Sets the height of the header section for one of the panels. */ | |||
void setPanelHeaderSize (Component* panelComponent, int headerSize); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawConcertinaPanelHeader (Graphics&, const Rectangle<int>& area, | |||
bool isMouseOver, bool isMouseDown, ConcertinaPanel&, Component&) = 0; | |||
}; | |||
private: | |||
void resized() override; | |||
@@ -31,11 +31,8 @@ GroupComponent::GroupComponent (const String& name, | |||
setInterceptsMouseClicks (false, true); | |||
} | |||
GroupComponent::~GroupComponent() | |||
{ | |||
} | |||
GroupComponent::~GroupComponent() {} | |||
//============================================================================== | |||
void GroupComponent::setText (const String& newText) | |||
{ | |||
if (text != newText) | |||
@@ -50,7 +47,6 @@ String GroupComponent::getText() const | |||
return text; | |||
} | |||
//============================================================================== | |||
void GroupComponent::setTextLabelPosition (Justification newJustification) | |||
{ | |||
if (justification != newJustification) | |||
@@ -62,18 +58,9 @@ void GroupComponent::setTextLabelPosition (Justification newJustification) | |||
void GroupComponent::paint (Graphics& g) | |||
{ | |||
getLookAndFeel() | |||
.drawGroupComponentOutline (g, getWidth(), getHeight(), | |||
text, justification, | |||
*this); | |||
getLookAndFeel().drawGroupComponentOutline (g, getWidth(), getHeight(), | |||
text, justification, *this); | |||
} | |||
void GroupComponent::enablementChanged() | |||
{ | |||
repaint(); | |||
} | |||
void GroupComponent::colourChanged() | |||
{ | |||
repaint(); | |||
} | |||
void GroupComponent::enablementChanged() { repaint(); } | |||
void GroupComponent::colourChanged() { repaint(); } |
@@ -82,6 +82,16 @@ public: | |||
textColourId = 0x1005410 /**< The colour to use to draw the text label. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawGroupComponentOutline (Graphics&, int w, int h, const String& text, | |||
const Justification&, GroupComponent&) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void paint (Graphics&) override; | |||
@@ -292,6 +292,73 @@ public: | |||
/** Deregisters a previously-registered listener. */ | |||
void removeListener (Listener* listener); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
scrollbar-drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual bool areScrollbarButtonsVisible() = 0; | |||
/** 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) = 0; | |||
/** 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 coordinate 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) = 0; | |||
/** Returns the component effect to use for a scrollbar */ | |||
virtual ImageEffectFilter* getScrollbarEffect() = 0; | |||
/** Returns the minimum length in pixels to use for a scrollbar thumb. */ | |||
virtual int getMinimumScrollbarThumbSize (ScrollBar&) = 0; | |||
/** Returns the default thickness to use for a scrollbar. */ | |||
virtual int getDefaultScrollbarWidth() = 0; | |||
/** Returns the length in pixels to use for a scrollbar button. */ | |||
virtual int getScrollbarButtonSize (ScrollBar&) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
bool keyPressed (const KeyPress&) override; | |||
@@ -72,6 +72,16 @@ public: | |||
*/ | |||
virtual void hasBeenMoved(); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawStretchableLayoutResizerBar (Graphics&, int w, int h, | |||
bool isVerticalBar, bool isMouseOver, bool isMouseDragging) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void paint (Graphics&) override; | |||
@@ -93,7 +93,26 @@ void TabBarButton::calcAreas (Rectangle<int>& extraComp, Rectangle<int>& textAre | |||
} | |||
if (extraComponent != nullptr) | |||
{ | |||
extraComp = lf.getTabButtonExtraComponentBounds (*this, textArea, *extraComponent); | |||
const TabbedButtonBar::Orientation orientation = owner.getOrientation(); | |||
if (orientation == TabbedButtonBar::TabsAtLeft || orientation == TabbedButtonBar::TabsAtRight) | |||
{ | |||
if (extraComp.getCentreY() > textArea.getCentreY()) | |||
textArea.setBottom (jmin (textArea.getBottom(), extraComp.getY())); | |||
else | |||
textArea.setTop (jmax (textArea.getY(), extraComp.getBottom())); | |||
} | |||
else | |||
{ | |||
if (extraComp.getCentreX() > textArea.getCentreX()) | |||
textArea.setRight (jmin (textArea.getRight(), extraComp.getX())); | |||
else | |||
textArea.setLeft (jmax (textArea.getX(), extraComp.getRight())); | |||
} | |||
} | |||
} | |||
Rectangle<int> TabBarButton::getTextArea() const | |||
@@ -293,6 +293,30 @@ public: | |||
colour. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
window drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual int getTabButtonSpaceAroundImage() = 0; | |||
virtual int getTabButtonOverlap (int tabDepth) = 0; | |||
virtual int getTabButtonBestWidth (TabBarButton&, int tabDepth) = 0; | |||
virtual Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp) = 0; | |||
virtual void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) = 0; | |||
virtual void drawTabButtonText (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) = 0; | |||
virtual void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) = 0; | |||
virtual void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h) = 0; | |||
virtual void createTabButtonShape (TabBarButton&, Path& path, bool isMouseOver, bool isMouseDown) = 0; | |||
virtual void fillTabButtonShape (TabBarButton&, Graphics&, const Path& path, bool isMouseOver, bool isMouseDown) = 0; | |||
virtual Button* createTabBarExtrasButton() = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void paint (Graphics&) override; | |||
@@ -25,14 +25,80 @@ | |||
#ifndef JUCE_LOOKANDFEEL_H_INCLUDED | |||
#define JUCE_LOOKANDFEEL_H_INCLUDED | |||
//============================================================================== | |||
/** This class is used to hold a few look and feel base classes which are associated | |||
with classes that may not be present because they're from modules other than | |||
juce_gui_basics. | |||
*/ | |||
struct JUCE_API ExtraLookAndFeelBaseClasses | |||
{ | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LassoComponentMethods | |||
{ | |||
virtual ~LassoComponentMethods() {} | |||
virtual void drawLasso (Graphics&, Component& lassoComp) = 0; | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API KeyMappingEditorComponentMethods | |||
{ | |||
virtual ~KeyMappingEditorComponentMethods() {} | |||
virtual void drawKeymapChangeButton (Graphics&, int width, int height, Button&, const String& keyDescription) = 0; | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API AudioDeviceSelectorComponentMethods | |||
{ | |||
virtual ~AudioDeviceSelectorComponentMethods() {} | |||
virtual void drawLevelMeter (Graphics&, int width, int height, float level) = 0; | |||
}; | |||
}; | |||
//============================================================================== | |||
/** | |||
LookAndFeel objects define the appearance of all the JUCE widgets, and subclasses | |||
can be used to apply different 'skins' to the application. | |||
This class is an abstract base-class - for actual look-and-feels that you can | |||
instantiate, see LookAndFeel_V1, LookAndFeel_V2 and LookAndFeel_V3. | |||
@see LookAndFeel_V1, LookAndFeel_V2, LookAndFeel_V3 | |||
*/ | |||
class JUCE_API LookAndFeel | |||
class JUCE_API LookAndFeel : public ScrollBar::LookAndFeelMethods, | |||
public Button::LookAndFeelMethods, | |||
public ImageButton::LookAndFeelMethods, | |||
public TextEditor::LookAndFeelMethods, | |||
public FileBrowserComponent::LookAndFeelMethods, | |||
public TreeView::LookAndFeelMethods, | |||
public BubbleComponent::LookAndFeelMethods, | |||
public AlertWindow::LookAndFeelMethods, | |||
public PopupMenu::LookAndFeelMethods, | |||
public ComboBox::LookAndFeelMethods, | |||
public Label::LookAndFeelMethods, | |||
public Slider::LookAndFeelMethods, | |||
public ResizableWindow::LookAndFeelMethods, | |||
public DocumentWindow::LookAndFeelMethods, | |||
public TooltipWindow::LookAndFeelMethods, | |||
public TabbedButtonBar::LookAndFeelMethods, | |||
public PropertyComponent::LookAndFeelMethods, | |||
public FilenameComponent::LookAndFeelMethods, | |||
public GroupComponent::LookAndFeelMethods, | |||
public TableHeaderComponent::LookAndFeelMethods, | |||
public CallOutBox::LookAndFeelMethods, | |||
public Toolbar::LookAndFeelMethods, | |||
public ConcertinaPanel::LookAndFeelMethods, | |||
public ProgressBar::LookAndFeelMethods, | |||
public StretchableLayoutResizerBar::LookAndFeelMethods, | |||
public ExtraLookAndFeelBaseClasses::KeyMappingEditorComponentMethods, | |||
public ExtraLookAndFeelBaseClasses::AudioDeviceSelectorComponentMethods, | |||
public ExtraLookAndFeelBaseClasses::LassoComponentMethods | |||
{ | |||
public: | |||
//============================================================================== | |||
@@ -60,7 +126,6 @@ public: | |||
*/ | |||
static void setDefaultLookAndFeel (LookAndFeel* newDefaultLookAndFeel) noexcept; | |||
//============================================================================== | |||
/** Looks for a colour that has been registered with the given colour ID number. | |||
@@ -82,9 +147,7 @@ public: | |||
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, Colour colour) noexcept; | |||
@@ -94,9 +157,12 @@ public: | |||
*/ | |||
bool isColourSpecified (int colourId) const noexcept; | |||
//============================================================================== | |||
virtual Typeface::Ptr getTypefaceForFont (const Font& font); | |||
/** Returns the typeface that should be used for a given font. | |||
The default implementation just does what you'd expect it to, but you can override | |||
this if you want to intercept fonts and use your own custom typeface object. | |||
*/ | |||
virtual Typeface::Ptr getTypefaceForFont (const Font&); | |||
/** Allows you to change the default sans-serif font. | |||
@@ -110,509 +176,38 @@ public: | |||
/** Override this to get the chance to swap a component's mouse cursor for a | |||
customised one. | |||
*/ | |||
virtual MouseCursor getMouseCursorFor (Component& component); | |||
virtual MouseCursor getMouseCursorFor (Component&); | |||
//============================================================================== | |||
// Creates a new graphics context object. | |||
/** Creates a new graphics context object. */ | |||
virtual LowLevelGraphicsContext* createGraphicsContext (const Image& imageToRenderOn, | |||
const Point<int>& origin, | |||
const RectangleList<int>& initialClip); | |||
//============================================================================== | |||
/** Draws the lozenge-shaped background for a standard button. */ | |||
virtual void drawButtonBackground (Graphics&, | |||
Button& button, | |||
const Colour& backgroundColour, | |||
bool isMouseOverButton, | |||
bool isButtonDown); | |||
virtual Font getTextButtonFont (TextButton& button); | |||
/** Draws the text for a TextButton. */ | |||
virtual void drawButtonText (Graphics&, | |||
TextButton& button, | |||
bool isMouseOverButton, | |||
bool isButtonDown); | |||
/** Draws the contents of a standard ToggleButton. */ | |||
virtual void drawToggleButton (Graphics&, | |||
ToggleButton& button, | |||
bool isMouseOverButton, | |||
bool isButtonDown); | |||
virtual void changeToggleButtonWidthToFitText (ToggleButton& button); | |||
virtual void drawTickBox (Graphics&, | |||
Component& component, | |||
float x, float y, float w, float h, | |||
bool ticked, | |||
bool isEnabled, | |||
bool isMouseOverButton, | |||
bool isButtonDown); | |||
virtual void drawDrawableButton (Graphics&, | |||
DrawableButton& button, | |||
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&, | |||
AlertWindow& alert, | |||
const Rectangle<int>& textArea, | |||
TextLayout& textLayout); | |||
virtual int getAlertBoxWindowFlags(); | |||
virtual int getAlertWindowButtonHeight(); | |||
virtual Font getAlertWindowMessageFont(); | |||
virtual 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&, 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&, const Colour& colour, | |||
int x, int y, int w, int h); | |||
//============================================================================== | |||
virtual bool areScrollbarButtonsVisible(); | |||
/** 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 | |||
/** 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 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 coordinate 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); | |||
virtual void drawSpinningWaitAnimation (Graphics&, const Colour& colour, | |||
int x, int y, int w, int h) = 0; | |||
//============================================================================== | |||
/** Returns a tick shape for use in yes/no boxes, etc. */ | |||
virtual Path getTickShape (float height); | |||
virtual Path getTickShape (float height) = 0; | |||
/** Returns a cross shape for use in yes/no boxes, etc. */ | |||
virtual Path getCrossShape (float height); | |||
//============================================================================== | |||
/** Draws the + or - box in a treeview. */ | |||
virtual void drawTreeviewPlusMinusBox (Graphics&, int x, int y, int w, int h, bool isPlus, bool isMouseOver); | |||
virtual Path getCrossShape (float height) = 0; | |||
//============================================================================== | |||
virtual void fillTextEditorBackground (Graphics&, int width, int height, TextEditor& textEditor); | |||
virtual void drawTextEditorOutline (Graphics&, 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 AttributedString createFileChooserHeaderText (const String& title, | |||
const String& instructions); | |||
virtual void drawFileBrowserRow (Graphics&, 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&, BubbleComponent&, | |||
const Point<float>& tip, const Rectangle<float>& body); | |||
//============================================================================== | |||
virtual void drawLasso (Graphics&, Component& lassoComp); | |||
//============================================================================== | |||
/** Fills the background of a popup menu component. */ | |||
virtual void drawPopupMenuBackground (Graphics&, int width, int height); | |||
/** Draws one of the items in a popup menu. */ | |||
virtual void drawPopupMenuItem (Graphics&, | |||
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 Font getPopupMenuFont(); | |||
virtual void drawPopupMenuUpDownArrow (Graphics&, | |||
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&, int width, int height, | |||
bool isMouseOverBar, | |||
MenuBarComponent& menuBar); | |||
virtual int getMenuBarItemWidth (MenuBarComponent& menuBar, int itemIndex, const String& itemText); | |||
virtual Font getMenuBarFont (MenuBarComponent& menuBar, int itemIndex, const String& itemText); | |||
virtual void drawMenuBarItem (Graphics&, | |||
int width, int height, | |||
int itemIndex, | |||
const String& itemText, | |||
bool isMouseOverItem, | |||
bool isMenuOpen, | |||
bool isMouseOverBar, | |||
MenuBarComponent& menuBar); | |||
//============================================================================== | |||
virtual void drawComboBox (Graphics&, int width, int height, | |||
bool isButtonDown, | |||
int buttonX, int buttonY, | |||
int buttonW, int buttonH, | |||
ComboBox& box); | |||
virtual Font getComboBoxFont (ComboBox& box); | |||
virtual Label* createComboBoxTextBox (ComboBox& box); | |||
virtual void positionComboBoxText (ComboBox& box, Label& labelToPosition); | |||
virtual DropShadower* createDropShadowerForComponent (Component*) = 0; | |||
//============================================================================== | |||
virtual void drawLabel (Graphics&, Label&); | |||
virtual Font getLabelFont (Label&); | |||
//============================================================================== | |||
virtual void drawLinearSlider (Graphics&, | |||
int x, int y, | |||
int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider& slider); | |||
virtual void drawLinearSliderBackground (Graphics&, | |||
int x, int y, | |||
int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider& slider); | |||
virtual void drawLinearSliderThumb (Graphics&, | |||
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&, | |||
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 Font getSliderPopupFont(); | |||
virtual int getSliderPopupPlacement(); | |||
//============================================================================== | |||
virtual void getTooltipSize (const String& tipText, int& width, int& height); | |||
virtual void drawTooltip (Graphics&, const String& text, int width, int height); | |||
//============================================================================== | |||
virtual Button* createFilenameComponentBrowseButton (const String& text); | |||
virtual void layoutFilenameComponent (FilenameComponent& filenameComp, | |||
ComboBox* filenameBox, Button* browseButton); | |||
//============================================================================== | |||
virtual void drawConcertinaPanelHeader (Graphics&, const Rectangle<int>& area, | |||
bool isMouseOver, bool isMouseDown, | |||
ConcertinaPanel&, Component& panel); | |||
//============================================================================== | |||
virtual void drawCornerResizer (Graphics&, | |||
int w, int h, | |||
bool isMouseOver, | |||
bool isMouseDragging); | |||
virtual void drawResizableFrame (Graphics&, | |||
int w, int h, | |||
const BorderSize<int>&); | |||
//============================================================================== | |||
virtual void fillResizableWindowBackground (Graphics&, int w, int h, | |||
const BorderSize<int>&, | |||
ResizableWindow& window); | |||
virtual void drawResizableWindowBorder (Graphics&, | |||
int w, int h, | |||
const BorderSize<int>& border, | |||
ResizableWindow& window); | |||
//============================================================================== | |||
virtual void drawDocumentWindowTitleBar (DocumentWindow& window, | |||
Graphics&, 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&, | |||
int w, int h, | |||
bool isVerticalBar, | |||
bool isMouseOver, | |||
bool isMouseDragging); | |||
//============================================================================== | |||
virtual void drawGroupComponentOutline (Graphics&, int w, int h, | |||
const String& text, | |||
const Justification& position, | |||
GroupComponent& group); | |||
//============================================================================== | |||
virtual int getTabButtonSpaceAroundImage(); | |||
virtual int getTabButtonOverlap (int tabDepth); | |||
virtual int getTabButtonBestWidth (TabBarButton&, int tabDepth); | |||
virtual Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp); | |||
virtual void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown); | |||
virtual void drawTabButtonText (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown); | |||
virtual void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&); | |||
virtual void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h); | |||
virtual void createTabButtonShape (TabBarButton&, Path& path, bool isMouseOver, bool isMouseDown); | |||
virtual void fillTabButtonShape (TabBarButton&, Graphics&, const Path& path, bool isMouseOver, bool isMouseDown); | |||
virtual Button* createTabBarExtrasButton(); | |||
//============================================================================== | |||
virtual void drawImageButton (Graphics&, Image* image, | |||
int imageX, int imageY, int imageW, int imageH, | |||
const Colour& overlayColour, | |||
float imageOpacity, | |||
ImageButton& button); | |||
//============================================================================== | |||
virtual void drawTableHeaderBackground (Graphics&, TableHeaderComponent&); | |||
virtual void drawTableHeaderColumn (Graphics&, const String& columnName, int columnId, | |||
int width, int height, | |||
bool isMouseOver, bool isMouseDown, | |||
int columnFlags); | |||
//============================================================================== | |||
virtual void paintToolbarBackground (Graphics&, int width, int height, Toolbar& toolbar); | |||
virtual Button* createToolbarMissingItemsButton (Toolbar& toolbar); | |||
virtual void paintToolbarButtonBackground (Graphics&, int width, int height, | |||
bool isMouseOver, bool isMouseDown, | |||
ToolbarItemComponent& component); | |||
virtual void paintToolbarButtonLabel (Graphics&, int x, int y, int width, int height, | |||
const String& text, ToolbarItemComponent& component); | |||
//============================================================================== | |||
virtual void drawPropertyPanelSectionHeader (Graphics&, const String& name, | |||
bool isOpen, int width, int height); | |||
virtual void drawPropertyComponentBackground (Graphics&, int width, int height, | |||
PropertyComponent& component); | |||
virtual void drawPropertyComponentLabel (Graphics&, int width, int height, | |||
PropertyComponent& component); | |||
virtual Rectangle<int> getPropertyComponentContentPosition (PropertyComponent& component); | |||
//============================================================================== | |||
virtual void drawCallOutBoxBackground (CallOutBox& box, Graphics&, const Path& path, Image& cachedImage); | |||
//============================================================================== | |||
virtual void drawLevelMeter (Graphics&, int width, int height, float level); | |||
virtual void drawKeymapChangeButton (Graphics&, int width, int height, Button& button, const String& keyDescription); | |||
//============================================================================== | |||
/** Plays the system's default 'beep' noise, to alert the user about something very important. | |||
*/ | |||
/** Plays the system's default 'beep' noise, to alert the user about something very important. */ | |||
virtual void playAlertSound(); | |||
//============================================================================== | |||
/** 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. | |||
*/ | |||
static void drawBevel (Graphics&, | |||
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); | |||
/** Utility function to draw a shiny, glassy circle (for round LED-type buttons). */ | |||
static void drawGlassSphere (Graphics&, | |||
float x, float y, | |||
float diameter, | |||
const Colour& colour, | |||
float outlineThickness) noexcept; | |||
static void drawGlassPointer (Graphics&, | |||
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&, | |||
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>; | |||
@@ -628,40 +223,9 @@ private: | |||
}; | |||
SortedSet<ColourSetting> colours; | |||
// default typeface names | |||
String defaultSans, defaultSerif, defaultFixed; | |||
ScopedPointer<Drawable> folderImage, documentImage; | |||
bool useNativeAlertWindows; | |||
void drawShinyButtonShape (Graphics&, | |||
float x, float y, float w, float h, float maxCornerSize, | |||
const Colour& baseColour, | |||
float strokeWidth, | |||
bool flatOnLeft, | |||
bool flatOnRight, | |||
bool flatOnTop, | |||
bool flatOnBottom) noexcept; | |||
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE | |||
// These methods have been deprecated - see their new parameter lists.. | |||
virtual int drawFileBrowserRow (Graphics&, int, int, const String&, Image*, const String&, const String&, bool, bool, int) { return 0; } | |||
virtual int drawTabButton (Graphics&, int, int, const Colour&, int, const String&, Button&, TabbedButtonBar::Orientation, bool, bool, bool) { return 0; } | |||
virtual int createTabButtonShape (Path&, int, int, int, const String&, Button&, TabbedButtonBar::Orientation, bool, bool, bool) { return 0; } | |||
virtual int fillTabButtonShape (Graphics&, const Path&, const Colour&, int, const String&, Button&, TabbedButtonBar::Orientation, bool, bool, bool) { return 0; } | |||
virtual int drawTabAreaBehindFrontButton (Graphics&, int, int, TabbedButtonBar&, TabbedButtonBar::Orientation) { return 0; } | |||
virtual int drawTabButtonText (Graphics&, int, int, int, int, const Colour&, int, const String&, Button&, TabbedButtonBar::Orientation, bool, bool, bool) { return 0; } | |||
virtual int getTabButtonBestWidth (int, const String&, int, Button&) { return 0; } | |||
virtual int drawBubble (Graphics&, float, float, float, float, float, float) { return 0; } | |||
virtual int getFontForTextButton (TextButton&) { return 0; } | |||
virtual int createFileChooserHeaderText (const String&, const String&, GlyphArrangement&, int) { return 0; } | |||
#endif | |||
class GlassWindowButton; | |||
class SliderLabelComp; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeel) | |||
}; | |||
@@ -0,0 +1,567 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2013 - Raw Material Software Ltd. | |||
Permission is granted to use this software under the terms of either: | |||
a) the GPL v2 (or any later version) | |||
b) the Affero GPL v3 | |||
Details of these licenses can be found 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.juce.com for more information. | |||
============================================================================== | |||
*/ | |||
LookAndFeel_V1::LookAndFeel_V1() | |||
{ | |||
setColour (TextButton::buttonColourId, Colour (0xffbbbbff)); | |||
setColour (ListBox::outlineColourId, findColour (ComboBox::outlineColourId)); | |||
setColour (ScrollBar::thumbColourId, Colour (0xffbbbbdd)); | |||
setColour (ScrollBar::backgroundColourId, Colours::transparentBlack); | |||
setColour (Slider::thumbColourId, Colours::white); | |||
setColour (Slider::trackColourId, Colour (0x7f000000)); | |||
setColour (Slider::textBoxOutlineColourId, Colours::grey); | |||
setColour (ProgressBar::backgroundColourId, Colours::white.withAlpha (0.6f)); | |||
setColour (ProgressBar::foregroundColourId, Colours::green.withAlpha (0.7f)); | |||
setColour (PopupMenu::backgroundColourId, Colour (0xffeef5f8)); | |||
setColour (PopupMenu::highlightedBackgroundColourId, Colour (0xbfa4c2ce)); | |||
setColour (PopupMenu::highlightedTextColourId, Colours::black); | |||
setColour (TextEditor::focusedOutlineColourId, findColour (TextButton::buttonColourId)); | |||
scrollbarShadow.setShadowProperties (DropShadow (Colours::black.withAlpha (0.5f), 2, Point<int>())); | |||
} | |||
LookAndFeel_V1::~LookAndFeel_V1() | |||
{ | |||
} | |||
//============================================================================== | |||
void LookAndFeel_V1::drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour, | |||
bool isMouseOverButton, bool isButtonDown) | |||
{ | |||
const int width = button.getWidth(); | |||
const int height = button.getHeight(); | |||
const float indent = 2.0f; | |||
const int cornerSize = jmin (roundToInt (width * 0.4f), | |||
roundToInt (height * 0.4f)); | |||
Path p; | |||
p.addRoundedRectangle (indent, indent, | |||
width - indent * 2.0f, | |||
height - indent * 2.0f, | |||
(float) cornerSize); | |||
Colour bc (backgroundColour.withMultipliedSaturation (0.3f)); | |||
if (isMouseOverButton) | |||
{ | |||
if (isButtonDown) | |||
bc = bc.brighter(); | |||
else if (bc.getBrightness() > 0.5f) | |||
bc = bc.darker (0.1f); | |||
else | |||
bc = bc.brighter (0.1f); | |||
} | |||
g.setColour (bc); | |||
g.fillPath (p); | |||
g.setColour (bc.contrasting().withAlpha ((isMouseOverButton) ? 0.6f : 0.4f)); | |||
g.strokePath (p, PathStrokeType ((isMouseOverButton) ? 2.0f : 1.4f)); | |||
} | |||
void LookAndFeel_V1::drawTickBox (Graphics& g, Component& /*component*/, | |||
float x, float y, float w, float h, | |||
const bool ticked, | |||
const bool isEnabled, | |||
const bool /*isMouseOverButton*/, | |||
const bool isButtonDown) | |||
{ | |||
Path box; | |||
box.addRoundedRectangle (0.0f, 2.0f, 6.0f, 6.0f, 1.0f); | |||
g.setColour (isEnabled ? Colours::blue.withAlpha (isButtonDown ? 0.3f : 0.1f) | |||
: Colours::lightgrey.withAlpha (0.1f)); | |||
AffineTransform trans (AffineTransform::scale (w / 9.0f, h / 9.0f).translated (x, y)); | |||
g.fillPath (box, trans); | |||
g.setColour (Colours::black.withAlpha (0.6f)); | |||
g.strokePath (box, PathStrokeType (0.9f), trans); | |||
if (ticked) | |||
{ | |||
Path tick; | |||
tick.startNewSubPath (1.5f, 3.0f); | |||
tick.lineTo (3.0f, 6.0f); | |||
tick.lineTo (6.0f, 0.0f); | |||
g.setColour (isEnabled ? Colours::black : Colours::grey); | |||
g.strokePath (tick, PathStrokeType (2.5f), trans); | |||
} | |||
} | |||
void LookAndFeel_V1::drawToggleButton (Graphics& g, ToggleButton& button, bool isMouseOverButton, bool isButtonDown) | |||
{ | |||
if (button.hasKeyboardFocus (true)) | |||
{ | |||
g.setColour (button.findColour (TextEditor::focusedOutlineColourId)); | |||
g.drawRect (0, 0, button.getWidth(), button.getHeight()); | |||
} | |||
const int tickWidth = jmin (20, button.getHeight() - 4); | |||
drawTickBox (g, button, 4.0f, (button.getHeight() - tickWidth) * 0.5f, | |||
(float) tickWidth, (float) tickWidth, | |||
button.getToggleState(), | |||
button.isEnabled(), | |||
isMouseOverButton, | |||
isButtonDown); | |||
g.setColour (button.findColour (ToggleButton::textColourId)); | |||
g.setFont (jmin (15.0f, button.getHeight() * 0.6f)); | |||
if (! button.isEnabled()) | |||
g.setOpacity (0.5f); | |||
const int textX = tickWidth + 5; | |||
g.drawFittedText (button.getButtonText(), | |||
textX, 4, | |||
button.getWidth() - textX - 2, button.getHeight() - 8, | |||
Justification::centredLeft, 10); | |||
} | |||
void LookAndFeel_V1::drawProgressBar (Graphics& g, ProgressBar& progressBar, | |||
int width, int height, | |||
double progress, const String& textToShow) | |||
{ | |||
if (progress < 0 || progress >= 1.0) | |||
{ | |||
LookAndFeel_V2::drawProgressBar (g, progressBar, width, height, progress, textToShow); | |||
} | |||
else | |||
{ | |||
const Colour background (progressBar.findColour (ProgressBar::backgroundColourId)); | |||
const Colour foreground (progressBar.findColour (ProgressBar::foregroundColourId)); | |||
g.fillAll (background); | |||
g.setColour (foreground); | |||
g.fillRect (1, 1, | |||
jlimit (0, width - 2, roundToInt (progress * (width - 2))), | |||
height - 2); | |||
if (textToShow.isNotEmpty()) | |||
{ | |||
g.setColour (Colour::contrasting (background, foreground)); | |||
g.setFont (height * 0.6f); | |||
g.drawText (textToShow, 0, 0, width, height, Justification::centred, false); | |||
} | |||
} | |||
} | |||
void LookAndFeel_V1::drawScrollbarButton (Graphics& g, ScrollBar& bar, | |||
int width, int height, int buttonDirection, | |||
bool isScrollbarVertical, | |||
bool isMouseOverButton, | |||
bool isButtonDown) | |||
{ | |||
if (isScrollbarVertical) | |||
width -= 2; | |||
else | |||
height -= 2; | |||
Path p; | |||
if (buttonDirection == 0) | |||
p.addTriangle (width * 0.5f, height * 0.2f, | |||
width * 0.1f, height * 0.7f, | |||
width * 0.9f, height * 0.7f); | |||
else if (buttonDirection == 1) | |||
p.addTriangle (width * 0.8f, height * 0.5f, | |||
width * 0.3f, height * 0.1f, | |||
width * 0.3f, height * 0.9f); | |||
else if (buttonDirection == 2) | |||
p.addTriangle (width * 0.5f, height * 0.8f, | |||
width * 0.1f, height * 0.3f, | |||
width * 0.9f, height * 0.3f); | |||
else if (buttonDirection == 3) | |||
p.addTriangle (width * 0.2f, height * 0.5f, | |||
width * 0.7f, height * 0.1f, | |||
width * 0.7f, height * 0.9f); | |||
if (isButtonDown) | |||
g.setColour (Colours::white); | |||
else if (isMouseOverButton) | |||
g.setColour (Colours::white.withAlpha (0.7f)); | |||
else | |||
g.setColour (bar.findColour (ScrollBar::thumbColourId).withAlpha (0.5f)); | |||
g.fillPath (p); | |||
g.setColour (Colours::black.withAlpha (0.5f)); | |||
g.strokePath (p, PathStrokeType (0.5f)); | |||
} | |||
void LookAndFeel_V1::drawScrollbar (Graphics& g, ScrollBar& bar, | |||
int x, int y, int width, int height, | |||
bool isScrollbarVertical, int thumbStartPosition, int thumbSize, | |||
bool isMouseOver, bool isMouseDown) | |||
{ | |||
g.fillAll (bar.findColour (ScrollBar::backgroundColourId)); | |||
g.setColour (bar.findColour (ScrollBar::thumbColourId) | |||
.withAlpha ((isMouseOver || isMouseDown) ? 0.4f : 0.15f)); | |||
if (thumbSize > 0.0f) | |||
{ | |||
Rectangle<int> thumb; | |||
if (isScrollbarVertical) | |||
{ | |||
width -= 2; | |||
g.fillRect (x + roundToInt (width * 0.35f), y, | |||
roundToInt (width * 0.3f), height); | |||
thumb.setBounds (x + 1, thumbStartPosition, | |||
width - 2, thumbSize); | |||
} | |||
else | |||
{ | |||
height -= 2; | |||
g.fillRect (x, y + roundToInt (height * 0.35f), | |||
width, roundToInt (height * 0.3f)); | |||
thumb.setBounds (thumbStartPosition, y + 1, | |||
thumbSize, height - 2); | |||
} | |||
g.setColour (bar.findColour (ScrollBar::thumbColourId) | |||
.withAlpha ((isMouseOver || isMouseDown) ? 0.95f : 0.7f)); | |||
g.fillRect (thumb); | |||
g.setColour (Colours::black.withAlpha ((isMouseOver || isMouseDown) ? 0.4f : 0.25f)); | |||
g.drawRect (thumb.getX(), thumb.getY(), thumb.getWidth(), thumb.getHeight()); | |||
if (thumbSize > 16) | |||
{ | |||
for (int i = 3; --i >= 0;) | |||
{ | |||
const float linePos = thumbStartPosition + thumbSize / 2 + (i - 1) * 4.0f; | |||
g.setColour (Colours::black.withAlpha (0.15f)); | |||
if (isScrollbarVertical) | |||
{ | |||
g.drawLine (x + width * 0.2f, linePos, width * 0.8f, linePos); | |||
g.setColour (Colours::white.withAlpha (0.15f)); | |||
g.drawLine (width * 0.2f, linePos - 1, width * 0.8f, linePos - 1); | |||
} | |||
else | |||
{ | |||
g.drawLine (linePos, height * 0.2f, linePos, height * 0.8f); | |||
g.setColour (Colours::white.withAlpha (0.15f)); | |||
g.drawLine (linePos - 1, height * 0.2f, linePos - 1, height * 0.8f); | |||
} | |||
} | |||
} | |||
} | |||
} | |||
ImageEffectFilter* LookAndFeel_V1::getScrollbarEffect() | |||
{ | |||
return &scrollbarShadow; | |||
} | |||
//============================================================================== | |||
void LookAndFeel_V1::drawPopupMenuBackground (Graphics& g, int width, int height) | |||
{ | |||
g.fillAll (findColour (PopupMenu::backgroundColourId)); | |||
g.setColour (Colours::black.withAlpha (0.6f)); | |||
g.drawRect (0, 0, width, height); | |||
} | |||
void LookAndFeel_V1::drawMenuBarBackground (Graphics& g, int /*width*/, int /*height*/, bool, MenuBarComponent& menuBar) | |||
{ | |||
g.fillAll (menuBar.findColour (PopupMenu::backgroundColourId)); | |||
} | |||
//============================================================================== | |||
void LookAndFeel_V1::drawTextEditorOutline (Graphics& g, int width, int height, TextEditor& textEditor) | |||
{ | |||
if (textEditor.isEnabled()) | |||
{ | |||
g.setColour (textEditor.findColour (TextEditor::outlineColourId)); | |||
g.drawRect (0, 0, width, height); | |||
} | |||
} | |||
//============================================================================== | |||
void LookAndFeel_V1::drawComboBox (Graphics& g, int width, int height, | |||
const bool isButtonDown, | |||
int buttonX, int buttonY, int buttonW, int buttonH, | |||
ComboBox& box) | |||
{ | |||
g.fillAll (box.findColour (ComboBox::backgroundColourId)); | |||
g.setColour (box.findColour ((isButtonDown) ? ComboBox::buttonColourId | |||
: ComboBox::backgroundColourId)); | |||
g.fillRect (buttonX, buttonY, buttonW, buttonH); | |||
g.setColour (box.findColour (ComboBox::outlineColourId)); | |||
g.drawRect (0, 0, width, height); | |||
const float arrowX = 0.2f; | |||
const float arrowH = 0.3f; | |||
if (box.isEnabled()) | |||
{ | |||
Path p; | |||
p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.45f - arrowH), | |||
buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.45f, | |||
buttonX + buttonW * arrowX, buttonY + buttonH * 0.45f); | |||
p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.55f + arrowH), | |||
buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.55f, | |||
buttonX + buttonW * arrowX, buttonY + buttonH * 0.55f); | |||
g.setColour (box.findColour ((isButtonDown) ? ComboBox::backgroundColourId | |||
: ComboBox::buttonColourId)); | |||
g.fillPath (p); | |||
} | |||
} | |||
Font LookAndFeel_V1::getComboBoxFont (ComboBox& box) | |||
{ | |||
Font f (jmin (15.0f, box.getHeight() * 0.85f)); | |||
f.setHorizontalScale (0.9f); | |||
return f; | |||
} | |||
//============================================================================== | |||
static void drawTriangle (Graphics& g, float x1, float y1, float x2, float y2, float x3, float y3, Colour fill, Colour outline) | |||
{ | |||
Path p; | |||
p.addTriangle (x1, y1, x2, y2, x3, y3); | |||
g.setColour (fill); | |||
g.fillPath (p); | |||
g.setColour (outline); | |||
g.strokePath (p, PathStrokeType (0.3f)); | |||
} | |||
void LookAndFeel_V1::drawLinearSlider (Graphics& g, | |||
int x, int y, int w, int h, | |||
float sliderPos, float minSliderPos, float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider& slider) | |||
{ | |||
g.fillAll (slider.findColour (Slider::backgroundColourId)); | |||
if (style == Slider::LinearBar) | |||
{ | |||
g.setColour (slider.findColour (Slider::thumbColourId)); | |||
g.fillRect (x, y, (int) sliderPos - x, h); | |||
g.setColour (slider.findColour (Slider::textBoxTextColourId).withMultipliedAlpha (0.5f)); | |||
g.drawRect (x, y, (int) sliderPos - x, h); | |||
} | |||
else | |||
{ | |||
g.setColour (slider.findColour (Slider::trackColourId) | |||
.withMultipliedAlpha (slider.isEnabled() ? 1.0f : 0.3f)); | |||
if (slider.isHorizontal()) | |||
{ | |||
g.fillRect (x, y + roundToInt (h * 0.6f), | |||
w, roundToInt (h * 0.2f)); | |||
} | |||
else | |||
{ | |||
g.fillRect (x + roundToInt (w * 0.5f - jmin (3.0f, w * 0.1f)), y, | |||
jmin (4, roundToInt (w * 0.2f)), h); | |||
} | |||
float alpha = 0.35f; | |||
if (slider.isEnabled()) | |||
alpha = slider.isMouseOverOrDragging() ? 1.0f : 0.7f; | |||
const Colour fill (slider.findColour (Slider::thumbColourId).withAlpha (alpha)); | |||
const Colour outline (Colours::black.withAlpha (slider.isEnabled() ? 0.7f : 0.35f)); | |||
if (style == Slider::TwoValueVertical || style == Slider::ThreeValueVertical) | |||
{ | |||
drawTriangle (g, x + w * 0.5f + jmin (4.0f, w * 0.3f), minSliderPos, | |||
x + w * 0.5f - jmin (8.0f, w * 0.4f), minSliderPos - 7.0f, | |||
x + w * 0.5f - jmin (8.0f, w * 0.4f), minSliderPos, | |||
fill, outline); | |||
drawTriangle (g, x + w * 0.5f + jmin (4.0f, w * 0.3f), maxSliderPos, | |||
x + w * 0.5f - jmin (8.0f, w * 0.4f), maxSliderPos, | |||
x + w * 0.5f - jmin (8.0f, w * 0.4f), maxSliderPos + 7.0f, | |||
fill, outline); | |||
} | |||
else if (style == Slider::TwoValueHorizontal || style == Slider::ThreeValueHorizontal) | |||
{ | |||
drawTriangle (g, minSliderPos, y + h * 0.6f - jmin (4.0f, h * 0.3f), | |||
minSliderPos - 7.0f, y + h * 0.9f , | |||
minSliderPos, y + h * 0.9f, | |||
fill, outline); | |||
drawTriangle (g, maxSliderPos, y + h * 0.6f - jmin (4.0f, h * 0.3f), | |||
maxSliderPos, y + h * 0.9f, | |||
maxSliderPos + 7.0f, y + h * 0.9f, | |||
fill, outline); | |||
} | |||
if (style == Slider::LinearHorizontal || style == Slider::ThreeValueHorizontal) | |||
{ | |||
drawTriangle (g, sliderPos, y + h * 0.9f, | |||
sliderPos - 7.0f, y + h * 0.2f, | |||
sliderPos + 7.0f, y + h * 0.2f, | |||
fill, outline); | |||
} | |||
else if (style == Slider::LinearVertical || style == Slider::ThreeValueVertical) | |||
{ | |||
drawTriangle (g, x + w * 0.5f - jmin (4.0f, w * 0.3f), sliderPos, | |||
x + w * 0.5f + jmin (8.0f, w * 0.4f), sliderPos - 7.0f, | |||
x + w * 0.5f + jmin (8.0f, w * 0.4f), sliderPos + 7.0f, | |||
fill, outline); | |||
} | |||
} | |||
} | |||
Button* LookAndFeel_V1::createSliderButton (const bool isIncrement) | |||
{ | |||
if (isIncrement) | |||
return new ArrowButton ("u", 0.75f, Colours::white.withAlpha (0.8f)); | |||
else | |||
return new ArrowButton ("d", 0.25f, Colours::white.withAlpha (0.8f)); | |||
} | |||
ImageEffectFilter* LookAndFeel_V1::getSliderEffect() | |||
{ | |||
return &scrollbarShadow; | |||
} | |||
int LookAndFeel_V1::getSliderThumbRadius (Slider&) | |||
{ | |||
return 8; | |||
} | |||
//============================================================================== | |||
void LookAndFeel_V1::drawCornerResizer (Graphics& g, int w, int h, bool isMouseOver, bool isMouseDragging) | |||
{ | |||
g.setColour ((isMouseOver || isMouseDragging) ? Colours::lightgrey | |||
: Colours::darkgrey); | |||
const float lineThickness = jmin (w, h) * 0.1f; | |||
for (float i = 0.0f; i < 1.0f; i += 0.3f) | |||
{ | |||
g.drawLine (w * i, | |||
h + 1.0f, | |||
w + 1.0f, | |||
h * i, | |||
lineThickness); | |||
} | |||
} | |||
//============================================================================== | |||
Button* LookAndFeel_V1::createDocumentWindowButton (int buttonType) | |||
{ | |||
Path shape; | |||
if (buttonType == DocumentWindow::closeButton) | |||
{ | |||
shape.addLineSegment (Line<float> (0.0f, 0.0f, 1.0f, 1.0f), 0.35f); | |||
shape.addLineSegment (Line<float> (1.0f, 0.0f, 0.0f, 1.0f), 0.35f); | |||
ShapeButton* const b = new ShapeButton ("close", | |||
Colour (0x7fff3333), | |||
Colour (0xd7ff3333), | |||
Colour (0xf7ff3333)); | |||
b->setShape (shape, true, true, true); | |||
return b; | |||
} | |||
else if (buttonType == DocumentWindow::minimiseButton) | |||
{ | |||
shape.addLineSegment (Line<float> (0.0f, 0.5f, 1.0f, 0.5f), 0.25f); | |||
DrawableButton* b = new DrawableButton ("minimise", DrawableButton::ImageFitted); | |||
DrawablePath dp; | |||
dp.setPath (shape); | |||
dp.setFill (Colours::black.withAlpha (0.3f)); | |||
b->setImages (&dp); | |||
return b; | |||
} | |||
else if (buttonType == DocumentWindow::maximiseButton) | |||
{ | |||
shape.addLineSegment (Line<float> (0.5f, 0.0f, 0.5f, 1.0f), 0.25f); | |||
shape.addLineSegment (Line<float> (0.0f, 0.5f, 1.0f, 0.5f), 0.25f); | |||
DrawableButton* b = new DrawableButton ("maximise", DrawableButton::ImageFitted); | |||
DrawablePath dp; | |||
dp.setPath (shape); | |||
dp.setFill (Colours::black.withAlpha (0.3f)); | |||
b->setImages (&dp); | |||
return b; | |||
} | |||
jassertfalse; | |||
return nullptr; | |||
} | |||
void LookAndFeel_V1::positionDocumentWindowButtons (DocumentWindow&, | |||
int titleBarX, int titleBarY, int titleBarW, int titleBarH, | |||
Button* minimiseButton, | |||
Button* maximiseButton, | |||
Button* closeButton, | |||
bool positionTitleBarButtonsOnLeft) | |||
{ | |||
titleBarY += titleBarH / 8; | |||
titleBarH -= titleBarH / 4; | |||
const int buttonW = titleBarH; | |||
int x = positionTitleBarButtonsOnLeft ? titleBarX + 4 | |||
: titleBarX + titleBarW - buttonW - 4; | |||
if (closeButton != nullptr) | |||
{ | |||
closeButton->setBounds (x, titleBarY, buttonW, titleBarH); | |||
x += positionTitleBarButtonsOnLeft ? buttonW + buttonW / 5 | |||
: -(buttonW + buttonW / 5); | |||
} | |||
if (positionTitleBarButtonsOnLeft) | |||
std::swap (minimiseButton, maximiseButton); | |||
if (maximiseButton != nullptr) | |||
{ | |||
maximiseButton->setBounds (x, titleBarY - 2, buttonW, titleBarH); | |||
x += positionTitleBarButtonsOnLeft ? buttonW : -buttonW; | |||
} | |||
if (minimiseButton != nullptr) | |||
minimiseButton->setBounds (x, titleBarY - 2, buttonW, titleBarH); | |||
} |
@@ -0,0 +1,101 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2013 - Raw Material Software Ltd. | |||
Permission is granted to use this software under the terms of either: | |||
a) the GPL v2 (or any later version) | |||
b) the Affero GPL v3 | |||
Details of these licenses can be found 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.juce.com for more information. | |||
============================================================================== | |||
*/ | |||
#ifndef JUCE_LOOKANDFEEL_V1_H_INCLUDED | |||
#define JUCE_LOOKANDFEEL_V1_H_INCLUDED | |||
//============================================================================== | |||
/** | |||
The original JUCE look-and-feel, as used back from 2002 to about 2007ish. | |||
@see LookAndFeel, LookAndFeel_V2, LookAndFeel_V3 | |||
*/ | |||
class JUCE_API LookAndFeel_V1 : public LookAndFeel_V2 | |||
{ | |||
public: | |||
LookAndFeel_V1(); | |||
~LookAndFeel_V1(); | |||
//============================================================================== | |||
void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour, | |||
bool isMouseOverButton, bool isButtonDown) override; | |||
void drawToggleButton (Graphics&, ToggleButton&, bool isMouseOverButton, bool isButtonDown) override; | |||
void drawTickBox (Graphics&, Component&, float x, float y, float w, float h, | |||
bool ticked, bool isEnabled, bool isMouseOverButton, bool isButtonDown) override; | |||
void drawProgressBar (Graphics&, ProgressBar&, int width, int height, | |||
double progress, const String& textToShow) override; | |||
//============================================================================== | |||
void drawScrollbarButton (Graphics&, ScrollBar&, int width, int height, | |||
int buttonDirection, bool isScrollbarVertical, | |||
bool isMouseOverButton, bool isButtonDown) override; | |||
void drawScrollbar (Graphics&, ScrollBar&, int x, int y, int width, int height, | |||
bool isScrollbarVertical, int thumbStartPosition, int thumbSize, | |||
bool isMouseOver, bool isMouseDown) override; | |||
ImageEffectFilter* getScrollbarEffect() override; | |||
//============================================================================== | |||
void drawTextEditorOutline (Graphics&, int width, int height, TextEditor&) override; | |||
//============================================================================== | |||
void drawPopupMenuBackground (Graphics&, int width, int height) override; | |||
void drawMenuBarBackground (Graphics&, int width, int height, bool isMouseOverBar, MenuBarComponent&) override; | |||
//============================================================================== | |||
void drawComboBox (Graphics&, int width, int height, bool isButtonDown, | |||
int buttonX, int buttonY, int buttonW, int buttonH, ComboBox&) override; | |||
Font getComboBoxFont (ComboBox&) override; | |||
//============================================================================== | |||
void drawLinearSlider (Graphics&, int x, int y, int width, int height, | |||
float sliderPos, float minSliderPos, float maxSliderPos, | |||
const Slider::SliderStyle, Slider&) override; | |||
int getSliderThumbRadius (Slider&) override; | |||
Button* createSliderButton (bool isIncrement) override; | |||
ImageEffectFilter* getSliderEffect() override; | |||
//============================================================================== | |||
void drawCornerResizer (Graphics&, int w, int h, bool isMouseOver, bool isMouseDragging) override; | |||
Button* createDocumentWindowButton (int buttonType) override; | |||
void positionDocumentWindowButtons (DocumentWindow&, | |||
int titleBarX, int titleBarY, int titleBarW, int titleBarH, | |||
Button* minimiseButton, Button* maximiseButton, Button* closeButton, | |||
bool positionTitleBarButtonsOnLeft) override; | |||
private: | |||
DropShadowEffect scrollbarShadow; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeel_V1) | |||
}; | |||
#endif // JUCE_LOOKANDFEEL_H_INCLUDED |
@@ -0,0 +1,347 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2013 - Raw Material Software Ltd. | |||
Permission is granted to use this software under the terms of either: | |||
a) the GPL v2 (or any later version) | |||
b) the Affero GPL v3 | |||
Details of these licenses can be found 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.juce.com for more information. | |||
============================================================================== | |||
*/ | |||
#ifndef JUCE_LOOKANDFEEL_V2_H_INCLUDED | |||
#define JUCE_LOOKANDFEEL_V2_H_INCLUDED | |||
//============================================================================== | |||
/** | |||
This LookAndFeel subclass implements the juce style from around 2008-12. | |||
@see LookAndFeel, LookAndFeel_V1, LookAndFeel_V3 | |||
*/ | |||
class JUCE_API LookAndFeel_V2 : public LookAndFeel | |||
{ | |||
public: | |||
LookAndFeel_V2(); | |||
~LookAndFeel_V2(); | |||
//============================================================================== | |||
void drawButtonBackground (Graphics&, Button& button, const Colour& backgroundColour, | |||
bool isMouseOverButton, bool isButtonDown) override; | |||
Font getTextButtonFont (TextButton&) override; | |||
void drawButtonText (Graphics&, TextButton& button, | |||
bool isMouseOverButton, bool isButtonDown) override; | |||
void drawToggleButton (Graphics&, ToggleButton& button, bool isMouseOverButton, bool isButtonDown) override; | |||
void changeToggleButtonWidthToFitText (ToggleButton&) override; | |||
void drawTickBox (Graphics&, Component&, | |||
float x, float y, float w, float h, | |||
bool ticked, bool isEnabled, bool isMouseOverButton, bool isButtonDown) override; | |||
void drawDrawableButton (Graphics&, DrawableButton&, bool isMouseOverButton, bool isButtonDown) override; | |||
//============================================================================== | |||
AlertWindow* createAlertWindow (const String& title, const String& message, | |||
const String& button1, | |||
const String& button2, | |||
const String& button3, | |||
AlertWindow::AlertIconType iconType, | |||
int numButtons, Component* associatedComponent) override; | |||
void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) override; | |||
int getAlertBoxWindowFlags() override; | |||
int getAlertWindowButtonHeight() override; | |||
Font getAlertWindowMessageFont() override; | |||
Font getAlertWindowFont() override; | |||
//============================================================================== | |||
void drawProgressBar (Graphics&, ProgressBar&, int width, int height, double progress, const String& textToShow) override; | |||
void drawSpinningWaitAnimation (Graphics&, const Colour& colour, int x, int y, int w, int h) override; | |||
//============================================================================== | |||
bool areScrollbarButtonsVisible() override; | |||
void drawScrollbarButton (Graphics& g, ScrollBar&, int width, int height, int buttonDirection, | |||
bool isScrollbarVertical, bool isMouseOverButton, bool isButtonDown) override; | |||
void drawScrollbar (Graphics& g, ScrollBar&, int x, int y, int width, int height, | |||
bool isScrollbarVertical, int thumbStartPosition, int thumbSize, | |||
bool isMouseOver, bool isMouseDown) override; | |||
ImageEffectFilter* getScrollbarEffect() override; | |||
int getMinimumScrollbarThumbSize (ScrollBar&) override; | |||
int getDefaultScrollbarWidth() override; | |||
int getScrollbarButtonSize (ScrollBar& scrollbar) override; | |||
//============================================================================== | |||
Path getTickShape (float height) override; | |||
Path getCrossShape (float height) override; | |||
//============================================================================== | |||
void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area, | |||
Colour backgroundColour, bool isOpen, bool isMouseOver) override; | |||
bool areLinesDrawnForTreeView (TreeView&) override; | |||
int getTreeViewIndentSize (TreeView&) override; | |||
//============================================================================== | |||
void fillTextEditorBackground (Graphics&, int width, int height, TextEditor&) override; | |||
void drawTextEditorOutline (Graphics&, int width, int height, TextEditor&) override; | |||
CaretComponent* createCaretComponent (Component* keyFocusOwner) override; | |||
//============================================================================== | |||
const Drawable* getDefaultFolderImage() override; | |||
const Drawable* getDefaultDocumentFileImage() override; | |||
AttributedString createFileChooserHeaderText (const String& title, const String& instructions) override; | |||
void drawFileBrowserRow (Graphics&, int width, int height, | |||
const String& filename, Image* icon, | |||
const String& fileSizeDescription, const String& fileTimeDescription, | |||
bool isDirectory, bool isItemSelected, int itemIndex, | |||
DirectoryContentsDisplayComponent&) override; | |||
Button* createFileBrowserGoUpButton() override; | |||
void layoutFileBrowserComponent (FileBrowserComponent&, | |||
DirectoryContentsDisplayComponent*, | |||
FilePreviewComponent*, | |||
ComboBox* currentPathBox, | |||
TextEditor* filenameBox, | |||
Button* goUpButton) override; | |||
//============================================================================== | |||
void drawBubble (Graphics&, BubbleComponent&, const Point<float>& tip, const Rectangle<float>& body) override; | |||
void drawLasso (Graphics&, Component&) override; | |||
//============================================================================== | |||
void drawPopupMenuBackground (Graphics&, int width, int height) override; | |||
void drawPopupMenuItem (Graphics&, int width, int height, | |||
bool isSeparator, bool isActive, bool isHighlighted, bool isTicked, bool hasSubMenu, | |||
const String& text, const String& shortcutKeyText, | |||
Image* image, const Colour* textColour) override; | |||
Font getPopupMenuFont() override; | |||
void drawPopupMenuUpDownArrow (Graphics&, int width, int height, bool isScrollUpArrow) override; | |||
void getIdealPopupMenuItemSize (const String& text, bool isSeparator, int standardMenuItemHeight, | |||
int& idealWidth, int& idealHeight) override; | |||
int getMenuWindowFlags() override; | |||
void drawMenuBarBackground (Graphics&, int width, int height, bool isMouseOverBar, MenuBarComponent&) override; | |||
int getMenuBarItemWidth (MenuBarComponent&, int itemIndex, const String& itemText) override; | |||
Font getMenuBarFont (MenuBarComponent&, int itemIndex, const String& itemText) override; | |||
int getDefaultMenuBarHeight() override; | |||
void drawMenuBarItem (Graphics&, int width, int height, | |||
int itemIndex, const String& itemText, | |||
bool isMouseOverItem, bool isMenuOpen, bool isMouseOverBar, | |||
MenuBarComponent&) override; | |||
//============================================================================== | |||
void drawComboBox (Graphics&, int width, int height, bool isButtonDown, | |||
int buttonX, int buttonY, int buttonW, int buttonH, | |||
ComboBox&) override; | |||
Font getComboBoxFont (ComboBox&) override; | |||
Label* createComboBoxTextBox (ComboBox&) override; | |||
void positionComboBoxText (ComboBox&, Label&) override; | |||
//============================================================================== | |||
void drawLabel (Graphics&, Label&) override; | |||
Font getLabelFont (Label&) override; | |||
//============================================================================== | |||
void drawLinearSlider (Graphics&, int x, int y, int width, int height, | |||
float sliderPos, float minSliderPos, float maxSliderPos, | |||
const Slider::SliderStyle, Slider&) override; | |||
void drawLinearSliderBackground (Graphics&, int x, int y, int width, int height, | |||
float sliderPos, float minSliderPos, float maxSliderPos, | |||
const Slider::SliderStyle, Slider&) override; | |||
void drawLinearSliderThumb (Graphics&, int x, int y, int width, int height, | |||
float sliderPos, float minSliderPos, float maxSliderPos, | |||
const Slider::SliderStyle, Slider&) override; | |||
void drawRotarySlider (Graphics&, int x, int y, int width, int height, | |||
float sliderPosProportional, float rotaryStartAngle, float rotaryEndAngle, | |||
Slider&) override; | |||
int getSliderThumbRadius (Slider&) override; | |||
Button* createSliderButton (bool isIncrement) override; | |||
Label* createSliderTextBox (Slider&) override; | |||
ImageEffectFilter* getSliderEffect() override; | |||
Font getSliderPopupFont() override; | |||
int getSliderPopupPlacement() override; | |||
//============================================================================== | |||
void getTooltipSize (const String& tipText, int& width, int& height) override; | |||
void drawTooltip (Graphics&, const String& text, int width, int height) override; | |||
//============================================================================== | |||
Button* createFilenameComponentBrowseButton (const String& text) override; | |||
void layoutFilenameComponent (FilenameComponent& filenameComp, ComboBox* filenameBox, Button* browseButton) override; | |||
//============================================================================== | |||
void drawConcertinaPanelHeader (Graphics&, const Rectangle<int>& area, | |||
bool isMouseOver, bool isMouseDown, | |||
ConcertinaPanel&, Component& panel) override; | |||
//============================================================================== | |||
void drawCornerResizer (Graphics&, int w, int h, bool isMouseOver, bool isMouseDragging) override; | |||
void drawResizableFrame (Graphics&, int w, int h, const BorderSize<int>&) override; | |||
//============================================================================== | |||
void fillResizableWindowBackground (Graphics&, int w, int h, const BorderSize<int>&, ResizableWindow&) override; | |||
void drawResizableWindowBorder (Graphics&, int w, int h, const BorderSize<int>& border, ResizableWindow&) override; | |||
//============================================================================== | |||
void drawDocumentWindowTitleBar (DocumentWindow&, Graphics&, int w, int h, | |||
int titleSpaceX, int titleSpaceW, | |||
const Image* icon, bool drawTitleTextOnLeft) override; | |||
Button* createDocumentWindowButton (int buttonType) override; | |||
void positionDocumentWindowButtons (DocumentWindow&, | |||
int titleBarX, int titleBarY, int titleBarW, int titleBarH, | |||
Button* minimiseButton, | |||
Button* maximiseButton, | |||
Button* closeButton, | |||
bool positionTitleBarButtonsOnLeft) override; | |||
//============================================================================== | |||
DropShadower* createDropShadowerForComponent (Component*) override; | |||
//============================================================================== | |||
void drawStretchableLayoutResizerBar (Graphics&, int w, int h, bool isVerticalBar, | |||
bool isMouseOver, bool isMouseDragging) override; | |||
//============================================================================== | |||
void drawGroupComponentOutline (Graphics&, int w, int h, const String& text, | |||
const Justification&, GroupComponent&) override; | |||
//============================================================================== | |||
int getTabButtonSpaceAroundImage() override; | |||
int getTabButtonOverlap (int tabDepth) override; | |||
int getTabButtonBestWidth (TabBarButton&, int tabDepth) override; | |||
Rectangle<int> getTabButtonExtraComponentBounds (const TabBarButton&, Rectangle<int>& textArea, Component& extraComp) override; | |||
void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) override; | |||
void drawTabButtonText (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) override; | |||
void drawTabbedButtonBarBackground (TabbedButtonBar&, Graphics&) override; | |||
void drawTabAreaBehindFrontButton (TabbedButtonBar&, Graphics&, int w, int h) override; | |||
void createTabButtonShape (TabBarButton&, Path& path, bool isMouseOver, bool isMouseDown) override; | |||
void fillTabButtonShape (TabBarButton&, Graphics&, const Path& path, bool isMouseOver, bool isMouseDown) override; | |||
Button* createTabBarExtrasButton() override; | |||
//============================================================================== | |||
void drawImageButton (Graphics&, Image*, | |||
int imageX, int imageY, int imageW, int imageH, | |||
const Colour& overlayColour, float imageOpacity, ImageButton&) override; | |||
//============================================================================== | |||
void drawTableHeaderBackground (Graphics&, TableHeaderComponent&) override; | |||
void drawTableHeaderColumn (Graphics&, const String& columnName, int columnId, | |||
int width, int height, bool isMouseOver, bool isMouseDown, | |||
int columnFlags) override; | |||
//============================================================================== | |||
void paintToolbarBackground (Graphics&, int width, int height, Toolbar&) override; | |||
Button* createToolbarMissingItemsButton (Toolbar&) override; | |||
void paintToolbarButtonBackground (Graphics&, int width, int height, | |||
bool isMouseOver, bool isMouseDown, | |||
ToolbarItemComponent&) override; | |||
void paintToolbarButtonLabel (Graphics&, int x, int y, int width, int height, | |||
const String& text, ToolbarItemComponent&) override; | |||
//============================================================================== | |||
void drawPropertyPanelSectionHeader (Graphics&, const String& name, bool isOpen, int width, int height) override; | |||
void drawPropertyComponentBackground (Graphics&, int width, int height, PropertyComponent&) override; | |||
void drawPropertyComponentLabel (Graphics&, int width, int height, PropertyComponent&) override; | |||
Rectangle<int> getPropertyComponentContentPosition (PropertyComponent&) override; | |||
//============================================================================== | |||
void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path& path, Image& cachedImage) override; | |||
//============================================================================== | |||
void drawLevelMeter (Graphics&, int width, int height, float level) override; | |||
void drawKeymapChangeButton (Graphics&, int width, int height, Button& button, const String& keyDescription) override; | |||
//============================================================================== | |||
/** 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. | |||
*/ | |||
static void drawBevel (Graphics&, | |||
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); | |||
/** Utility function to draw a shiny, glassy circle (for round LED-type buttons). */ | |||
static void drawGlassSphere (Graphics&, float x, float y, float diameter, | |||
const Colour& colour, float outlineThickness) noexcept; | |||
static void drawGlassPointer (Graphics&, 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&, | |||
float x, float y, float width, float height, | |||
const Colour& colour, float outlineThickness, float cornerSize, | |||
bool flatOnLeft, bool flatOnRight, bool flatOnTop, bool flatOnBottom) noexcept; | |||
private: | |||
//============================================================================== | |||
ScopedPointer<Drawable> folderImage, documentImage; | |||
void drawShinyButtonShape (Graphics&, | |||
float x, float y, float w, float h, float maxCornerSize, | |||
const Colour& baseColour, float strokeWidth, | |||
bool flatOnLeft, bool flatOnRight, bool flatOnTop, bool flatOnBottom) noexcept; | |||
class GlassWindowButton; | |||
class SliderLabelComp; | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LookAndFeel_V2) | |||
}; | |||
#endif // JUCE_LOOKANDFEEL_H_INCLUDED |
@@ -0,0 +1,361 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2013 - Raw Material Software Ltd. | |||
Permission is granted to use this software under the terms of either: | |||
a) the GPL v2 (or any later version) | |||
b) the Affero GPL v3 | |||
Details of these licenses can be found 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.juce.com for more information. | |||
============================================================================== | |||
*/ | |||
LookAndFeel_V3::LookAndFeel_V3() | |||
{ | |||
setColour (TreeView::selectedItemBackgroundColourId, Colour (0x301111ee)); | |||
const Colour textButtonColour (0xffeeeeff); | |||
setColour (TextButton::buttonColourId, textButtonColour); | |||
setColour (ComboBox::buttonColourId, textButtonColour); | |||
setColour (ScrollBar::thumbColourId, Colour::greyLevel (0.8f).contrasting().withAlpha (0.13f)); | |||
} | |||
LookAndFeel_V3::~LookAndFeel_V3() {} | |||
bool LookAndFeel_V3::areScrollbarButtonsVisible() { return false; } | |||
void LookAndFeel_V3::drawStretchableLayoutResizerBar (Graphics& g, int /*w*/, int /*h*/, bool /*isVerticalBar*/, | |||
bool isMouseOver, bool isMouseDragging) | |||
{ | |||
if (isMouseOver || isMouseDragging) | |||
g.fillAll (Colours::yellow.withAlpha (0.4f)); | |||
} | |||
void LookAndFeel_V3::drawScrollbar (Graphics& g, ScrollBar& scrollbar, int x, int y, int width, int height, | |||
bool isScrollbarVertical, int thumbStartPosition, int thumbSize, bool isMouseOver, bool isMouseDown) | |||
{ | |||
Path thumbPath; | |||
if (thumbSize > 0) | |||
{ | |||
const float thumbIndent = (isScrollbarVertical ? width : height) * 0.25f; | |||
const float thumbIndentx2 = thumbIndent * 2.0f; | |||
if (isScrollbarVertical) | |||
thumbPath.addRoundedRectangle (x + thumbIndent, thumbStartPosition + thumbIndent, | |||
width - thumbIndentx2, thumbSize - thumbIndentx2, (width - thumbIndentx2) * 0.5f); | |||
else | |||
thumbPath.addRoundedRectangle (thumbStartPosition + thumbIndent, y + thumbIndent, | |||
thumbSize - thumbIndentx2, height - thumbIndentx2, (height - thumbIndentx2) * 0.5f); | |||
} | |||
Colour thumbCol (scrollbar.findColour (ScrollBar::thumbColourId, true)); | |||
if (isMouseOver || isMouseDown) | |||
thumbCol = thumbCol.withMultipliedAlpha (2.0f); | |||
g.setColour (thumbCol); | |||
g.fillPath (thumbPath); | |||
g.setColour (thumbCol.contrasting ((isMouseOver || isMouseDown) ? 0.2f : 0.1f)); | |||
g.strokePath (thumbPath, PathStrokeType (1.0f)); | |||
} | |||
void LookAndFeel_V3::drawConcertinaPanelHeader (Graphics& g, const Rectangle<int>& area, | |||
bool isMouseOver, bool /*isMouseDown*/, | |||
ConcertinaPanel&, Component& panel) | |||
{ | |||
const Colour bkg (Colours::grey); | |||
g.setGradientFill (ColourGradient (Colours::white.withAlpha (isMouseOver ? 0.4f : 0.2f), 0, (float) area.getY(), | |||
Colours::darkgrey.withAlpha (0.2f), 0, (float) area.getBottom(), false)); | |||
g.fillAll(); | |||
g.setColour (bkg.contrasting().withAlpha (0.04f)); | |||
g.fillRect (area.withHeight (1)); | |||
g.fillRect (area.withTop (area.getBottom() - 1)); | |||
g.setColour (bkg.contrasting()); | |||
g.setFont (Font (area.getHeight() * 0.6f).boldened()); | |||
g.drawFittedText (panel.getName(), 4, 0, area.getWidth() - 6, area.getHeight(), Justification::centredLeft, 1); | |||
} | |||
static void drawButtonShape (Graphics& g, const Path& outline, Colour baseColour, float height) | |||
{ | |||
const float mainBrightness = baseColour.getBrightness(); | |||
const float mainAlpha = baseColour.getFloatAlpha(); | |||
g.setGradientFill (ColourGradient (baseColour.brighter (0.2f), 0.0f, 0.0f, | |||
baseColour.darker (0.25f), 0.0f, height, false)); | |||
g.fillPath (outline); | |||
g.setColour (Colours::white.withAlpha (0.4f * mainAlpha * mainBrightness * mainBrightness)); | |||
g.strokePath (outline, PathStrokeType (1.0f), AffineTransform::translation (0.0f, 1.0f) | |||
.scaled (1.0f, (height - 1.6f) / height)); | |||
g.setColour (Colours::black.withAlpha (0.4f * mainAlpha)); | |||
g.strokePath (outline, PathStrokeType (1.0f)); | |||
} | |||
void LookAndFeel_V3::drawButtonBackground (Graphics& g, Button& button, const Colour& backgroundColour, | |||
bool isMouseOverButton, bool isButtonDown) | |||
{ | |||
Colour baseColour (backgroundColour.withMultipliedSaturation (button.hasKeyboardFocus (true) ? 1.3f : 0.9f) | |||
.withMultipliedAlpha (button.isEnabled() ? 0.9f : 0.5f)); | |||
if (isButtonDown || isMouseOverButton) | |||
baseColour = baseColour.contrasting (isButtonDown ? 0.2f : 0.1f); | |||
const bool flatOnLeft = button.isConnectedOnLeft(); | |||
const bool flatOnRight = button.isConnectedOnRight(); | |||
const bool flatOnTop = button.isConnectedOnTop(); | |||
const bool flatOnBottom = button.isConnectedOnBottom(); | |||
const float width = button.getWidth() - 1.0f; | |||
const float height = button.getHeight() - 1.0f; | |||
const float cornerSize = 4.0f; | |||
Path outline; | |||
outline.addRoundedRectangle (0.5f, 0.5f, width, height, cornerSize, cornerSize, | |||
! (flatOnLeft || flatOnTop), | |||
! (flatOnRight || flatOnTop), | |||
! (flatOnLeft || flatOnBottom), | |||
! (flatOnRight || flatOnBottom)); | |||
drawButtonShape (g, outline, baseColour, height); | |||
} | |||
void LookAndFeel_V3::drawTableHeaderBackground (Graphics& g, TableHeaderComponent& header) | |||
{ | |||
Rectangle<int> r (header.getLocalBounds()); | |||
g.setColour (Colours::black.withAlpha (0.5f)); | |||
g.fillRect (r.removeFromBottom (1)); | |||
g.setColour (Colours::white.withAlpha (0.6f)); | |||
g.fillRect (r); | |||
g.setColour (Colours::black.withAlpha (0.5f)); | |||
for (int i = header.getNumColumns (true); --i >= 0;) | |||
g.fillRect (header.getColumnPosition (i).removeFromRight (1)); | |||
} | |||
int LookAndFeel_V3::getTabButtonOverlap (int /*tabDepth*/) { return -1; } | |||
int LookAndFeel_V3::getTabButtonSpaceAroundImage() { return 1; } | |||
void LookAndFeel_V3::createTabTextLayout (const TabBarButton& button, float length, float depth, | |||
Colour colour, TextLayout& textLayout) | |||
{ | |||
Font font (depth * 0.5f); | |||
font.setUnderline (button.hasKeyboardFocus (false)); | |||
AttributedString s; | |||
s.setJustification (Justification::centred); | |||
s.append (button.getButtonText().trim(), font, colour); | |||
textLayout.createLayout (s, length); | |||
} | |||
void LookAndFeel_V3::drawTabButton (TabBarButton& button, Graphics& g, bool isMouseOver, bool isMouseDown) | |||
{ | |||
const Rectangle<int> activeArea (button.getActiveArea()); | |||
const TabbedButtonBar::Orientation o = button.getTabbedButtonBar().getOrientation(); | |||
const Colour bkg (button.getTabBackgroundColour()); | |||
if (button.getToggleState()) | |||
{ | |||
g.setColour (bkg); | |||
g.fillRect (activeArea); | |||
} | |||
else | |||
{ | |||
Point<int> p1, p2; | |||
switch (o) | |||
{ | |||
case TabbedButtonBar::TabsAtBottom: p1 = activeArea.getBottomLeft(); p2 = activeArea.getTopLeft(); break; | |||
case TabbedButtonBar::TabsAtTop: p1 = activeArea.getTopLeft(); p2 = activeArea.getBottomLeft(); break; | |||
case TabbedButtonBar::TabsAtRight: p1 = activeArea.getTopRight(); p2 = activeArea.getTopLeft(); break; | |||
case TabbedButtonBar::TabsAtLeft: p1 = activeArea.getTopLeft(); p2 = activeArea.getTopRight(); break; | |||
default: jassertfalse; break; | |||
} | |||
g.setGradientFill (ColourGradient (bkg.brighter (0.2f), (float) p1.x, (float) p1.y, | |||
bkg.darker (0.1f), (float) p2.x, (float) p2.y, false)); | |||
g.fillRect (activeArea); | |||
} | |||
g.setColour (bkg.contrasting (0.3f)); | |||
Rectangle<int> r (activeArea); | |||
if (o != TabbedButtonBar::TabsAtBottom) g.fillRect (r.removeFromTop (1)); | |||
if (o != TabbedButtonBar::TabsAtTop) g.fillRect (r.removeFromBottom (1)); | |||
if (o != TabbedButtonBar::TabsAtRight) g.fillRect (r.removeFromLeft (1)); | |||
if (o != TabbedButtonBar::TabsAtLeft) g.fillRect (r.removeFromRight (1)); | |||
const float alpha = button.isEnabled() ? ((isMouseOver || isMouseDown) ? 1.0f : 0.8f) : 0.3f; | |||
const Colour col (bkg.contrasting().withMultipliedAlpha (alpha)); | |||
const Rectangle<float> area (button.getTextArea().toFloat()); | |||
float length = area.getWidth(); | |||
float depth = area.getHeight(); | |||
if (button.getTabbedButtonBar().isVertical()) | |||
std::swap (length, depth); | |||
TextLayout textLayout; | |||
createTabTextLayout (button, length, depth, col, textLayout); | |||
AffineTransform t; | |||
switch (o) | |||
{ | |||
case TabbedButtonBar::TabsAtLeft: t = t.rotated (float_Pi * -0.5f).translated (area.getX(), area.getBottom()); break; | |||
case TabbedButtonBar::TabsAtRight: t = t.rotated (float_Pi * 0.5f).translated (area.getRight(), area.getY()); break; | |||
case TabbedButtonBar::TabsAtTop: | |||
case TabbedButtonBar::TabsAtBottom: t = t.translated (area.getX(), area.getY()); break; | |||
default: jassertfalse; break; | |||
} | |||
g.addTransform (t); | |||
textLayout.draw (g, Rectangle<float> (length, depth)); | |||
} | |||
void LookAndFeel_V3::drawTreeviewPlusMinusBox (Graphics& g, const Rectangle<float>& area, | |||
Colour backgroundColour, bool isOpen, bool isMouseOver) | |||
{ | |||
Path p; | |||
p.addTriangle (0.0f, 0.0f, 1.0f, isOpen ? 0.0f : 0.5f, isOpen ? 0.5f : 0.0f, 1.0f); | |||
g.setColour (backgroundColour.contrasting().withAlpha (isMouseOver ? 0.5f : 0.3f)); | |||
g.fillPath (p, p.getTransformToScaleToFit (area.reduced (2, area.getHeight() / 4), true)); | |||
} | |||
bool LookAndFeel_V3::areLinesDrawnForTreeView (TreeView&) | |||
{ | |||
return false; | |||
} | |||
int LookAndFeel_V3::getTreeViewIndentSize (TreeView&) | |||
{ | |||
return 20; | |||
} | |||
void LookAndFeel_V3::drawComboBox (Graphics& g, int width, int height, const bool isButtonDown, | |||
int buttonX, int buttonY, int buttonW, int buttonH, ComboBox& box) | |||
{ | |||
g.fillAll (box.findColour (ComboBox::backgroundColourId)); | |||
const Colour buttonColour (box.findColour (ComboBox::buttonColourId)); | |||
if (box.isEnabled() && box.hasKeyboardFocus (false)) | |||
{ | |||
g.setColour (buttonColour); | |||
g.drawRect (0, 0, width, height, 2); | |||
} | |||
else | |||
{ | |||
g.setColour (box.findColour (ComboBox::outlineColourId)); | |||
g.drawRect (0, 0, width, height); | |||
} | |||
const float outlineThickness = box.isEnabled() ? (isButtonDown ? 1.2f : 0.5f) : 0.3f; | |||
Path buttonShape; | |||
buttonShape.addRectangle (buttonX + outlineThickness, | |||
buttonY + outlineThickness, | |||
buttonW - outlineThickness * 2.0f, | |||
buttonH - outlineThickness * 2.0f); | |||
drawButtonShape (g, buttonShape, | |||
buttonColour.withMultipliedSaturation (box.hasKeyboardFocus (true) ? 1.3f : 0.9f) | |||
.withMultipliedAlpha (box.isEnabled() ? 0.9f : 0.5f), | |||
(float) height); | |||
if (box.isEnabled()) | |||
{ | |||
const float arrowX = 0.3f; | |||
const float arrowH = 0.2f; | |||
Path p; | |||
p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.45f - arrowH), | |||
buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.45f, | |||
buttonX + buttonW * arrowX, buttonY + buttonH * 0.45f); | |||
p.addTriangle (buttonX + buttonW * 0.5f, buttonY + buttonH * (0.55f + arrowH), | |||
buttonX + buttonW * (1.0f - arrowX), buttonY + buttonH * 0.55f, | |||
buttonX + buttonW * arrowX, buttonY + buttonH * 0.55f); | |||
g.setColour (box.findColour (ComboBox::arrowColourId)); | |||
g.fillPath (p); | |||
} | |||
} | |||
void LookAndFeel_V3::drawPopupMenuBackground (Graphics& g, int width, int height) | |||
{ | |||
g.fillAll (findColour (PopupMenu::backgroundColourId)); | |||
(void) width; (void) height; | |||
#if ! JUCE_MAC | |||
g.setColour (findColour (PopupMenu::textColourId).withAlpha (0.6f)); | |||
g.drawRect (0, 0, width, height); | |||
#endif | |||
} | |||
void LookAndFeel_V3::drawKeymapChangeButton (Graphics& g, int width, int height, | |||
Button& button, const String& keyDescription) | |||
{ | |||
const Colour textColour (button.findColour (0x100ad01 /*KeyMappingEditorComponent::textColourId*/, true)); | |||
if (keyDescription.isNotEmpty()) | |||
{ | |||
if (button.isEnabled()) | |||
{ | |||
g.setColour (textColour.withAlpha (button.isDown() ? 0.4f : (button.isOver() ? 0.2f : 0.1f))); | |||
g.fillRoundedRectangle (button.getLocalBounds().toFloat(), 4.0f); | |||
g.drawRoundedRectangle (button.getLocalBounds().toFloat(), 4.0f, 1.0f); | |||
} | |||
g.setColour (textColour); | |||
g.setFont (height * 0.6f); | |||
g.drawFittedText (keyDescription, 4, 0, width - 8, height, Justification::centred, 1); | |||
} | |||
else | |||
{ | |||
const float thickness = 7.0f; | |||
const float indent = 22.0f; | |||
Path p; | |||
p.addEllipse (0.0f, 0.0f, 100.0f, 100.0f); | |||
p.addRectangle (indent, 50.0f - thickness, 100.0f - indent * 2.0f, thickness * 2.0f); | |||
p.addRectangle (50.0f - thickness, indent, thickness * 2.0f, 50.0f - indent - thickness); | |||
p.addRectangle (50.0f - thickness, 50.0f + thickness, thickness * 2.0f, 50.0f - indent - thickness); | |||
p.setUsingNonZeroWinding (false); | |||
g.setColour (textColour.darker(0.1f).withAlpha (button.isDown() ? 0.7f : (button.isOver() ? 0.5f : 0.3f))); | |||
g.fillPath (p, p.getTransformToScaleToFit (2.0f, 2.0f, width - 4.0f, height - 4.0f, true)); | |||
} | |||
if (button.hasKeyboardFocus (false)) | |||
{ | |||
g.setColour (textColour.withAlpha (0.4f)); | |||
g.drawRect (0, 0, width, height); | |||
} | |||
} |
@@ -0,0 +1,79 @@ | |||
/* | |||
============================================================================== | |||
This file is part of the JUCE library. | |||
Copyright (c) 2013 - Raw Material Software Ltd. | |||
Permission is granted to use this software under the terms of either: | |||
a) the GPL v2 (or any later version) | |||
b) the Affero GPL v3 | |||
Details of these licenses can be found 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.juce.com for more information. | |||
============================================================================== | |||
*/ | |||
#ifndef JUCE_LOOKANDFEEL_V3_H_INCLUDED | |||
#define JUCE_LOOKANDFEEL_V3_H_INCLUDED | |||
//============================================================================== | |||
/** | |||
The latest JUCE look-and-feel style, as introduced in 2013. | |||
@see LookAndFeel, LookAndFeel_V1, LookAndFeel_V2 | |||
*/ | |||
class JUCE_API LookAndFeel_V3 : public LookAndFeel_V2 | |||
{ | |||
public: | |||
LookAndFeel_V3(); | |||
~LookAndFeel_V3(); | |||
//============================================================================== | |||
void drawButtonBackground (Graphics&, Button&, const Colour& backgroundColour, | |||
bool isMouseOverButton, bool isButtonDown) override; | |||
void drawTableHeaderBackground (Graphics&, TableHeaderComponent&) override; | |||
void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area, | |||
Colour backgroundColour, bool isOpen, bool isMouseOver) override; | |||
bool areLinesDrawnForTreeView (TreeView&) override; | |||
int getTreeViewIndentSize (TreeView&) override; | |||
void drawComboBox (Graphics& g, int width, int height, bool isButtonDown, | |||
int buttonX, int buttonY, int buttonW, int buttonH, ComboBox& box) override; | |||
void drawKeymapChangeButton (Graphics& g, int width, int height, Button& button, const String& keyDescription) override; | |||
void drawPopupMenuBackground (Graphics& g, int width, int height) override; | |||
int getTabButtonOverlap (int tabDepth) override; | |||
int getTabButtonSpaceAroundImage() override; | |||
void drawTabButton (TabBarButton&, Graphics&, bool isMouseOver, bool isMouseDown) override; | |||
void drawStretchableLayoutResizerBar (Graphics&, int w, int h, bool isVerticalBar, bool isMouseOver, bool isMouseDragging) override; | |||
bool areScrollbarButtonsVisible() override; | |||
void drawScrollbar (Graphics&, ScrollBar&, int x, int y, int width, int height, bool isScrollbarVertical, | |||
int thumbStartPosition, int thumbSize, bool isMouseOver, bool isMouseDown) override; | |||
void drawConcertinaPanelHeader (Graphics&, const Rectangle<int>& area, bool isMouseOver, bool isMouseDown, | |||
ConcertinaPanel&, Component&) override; | |||
static void createTabTextLayout (const TabBarButton& button, float length, float depth, Colour colour, TextLayout&); | |||
private: | |||
Image backgroundTexture; | |||
Colour backgroundTextureBaseColour; | |||
}; | |||
#endif // JUCE_LOOKANDFEEL_H_INCLUDED |
@@ -480,6 +480,62 @@ public: | |||
void addCustomItem (int itemResultID, CustomComponent* customComponent, | |||
const PopupMenu* optionalSubMenu = nullptr); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
menu drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
/** Fills the background of a popup menu component. */ | |||
virtual void drawPopupMenuBackground (Graphics&, int width, int height) = 0; | |||
/** Draws one of the items in a popup menu. */ | |||
virtual void drawPopupMenuItem (Graphics&, int width, int height, | |||
bool isSeparator, bool isActive, bool isHighlighted, | |||
bool isTicked, bool hasSubMenu, | |||
const String& text, | |||
const String& shortcutKeyText, | |||
Image* icon, | |||
const Colour* textColour) = 0; | |||
/** Returns the size and style of font to use in popup menus. */ | |||
virtual Font getPopupMenuFont() = 0; | |||
virtual void drawPopupMenuUpDownArrow (Graphics&, | |||
int width, int height, | |||
bool isScrollUpArrow) = 0; | |||
/** 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) = 0; | |||
virtual int getMenuWindowFlags() = 0; | |||
virtual void drawMenuBarBackground (Graphics&, int width, int height, | |||
bool isMouseOverBar, | |||
MenuBarComponent&) = 0; | |||
virtual int getDefaultMenuBarHeight() = 0; | |||
virtual int getMenuBarItemWidth (MenuBarComponent&, int itemIndex, const String& itemText) = 0; | |||
virtual Font getMenuBarFont (MenuBarComponent&, int itemIndex, const String& itemText) = 0; | |||
virtual void drawMenuBarItem (Graphics&, int width, int height, | |||
int itemIndex, | |||
const String& itemText, | |||
bool isMouseOverItem, | |||
bool isMenuOpen, | |||
bool isMouseOverBar, | |||
MenuBarComponent&) = 0; | |||
}; | |||
private: | |||
//============================================================================== | |||
JUCE_PUBLIC_IN_DLL_BUILD (class Item) | |||
@@ -136,6 +136,19 @@ public: | |||
outlineColourId = 0x1000af1 /**< The colour to use for an outline around the bubble. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawBubble (Graphics&, BubbleComponent&, | |||
const Point<float>& positionOfTip, | |||
const Rectangle<float>& body) = 0; | |||
}; | |||
protected: | |||
//============================================================================== | |||
/** Subclasses should override this to return the size of the content they | |||
@@ -315,26 +315,39 @@ public: | |||
} | |||
//============================================================================== | |||
void handleMouseDownCallback (int index, float x, float y, int64 time) | |||
void handleMouseDownCallback (int index, Point<float> pos, int64 time) | |||
{ | |||
lastMousePos.setXY ((int) x, (int) y); | |||
currentModifiers = currentModifiers.withoutMouseButtons(); | |||
handleMouseEvent (index, lastMousePos, currentModifiers, time); | |||
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
handleMouseEvent (index, lastMousePos, currentModifiers, time); | |||
lastMousePos = pos; | |||
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
handleMouseEvent (index, pos.toInt(), currentModifiers.withoutMouseButtons(), time); | |||
if (isValidPeer (this)) | |||
handleMouseDragCallback (index, pos, time); | |||
} | |||
void handleMouseDragCallback (int index, float x, float y, int64 time) | |||
void handleMouseDragCallback (int index, Point<float> pos, int64 time) | |||
{ | |||
lastMousePos.setXY ((int) x, (int) y); | |||
handleMouseEvent (index, lastMousePos, currentModifiers, time); | |||
lastMousePos = pos; | |||
jassert (index < 64); | |||
touchesDown = (touchesDown | (1 << (index & 63))); | |||
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
handleMouseEvent (index, pos.toInt(), currentModifiers.withoutMouseButtons() | |||
.withFlags (ModifierKeys::leftButtonModifier), time); | |||
} | |||
void handleMouseUpCallback (int index, float x, float y, int64 time) | |||
void handleMouseUpCallback (int index, Point<float> pos, int64 time) | |||
{ | |||
lastMousePos.setXY ((int) x, (int) y); | |||
currentModifiers = currentModifiers.withoutMouseButtons(); | |||
handleMouseEvent (index, lastMousePos, currentModifiers, time); | |||
lastMousePos = pos; | |||
jassert (index < 64); | |||
touchesDown = (touchesDown & ~(1 << (index & 63))); | |||
if (touchesDown == 0) | |||
currentModifiers = currentModifiers.withoutMouseButtons(); | |||
handleMouseEvent (index, pos.toInt(), currentModifiers.withoutMouseButtons(), time); | |||
} | |||
void handleKeyDownCallback (int k, int kc) | |||
@@ -461,7 +474,8 @@ public: | |||
//============================================================================== | |||
static ModifierKeys currentModifiers; | |||
static Point<int> lastMousePos; | |||
static Point<float> lastMousePos; | |||
static int64 touchesDown; | |||
private: | |||
//============================================================================== | |||
@@ -526,7 +540,8 @@ private: | |||
}; | |||
ModifierKeys AndroidComponentPeer::currentModifiers = 0; | |||
Point<int> AndroidComponentPeer::lastMousePos; | |||
Point<float> AndroidComponentPeer::lastMousePos; | |||
int64 AndroidComponentPeer::touchesDown = 0; | |||
//============================================================================== | |||
#define JUCE_VIEW_CALLBACK(returnType, javaMethodName, params, juceMethodInvocation) \ | |||
@@ -537,9 +552,9 @@ Point<int> AndroidComponentPeer::lastMousePos; | |||
} | |||
JUCE_VIEW_CALLBACK (void, handlePaint, (JNIEnv* env, jobject view, jlong host, jobject canvas), handlePaintCallback (env, canvas)) | |||
JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv* env, jobject view, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseDownCallback (i, (float) x, (float) y, (int64) time)) | |||
JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv* env, jobject view, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseDragCallback (i, (float) x, (float) y, (int64) time)) | |||
JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv* env, jobject view, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseUpCallback (i, (float) x, (float) y, (int64) time)) | |||
JUCE_VIEW_CALLBACK (void, handleMouseDown, (JNIEnv* env, jobject view, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseDownCallback (i, Point<float> ((float) x, (float) y), (int64) time)) | |||
JUCE_VIEW_CALLBACK (void, handleMouseDrag, (JNIEnv* env, jobject view, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseDragCallback (i, Point<float> ((float) x, (float) y), (int64) time)) | |||
JUCE_VIEW_CALLBACK (void, handleMouseUp, (JNIEnv* env, jobject view, jlong host, jint i, jfloat x, jfloat y, jlong time), handleMouseUpCallback (i, Point<float> ((float) x, (float) y), (int64) time)) | |||
JUCE_VIEW_CALLBACK (void, viewSizeChanged, (JNIEnv* env, jobject view, jlong host), handleMovedOrResized()) | |||
JUCE_VIEW_CALLBACK (void, focusChanged, (JNIEnv* env, jobject view, jlong host, jboolean hasFocus), handleFocusChangeCallback (hasFocus)) | |||
JUCE_VIEW_CALLBACK (void, handleKeyDown, (JNIEnv* env, jobject view, jlong host, jint k, jint kc), handleKeyDownCallback ((int) k, (int) kc)) | |||
@@ -582,7 +597,7 @@ bool MouseInputSource::SourceList::addSource() | |||
Point<int> MouseInputSource::getCurrentRawMousePosition() | |||
{ | |||
return AndroidComponentPeer::lastMousePos; | |||
return AndroidComponentPeer::lastMousePos.toInt(); | |||
} | |||
void MouseInputSource::setRawMousePosition (Point<int>) | |||
@@ -499,6 +499,7 @@ UIViewComponentPeer::UIViewComponentPeer (Component& comp, const int windowStyle | |||
r.origin.y = [UIScreen mainScreen].bounds.size.height - (r.origin.y + r.size.height); | |||
window = [[JuceUIWindow alloc] init]; | |||
window.hidden = true; | |||
window.autoresizesSubviews = NO; | |||
window.transform = CGAffineTransformIdentity; | |||
window.frame = r; | |||
@@ -62,7 +62,6 @@ namespace MouseCursorHelpers | |||
return CustomMouseCursorInfo (im, (int) (hx * im.getWidth()), | |||
(int) (hy * im.getHeight())).create(); | |||
jassertfalse; | |||
return nullptr; | |||
} | |||
} | |||
@@ -95,7 +94,16 @@ void* MouseCursor::createStandardMouseCursor (MouseCursor::StandardCursorType ty | |||
case LeftEdgeResizeCursor: c = [NSCursor resizeLeftCursor]; break; | |||
case RightEdgeResizeCursor: c = [NSCursor resizeRightCursor]; break; | |||
case CrosshairCursor: c = [NSCursor crosshairCursor]; break; | |||
case CopyingCursor: return MouseCursorHelpers::fromWebKitFile ("copyCursor.png", 0, 0); | |||
case CopyingCursor: | |||
{ | |||
#if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 | |||
if (void* m = MouseCursorHelpers::fromWebKitFile ("copyCursor.png", 0, 0)) | |||
return m; | |||
#endif | |||
c = [NSCursor dragCopyCursor]; // added in 10.6 | |||
break; | |||
} | |||
case UpDownResizeCursor: | |||
case TopEdgeResizeCursor: | |||
@@ -1686,7 +1686,7 @@ struct JuceNSWindowClass : public ObjCClass <NSWindow> | |||
addMethod (@selector (canBecomeKeyWindow), canBecomeKeyWindow, "c@:"); | |||
addMethod (@selector (becomeKeyWindow), becomeKeyWindow, "v@:"); | |||
addMethod (@selector (windowShouldClose:), windowShouldClose, "c@:@"); | |||
addMethod (@selector (constrainFrameRect:toScreen:), constrainFrameRect, @encode (NSRect), "@:", @encode (NSRect*), "@"); | |||
addMethod (@selector (constrainFrameRect:toScreen:), constrainFrameRect, @encode (NSRect), "@:", @encode (NSRect), "@"); | |||
addMethod (@selector (windowWillResize:toSize:), windowWillResize, @encode (NSSize), "@:@", @encode (NSSize)); | |||
addMethod (@selector (zoom:), zoom, "v@:@"); | |||
addMethod (@selector (windowWillMove:), windowWillMove, "v@:@"); | |||
@@ -1807,13 +1807,10 @@ private: | |||
{ | |||
const DWORD flags = inputInfo[i].dwFlags; | |||
if ((flags & TOUCHEVENTF_PRIMARY) == 0 // primary events are handled by WM_LBUTTON etc | |||
&& (flags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE | TOUCHEVENTF_UP)) != 0) | |||
{ | |||
if (! handleTouchInput (inputInfo[i], (flags & TOUCHEVENTF_DOWN) != 0, | |||
(flags & TOUCHEVENTF_UP) != 0)) | |||
if ((flags & (TOUCHEVENTF_DOWN | TOUCHEVENTF_MOVE | TOUCHEVENTF_UP)) != 0) | |||
if (! handleTouchInput (inputInfo[i], (flags & TOUCHEVENTF_PRIMARY) != 0, | |||
(flags & TOUCHEVENTF_DOWN) != 0, (flags & TOUCHEVENTF_UP) != 0)) | |||
return 0; // abandon method if this window was deleted by the callback | |||
} | |||
} | |||
} | |||
@@ -1821,7 +1818,7 @@ private: | |||
return 0; | |||
} | |||
bool handleTouchInput (const TOUCHINPUT& touch, const bool isDown, const bool isUp) | |||
bool handleTouchInput (const TOUCHINPUT& touch, const bool isPrimary, const bool isDown, const bool isUp) | |||
{ | |||
bool isCancel = false; | |||
const int touchIndex = currentTouches.getIndexOfTouch (touch.dwID); | |||
@@ -1835,10 +1832,13 @@ private: | |||
currentModifiers = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
modsToSend = currentModifiers; | |||
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
handleMouseEvent (touchIndex + 1, pos, modsToSend.withoutMouseButtons(), time); | |||
if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
return false; | |||
if (! isPrimary) | |||
{ | |||
// this forces a mouse-enter/up event, in case for some reason we didn't get a mouse-up before. | |||
handleMouseEvent (touchIndex, pos, modsToSend.withoutMouseButtons(), time); | |||
if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
return false; | |||
} | |||
} | |||
else if (isUp) | |||
{ | |||
@@ -1848,6 +1848,10 @@ private: | |||
if (! currentTouches.areAnyTouchesActive()) | |||
isCancel = true; | |||
} | |||
else | |||
{ | |||
modsToSend = currentModifiers.withoutMouseButtons().withFlags (ModifierKeys::leftButtonModifier); | |||
} | |||
if (isCancel) | |||
{ | |||
@@ -1855,13 +1859,16 @@ private: | |||
currentModifiers = currentModifiers.withoutMouseButtons(); | |||
} | |||
handleMouseEvent (touchIndex + 1, pos, modsToSend, time); | |||
if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
return false; | |||
if (! isPrimary) | |||
{ | |||
handleMouseEvent (touchIndex, pos, modsToSend, time); | |||
if (! isValidPeer (this)) // (in case this component was deleted by the event) | |||
return false; | |||
} | |||
if (isUp || isCancel) | |||
if ((isUp || isCancel) && ! isPrimary) | |||
{ | |||
handleMouseEvent (touchIndex + 1, Point<int> (-10, -10), currentModifiers, time); | |||
handleMouseEvent (touchIndex, Point<int> (-10, -10), currentModifiers, time); | |||
if (! isValidPeer (this)) | |||
return false; | |||
} | |||
@@ -102,6 +102,18 @@ public: | |||
/** By default, this just repaints the component. */ | |||
void enablementChanged() override; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawPropertyPanelSectionHeader (Graphics&, const String& name, bool isOpen, int width, int height) = 0; | |||
virtual void drawPropertyComponentBackground (Graphics&, int width, int height, PropertyComponent&) = 0; | |||
virtual void drawPropertyComponentLabel (Graphics&, int width, int height, PropertyComponent&) = 0; | |||
virtual Rectangle<int> getPropertyComponentContentPosition (PropertyComponent&) = 0; | |||
}; | |||
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 | |||
@@ -333,6 +333,25 @@ public: | |||
arrowColourId = 0x1000e00, /**< The colour for the arrow shape that pops up the menu */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
ComboBox functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawComboBox (Graphics&, int width, int height, bool isButtonDown, | |||
int buttonX, int buttonY, int buttonW, int buttonH, | |||
ComboBox&) = 0; | |||
virtual Font getComboBoxFont (ComboBox&) = 0; | |||
virtual Label* createComboBoxTextBox (ComboBox&) = 0; | |||
virtual void positionComboBoxText (ComboBox&, Label& labelToPosition) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void labelTextChanged (Label*) override; | |||
@@ -249,6 +249,18 @@ public: | |||
/** Returns the currently-visible text editor, or nullptr if none is open. */ | |||
TextEditor* getCurrentTextEditor() const noexcept; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
label drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawLabel (Graphics&, Label&) = 0; | |||
virtual Font getLabelFont (Label&) = 0; | |||
}; | |||
protected: | |||
//============================================================================== | |||
/** Creates the TextEditor component that will be used when the user has clicked on the label. | |||
@@ -90,6 +90,24 @@ public: | |||
classes will probably use variations on this colour. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
/** 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&, ProgressBar&, int width, int height, | |||
double progress, const String& textToShow) = 0; | |||
}; | |||
protected: | |||
//============================================================================== | |||
/** @internal */ | |||
@@ -762,6 +762,57 @@ public: | |||
textBoxOutlineColourId = 0x1001700 /**< The colour to use for a border around the text-editor box. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
slider drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
//============================================================================== | |||
virtual void drawLinearSlider (Graphics&, | |||
int x, int y, int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle, | |||
Slider&) = 0; | |||
virtual void drawLinearSliderBackground (Graphics&, | |||
int x, int y, int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle style, | |||
Slider&) = 0; | |||
virtual void drawLinearSliderThumb (Graphics&, | |||
int x, int y, int width, int height, | |||
float sliderPos, | |||
float minSliderPos, | |||
float maxSliderPos, | |||
const Slider::SliderStyle, | |||
Slider&) = 0; | |||
virtual int getSliderThumbRadius (Slider&) = 0; | |||
virtual void drawRotarySlider (Graphics&, | |||
int x, int y, int width, int height, | |||
float sliderPosProportional, | |||
float rotaryStartAngle, | |||
float rotaryEndAngle, | |||
Slider&) = 0; | |||
virtual Button* createSliderButton (bool isIncrement) = 0; | |||
virtual Label* createSliderTextBox (Slider&) = 0; | |||
virtual ImageEffectFilter* getSliderEffect() = 0; | |||
virtual Font getSliderPopupFont() = 0; | |||
virtual int getSliderPopupPlacement() = 0; | |||
}; | |||
protected: | |||
//============================================================================== | |||
/** @internal */ | |||
@@ -366,6 +366,19 @@ public: | |||
*/ | |||
virtual void reactToMenuItem (int menuReturnId, int columnIdClicked); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawTableHeaderBackground (Graphics&, TableHeaderComponent&) = 0; | |||
virtual void drawTableHeaderColumn (Graphics&, const String& columnName, int columnId, | |||
int width, int height, | |||
bool isMouseOver, bool isMouseDown, int columnFlags) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void paint (Graphics&) override; | |||
@@ -580,6 +580,20 @@ public: | |||
void setInputRestrictions (int maxTextLength, | |||
const String& allowedCharacters = String::empty); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
TextEditor drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void fillTextEditorBackground (Graphics&, int width, int height, TextEditor&) = 0; | |||
virtual void drawTextEditorOutline (Graphics&, int width, int height, TextEditor&) = 0; | |||
virtual CaretComponent* createCaretComponent (Component* keyFocusOwner) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void paint (Graphics&) override; | |||
@@ -267,6 +267,24 @@ public: | |||
bool restoreFromString (ToolbarItemFactory& factoryToUse, | |||
const String& savedVersion); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void paintToolbarBackground (Graphics&, int width, int height, Toolbar&) = 0; | |||
virtual Button* createToolbarMissingItemsButton (Toolbar&) = 0; | |||
virtual void paintToolbarButtonBackground (Graphics&, int width, int height, | |||
bool isMouseOver, bool isMouseDown, | |||
ToolbarItemComponent&) = 0; | |||
virtual void paintToolbarButtonLabel (Graphics&, int x, int y, int width, int height, | |||
const String& text, ToolbarItemComponent&) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void paint (Graphics&) override; | |||
@@ -439,7 +439,7 @@ TreeView::TreeView (const String& name) | |||
: Component (name), | |||
viewport (new TreeViewport()), | |||
rootItem (nullptr), | |||
indentSize (24), | |||
indentSize (-1), | |||
defaultOpenness (false), | |||
needsRecalculating (true), | |||
rootItemVisible (true), | |||
@@ -522,6 +522,12 @@ void TreeView::setIndentSize (const int newIndentSize) | |||
} | |||
} | |||
int TreeView::getIndentSize() noexcept | |||
{ | |||
return indentSize >= 0 ? indentSize | |||
: getLookAndFeel().getTreeViewIndentSize (*this); | |||
} | |||
void TreeView::setDefaultOpenness (const bool isOpenByDefault) | |||
{ | |||
if (defaultOpenness != isOpenByDefault) | |||
@@ -860,7 +866,7 @@ void TreeView::recalculateIfNeeded() | |||
//============================================================================== | |||
struct TreeView::InsertPoint | |||
{ | |||
InsertPoint (const TreeView& view, const StringArray& files, | |||
InsertPoint (TreeView& view, const StringArray& files, | |||
const DragAndDropTarget::SourceDetails& dragSourceDetails) | |||
: pos (dragSourceDetails.localPosition), | |||
item (view.getItemAt (dragSourceDetails.localPosition.y)), | |||
@@ -1125,7 +1131,8 @@ TreeViewItem::TreeViewItem() | |||
totalWidth (0), | |||
selected (false), | |||
redrawNeeded (true), | |||
drawLinesInside (true), | |||
drawLinesInside (false), | |||
drawLinesSet (false), | |||
drawsInLeftMargin (false), | |||
openness (opennessDefault) | |||
{ | |||
@@ -1317,10 +1324,10 @@ void TreeViewItem::paintItem (Graphics&, int, int) | |||
{ | |||
} | |||
void TreeViewItem::paintOpenCloseButton (Graphics& g, int width, int height, bool isMouseOver) | |||
void TreeViewItem::paintOpenCloseButton (Graphics& g, const Rectangle<float>& area, Colour backgroundColour, bool isMouseOver) | |||
{ | |||
ownerView->getLookAndFeel() | |||
.drawTreeviewPlusMinusBox (g, 0, 0, width, height, ! isOpen(), isMouseOver); | |||
getOwnerView()->getLookAndFeel() | |||
.drawTreeviewPlusMinusBox (g, area, backgroundColour, isOpen(), isMouseOver); | |||
} | |||
void TreeViewItem::paintHorizontalConnectingLine (Graphics& g, const Line<float>& line) | |||
@@ -1495,6 +1502,12 @@ namespace TreeViewHelpers | |||
} | |||
} | |||
bool TreeViewItem::areLinesDrawn() const | |||
{ | |||
return drawLinesSet ? drawLinesInside | |||
: (ownerView != nullptr && ownerView->getLookAndFeel().areLinesDrawnForTreeView (*ownerView)); | |||
} | |||
void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
{ | |||
jassert (ownerView != nullptr); | |||
@@ -1510,7 +1523,12 @@ void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
if (g.reduceClipRegion (drawsInLeftMargin ? -indent : 0, 0, | |||
drawsInLeftMargin ? itemW + indent : itemW, itemHeight)) | |||
{ | |||
if (isSelected()) | |||
g.fillAll (ownerView->findColour (TreeView::selectedItemBackgroundColourId)); | |||
paintItem (g, itemW, itemHeight); | |||
} | |||
} | |||
const float halfH = itemHeight * 0.5f; | |||
@@ -1521,11 +1539,12 @@ void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
{ | |||
float x = (depth + 0.5f) * indentWidth; | |||
if (parentItem != nullptr && parentItem->drawLinesInside) | |||
const bool parentLinesDrawn = parentItem != nullptr && parentItem->areLinesDrawn(); | |||
if (parentLinesDrawn) | |||
paintVerticalConnectingLine (g, Line<float> (x, 0, x, isLastOfSiblings() ? halfH : (float) itemHeight)); | |||
if ((parentItem != nullptr && parentItem->drawLinesInside) | |||
|| (parentItem == nullptr && drawLinesInside)) | |||
if (parentLinesDrawn || (parentItem == nullptr && areLinesDrawn())) | |||
paintHorizontalConnectingLine (g, Line<float> (x, halfH, x + indentWidth / 2, halfH)); | |||
{ | |||
@@ -1536,8 +1555,7 @@ void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
{ | |||
x -= (float) indentWidth; | |||
if ((p->parentItem == nullptr || p->parentItem->drawLinesInside) | |||
&& ! p->isLastOfSiblings()) | |||
if ((p->parentItem == nullptr || p->parentItem->areLinesDrawn()) && ! p->isLastOfSiblings()) | |||
p->paintVerticalConnectingLine (g, Line<float> (x, 0, x, (float) itemHeight)); | |||
p = p->parentItem; | |||
@@ -1545,15 +1563,9 @@ void TreeViewItem::paintRecursively (Graphics& g, int width) | |||
} | |||
if (mightContainSubItems()) | |||
{ | |||
Graphics::ScopedSaveState ss (g); | |||
g.setOrigin (depth * indentWidth, 0); | |||
g.reduceClipRegion (0, 0, indentWidth, itemHeight); | |||
paintOpenCloseButton (g, indentWidth, itemHeight, | |||
paintOpenCloseButton (g, Rectangle<float> ((float) (depth * indentWidth), 0, (float) indentWidth, (float) itemHeight), | |||
Colours::white, | |||
ownerView->viewport->getContentComp()->isMouseOverButton (this)); | |||
} | |||
} | |||
if (isOpen()) | |||
@@ -1731,6 +1743,7 @@ int TreeViewItem::getRowNumberInTree() const noexcept | |||
void TreeViewItem::setLinesDrawnForSubItems (const bool drawLines) noexcept | |||
{ | |||
drawLinesInside = drawLines; | |||
drawLinesSet = true; | |||
} | |||
TreeViewItem* TreeViewItem::getNextVisibleItem (const bool recurse) const noexcept | |||
@@ -1840,8 +1853,8 @@ XmlElement* TreeViewItem::getOpennessState (const bool canReturnNull) const | |||
e = new XmlElement ("OPEN"); | |||
for (int i = 0; i < subItems.size(); ++i) | |||
e->addChildElement (subItems.getUnchecked(i)->getOpennessState (true)); | |||
for (int i = subItems.size(); --i >= 0;) | |||
e->prependChildElement (subItems.getUnchecked(i)->getOpennessState (true)); | |||
} | |||
else | |||
{ | |||
@@ -83,6 +83,20 @@ public: | |||
*/ | |||
void addSubItem (TreeViewItem* newItem, int insertPosition = -1); | |||
/** Adds a sub-item with a sort-comparator, assuming that the existing items are already sorted. | |||
@param comparator the comparator object for sorting - see sortSubItems() for details about | |||
the methods this class must provide. | |||
@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. | |||
*/ | |||
template <class ElementComparator> | |||
void addSubItemSorted (ElementComparator& comparator, TreeViewItem* newItem) | |||
{ | |||
addSubItem (newItem, findInsertIndexInSortedArray (comparator, subItems.begin(), newItem, 0, subItems.size())); | |||
} | |||
/** Removes one of the sub-items. | |||
@param index the item to remove | |||
@@ -178,7 +192,7 @@ public: | |||
bool areAllParentsOpen() const noexcept; | |||
/** Changes whether lines are drawn to connect any sub-items to this item. | |||
By default, line-drawing is turned on. | |||
By default, line-drawing is turned on according to LookAndFeel::areLinesDrawnForTreeView(). | |||
*/ | |||
void setLinesDrawnForSubItems (bool shouldDrawLines) noexcept; | |||
@@ -299,11 +313,14 @@ public: | |||
/** 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. | |||
If you don't implement this method, the default behaviour is to call | |||
LookAndFeel::drawTreeviewPlusMinusBox(), but you can override it for custom | |||
effects. You may want to override it and call the base-class implementation | |||
with a different backgroundColour parameter, if your implementation has a | |||
background colour other than the default (white). | |||
*/ | |||
virtual void paintOpenCloseButton (Graphics&, int width, int height, bool isMouseOver); | |||
virtual void paintOpenCloseButton (Graphics&, const Rectangle<float>& area, | |||
Colour backgroundColour, bool isMouseOver); | |||
/** Draws the line that connects this item to the vertical line extending below its parent. */ | |||
virtual void paintHorizontalConnectingLine (Graphics&, const Line<float>& line); | |||
@@ -519,12 +536,13 @@ private: | |||
//============================================================================== | |||
TreeView* ownerView; | |||
TreeViewItem* parentItem; | |||
OwnedArray <TreeViewItem> subItems; | |||
OwnedArray<TreeViewItem> subItems; | |||
int y, itemHeight, totalHeight, itemWidth, totalWidth; | |||
int uid; | |||
bool selected : 1; | |||
bool redrawNeeded : 1; | |||
bool drawLinesInside : 1; | |||
bool drawLinesSet : 1; | |||
bool drawsInLeftMargin : 1; | |||
unsigned int openness : 2; | |||
@@ -549,6 +567,7 @@ private: | |||
XmlElement* getOpennessState (bool canReturnNull) const; | |||
bool removeSubItemFromList (int index, bool deleteItem); | |||
void removeAllSubItemsFromList(); | |||
bool areLinesDrawn() const; | |||
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE | |||
// The parameters for these methods have changed - please update your code! | |||
@@ -721,7 +740,7 @@ public: | |||
/** Returns the number of pixels by which each nested level of the tree is indented. | |||
@see setIndentSize | |||
*/ | |||
int getIndentSize() const noexcept { return indentSize; } | |||
int getIndentSize() noexcept; | |||
/** Changes the distance by which each nested level of the tree is indented. | |||
@see getIndentSize | |||
@@ -779,9 +798,25 @@ public: | |||
*/ | |||
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. */ | |||
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. */ | |||
selectedItemBackgroundColourId = 0x1000503 /**< The colour to use to fill the background of any selected items. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
treeview drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawTreeviewPlusMinusBox (Graphics&, const Rectangle<float>& area, | |||
Colour backgroundColour, bool isItemOpen, bool isMouseOver) = 0; | |||
virtual bool areLinesDrawnForTreeView (TreeView&) = 0; | |||
virtual int getTreeViewIndentSize (TreeView&) = 0; | |||
}; | |||
//============================================================================== | |||
@@ -849,6 +884,11 @@ private: | |||
void moveIntoSelectedItem(); | |||
void moveByPages (int numPages); | |||
#if JUCE_CATCH_DEPRECATED_CODE_MISUSE | |||
// this method has been deprecated - see the new version.. | |||
virtual int paintOpenCloseButton (Graphics&, int, int, bool) { return 0; } | |||
#endif | |||
JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (TreeView) | |||
}; | |||
@@ -417,6 +417,32 @@ public: | |||
outlineColourId = 0x1001820 /**< An optional colour to use to draw a border around the window. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
alert-window drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
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) = 0; | |||
virtual void drawAlertBox (Graphics&, AlertWindow&, const Rectangle<int>& textArea, TextLayout&) = 0; | |||
virtual int getAlertBoxWindowFlags() = 0; | |||
virtual int getAlertWindowButtonHeight() = 0; | |||
virtual Font getAlertWindowMessageFont() = 0; | |||
virtual Font getAlertWindowFont() = 0; | |||
}; | |||
protected: | |||
//============================================================================== | |||
/** @internal */ | |||
@@ -48,8 +48,11 @@ CallOutBox::~CallOutBox() | |||
{ | |||
} | |||
enum { callOutBoxDismissCommandId = 0x4f83a04b }; | |||
//============================================================================== | |||
class CallOutBoxCallback : public ModalComponentManager::Callback | |||
class CallOutBoxCallback : public ModalComponentManager::Callback, | |||
private Timer | |||
{ | |||
public: | |||
CallOutBoxCallback (Component* c, const Rectangle<int>& area, Component* parent) | |||
@@ -57,9 +60,16 @@ public: | |||
{ | |||
callout.setVisible (true); | |||
callout.enterModalState (true, this); | |||
startTimer (200); | |||
} | |||
void modalStateFinished (int) {} | |||
void modalStateFinished (int) override {} | |||
void timerCallback() override | |||
{ | |||
if (! Process::isForegroundProcess()) | |||
callout.postCommandMessage (callOutBoxDismissCommandId); | |||
} | |||
ScopedPointer<Component> content; | |||
CallOutBox callout; | |||
@@ -110,8 +120,6 @@ bool CallOutBox::hitTest (int x, int y) | |||
return outline.contains ((float) x, (float) y); | |||
} | |||
enum { callOutBoxDismissCommandId = 0x4f83a04b }; | |||
void CallOutBox::inputAttemptWhenModal() | |||
{ | |||
const Point<int> mousePos (getMouseXYRelative() + getBounds().getPosition()); | |||
@@ -118,6 +118,15 @@ public: | |||
const Rectangle<int>& areaToPointTo, | |||
Component* parentComponent); | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes. */ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawCallOutBoxBackground (CallOutBox&, Graphics&, const Path&, Image& cachedImage) = 0; | |||
}; | |||
//============================================================================== | |||
/** @internal */ | |||
void paint (Graphics&) override; | |||
@@ -298,15 +298,11 @@ void ComponentPeer::handleMovedOrResized() | |||
Rectangle<int> newBounds (Component::ComponentHelpers::rawPeerPositionToLocal (component, getBounds())); | |||
Rectangle<int> oldBounds (component.getBounds()); | |||
// oldBounds = Component::ComponentHelpers::localPositionToRawPeerPos (component, oldBounds); | |||
const bool wasMoved = (oldBounds.getPosition() != newBounds.getPosition()); | |||
const bool wasResized = (oldBounds.getWidth() != newBounds.getWidth() || oldBounds.getHeight() != newBounds.getHeight()); | |||
if (wasMoved || wasResized) | |||
{ | |||
// newBounds = Component::ComponentHelpers::rawPeerPositionToLocal (component, newBounds); | |||
component.bounds = newBounds; | |||
if (wasResized) | |||
@@ -223,6 +223,30 @@ public: | |||
and feel class how this is used. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
window drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void drawDocumentWindowTitleBar (DocumentWindow&, | |||
Graphics&, int w, int h, | |||
int titleSpaceX, int titleSpaceW, | |||
const Image* icon, | |||
bool drawTitleTextOnLeft) = 0; | |||
virtual Button* createDocumentWindowButton (int buttonType) = 0; | |||
virtual void positionDocumentWindowButtons (DocumentWindow&, | |||
int titleBarX, int titleBarY, int titleBarW, int titleBarH, | |||
Button* minimiseButton, | |||
Button* maximiseButton, | |||
Button* closeButton, | |||
bool positionTitleBarButtonsOnLeft) = 0; | |||
}; | |||
//============================================================================== | |||
#ifndef DOXYGEN | |||
/** @internal */ | |||
@@ -306,8 +306,23 @@ public: | |||
bool resizeToFit = false)); | |||
using TopLevelWindow::addToDesktop; | |||
protected: | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
window drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
//============================================================================== | |||
virtual void drawCornerResizer (Graphics&, int w, int h, bool isMouseOver, bool isMouseDragging) = 0; | |||
virtual void drawResizableFrame (Graphics&, int w, int h, const BorderSize<int>&) = 0; | |||
virtual void fillResizableWindowBackground (Graphics&, int w, int h, const BorderSize<int>&, ResizableWindow&) = 0; | |||
virtual void drawResizableWindowBorder (Graphics&, int w, int h, const BorderSize<int>& border, ResizableWindow&) = 0; | |||
}; | |||
protected: | |||
/** @internal */ | |||
void paint (Graphics&) override; | |||
/** (if overriding this, make sure you call ResizableWindow::moved() in your subclass) */ | |||
@@ -96,6 +96,17 @@ public: | |||
outlineColourId = 0x1001c10 /**< The colour to use to draw an outline around the tooltip. */ | |||
}; | |||
//============================================================================== | |||
/** This abstract base class is implemented by LookAndFeel classes to provide | |||
window drawing functionality. | |||
*/ | |||
struct JUCE_API LookAndFeelMethods | |||
{ | |||
virtual ~LookAndFeelMethods() {} | |||
virtual void getTooltipSize (const String& tipText, int& width, int& height) = 0; | |||
virtual void drawTooltip (Graphics&, const String& text, int width, int height) = 0; | |||
}; | |||
private: | |||
//============================================================================== | |||