diff --git a/juce_amalgamated.cpp b/juce_amalgamated.cpp index 6eae8ddf54..75529f25b1 100644 --- a/juce_amalgamated.cpp +++ b/juce_amalgamated.cpp @@ -2103,7 +2103,7 @@ void BitArray::parseString (const String& text, const MemoryBlock BitArray::toMemoryBlock() const throw() { - const int numBytes = (getHighestBit() + 7) >> 3; + const int numBytes = (getHighestBit() + 8) >> 3; MemoryBlock mb (numBytes); for (int i = 0; i < numBytes; ++i) @@ -5526,14 +5526,8 @@ const String File::getRelativePathFrom (const File& dir) const throw() --commonBitLength; // if the only common bit is the root, then just return the full path.. -#if JUCE_WIN32 - if (commonBitLength <= 0 - || (commonBitLength == 1 && thisPath [1] == File::separator) - || (commonBitLength <= 3 && thisPath [1] == T(':'))) -#else if (commonBitLength <= 0 || (commonBitLength == 1 && thisPath [1] == File::separator)) -#endif return fullPath; thisPath = thisPath.substring (commonBitLength); @@ -10814,15 +10808,11 @@ const String String::toHexString (const unsigned char* data, *d++ = hexDigits [(*data) & 0xf]; ++data; - if (groupSize > 0 && (i % groupSize) == 0) + if (groupSize > 0 && (i % groupSize) == (groupSize - 1) && i < (size - 1)) *d++ = T(' '); } - if (groupSize > 0) - --d; - *d = 0; - return s; } @@ -10908,26 +10898,7 @@ const String String::createStringFromData (const void* const data_, } else { -#if JUCE_STRINGS_ARE_UNICODE && JUCE_LINUX - // (workaround for strange behaviour of mbstowcs) - int i; - for (i = 0; i < size; ++i) - if (data[i] == 0) - break; - - String result; - result.preallocateStorage (i + 1); - tchar* const dst = const_cast ((const tchar*) result); - - for (int j = 0; j < i; ++j) - dst[j] = (juce_wchar) (unsigned char) data[j]; - - dst[i] = 0; - - return result; -#else - return String (data, size); -#endif + return String::fromUTF8 ((const uint8*) data, size); } } @@ -23956,7 +23927,6 @@ int MidiMessage::getMessageLengthFromFirstByte (const uint8 firstByte) throw() { // this method only works for valid starting bytes of a short midi message jassert (firstByte >= 0x80 - && firstByte != 0xff && firstByte != 0xf0 && firstByte != 0xf7); @@ -25092,7 +25062,7 @@ void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, { // if our list of events is longer than the buffer we're being // asked for, scale them down to squeeze them all in.. - const int maxBlockLengthToUse = numSamples << 3; + const int maxBlockLengthToUse = numSamples << 5; if (numSourceSamples > maxBlockLengthToUse) { @@ -25131,7 +25101,7 @@ void MidiMessageCollector::removeNextBlockOfMessages (MidiBuffer& destBuffer, void MidiMessageCollector::handleNoteOn (MidiKeyboardState*, int midiChannel, int midiNoteNumber, float velocity) { MidiMessage m (MidiMessage::noteOn (midiChannel, midiNoteNumber, velocity)); - m.setTimeStamp (Time::getMillisecondCounter() * 0.001); + m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001); addMessageToQueue (m); } @@ -25139,7 +25109,7 @@ void MidiMessageCollector::handleNoteOn (MidiKeyboardState*, int midiChannel, in void MidiMessageCollector::handleNoteOff (MidiKeyboardState*, int midiChannel, int midiNoteNumber) { MidiMessage m (MidiMessage::noteOff (midiChannel, midiNoteNumber)); - m.setTimeStamp (Time::getMillisecondCounter() * 0.001); + m.setTimeStamp (Time::getMillisecondCounterHiRes() * 0.001); addMessageToQueue (m); } @@ -41240,6 +41210,8 @@ Label::Label (const String& componentName, listeners (2), ownerComponent (0), deletionWatcher (0), + horizontalBorderSize (3), + verticalBorderSize (1), editSingleClick (false), editDoubleClick (false), lossOfFocusDiscardsChanges (false) @@ -41315,6 +41287,13 @@ void Label::setJustificationType (const Justification& justification_) throw() repaint(); } +void Label::setBorderSize (int h, int v) +{ + horizontalBorderSize = h; + verticalBorderSize = v; + repaint(); +} + void Label::attachToComponent (Component* owner, const bool onLeft) { @@ -41477,7 +41456,10 @@ void Label::paint (Graphics& g) g.setColour (findColour (textColourId).withMultipliedAlpha (alpha)); g.setFont (font); g.drawFittedText (text, - 3, 1, getWidth() - 6, getHeight() - 2, + horizontalBorderSize, + verticalBorderSize, + getWidth() - 2 * horizontalBorderSize, + getHeight() - 2 * verticalBorderSize, justification, jmax (1, (int) (getHeight() / font.getHeight()))); @@ -43916,7 +43898,9 @@ void Slider::mouseDoubleClick (const MouseEvent&) void Slider::mouseWheelMove (const MouseEvent& e, float wheelIncrementX, float wheelIncrementY) { - if (scrollWheelEnabled && isEnabled()) + if (scrollWheelEnabled && isEnabled() + && style != TwoValueHorizontal + && style != TwoValueVertical) { if (maximum > minimum && ! isMouseButtonDownAnywhere()) { @@ -46723,6 +46707,58 @@ int TextEditor::getCaretPosition() const throw() return caretPosition; } +void TextEditor::scrollEditorToPositionCaret (const int desiredCaretX, + const int desiredCaretY) throw() + +{ + updateCaretPosition(); + + int vx = roundFloatToInt (cursorX) - desiredCaretX; + int vy = roundFloatToInt (cursorY) - desiredCaretY; + + if (desiredCaretX < jmax (1, proportionOfWidth (0.05f))) + { + vx += desiredCaretX - proportionOfWidth (0.2f); + } + else if (desiredCaretX > jmax (0, viewport->getMaximumVisibleWidth() - (wordWrap ? 2 : 10))) + { + vx += desiredCaretX + (isMultiLine() ? proportionOfWidth (0.2f) : 10) - viewport->getMaximumVisibleWidth(); + } + + vx = jlimit (0, jmax (0, textHolder->getWidth() + 8 - viewport->getMaximumVisibleWidth()), vx); + + if (! isMultiLine()) + { + vy = viewport->getViewPositionY(); + } + else + { + vy = jlimit (0, jmax (0, textHolder->getHeight() - viewport->getMaximumVisibleHeight()), vy); + + const int curH = roundFloatToInt (cursorHeight); + + if (desiredCaretY < 0) + { + vy = jmax (0, desiredCaretY + vy); + } + else if (desiredCaretY > jmax (0, viewport->getMaximumVisibleHeight() - topIndent - curH)) + { + vy += desiredCaretY + 2 + curH + topIndent - viewport->getMaximumVisibleHeight(); + } + } + + viewport->setViewPosition (vx, vy); +} + +const Rectangle TextEditor::getCaretRectangle() throw() +{ + updateCaretPosition(); + + return Rectangle (roundFloatToInt (cursorX) - viewport->getX(), + roundFloatToInt (cursorY) - viewport->getY(), + 1, roundFloatToInt (cursorHeight)); +} + float TextEditor::getWordWrapWidth() const throw() { return (wordWrap) ? (float) (viewport->getMaximumVisibleWidth() - leftIndent - leftIndent / 2) @@ -46783,13 +46819,15 @@ void TextEditor::setScrollToShowCursor (const bool shouldScrollToShowCursor) thr keepCursorOnScreen = shouldScrollToShowCursor; } -void TextEditor::scrollToMakeSureCursorIsVisible() throw() +void TextEditor::updateCaretPosition() throw() { cursorHeight = currentFont.getHeight(); // (in case the text is empty and the call below doesn't set this value) + getCharPosition (caretPosition, cursorX, cursorY, cursorHeight); +} - getCharPosition (caretPosition, - cursorX, cursorY, - cursorHeight); +void TextEditor::scrollToMakeSureCursorIsVisible() throw() +{ + updateCaretPosition(); if (keepCursorOnScreen) { @@ -46912,7 +46950,7 @@ void TextEditor::insertTextAtCursor (String newText) remove (selectionStart, selectionEnd, &undoManager, - newCaretPos); + newCaretPos - 1); if (maxTextLength > 0) newText = newText.substring (0, maxTextLength - getTotalNumChars()); @@ -47458,11 +47496,7 @@ void TextEditor::resized() } else { - cursorHeight = currentFont.getHeight(); // (in case the text is empty and the call below doesn't set this value) - - getCharPosition (caretPosition, - cursorX, cursorY, - cursorHeight); + updateCaretPosition(); } } @@ -64535,6 +64569,27 @@ void PropertyPanel::setSectionOpen (const int sectionIndex, const bool shouldBeO } } +void PropertyPanel::setSectionEnabled (const int sectionIndex, const bool shouldBeEnabled) +{ + int index = 0; + + for (int i = 0; i < propertyHolderComponent->getNumChildComponents(); ++i) + { + PropertySectionComponent* const section = dynamic_cast (propertyHolderComponent->getChildComponent (i)); + + if (section != 0 && section->getName().isNotEmpty()) + { + if (index == sectionIndex) + { + section->setEnabled (shouldBeEnabled); + break; + } + + ++index; + } + } +} + XmlElement* PropertyPanel::getOpennessState() const { XmlElement* const xml = new XmlElement (T("PROPERTYPANELSTATE")); @@ -77117,7 +77172,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillAlphaChannelWithColour (int cl const uint8* const alphaValues = clipImage.lockPixelDataReadOnly (sx, sy, w, h, alphaStride, pixelStride); -#if JUCE_MAC +#if JUCE_BIG_ENDIAN const uint8* const alphas = alphaValues; #else const uint8* const alphas = alphaValues + (clipImage.getFormat() == Image::ARGB ? 3 : 0); @@ -77218,7 +77273,7 @@ void LowLevelGraphicsSoftwareRenderer::clippedFillAlphaChannelWithImage (int x, const uint8* const alpha = alphaImage.lockPixelDataReadOnly (x - alphaImageX, y - alphaImageY, w, h, maskStride, maskPixStride); -#if JUCE_MAC +#if JUCE_BIG_ENDIAN const uint8* const alphaValues = alpha; #else const uint8* const alphaValues = alpha + (alphaImage.getFormat() == Image::ARGB ? 3 : 0); @@ -180039,7 +180094,26 @@ public: int64 startSampleInFile, int numSamples) { - int writeOffset = 0; + int startOffsetInDestBuffer = 0; + + if (startSampleInFile < 0) + { + const int silence = (int) jmin (-startSampleInFile, (int64) numSamples); + + int** destChan = destSamples; + + for (int i = 2; --i >= 0;) + { + if (*destChan != 0) + { + zeromem (*destChan, sizeof (int) * silence); + ++destChan; + } + } + + startOffsetInDestBuffer += silence; + numSamples -= silence; + } while (numSamples > 0) { @@ -180056,7 +180130,7 @@ public: if (destSamples[i] == 0) break; - memcpy (destSamples[i] + writeOffset, + memcpy (destSamples[i] + startOffsetInDestBuffer, reservoir.getSampleData (jmin (i, reservoir.getNumChannels()), (int) (startSampleInFile - reservoirStart)), sizeof (float) * numToUse); @@ -180064,7 +180138,7 @@ public: startSampleInFile += numToUse; numSamples -= numToUse; - writeOffset += numToUse; + startOffsetInDestBuffer += numToUse; if (numSamples == 0) break; @@ -203846,6 +203920,8 @@ Image* juce_loadJPEGImageFromStream (InputStream& in) throw() } catch (...) {} + + in.setPosition (((char*) jpegDecompStruct.src->next_input_byte) - (char*) mb.getData()); } return image; @@ -203929,7 +204005,7 @@ bool juce_writeJPEGImageToStream (const Image& image, // jpegCompStruct.smoothing_factor = 10; if (quality < 0.0f) - quality = 6.0f; + quality = 0.85f; jpeg_set_quality (&jpegCompStruct, jlimit (0, 100, roundFloatToInt (quality * 100.0f)), TRUE); @@ -232743,7 +232819,7 @@ public: AudioIODeviceCallback* const oldCallback = currentCallback; close(); - open (currentChansIn, currentChansOut, + open (BitArray (currentChansIn), BitArray (currentChansOut), currentSampleRate, currentBlockSizeSamples); if (oldCallback != 0) @@ -243469,7 +243545,8 @@ public: static bool doesWindowMatch (const ActiveXControlComponent* const ax, HWND hwnd) { - return ((ActiveXControlData*) ax->control)->controlHWND == hwnd; + return ((ActiveXControlData*) ax->control) != 0 + && ((ActiveXControlData*) ax->control)->controlHWND == hwnd; } }; @@ -256036,7 +256113,7 @@ END_JUCE_NAMESPACE - (JuceFileChooserDelegate*) initWithFilters: (JUCE_NAMESPACE::StringArray*) filters_; - (void) dealloc; -- (BOOL) panel:(id) sender shouldShowFilename: (NSString*) filename; +- (BOOL) panel: (id) sender shouldShowFilename: (NSString*) filename; @end @@ -256056,17 +256133,18 @@ END_JUCE_NAMESPACE - (BOOL) panel:(id) sender shouldShowFilename: (NSString*) filename { - const char* filenameUTF8 = (const char*) [filename UTF8String]; + const JUCE_NAMESPACE::String fname (nsStringToJuce (filename)); for (int i = filters->size(); --i >= 0;) { - const JUCE_NAMESPACE::String wildcard ((*filters)[i].toLowerCase()); + const JUCE_NAMESPACE::String wildcard ((*filters)[i]); - if (fnmatch (wildcard.toUTF8(), filenameUTF8, 0) == 0) + if (fnmatch (wildcard.toLowerCase().toUTF8(), + fname.toLowerCase().toUTF8(), 0) == 0) return true; } - return JUCE_NAMESPACE::File (nsStringToJuce (filename)).isDirectory(); + return JUCE_NAMESPACE::File (fname).isDirectory(); } @end @@ -256138,6 +256216,8 @@ void FileChooser::showPlatformDialog (OwnedArray& results, } } } + + [panel setDelegate: nil]; } END_JUCE_NAMESPACE diff --git a/juce_amalgamated.h b/juce_amalgamated.h index 7b4c547d8a..91be5ad365 100644 --- a/juce_amalgamated.h +++ b/juce_amalgamated.h @@ -586,6 +586,7 @@ #include #include #include +#include #if JUCE_MAC || JUCE_LINUX #include @@ -30527,6 +30528,12 @@ public: */ void setSectionOpen (const int sectionIndex, const bool shouldBeOpen); + /** Enables or disables one of the sections. + + The index is from 0 up to the number of items returned by getSectionNames(). + */ + void setSectionEnabled (const int sectionIndex, const bool shouldBeEnabled); + /** Saves the current state of open/closed sections so it can be restored later. The caller is responsible for deleting the object that is returned. @@ -32671,6 +32678,27 @@ l */ */ int getCaretPosition() const throw(); + /** Attempts to scroll the text editor so that the caret ends up at + a specified position. + + This won't affect the caret's position within the text, it tries to scroll + the entire editor vertically and horizontally so that the caret is sitting + at the given position (relative to the top-left of this component). + + Depending on the amount of text available, it might not be possible to + scroll far enough for the caret to reach this exact position, but it + will go as far as it can in that direction. + */ + void scrollEditorToPositionCaret (const int desiredCaretX, + const int desiredCaretY) throw(); + + /** Get the graphical position of the caret. + + The rectangle returned is relative to the component's top-left corner. + @see scrollEditorToPositionCaret + */ + const Rectangle getCaretRectangle() throw(); + /** Selects a section of the text. */ void setHighlightedRegion (int startIndex, @@ -32914,6 +32942,8 @@ private: float& x, float& y, float& lineHeight) const throw(); + void updateCaretPosition() throw(); + int indexAtPosition (const float x, const float y) throw(); @@ -33041,6 +33071,12 @@ public: /** Returns the type of justification, as set in setJustificationType(). */ const Justification getJustificationType() const throw() { return justification; } + /** Changes the gap that is left between the edge of the component and the text. + By default there's a small gap left at the sides of the component to allow for + the drawing of the border, but you can change this if necessary. + */ + void setBorderSize (int horizontalBorder, int verticalBorder); + /** Makes this label "stick to" another component. This will cause the label to follow another component around, staying @@ -33184,7 +33220,7 @@ private: SortedSet listeners; Component* ownerComponent; ComponentDeletionWatcher* deletionWatcher; - + int horizontalBorderSize, verticalBorderSize; bool editSingleClick : 1; bool editDoubleClick : 1; bool lossOfFocusDiscardsChanges : 1; @@ -43195,7 +43231,6 @@ private: void hideCurrentMenu(); void timerCallback(); void repaintMenuItem (int index); - void showMenuInternal (const int menuIndex); MenuBarComponent (const MenuBarComponent&); const MenuBarComponent& operator= (const MenuBarComponent&);