migrating to the latest JUCE version
This commit is contained in:
		@@ -1,74 +1,74 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
CPlusPlusCodeTokeniser::CPlusPlusCodeTokeniser() {}
 | 
			
		||||
CPlusPlusCodeTokeniser::~CPlusPlusCodeTokeniser() {}
 | 
			
		||||
 | 
			
		||||
int CPlusPlusCodeTokeniser::readNextToken (CodeDocument::Iterator& source)
 | 
			
		||||
{
 | 
			
		||||
    return CppTokeniserFunctions::readNextToken (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CodeEditorComponent::ColourScheme CPlusPlusCodeTokeniser::getDefaultColourScheme()
 | 
			
		||||
{
 | 
			
		||||
    struct Type
 | 
			
		||||
    {
 | 
			
		||||
        const char* name;
 | 
			
		||||
        uint32 colour;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const Type types[] =
 | 
			
		||||
    {
 | 
			
		||||
        { "Error",              0xffcc0000 },
 | 
			
		||||
        { "Comment",            0xff00aa00 },
 | 
			
		||||
        { "Keyword",            0xff0000cc },
 | 
			
		||||
        { "Operator",           0xff225500 },
 | 
			
		||||
        { "Identifier",         0xff000000 },
 | 
			
		||||
        { "Integer",            0xff880000 },
 | 
			
		||||
        { "Float",              0xff885500 },
 | 
			
		||||
        { "String",             0xff990099 },
 | 
			
		||||
        { "Bracket",            0xff000055 },
 | 
			
		||||
        { "Punctuation",        0xff004400 },
 | 
			
		||||
        { "Preprocessor Text",  0xff660000 }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CodeEditorComponent::ColourScheme cs;
 | 
			
		||||
 | 
			
		||||
    for (auto& t : types)
 | 
			
		||||
        cs.set (t.name, Colour (t.colour));
 | 
			
		||||
 | 
			
		||||
    return cs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CPlusPlusCodeTokeniser::isReservedKeyword (const String& token) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return CppTokeniserFunctions::isReservedKeyword (token.getCharPointer(), token.length());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
CPlusPlusCodeTokeniser::CPlusPlusCodeTokeniser() {}
 | 
			
		||||
CPlusPlusCodeTokeniser::~CPlusPlusCodeTokeniser() {}
 | 
			
		||||
 | 
			
		||||
int CPlusPlusCodeTokeniser::readNextToken (CodeDocument::Iterator& source)
 | 
			
		||||
{
 | 
			
		||||
    return CppTokeniserFunctions::readNextToken (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CodeEditorComponent::ColourScheme CPlusPlusCodeTokeniser::getDefaultColourScheme()
 | 
			
		||||
{
 | 
			
		||||
    struct Type
 | 
			
		||||
    {
 | 
			
		||||
        const char* name;
 | 
			
		||||
        uint32 colour;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const Type types[] =
 | 
			
		||||
    {
 | 
			
		||||
        { "Error",              0xffcc0000 },
 | 
			
		||||
        { "Comment",            0xff00aa00 },
 | 
			
		||||
        { "Keyword",            0xff0000cc },
 | 
			
		||||
        { "Operator",           0xff225500 },
 | 
			
		||||
        { "Identifier",         0xff000000 },
 | 
			
		||||
        { "Integer",            0xff880000 },
 | 
			
		||||
        { "Float",              0xff885500 },
 | 
			
		||||
        { "String",             0xff990099 },
 | 
			
		||||
        { "Bracket",            0xff000055 },
 | 
			
		||||
        { "Punctuation",        0xff004400 },
 | 
			
		||||
        { "Preprocessor Text",  0xff660000 }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CodeEditorComponent::ColourScheme cs;
 | 
			
		||||
 | 
			
		||||
    for (auto& t : types)
 | 
			
		||||
        cs.set (t.name, Colour (t.colour));
 | 
			
		||||
 | 
			
		||||
    return cs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool CPlusPlusCodeTokeniser::isReservedKeyword (const String& token) noexcept
 | 
			
		||||
{
 | 
			
		||||
    return CppTokeniserFunctions::isReservedKeyword (token.getCharPointer(), token.length());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,72 +1,72 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A simple lexical analyser for syntax colouring of C++ code.
 | 
			
		||||
 | 
			
		||||
    @see CodeEditorComponent, CodeDocument
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CPlusPlusCodeTokeniser    : public CodeTokeniser
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CPlusPlusCodeTokeniser();
 | 
			
		||||
    ~CPlusPlusCodeTokeniser() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int readNextToken (CodeDocument::Iterator&) override;
 | 
			
		||||
    CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
 | 
			
		||||
 | 
			
		||||
    /** This is a handy method for checking whether a string is a c++ reserved keyword. */
 | 
			
		||||
    static bool isReservedKeyword (const String& token) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** The token values returned by this tokeniser. */
 | 
			
		||||
    enum TokenType
 | 
			
		||||
    {
 | 
			
		||||
        tokenType_error = 0,
 | 
			
		||||
        tokenType_comment,
 | 
			
		||||
        tokenType_keyword,
 | 
			
		||||
        tokenType_operator,
 | 
			
		||||
        tokenType_identifier,
 | 
			
		||||
        tokenType_integer,
 | 
			
		||||
        tokenType_float,
 | 
			
		||||
        tokenType_string,
 | 
			
		||||
        tokenType_bracket,
 | 
			
		||||
        tokenType_punctuation,
 | 
			
		||||
        tokenType_preprocessor
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_LEAK_DETECTOR (CPlusPlusCodeTokeniser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A simple lexical analyser for syntax colouring of C++ code.
 | 
			
		||||
 | 
			
		||||
    @see CodeEditorComponent, CodeDocument
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CPlusPlusCodeTokeniser    : public CodeTokeniser
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CPlusPlusCodeTokeniser();
 | 
			
		||||
    ~CPlusPlusCodeTokeniser() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int readNextToken (CodeDocument::Iterator&) override;
 | 
			
		||||
    CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
 | 
			
		||||
 | 
			
		||||
    /** This is a handy method for checking whether a string is a c++ reserved keyword. */
 | 
			
		||||
    static bool isReservedKeyword (const String& token) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** The token values returned by this tokeniser. */
 | 
			
		||||
    enum TokenType
 | 
			
		||||
    {
 | 
			
		||||
        tokenType_error = 0,
 | 
			
		||||
        tokenType_comment,
 | 
			
		||||
        tokenType_keyword,
 | 
			
		||||
        tokenType_operator,
 | 
			
		||||
        tokenType_identifier,
 | 
			
		||||
        tokenType_integer,
 | 
			
		||||
        tokenType_float,
 | 
			
		||||
        tokenType_string,
 | 
			
		||||
        tokenType_bracket,
 | 
			
		||||
        tokenType_punctuation,
 | 
			
		||||
        tokenType_preprocessor
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_LEAK_DETECTOR (CPlusPlusCodeTokeniser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,450 +1,450 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class CodeDocumentLine;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A class for storing and manipulating a source code file.
 | 
			
		||||
 | 
			
		||||
    When using a CodeEditorComponent, it takes one of these as its source object.
 | 
			
		||||
 | 
			
		||||
    The CodeDocument stores its content as an array of lines, which makes it
 | 
			
		||||
    quick to insert and delete.
 | 
			
		||||
 | 
			
		||||
    @see CodeEditorComponent
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CodeDocument
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Creates a new, empty document. */
 | 
			
		||||
    CodeDocument();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~CodeDocument();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A position in a code document.
 | 
			
		||||
 | 
			
		||||
        Using this class you can find a position in a code document and quickly get its
 | 
			
		||||
        character position, line, and index. By calling setPositionMaintained (true), the
 | 
			
		||||
        position is automatically updated when text is inserted or deleted in the document,
 | 
			
		||||
        so that it maintains its original place in the text.
 | 
			
		||||
    */
 | 
			
		||||
    class JUCE_API  Position
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        /** Creates an uninitialised position.
 | 
			
		||||
            Don't attempt to call any methods on this until you've given it an owner document
 | 
			
		||||
            to refer to!
 | 
			
		||||
        */
 | 
			
		||||
        Position() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Creates a position based on a line and index in a document.
 | 
			
		||||
 | 
			
		||||
            Note that this index is NOT the column number, it's the number of characters from the
 | 
			
		||||
            start of the line. The "column" number isn't quite the same, because if the line
 | 
			
		||||
            contains any tab characters, the relationship of the index to its visual column depends on
 | 
			
		||||
            the number of spaces per tab being used!
 | 
			
		||||
 | 
			
		||||
            Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
 | 
			
		||||
            they will be adjusted to keep them within its limits.
 | 
			
		||||
        */
 | 
			
		||||
        Position (const CodeDocument& ownerDocument,
 | 
			
		||||
                  int line, int indexInLine) noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Creates a position based on a character index in a document.
 | 
			
		||||
            This position is placed at the specified number of characters from the start of the
 | 
			
		||||
            document. The line and column are auto-calculated.
 | 
			
		||||
 | 
			
		||||
            If the position is beyond the range of the document, it'll be adjusted to keep it
 | 
			
		||||
            inside.
 | 
			
		||||
        */
 | 
			
		||||
        Position (const CodeDocument& ownerDocument,
 | 
			
		||||
                  int charactersFromStartOfDocument) noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Creates a copy of another position.
 | 
			
		||||
 | 
			
		||||
            This will copy the position, but the new object will not be set to maintain its position,
 | 
			
		||||
            even if the source object was set to do so.
 | 
			
		||||
        */
 | 
			
		||||
        Position (const Position&) noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Destructor. */
 | 
			
		||||
        ~Position();
 | 
			
		||||
 | 
			
		||||
        Position& operator= (const Position&);
 | 
			
		||||
 | 
			
		||||
        bool operator== (const Position&) const noexcept;
 | 
			
		||||
        bool operator!= (const Position&) const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Points this object at a new position within the document.
 | 
			
		||||
 | 
			
		||||
            If the position is beyond the range of the document, it'll be adjusted to keep it
 | 
			
		||||
            inside.
 | 
			
		||||
            @see getPosition, setLineAndIndex
 | 
			
		||||
        */
 | 
			
		||||
        void setPosition (int charactersFromStartOfDocument);
 | 
			
		||||
 | 
			
		||||
        /** Returns the position as the number of characters from the start of the document.
 | 
			
		||||
            @see setPosition, getLineNumber, getIndexInLine
 | 
			
		||||
        */
 | 
			
		||||
        int getPosition() const noexcept            { return characterPos; }
 | 
			
		||||
 | 
			
		||||
        /** Moves the position to a new line and index within the line.
 | 
			
		||||
 | 
			
		||||
            Note that the index is NOT the column at which the position appears in an editor.
 | 
			
		||||
            If the line contains any tab characters, the relationship of the index to its
 | 
			
		||||
            visual position depends on the number of spaces per tab being used!
 | 
			
		||||
 | 
			
		||||
            Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
 | 
			
		||||
            they will be adjusted to keep them within its limits.
 | 
			
		||||
        */
 | 
			
		||||
        void setLineAndIndex (int newLineNumber, int newIndexInLine);
 | 
			
		||||
 | 
			
		||||
        /** Returns the line number of this position.
 | 
			
		||||
            The first line in the document is numbered zero, not one!
 | 
			
		||||
        */
 | 
			
		||||
        int getLineNumber() const noexcept          { return line; }
 | 
			
		||||
 | 
			
		||||
        /** Returns the number of characters from the start of the line.
 | 
			
		||||
 | 
			
		||||
            Note that this value is NOT the column at which the position appears in an editor.
 | 
			
		||||
            If the line contains any tab characters, the relationship of the index to its
 | 
			
		||||
            visual position depends on the number of spaces per tab being used!
 | 
			
		||||
        */
 | 
			
		||||
        int getIndexInLine() const noexcept         { return indexInLine; }
 | 
			
		||||
 | 
			
		||||
        /** Allows the position to be automatically updated when the document changes.
 | 
			
		||||
 | 
			
		||||
            If this is set to true, the position will register with its document so that
 | 
			
		||||
            when the document has text inserted or deleted, this position will be automatically
 | 
			
		||||
            moved to keep it at the same position in the text.
 | 
			
		||||
        */
 | 
			
		||||
        void setPositionMaintained (bool isMaintained);
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        /** Moves the position forwards or backwards by the specified number of characters.
 | 
			
		||||
            @see movedBy
 | 
			
		||||
        */
 | 
			
		||||
        void moveBy (int characterDelta);
 | 
			
		||||
 | 
			
		||||
        /** Returns a position which is the same as this one, moved by the specified number of
 | 
			
		||||
            characters.
 | 
			
		||||
            @see moveBy
 | 
			
		||||
        */
 | 
			
		||||
        Position movedBy (int characterDelta) const;
 | 
			
		||||
 | 
			
		||||
        /** Returns a position which is the same as this one, moved up or down by the specified
 | 
			
		||||
            number of lines.
 | 
			
		||||
            @see movedBy
 | 
			
		||||
        */
 | 
			
		||||
        Position movedByLines (int deltaLines) const;
 | 
			
		||||
 | 
			
		||||
        /** Returns the character in the document at this position.
 | 
			
		||||
            @see getLineText
 | 
			
		||||
        */
 | 
			
		||||
        juce_wchar getCharacter() const;
 | 
			
		||||
 | 
			
		||||
        /** Returns the line from the document that this position is within.
 | 
			
		||||
            @see getCharacter, getLineNumber
 | 
			
		||||
        */
 | 
			
		||||
        String getLineText() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        CodeDocument* owner = nullptr;
 | 
			
		||||
        int characterPos = 0, line = 0, indexInLine = 0;
 | 
			
		||||
        bool positionMaintained = false;
 | 
			
		||||
 | 
			
		||||
        friend class CodeDocument;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the full text of the document. */
 | 
			
		||||
    String getAllContent() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns a section of the document's text. */
 | 
			
		||||
    String getTextBetween (const Position& start, const Position& end) const;
 | 
			
		||||
 | 
			
		||||
    /** Returns a line from the document. */
 | 
			
		||||
    String getLine (int lineIndex) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of characters in the document. */
 | 
			
		||||
    int getNumCharacters() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of lines in the document. */
 | 
			
		||||
    int getNumLines() const noexcept                    { return lines.size(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of characters in the longest line of the document. */
 | 
			
		||||
    int getMaximumLineLength() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Deletes a section of the text.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void deleteSection (const Position& startPosition, const Position& endPosition);
 | 
			
		||||
 | 
			
		||||
    /** Deletes a section of the text.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void deleteSection (int startIndex, int endIndex);
 | 
			
		||||
 | 
			
		||||
    /** Inserts some text into the document at a given position.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void insertText (const Position& position, const String& text);
 | 
			
		||||
 | 
			
		||||
    /** Inserts some text into the document at a given position.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void insertText (int insertIndex, const String& text);
 | 
			
		||||
 | 
			
		||||
    /** Replaces a section of the text with a new string.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void replaceSection (int startIndex, int endIndex, const String& newText);
 | 
			
		||||
 | 
			
		||||
    /** Clears the document and replaces it with some new text.
 | 
			
		||||
 | 
			
		||||
        This operation is undoable - if you're trying to completely reset the document, you
 | 
			
		||||
        might want to also call clearUndoHistory() and setSavePoint() after using this method.
 | 
			
		||||
    */
 | 
			
		||||
    void replaceAllContent (const String& newContent);
 | 
			
		||||
 | 
			
		||||
    /** Analyses the changes between the current content and some new text, and applies
 | 
			
		||||
        those changes.
 | 
			
		||||
    */
 | 
			
		||||
    void applyChanges (const String& newContent);
 | 
			
		||||
 | 
			
		||||
    /** Replaces the editor's contents with the contents of a stream.
 | 
			
		||||
        This will also reset the undo history and save point marker.
 | 
			
		||||
    */
 | 
			
		||||
    bool loadFromStream (InputStream& stream);
 | 
			
		||||
 | 
			
		||||
    /** Writes the editor's current contents to a stream. */
 | 
			
		||||
    bool writeToStream (OutputStream& stream);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the preferred new-line characters for the document.
 | 
			
		||||
        This will be either "\\n", "\\r\\n", or (rarely) "\\r".
 | 
			
		||||
        @see setNewLineCharacters
 | 
			
		||||
    */
 | 
			
		||||
    String getNewLineCharacters() const noexcept          { return newLineChars; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the new-line characters that the document should use.
 | 
			
		||||
        The string must be either "\\n", "\\r\\n", or (rarely) "\\r".
 | 
			
		||||
        @see getNewLineCharacters
 | 
			
		||||
    */
 | 
			
		||||
    void setNewLineCharacters (const String& newLineCharacters) noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Begins a new undo transaction.
 | 
			
		||||
 | 
			
		||||
        The document itself will not call this internally, so relies on whatever is using the
 | 
			
		||||
        document to periodically call this to break up the undo sequence into sensible chunks.
 | 
			
		||||
        @see UndoManager::beginNewTransaction
 | 
			
		||||
    */
 | 
			
		||||
    void newTransaction();
 | 
			
		||||
 | 
			
		||||
    /** Undo the last operation.
 | 
			
		||||
        @see UndoManager::undo
 | 
			
		||||
    */
 | 
			
		||||
    void undo();
 | 
			
		||||
 | 
			
		||||
    /** Redo the last operation.
 | 
			
		||||
        @see UndoManager::redo
 | 
			
		||||
    */
 | 
			
		||||
    void redo();
 | 
			
		||||
 | 
			
		||||
    /** Clears the undo history.
 | 
			
		||||
        @see UndoManager::clearUndoHistory
 | 
			
		||||
    */
 | 
			
		||||
    void clearUndoHistory();
 | 
			
		||||
 | 
			
		||||
    /** Returns the document's UndoManager */
 | 
			
		||||
    UndoManager& getUndoManager() noexcept              { return undoManager; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Makes a note that the document's current state matches the one that is saved.
 | 
			
		||||
 | 
			
		||||
        After this has been called, hasChangedSinceSavePoint() will return false until
 | 
			
		||||
        the document has been altered, and then it'll start returning true. If the document is
 | 
			
		||||
        altered, but then undone until it gets back to this state, hasChangedSinceSavePoint()
 | 
			
		||||
        will again return false.
 | 
			
		||||
 | 
			
		||||
        @see hasChangedSinceSavePoint
 | 
			
		||||
    */
 | 
			
		||||
    void setSavePoint() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the state of the document differs from the state it was in when
 | 
			
		||||
        setSavePoint() was last called.
 | 
			
		||||
 | 
			
		||||
        @see setSavePoint
 | 
			
		||||
    */
 | 
			
		||||
    bool hasChangedSinceSavePoint() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Searches for a word-break. */
 | 
			
		||||
    Position findWordBreakAfter (const Position& position) const noexcept;
 | 
			
		||||
    /** Searches for a word-break. */
 | 
			
		||||
    Position findWordBreakBefore (const Position& position) const noexcept;
 | 
			
		||||
    /** Finds the token that contains the given position. */
 | 
			
		||||
    void findTokenContaining (const Position& pos, Position& start, Position& end) const noexcept;
 | 
			
		||||
    /** Finds the line that contains the given position. */
 | 
			
		||||
    void findLineContaining  (const Position& pos, Position& start, Position& end) const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** An object that receives callbacks from the CodeDocument when its text changes.
 | 
			
		||||
        @see CodeDocument::addListener, CodeDocument::removeListener
 | 
			
		||||
    */
 | 
			
		||||
    class JUCE_API  Listener
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        Listener() = default;
 | 
			
		||||
        virtual ~Listener() = default;
 | 
			
		||||
 | 
			
		||||
        /** Called by a CodeDocument when text is added. */
 | 
			
		||||
        virtual void codeDocumentTextInserted (const String& newText, int insertIndex) = 0;
 | 
			
		||||
 | 
			
		||||
        /** Called by a CodeDocument when text is deleted. */
 | 
			
		||||
        virtual void codeDocumentTextDeleted (int startIndex, int endIndex) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Registers a listener object to receive callbacks when the document changes.
 | 
			
		||||
        If the listener is already registered, this method has no effect.
 | 
			
		||||
        @see removeListener
 | 
			
		||||
    */
 | 
			
		||||
    void addListener (Listener* listener);
 | 
			
		||||
 | 
			
		||||
    /** Deregisters a listener.
 | 
			
		||||
        @see addListener
 | 
			
		||||
    */
 | 
			
		||||
    void removeListener (Listener* listener);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Iterates the text in a CodeDocument.
 | 
			
		||||
 | 
			
		||||
        This class lets you read characters from a CodeDocument. It's designed to be used
 | 
			
		||||
        by a CodeTokeniser object.
 | 
			
		||||
 | 
			
		||||
        @see CodeDocument
 | 
			
		||||
    */
 | 
			
		||||
    class JUCE_API  Iterator
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        /** Creates an uninitialised iterator.
 | 
			
		||||
            Don't attempt to call any methods on this until you've given it an
 | 
			
		||||
            owner document to refer to!
 | 
			
		||||
         */
 | 
			
		||||
        Iterator() noexcept;
 | 
			
		||||
 | 
			
		||||
        Iterator (const CodeDocument& document) noexcept;
 | 
			
		||||
        Iterator (CodeDocument::Position) noexcept;
 | 
			
		||||
        ~Iterator() noexcept;
 | 
			
		||||
 | 
			
		||||
        Iterator (const Iterator&) = default;
 | 
			
		||||
        Iterator& operator= (const Iterator&) = default;
 | 
			
		||||
 | 
			
		||||
        /** Reads the next character and returns it. Returns 0 if you try to
 | 
			
		||||
            read past the document's end.
 | 
			
		||||
            @see peekNextChar, previousChar
 | 
			
		||||
        */
 | 
			
		||||
        juce_wchar nextChar() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Reads the next character without moving the current position. */
 | 
			
		||||
        juce_wchar peekNextChar() const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Reads the previous character and returns it. Returns 0 if you try to
 | 
			
		||||
            read past the document's start.
 | 
			
		||||
            @see isSOF, peekPreviousChar, nextChar
 | 
			
		||||
         */
 | 
			
		||||
        juce_wchar previousChar() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Reads the next character without moving the current position. */
 | 
			
		||||
        juce_wchar peekPreviousChar() const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Advances the position by one character. */
 | 
			
		||||
        void skip() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Returns the position as the number of characters from the start of the document. */
 | 
			
		||||
        int getPosition() const noexcept        { return position; }
 | 
			
		||||
 | 
			
		||||
        /** Skips over any whitespace characters until the next character is non-whitespace. */
 | 
			
		||||
        void skipWhitespace() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Skips forward until the next character will be the first character on the next line */
 | 
			
		||||
        void skipToEndOfLine() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Skips backward until the next character will be the first character on this line */
 | 
			
		||||
        void skipToStartOfLine() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Returns the line number of the next character. */
 | 
			
		||||
        int getLine() const noexcept            { return line; }
 | 
			
		||||
 | 
			
		||||
        /** Returns true if the iterator has reached the end of the document. */
 | 
			
		||||
        bool isEOF() const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Returns true if the iterator is at the start of the document. */
 | 
			
		||||
        bool isSOF() const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Convert this iterator to a CodeDocument::Position. */
 | 
			
		||||
        CodeDocument::Position toPosition() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        bool reinitialiseCharPtr() const;
 | 
			
		||||
 | 
			
		||||
        const CodeDocument* document;
 | 
			
		||||
        mutable String::CharPointerType charPointer { nullptr };
 | 
			
		||||
        int line = 0, position = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct InsertAction;
 | 
			
		||||
    struct DeleteAction;
 | 
			
		||||
    friend class Iterator;
 | 
			
		||||
    friend class Position;
 | 
			
		||||
 | 
			
		||||
    OwnedArray<CodeDocumentLine> lines;
 | 
			
		||||
    Array<Position*> positionsToMaintain;
 | 
			
		||||
    UndoManager undoManager;
 | 
			
		||||
    int currentActionIndex = 0, indexOfSavedState = -1;
 | 
			
		||||
    int maximumLineLength = -1;
 | 
			
		||||
    ListenerList<Listener> listeners;
 | 
			
		||||
    String newLineChars { "\r\n" };
 | 
			
		||||
 | 
			
		||||
    void insert (const String& text, int insertPos, bool undoable);
 | 
			
		||||
    void remove (int startPos, int endPos, bool undoable);
 | 
			
		||||
    void checkLastLineStatus();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeDocument)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class CodeDocumentLine;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A class for storing and manipulating a source code file.
 | 
			
		||||
 | 
			
		||||
    When using a CodeEditorComponent, it takes one of these as its source object.
 | 
			
		||||
 | 
			
		||||
    The CodeDocument stores its content as an array of lines, which makes it
 | 
			
		||||
    quick to insert and delete.
 | 
			
		||||
 | 
			
		||||
    @see CodeEditorComponent
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CodeDocument
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Creates a new, empty document. */
 | 
			
		||||
    CodeDocument();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~CodeDocument();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A position in a code document.
 | 
			
		||||
 | 
			
		||||
        Using this class you can find a position in a code document and quickly get its
 | 
			
		||||
        character position, line, and index. By calling setPositionMaintained (true), the
 | 
			
		||||
        position is automatically updated when text is inserted or deleted in the document,
 | 
			
		||||
        so that it maintains its original place in the text.
 | 
			
		||||
    */
 | 
			
		||||
    class JUCE_API  Position
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        /** Creates an uninitialised position.
 | 
			
		||||
            Don't attempt to call any methods on this until you've given it an owner document
 | 
			
		||||
            to refer to!
 | 
			
		||||
        */
 | 
			
		||||
        Position() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Creates a position based on a line and index in a document.
 | 
			
		||||
 | 
			
		||||
            Note that this index is NOT the column number, it's the number of characters from the
 | 
			
		||||
            start of the line. The "column" number isn't quite the same, because if the line
 | 
			
		||||
            contains any tab characters, the relationship of the index to its visual column depends on
 | 
			
		||||
            the number of spaces per tab being used!
 | 
			
		||||
 | 
			
		||||
            Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
 | 
			
		||||
            they will be adjusted to keep them within its limits.
 | 
			
		||||
        */
 | 
			
		||||
        Position (const CodeDocument& ownerDocument,
 | 
			
		||||
                  int line, int indexInLine) noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Creates a position based on a character index in a document.
 | 
			
		||||
            This position is placed at the specified number of characters from the start of the
 | 
			
		||||
            document. The line and column are auto-calculated.
 | 
			
		||||
 | 
			
		||||
            If the position is beyond the range of the document, it'll be adjusted to keep it
 | 
			
		||||
            inside.
 | 
			
		||||
        */
 | 
			
		||||
        Position (const CodeDocument& ownerDocument,
 | 
			
		||||
                  int charactersFromStartOfDocument) noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Creates a copy of another position.
 | 
			
		||||
 | 
			
		||||
            This will copy the position, but the new object will not be set to maintain its position,
 | 
			
		||||
            even if the source object was set to do so.
 | 
			
		||||
        */
 | 
			
		||||
        Position (const Position&) noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Destructor. */
 | 
			
		||||
        ~Position();
 | 
			
		||||
 | 
			
		||||
        Position& operator= (const Position&);
 | 
			
		||||
 | 
			
		||||
        bool operator== (const Position&) const noexcept;
 | 
			
		||||
        bool operator!= (const Position&) const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Points this object at a new position within the document.
 | 
			
		||||
 | 
			
		||||
            If the position is beyond the range of the document, it'll be adjusted to keep it
 | 
			
		||||
            inside.
 | 
			
		||||
            @see getPosition, setLineAndIndex
 | 
			
		||||
        */
 | 
			
		||||
        void setPosition (int charactersFromStartOfDocument);
 | 
			
		||||
 | 
			
		||||
        /** Returns the position as the number of characters from the start of the document.
 | 
			
		||||
            @see setPosition, getLineNumber, getIndexInLine
 | 
			
		||||
        */
 | 
			
		||||
        int getPosition() const noexcept            { return characterPos; }
 | 
			
		||||
 | 
			
		||||
        /** Moves the position to a new line and index within the line.
 | 
			
		||||
 | 
			
		||||
            Note that the index is NOT the column at which the position appears in an editor.
 | 
			
		||||
            If the line contains any tab characters, the relationship of the index to its
 | 
			
		||||
            visual position depends on the number of spaces per tab being used!
 | 
			
		||||
 | 
			
		||||
            Lines are numbered from zero, and if the line or index are beyond the bounds of the document,
 | 
			
		||||
            they will be adjusted to keep them within its limits.
 | 
			
		||||
        */
 | 
			
		||||
        void setLineAndIndex (int newLineNumber, int newIndexInLine);
 | 
			
		||||
 | 
			
		||||
        /** Returns the line number of this position.
 | 
			
		||||
            The first line in the document is numbered zero, not one!
 | 
			
		||||
        */
 | 
			
		||||
        int getLineNumber() const noexcept          { return line; }
 | 
			
		||||
 | 
			
		||||
        /** Returns the number of characters from the start of the line.
 | 
			
		||||
 | 
			
		||||
            Note that this value is NOT the column at which the position appears in an editor.
 | 
			
		||||
            If the line contains any tab characters, the relationship of the index to its
 | 
			
		||||
            visual position depends on the number of spaces per tab being used!
 | 
			
		||||
        */
 | 
			
		||||
        int getIndexInLine() const noexcept         { return indexInLine; }
 | 
			
		||||
 | 
			
		||||
        /** Allows the position to be automatically updated when the document changes.
 | 
			
		||||
 | 
			
		||||
            If this is set to true, the position will register with its document so that
 | 
			
		||||
            when the document has text inserted or deleted, this position will be automatically
 | 
			
		||||
            moved to keep it at the same position in the text.
 | 
			
		||||
        */
 | 
			
		||||
        void setPositionMaintained (bool isMaintained);
 | 
			
		||||
 | 
			
		||||
        //==============================================================================
 | 
			
		||||
        /** Moves the position forwards or backwards by the specified number of characters.
 | 
			
		||||
            @see movedBy
 | 
			
		||||
        */
 | 
			
		||||
        void moveBy (int characterDelta);
 | 
			
		||||
 | 
			
		||||
        /** Returns a position which is the same as this one, moved by the specified number of
 | 
			
		||||
            characters.
 | 
			
		||||
            @see moveBy
 | 
			
		||||
        */
 | 
			
		||||
        Position movedBy (int characterDelta) const;
 | 
			
		||||
 | 
			
		||||
        /** Returns a position which is the same as this one, moved up or down by the specified
 | 
			
		||||
            number of lines.
 | 
			
		||||
            @see movedBy
 | 
			
		||||
        */
 | 
			
		||||
        Position movedByLines (int deltaLines) const;
 | 
			
		||||
 | 
			
		||||
        /** Returns the character in the document at this position.
 | 
			
		||||
            @see getLineText
 | 
			
		||||
        */
 | 
			
		||||
        juce_wchar getCharacter() const;
 | 
			
		||||
 | 
			
		||||
        /** Returns the line from the document that this position is within.
 | 
			
		||||
            @see getCharacter, getLineNumber
 | 
			
		||||
        */
 | 
			
		||||
        String getLineText() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        CodeDocument* owner = nullptr;
 | 
			
		||||
        int characterPos = 0, line = 0, indexInLine = 0;
 | 
			
		||||
        bool positionMaintained = false;
 | 
			
		||||
 | 
			
		||||
        friend class CodeDocument;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the full text of the document. */
 | 
			
		||||
    String getAllContent() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns a section of the document's text. */
 | 
			
		||||
    String getTextBetween (const Position& start, const Position& end) const;
 | 
			
		||||
 | 
			
		||||
    /** Returns a line from the document. */
 | 
			
		||||
    String getLine (int lineIndex) const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of characters in the document. */
 | 
			
		||||
    int getNumCharacters() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of lines in the document. */
 | 
			
		||||
    int getNumLines() const noexcept                    { return lines.size(); }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of characters in the longest line of the document. */
 | 
			
		||||
    int getMaximumLineLength() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Deletes a section of the text.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void deleteSection (const Position& startPosition, const Position& endPosition);
 | 
			
		||||
 | 
			
		||||
    /** Deletes a section of the text.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void deleteSection (int startIndex, int endIndex);
 | 
			
		||||
 | 
			
		||||
    /** Inserts some text into the document at a given position.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void insertText (const Position& position, const String& text);
 | 
			
		||||
 | 
			
		||||
    /** Inserts some text into the document at a given position.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void insertText (int insertIndex, const String& text);
 | 
			
		||||
 | 
			
		||||
    /** Replaces a section of the text with a new string.
 | 
			
		||||
        This operation is undoable.
 | 
			
		||||
    */
 | 
			
		||||
    void replaceSection (int startIndex, int endIndex, const String& newText);
 | 
			
		||||
 | 
			
		||||
    /** Clears the document and replaces it with some new text.
 | 
			
		||||
 | 
			
		||||
        This operation is undoable - if you're trying to completely reset the document, you
 | 
			
		||||
        might want to also call clearUndoHistory() and setSavePoint() after using this method.
 | 
			
		||||
    */
 | 
			
		||||
    void replaceAllContent (const String& newContent);
 | 
			
		||||
 | 
			
		||||
    /** Analyses the changes between the current content and some new text, and applies
 | 
			
		||||
        those changes.
 | 
			
		||||
    */
 | 
			
		||||
    void applyChanges (const String& newContent);
 | 
			
		||||
 | 
			
		||||
    /** Replaces the editor's contents with the contents of a stream.
 | 
			
		||||
        This will also reset the undo history and save point marker.
 | 
			
		||||
    */
 | 
			
		||||
    bool loadFromStream (InputStream& stream);
 | 
			
		||||
 | 
			
		||||
    /** Writes the editor's current contents to a stream. */
 | 
			
		||||
    bool writeToStream (OutputStream& stream);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the preferred new-line characters for the document.
 | 
			
		||||
        This will be either "\\n", "\\r\\n", or (rarely) "\\r".
 | 
			
		||||
        @see setNewLineCharacters
 | 
			
		||||
    */
 | 
			
		||||
    String getNewLineCharacters() const noexcept          { return newLineChars; }
 | 
			
		||||
 | 
			
		||||
    /** Sets the new-line characters that the document should use.
 | 
			
		||||
        The string must be either "\\n", "\\r\\n", or (rarely) "\\r".
 | 
			
		||||
        @see getNewLineCharacters
 | 
			
		||||
    */
 | 
			
		||||
    void setNewLineCharacters (const String& newLineCharacters) noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Begins a new undo transaction.
 | 
			
		||||
 | 
			
		||||
        The document itself will not call this internally, so relies on whatever is using the
 | 
			
		||||
        document to periodically call this to break up the undo sequence into sensible chunks.
 | 
			
		||||
        @see UndoManager::beginNewTransaction
 | 
			
		||||
    */
 | 
			
		||||
    void newTransaction();
 | 
			
		||||
 | 
			
		||||
    /** Undo the last operation.
 | 
			
		||||
        @see UndoManager::undo
 | 
			
		||||
    */
 | 
			
		||||
    void undo();
 | 
			
		||||
 | 
			
		||||
    /** Redo the last operation.
 | 
			
		||||
        @see UndoManager::redo
 | 
			
		||||
    */
 | 
			
		||||
    void redo();
 | 
			
		||||
 | 
			
		||||
    /** Clears the undo history.
 | 
			
		||||
        @see UndoManager::clearUndoHistory
 | 
			
		||||
    */
 | 
			
		||||
    void clearUndoHistory();
 | 
			
		||||
 | 
			
		||||
    /** Returns the document's UndoManager */
 | 
			
		||||
    UndoManager& getUndoManager() noexcept              { return undoManager; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Makes a note that the document's current state matches the one that is saved.
 | 
			
		||||
 | 
			
		||||
        After this has been called, hasChangedSinceSavePoint() will return false until
 | 
			
		||||
        the document has been altered, and then it'll start returning true. If the document is
 | 
			
		||||
        altered, but then undone until it gets back to this state, hasChangedSinceSavePoint()
 | 
			
		||||
        will again return false.
 | 
			
		||||
 | 
			
		||||
        @see hasChangedSinceSavePoint
 | 
			
		||||
    */
 | 
			
		||||
    void setSavePoint() noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the state of the document differs from the state it was in when
 | 
			
		||||
        setSavePoint() was last called.
 | 
			
		||||
 | 
			
		||||
        @see setSavePoint
 | 
			
		||||
    */
 | 
			
		||||
    bool hasChangedSinceSavePoint() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Searches for a word-break. */
 | 
			
		||||
    Position findWordBreakAfter (const Position& position) const noexcept;
 | 
			
		||||
    /** Searches for a word-break. */
 | 
			
		||||
    Position findWordBreakBefore (const Position& position) const noexcept;
 | 
			
		||||
    /** Finds the token that contains the given position. */
 | 
			
		||||
    void findTokenContaining (const Position& pos, Position& start, Position& end) const noexcept;
 | 
			
		||||
    /** Finds the line that contains the given position. */
 | 
			
		||||
    void findLineContaining  (const Position& pos, Position& start, Position& end) const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** An object that receives callbacks from the CodeDocument when its text changes.
 | 
			
		||||
        @see CodeDocument::addListener, CodeDocument::removeListener
 | 
			
		||||
    */
 | 
			
		||||
    class JUCE_API  Listener
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        Listener() = default;
 | 
			
		||||
        virtual ~Listener() = default;
 | 
			
		||||
 | 
			
		||||
        /** Called by a CodeDocument when text is added. */
 | 
			
		||||
        virtual void codeDocumentTextInserted (const String& newText, int insertIndex) = 0;
 | 
			
		||||
 | 
			
		||||
        /** Called by a CodeDocument when text is deleted. */
 | 
			
		||||
        virtual void codeDocumentTextDeleted (int startIndex, int endIndex) = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Registers a listener object to receive callbacks when the document changes.
 | 
			
		||||
        If the listener is already registered, this method has no effect.
 | 
			
		||||
        @see removeListener
 | 
			
		||||
    */
 | 
			
		||||
    void addListener (Listener* listener);
 | 
			
		||||
 | 
			
		||||
    /** Deregisters a listener.
 | 
			
		||||
        @see addListener
 | 
			
		||||
    */
 | 
			
		||||
    void removeListener (Listener* listener);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Iterates the text in a CodeDocument.
 | 
			
		||||
 | 
			
		||||
        This class lets you read characters from a CodeDocument. It's designed to be used
 | 
			
		||||
        by a CodeTokeniser object.
 | 
			
		||||
 | 
			
		||||
        @see CodeDocument
 | 
			
		||||
    */
 | 
			
		||||
    class JUCE_API  Iterator
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        /** Creates an uninitialised iterator.
 | 
			
		||||
            Don't attempt to call any methods on this until you've given it an
 | 
			
		||||
            owner document to refer to!
 | 
			
		||||
         */
 | 
			
		||||
        Iterator() noexcept;
 | 
			
		||||
 | 
			
		||||
        Iterator (const CodeDocument& document) noexcept;
 | 
			
		||||
        Iterator (CodeDocument::Position) noexcept;
 | 
			
		||||
        ~Iterator() noexcept;
 | 
			
		||||
 | 
			
		||||
        Iterator (const Iterator&) = default;
 | 
			
		||||
        Iterator& operator= (const Iterator&) = default;
 | 
			
		||||
 | 
			
		||||
        /** Reads the next character and returns it. Returns 0 if you try to
 | 
			
		||||
            read past the document's end.
 | 
			
		||||
            @see peekNextChar, previousChar
 | 
			
		||||
        */
 | 
			
		||||
        juce_wchar nextChar() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Reads the next character without moving the current position. */
 | 
			
		||||
        juce_wchar peekNextChar() const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Reads the previous character and returns it. Returns 0 if you try to
 | 
			
		||||
            read past the document's start.
 | 
			
		||||
            @see isSOF, peekPreviousChar, nextChar
 | 
			
		||||
         */
 | 
			
		||||
        juce_wchar previousChar() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Reads the next character without moving the current position. */
 | 
			
		||||
        juce_wchar peekPreviousChar() const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Advances the position by one character. */
 | 
			
		||||
        void skip() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Returns the position as the number of characters from the start of the document. */
 | 
			
		||||
        int getPosition() const noexcept        { return position; }
 | 
			
		||||
 | 
			
		||||
        /** Skips over any whitespace characters until the next character is non-whitespace. */
 | 
			
		||||
        void skipWhitespace() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Skips forward until the next character will be the first character on the next line */
 | 
			
		||||
        void skipToEndOfLine() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Skips backward until the next character will be the first character on this line */
 | 
			
		||||
        void skipToStartOfLine() noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Returns the line number of the next character. */
 | 
			
		||||
        int getLine() const noexcept            { return line; }
 | 
			
		||||
 | 
			
		||||
        /** Returns true if the iterator has reached the end of the document. */
 | 
			
		||||
        bool isEOF() const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Returns true if the iterator is at the start of the document. */
 | 
			
		||||
        bool isSOF() const noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Convert this iterator to a CodeDocument::Position. */
 | 
			
		||||
        CodeDocument::Position toPosition() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        bool reinitialiseCharPtr() const;
 | 
			
		||||
 | 
			
		||||
        const CodeDocument* document;
 | 
			
		||||
        mutable String::CharPointerType charPointer { nullptr };
 | 
			
		||||
        int line = 0, position = 0;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct InsertAction;
 | 
			
		||||
    struct DeleteAction;
 | 
			
		||||
    friend class Iterator;
 | 
			
		||||
    friend class Position;
 | 
			
		||||
 | 
			
		||||
    OwnedArray<CodeDocumentLine> lines;
 | 
			
		||||
    Array<Position*> positionsToMaintain;
 | 
			
		||||
    UndoManager undoManager;
 | 
			
		||||
    int currentActionIndex = 0, indexOfSavedState = -1;
 | 
			
		||||
    int maximumLineLength = -1;
 | 
			
		||||
    ListenerList<Listener> listeners;
 | 
			
		||||
    String newLineChars { "\r\n" };
 | 
			
		||||
 | 
			
		||||
    void insert (const String& text, int insertPos, bool undoable);
 | 
			
		||||
    void remove (int startPos, int endPos, bool undoable);
 | 
			
		||||
    void checkLastLineStatus();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeDocument)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,456 +1,476 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class CodeTokeniser;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A text editor component designed specifically for source code.
 | 
			
		||||
 | 
			
		||||
    This is designed to handle syntax highlighting and fast editing of very large
 | 
			
		||||
    files.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CodeEditorComponent   : public Component,
 | 
			
		||||
                                        public ApplicationCommandTarget,
 | 
			
		||||
                                        public TextInputTarget
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an editor for a document.
 | 
			
		||||
 | 
			
		||||
        The tokeniser object is optional - pass nullptr to disable syntax highlighting.
 | 
			
		||||
        The object that you pass in is not owned or deleted by the editor - you must
 | 
			
		||||
        make sure that it doesn't get deleted while this component is still using it.
 | 
			
		||||
 | 
			
		||||
        @see CodeDocument
 | 
			
		||||
    */
 | 
			
		||||
    CodeEditorComponent (CodeDocument& document,
 | 
			
		||||
                         CodeTokeniser* codeTokeniser);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~CodeEditorComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the code document that this component is editing. */
 | 
			
		||||
    CodeDocument& getDocument() const noexcept          { return document; }
 | 
			
		||||
 | 
			
		||||
    /** Loads the given content into the document.
 | 
			
		||||
        This will completely reset the CodeDocument object, clear its undo history,
 | 
			
		||||
        and fill it with this text.
 | 
			
		||||
    */
 | 
			
		||||
    void loadContent (const String& newContent);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the standard character width. */
 | 
			
		||||
    float getCharWidth() const noexcept                         { return charWidth; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the height of a line of text, in pixels. */
 | 
			
		||||
    int getLineHeight() const noexcept                          { return lineHeight; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of whole lines visible on the screen,
 | 
			
		||||
        This doesn't include a cut-off line that might be visible at the bottom if the
 | 
			
		||||
        component's height isn't an exact multiple of the line-height.
 | 
			
		||||
    */
 | 
			
		||||
    int getNumLinesOnScreen() const noexcept                    { return linesOnScreen; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the index of the first line that's visible at the top of the editor. */
 | 
			
		||||
    int getFirstLineOnScreen() const noexcept                   { return firstLineOnScreen; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of whole columns visible on the screen.
 | 
			
		||||
        This doesn't include any cut-off columns at the right-hand edge.
 | 
			
		||||
    */
 | 
			
		||||
    int getNumColumnsOnScreen() const noexcept                  { return columnsOnScreen; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the current caret position. */
 | 
			
		||||
    CodeDocument::Position getCaretPos() const                  { return caretPos; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the position of the caret, relative to the editor's origin. */
 | 
			
		||||
    Rectangle<int> getCaretRectangle() override;
 | 
			
		||||
 | 
			
		||||
    /** Moves the caret.
 | 
			
		||||
        If selecting is true, the section of the document between the current
 | 
			
		||||
        caret position and the new one will become selected. If false, any currently
 | 
			
		||||
        selected region will be deselected.
 | 
			
		||||
    */
 | 
			
		||||
    void moveCaretTo (const CodeDocument::Position& newPos, bool selecting);
 | 
			
		||||
 | 
			
		||||
    /** Returns the on-screen position of a character in the document.
 | 
			
		||||
        The rectangle returned is relative to this component's top-left origin.
 | 
			
		||||
    */
 | 
			
		||||
    Rectangle<int> getCharacterBounds (const CodeDocument::Position& pos) const;
 | 
			
		||||
 | 
			
		||||
    /** Finds the character at a given on-screen position.
 | 
			
		||||
        The coordinates are relative to this component's top-left origin.
 | 
			
		||||
    */
 | 
			
		||||
    CodeDocument::Position getPositionAt (int x, int y) const;
 | 
			
		||||
 | 
			
		||||
    /** Returns the start of the selection as a position. */
 | 
			
		||||
    CodeDocument::Position getSelectionStart() const            { return selectionStart; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the end of the selection as a position. */
 | 
			
		||||
    CodeDocument::Position getSelectionEnd() const              { return selectionEnd; }
 | 
			
		||||
 | 
			
		||||
    /** Enables or disables the line-number display in the gutter. */
 | 
			
		||||
    void setLineNumbersShown (bool shouldBeShown);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting);
 | 
			
		||||
    bool moveCaretRight (bool moveInWholeWordSteps, bool selecting);
 | 
			
		||||
    bool moveCaretUp (bool selecting);
 | 
			
		||||
    bool moveCaretDown (bool selecting);
 | 
			
		||||
    bool scrollDown();
 | 
			
		||||
    bool scrollUp();
 | 
			
		||||
    bool pageUp (bool selecting);
 | 
			
		||||
    bool pageDown (bool selecting);
 | 
			
		||||
    bool moveCaretToTop (bool selecting);
 | 
			
		||||
    bool moveCaretToStartOfLine (bool selecting);
 | 
			
		||||
    bool moveCaretToEnd (bool selecting);
 | 
			
		||||
    bool moveCaretToEndOfLine (bool selecting);
 | 
			
		||||
    bool deleteBackwards (bool moveInWholeWordSteps);
 | 
			
		||||
    bool deleteForwards (bool moveInWholeWordSteps);
 | 
			
		||||
    bool deleteWhitespaceBackwardsToTabStop();
 | 
			
		||||
    virtual bool copyToClipboard();
 | 
			
		||||
    virtual bool cutToClipboard();
 | 
			
		||||
    virtual bool pasteFromClipboard();
 | 
			
		||||
    bool undo();
 | 
			
		||||
    bool redo();
 | 
			
		||||
 | 
			
		||||
    void selectRegion (const CodeDocument::Position& start, const CodeDocument::Position& end);
 | 
			
		||||
    bool selectAll();
 | 
			
		||||
    void deselectAll();
 | 
			
		||||
 | 
			
		||||
    void scrollToLine (int newFirstLineOnScreen);
 | 
			
		||||
    void scrollBy (int deltaLines);
 | 
			
		||||
    void scrollToColumn (int newFirstColumnOnScreen);
 | 
			
		||||
    void scrollToKeepCaretOnScreen();
 | 
			
		||||
    void scrollToKeepLinesOnScreen (Range<int> linesToShow);
 | 
			
		||||
 | 
			
		||||
    void insertTextAtCaret (const String& textToInsert) override;
 | 
			
		||||
    void insertTabAtCaret();
 | 
			
		||||
 | 
			
		||||
    void indentSelection();
 | 
			
		||||
    void unindentSelection();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Range<int> getHighlightedRegion() const override;
 | 
			
		||||
    bool isHighlightActive() const noexcept;
 | 
			
		||||
    void setHighlightedRegion (const Range<int>& newRange) override;
 | 
			
		||||
    String getTextInRange (const Range<int>& range) const override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Can be used to save and restore the editor's caret position, selection state, etc. */
 | 
			
		||||
    struct State
 | 
			
		||||
    {
 | 
			
		||||
        /** Creates an object containing the state of the given editor. */
 | 
			
		||||
        State (const CodeEditorComponent&);
 | 
			
		||||
        /** Creates a state object from a string that was previously created with toString(). */
 | 
			
		||||
        State (const String& stringifiedVersion);
 | 
			
		||||
        State (const State&) noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Updates the given editor with this saved state. */
 | 
			
		||||
        void restoreState (CodeEditorComponent&) const;
 | 
			
		||||
 | 
			
		||||
        /** Returns a stringified version of this state that can be used to recreate it later. */
 | 
			
		||||
        String toString() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        int lastTopLine, lastCaretPos, lastSelectionEnd;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the current tab settings.
 | 
			
		||||
        This lets you change the tab size and whether pressing the tab key inserts a
 | 
			
		||||
        tab character, or its equivalent number of spaces.
 | 
			
		||||
    */
 | 
			
		||||
    void setTabSize (int numSpacesPerTab, bool insertSpacesInsteadOfTabCharacters);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current number of spaces per tab.
 | 
			
		||||
        @see setTabSize
 | 
			
		||||
    */
 | 
			
		||||
    int getTabSize() const noexcept                     { return spacesPerTab; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the tab key will insert spaces instead of actual tab characters.
 | 
			
		||||
        @see setTabSize
 | 
			
		||||
    */
 | 
			
		||||
    bool areSpacesInsertedForTabs() const               { return useSpacesForTabs; }
 | 
			
		||||
 | 
			
		||||
    /** Returns a string containing spaces or tab characters to generate the given number of spaces. */
 | 
			
		||||
    String getTabString (int numSpaces) const;
 | 
			
		||||
 | 
			
		||||
    /** Changes the font.
 | 
			
		||||
        Make sure you only use a fixed-width font, or this component will look pretty nasty!
 | 
			
		||||
    */
 | 
			
		||||
    void setFont (const Font& newFont);
 | 
			
		||||
 | 
			
		||||
    /** Returns the font that the editor is using. */
 | 
			
		||||
    const Font& getFont() const noexcept                { return font; }
 | 
			
		||||
 | 
			
		||||
    /** Makes the editor read-only. */
 | 
			
		||||
    void setReadOnly (bool shouldBeReadOnly) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the editor is set to be read-only. */
 | 
			
		||||
    bool isReadOnly() const noexcept                    { return readOnly; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Defines a syntax highlighting colour scheme */
 | 
			
		||||
    struct JUCE_API  ColourScheme
 | 
			
		||||
    {
 | 
			
		||||
        /** Defines a colour for a token type */
 | 
			
		||||
        struct TokenType
 | 
			
		||||
        {
 | 
			
		||||
            String name;
 | 
			
		||||
            Colour colour;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Array<TokenType> types;
 | 
			
		||||
 | 
			
		||||
        void set (const String& name, Colour colour);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Changes the syntax highlighting scheme.
 | 
			
		||||
        The token type values are dependent on the tokeniser being used - use
 | 
			
		||||
        CodeTokeniser::getTokenTypes() to get a list of the token types.
 | 
			
		||||
        @see getColourForTokenType
 | 
			
		||||
    */
 | 
			
		||||
    void setColourScheme (const ColourScheme& scheme);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current syntax highlighting colour scheme. */
 | 
			
		||||
    const ColourScheme& getColourScheme() const noexcept    { return colourScheme; }
 | 
			
		||||
 | 
			
		||||
    /** Returns one the syntax highlighting colour for the given token.
 | 
			
		||||
        The token type values are dependent on the tokeniser being used.
 | 
			
		||||
        @see setColourScheme
 | 
			
		||||
    */
 | 
			
		||||
    Colour getColourForTokenType (int tokenType) const;
 | 
			
		||||
 | 
			
		||||
    /** Rebuilds the syntax highlighting for a section of text.
 | 
			
		||||
 | 
			
		||||
        This happens automatically any time the CodeDocument is edited, but this
 | 
			
		||||
        method lets you change text colours even when the CodeDocument hasn't changed.
 | 
			
		||||
 | 
			
		||||
        For example, you could use this to highlight tokens as the cursor moves.
 | 
			
		||||
        To do so you'll need to tell your custom CodeTokeniser where the token you
 | 
			
		||||
        want to highlight is, and make it return a special type of token. Then you
 | 
			
		||||
        should call this method supplying the range of the highlighted text.
 | 
			
		||||
        @see CodeTokeniser
 | 
			
		||||
     */
 | 
			
		||||
    void retokenise (int startIndex, int endIndex);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the editor.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId          = 0x1004500,  /**< A colour to use to fill the editor's background. */
 | 
			
		||||
        highlightColourId           = 0x1004502,  /**< The colour to use for the highlighted background under selected text. */
 | 
			
		||||
        defaultTextColourId         = 0x1004503,  /**< The colour to use for text when no syntax colouring is enabled. */
 | 
			
		||||
        lineNumberBackgroundId      = 0x1004504,  /**< The colour to use for filling the background of the line-number gutter. */
 | 
			
		||||
        lineNumberTextId            = 0x1004505,  /**< The colour to use for drawing the line numbers. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the size of the scrollbars. */
 | 
			
		||||
    void setScrollbarThickness (int thickness);
 | 
			
		||||
 | 
			
		||||
    /** Returns the thickness of the scrollbars. */
 | 
			
		||||
    int getScrollbarThickness() const noexcept          { return scrollbarThickness; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Called when the return key is pressed - this can be overridden for custom behaviour. */
 | 
			
		||||
    virtual void handleReturnKey();
 | 
			
		||||
    /** Called when the tab key is pressed - this can be overridden for custom behaviour. */
 | 
			
		||||
    virtual void handleTabKey();
 | 
			
		||||
    /** Called when the escape key is pressed - this can be overridden for custom behaviour. */
 | 
			
		||||
    virtual void handleEscapeKey();
 | 
			
		||||
 | 
			
		||||
    /** Called when the view position is scrolled horizontally or vertically. */
 | 
			
		||||
    virtual void editorViewportPositionChanged();
 | 
			
		||||
 | 
			
		||||
    /** Called when the caret position moves. */
 | 
			
		||||
    virtual void caretPositionMoved();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This adds the items to the popup menu.
 | 
			
		||||
 | 
			
		||||
        By default it adds the cut/copy/paste items, but you can override this if
 | 
			
		||||
        you need to replace these with your own items.
 | 
			
		||||
 | 
			
		||||
        If you want to add your own items to the existing ones, you can override this,
 | 
			
		||||
        call the base class's addPopupMenuItems() method, then append your own items.
 | 
			
		||||
 | 
			
		||||
        When the menu has been shown, performPopupMenuAction() will be called to
 | 
			
		||||
        perform the item that the user has chosen.
 | 
			
		||||
 | 
			
		||||
        If this was triggered by a mouse-click, the mouseClickEvent parameter will be
 | 
			
		||||
        a pointer to the info about it, or may be null if the menu is being triggered
 | 
			
		||||
        by some other means.
 | 
			
		||||
 | 
			
		||||
        @see performPopupMenuAction, setPopupMenuEnabled, isPopupMenuEnabled
 | 
			
		||||
    */
 | 
			
		||||
    virtual void addPopupMenuItems (PopupMenu& menuToAddTo,
 | 
			
		||||
                                    const MouseEvent* mouseClickEvent);
 | 
			
		||||
 | 
			
		||||
    /** This is called to perform one of the items that was shown on the popup menu.
 | 
			
		||||
 | 
			
		||||
        If you've overridden addPopupMenuItems(), you should also override this
 | 
			
		||||
        to perform the actions that you've added.
 | 
			
		||||
 | 
			
		||||
        If you've overridden addPopupMenuItems() but have still left the default items
 | 
			
		||||
        on the menu, remember to call the superclass's performPopupMenuAction()
 | 
			
		||||
        so that it can perform the default actions if that's what the user clicked on.
 | 
			
		||||
 | 
			
		||||
        @see addPopupMenuItems, setPopupMenuEnabled, isPopupMenuEnabled
 | 
			
		||||
    */
 | 
			
		||||
    virtual void performPopupMenuAction (int menuItemID);
 | 
			
		||||
 | 
			
		||||
    /** Specifies a command-manager which the editor will notify whenever the state
 | 
			
		||||
        of any of its commands changes.
 | 
			
		||||
        If you're making use of the editor's ApplicationCommandTarget interface, then
 | 
			
		||||
        you should also use this to tell it which command manager it should use. Make
 | 
			
		||||
        sure that the manager does not go out of scope while the editor is using it. You
 | 
			
		||||
        can pass a nullptr here to disable this.
 | 
			
		||||
    */
 | 
			
		||||
    void setCommandManager (ApplicationCommandManager* newManager) noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool keyPressed (const KeyPress&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDown (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDrag (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseUp (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDoubleClick (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseWheelMove (const MouseEvent&, const MouseWheelDetails&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void focusGained (FocusChangeType) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void focusLost (FocusChangeType) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool isTextInputActive() const override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void setTemporaryUnderlining (const Array<Range<int>>&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    ApplicationCommandTarget* getNextCommandTarget() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void getAllCommands (Array<CommandID>&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void getCommandInfo (CommandID, ApplicationCommandInfo&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool perform (const InvocationInfo&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void lookAndFeelChanged() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CodeDocument& document;
 | 
			
		||||
 | 
			
		||||
    Font font;
 | 
			
		||||
    int firstLineOnScreen = 0, spacesPerTab = 4;
 | 
			
		||||
    float charWidth = 0;
 | 
			
		||||
    int lineHeight = 0, linesOnScreen = 0, columnsOnScreen = 0;
 | 
			
		||||
    int scrollbarThickness = 16, columnToTryToMaintain = -1;
 | 
			
		||||
    bool readOnly = false, useSpacesForTabs = true, showLineNumbers = false, shouldFollowDocumentChanges = false;
 | 
			
		||||
    double xOffset = 0;
 | 
			
		||||
    CodeDocument::Position caretPos, selectionStart, selectionEnd;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<CaretComponent> caret;
 | 
			
		||||
    ScrollBar verticalScrollBar { true }, horizontalScrollBar { false };
 | 
			
		||||
    ApplicationCommandManager* appCommandManager = nullptr;
 | 
			
		||||
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    class GutterComponent;
 | 
			
		||||
    std::unique_ptr<GutterComponent> gutter;
 | 
			
		||||
 | 
			
		||||
    class CodeEditorAccessibilityHandler;
 | 
			
		||||
 | 
			
		||||
    enum DragType
 | 
			
		||||
    {
 | 
			
		||||
        notDragging,
 | 
			
		||||
        draggingSelectionStart,
 | 
			
		||||
        draggingSelectionEnd
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    DragType dragType = notDragging;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CodeTokeniser* codeTokeniser;
 | 
			
		||||
    ColourScheme colourScheme;
 | 
			
		||||
 | 
			
		||||
    class CodeEditorLine;
 | 
			
		||||
    OwnedArray<CodeEditorLine> lines;
 | 
			
		||||
    void rebuildLineTokens();
 | 
			
		||||
    void rebuildLineTokensAsync();
 | 
			
		||||
    void codeDocumentChanged (int start, int end);
 | 
			
		||||
 | 
			
		||||
    Array<CodeDocument::Iterator> cachedIterators;
 | 
			
		||||
    void clearCachedIterators (int firstLineToBeInvalid);
 | 
			
		||||
    void updateCachedIterators (int maxLineNum);
 | 
			
		||||
    void getIteratorForPosition (int position, CodeDocument::Iterator&);
 | 
			
		||||
 | 
			
		||||
    void moveLineDelta (int delta, bool selecting);
 | 
			
		||||
    int getGutterSize() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
    void insertText (const String&);
 | 
			
		||||
    virtual void updateCaretPosition();
 | 
			
		||||
    void updateScrollBars();
 | 
			
		||||
    void scrollToLineInternal (int line);
 | 
			
		||||
    void scrollToColumnInternal (double column);
 | 
			
		||||
    void newTransaction();
 | 
			
		||||
    void cut();
 | 
			
		||||
    void indentSelectedLines (int spacesToAdd);
 | 
			
		||||
    bool skipBackwardsToPreviousTab();
 | 
			
		||||
    bool performCommand (CommandID);
 | 
			
		||||
    void setSelection (CodeDocument::Position, CodeDocument::Position);
 | 
			
		||||
 | 
			
		||||
    int indexToColumn (int line, int index) const noexcept;
 | 
			
		||||
    int columnToIndex (int line, int column) const noexcept;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeEditorComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class CodeTokeniser;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A text editor component designed specifically for source code.
 | 
			
		||||
 | 
			
		||||
    This is designed to handle syntax highlighting and fast editing of very large
 | 
			
		||||
    files.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CodeEditorComponent   : public Component,
 | 
			
		||||
                                        public ApplicationCommandTarget,
 | 
			
		||||
                                        public TextInputTarget
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an editor for a document.
 | 
			
		||||
 | 
			
		||||
        The tokeniser object is optional - pass nullptr to disable syntax highlighting.
 | 
			
		||||
        The object that you pass in is not owned or deleted by the editor - you must
 | 
			
		||||
        make sure that it doesn't get deleted while this component is still using it.
 | 
			
		||||
 | 
			
		||||
        @see CodeDocument
 | 
			
		||||
    */
 | 
			
		||||
    CodeEditorComponent (CodeDocument& document,
 | 
			
		||||
                         CodeTokeniser* codeTokeniser);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~CodeEditorComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the code document that this component is editing. */
 | 
			
		||||
    CodeDocument& getDocument() const noexcept          { return document; }
 | 
			
		||||
 | 
			
		||||
    /** Loads the given content into the document.
 | 
			
		||||
        This will completely reset the CodeDocument object, clear its undo history,
 | 
			
		||||
        and fill it with this text.
 | 
			
		||||
    */
 | 
			
		||||
    void loadContent (const String& newContent);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the standard character width. */
 | 
			
		||||
    float getCharWidth() const noexcept                         { return charWidth; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the height of a line of text, in pixels. */
 | 
			
		||||
    int getLineHeight() const noexcept                          { return lineHeight; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of whole lines visible on the screen,
 | 
			
		||||
        This doesn't include a cut-off line that might be visible at the bottom if the
 | 
			
		||||
        component's height isn't an exact multiple of the line-height.
 | 
			
		||||
    */
 | 
			
		||||
    int getNumLinesOnScreen() const noexcept                    { return linesOnScreen; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the index of the first line that's visible at the top of the editor. */
 | 
			
		||||
    int getFirstLineOnScreen() const noexcept                   { return firstLineOnScreen; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of whole columns visible on the screen.
 | 
			
		||||
        This doesn't include any cut-off columns at the right-hand edge.
 | 
			
		||||
    */
 | 
			
		||||
    int getNumColumnsOnScreen() const noexcept                  { return columnsOnScreen; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the current caret position. */
 | 
			
		||||
    CodeDocument::Position getCaretPos() const                  { return caretPos; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the total number of codepoints in the string. */
 | 
			
		||||
    int getTotalNumChars() const override                       { return document.getNumCharacters(); }
 | 
			
		||||
 | 
			
		||||
    /** Moves the caret.
 | 
			
		||||
        If selecting is true, the section of the document between the current
 | 
			
		||||
        caret position and the new one will become selected. If false, any currently
 | 
			
		||||
        selected region will be deselected.
 | 
			
		||||
    */
 | 
			
		||||
    void moveCaretTo (const CodeDocument::Position& newPos, bool selecting);
 | 
			
		||||
 | 
			
		||||
    /** Returns the on-screen position of a character in the document.
 | 
			
		||||
        The rectangle returned is relative to this component's top-left origin.
 | 
			
		||||
    */
 | 
			
		||||
    Rectangle<int> getCharacterBounds (const CodeDocument::Position& pos) const;
 | 
			
		||||
 | 
			
		||||
    /** Finds the character at a given on-screen position.
 | 
			
		||||
        The coordinates are relative to this component's top-left origin.
 | 
			
		||||
    */
 | 
			
		||||
    CodeDocument::Position getPositionAt (int x, int y) const;
 | 
			
		||||
 | 
			
		||||
    /** Returns the start of the selection as a position. */
 | 
			
		||||
    CodeDocument::Position getSelectionStart() const            { return selectionStart; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the end of the selection as a position. */
 | 
			
		||||
    CodeDocument::Position getSelectionEnd() const              { return selectionEnd; }
 | 
			
		||||
 | 
			
		||||
    /** Enables or disables the line-number display in the gutter. */
 | 
			
		||||
    void setLineNumbersShown (bool shouldBeShown);
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of characters from the beginning of the document to the caret. */
 | 
			
		||||
    int getCaretPosition() const override       { return getCaretPos().getPosition(); }
 | 
			
		||||
 | 
			
		||||
    /** @see getPositionAt */
 | 
			
		||||
    int getCharIndexForPoint (Point<int> point) const override;
 | 
			
		||||
 | 
			
		||||
    /** Returns the bounds of the caret at a particular location in the text. */
 | 
			
		||||
    Rectangle<int> getCaretRectangleForCharIndex (int index) const override
 | 
			
		||||
    {
 | 
			
		||||
        return getCharacterBounds ({ document, index });
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /** Returns the bounding box for a range of text in the editor. As the range may span
 | 
			
		||||
        multiple lines, this method returns a RectangleList.
 | 
			
		||||
 | 
			
		||||
        The bounds are relative to the component's top-left and may extend beyond the bounds
 | 
			
		||||
        of the component if the text is long and word wrapping is disabled.
 | 
			
		||||
    */
 | 
			
		||||
    RectangleList<int> getTextBounds (Range<int> textRange) const override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    bool moveCaretLeft (bool moveInWholeWordSteps, bool selecting);
 | 
			
		||||
    bool moveCaretRight (bool moveInWholeWordSteps, bool selecting);
 | 
			
		||||
    bool moveCaretUp (bool selecting);
 | 
			
		||||
    bool moveCaretDown (bool selecting);
 | 
			
		||||
    bool scrollDown();
 | 
			
		||||
    bool scrollUp();
 | 
			
		||||
    bool pageUp (bool selecting);
 | 
			
		||||
    bool pageDown (bool selecting);
 | 
			
		||||
    bool moveCaretToTop (bool selecting);
 | 
			
		||||
    bool moveCaretToStartOfLine (bool selecting);
 | 
			
		||||
    bool moveCaretToEnd (bool selecting);
 | 
			
		||||
    bool moveCaretToEndOfLine (bool selecting);
 | 
			
		||||
    bool deleteBackwards (bool moveInWholeWordSteps);
 | 
			
		||||
    bool deleteForwards (bool moveInWholeWordSteps);
 | 
			
		||||
    bool deleteWhitespaceBackwardsToTabStop();
 | 
			
		||||
    virtual bool copyToClipboard();
 | 
			
		||||
    virtual bool cutToClipboard();
 | 
			
		||||
    virtual bool pasteFromClipboard();
 | 
			
		||||
    bool undo();
 | 
			
		||||
    bool redo();
 | 
			
		||||
 | 
			
		||||
    void selectRegion (const CodeDocument::Position& start, const CodeDocument::Position& end);
 | 
			
		||||
    bool selectAll();
 | 
			
		||||
    void deselectAll();
 | 
			
		||||
 | 
			
		||||
    void scrollToLine (int newFirstLineOnScreen);
 | 
			
		||||
    void scrollBy (int deltaLines);
 | 
			
		||||
    void scrollToColumn (int newFirstColumnOnScreen);
 | 
			
		||||
    void scrollToKeepCaretOnScreen();
 | 
			
		||||
    void scrollToKeepLinesOnScreen (Range<int> linesToShow);
 | 
			
		||||
 | 
			
		||||
    void insertTextAtCaret (const String& textToInsert) override;
 | 
			
		||||
    void insertTabAtCaret();
 | 
			
		||||
 | 
			
		||||
    void indentSelection();
 | 
			
		||||
    void unindentSelection();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Range<int> getHighlightedRegion() const override;
 | 
			
		||||
    bool isHighlightActive() const noexcept;
 | 
			
		||||
    void setHighlightedRegion (const Range<int>& newRange) override;
 | 
			
		||||
    String getTextInRange (const Range<int>& range) const override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Can be used to save and restore the editor's caret position, selection state, etc. */
 | 
			
		||||
    struct State
 | 
			
		||||
    {
 | 
			
		||||
        /** Creates an object containing the state of the given editor. */
 | 
			
		||||
        State (const CodeEditorComponent&);
 | 
			
		||||
        /** Creates a state object from a string that was previously created with toString(). */
 | 
			
		||||
        State (const String& stringifiedVersion);
 | 
			
		||||
        State (const State&) noexcept;
 | 
			
		||||
 | 
			
		||||
        /** Updates the given editor with this saved state. */
 | 
			
		||||
        void restoreState (CodeEditorComponent&) const;
 | 
			
		||||
 | 
			
		||||
        /** Returns a stringified version of this state that can be used to recreate it later. */
 | 
			
		||||
        String toString() const;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        int lastTopLine, lastCaretPos, lastSelectionEnd;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the current tab settings.
 | 
			
		||||
        This lets you change the tab size and whether pressing the tab key inserts a
 | 
			
		||||
        tab character, or its equivalent number of spaces.
 | 
			
		||||
    */
 | 
			
		||||
    void setTabSize (int numSpacesPerTab, bool insertSpacesInsteadOfTabCharacters);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current number of spaces per tab.
 | 
			
		||||
        @see setTabSize
 | 
			
		||||
    */
 | 
			
		||||
    int getTabSize() const noexcept                     { return spacesPerTab; }
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the tab key will insert spaces instead of actual tab characters.
 | 
			
		||||
        @see setTabSize
 | 
			
		||||
    */
 | 
			
		||||
    bool areSpacesInsertedForTabs() const               { return useSpacesForTabs; }
 | 
			
		||||
 | 
			
		||||
    /** Returns a string containing spaces or tab characters to generate the given number of spaces. */
 | 
			
		||||
    String getTabString (int numSpaces) const;
 | 
			
		||||
 | 
			
		||||
    /** Changes the font.
 | 
			
		||||
        Make sure you only use a fixed-width font, or this component will look pretty nasty!
 | 
			
		||||
    */
 | 
			
		||||
    void setFont (const Font& newFont);
 | 
			
		||||
 | 
			
		||||
    /** Returns the font that the editor is using. */
 | 
			
		||||
    const Font& getFont() const noexcept                { return font; }
 | 
			
		||||
 | 
			
		||||
    /** Makes the editor read-only. */
 | 
			
		||||
    void setReadOnly (bool shouldBeReadOnly) noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the editor is set to be read-only. */
 | 
			
		||||
    bool isReadOnly() const noexcept                    { return readOnly; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Defines a syntax highlighting colour scheme */
 | 
			
		||||
    struct JUCE_API  ColourScheme
 | 
			
		||||
    {
 | 
			
		||||
        /** Defines a colour for a token type */
 | 
			
		||||
        struct TokenType
 | 
			
		||||
        {
 | 
			
		||||
            String name;
 | 
			
		||||
            Colour colour;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        Array<TokenType> types;
 | 
			
		||||
 | 
			
		||||
        void set (const String& name, Colour colour);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /** Changes the syntax highlighting scheme.
 | 
			
		||||
        The token type values are dependent on the tokeniser being used - use
 | 
			
		||||
        CodeTokeniser::getTokenTypes() to get a list of the token types.
 | 
			
		||||
        @see getColourForTokenType
 | 
			
		||||
    */
 | 
			
		||||
    void setColourScheme (const ColourScheme& scheme);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current syntax highlighting colour scheme. */
 | 
			
		||||
    const ColourScheme& getColourScheme() const noexcept    { return colourScheme; }
 | 
			
		||||
 | 
			
		||||
    /** Returns one the syntax highlighting colour for the given token.
 | 
			
		||||
        The token type values are dependent on the tokeniser being used.
 | 
			
		||||
        @see setColourScheme
 | 
			
		||||
    */
 | 
			
		||||
    Colour getColourForTokenType (int tokenType) const;
 | 
			
		||||
 | 
			
		||||
    /** Rebuilds the syntax highlighting for a section of text.
 | 
			
		||||
 | 
			
		||||
        This happens automatically any time the CodeDocument is edited, but this
 | 
			
		||||
        method lets you change text colours even when the CodeDocument hasn't changed.
 | 
			
		||||
 | 
			
		||||
        For example, you could use this to highlight tokens as the cursor moves.
 | 
			
		||||
        To do so you'll need to tell your custom CodeTokeniser where the token you
 | 
			
		||||
        want to highlight is, and make it return a special type of token. Then you
 | 
			
		||||
        should call this method supplying the range of the highlighted text.
 | 
			
		||||
        @see CodeTokeniser
 | 
			
		||||
     */
 | 
			
		||||
    void retokenise (int startIndex, int endIndex);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the editor.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId          = 0x1004500,  /**< A colour to use to fill the editor's background. */
 | 
			
		||||
        highlightColourId           = 0x1004502,  /**< The colour to use for the highlighted background under selected text. */
 | 
			
		||||
        defaultTextColourId         = 0x1004503,  /**< The colour to use for text when no syntax colouring is enabled. */
 | 
			
		||||
        lineNumberBackgroundId      = 0x1004504,  /**< The colour to use for filling the background of the line-number gutter. */
 | 
			
		||||
        lineNumberTextId            = 0x1004505,  /**< The colour to use for drawing the line numbers. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the size of the scrollbars. */
 | 
			
		||||
    void setScrollbarThickness (int thickness);
 | 
			
		||||
 | 
			
		||||
    /** Returns the thickness of the scrollbars. */
 | 
			
		||||
    int getScrollbarThickness() const noexcept          { return scrollbarThickness; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Called when the return key is pressed - this can be overridden for custom behaviour. */
 | 
			
		||||
    virtual void handleReturnKey();
 | 
			
		||||
    /** Called when the tab key is pressed - this can be overridden for custom behaviour. */
 | 
			
		||||
    virtual void handleTabKey();
 | 
			
		||||
    /** Called when the escape key is pressed - this can be overridden for custom behaviour. */
 | 
			
		||||
    virtual void handleEscapeKey();
 | 
			
		||||
 | 
			
		||||
    /** Called when the view position is scrolled horizontally or vertically. */
 | 
			
		||||
    virtual void editorViewportPositionChanged();
 | 
			
		||||
 | 
			
		||||
    /** Called when the caret position moves. */
 | 
			
		||||
    virtual void caretPositionMoved();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This adds the items to the popup menu.
 | 
			
		||||
 | 
			
		||||
        By default it adds the cut/copy/paste items, but you can override this if
 | 
			
		||||
        you need to replace these with your own items.
 | 
			
		||||
 | 
			
		||||
        If you want to add your own items to the existing ones, you can override this,
 | 
			
		||||
        call the base class's addPopupMenuItems() method, then append your own items.
 | 
			
		||||
 | 
			
		||||
        When the menu has been shown, performPopupMenuAction() will be called to
 | 
			
		||||
        perform the item that the user has chosen.
 | 
			
		||||
 | 
			
		||||
        If this was triggered by a mouse-click, the mouseClickEvent parameter will be
 | 
			
		||||
        a pointer to the info about it, or may be null if the menu is being triggered
 | 
			
		||||
        by some other means.
 | 
			
		||||
 | 
			
		||||
        @see performPopupMenuAction, setPopupMenuEnabled, isPopupMenuEnabled
 | 
			
		||||
    */
 | 
			
		||||
    virtual void addPopupMenuItems (PopupMenu& menuToAddTo,
 | 
			
		||||
                                    const MouseEvent* mouseClickEvent);
 | 
			
		||||
 | 
			
		||||
    /** This is called to perform one of the items that was shown on the popup menu.
 | 
			
		||||
 | 
			
		||||
        If you've overridden addPopupMenuItems(), you should also override this
 | 
			
		||||
        to perform the actions that you've added.
 | 
			
		||||
 | 
			
		||||
        If you've overridden addPopupMenuItems() but have still left the default items
 | 
			
		||||
        on the menu, remember to call the superclass's performPopupMenuAction()
 | 
			
		||||
        so that it can perform the default actions if that's what the user clicked on.
 | 
			
		||||
 | 
			
		||||
        @see addPopupMenuItems, setPopupMenuEnabled, isPopupMenuEnabled
 | 
			
		||||
    */
 | 
			
		||||
    virtual void performPopupMenuAction (int menuItemID);
 | 
			
		||||
 | 
			
		||||
    /** Specifies a command-manager which the editor will notify whenever the state
 | 
			
		||||
        of any of its commands changes.
 | 
			
		||||
        If you're making use of the editor's ApplicationCommandTarget interface, then
 | 
			
		||||
        you should also use this to tell it which command manager it should use. Make
 | 
			
		||||
        sure that the manager does not go out of scope while the editor is using it. You
 | 
			
		||||
        can pass a nullptr here to disable this.
 | 
			
		||||
    */
 | 
			
		||||
    void setCommandManager (ApplicationCommandManager* newManager) noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool keyPressed (const KeyPress&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDown (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDrag (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseUp (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseDoubleClick (const MouseEvent&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void mouseWheelMove (const MouseEvent&, const MouseWheelDetails&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void focusGained (FocusChangeType) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void focusLost (FocusChangeType) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool isTextInputActive() const override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void setTemporaryUnderlining (const Array<Range<int>>&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    ApplicationCommandTarget* getNextCommandTarget() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void getAllCommands (Array<CommandID>&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void getCommandInfo (CommandID, ApplicationCommandInfo&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    bool perform (const InvocationInfo&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void lookAndFeelChanged() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CodeDocument& document;
 | 
			
		||||
 | 
			
		||||
    Font font;
 | 
			
		||||
    int firstLineOnScreen = 0, spacesPerTab = 4;
 | 
			
		||||
    float charWidth = 0;
 | 
			
		||||
    int lineHeight = 0, linesOnScreen = 0, columnsOnScreen = 0;
 | 
			
		||||
    int scrollbarThickness = 16, columnToTryToMaintain = -1;
 | 
			
		||||
    bool readOnly = false, useSpacesForTabs = true, showLineNumbers = false, shouldFollowDocumentChanges = false;
 | 
			
		||||
    double xOffset = 0;
 | 
			
		||||
    CodeDocument::Position caretPos, selectionStart, selectionEnd;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<CaretComponent> caret;
 | 
			
		||||
    ScrollBar verticalScrollBar { true }, horizontalScrollBar { false };
 | 
			
		||||
    ApplicationCommandManager* appCommandManager = nullptr;
 | 
			
		||||
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    class GutterComponent;
 | 
			
		||||
    std::unique_ptr<GutterComponent> gutter;
 | 
			
		||||
 | 
			
		||||
    class CodeEditorAccessibilityHandler;
 | 
			
		||||
 | 
			
		||||
    enum DragType
 | 
			
		||||
    {
 | 
			
		||||
        notDragging,
 | 
			
		||||
        draggingSelectionStart,
 | 
			
		||||
        draggingSelectionEnd
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    DragType dragType = notDragging;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    CodeTokeniser* codeTokeniser;
 | 
			
		||||
    ColourScheme colourScheme;
 | 
			
		||||
 | 
			
		||||
    class CodeEditorLine;
 | 
			
		||||
    OwnedArray<CodeEditorLine> lines;
 | 
			
		||||
    void rebuildLineTokens();
 | 
			
		||||
    void rebuildLineTokensAsync();
 | 
			
		||||
    void codeDocumentChanged (int start, int end);
 | 
			
		||||
 | 
			
		||||
    Array<CodeDocument::Iterator> cachedIterators;
 | 
			
		||||
    void clearCachedIterators (int firstLineToBeInvalid);
 | 
			
		||||
    void updateCachedIterators (int maxLineNum);
 | 
			
		||||
    void getIteratorForPosition (int position, CodeDocument::Iterator&);
 | 
			
		||||
 | 
			
		||||
    void moveLineDelta (int delta, bool selecting);
 | 
			
		||||
    int getGutterSize() const noexcept;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override;
 | 
			
		||||
    void insertText (const String&);
 | 
			
		||||
    virtual void updateCaretPosition();
 | 
			
		||||
    void updateScrollBars();
 | 
			
		||||
    void scrollToLineInternal (int line);
 | 
			
		||||
    void scrollToColumnInternal (double column);
 | 
			
		||||
    void newTransaction();
 | 
			
		||||
    void cut();
 | 
			
		||||
    void indentSelectedLines (int spacesToAdd);
 | 
			
		||||
    bool skipBackwardsToPreviousTab();
 | 
			
		||||
    bool performCommand (CommandID);
 | 
			
		||||
    void setSelection (CodeDocument::Position, CodeDocument::Position);
 | 
			
		||||
 | 
			
		||||
    int indexToColumn (int line, int index) const noexcept;
 | 
			
		||||
    int columnToIndex (int line, int column) const noexcept;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CodeEditorComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,59 +1,59 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for tokenising code so that the syntax can be displayed in a
 | 
			
		||||
    code editor.
 | 
			
		||||
 | 
			
		||||
    @see CodeDocument, CodeEditorComponent
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CodeTokeniser
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CodeTokeniser() = default;
 | 
			
		||||
    virtual ~CodeTokeniser() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Reads the next token from the source and returns its token type.
 | 
			
		||||
 | 
			
		||||
        This must leave the source pointing to the first character in the
 | 
			
		||||
        next token.
 | 
			
		||||
    */
 | 
			
		||||
    virtual int readNextToken (CodeDocument::Iterator& source) = 0;
 | 
			
		||||
 | 
			
		||||
    /** Returns a suggested syntax highlighting colour scheme. */
 | 
			
		||||
    virtual CodeEditorComponent::ColourScheme getDefaultColourScheme() = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_LEAK_DETECTOR (CodeTokeniser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for tokenising code so that the syntax can be displayed in a
 | 
			
		||||
    code editor.
 | 
			
		||||
 | 
			
		||||
    @see CodeDocument, CodeEditorComponent
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  CodeTokeniser
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CodeTokeniser() = default;
 | 
			
		||||
    virtual ~CodeTokeniser() = default;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Reads the next token from the source and returns its token type.
 | 
			
		||||
 | 
			
		||||
        This must leave the source pointing to the first character in the
 | 
			
		||||
        next token.
 | 
			
		||||
    */
 | 
			
		||||
    virtual int readNextToken (CodeDocument::Iterator& source) = 0;
 | 
			
		||||
 | 
			
		||||
    /** Returns a suggested syntax highlighting colour scheme. */
 | 
			
		||||
    virtual CodeEditorComponent::ColourScheme getDefaultColourScheme() = 0;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_LEAK_DETECTOR (CodeTokeniser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,239 +1,239 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
struct LuaTokeniserFunctions
 | 
			
		||||
{
 | 
			
		||||
    static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        static const char* const keywords2Char[] =
 | 
			
		||||
            { "if", "or", "in", "do", nullptr };
 | 
			
		||||
 | 
			
		||||
        static const char* const keywords3Char[] =
 | 
			
		||||
            { "and", "end", "for", "nil", "not", nullptr };
 | 
			
		||||
 | 
			
		||||
        static const char* const keywords4Char[] =
 | 
			
		||||
            { "then", "true", "else", nullptr };
 | 
			
		||||
 | 
			
		||||
        static const char* const keywords5Char[] =
 | 
			
		||||
            {  "false", "local", "until", "while", "break", nullptr };
 | 
			
		||||
 | 
			
		||||
        static const char* const keywords6Char[] =
 | 
			
		||||
            { "repeat", "return", "elseif", nullptr};
 | 
			
		||||
 | 
			
		||||
        static const char* const keywordsOther[] =
 | 
			
		||||
            { "function", "@interface", "@end", "@synthesize", "@dynamic", "@public",
 | 
			
		||||
              "@private", "@property", "@protected", "@class", nullptr };
 | 
			
		||||
 | 
			
		||||
        const char* const* k;
 | 
			
		||||
 | 
			
		||||
        switch (tokenLength)
 | 
			
		||||
        {
 | 
			
		||||
            case 2:   k = keywords2Char; break;
 | 
			
		||||
            case 3:   k = keywords3Char; break;
 | 
			
		||||
            case 4:   k = keywords4Char; break;
 | 
			
		||||
            case 5:   k = keywords5Char; break;
 | 
			
		||||
            case 6:   k = keywords6Char; break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                if (tokenLength < 2 || tokenLength > 16)
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
                k = keywordsOther;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; k[i] != nullptr; ++i)
 | 
			
		||||
            if (token.compare (CharPointer_ASCII (k[i])) == 0)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Iterator>
 | 
			
		||||
    static int parseIdentifier (Iterator& source) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        int tokenLength = 0;
 | 
			
		||||
        String::CharPointerType::CharType possibleIdentifier[100];
 | 
			
		||||
        String::CharPointerType possible (possibleIdentifier);
 | 
			
		||||
 | 
			
		||||
        while (CppTokeniserFunctions::isIdentifierBody (source.peekNextChar()))
 | 
			
		||||
        {
 | 
			
		||||
            auto c = source.nextChar();
 | 
			
		||||
 | 
			
		||||
            if (tokenLength < 20)
 | 
			
		||||
                possible.write (c);
 | 
			
		||||
 | 
			
		||||
            ++tokenLength;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (tokenLength > 1 && tokenLength <= 16)
 | 
			
		||||
        {
 | 
			
		||||
            possible.writeNull();
 | 
			
		||||
 | 
			
		||||
            if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength))
 | 
			
		||||
                return LuaTokeniser::tokenType_keyword;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return LuaTokeniser::tokenType_identifier;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Iterator>
 | 
			
		||||
    static int readNextToken (Iterator& source)
 | 
			
		||||
    {
 | 
			
		||||
        source.skipWhitespace();
 | 
			
		||||
 | 
			
		||||
        auto firstChar = source.peekNextChar();
 | 
			
		||||
 | 
			
		||||
        switch (firstChar)
 | 
			
		||||
        {
 | 
			
		||||
        case 0:
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case '0':   case '1':   case '2':   case '3':   case '4':
 | 
			
		||||
        case '5':   case '6':   case '7':   case '8':   case '9':
 | 
			
		||||
        case '.':
 | 
			
		||||
        {
 | 
			
		||||
            auto result = CppTokeniserFunctions::parseNumber (source);
 | 
			
		||||
 | 
			
		||||
            if (result == LuaTokeniser::tokenType_error)
 | 
			
		||||
            {
 | 
			
		||||
                source.skip();
 | 
			
		||||
 | 
			
		||||
                if (firstChar == '.')
 | 
			
		||||
                    return LuaTokeniser::tokenType_punctuation;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case ',':
 | 
			
		||||
        case ';':
 | 
			
		||||
        case ':':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return LuaTokeniser::tokenType_punctuation;
 | 
			
		||||
 | 
			
		||||
        case '(':   case ')':
 | 
			
		||||
        case '{':   case '}':
 | 
			
		||||
        case '[':   case ']':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return LuaTokeniser::tokenType_bracket;
 | 
			
		||||
 | 
			
		||||
        case '"':
 | 
			
		||||
        case '\'':
 | 
			
		||||
            CppTokeniserFunctions::skipQuotedString (source);
 | 
			
		||||
            return LuaTokeniser::tokenType_string;
 | 
			
		||||
 | 
			
		||||
        case '+':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '+', '=');
 | 
			
		||||
            return LuaTokeniser::tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        case '-':
 | 
			
		||||
        {
 | 
			
		||||
            source.skip();
 | 
			
		||||
            auto result = CppTokeniserFunctions::parseNumber (source);
 | 
			
		||||
 | 
			
		||||
            if (source.peekNextChar() == '-')
 | 
			
		||||
            {
 | 
			
		||||
                source.skipToEndOfLine();
 | 
			
		||||
                return LuaTokeniser::tokenType_comment;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result == LuaTokeniser::tokenType_error)
 | 
			
		||||
            {
 | 
			
		||||
                CppTokeniserFunctions::skipIfNextCharMatches (source, '-', '=');
 | 
			
		||||
                return LuaTokeniser::tokenType_operator;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case '*':   case '%':
 | 
			
		||||
        case '=':   case '!':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
 | 
			
		||||
            return LuaTokeniser::tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        case '?':
 | 
			
		||||
        case '~':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return LuaTokeniser::tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        case '<':   case '>':
 | 
			
		||||
        case '|':   case '&':   case '^':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, firstChar);
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
 | 
			
		||||
            return LuaTokeniser::tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            if (CppTokeniserFunctions::isIdentifierStart (firstChar))
 | 
			
		||||
                return parseIdentifier (source);
 | 
			
		||||
 | 
			
		||||
            source.skip();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return LuaTokeniser::tokenType_error;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
LuaTokeniser::LuaTokeniser() {}
 | 
			
		||||
LuaTokeniser::~LuaTokeniser() {}
 | 
			
		||||
 | 
			
		||||
int LuaTokeniser::readNextToken (CodeDocument::Iterator& source)
 | 
			
		||||
{
 | 
			
		||||
    return LuaTokeniserFunctions::readNextToken (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CodeEditorComponent::ColourScheme LuaTokeniser::getDefaultColourScheme()
 | 
			
		||||
{
 | 
			
		||||
    static const CodeEditorComponent::ColourScheme::TokenType types[] =
 | 
			
		||||
    {
 | 
			
		||||
        { "Error",          Colour (0xffcc0000) },
 | 
			
		||||
        { "Comment",        Colour (0xff3c3c3c) },
 | 
			
		||||
        { "Keyword",        Colour (0xff0000cc) },
 | 
			
		||||
        { "Operator",       Colour (0xff225500) },
 | 
			
		||||
        { "Identifier",     Colour (0xff000000) },
 | 
			
		||||
        { "Integer",        Colour (0xff880000) },
 | 
			
		||||
        { "Float",          Colour (0xff885500) },
 | 
			
		||||
        { "String",         Colour (0xff990099) },
 | 
			
		||||
        { "Bracket",        Colour (0xff000055) },
 | 
			
		||||
        { "Punctuation",    Colour (0xff004400) }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CodeEditorComponent::ColourScheme cs;
 | 
			
		||||
 | 
			
		||||
    for (auto& t : types)
 | 
			
		||||
        cs.set (t.name, Colour (t.colour));
 | 
			
		||||
 | 
			
		||||
    return cs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
struct LuaTokeniserFunctions
 | 
			
		||||
{
 | 
			
		||||
    static bool isReservedKeyword (String::CharPointerType token, const int tokenLength) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        static const char* const keywords2Char[] =
 | 
			
		||||
            { "if", "or", "in", "do", nullptr };
 | 
			
		||||
 | 
			
		||||
        static const char* const keywords3Char[] =
 | 
			
		||||
            { "and", "end", "for", "nil", "not", nullptr };
 | 
			
		||||
 | 
			
		||||
        static const char* const keywords4Char[] =
 | 
			
		||||
            { "then", "true", "else", nullptr };
 | 
			
		||||
 | 
			
		||||
        static const char* const keywords5Char[] =
 | 
			
		||||
            {  "false", "local", "until", "while", "break", nullptr };
 | 
			
		||||
 | 
			
		||||
        static const char* const keywords6Char[] =
 | 
			
		||||
            { "repeat", "return", "elseif", nullptr};
 | 
			
		||||
 | 
			
		||||
        static const char* const keywordsOther[] =
 | 
			
		||||
            { "function", "@interface", "@end", "@synthesize", "@dynamic", "@public",
 | 
			
		||||
              "@private", "@property", "@protected", "@class", nullptr };
 | 
			
		||||
 | 
			
		||||
        const char* const* k;
 | 
			
		||||
 | 
			
		||||
        switch (tokenLength)
 | 
			
		||||
        {
 | 
			
		||||
            case 2:   k = keywords2Char; break;
 | 
			
		||||
            case 3:   k = keywords3Char; break;
 | 
			
		||||
            case 4:   k = keywords4Char; break;
 | 
			
		||||
            case 5:   k = keywords5Char; break;
 | 
			
		||||
            case 6:   k = keywords6Char; break;
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                if (tokenLength < 2 || tokenLength > 16)
 | 
			
		||||
                    return false;
 | 
			
		||||
 | 
			
		||||
                k = keywordsOther;
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; k[i] != nullptr; ++i)
 | 
			
		||||
            if (token.compare (CharPointer_ASCII (k[i])) == 0)
 | 
			
		||||
                return true;
 | 
			
		||||
 | 
			
		||||
        return false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Iterator>
 | 
			
		||||
    static int parseIdentifier (Iterator& source) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        int tokenLength = 0;
 | 
			
		||||
        String::CharPointerType::CharType possibleIdentifier[100] = {};
 | 
			
		||||
        String::CharPointerType possible (possibleIdentifier);
 | 
			
		||||
 | 
			
		||||
        while (CppTokeniserFunctions::isIdentifierBody (source.peekNextChar()))
 | 
			
		||||
        {
 | 
			
		||||
            auto c = source.nextChar();
 | 
			
		||||
 | 
			
		||||
            if (tokenLength < 20)
 | 
			
		||||
                possible.write (c);
 | 
			
		||||
 | 
			
		||||
            ++tokenLength;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (tokenLength > 1 && tokenLength <= 16)
 | 
			
		||||
        {
 | 
			
		||||
            possible.writeNull();
 | 
			
		||||
 | 
			
		||||
            if (isReservedKeyword (String::CharPointerType (possibleIdentifier), tokenLength))
 | 
			
		||||
                return LuaTokeniser::tokenType_keyword;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return LuaTokeniser::tokenType_identifier;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Iterator>
 | 
			
		||||
    static int readNextToken (Iterator& source)
 | 
			
		||||
    {
 | 
			
		||||
        source.skipWhitespace();
 | 
			
		||||
 | 
			
		||||
        auto firstChar = source.peekNextChar();
 | 
			
		||||
 | 
			
		||||
        switch (firstChar)
 | 
			
		||||
        {
 | 
			
		||||
        case 0:
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        case '0':   case '1':   case '2':   case '3':   case '4':
 | 
			
		||||
        case '5':   case '6':   case '7':   case '8':   case '9':
 | 
			
		||||
        case '.':
 | 
			
		||||
        {
 | 
			
		||||
            auto result = CppTokeniserFunctions::parseNumber (source);
 | 
			
		||||
 | 
			
		||||
            if (result == LuaTokeniser::tokenType_error)
 | 
			
		||||
            {
 | 
			
		||||
                source.skip();
 | 
			
		||||
 | 
			
		||||
                if (firstChar == '.')
 | 
			
		||||
                    return LuaTokeniser::tokenType_punctuation;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case ',':
 | 
			
		||||
        case ';':
 | 
			
		||||
        case ':':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return LuaTokeniser::tokenType_punctuation;
 | 
			
		||||
 | 
			
		||||
        case '(':   case ')':
 | 
			
		||||
        case '{':   case '}':
 | 
			
		||||
        case '[':   case ']':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return LuaTokeniser::tokenType_bracket;
 | 
			
		||||
 | 
			
		||||
        case '"':
 | 
			
		||||
        case '\'':
 | 
			
		||||
            CppTokeniserFunctions::skipQuotedString (source);
 | 
			
		||||
            return LuaTokeniser::tokenType_string;
 | 
			
		||||
 | 
			
		||||
        case '+':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '+', '=');
 | 
			
		||||
            return LuaTokeniser::tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        case '-':
 | 
			
		||||
        {
 | 
			
		||||
            source.skip();
 | 
			
		||||
            auto result = CppTokeniserFunctions::parseNumber (source);
 | 
			
		||||
 | 
			
		||||
            if (source.peekNextChar() == '-')
 | 
			
		||||
            {
 | 
			
		||||
                source.skipToEndOfLine();
 | 
			
		||||
                return LuaTokeniser::tokenType_comment;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (result == LuaTokeniser::tokenType_error)
 | 
			
		||||
            {
 | 
			
		||||
                CppTokeniserFunctions::skipIfNextCharMatches (source, '-', '=');
 | 
			
		||||
                return LuaTokeniser::tokenType_operator;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return result;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case '*':   case '%':
 | 
			
		||||
        case '=':   case '!':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
 | 
			
		||||
            return LuaTokeniser::tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        case '?':
 | 
			
		||||
        case '~':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return LuaTokeniser::tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        case '<':   case '>':
 | 
			
		||||
        case '|':   case '&':   case '^':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, firstChar);
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '=');
 | 
			
		||||
            return LuaTokeniser::tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            if (CppTokeniserFunctions::isIdentifierStart (firstChar))
 | 
			
		||||
                return parseIdentifier (source);
 | 
			
		||||
 | 
			
		||||
            source.skip();
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return LuaTokeniser::tokenType_error;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
LuaTokeniser::LuaTokeniser() {}
 | 
			
		||||
LuaTokeniser::~LuaTokeniser() {}
 | 
			
		||||
 | 
			
		||||
int LuaTokeniser::readNextToken (CodeDocument::Iterator& source)
 | 
			
		||||
{
 | 
			
		||||
    return LuaTokeniserFunctions::readNextToken (source);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CodeEditorComponent::ColourScheme LuaTokeniser::getDefaultColourScheme()
 | 
			
		||||
{
 | 
			
		||||
    static const CodeEditorComponent::ColourScheme::TokenType types[] =
 | 
			
		||||
    {
 | 
			
		||||
        { "Error",          Colour (0xffcc0000) },
 | 
			
		||||
        { "Comment",        Colour (0xff3c3c3c) },
 | 
			
		||||
        { "Keyword",        Colour (0xff0000cc) },
 | 
			
		||||
        { "Operator",       Colour (0xff225500) },
 | 
			
		||||
        { "Identifier",     Colour (0xff000000) },
 | 
			
		||||
        { "Integer",        Colour (0xff880000) },
 | 
			
		||||
        { "Float",          Colour (0xff885500) },
 | 
			
		||||
        { "String",         Colour (0xff990099) },
 | 
			
		||||
        { "Bracket",        Colour (0xff000055) },
 | 
			
		||||
        { "Punctuation",    Colour (0xff004400) }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CodeEditorComponent::ColourScheme cs;
 | 
			
		||||
 | 
			
		||||
    for (auto& t : types)
 | 
			
		||||
        cs.set (t.name, Colour (t.colour));
 | 
			
		||||
 | 
			
		||||
    return cs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,65 +1,65 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  LuaTokeniser   : public CodeTokeniser
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    LuaTokeniser();
 | 
			
		||||
    ~LuaTokeniser() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int readNextToken (CodeDocument::Iterator&) override;
 | 
			
		||||
    CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
 | 
			
		||||
 | 
			
		||||
    /** The token values returned by this tokeniser. */
 | 
			
		||||
    enum TokenType
 | 
			
		||||
    {
 | 
			
		||||
        tokenType_error = 0,
 | 
			
		||||
        tokenType_comment,
 | 
			
		||||
        tokenType_keyword,
 | 
			
		||||
        tokenType_operator,
 | 
			
		||||
        tokenType_identifier,
 | 
			
		||||
        tokenType_integer,
 | 
			
		||||
        tokenType_float,
 | 
			
		||||
        tokenType_string,
 | 
			
		||||
        tokenType_bracket,
 | 
			
		||||
        tokenType_punctuation
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LuaTokeniser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  LuaTokeniser   : public CodeTokeniser
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    LuaTokeniser();
 | 
			
		||||
    ~LuaTokeniser() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int readNextToken (CodeDocument::Iterator&) override;
 | 
			
		||||
    CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
 | 
			
		||||
 | 
			
		||||
    /** The token values returned by this tokeniser. */
 | 
			
		||||
    enum TokenType
 | 
			
		||||
    {
 | 
			
		||||
        tokenType_error = 0,
 | 
			
		||||
        tokenType_comment,
 | 
			
		||||
        tokenType_keyword,
 | 
			
		||||
        tokenType_operator,
 | 
			
		||||
        tokenType_identifier,
 | 
			
		||||
        tokenType_integer,
 | 
			
		||||
        tokenType_float,
 | 
			
		||||
        tokenType_string,
 | 
			
		||||
        tokenType_bracket,
 | 
			
		||||
        tokenType_punctuation
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (LuaTokeniser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,172 +1,172 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
XmlTokeniser::XmlTokeniser() {}
 | 
			
		||||
XmlTokeniser::~XmlTokeniser() {}
 | 
			
		||||
 | 
			
		||||
CodeEditorComponent::ColourScheme XmlTokeniser::getDefaultColourScheme()
 | 
			
		||||
{
 | 
			
		||||
    struct Type
 | 
			
		||||
    {
 | 
			
		||||
        const char* name;
 | 
			
		||||
        uint32 colour;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const Type types[] =
 | 
			
		||||
    {
 | 
			
		||||
        { "Error",              0xffcc0000 },
 | 
			
		||||
        { "Comment",            0xff00aa00 },
 | 
			
		||||
        { "Keyword",            0xff0000cc },
 | 
			
		||||
        { "Operator",           0xff225500 },
 | 
			
		||||
        { "Identifier",         0xff000000 },
 | 
			
		||||
        { "String",             0xff990099 },
 | 
			
		||||
        { "Bracket",            0xff000055 },
 | 
			
		||||
        { "Punctuation",        0xff004400 },
 | 
			
		||||
        { "Preprocessor Text",  0xff660000 }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CodeEditorComponent::ColourScheme cs;
 | 
			
		||||
 | 
			
		||||
    for (auto& t : types)
 | 
			
		||||
        cs.set (t.name, Colour (t.colour));
 | 
			
		||||
 | 
			
		||||
    return cs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iterator>
 | 
			
		||||
static void skipToEndOfXmlDTD (Iterator& source) noexcept
 | 
			
		||||
{
 | 
			
		||||
    bool lastWasQuestionMark = false;
 | 
			
		||||
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
        auto c = source.nextChar();
 | 
			
		||||
 | 
			
		||||
        if (c == 0 || (c == '>' && lastWasQuestionMark))
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        lastWasQuestionMark = (c == '?');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iterator>
 | 
			
		||||
static void skipToEndOfXmlComment (Iterator& source) noexcept
 | 
			
		||||
{
 | 
			
		||||
    juce_wchar last[2] = {};
 | 
			
		||||
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
        auto c = source.nextChar();
 | 
			
		||||
 | 
			
		||||
        if (c == 0 || (c == '>' && last[0] == '-' && last[1] == '-'))
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        last[1] = last[0];
 | 
			
		||||
        last[0] = c;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int XmlTokeniser::readNextToken (CodeDocument::Iterator& source)
 | 
			
		||||
{
 | 
			
		||||
    source.skipWhitespace();
 | 
			
		||||
    auto firstChar = source.peekNextChar();
 | 
			
		||||
 | 
			
		||||
    switch (firstChar)
 | 
			
		||||
    {
 | 
			
		||||
        case 0:  break;
 | 
			
		||||
 | 
			
		||||
        case '"':
 | 
			
		||||
        case '\'':
 | 
			
		||||
            CppTokeniserFunctions::skipQuotedString (source);
 | 
			
		||||
            return tokenType_string;
 | 
			
		||||
 | 
			
		||||
        case '<':
 | 
			
		||||
        {
 | 
			
		||||
            source.skip();
 | 
			
		||||
            source.skipWhitespace();
 | 
			
		||||
            auto nextChar = source.peekNextChar();
 | 
			
		||||
 | 
			
		||||
            if (nextChar == '?')
 | 
			
		||||
            {
 | 
			
		||||
                source.skip();
 | 
			
		||||
                skipToEndOfXmlDTD (source);
 | 
			
		||||
                return tokenType_preprocessor;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (nextChar == '!')
 | 
			
		||||
            {
 | 
			
		||||
                source.skip();
 | 
			
		||||
 | 
			
		||||
                if (source.peekNextChar() == '-')
 | 
			
		||||
                {
 | 
			
		||||
                    source.skip();
 | 
			
		||||
 | 
			
		||||
                    if (source.peekNextChar() == '-')
 | 
			
		||||
                    {
 | 
			
		||||
                        skipToEndOfXmlComment (source);
 | 
			
		||||
                        return tokenType_comment;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '/');
 | 
			
		||||
            CppTokeniserFunctions::parseIdentifier (source);
 | 
			
		||||
            source.skipWhitespace();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '/');
 | 
			
		||||
            source.skipWhitespace();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '>');
 | 
			
		||||
            return tokenType_keyword;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case '>':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return tokenType_keyword;
 | 
			
		||||
 | 
			
		||||
        case '/':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            source.skipWhitespace();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '>');
 | 
			
		||||
            return tokenType_keyword;
 | 
			
		||||
 | 
			
		||||
        case '=':
 | 
			
		||||
        case ':':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            if (CppTokeniserFunctions::isIdentifierStart (firstChar))
 | 
			
		||||
                CppTokeniserFunctions::parseIdentifier (source);
 | 
			
		||||
 | 
			
		||||
            source.skip();
 | 
			
		||||
            break;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return tokenType_identifier;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
XmlTokeniser::XmlTokeniser() {}
 | 
			
		||||
XmlTokeniser::~XmlTokeniser() {}
 | 
			
		||||
 | 
			
		||||
CodeEditorComponent::ColourScheme XmlTokeniser::getDefaultColourScheme()
 | 
			
		||||
{
 | 
			
		||||
    struct Type
 | 
			
		||||
    {
 | 
			
		||||
        const char* name;
 | 
			
		||||
        uint32 colour;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const Type types[] =
 | 
			
		||||
    {
 | 
			
		||||
        { "Error",              0xffcc0000 },
 | 
			
		||||
        { "Comment",            0xff00aa00 },
 | 
			
		||||
        { "Keyword",            0xff0000cc },
 | 
			
		||||
        { "Operator",           0xff225500 },
 | 
			
		||||
        { "Identifier",         0xff000000 },
 | 
			
		||||
        { "String",             0xff990099 },
 | 
			
		||||
        { "Bracket",            0xff000055 },
 | 
			
		||||
        { "Punctuation",        0xff004400 },
 | 
			
		||||
        { "Preprocessor Text",  0xff660000 }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    CodeEditorComponent::ColourScheme cs;
 | 
			
		||||
 | 
			
		||||
    for (auto& t : types)
 | 
			
		||||
        cs.set (t.name, Colour (t.colour));
 | 
			
		||||
 | 
			
		||||
    return cs;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iterator>
 | 
			
		||||
static void skipToEndOfXmlDTD (Iterator& source) noexcept
 | 
			
		||||
{
 | 
			
		||||
    bool lastWasQuestionMark = false;
 | 
			
		||||
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
        auto c = source.nextChar();
 | 
			
		||||
 | 
			
		||||
        if (c == 0 || (c == '>' && lastWasQuestionMark))
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        lastWasQuestionMark = (c == '?');
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
template <typename Iterator>
 | 
			
		||||
static void skipToEndOfXmlComment (Iterator& source) noexcept
 | 
			
		||||
{
 | 
			
		||||
    juce_wchar last[2] = {};
 | 
			
		||||
 | 
			
		||||
    for (;;)
 | 
			
		||||
    {
 | 
			
		||||
        auto c = source.nextChar();
 | 
			
		||||
 | 
			
		||||
        if (c == 0 || (c == '>' && last[0] == '-' && last[1] == '-'))
 | 
			
		||||
            break;
 | 
			
		||||
 | 
			
		||||
        last[1] = last[0];
 | 
			
		||||
        last[0] = c;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int XmlTokeniser::readNextToken (CodeDocument::Iterator& source)
 | 
			
		||||
{
 | 
			
		||||
    source.skipWhitespace();
 | 
			
		||||
    auto firstChar = source.peekNextChar();
 | 
			
		||||
 | 
			
		||||
    switch (firstChar)
 | 
			
		||||
    {
 | 
			
		||||
        case 0:  break;
 | 
			
		||||
 | 
			
		||||
        case '"':
 | 
			
		||||
        case '\'':
 | 
			
		||||
            CppTokeniserFunctions::skipQuotedString (source);
 | 
			
		||||
            return tokenType_string;
 | 
			
		||||
 | 
			
		||||
        case '<':
 | 
			
		||||
        {
 | 
			
		||||
            source.skip();
 | 
			
		||||
            source.skipWhitespace();
 | 
			
		||||
            auto nextChar = source.peekNextChar();
 | 
			
		||||
 | 
			
		||||
            if (nextChar == '?')
 | 
			
		||||
            {
 | 
			
		||||
                source.skip();
 | 
			
		||||
                skipToEndOfXmlDTD (source);
 | 
			
		||||
                return tokenType_preprocessor;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (nextChar == '!')
 | 
			
		||||
            {
 | 
			
		||||
                source.skip();
 | 
			
		||||
 | 
			
		||||
                if (source.peekNextChar() == '-')
 | 
			
		||||
                {
 | 
			
		||||
                    source.skip();
 | 
			
		||||
 | 
			
		||||
                    if (source.peekNextChar() == '-')
 | 
			
		||||
                    {
 | 
			
		||||
                        skipToEndOfXmlComment (source);
 | 
			
		||||
                        return tokenType_comment;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '/');
 | 
			
		||||
            CppTokeniserFunctions::parseIdentifier (source);
 | 
			
		||||
            source.skipWhitespace();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '/');
 | 
			
		||||
            source.skipWhitespace();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '>');
 | 
			
		||||
            return tokenType_keyword;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        case '>':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return tokenType_keyword;
 | 
			
		||||
 | 
			
		||||
        case '/':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            source.skipWhitespace();
 | 
			
		||||
            CppTokeniserFunctions::skipIfNextCharMatches (source, '>');
 | 
			
		||||
            return tokenType_keyword;
 | 
			
		||||
 | 
			
		||||
        case '=':
 | 
			
		||||
        case ':':
 | 
			
		||||
            source.skip();
 | 
			
		||||
            return tokenType_operator;
 | 
			
		||||
 | 
			
		||||
        default:
 | 
			
		||||
            if (CppTokeniserFunctions::isIdentifierStart (firstChar))
 | 
			
		||||
                CppTokeniserFunctions::parseIdentifier (source);
 | 
			
		||||
 | 
			
		||||
            source.skip();
 | 
			
		||||
            break;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    return tokenType_identifier;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,63 +1,63 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  XmlTokeniser   : public CodeTokeniser
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    XmlTokeniser();
 | 
			
		||||
    ~XmlTokeniser() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int readNextToken (CodeDocument::Iterator&) override;
 | 
			
		||||
    CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
 | 
			
		||||
 | 
			
		||||
    /** The token values returned by this tokeniser. */
 | 
			
		||||
    enum TokenType
 | 
			
		||||
    {
 | 
			
		||||
        tokenType_error = 0,
 | 
			
		||||
        tokenType_comment,
 | 
			
		||||
        tokenType_keyword,
 | 
			
		||||
        tokenType_operator,
 | 
			
		||||
        tokenType_identifier,
 | 
			
		||||
        tokenType_string,
 | 
			
		||||
        tokenType_bracket,
 | 
			
		||||
        tokenType_punctuation,
 | 
			
		||||
        tokenType_preprocessor
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XmlTokeniser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  XmlTokeniser   : public CodeTokeniser
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    XmlTokeniser();
 | 
			
		||||
    ~XmlTokeniser() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int readNextToken (CodeDocument::Iterator&) override;
 | 
			
		||||
    CodeEditorComponent::ColourScheme getDefaultColourScheme() override;
 | 
			
		||||
 | 
			
		||||
    /** The token values returned by this tokeniser. */
 | 
			
		||||
    enum TokenType
 | 
			
		||||
    {
 | 
			
		||||
        tokenType_error = 0,
 | 
			
		||||
        tokenType_comment,
 | 
			
		||||
        tokenType_keyword,
 | 
			
		||||
        tokenType_operator,
 | 
			
		||||
        tokenType_identifier,
 | 
			
		||||
        tokenType_string,
 | 
			
		||||
        tokenType_bracket,
 | 
			
		||||
        tokenType_punctuation,
 | 
			
		||||
        tokenType_preprocessor
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (XmlTokeniser)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,431 +1,431 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A class to take care of the logic involved with the loading/saving of some kind
 | 
			
		||||
    of document.
 | 
			
		||||
 | 
			
		||||
    There's quite a lot of tedious logic involved in writing all the load/save/save-as
 | 
			
		||||
    functions you need for documents that get saved to a file, so this class attempts
 | 
			
		||||
    to abstract most of the boring stuff.
 | 
			
		||||
 | 
			
		||||
    Your subclass should just implement all the pure virtual methods, and you can
 | 
			
		||||
    then use the higher-level public methods to do the load/save dialogs, to warn the user
 | 
			
		||||
    about overwriting files, etc.
 | 
			
		||||
 | 
			
		||||
    The document object keeps track of whether it has changed since it was last saved or
 | 
			
		||||
    loaded, so when you change something, call its changed() method. This will set a
 | 
			
		||||
    flag so it knows it needs saving, and will also broadcast a change message using the
 | 
			
		||||
    ChangeBroadcaster base class.
 | 
			
		||||
 | 
			
		||||
    @see ChangeBroadcaster
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API FileBasedDocument  : public ChangeBroadcaster
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Creates a FileBasedDocument.
 | 
			
		||||
 | 
			
		||||
        @param fileExtension            the extension to use when loading/saving files, e.g. ".doc"
 | 
			
		||||
        @param fileWildCard             the wildcard to use in file dialogs, e.g. "*.doc"
 | 
			
		||||
        @param openFileDialogTitle      the title to show on an open-file dialog, e.g. "Choose a file to open.."
 | 
			
		||||
        @param saveFileDialogTitle      the title to show on an save-file dialog, e.g. "Choose a file to save as.."
 | 
			
		||||
    */
 | 
			
		||||
    FileBasedDocument (const String& fileExtension,
 | 
			
		||||
                       const String& fileWildCard,
 | 
			
		||||
                       const String& openFileDialogTitle,
 | 
			
		||||
                       const String& saveFileDialogTitle);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~FileBasedDocument() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the changed() method has been called since the file was
 | 
			
		||||
        last saved or loaded.
 | 
			
		||||
 | 
			
		||||
        @see setChangedFlag, changed
 | 
			
		||||
    */
 | 
			
		||||
    bool hasChangedSinceSaved() const;
 | 
			
		||||
 | 
			
		||||
    /** Called to indicate that the document has changed and needs saving.
 | 
			
		||||
 | 
			
		||||
        This method will also trigger a change message to be sent out using the
 | 
			
		||||
        ChangeBroadcaster base class.
 | 
			
		||||
 | 
			
		||||
        After calling the method, the hasChangedSinceSaved() method will return true, until
 | 
			
		||||
        it is reset either by saving to a file or using the setChangedFlag() method.
 | 
			
		||||
 | 
			
		||||
        @see hasChangedSinceSaved, setChangedFlag
 | 
			
		||||
    */
 | 
			
		||||
    virtual void changed();
 | 
			
		||||
 | 
			
		||||
    /** Sets the state of the 'changed' flag.
 | 
			
		||||
 | 
			
		||||
        The 'changed' flag is set to true when the changed() method is called - use this method
 | 
			
		||||
        to reset it or to set it without also broadcasting a change message.
 | 
			
		||||
 | 
			
		||||
        @see changed, hasChangedSinceSaved
 | 
			
		||||
    */
 | 
			
		||||
    void setChangedFlag (bool hasChanged);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Tries to open a file.
 | 
			
		||||
 | 
			
		||||
        If the file opens correctly the document's file (see the getFile() method) is set
 | 
			
		||||
        to this new one; if it fails, the document's file is left unchanged, and optionally
 | 
			
		||||
        a message box is shown telling the user there was an error.
 | 
			
		||||
 | 
			
		||||
        @returns A result indicating whether the new file loaded successfully, or the error
 | 
			
		||||
                 message if it failed.
 | 
			
		||||
        @see loadDocument, loadFromUserSpecifiedFile
 | 
			
		||||
    */
 | 
			
		||||
    Result loadFrom (const File& fileToLoadFrom,
 | 
			
		||||
                     bool showMessageOnFailure,
 | 
			
		||||
                     bool showWaitCursor = true);
 | 
			
		||||
 | 
			
		||||
    /** Tries to open a file.
 | 
			
		||||
 | 
			
		||||
        The callback is called with the result indicating whether the new file loaded
 | 
			
		||||
        successfully, or the error message if it failed.
 | 
			
		||||
 | 
			
		||||
        If the file opens correctly the document's file (see the getFile() method) is set
 | 
			
		||||
        to this new one; if it fails, the document's file is left unchanged, and optionally
 | 
			
		||||
        a message box is shown telling the user there was an error.
 | 
			
		||||
 | 
			
		||||
        @see loadDocumentAsync, loadFromUserSpecifiedFileAsync
 | 
			
		||||
    */
 | 
			
		||||
    void loadFromAsync (const File& fileToLoadFrom,
 | 
			
		||||
                        bool showMessageOnFailure,
 | 
			
		||||
                        std::function<void (Result)> callback);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Asks the user for a file and tries to load it.
 | 
			
		||||
 | 
			
		||||
        This will pop up a dialog box using the title, file extension and
 | 
			
		||||
        wildcard specified in the document's constructor, and asks the user
 | 
			
		||||
        for a file. If they pick one, the loadFrom() method is used to
 | 
			
		||||
        try to load it, optionally showing a message if it fails.
 | 
			
		||||
 | 
			
		||||
        @returns    a result indicating success; This will be a failure message if the user
 | 
			
		||||
                    cancelled or if they picked a file which failed to load correctly
 | 
			
		||||
        @see loadFrom
 | 
			
		||||
    */
 | 
			
		||||
    Result loadFromUserSpecifiedFile (bool showMessageOnFailure);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Asks the user for a file and tries to load it.
 | 
			
		||||
 | 
			
		||||
        This will pop up a dialog box using the title, file extension and
 | 
			
		||||
        wildcard specified in the document's constructor, and asks the user
 | 
			
		||||
        for a file. If they pick one, the loadFrom() method is used to
 | 
			
		||||
        try to load it, optionally showing a message if it fails. The result
 | 
			
		||||
        of the operation is provided in the callback function.
 | 
			
		||||
 | 
			
		||||
        @see loadFrom
 | 
			
		||||
    */
 | 
			
		||||
    void loadFromUserSpecifiedFileAsync (bool showMessageOnFailure, std::function<void (Result)> callback);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of possible outcomes of one of the save() methods
 | 
			
		||||
    */
 | 
			
		||||
    enum SaveResult
 | 
			
		||||
    {
 | 
			
		||||
        savedOk = 0,            /**< indicates that a file was saved successfully. */
 | 
			
		||||
        userCancelledSave,      /**< indicates that the user aborted the save operation. */
 | 
			
		||||
        failedToWriteToFile     /**< indicates that it tried to write to a file but this failed. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Tries to save the document to the last file it was saved or loaded from.
 | 
			
		||||
 | 
			
		||||
        This will always try to write to the file, even if the document isn't flagged as
 | 
			
		||||
        having changed.
 | 
			
		||||
 | 
			
		||||
        @param askUserForFileIfNotSpecified     if there's no file currently specified and this is
 | 
			
		||||
                                                true, it will prompt the user to pick a file, as if
 | 
			
		||||
                                                saveAsInteractive() was called.
 | 
			
		||||
        @param showMessageOnFailure             if true it will show a warning message when if the
 | 
			
		||||
                                                save operation fails
 | 
			
		||||
        @see saveIfNeededAndUserAgrees, saveAs, saveAsInteractive
 | 
			
		||||
    */
 | 
			
		||||
    SaveResult save (bool askUserForFileIfNotSpecified,
 | 
			
		||||
                     bool showMessageOnFailure);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Tries to save the document to the last file it was saved or loaded from.
 | 
			
		||||
 | 
			
		||||
        This will always try to write to the file, even if the document isn't flagged as
 | 
			
		||||
        having changed.
 | 
			
		||||
 | 
			
		||||
        @param askUserForFileIfNotSpecified     if there's no file currently specified and this is
 | 
			
		||||
                                                true, it will prompt the user to pick a file, as if
 | 
			
		||||
                                                saveAsInteractive() was called.
 | 
			
		||||
        @param showMessageOnFailure             if true it will show a warning message when if the
 | 
			
		||||
                                                save operation fails
 | 
			
		||||
        @param callback                         called after the save operation with the result
 | 
			
		||||
        @see saveIfNeededAndUserAgrees, saveAs, saveAsInteractive
 | 
			
		||||
    */
 | 
			
		||||
    void saveAsync (bool askUserForFileIfNotSpecified,
 | 
			
		||||
                    bool showMessageOnFailure,
 | 
			
		||||
                    std::function<void (SaveResult)> callback);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** If the file needs saving, it'll ask the user if that's what they want to do, and save
 | 
			
		||||
        it if they say yes.
 | 
			
		||||
 | 
			
		||||
        If you've got a document open and want to close it (e.g. to quit the app), this is the
 | 
			
		||||
        method to call.
 | 
			
		||||
 | 
			
		||||
        If the document doesn't need saving it'll return the value savedOk so
 | 
			
		||||
        you can go ahead and delete the document.
 | 
			
		||||
 | 
			
		||||
        If it does need saving it'll prompt the user, and if they say "discard changes" it'll
 | 
			
		||||
        return savedOk, so again, you can safely delete the document.
 | 
			
		||||
 | 
			
		||||
        If the user clicks "cancel", it'll return userCancelledSave, so if you can abort the
 | 
			
		||||
        close-document operation.
 | 
			
		||||
 | 
			
		||||
        And if they click "save changes", it'll try to save and either return savedOk, or
 | 
			
		||||
        failedToWriteToFile if there was a problem.
 | 
			
		||||
 | 
			
		||||
        @see save, saveAs, saveAsInteractive
 | 
			
		||||
    */
 | 
			
		||||
    SaveResult saveIfNeededAndUserAgrees();
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** If the file needs saving, it'll ask the user if that's what they want to do, and save
 | 
			
		||||
        it if they say yes.
 | 
			
		||||
 | 
			
		||||
        If you've got a document open and want to close it (e.g. to quit the app), this is the
 | 
			
		||||
        method to call.
 | 
			
		||||
 | 
			
		||||
        If the document doesn't need saving the callback will be called with the value savedOk
 | 
			
		||||
        so you can go ahead and delete the document.
 | 
			
		||||
 | 
			
		||||
        If it does need saving it'll prompt the user, and if they say "discard changes" the
 | 
			
		||||
        callback will be called with savedOk, so again, you can safely delete the document.
 | 
			
		||||
 | 
			
		||||
        If the user clicks "cancel", the callback will be aclled with userCancelledSave, so
 | 
			
		||||
        you can abort the close-document operation.
 | 
			
		||||
 | 
			
		||||
        And if they click "save changes", it'll try to save and the callback will be called
 | 
			
		||||
        with either savedOk, or failedToWriteToFile if there was a problem.
 | 
			
		||||
 | 
			
		||||
        @see saveAsync, saveAsAsync, saveAsInteractiveAsync
 | 
			
		||||
    */
 | 
			
		||||
    void saveIfNeededAndUserAgreesAsync (std::function<void (SaveResult)> callback);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Tries to save the document to a specified file.
 | 
			
		||||
 | 
			
		||||
        If this succeeds, it'll also change the document's internal file (as returned by
 | 
			
		||||
        the getFile() method). If it fails, the file will be left unchanged.
 | 
			
		||||
 | 
			
		||||
        @param newFile                      the file to try to write to
 | 
			
		||||
        @param warnAboutOverwritingExistingFiles    if true and the file exists, it'll ask
 | 
			
		||||
                                            the user first if they want to overwrite it
 | 
			
		||||
        @param askUserForFileIfNotSpecified if the file is non-existent and this is true, it'll
 | 
			
		||||
                                            use the saveAsInteractive() method to ask the user for a
 | 
			
		||||
                                            filename
 | 
			
		||||
        @param showMessageOnFailure         if true and the write operation fails, it'll show
 | 
			
		||||
                                            a message box to warn the user
 | 
			
		||||
        @param showWaitCursor               if true, the 'wait' mouse cursor will be showin during
 | 
			
		||||
                                            saving
 | 
			
		||||
        @see saveIfNeededAndUserAgrees, save, saveAsInteractive
 | 
			
		||||
    */
 | 
			
		||||
    SaveResult saveAs (const File& newFile,
 | 
			
		||||
                       bool warnAboutOverwritingExistingFiles,
 | 
			
		||||
                       bool askUserForFileIfNotSpecified,
 | 
			
		||||
                       bool showMessageOnFailure,
 | 
			
		||||
                       bool showWaitCursor = true);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Tries to save the document to a specified file.
 | 
			
		||||
 | 
			
		||||
        If this succeeds, it'll also change the document's internal file (as returned by
 | 
			
		||||
        the getFile() method). If it fails, the file will be left unchanged.
 | 
			
		||||
 | 
			
		||||
        @param newFile                              the file to try to write to
 | 
			
		||||
        @param warnAboutOverwritingExistingFiles    if true and the file exists, it'll ask the user
 | 
			
		||||
                                                    first if they want to overwrite it
 | 
			
		||||
        @param askUserForFileIfNotSpecified         if the file is non-existent and this is true, it'll
 | 
			
		||||
                                                    use the saveAsInteractive() method to ask the user
 | 
			
		||||
                                                    for a filename
 | 
			
		||||
        @param showMessageOnFailure                 if true and the write operation fails, it'll show
 | 
			
		||||
                                                    a message box to warn the user
 | 
			
		||||
        @param callback                             called with the result of the save operation
 | 
			
		||||
 | 
			
		||||
        @see saveIfNeededAndUserAgreesAsync, saveAsync, saveAsInteractiveAsync
 | 
			
		||||
    */
 | 
			
		||||
    void saveAsAsync (const File& newFile,
 | 
			
		||||
                      bool warnAboutOverwritingExistingFiles,
 | 
			
		||||
                      bool askUserForFileIfNotSpecified,
 | 
			
		||||
                      bool showMessageOnFailure,
 | 
			
		||||
                      std::function<void (SaveResult)> callback);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Prompts the user for a filename and tries to save to it.
 | 
			
		||||
 | 
			
		||||
        This will pop up a dialog box using the title, file extension and
 | 
			
		||||
        wildcard specified in the document's constructor, and asks the user
 | 
			
		||||
        for a file. If they pick one, the saveAs() method is used to try to save
 | 
			
		||||
        to this file.
 | 
			
		||||
 | 
			
		||||
        @param warnAboutOverwritingExistingFiles    if true and the file exists, it'll ask
 | 
			
		||||
                                                    the user first if they want to overwrite it
 | 
			
		||||
        @see saveIfNeededAndUserAgrees, save, saveAs
 | 
			
		||||
    */
 | 
			
		||||
    SaveResult saveAsInteractive (bool warnAboutOverwritingExistingFiles);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Prompts the user for a filename and tries to save to it.
 | 
			
		||||
 | 
			
		||||
        This will pop up a dialog box using the title, file extension and
 | 
			
		||||
        wildcard specified in the document's constructor, and asks the user
 | 
			
		||||
        for a file. If they pick one, the saveAs() method is used to try to save
 | 
			
		||||
        to this file.
 | 
			
		||||
 | 
			
		||||
        @param warnAboutOverwritingExistingFiles    if true and the file exists, it'll ask
 | 
			
		||||
                                                    the user first if they want to overwrite it
 | 
			
		||||
        @param callback                             called with the result of the save operation
 | 
			
		||||
        @see saveIfNeededAndUserAgreesAsync, saveAsync, saveAsAsync
 | 
			
		||||
    */
 | 
			
		||||
    void saveAsInteractiveAsync (bool warnAboutOverwritingExistingFiles,
 | 
			
		||||
                                 std::function<void (SaveResult)> callback);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the file that this document was last successfully saved or loaded from.
 | 
			
		||||
 | 
			
		||||
        When the document object is created, this will be set to File().
 | 
			
		||||
 | 
			
		||||
        It is changed when one of the load or save methods is used, or when setFile()
 | 
			
		||||
        is used to explicitly set it.
 | 
			
		||||
    */
 | 
			
		||||
    const File& getFile() const;
 | 
			
		||||
 | 
			
		||||
    /** Sets the file that this document thinks it was loaded from.
 | 
			
		||||
 | 
			
		||||
        This won't actually load anything - it just changes the file stored internally.
 | 
			
		||||
 | 
			
		||||
        @see getFile
 | 
			
		||||
    */
 | 
			
		||||
    void setFile (const File& newFile);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Overload this to return the title of the document.
 | 
			
		||||
 | 
			
		||||
        This is used in message boxes, filenames and file choosers, so it should be
 | 
			
		||||
        something sensible.
 | 
			
		||||
    */
 | 
			
		||||
    virtual String getDocumentTitle() = 0;
 | 
			
		||||
 | 
			
		||||
    /** This method should try to load your document from the given file.
 | 
			
		||||
        @returns a Result object to indicate the whether there was an error.
 | 
			
		||||
    */
 | 
			
		||||
    virtual Result loadDocument (const File& file) = 0;
 | 
			
		||||
 | 
			
		||||
    /** This method should try to load your document from the given file, then
 | 
			
		||||
        call the provided callback on the message thread, passing the result of the load.
 | 
			
		||||
 | 
			
		||||
        By default, this will synchronously call through to loadDocument.
 | 
			
		||||
 | 
			
		||||
        For longer-running load operations, you may wish to override this function to
 | 
			
		||||
        run the load on a background thread, and then to call the callback later on the
 | 
			
		||||
        message thread to signal that the load has completed.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void loadDocumentAsync (const File& file, std::function<void (Result)> callback);
 | 
			
		||||
 | 
			
		||||
    /** This method should try to write your document to the given file.
 | 
			
		||||
        @returns a Result object to indicate the whether there was an error.
 | 
			
		||||
    */
 | 
			
		||||
    virtual Result saveDocument (const File& file) = 0;
 | 
			
		||||
 | 
			
		||||
    /** This method should try to write your document to the given file, then
 | 
			
		||||
        call the provided callback on the message thread, passing the result of the write.
 | 
			
		||||
 | 
			
		||||
        By default, this will synchronously call through to saveDocument.
 | 
			
		||||
 | 
			
		||||
        For longer-running save operations, you may wish to override this function to
 | 
			
		||||
        run the save on a background thread, and then to call the callback later on the
 | 
			
		||||
        message thread to signal that the save has completed.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void saveDocumentAsync (const File& file, std::function<void (Result)> callback);
 | 
			
		||||
 | 
			
		||||
    /** This is used for dialog boxes to make them open at the last folder you
 | 
			
		||||
        were using.
 | 
			
		||||
 | 
			
		||||
        getLastDocumentOpened() and setLastDocumentOpened() are used to store
 | 
			
		||||
        the last document that was used - you might want to store this value
 | 
			
		||||
        in a static variable, or even in your application's properties. It should
 | 
			
		||||
        be a global setting rather than a property of this object.
 | 
			
		||||
 | 
			
		||||
        This method works very well in conjunction with a RecentlyOpenedFilesList
 | 
			
		||||
        object to manage your recent-files list.
 | 
			
		||||
 | 
			
		||||
        As a default value, it's ok to return File(), and the document object will
 | 
			
		||||
        use a sensible one instead.
 | 
			
		||||
 | 
			
		||||
        @see RecentlyOpenedFilesList
 | 
			
		||||
    */
 | 
			
		||||
    virtual File getLastDocumentOpened() = 0;
 | 
			
		||||
 | 
			
		||||
    /** This is used for dialog boxes to make them open at the last folder you
 | 
			
		||||
        were using.
 | 
			
		||||
 | 
			
		||||
        getLastDocumentOpened() and setLastDocumentOpened() are used to store
 | 
			
		||||
        the last document that was used - you might want to store this value
 | 
			
		||||
        in a static variable, or even in your application's properties. It should
 | 
			
		||||
        be a global setting rather than a property of this object.
 | 
			
		||||
 | 
			
		||||
        This method works very well in conjunction with a RecentlyOpenedFilesList
 | 
			
		||||
        object to manage your recent-files list.
 | 
			
		||||
 | 
			
		||||
        @see RecentlyOpenedFilesList
 | 
			
		||||
    */
 | 
			
		||||
    virtual void setLastDocumentOpened (const File& file) = 0;
 | 
			
		||||
 | 
			
		||||
    /** This is called by saveAsInteractiveAsync() to allow you to optionally customise the
 | 
			
		||||
        filename that the user is presented with in the save dialog.
 | 
			
		||||
        The defaultFile parameter is an initial suggestion based on what the class knows
 | 
			
		||||
        about the current document - you can return a variation on this file with a different
 | 
			
		||||
        extension, etc, or just return something completely different.
 | 
			
		||||
    */
 | 
			
		||||
    virtual File getSuggestedSaveAsFile (const File& defaultFile);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileBasedDocument)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A class to take care of the logic involved with the loading/saving of some kind
 | 
			
		||||
    of document.
 | 
			
		||||
 | 
			
		||||
    There's quite a lot of tedious logic involved in writing all the load/save/save-as
 | 
			
		||||
    functions you need for documents that get saved to a file, so this class attempts
 | 
			
		||||
    to abstract most of the boring stuff.
 | 
			
		||||
 | 
			
		||||
    Your subclass should just implement all the pure virtual methods, and you can
 | 
			
		||||
    then use the higher-level public methods to do the load/save dialogs, to warn the user
 | 
			
		||||
    about overwriting files, etc.
 | 
			
		||||
 | 
			
		||||
    The document object keeps track of whether it has changed since it was last saved or
 | 
			
		||||
    loaded, so when you change something, call its changed() method. This will set a
 | 
			
		||||
    flag so it knows it needs saving, and will also broadcast a change message using the
 | 
			
		||||
    ChangeBroadcaster base class.
 | 
			
		||||
 | 
			
		||||
    @see ChangeBroadcaster
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API FileBasedDocument  : public ChangeBroadcaster
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    /** Creates a FileBasedDocument.
 | 
			
		||||
 | 
			
		||||
        @param fileExtension            the extension to use when loading/saving files, e.g. ".doc"
 | 
			
		||||
        @param fileWildCard             the wildcard to use in file dialogs, e.g. "*.doc"
 | 
			
		||||
        @param openFileDialogTitle      the title to show on an open-file dialog, e.g. "Choose a file to open.."
 | 
			
		||||
        @param saveFileDialogTitle      the title to show on an save-file dialog, e.g. "Choose a file to save as.."
 | 
			
		||||
    */
 | 
			
		||||
    FileBasedDocument (const String& fileExtension,
 | 
			
		||||
                       const String& fileWildCard,
 | 
			
		||||
                       const String& openFileDialogTitle,
 | 
			
		||||
                       const String& saveFileDialogTitle);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~FileBasedDocument() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns true if the changed() method has been called since the file was
 | 
			
		||||
        last saved or loaded.
 | 
			
		||||
 | 
			
		||||
        @see setChangedFlag, changed
 | 
			
		||||
    */
 | 
			
		||||
    bool hasChangedSinceSaved() const;
 | 
			
		||||
 | 
			
		||||
    /** Called to indicate that the document has changed and needs saving.
 | 
			
		||||
 | 
			
		||||
        This method will also trigger a change message to be sent out using the
 | 
			
		||||
        ChangeBroadcaster base class.
 | 
			
		||||
 | 
			
		||||
        After calling the method, the hasChangedSinceSaved() method will return true, until
 | 
			
		||||
        it is reset either by saving to a file or using the setChangedFlag() method.
 | 
			
		||||
 | 
			
		||||
        @see hasChangedSinceSaved, setChangedFlag
 | 
			
		||||
    */
 | 
			
		||||
    virtual void changed();
 | 
			
		||||
 | 
			
		||||
    /** Sets the state of the 'changed' flag.
 | 
			
		||||
 | 
			
		||||
        The 'changed' flag is set to true when the changed() method is called - use this method
 | 
			
		||||
        to reset it or to set it without also broadcasting a change message.
 | 
			
		||||
 | 
			
		||||
        @see changed, hasChangedSinceSaved
 | 
			
		||||
    */
 | 
			
		||||
    void setChangedFlag (bool hasChanged);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Tries to open a file.
 | 
			
		||||
 | 
			
		||||
        If the file opens correctly the document's file (see the getFile() method) is set
 | 
			
		||||
        to this new one; if it fails, the document's file is left unchanged, and optionally
 | 
			
		||||
        a message box is shown telling the user there was an error.
 | 
			
		||||
 | 
			
		||||
        @returns A result indicating whether the new file loaded successfully, or the error
 | 
			
		||||
                 message if it failed.
 | 
			
		||||
        @see loadDocument, loadFromUserSpecifiedFile
 | 
			
		||||
    */
 | 
			
		||||
    Result loadFrom (const File& fileToLoadFrom,
 | 
			
		||||
                     bool showMessageOnFailure,
 | 
			
		||||
                     bool showWaitCursor = true);
 | 
			
		||||
 | 
			
		||||
    /** Tries to open a file.
 | 
			
		||||
 | 
			
		||||
        The callback is called with the result indicating whether the new file loaded
 | 
			
		||||
        successfully, or the error message if it failed.
 | 
			
		||||
 | 
			
		||||
        If the file opens correctly the document's file (see the getFile() method) is set
 | 
			
		||||
        to this new one; if it fails, the document's file is left unchanged, and optionally
 | 
			
		||||
        a message box is shown telling the user there was an error.
 | 
			
		||||
 | 
			
		||||
        @see loadDocumentAsync, loadFromUserSpecifiedFileAsync
 | 
			
		||||
    */
 | 
			
		||||
    void loadFromAsync (const File& fileToLoadFrom,
 | 
			
		||||
                        bool showMessageOnFailure,
 | 
			
		||||
                        std::function<void (Result)> callback);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Asks the user for a file and tries to load it.
 | 
			
		||||
 | 
			
		||||
        This will pop up a dialog box using the title, file extension and
 | 
			
		||||
        wildcard specified in the document's constructor, and asks the user
 | 
			
		||||
        for a file. If they pick one, the loadFrom() method is used to
 | 
			
		||||
        try to load it, optionally showing a message if it fails.
 | 
			
		||||
 | 
			
		||||
        @returns    a result indicating success; This will be a failure message if the user
 | 
			
		||||
                    cancelled or if they picked a file which failed to load correctly
 | 
			
		||||
        @see loadFrom
 | 
			
		||||
    */
 | 
			
		||||
    Result loadFromUserSpecifiedFile (bool showMessageOnFailure);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Asks the user for a file and tries to load it.
 | 
			
		||||
 | 
			
		||||
        This will pop up a dialog box using the title, file extension and
 | 
			
		||||
        wildcard specified in the document's constructor, and asks the user
 | 
			
		||||
        for a file. If they pick one, the loadFrom() method is used to
 | 
			
		||||
        try to load it, optionally showing a message if it fails. The result
 | 
			
		||||
        of the operation is provided in the callback function.
 | 
			
		||||
 | 
			
		||||
        @see loadFrom
 | 
			
		||||
    */
 | 
			
		||||
    void loadFromUserSpecifiedFileAsync (bool showMessageOnFailure, std::function<void (Result)> callback);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of possible outcomes of one of the save() methods
 | 
			
		||||
    */
 | 
			
		||||
    enum SaveResult
 | 
			
		||||
    {
 | 
			
		||||
        savedOk = 0,            /**< indicates that a file was saved successfully. */
 | 
			
		||||
        userCancelledSave,      /**< indicates that the user aborted the save operation. */
 | 
			
		||||
        failedToWriteToFile     /**< indicates that it tried to write to a file but this failed. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Tries to save the document to the last file it was saved or loaded from.
 | 
			
		||||
 | 
			
		||||
        This will always try to write to the file, even if the document isn't flagged as
 | 
			
		||||
        having changed.
 | 
			
		||||
 | 
			
		||||
        @param askUserForFileIfNotSpecified     if there's no file currently specified and this is
 | 
			
		||||
                                                true, it will prompt the user to pick a file, as if
 | 
			
		||||
                                                saveAsInteractive() was called.
 | 
			
		||||
        @param showMessageOnFailure             if true it will show a warning message when if the
 | 
			
		||||
                                                save operation fails
 | 
			
		||||
        @see saveIfNeededAndUserAgrees, saveAs, saveAsInteractive
 | 
			
		||||
    */
 | 
			
		||||
    SaveResult save (bool askUserForFileIfNotSpecified,
 | 
			
		||||
                     bool showMessageOnFailure);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Tries to save the document to the last file it was saved or loaded from.
 | 
			
		||||
 | 
			
		||||
        This will always try to write to the file, even if the document isn't flagged as
 | 
			
		||||
        having changed.
 | 
			
		||||
 | 
			
		||||
        @param askUserForFileIfNotSpecified     if there's no file currently specified and this is
 | 
			
		||||
                                                true, it will prompt the user to pick a file, as if
 | 
			
		||||
                                                saveAsInteractive() was called.
 | 
			
		||||
        @param showMessageOnFailure             if true it will show a warning message when if the
 | 
			
		||||
                                                save operation fails
 | 
			
		||||
        @param callback                         called after the save operation with the result
 | 
			
		||||
        @see saveIfNeededAndUserAgrees, saveAs, saveAsInteractive
 | 
			
		||||
    */
 | 
			
		||||
    void saveAsync (bool askUserForFileIfNotSpecified,
 | 
			
		||||
                    bool showMessageOnFailure,
 | 
			
		||||
                    std::function<void (SaveResult)> callback);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** If the file needs saving, it'll ask the user if that's what they want to do, and save
 | 
			
		||||
        it if they say yes.
 | 
			
		||||
 | 
			
		||||
        If you've got a document open and want to close it (e.g. to quit the app), this is the
 | 
			
		||||
        method to call.
 | 
			
		||||
 | 
			
		||||
        If the document doesn't need saving it'll return the value savedOk so
 | 
			
		||||
        you can go ahead and delete the document.
 | 
			
		||||
 | 
			
		||||
        If it does need saving it'll prompt the user, and if they say "discard changes" it'll
 | 
			
		||||
        return savedOk, so again, you can safely delete the document.
 | 
			
		||||
 | 
			
		||||
        If the user clicks "cancel", it'll return userCancelledSave, so if you can abort the
 | 
			
		||||
        close-document operation.
 | 
			
		||||
 | 
			
		||||
        And if they click "save changes", it'll try to save and either return savedOk, or
 | 
			
		||||
        failedToWriteToFile if there was a problem.
 | 
			
		||||
 | 
			
		||||
        @see save, saveAs, saveAsInteractive
 | 
			
		||||
    */
 | 
			
		||||
    SaveResult saveIfNeededAndUserAgrees();
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** If the file needs saving, it'll ask the user if that's what they want to do, and save
 | 
			
		||||
        it if they say yes.
 | 
			
		||||
 | 
			
		||||
        If you've got a document open and want to close it (e.g. to quit the app), this is the
 | 
			
		||||
        method to call.
 | 
			
		||||
 | 
			
		||||
        If the document doesn't need saving the callback will be called with the value savedOk
 | 
			
		||||
        so you can go ahead and delete the document.
 | 
			
		||||
 | 
			
		||||
        If it does need saving it'll prompt the user, and if they say "discard changes" the
 | 
			
		||||
        callback will be called with savedOk, so again, you can safely delete the document.
 | 
			
		||||
 | 
			
		||||
        If the user clicks "cancel", the callback will be called with userCancelledSave, so
 | 
			
		||||
        you can abort the close-document operation.
 | 
			
		||||
 | 
			
		||||
        And if they click "save changes", it'll try to save and the callback will be called
 | 
			
		||||
        with either savedOk, or failedToWriteToFile if there was a problem.
 | 
			
		||||
 | 
			
		||||
        @see saveAsync, saveAsAsync, saveAsInteractiveAsync
 | 
			
		||||
    */
 | 
			
		||||
    void saveIfNeededAndUserAgreesAsync (std::function<void (SaveResult)> callback);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Tries to save the document to a specified file.
 | 
			
		||||
 | 
			
		||||
        If this succeeds, it'll also change the document's internal file (as returned by
 | 
			
		||||
        the getFile() method). If it fails, the file will be left unchanged.
 | 
			
		||||
 | 
			
		||||
        @param newFile                      the file to try to write to
 | 
			
		||||
        @param warnAboutOverwritingExistingFiles    if true and the file exists, it'll ask
 | 
			
		||||
                                            the user first if they want to overwrite it
 | 
			
		||||
        @param askUserForFileIfNotSpecified if the file is non-existent and this is true, it'll
 | 
			
		||||
                                            use the saveAsInteractive() method to ask the user for a
 | 
			
		||||
                                            filename
 | 
			
		||||
        @param showMessageOnFailure         if true and the write operation fails, it'll show
 | 
			
		||||
                                            a message box to warn the user
 | 
			
		||||
        @param showWaitCursor               if true, the 'wait' mouse cursor will be showin during
 | 
			
		||||
                                            saving
 | 
			
		||||
        @see saveIfNeededAndUserAgrees, save, saveAsInteractive
 | 
			
		||||
    */
 | 
			
		||||
    SaveResult saveAs (const File& newFile,
 | 
			
		||||
                       bool warnAboutOverwritingExistingFiles,
 | 
			
		||||
                       bool askUserForFileIfNotSpecified,
 | 
			
		||||
                       bool showMessageOnFailure,
 | 
			
		||||
                       bool showWaitCursor = true);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Tries to save the document to a specified file.
 | 
			
		||||
 | 
			
		||||
        If this succeeds, it'll also change the document's internal file (as returned by
 | 
			
		||||
        the getFile() method). If it fails, the file will be left unchanged.
 | 
			
		||||
 | 
			
		||||
        @param newFile                              the file to try to write to
 | 
			
		||||
        @param warnAboutOverwritingExistingFiles    if true and the file exists, it'll ask the user
 | 
			
		||||
                                                    first if they want to overwrite it
 | 
			
		||||
        @param askUserForFileIfNotSpecified         if the file is non-existent and this is true, it'll
 | 
			
		||||
                                                    use the saveAsInteractive() method to ask the user
 | 
			
		||||
                                                    for a filename
 | 
			
		||||
        @param showMessageOnFailure                 if true and the write operation fails, it'll show
 | 
			
		||||
                                                    a message box to warn the user
 | 
			
		||||
        @param callback                             called with the result of the save operation
 | 
			
		||||
 | 
			
		||||
        @see saveIfNeededAndUserAgreesAsync, saveAsync, saveAsInteractiveAsync
 | 
			
		||||
    */
 | 
			
		||||
    void saveAsAsync (const File& newFile,
 | 
			
		||||
                      bool warnAboutOverwritingExistingFiles,
 | 
			
		||||
                      bool askUserForFileIfNotSpecified,
 | 
			
		||||
                      bool showMessageOnFailure,
 | 
			
		||||
                      std::function<void (SaveResult)> callback);
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MODAL_LOOPS_PERMITTED
 | 
			
		||||
    /** Prompts the user for a filename and tries to save to it.
 | 
			
		||||
 | 
			
		||||
        This will pop up a dialog box using the title, file extension and
 | 
			
		||||
        wildcard specified in the document's constructor, and asks the user
 | 
			
		||||
        for a file. If they pick one, the saveAs() method is used to try to save
 | 
			
		||||
        to this file.
 | 
			
		||||
 | 
			
		||||
        @param warnAboutOverwritingExistingFiles    if true and the file exists, it'll ask
 | 
			
		||||
                                                    the user first if they want to overwrite it
 | 
			
		||||
        @see saveIfNeededAndUserAgrees, save, saveAs
 | 
			
		||||
    */
 | 
			
		||||
    SaveResult saveAsInteractive (bool warnAboutOverwritingExistingFiles);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    /** Prompts the user for a filename and tries to save to it.
 | 
			
		||||
 | 
			
		||||
        This will pop up a dialog box using the title, file extension and
 | 
			
		||||
        wildcard specified in the document's constructor, and asks the user
 | 
			
		||||
        for a file. If they pick one, the saveAs() method is used to try to save
 | 
			
		||||
        to this file.
 | 
			
		||||
 | 
			
		||||
        @param warnAboutOverwritingExistingFiles    if true and the file exists, it'll ask
 | 
			
		||||
                                                    the user first if they want to overwrite it
 | 
			
		||||
        @param callback                             called with the result of the save operation
 | 
			
		||||
        @see saveIfNeededAndUserAgreesAsync, saveAsync, saveAsAsync
 | 
			
		||||
    */
 | 
			
		||||
    void saveAsInteractiveAsync (bool warnAboutOverwritingExistingFiles,
 | 
			
		||||
                                 std::function<void (SaveResult)> callback);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the file that this document was last successfully saved or loaded from.
 | 
			
		||||
 | 
			
		||||
        When the document object is created, this will be set to File().
 | 
			
		||||
 | 
			
		||||
        It is changed when one of the load or save methods is used, or when setFile()
 | 
			
		||||
        is used to explicitly set it.
 | 
			
		||||
    */
 | 
			
		||||
    const File& getFile() const;
 | 
			
		||||
 | 
			
		||||
    /** Sets the file that this document thinks it was loaded from.
 | 
			
		||||
 | 
			
		||||
        This won't actually load anything - it just changes the file stored internally.
 | 
			
		||||
 | 
			
		||||
        @see getFile
 | 
			
		||||
    */
 | 
			
		||||
    void setFile (const File& newFile);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Overload this to return the title of the document.
 | 
			
		||||
 | 
			
		||||
        This is used in message boxes, filenames and file choosers, so it should be
 | 
			
		||||
        something sensible.
 | 
			
		||||
    */
 | 
			
		||||
    virtual String getDocumentTitle() = 0;
 | 
			
		||||
 | 
			
		||||
    /** This method should try to load your document from the given file.
 | 
			
		||||
        @returns a Result object to indicate the whether there was an error.
 | 
			
		||||
    */
 | 
			
		||||
    virtual Result loadDocument (const File& file) = 0;
 | 
			
		||||
 | 
			
		||||
    /** This method should try to load your document from the given file, then
 | 
			
		||||
        call the provided callback on the message thread, passing the result of the load.
 | 
			
		||||
 | 
			
		||||
        By default, this will synchronously call through to loadDocument.
 | 
			
		||||
 | 
			
		||||
        For longer-running load operations, you may wish to override this function to
 | 
			
		||||
        run the load on a background thread, and then to call the callback later on the
 | 
			
		||||
        message thread to signal that the load has completed.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void loadDocumentAsync (const File& file, std::function<void (Result)> callback);
 | 
			
		||||
 | 
			
		||||
    /** This method should try to write your document to the given file.
 | 
			
		||||
        @returns a Result object to indicate the whether there was an error.
 | 
			
		||||
    */
 | 
			
		||||
    virtual Result saveDocument (const File& file) = 0;
 | 
			
		||||
 | 
			
		||||
    /** This method should try to write your document to the given file, then
 | 
			
		||||
        call the provided callback on the message thread, passing the result of the write.
 | 
			
		||||
 | 
			
		||||
        By default, this will synchronously call through to saveDocument.
 | 
			
		||||
 | 
			
		||||
        For longer-running save operations, you may wish to override this function to
 | 
			
		||||
        run the save on a background thread, and then to call the callback later on the
 | 
			
		||||
        message thread to signal that the save has completed.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void saveDocumentAsync (const File& file, std::function<void (Result)> callback);
 | 
			
		||||
 | 
			
		||||
    /** This is used for dialog boxes to make them open at the last folder you
 | 
			
		||||
        were using.
 | 
			
		||||
 | 
			
		||||
        getLastDocumentOpened() and setLastDocumentOpened() are used to store
 | 
			
		||||
        the last document that was used - you might want to store this value
 | 
			
		||||
        in a static variable, or even in your application's properties. It should
 | 
			
		||||
        be a global setting rather than a property of this object.
 | 
			
		||||
 | 
			
		||||
        This method works very well in conjunction with a RecentlyOpenedFilesList
 | 
			
		||||
        object to manage your recent-files list.
 | 
			
		||||
 | 
			
		||||
        As a default value, it's ok to return File(), and the document object will
 | 
			
		||||
        use a sensible one instead.
 | 
			
		||||
 | 
			
		||||
        @see RecentlyOpenedFilesList
 | 
			
		||||
    */
 | 
			
		||||
    virtual File getLastDocumentOpened() = 0;
 | 
			
		||||
 | 
			
		||||
    /** This is used for dialog boxes to make them open at the last folder you
 | 
			
		||||
        were using.
 | 
			
		||||
 | 
			
		||||
        getLastDocumentOpened() and setLastDocumentOpened() are used to store
 | 
			
		||||
        the last document that was used - you might want to store this value
 | 
			
		||||
        in a static variable, or even in your application's properties. It should
 | 
			
		||||
        be a global setting rather than a property of this object.
 | 
			
		||||
 | 
			
		||||
        This method works very well in conjunction with a RecentlyOpenedFilesList
 | 
			
		||||
        object to manage your recent-files list.
 | 
			
		||||
 | 
			
		||||
        @see RecentlyOpenedFilesList
 | 
			
		||||
    */
 | 
			
		||||
    virtual void setLastDocumentOpened (const File& file) = 0;
 | 
			
		||||
 | 
			
		||||
    /** This is called by saveAsInteractiveAsync() to allow you to optionally customise the
 | 
			
		||||
        filename that the user is presented with in the save dialog.
 | 
			
		||||
        The defaultFile parameter is an initial suggestion based on what the class knows
 | 
			
		||||
        about the current document - you can return a variation on this file with a different
 | 
			
		||||
        extension, etc, or just return something completely different.
 | 
			
		||||
    */
 | 
			
		||||
    virtual File getSuggestedSaveAsFile (const File& defaultFile);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (FileBasedDocument)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,128 +1,128 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WINDOWS || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Windows-specific class that can create and embed an ActiveX control inside
 | 
			
		||||
    itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use createControl() to instantiate an ActiveX control. The control
 | 
			
		||||
    will then be moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the control is a heavyweight window, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ActiveXControlComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container. */
 | 
			
		||||
    ActiveXControlComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ActiveXControlComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Tries to create an ActiveX control and embed it in this peer.
 | 
			
		||||
 | 
			
		||||
        The peer controlIID is a pointer to an IID structure - it's treated
 | 
			
		||||
        as a void* because when including the JUCE headers, you might not always
 | 
			
		||||
        have included windows.h first, in which case IID wouldn't be defined.
 | 
			
		||||
 | 
			
		||||
        e.g. @code
 | 
			
		||||
        const IID myIID = __uuidof (QTControl);
 | 
			
		||||
        myControlComp->createControl (&myIID);
 | 
			
		||||
        @endcode
 | 
			
		||||
    */
 | 
			
		||||
    bool createControl (const void* controlIID);
 | 
			
		||||
 | 
			
		||||
    /** Deletes the ActiveX control, if one has been created.
 | 
			
		||||
    */
 | 
			
		||||
    void deleteControl();
 | 
			
		||||
 | 
			
		||||
    /** Returns true if a control is currently in use. */
 | 
			
		||||
    bool isControlOpen() const noexcept                 { return control != nullptr; }
 | 
			
		||||
 | 
			
		||||
    /** Does a QueryInterface call on the embedded control object.
 | 
			
		||||
 | 
			
		||||
        This allows you to cast the control to whatever type of COM object you need.
 | 
			
		||||
 | 
			
		||||
        The iid parameter is a pointer to an IID structure - it's treated
 | 
			
		||||
        as a void* because when including the JUCE headers, you might not always
 | 
			
		||||
        have included windows.h first, in which case IID wouldn't be defined, but
 | 
			
		||||
        you should just pass a pointer to an IID.
 | 
			
		||||
 | 
			
		||||
        e.g. @code
 | 
			
		||||
        const IID iid = __uuidof (IOleWindow);
 | 
			
		||||
 | 
			
		||||
        IOleWindow* oleWindow = (IOleWindow*) myControlComp->queryInterface (&iid);
 | 
			
		||||
 | 
			
		||||
        if (oleWindow != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            HWND hwnd;
 | 
			
		||||
            oleWindow->GetWindow (&hwnd);
 | 
			
		||||
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
            oleWindow->Release();
 | 
			
		||||
        }
 | 
			
		||||
        @endcode
 | 
			
		||||
    */
 | 
			
		||||
    void* queryInterface (const void* iid) const;
 | 
			
		||||
 | 
			
		||||
    /** Set this to false to stop mouse events being allowed through to the control.
 | 
			
		||||
    */
 | 
			
		||||
    void setMouseEventsAllowed (bool eventsCanReachControl);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if mouse events are allowed to get through to the control.
 | 
			
		||||
    */
 | 
			
		||||
    bool areMouseEventsAllowed() const noexcept                 { return mouseEventsAllowed; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    intptr_t offerEventToActiveXControl (void*);
 | 
			
		||||
    static intptr_t offerEventToActiveXControlStatic (void*);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> control;
 | 
			
		||||
    bool mouseEventsAllowed = true;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveXControlComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WINDOWS || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Windows-specific class that can create and embed an ActiveX control inside
 | 
			
		||||
    itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use createControl() to instantiate an ActiveX control. The control
 | 
			
		||||
    will then be moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the control is a heavyweight window, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ActiveXControlComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container. */
 | 
			
		||||
    ActiveXControlComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ActiveXControlComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Tries to create an ActiveX control and embed it in this peer.
 | 
			
		||||
 | 
			
		||||
        The peer controlIID is a pointer to an IID structure - it's treated
 | 
			
		||||
        as a void* because when including the JUCE headers, you might not always
 | 
			
		||||
        have included windows.h first, in which case IID wouldn't be defined.
 | 
			
		||||
 | 
			
		||||
        e.g. @code
 | 
			
		||||
        const IID myIID = __uuidof (QTControl);
 | 
			
		||||
        myControlComp->createControl (&myIID);
 | 
			
		||||
        @endcode
 | 
			
		||||
    */
 | 
			
		||||
    bool createControl (const void* controlIID);
 | 
			
		||||
 | 
			
		||||
    /** Deletes the ActiveX control, if one has been created.
 | 
			
		||||
    */
 | 
			
		||||
    void deleteControl();
 | 
			
		||||
 | 
			
		||||
    /** Returns true if a control is currently in use. */
 | 
			
		||||
    bool isControlOpen() const noexcept                 { return control != nullptr; }
 | 
			
		||||
 | 
			
		||||
    /** Does a QueryInterface call on the embedded control object.
 | 
			
		||||
 | 
			
		||||
        This allows you to cast the control to whatever type of COM object you need.
 | 
			
		||||
 | 
			
		||||
        The iid parameter is a pointer to an IID structure - it's treated
 | 
			
		||||
        as a void* because when including the JUCE headers, you might not always
 | 
			
		||||
        have included windows.h first, in which case IID wouldn't be defined, but
 | 
			
		||||
        you should just pass a pointer to an IID.
 | 
			
		||||
 | 
			
		||||
        e.g. @code
 | 
			
		||||
        const IID iid = __uuidof (IOleWindow);
 | 
			
		||||
 | 
			
		||||
        IOleWindow* oleWindow = (IOleWindow*) myControlComp->queryInterface (&iid);
 | 
			
		||||
 | 
			
		||||
        if (oleWindow != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            HWND hwnd;
 | 
			
		||||
            oleWindow->GetWindow (&hwnd);
 | 
			
		||||
 | 
			
		||||
            ...
 | 
			
		||||
 | 
			
		||||
            oleWindow->Release();
 | 
			
		||||
        }
 | 
			
		||||
        @endcode
 | 
			
		||||
    */
 | 
			
		||||
    void* queryInterface (const void* iid) const;
 | 
			
		||||
 | 
			
		||||
    /** Set this to false to stop mouse events being allowed through to the control.
 | 
			
		||||
    */
 | 
			
		||||
    void setMouseEventsAllowed (bool eventsCanReachControl);
 | 
			
		||||
 | 
			
		||||
    /** Returns true if mouse events are allowed to get through to the control.
 | 
			
		||||
    */
 | 
			
		||||
    bool areMouseEventsAllowed() const noexcept                 { return mouseEventsAllowed; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    intptr_t offerEventToActiveXControl (void*);
 | 
			
		||||
    static intptr_t offerEventToActiveXControlStatic (void*);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> control;
 | 
			
		||||
    bool mouseEventsAllowed = true;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ActiveXControlComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,80 +1,80 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_ANDROID || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    An Android-specific class that can create and embed a View inside itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use setView() to assign a View to it. The view will then be
 | 
			
		||||
    moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the view is a native object, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AndroidViewComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container */
 | 
			
		||||
    AndroidViewComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~AndroidViewComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Assigns a View to this peer.
 | 
			
		||||
 | 
			
		||||
        The view will be retained and released by this component for as long as
 | 
			
		||||
        it is needed. To remove the current view, just call setView (nullptr).
 | 
			
		||||
    */
 | 
			
		||||
    void setView (void* uiView);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current View. */
 | 
			
		||||
    void* getView() const;
 | 
			
		||||
 | 
			
		||||
    /** Resizes this component to fit the view that it contains. */
 | 
			
		||||
    void resizeToFitView();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidViewComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_ANDROID || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    An Android-specific class that can create and embed a View inside itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use setView() to assign a View to it. The view will then be
 | 
			
		||||
    moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the view is a native object, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AndroidViewComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container */
 | 
			
		||||
    AndroidViewComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~AndroidViewComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Assigns a View to this peer.
 | 
			
		||||
 | 
			
		||||
        The view will be retained and released by this component for as long as
 | 
			
		||||
        it is needed. To remove the current view, just call setView (nullptr).
 | 
			
		||||
    */
 | 
			
		||||
    void setView (void* uiView);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current View. */
 | 
			
		||||
    void* getView() const;
 | 
			
		||||
 | 
			
		||||
    /** Resizes this component to fit the view that it contains. */
 | 
			
		||||
    void resizeToFitView();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AndroidViewComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,86 +1,89 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WINDOWS || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Windows-specific class that can create and embed a HWND inside itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use setHWND() to assign a HWND to it. The window will then be
 | 
			
		||||
    moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the window is a native object, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  HWNDComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container. */
 | 
			
		||||
    HWNDComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~HWNDComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Assigns a HWND to this peer.
 | 
			
		||||
 | 
			
		||||
        The window will be retained and released by this component for as long as
 | 
			
		||||
        it is needed. To remove the current HWND, just call setHWND (nullptr).
 | 
			
		||||
 | 
			
		||||
        Note: A void* is used here to avoid including the Windows headers as
 | 
			
		||||
        part of JuceHeader.h, but the method expects a HWND.
 | 
			
		||||
    */
 | 
			
		||||
    void setHWND (void* hwnd);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current HWND.
 | 
			
		||||
 | 
			
		||||
        Note: A void* is returned here to avoid the needing to include the Windows
 | 
			
		||||
        headers, so you should just cast the return value to a HWND.
 | 
			
		||||
    */
 | 
			
		||||
    void* getHWND() const;
 | 
			
		||||
 | 
			
		||||
    /** Resizes this component to fit the HWND that it contains. */
 | 
			
		||||
    void resizeToFit();
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HWNDComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WINDOWS || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Windows-specific class that can create and embed a HWND inside itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use setHWND() to assign a HWND to it. The window will then be
 | 
			
		||||
    moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the window is a native object, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  HWNDComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container. */
 | 
			
		||||
    HWNDComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~HWNDComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Assigns a HWND to this peer.
 | 
			
		||||
 | 
			
		||||
        The window will be retained and released by this component for as long as
 | 
			
		||||
        it is needed. To remove the current HWND, just call setHWND (nullptr).
 | 
			
		||||
 | 
			
		||||
        Note: A void* is used here to avoid including the Windows headers as
 | 
			
		||||
        part of JuceHeader.h, but the method expects a HWND.
 | 
			
		||||
    */
 | 
			
		||||
    void setHWND (void* hwnd);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current HWND.
 | 
			
		||||
 | 
			
		||||
        Note: A void* is returned here to avoid the needing to include the Windows
 | 
			
		||||
        headers, so you should just cast the return value to a HWND.
 | 
			
		||||
    */
 | 
			
		||||
    void* getHWND() const;
 | 
			
		||||
 | 
			
		||||
    /** Resizes this component to fit the HWND that it contains. */
 | 
			
		||||
    void resizeToFit();
 | 
			
		||||
 | 
			
		||||
    /** Forces the bounds of the HWND to match the bounds of this component. */
 | 
			
		||||
    void updateHWNDBounds();
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (HWNDComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,90 +1,90 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_MAC || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Mac-specific class that can create and embed an NSView inside itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use setView() to assign an NSView to it. The view will then be
 | 
			
		||||
    moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the view is a native object, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  NSViewComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container. */
 | 
			
		||||
    NSViewComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~NSViewComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Assigns an NSView to this peer.
 | 
			
		||||
 | 
			
		||||
        The view will be retained and released by this component for as long as
 | 
			
		||||
        it is needed. To remove the current view, just call setView (nullptr).
 | 
			
		||||
 | 
			
		||||
        Note: A void* is used here to avoid including the cocoa headers as
 | 
			
		||||
        part of JuceHeader.h, but the method expects an NSView*.
 | 
			
		||||
    */
 | 
			
		||||
    void setView (void* nsView);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current NSView.
 | 
			
		||||
 | 
			
		||||
        Note: A void* is returned here to avoid the needing to include the cocoa
 | 
			
		||||
        headers, so you should just cast the return value to an NSView*.
 | 
			
		||||
    */
 | 
			
		||||
    void* getView() const;
 | 
			
		||||
 | 
			
		||||
    /** Resizes this component to fit the view that it contains. */
 | 
			
		||||
    void resizeToFitView();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void alphaChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    static ReferenceCountedObject* attachViewToComponent (Component&, void*);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ReferenceCountedObjectPtr<ReferenceCountedObject> attachment;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_MAC || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Mac-specific class that can create and embed an NSView inside itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use setView() to assign an NSView to it. The view will then be
 | 
			
		||||
    moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the view is a native object, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  NSViewComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container. */
 | 
			
		||||
    NSViewComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~NSViewComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Assigns an NSView to this peer.
 | 
			
		||||
 | 
			
		||||
        The view will be retained and released by this component for as long as
 | 
			
		||||
        it is needed. To remove the current view, just call setView (nullptr).
 | 
			
		||||
 | 
			
		||||
        Note: A void* is used here to avoid including the cocoa headers as
 | 
			
		||||
        part of JuceHeader.h, but the method expects an NSView*.
 | 
			
		||||
    */
 | 
			
		||||
    void setView (void* nsView);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current NSView.
 | 
			
		||||
 | 
			
		||||
        Note: A void* is returned here to avoid the needing to include the cocoa
 | 
			
		||||
        headers, so you should just cast the return value to an NSView*.
 | 
			
		||||
    */
 | 
			
		||||
    void* getView() const;
 | 
			
		||||
 | 
			
		||||
    /** Resizes this component to fit the view that it contains. */
 | 
			
		||||
    void resizeToFitView();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void alphaChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    static ReferenceCountedObject* attachViewToComponent (Component&, void*);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ReferenceCountedObjectPtr<ReferenceCountedObject> attachment;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (NSViewComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,88 +1,88 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_IOS || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    An iOS-specific class that can create and embed an UIView inside itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use setView() to assign a UIView to it. The view will then be
 | 
			
		||||
    moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the view is a native object, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  UIViewComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container. */
 | 
			
		||||
    UIViewComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~UIViewComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Assigns an UIView to this peer.
 | 
			
		||||
 | 
			
		||||
        The view will be retained and released by this component for as long as
 | 
			
		||||
        it is needed. To remove the current view, just call setView (nullptr).
 | 
			
		||||
 | 
			
		||||
        Note: A void* is used here to avoid including the cocoa headers as
 | 
			
		||||
        part of JuceHeader.h, but the method expects an UIView*.
 | 
			
		||||
    */
 | 
			
		||||
    void setView (void* uiView);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current UIView.
 | 
			
		||||
 | 
			
		||||
        Note: A void* is returned here to avoid the needing to include the cocoa
 | 
			
		||||
        headers, so you should just cast the return value to an UIView*.
 | 
			
		||||
    */
 | 
			
		||||
    void* getView() const;
 | 
			
		||||
 | 
			
		||||
    /** Resizes this component to fit the view that it contains. */
 | 
			
		||||
    void resizeToFitView();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIViewComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_IOS || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    An iOS-specific class that can create and embed an UIView inside itself.
 | 
			
		||||
 | 
			
		||||
    To use it, create one of these, put it in place and make sure it's visible in a
 | 
			
		||||
    window, then use setView() to assign a UIView to it. The view will then be
 | 
			
		||||
    moved and resized to follow the movements of this component.
 | 
			
		||||
 | 
			
		||||
    Of course, since the view is a native object, it'll obliterate any
 | 
			
		||||
    JUCE components that may overlap this component, but that's life.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  UIViewComponent   : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Create an initially-empty container. */
 | 
			
		||||
    UIViewComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~UIViewComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Assigns an UIView to this peer.
 | 
			
		||||
 | 
			
		||||
        The view will be retained and released by this component for as long as
 | 
			
		||||
        it is needed. To remove the current view, just call setView (nullptr).
 | 
			
		||||
 | 
			
		||||
        Note: A void* is used here to avoid including the cocoa headers as
 | 
			
		||||
        part of JuceHeader.h, but the method expects an UIView*.
 | 
			
		||||
    */
 | 
			
		||||
    void setView (void* uiView);
 | 
			
		||||
 | 
			
		||||
    /** Returns the current UIView.
 | 
			
		||||
 | 
			
		||||
        Note: A void* is returned here to avoid the needing to include the cocoa
 | 
			
		||||
        headers, so you should just cast the return value to an UIView*.
 | 
			
		||||
    */
 | 
			
		||||
    void* getView() const;
 | 
			
		||||
 | 
			
		||||
    /** Resizes this component to fit the view that it contains. */
 | 
			
		||||
    void resizeToFitView();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (UIViewComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,117 +1,120 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
/** @internal */
 | 
			
		||||
bool juce_handleXEmbedEvent (ComponentPeer*, void*);
 | 
			
		||||
/** @internal */
 | 
			
		||||
unsigned long juce_getCurrentFocusWindow (ComponentPeer*);
 | 
			
		||||
 | 
			
		||||
#if JUCE_LINUX || JUCE_BSD || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Linux-specific class that can embed a foreign X11 widget.
 | 
			
		||||
 | 
			
		||||
    Use this class to embed a foreign X11 widget from other toolkits such as
 | 
			
		||||
    GTK+ or QT.
 | 
			
		||||
 | 
			
		||||
    There are two ways to initiate the Xembed protocol. Either the client creates
 | 
			
		||||
    a window and passes this to the host (client initiated) or the host
 | 
			
		||||
    creates a window in which the client can reparent it's client widget
 | 
			
		||||
    (host initiated). XEmbedComponent supports both protocol types.
 | 
			
		||||
 | 
			
		||||
    This is how you embed a GTK+ widget: if you are using the client
 | 
			
		||||
    initiated version of the protocol, then create a new gtk widget with
 | 
			
		||||
    gtk_plug_new (0). Then query the window id of the plug via gtk_plug_get_id().
 | 
			
		||||
    Pass this id to the constructor of this class.
 | 
			
		||||
 | 
			
		||||
    If you are using the host initiated version of the protocol, then first create
 | 
			
		||||
    the XEmbedComponent using the default constructor. Use getHostWindowID to get
 | 
			
		||||
    the window id of the host, use this to construct your gtk plug via gtk_plug_new.
 | 
			
		||||
 | 
			
		||||
    A similar approach can be used to embed QT widgets via QT's QX11EmbedWidget
 | 
			
		||||
    class.
 | 
			
		||||
 | 
			
		||||
    Other toolkits or raw X11 widgets should follow the X11 embed protocol:
 | 
			
		||||
    https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class XEmbedComponent : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
 | 
			
		||||
    /** Creates a JUCE component wrapping a foreign widget
 | 
			
		||||
 | 
			
		||||
        Use this constructor if you are using the host initiated version
 | 
			
		||||
        of the XEmbedProtocol. When using this version of the protocol
 | 
			
		||||
        you must call getHostWindowID() and pass this id to the foreign toolkit.
 | 
			
		||||
    */
 | 
			
		||||
    XEmbedComponent (bool wantsKeyboardFocus = true,
 | 
			
		||||
                     bool allowForeignWidgetToResizeComponent = false);
 | 
			
		||||
 | 
			
		||||
    /** Create a JUCE component wrapping the foreign widget with id wID
 | 
			
		||||
 | 
			
		||||
        Use this constructor if you are using the client initiated version
 | 
			
		||||
        of the XEmbedProtocol.
 | 
			
		||||
    */
 | 
			
		||||
    XEmbedComponent (unsigned long wID, bool wantsKeyboardFocus = true,
 | 
			
		||||
                     bool allowForeignWidgetToResizeComponent = false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~XEmbedComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Use this method to retrieve the host's window id when using the
 | 
			
		||||
        host initiated version of the XEmbedProtocol
 | 
			
		||||
    */
 | 
			
		||||
    unsigned long getHostWindowID();
 | 
			
		||||
 | 
			
		||||
    /** Removes the client window from the host. */
 | 
			
		||||
    void removeClient();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    void focusGained (FocusChangeType) override;
 | 
			
		||||
    void focusLost (FocusChangeType) override;
 | 
			
		||||
    void broughtToFront() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend bool juce::juce_handleXEmbedEvent (ComponentPeer*, void*);
 | 
			
		||||
    friend unsigned long juce_getCurrentFocusWindow (ComponentPeer*);
 | 
			
		||||
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
/** @internal */
 | 
			
		||||
bool juce_handleXEmbedEvent (ComponentPeer*, void*);
 | 
			
		||||
/** @internal */
 | 
			
		||||
unsigned long juce_getCurrentFocusWindow (ComponentPeer*);
 | 
			
		||||
 | 
			
		||||
#if JUCE_LINUX || JUCE_BSD || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A Linux-specific class that can embed a foreign X11 widget.
 | 
			
		||||
 | 
			
		||||
    Use this class to embed a foreign X11 widget from other toolkits such as
 | 
			
		||||
    GTK+ or QT.
 | 
			
		||||
 | 
			
		||||
    There are two ways to initiate the Xembed protocol. Either the client creates
 | 
			
		||||
    a window and passes this to the host (client initiated) or the host
 | 
			
		||||
    creates a window in which the client can reparent it's client widget
 | 
			
		||||
    (host initiated). XEmbedComponent supports both protocol types.
 | 
			
		||||
 | 
			
		||||
    This is how you embed a GTK+ widget: if you are using the client
 | 
			
		||||
    initiated version of the protocol, then create a new gtk widget with
 | 
			
		||||
    gtk_plug_new (0). Then query the window id of the plug via gtk_plug_get_id().
 | 
			
		||||
    Pass this id to the constructor of this class.
 | 
			
		||||
 | 
			
		||||
    If you are using the host initiated version of the protocol, then first create
 | 
			
		||||
    the XEmbedComponent using the default constructor. Use getHostWindowID to get
 | 
			
		||||
    the window id of the host, use this to construct your gtk plug via gtk_plug_new.
 | 
			
		||||
 | 
			
		||||
    A similar approach can be used to embed QT widgets via QT's QX11EmbedWidget
 | 
			
		||||
    class.
 | 
			
		||||
 | 
			
		||||
    Other toolkits or raw X11 widgets should follow the X11 embed protocol:
 | 
			
		||||
    https://specifications.freedesktop.org/xembed-spec/xembed-spec-latest.html
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class XEmbedComponent : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
 | 
			
		||||
    /** Creates a JUCE component wrapping a foreign widget
 | 
			
		||||
 | 
			
		||||
        Use this constructor if you are using the host initiated version
 | 
			
		||||
        of the XEmbedProtocol. When using this version of the protocol
 | 
			
		||||
        you must call getHostWindowID() and pass this id to the foreign toolkit.
 | 
			
		||||
    */
 | 
			
		||||
    XEmbedComponent (bool wantsKeyboardFocus = true,
 | 
			
		||||
                     bool allowForeignWidgetToResizeComponent = false);
 | 
			
		||||
 | 
			
		||||
    /** Create a JUCE component wrapping the foreign widget with id wID
 | 
			
		||||
 | 
			
		||||
        Use this constructor if you are using the client initiated version
 | 
			
		||||
        of the XEmbedProtocol.
 | 
			
		||||
    */
 | 
			
		||||
    XEmbedComponent (unsigned long wID, bool wantsKeyboardFocus = true,
 | 
			
		||||
                     bool allowForeignWidgetToResizeComponent = false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~XEmbedComponent() override;
 | 
			
		||||
 | 
			
		||||
    /** Use this method to retrieve the host's window id when using the
 | 
			
		||||
        host initiated version of the XEmbedProtocol
 | 
			
		||||
    */
 | 
			
		||||
    unsigned long getHostWindowID();
 | 
			
		||||
 | 
			
		||||
    /** Removes the client window from the host. */
 | 
			
		||||
    void removeClient();
 | 
			
		||||
 | 
			
		||||
    /** Forces the embedded window to match the current size of this component. */
 | 
			
		||||
    void updateEmbeddedBounds();
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    void focusGained (FocusChangeType) override;
 | 
			
		||||
    void focusLost (FocusChangeType) override;
 | 
			
		||||
    void broughtToFront() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    friend bool juce::juce_handleXEmbedEvent (ComponentPeer*, void*);
 | 
			
		||||
    friend unsigned long juce_getCurrentFocusWindow (ComponentPeer*);
 | 
			
		||||
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										392
									
								
								deps/juce/modules/juce_gui_extra/juce_gui_extra.cpp
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										392
									
								
								deps/juce/modules/juce_gui_extra/juce_gui_extra.cpp
									
									
									
									
										vendored
									
									
								
							@@ -1,197 +1,195 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifdef JUCE_GUI_EXTRA_H_INCLUDED
 | 
			
		||||
 /* When you add this cpp file to your project, you mustn't include it in a file where you've
 | 
			
		||||
    already included any other headers - just put it inside a file on its own, possibly with your config
 | 
			
		||||
    flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
 | 
			
		||||
    header files that the compiler may be using.
 | 
			
		||||
 */
 | 
			
		||||
 #error "Incorrect use of JUCE cpp file"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
 | 
			
		||||
#define JUCE_CORE_INCLUDE_COM_SMART_PTR 1
 | 
			
		||||
#define JUCE_CORE_INCLUDE_JNI_HELPERS 1
 | 
			
		||||
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
 | 
			
		||||
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1
 | 
			
		||||
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
 | 
			
		||||
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
 | 
			
		||||
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
 | 
			
		||||
 | 
			
		||||
#ifndef JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
 #define JUCE_PUSH_NOTIFICATIONS 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "juce_gui_extra.h"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_MAC
 | 
			
		||||
 #import <WebKit/WebKit.h>
 | 
			
		||||
 #import <IOKit/IOKitLib.h>
 | 
			
		||||
 #import <IOKit/IOCFPlugIn.h>
 | 
			
		||||
 #import <IOKit/hid/IOHIDLib.h>
 | 
			
		||||
 #import <IOKit/hid/IOHIDKeys.h>
 | 
			
		||||
 #import <IOKit/pwr_mgt/IOPMLib.h>
 | 
			
		||||
 | 
			
		||||
 #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
  #import <Foundation/NSUserNotification.h>
 | 
			
		||||
 | 
			
		||||
  #include "native/juce_mac_PushNotifications.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_IOS
 | 
			
		||||
 #import <WebKit/WebKit.h>
 | 
			
		||||
 | 
			
		||||
 #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
  #if defined (__IPHONE_10_0) && __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_10_0
 | 
			
		||||
   #import <UserNotifications/UserNotifications.h>
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
  #include "native/juce_ios_PushNotifications.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_ANDROID
 | 
			
		||||
 #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
  #include "native/juce_android_PushNotifications.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_WINDOWS
 | 
			
		||||
 #include <windowsx.h>
 | 
			
		||||
 #include <vfw.h>
 | 
			
		||||
 #include <commdlg.h>
 | 
			
		||||
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include <exdisp.h>
 | 
			
		||||
  #include <exdispid.h>
 | 
			
		||||
 | 
			
		||||
  #if JUCE_USE_WIN_WEBVIEW2
 | 
			
		||||
   #include <windows.foundation.h>
 | 
			
		||||
   #include <windows.foundation.collections.h>
 | 
			
		||||
 | 
			
		||||
   JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4265)
 | 
			
		||||
   #include <wrl.h>
 | 
			
		||||
   #include <wrl/wrappers/corewrappers.h>
 | 
			
		||||
   JUCE_END_IGNORE_WARNINGS_MSVC
 | 
			
		||||
 | 
			
		||||
   #include "WebView2.h"
 | 
			
		||||
 | 
			
		||||
   JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4458)
 | 
			
		||||
   #include "WebView2EnvironmentOptions.h"
 | 
			
		||||
   JUCE_END_IGNORE_WARNINGS_MSVC
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif (JUCE_LINUX || JUCE_BSD) && JUCE_WEB_BROWSER
 | 
			
		||||
 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant", "-Wparentheses", "-Wdeprecated-declarations")
 | 
			
		||||
 | 
			
		||||
 // If you're missing this header, you need to install the webkit2gtk-4.0 package
 | 
			
		||||
 #include <gtk/gtk.h>
 | 
			
		||||
 #include <gtk/gtkx.h>
 | 
			
		||||
 #include <glib-unix.h>
 | 
			
		||||
 #include <webkit2/webkit2.h>
 | 
			
		||||
 | 
			
		||||
 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#include "documents/juce_FileBasedDocument.cpp"
 | 
			
		||||
#include "code_editor/juce_CodeDocument.cpp"
 | 
			
		||||
#include "code_editor/juce_CodeEditorComponent.cpp"
 | 
			
		||||
#include "code_editor/juce_CPlusPlusCodeTokeniser.cpp"
 | 
			
		||||
#include "code_editor/juce_XMLCodeTokeniser.cpp"
 | 
			
		||||
#include "code_editor/juce_LuaCodeTokeniser.cpp"
 | 
			
		||||
#include "misc/juce_BubbleMessageComponent.cpp"
 | 
			
		||||
#include "misc/juce_ColourSelector.cpp"
 | 
			
		||||
#include "misc/juce_KeyMappingEditorComponent.cpp"
 | 
			
		||||
#include "misc/juce_PreferencesPanel.cpp"
 | 
			
		||||
#include "misc/juce_PushNotifications.cpp"
 | 
			
		||||
#include "misc/juce_RecentlyOpenedFilesList.cpp"
 | 
			
		||||
#include "misc/juce_SplashScreen.cpp"
 | 
			
		||||
#include "misc/juce_SystemTrayIconComponent.cpp"
 | 
			
		||||
#include "misc/juce_LiveConstantEditor.cpp"
 | 
			
		||||
#include "misc/juce_AnimatedAppComponent.cpp"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_MAC || JUCE_IOS
 | 
			
		||||
 | 
			
		||||
 #if JUCE_MAC
 | 
			
		||||
  #include "native/juce_mac_NSViewComponent.mm"
 | 
			
		||||
  #include "native/juce_mac_AppleRemote.mm"
 | 
			
		||||
  #include "native/juce_mac_SystemTrayIcon.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
 #if JUCE_IOS
 | 
			
		||||
  #include "native/juce_ios_UIViewComponent.mm"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include "native/juce_mac_WebBrowserComponent.mm"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_WINDOWS
 | 
			
		||||
 #include "native/juce_win32_ActiveXComponent.cpp"
 | 
			
		||||
 #include "native/juce_win32_HWNDComponent.cpp"
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include "native/juce_win32_WebBrowserComponent.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 #include "native/juce_win32_SystemTrayIcon.cpp"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_LINUX || JUCE_BSD
 | 
			
		||||
 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant")
 | 
			
		||||
 | 
			
		||||
 #include "native/juce_linux_XEmbedComponent.cpp"
 | 
			
		||||
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include "native/juce_linux_X11_WebBrowserComponent.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
 #include "native/juce_linux_X11_SystemTrayIcon.cpp"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_ANDROID
 | 
			
		||||
 #include "native/juce_AndroidViewComponent.cpp"
 | 
			
		||||
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include "native/juce_android_WebBrowserComponent.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if ! JUCE_WINDOWS && JUCE_WEB_BROWSER
 | 
			
		||||
 juce::WebBrowserComponent::WebBrowserComponent (ConstructWithoutPimpl) {}
 | 
			
		||||
 juce::WindowsWebView2WebBrowserComponent::WindowsWebView2WebBrowserComponent (bool unloadWhenHidden,
 | 
			
		||||
                                                                               const WebView2Preferences&)
 | 
			
		||||
     : WebBrowserComponent (unloadWhenHidden) {}
 | 
			
		||||
#endif
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#ifdef JUCE_GUI_EXTRA_H_INCLUDED
 | 
			
		||||
 /* When you add this cpp file to your project, you mustn't include it in a file where you've
 | 
			
		||||
    already included any other headers - just put it inside a file on its own, possibly with your config
 | 
			
		||||
    flags preceding it, but don't include anything else. That also includes avoiding any automatic prefix
 | 
			
		||||
    header files that the compiler may be using.
 | 
			
		||||
 */
 | 
			
		||||
 #error "Incorrect use of JUCE cpp file"
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#define JUCE_CORE_INCLUDE_OBJC_HELPERS 1
 | 
			
		||||
#define JUCE_CORE_INCLUDE_COM_SMART_PTR 1
 | 
			
		||||
#define JUCE_CORE_INCLUDE_JNI_HELPERS 1
 | 
			
		||||
#define JUCE_CORE_INCLUDE_NATIVE_HEADERS 1
 | 
			
		||||
#define JUCE_EVENTS_INCLUDE_WIN32_MESSAGE_WINDOW 1
 | 
			
		||||
#define JUCE_GRAPHICS_INCLUDE_COREGRAPHICS_HELPERS 1
 | 
			
		||||
#define JUCE_GUI_BASICS_INCLUDE_XHEADERS 1
 | 
			
		||||
#define JUCE_GUI_BASICS_INCLUDE_SCOPED_THREAD_DPI_AWARENESS_SETTER 1
 | 
			
		||||
 | 
			
		||||
#ifndef JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
 #define JUCE_PUSH_NOTIFICATIONS 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#include "juce_gui_extra.h"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_MAC
 | 
			
		||||
 #import <WebKit/WebKit.h>
 | 
			
		||||
 #import <IOKit/IOKitLib.h>
 | 
			
		||||
 #import <IOKit/IOCFPlugIn.h>
 | 
			
		||||
 #import <IOKit/hid/IOHIDLib.h>
 | 
			
		||||
 #import <IOKit/hid/IOHIDKeys.h>
 | 
			
		||||
 #import <IOKit/pwr_mgt/IOPMLib.h>
 | 
			
		||||
 | 
			
		||||
 #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
  #import <Foundation/NSUserNotification.h>
 | 
			
		||||
 | 
			
		||||
  #include "native/juce_mac_PushNotifications.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_IOS
 | 
			
		||||
 #import <WebKit/WebKit.h>
 | 
			
		||||
 | 
			
		||||
 #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
  #import <UserNotifications/UserNotifications.h>
 | 
			
		||||
  #include "native/juce_ios_PushNotifications.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_ANDROID
 | 
			
		||||
 #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
  #include "native/juce_android_PushNotifications.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_WINDOWS
 | 
			
		||||
 #include <windowsx.h>
 | 
			
		||||
 #include <vfw.h>
 | 
			
		||||
 #include <commdlg.h>
 | 
			
		||||
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include <exdisp.h>
 | 
			
		||||
  #include <exdispid.h>
 | 
			
		||||
 | 
			
		||||
  #if JUCE_USE_WIN_WEBVIEW2
 | 
			
		||||
   #include <windows.foundation.h>
 | 
			
		||||
   #include <windows.foundation.collections.h>
 | 
			
		||||
 | 
			
		||||
   JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4265)
 | 
			
		||||
   #include <wrl.h>
 | 
			
		||||
   #include <wrl/wrappers/corewrappers.h>
 | 
			
		||||
   JUCE_END_IGNORE_WARNINGS_MSVC
 | 
			
		||||
 | 
			
		||||
   #include "WebView2.h"
 | 
			
		||||
 | 
			
		||||
   JUCE_BEGIN_IGNORE_WARNINGS_MSVC (4458)
 | 
			
		||||
   #include "WebView2EnvironmentOptions.h"
 | 
			
		||||
   JUCE_END_IGNORE_WARNINGS_MSVC
 | 
			
		||||
  #endif
 | 
			
		||||
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif (JUCE_LINUX || JUCE_BSD) && JUCE_WEB_BROWSER
 | 
			
		||||
 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant", "-Wparentheses", "-Wdeprecated-declarations")
 | 
			
		||||
 | 
			
		||||
 // If you're missing this header, you need to install the webkit2gtk-4.0 package
 | 
			
		||||
 #include <gtk/gtk.h>
 | 
			
		||||
 #include <gtk/gtkx.h>
 | 
			
		||||
 #include <glib-unix.h>
 | 
			
		||||
 #include <webkit2/webkit2.h>
 | 
			
		||||
 | 
			
		||||
 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#include "documents/juce_FileBasedDocument.cpp"
 | 
			
		||||
#include "code_editor/juce_CodeDocument.cpp"
 | 
			
		||||
#include "code_editor/juce_CodeEditorComponent.cpp"
 | 
			
		||||
#include "code_editor/juce_CPlusPlusCodeTokeniser.cpp"
 | 
			
		||||
#include "code_editor/juce_XMLCodeTokeniser.cpp"
 | 
			
		||||
#include "code_editor/juce_LuaCodeTokeniser.cpp"
 | 
			
		||||
#include "misc/juce_BubbleMessageComponent.cpp"
 | 
			
		||||
#include "misc/juce_ColourSelector.cpp"
 | 
			
		||||
#include "misc/juce_KeyMappingEditorComponent.cpp"
 | 
			
		||||
#include "misc/juce_PreferencesPanel.cpp"
 | 
			
		||||
#include "misc/juce_PushNotifications.cpp"
 | 
			
		||||
#include "misc/juce_RecentlyOpenedFilesList.cpp"
 | 
			
		||||
#include "misc/juce_SplashScreen.cpp"
 | 
			
		||||
#include "misc/juce_SystemTrayIconComponent.cpp"
 | 
			
		||||
#include "misc/juce_LiveConstantEditor.cpp"
 | 
			
		||||
#include "misc/juce_AnimatedAppComponent.cpp"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_MAC || JUCE_IOS
 | 
			
		||||
 | 
			
		||||
 #if JUCE_MAC
 | 
			
		||||
  #include "native/juce_mac_NSViewFrameWatcher.h"
 | 
			
		||||
  #include "native/juce_mac_NSViewComponent.mm"
 | 
			
		||||
  #include "native/juce_mac_AppleRemote.mm"
 | 
			
		||||
  #include "native/juce_mac_SystemTrayIcon.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
 #if JUCE_IOS
 | 
			
		||||
  #include "native/juce_ios_UIViewComponent.mm"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include "native/juce_mac_WebBrowserComponent.mm"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_WINDOWS
 | 
			
		||||
 #include "native/juce_win32_ActiveXComponent.cpp"
 | 
			
		||||
 #include "native/juce_win32_HWNDComponent.cpp"
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include "native/juce_win32_WebBrowserComponent.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 #include "native/juce_win32_SystemTrayIcon.cpp"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_LINUX || JUCE_BSD
 | 
			
		||||
 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wzero-as-null-pointer-constant")
 | 
			
		||||
 | 
			
		||||
 #include "native/juce_linux_XEmbedComponent.cpp"
 | 
			
		||||
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include "native/juce_linux_X11_WebBrowserComponent.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
 | 
			
		||||
 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
 #include "native/juce_linux_X11_SystemTrayIcon.cpp"
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#elif JUCE_ANDROID
 | 
			
		||||
 #include "native/juce_AndroidViewComponent.cpp"
 | 
			
		||||
 | 
			
		||||
 #if JUCE_WEB_BROWSER
 | 
			
		||||
  #include "native/juce_android_WebBrowserComponent.cpp"
 | 
			
		||||
 #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if ! JUCE_WINDOWS && JUCE_WEB_BROWSER
 | 
			
		||||
 juce::WebBrowserComponent::WebBrowserComponent (ConstructWithoutPimpl) {}
 | 
			
		||||
 juce::WindowsWebView2WebBrowserComponent::WindowsWebView2WebBrowserComponent (bool unloadWhenHidden,
 | 
			
		||||
                                                                               const WebView2Preferences&)
 | 
			
		||||
     : WebBrowserComponent (unloadWhenHidden) {}
 | 
			
		||||
#endif
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										244
									
								
								deps/juce/modules/juce_gui_extra/juce_gui_extra.h
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										244
									
								
								deps/juce/modules/juce_gui_extra/juce_gui_extra.h
									
									
									
									
										vendored
									
									
								
							@@ -1,121 +1,123 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************
 | 
			
		||||
 The block below describes the properties of this module, and is read by
 | 
			
		||||
 the Projucer to automatically generate project code that uses it.
 | 
			
		||||
 For details about the syntax and how to create or use a module, see the
 | 
			
		||||
 JUCE Module Format.md file.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 BEGIN_JUCE_MODULE_DECLARATION
 | 
			
		||||
 | 
			
		||||
  ID:                 juce_gui_extra
 | 
			
		||||
  vendor:             juce
 | 
			
		||||
  version:            6.1.2
 | 
			
		||||
  name:               JUCE extended GUI classes
 | 
			
		||||
  description:        Miscellaneous GUI classes for specialised tasks.
 | 
			
		||||
  website:            http://www.juce.com/juce
 | 
			
		||||
  license:            GPL/Commercial
 | 
			
		||||
  minimumCppStandard: 14
 | 
			
		||||
 | 
			
		||||
  dependencies:       juce_gui_basics
 | 
			
		||||
  OSXFrameworks:      WebKit
 | 
			
		||||
  iOSFrameworks:      WebKit
 | 
			
		||||
 | 
			
		||||
 END_JUCE_MODULE_DECLARATION
 | 
			
		||||
 | 
			
		||||
*******************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#define JUCE_GUI_EXTRA_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <juce_gui_basics/juce_gui_basics.h>
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** Config: JUCE_WEB_BROWSER
 | 
			
		||||
    This lets you disable the WebBrowserComponent class.
 | 
			
		||||
    If you're not using any embedded web-pages, turning this off may reduce your code size.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef JUCE_WEB_BROWSER
 | 
			
		||||
 #define JUCE_WEB_BROWSER 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Config: JUCE_USE_WIN_WEBVIEW2
 | 
			
		||||
    Enables the use of the Microsoft Edge (Chromium) WebView2 browser on Windows,
 | 
			
		||||
    currently in developer preview.
 | 
			
		||||
 | 
			
		||||
    If using the Projucer, the Microsoft.Web.WebView2 package will be added to the
 | 
			
		||||
    project solution if this flag is enabled. If you are building using CMake you
 | 
			
		||||
    will need to manually add the package via the Visual Studio package manager.
 | 
			
		||||
 | 
			
		||||
    In addition to enabling this macro, you will need to use the
 | 
			
		||||
    WindowsWebView2WebBrowserComponent wrapper - see the documentation of that
 | 
			
		||||
    class for more details.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef JUCE_USE_WIN_WEBVIEW2
 | 
			
		||||
 #define JUCE_USE_WIN_WEBVIEW2 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Config: JUCE_ENABLE_LIVE_CONSTANT_EDITOR
 | 
			
		||||
    This lets you turn on the JUCE_ENABLE_LIVE_CONSTANT_EDITOR support (desktop only). By default
 | 
			
		||||
    this will be enabled for debug builds and disabled for release builds. See the documentation
 | 
			
		||||
    for that macro for more details.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR
 | 
			
		||||
 #if JUCE_DEBUG && ! (JUCE_IOS || JUCE_ANDROID)
 | 
			
		||||
  #define JUCE_ENABLE_LIVE_CONSTANT_EDITOR 1
 | 
			
		||||
 #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#include "documents/juce_FileBasedDocument.h"
 | 
			
		||||
#include "code_editor/juce_CodeDocument.h"
 | 
			
		||||
#include "code_editor/juce_CodeEditorComponent.h"
 | 
			
		||||
#include "code_editor/juce_CodeTokeniser.h"
 | 
			
		||||
#include "code_editor/juce_CPlusPlusCodeTokeniser.h"
 | 
			
		||||
#include "code_editor/juce_CPlusPlusCodeTokeniserFunctions.h"
 | 
			
		||||
#include "code_editor/juce_XMLCodeTokeniser.h"
 | 
			
		||||
#include "code_editor/juce_LuaCodeTokeniser.h"
 | 
			
		||||
#include "embedding/juce_ActiveXControlComponent.h"
 | 
			
		||||
#include "embedding/juce_AndroidViewComponent.h"
 | 
			
		||||
#include "embedding/juce_NSViewComponent.h"
 | 
			
		||||
#include "embedding/juce_UIViewComponent.h"
 | 
			
		||||
#include "embedding/juce_XEmbedComponent.h"
 | 
			
		||||
#include "embedding/juce_HWNDComponent.h"
 | 
			
		||||
#include "misc/juce_AppleRemote.h"
 | 
			
		||||
#include "misc/juce_BubbleMessageComponent.h"
 | 
			
		||||
#include "misc/juce_ColourSelector.h"
 | 
			
		||||
#include "misc/juce_KeyMappingEditorComponent.h"
 | 
			
		||||
#include "misc/juce_PreferencesPanel.h"
 | 
			
		||||
#include "misc/juce_PushNotifications.h"
 | 
			
		||||
#include "misc/juce_RecentlyOpenedFilesList.h"
 | 
			
		||||
#include "misc/juce_SplashScreen.h"
 | 
			
		||||
#include "misc/juce_SystemTrayIconComponent.h"
 | 
			
		||||
#include "misc/juce_WebBrowserComponent.h"
 | 
			
		||||
#include "misc/juce_LiveConstantEditor.h"
 | 
			
		||||
#include "misc/juce_AnimatedAppComponent.h"
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*******************************************************************************
 | 
			
		||||
 The block below describes the properties of this module, and is read by
 | 
			
		||||
 the Projucer to automatically generate project code that uses it.
 | 
			
		||||
 For details about the syntax and how to create or use a module, see the
 | 
			
		||||
 JUCE Module Format.md file.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 BEGIN_JUCE_MODULE_DECLARATION
 | 
			
		||||
 | 
			
		||||
  ID:                     juce_gui_extra
 | 
			
		||||
  vendor:                 juce
 | 
			
		||||
  version:                7.0.2
 | 
			
		||||
  name:                   JUCE extended GUI classes
 | 
			
		||||
  description:            Miscellaneous GUI classes for specialised tasks.
 | 
			
		||||
  website:                http://www.juce.com/juce
 | 
			
		||||
  license:                GPL/Commercial
 | 
			
		||||
  minimumCppStandard:     14
 | 
			
		||||
 | 
			
		||||
  dependencies:           juce_gui_basics
 | 
			
		||||
  OSXFrameworks:          WebKit
 | 
			
		||||
  iOSFrameworks:          WebKit
 | 
			
		||||
  WeakiOSFrameworks:      UserNotifications
 | 
			
		||||
  WeakMacOSFrameworks:    UserNotifications
 | 
			
		||||
 | 
			
		||||
 END_JUCE_MODULE_DECLARATION
 | 
			
		||||
 | 
			
		||||
*******************************************************************************/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
#define JUCE_GUI_EXTRA_H_INCLUDED
 | 
			
		||||
 | 
			
		||||
#include <juce_gui_basics/juce_gui_basics.h>
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** Config: JUCE_WEB_BROWSER
 | 
			
		||||
    This lets you disable the WebBrowserComponent class.
 | 
			
		||||
    If you're not using any embedded web-pages, turning this off may reduce your code size.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef JUCE_WEB_BROWSER
 | 
			
		||||
 #define JUCE_WEB_BROWSER 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Config: JUCE_USE_WIN_WEBVIEW2
 | 
			
		||||
    Enables the use of the Microsoft Edge (Chromium) WebView2 browser on Windows,
 | 
			
		||||
    currently in developer preview.
 | 
			
		||||
 | 
			
		||||
    If using the Projucer, the Microsoft.Web.WebView2 package will be added to the
 | 
			
		||||
    project solution if this flag is enabled. If you are building using CMake you
 | 
			
		||||
    will need to manually add the package via the Visual Studio package manager.
 | 
			
		||||
 | 
			
		||||
    In addition to enabling this macro, you will need to use the
 | 
			
		||||
    WindowsWebView2WebBrowserComponent wrapper - see the documentation of that
 | 
			
		||||
    class for more details.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef JUCE_USE_WIN_WEBVIEW2
 | 
			
		||||
 #define JUCE_USE_WIN_WEBVIEW2 0
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
/** Config: JUCE_ENABLE_LIVE_CONSTANT_EDITOR
 | 
			
		||||
    This lets you turn on the JUCE_ENABLE_LIVE_CONSTANT_EDITOR support (desktop only). By default
 | 
			
		||||
    this will be enabled for debug builds and disabled for release builds. See the documentation
 | 
			
		||||
    for that macro for more details.
 | 
			
		||||
*/
 | 
			
		||||
#ifndef JUCE_ENABLE_LIVE_CONSTANT_EDITOR
 | 
			
		||||
 #if JUCE_DEBUG && ! (JUCE_IOS || JUCE_ANDROID)
 | 
			
		||||
  #define JUCE_ENABLE_LIVE_CONSTANT_EDITOR 1
 | 
			
		||||
 #endif
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#include "documents/juce_FileBasedDocument.h"
 | 
			
		||||
#include "code_editor/juce_CodeDocument.h"
 | 
			
		||||
#include "code_editor/juce_CodeEditorComponent.h"
 | 
			
		||||
#include "code_editor/juce_CodeTokeniser.h"
 | 
			
		||||
#include "code_editor/juce_CPlusPlusCodeTokeniser.h"
 | 
			
		||||
#include "code_editor/juce_CPlusPlusCodeTokeniserFunctions.h"
 | 
			
		||||
#include "code_editor/juce_XMLCodeTokeniser.h"
 | 
			
		||||
#include "code_editor/juce_LuaCodeTokeniser.h"
 | 
			
		||||
#include "embedding/juce_ActiveXControlComponent.h"
 | 
			
		||||
#include "embedding/juce_AndroidViewComponent.h"
 | 
			
		||||
#include "embedding/juce_NSViewComponent.h"
 | 
			
		||||
#include "embedding/juce_UIViewComponent.h"
 | 
			
		||||
#include "embedding/juce_XEmbedComponent.h"
 | 
			
		||||
#include "embedding/juce_HWNDComponent.h"
 | 
			
		||||
#include "misc/juce_AppleRemote.h"
 | 
			
		||||
#include "misc/juce_BubbleMessageComponent.h"
 | 
			
		||||
#include "misc/juce_ColourSelector.h"
 | 
			
		||||
#include "misc/juce_KeyMappingEditorComponent.h"
 | 
			
		||||
#include "misc/juce_PreferencesPanel.h"
 | 
			
		||||
#include "misc/juce_PushNotifications.h"
 | 
			
		||||
#include "misc/juce_RecentlyOpenedFilesList.h"
 | 
			
		||||
#include "misc/juce_SplashScreen.h"
 | 
			
		||||
#include "misc/juce_SystemTrayIconComponent.h"
 | 
			
		||||
#include "misc/juce_WebBrowserComponent.h"
 | 
			
		||||
#include "misc/juce_LiveConstantEditor.h"
 | 
			
		||||
#include "misc/juce_AnimatedAppComponent.h"
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -1,54 +1,54 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AnimatedAppComponent::AnimatedAppComponent()
 | 
			
		||||
    : lastUpdateTime (Time::getCurrentTime()), totalUpdates (0)
 | 
			
		||||
{
 | 
			
		||||
    setOpaque (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnimatedAppComponent::setFramesPerSecond (int framesPerSecond)
 | 
			
		||||
{
 | 
			
		||||
    jassert (framesPerSecond > 0 && framesPerSecond < 1000);
 | 
			
		||||
    startTimerHz (framesPerSecond);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int AnimatedAppComponent::getMillisecondsSinceLastUpdate() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return (int) (Time::getCurrentTime() - lastUpdateTime).inMilliseconds();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnimatedAppComponent::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    ++totalUpdates;
 | 
			
		||||
    update();
 | 
			
		||||
    repaint();
 | 
			
		||||
    lastUpdateTime = Time::getCurrentTime();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
AnimatedAppComponent::AnimatedAppComponent()
 | 
			
		||||
    : lastUpdateTime (Time::getCurrentTime()), totalUpdates (0)
 | 
			
		||||
{
 | 
			
		||||
    setOpaque (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnimatedAppComponent::setFramesPerSecond (int framesPerSecond)
 | 
			
		||||
{
 | 
			
		||||
    jassert (framesPerSecond > 0 && framesPerSecond < 1000);
 | 
			
		||||
    startTimerHz (framesPerSecond);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int AnimatedAppComponent::getMillisecondsSinceLastUpdate() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return (int) (Time::getCurrentTime() - lastUpdateTime).inMilliseconds();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AnimatedAppComponent::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    ++totalUpdates;
 | 
			
		||||
    update();
 | 
			
		||||
    repaint();
 | 
			
		||||
    lastUpdateTime = Time::getCurrentTime();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,77 +1,77 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for writing simple one-page graphical apps.
 | 
			
		||||
 | 
			
		||||
    A subclass can inherit from this and implement just a few methods such as
 | 
			
		||||
    paint() and mouse-handling. The base class provides some simple abstractions
 | 
			
		||||
    to take care of continuously repainting itself.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class AnimatedAppComponent   : public Component,
 | 
			
		||||
                               private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    AnimatedAppComponent();
 | 
			
		||||
 | 
			
		||||
    /** Your subclass can call this to start a timer running which will
 | 
			
		||||
        call update() and repaint the component at the given frequency.
 | 
			
		||||
    */
 | 
			
		||||
    void setFramesPerSecond (int framesPerSecond);
 | 
			
		||||
 | 
			
		||||
    /** Called periodically, at the frequency specified by setFramesPerSecond().
 | 
			
		||||
        This is a the best place to do things like advancing animation parameters,
 | 
			
		||||
        checking the mouse position, etc.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void update() = 0;
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of times that update() has been called since the component
 | 
			
		||||
        started running.
 | 
			
		||||
    */
 | 
			
		||||
    int getFrameCounter() const noexcept        { return totalUpdates; }
 | 
			
		||||
 | 
			
		||||
    /** When called from update(), this returns the number of milliseconds since the
 | 
			
		||||
        last update call.
 | 
			
		||||
        This might be useful for accurately timing animations, etc.
 | 
			
		||||
    */
 | 
			
		||||
    int getMillisecondsSinceLastUpdate() const noexcept;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Time lastUpdateTime;
 | 
			
		||||
    int totalUpdates;
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnimatedAppComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A base class for writing simple one-page graphical apps.
 | 
			
		||||
 | 
			
		||||
    A subclass can inherit from this and implement just a few methods such as
 | 
			
		||||
    paint() and mouse-handling. The base class provides some simple abstractions
 | 
			
		||||
    to take care of continuously repainting itself.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class AnimatedAppComponent   : public Component,
 | 
			
		||||
                               private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    AnimatedAppComponent();
 | 
			
		||||
 | 
			
		||||
    /** Your subclass can call this to start a timer running which will
 | 
			
		||||
        call update() and repaint the component at the given frequency.
 | 
			
		||||
    */
 | 
			
		||||
    void setFramesPerSecond (int framesPerSecond);
 | 
			
		||||
 | 
			
		||||
    /** Called periodically, at the frequency specified by setFramesPerSecond().
 | 
			
		||||
        This is a the best place to do things like advancing animation parameters,
 | 
			
		||||
        checking the mouse position, etc.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void update() = 0;
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of times that update() has been called since the component
 | 
			
		||||
        started running.
 | 
			
		||||
    */
 | 
			
		||||
    int getFrameCounter() const noexcept        { return totalUpdates; }
 | 
			
		||||
 | 
			
		||||
    /** When called from update(), this returns the number of milliseconds since the
 | 
			
		||||
        last update call.
 | 
			
		||||
        This might be useful for accurately timing animations, etc.
 | 
			
		||||
    */
 | 
			
		||||
    int getMillisecondsSinceLastUpdate() const noexcept;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Time lastUpdateTime;
 | 
			
		||||
    int totalUpdates;
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AnimatedAppComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,117 +1,117 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_MAC || DOXYGEN
 | 
			
		||||
/**
 | 
			
		||||
    Receives events from an Apple IR remote control device (Only available in OSX!).
 | 
			
		||||
 | 
			
		||||
    To use it, just create a subclass of this class, implementing the buttonPressed()
 | 
			
		||||
    callback, then call start() and stop() to start or stop receiving events.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AppleRemoteDevice
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    AppleRemoteDevice();
 | 
			
		||||
    virtual ~AppleRemoteDevice();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** The set of buttons that may be pressed.
 | 
			
		||||
        @see buttonPressed
 | 
			
		||||
    */
 | 
			
		||||
    enum ButtonType
 | 
			
		||||
    {
 | 
			
		||||
        menuButton = 0,     /**< The menu button (if it's held for a short time). */
 | 
			
		||||
        playButton,         /**< The play button. */
 | 
			
		||||
        plusButton,         /**< The plus or volume-up button. */
 | 
			
		||||
        minusButton,        /**< The minus or volume-down button. */
 | 
			
		||||
        rightButton,        /**< The right button (if it's held for a short time). */
 | 
			
		||||
        leftButton,         /**< The left button (if it's held for a short time). */
 | 
			
		||||
        rightButton_Long,   /**< The right button (if it's held for a long time). */
 | 
			
		||||
        leftButton_Long,    /**< The menu button (if it's held for a long time). */
 | 
			
		||||
        menuButton_Long,    /**< The menu button (if it's held for a long time). */
 | 
			
		||||
        playButtonSleepMode,
 | 
			
		||||
        switched
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Override this method to receive the callback about a button press.
 | 
			
		||||
 | 
			
		||||
        The callback will happen on the application's message thread.
 | 
			
		||||
 | 
			
		||||
        Some buttons trigger matching up and down events, in which the isDown parameter
 | 
			
		||||
        will be true and then false. Others only send a single event when the
 | 
			
		||||
        button is pressed.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void buttonPressed (ButtonType buttonId, bool isDown) = 0;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Starts the device running and responding to events.
 | 
			
		||||
 | 
			
		||||
        Returns true if it managed to open the device.
 | 
			
		||||
 | 
			
		||||
        @param inExclusiveMode  if true, the remote will be grabbed exclusively for this app,
 | 
			
		||||
                                and will not be available to any other part of the system. If
 | 
			
		||||
                                false, it will be shared with other apps.
 | 
			
		||||
        @see stop
 | 
			
		||||
    */
 | 
			
		||||
    bool start (bool inExclusiveMode);
 | 
			
		||||
 | 
			
		||||
    /** Stops the device running.
 | 
			
		||||
        @see start
 | 
			
		||||
    */
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the device has been started successfully.
 | 
			
		||||
    */
 | 
			
		||||
    bool isActive() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns the ID number of the remote, if it has sent one.
 | 
			
		||||
    */
 | 
			
		||||
    int getRemoteId() const                     { return remoteId; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void handleCallbackInternal();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void* device;
 | 
			
		||||
    void* queue;
 | 
			
		||||
    int remoteId;
 | 
			
		||||
 | 
			
		||||
    bool open (bool openInExclusiveMode);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AppleRemoteDevice)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_MAC || DOXYGEN
 | 
			
		||||
/**
 | 
			
		||||
    Receives events from an Apple IR remote control device (Only available in OSX!).
 | 
			
		||||
 | 
			
		||||
    To use it, just create a subclass of this class, implementing the buttonPressed()
 | 
			
		||||
    callback, then call start() and stop() to start or stop receiving events.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  AppleRemoteDevice
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    AppleRemoteDevice();
 | 
			
		||||
    virtual ~AppleRemoteDevice();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** The set of buttons that may be pressed.
 | 
			
		||||
        @see buttonPressed
 | 
			
		||||
    */
 | 
			
		||||
    enum ButtonType
 | 
			
		||||
    {
 | 
			
		||||
        menuButton = 0,     /**< The menu button (if it's held for a short time). */
 | 
			
		||||
        playButton,         /**< The play button. */
 | 
			
		||||
        plusButton,         /**< The plus or volume-up button. */
 | 
			
		||||
        minusButton,        /**< The minus or volume-down button. */
 | 
			
		||||
        rightButton,        /**< The right button (if it's held for a short time). */
 | 
			
		||||
        leftButton,         /**< The left button (if it's held for a short time). */
 | 
			
		||||
        rightButton_Long,   /**< The right button (if it's held for a long time). */
 | 
			
		||||
        leftButton_Long,    /**< The menu button (if it's held for a long time). */
 | 
			
		||||
        menuButton_Long,    /**< The menu button (if it's held for a long time). */
 | 
			
		||||
        playButtonSleepMode,
 | 
			
		||||
        switched
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Override this method to receive the callback about a button press.
 | 
			
		||||
 | 
			
		||||
        The callback will happen on the application's message thread.
 | 
			
		||||
 | 
			
		||||
        Some buttons trigger matching up and down events, in which the isDown parameter
 | 
			
		||||
        will be true and then false. Others only send a single event when the
 | 
			
		||||
        button is pressed.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void buttonPressed (ButtonType buttonId, bool isDown) = 0;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Starts the device running and responding to events.
 | 
			
		||||
 | 
			
		||||
        Returns true if it managed to open the device.
 | 
			
		||||
 | 
			
		||||
        @param inExclusiveMode  if true, the remote will be grabbed exclusively for this app,
 | 
			
		||||
                                and will not be available to any other part of the system. If
 | 
			
		||||
                                false, it will be shared with other apps.
 | 
			
		||||
        @see stop
 | 
			
		||||
    */
 | 
			
		||||
    bool start (bool inExclusiveMode);
 | 
			
		||||
 | 
			
		||||
    /** Stops the device running.
 | 
			
		||||
        @see start
 | 
			
		||||
    */
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
    /** Returns true if the device has been started successfully.
 | 
			
		||||
    */
 | 
			
		||||
    bool isActive() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns the ID number of the remote, if it has sent one.
 | 
			
		||||
    */
 | 
			
		||||
    int getRemoteId() const                     { return remoteId; }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void handleCallbackInternal();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void* device;
 | 
			
		||||
    void* queue;
 | 
			
		||||
    int remoteId;
 | 
			
		||||
 | 
			
		||||
    bool open (bool openInExclusiveMode);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (AppleRemoteDevice)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,124 +1,124 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
BubbleMessageComponent::BubbleMessageComponent (int fadeOutLengthMs)
 | 
			
		||||
    : fadeOutLength (fadeOutLengthMs), mouseClickCounter (0),
 | 
			
		||||
      expiryTime (0), deleteAfterUse (false)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BubbleMessageComponent::~BubbleMessageComponent()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::showAt (const Rectangle<int>& pos,
 | 
			
		||||
                                     const AttributedString& text,
 | 
			
		||||
                                     const int numMillisecondsBeforeRemoving,
 | 
			
		||||
                                     const bool removeWhenMouseClicked,
 | 
			
		||||
                                     const bool deleteSelfAfterUse)
 | 
			
		||||
{
 | 
			
		||||
    createLayout (text);
 | 
			
		||||
    setPosition (pos);
 | 
			
		||||
    init (numMillisecondsBeforeRemoving, removeWhenMouseClicked, deleteSelfAfterUse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::showAt (Component* const component,
 | 
			
		||||
                                     const AttributedString& text,
 | 
			
		||||
                                     const int numMillisecondsBeforeRemoving,
 | 
			
		||||
                                     const bool removeWhenMouseClicked,
 | 
			
		||||
                                     const bool deleteSelfAfterUse)
 | 
			
		||||
{
 | 
			
		||||
    createLayout (text);
 | 
			
		||||
    setPosition (component);
 | 
			
		||||
    init (numMillisecondsBeforeRemoving, removeWhenMouseClicked, deleteSelfAfterUse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::createLayout (const AttributedString& text)
 | 
			
		||||
{
 | 
			
		||||
    textLayout.createLayoutWithBalancedLineLengths (text, 256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::init (const int numMillisecondsBeforeRemoving,
 | 
			
		||||
                                   const bool removeWhenMouseClicked,
 | 
			
		||||
                                   const bool deleteSelfAfterUse)
 | 
			
		||||
{
 | 
			
		||||
    setAlpha (1.0f);
 | 
			
		||||
    setVisible (true);
 | 
			
		||||
    deleteAfterUse = deleteSelfAfterUse;
 | 
			
		||||
 | 
			
		||||
    expiryTime = numMillisecondsBeforeRemoving > 0
 | 
			
		||||
                    ? (Time::getMillisecondCounter() + (uint32) numMillisecondsBeforeRemoving) : 0;
 | 
			
		||||
 | 
			
		||||
    mouseClickCounter = Desktop::getInstance().getMouseButtonClickCounter();
 | 
			
		||||
 | 
			
		||||
    if (! (removeWhenMouseClicked && isShowing()))
 | 
			
		||||
        mouseClickCounter += 0xfffff;
 | 
			
		||||
 | 
			
		||||
    startTimer (77);
 | 
			
		||||
    repaint();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const float bubblePaddingX = 20.0f;
 | 
			
		||||
const float bubblePaddingY = 14.0f;
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::getContentSize (int& w, int& h)
 | 
			
		||||
{
 | 
			
		||||
    w = (int) (bubblePaddingX + textLayout.getWidth());
 | 
			
		||||
    h = (int) (bubblePaddingY + textLayout.getHeight());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::paintContent (Graphics& g, int w, int h)
 | 
			
		||||
{
 | 
			
		||||
    g.setColour (findColour (TooltipWindow::textColourId));
 | 
			
		||||
 | 
			
		||||
    textLayout.draw (g, Rectangle<float> (bubblePaddingX / 2.0f, bubblePaddingY / 2.0f,
 | 
			
		||||
                                          (float) w - bubblePaddingX, (float) h - bubblePaddingY));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    if (Desktop::getInstance().getMouseButtonClickCounter() > mouseClickCounter)
 | 
			
		||||
        hide (false);
 | 
			
		||||
    else if (expiryTime != 0 && Time::getMillisecondCounter() > expiryTime)
 | 
			
		||||
        hide (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::hide (const bool fadeOut)
 | 
			
		||||
{
 | 
			
		||||
    stopTimer();
 | 
			
		||||
 | 
			
		||||
    if (fadeOut)
 | 
			
		||||
        Desktop::getInstance().getAnimator().fadeOut (this, fadeOutLength);
 | 
			
		||||
    else
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
 | 
			
		||||
    if (deleteAfterUse)
 | 
			
		||||
        delete this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
BubbleMessageComponent::BubbleMessageComponent (int fadeOutLengthMs)
 | 
			
		||||
    : fadeOutLength (fadeOutLengthMs), mouseClickCounter (0),
 | 
			
		||||
      expiryTime (0), deleteAfterUse (false)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
BubbleMessageComponent::~BubbleMessageComponent()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::showAt (const Rectangle<int>& pos,
 | 
			
		||||
                                     const AttributedString& text,
 | 
			
		||||
                                     const int numMillisecondsBeforeRemoving,
 | 
			
		||||
                                     const bool removeWhenMouseClicked,
 | 
			
		||||
                                     const bool deleteSelfAfterUse)
 | 
			
		||||
{
 | 
			
		||||
    createLayout (text);
 | 
			
		||||
    setPosition (pos);
 | 
			
		||||
    init (numMillisecondsBeforeRemoving, removeWhenMouseClicked, deleteSelfAfterUse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::showAt (Component* const component,
 | 
			
		||||
                                     const AttributedString& text,
 | 
			
		||||
                                     const int numMillisecondsBeforeRemoving,
 | 
			
		||||
                                     const bool removeWhenMouseClicked,
 | 
			
		||||
                                     const bool deleteSelfAfterUse)
 | 
			
		||||
{
 | 
			
		||||
    createLayout (text);
 | 
			
		||||
    setPosition (component);
 | 
			
		||||
    init (numMillisecondsBeforeRemoving, removeWhenMouseClicked, deleteSelfAfterUse);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::createLayout (const AttributedString& text)
 | 
			
		||||
{
 | 
			
		||||
    textLayout.createLayoutWithBalancedLineLengths (text, 256);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::init (const int numMillisecondsBeforeRemoving,
 | 
			
		||||
                                   const bool removeWhenMouseClicked,
 | 
			
		||||
                                   const bool deleteSelfAfterUse)
 | 
			
		||||
{
 | 
			
		||||
    setAlpha (1.0f);
 | 
			
		||||
    setVisible (true);
 | 
			
		||||
    deleteAfterUse = deleteSelfAfterUse;
 | 
			
		||||
 | 
			
		||||
    expiryTime = numMillisecondsBeforeRemoving > 0
 | 
			
		||||
                    ? (Time::getMillisecondCounter() + (uint32) numMillisecondsBeforeRemoving) : 0;
 | 
			
		||||
 | 
			
		||||
    mouseClickCounter = Desktop::getInstance().getMouseButtonClickCounter();
 | 
			
		||||
 | 
			
		||||
    if (! (removeWhenMouseClicked && isShowing()))
 | 
			
		||||
        mouseClickCounter += 0xfffff;
 | 
			
		||||
 | 
			
		||||
    startTimer (77);
 | 
			
		||||
    repaint();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const float bubblePaddingX = 20.0f;
 | 
			
		||||
const float bubblePaddingY = 14.0f;
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::getContentSize (int& w, int& h)
 | 
			
		||||
{
 | 
			
		||||
    w = (int) (bubblePaddingX + textLayout.getWidth());
 | 
			
		||||
    h = (int) (bubblePaddingY + textLayout.getHeight());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::paintContent (Graphics& g, int w, int h)
 | 
			
		||||
{
 | 
			
		||||
    g.setColour (findColour (TooltipWindow::textColourId));
 | 
			
		||||
 | 
			
		||||
    textLayout.draw (g, Rectangle<float> (bubblePaddingX / 2.0f, bubblePaddingY / 2.0f,
 | 
			
		||||
                                          (float) w - bubblePaddingX, (float) h - bubblePaddingY));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    if (Desktop::getInstance().getMouseButtonClickCounter() > mouseClickCounter)
 | 
			
		||||
        hide (false);
 | 
			
		||||
    else if (expiryTime != 0 && Time::getMillisecondCounter() > expiryTime)
 | 
			
		||||
        hide (true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void BubbleMessageComponent::hide (const bool fadeOut)
 | 
			
		||||
{
 | 
			
		||||
    stopTimer();
 | 
			
		||||
 | 
			
		||||
    if (fadeOut)
 | 
			
		||||
        Desktop::getInstance().getAnimator().fadeOut (this, fadeOutLength);
 | 
			
		||||
    else
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
 | 
			
		||||
    if (deleteAfterUse)
 | 
			
		||||
        delete this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,125 +1,125 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A speech-bubble component that displays a short message.
 | 
			
		||||
 | 
			
		||||
    This can be used to show a message with the tail of the speech bubble
 | 
			
		||||
    pointing to a particular component or location on the screen.
 | 
			
		||||
 | 
			
		||||
    @see BubbleComponent
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  BubbleMessageComponent  : public BubbleComponent,
 | 
			
		||||
                                          private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a bubble component.
 | 
			
		||||
 | 
			
		||||
        After creating one a BubbleComponent, do the following:
 | 
			
		||||
        - add it to an appropriate parent component, or put it on the
 | 
			
		||||
          desktop with Component::addToDesktop (0).
 | 
			
		||||
        - use the showAt() method to show a message.
 | 
			
		||||
        - it will make itself invisible after it times-out (and can optionally
 | 
			
		||||
          also delete itself), or you can reuse it somewhere else by calling
 | 
			
		||||
          showAt() again.
 | 
			
		||||
    */
 | 
			
		||||
    BubbleMessageComponent (int fadeOutLengthMs = 150);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~BubbleMessageComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Shows a message bubble at a particular position.
 | 
			
		||||
 | 
			
		||||
        This shows the bubble with its stem pointing to the given location
 | 
			
		||||
        (coordinates being relative to its parent component).
 | 
			
		||||
 | 
			
		||||
        @param position                         the coords of the object to point to
 | 
			
		||||
        @param message                          the text to display
 | 
			
		||||
        @param numMillisecondsBeforeRemoving    how long to leave it on the screen before removing itself
 | 
			
		||||
                                                from its parent component. If this is 0 or less, it
 | 
			
		||||
                                                will stay there until manually removed.
 | 
			
		||||
        @param removeWhenMouseClicked           if this is true, the bubble will disappear as soon as a
 | 
			
		||||
                                                mouse button is pressed (anywhere on the screen)
 | 
			
		||||
        @param deleteSelfAfterUse               if true, then the component will delete itself after
 | 
			
		||||
                                                it becomes invisible
 | 
			
		||||
    */
 | 
			
		||||
    void showAt (const Rectangle<int>& position,
 | 
			
		||||
                 const AttributedString& message,
 | 
			
		||||
                 int numMillisecondsBeforeRemoving,
 | 
			
		||||
                 bool removeWhenMouseClicked = true,
 | 
			
		||||
                 bool deleteSelfAfterUse = false);
 | 
			
		||||
 | 
			
		||||
    /** Shows a message bubble next to a particular component.
 | 
			
		||||
 | 
			
		||||
        This shows the bubble with its stem pointing at the given component.
 | 
			
		||||
 | 
			
		||||
        @param component                        the component that you want to point at
 | 
			
		||||
        @param message                          the text to display
 | 
			
		||||
        @param numMillisecondsBeforeRemoving    how long to leave it on the screen before removing itself
 | 
			
		||||
                                                from its parent component. If this is 0 or less, it
 | 
			
		||||
                                                will stay there until manually removed.
 | 
			
		||||
        @param removeWhenMouseClicked           if this is true, the bubble will disappear as soon as a
 | 
			
		||||
                                                mouse button is pressed (anywhere on the screen)
 | 
			
		||||
        @param deleteSelfAfterUse               if true, then the component will delete itself after
 | 
			
		||||
                                                it becomes invisible
 | 
			
		||||
    */
 | 
			
		||||
    void showAt (Component* component,
 | 
			
		||||
                 const AttributedString& message,
 | 
			
		||||
                 int numMillisecondsBeforeRemoving,
 | 
			
		||||
                 bool removeWhenMouseClicked = true,
 | 
			
		||||
                 bool deleteSelfAfterUse = false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void getContentSize (int& w, int& h) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paintContent (Graphics& g, int w, int h) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int fadeOutLength, mouseClickCounter;
 | 
			
		||||
    TextLayout textLayout;
 | 
			
		||||
    int64 expiryTime;
 | 
			
		||||
    bool deleteAfterUse;
 | 
			
		||||
 | 
			
		||||
    void createLayout (const AttributedString&);
 | 
			
		||||
    void init (int, bool, bool);
 | 
			
		||||
    void hide (bool fadeOut);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleMessageComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A speech-bubble component that displays a short message.
 | 
			
		||||
 | 
			
		||||
    This can be used to show a message with the tail of the speech bubble
 | 
			
		||||
    pointing to a particular component or location on the screen.
 | 
			
		||||
 | 
			
		||||
    @see BubbleComponent
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  BubbleMessageComponent  : public BubbleComponent,
 | 
			
		||||
                                          private Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a bubble component.
 | 
			
		||||
 | 
			
		||||
        After creating one a BubbleComponent, do the following:
 | 
			
		||||
        - add it to an appropriate parent component, or put it on the
 | 
			
		||||
          desktop with Component::addToDesktop (0).
 | 
			
		||||
        - use the showAt() method to show a message.
 | 
			
		||||
        - it will make itself invisible after it times-out (and can optionally
 | 
			
		||||
          also delete itself), or you can reuse it somewhere else by calling
 | 
			
		||||
          showAt() again.
 | 
			
		||||
    */
 | 
			
		||||
    BubbleMessageComponent (int fadeOutLengthMs = 150);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~BubbleMessageComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Shows a message bubble at a particular position.
 | 
			
		||||
 | 
			
		||||
        This shows the bubble with its stem pointing to the given location
 | 
			
		||||
        (coordinates being relative to its parent component).
 | 
			
		||||
 | 
			
		||||
        @param position                         the coords of the object to point to
 | 
			
		||||
        @param message                          the text to display
 | 
			
		||||
        @param numMillisecondsBeforeRemoving    how long to leave it on the screen before removing itself
 | 
			
		||||
                                                from its parent component. If this is 0 or less, it
 | 
			
		||||
                                                will stay there until manually removed.
 | 
			
		||||
        @param removeWhenMouseClicked           if this is true, the bubble will disappear as soon as a
 | 
			
		||||
                                                mouse button is pressed (anywhere on the screen)
 | 
			
		||||
        @param deleteSelfAfterUse               if true, then the component will delete itself after
 | 
			
		||||
                                                it becomes invisible
 | 
			
		||||
    */
 | 
			
		||||
    void showAt (const Rectangle<int>& position,
 | 
			
		||||
                 const AttributedString& message,
 | 
			
		||||
                 int numMillisecondsBeforeRemoving,
 | 
			
		||||
                 bool removeWhenMouseClicked = true,
 | 
			
		||||
                 bool deleteSelfAfterUse = false);
 | 
			
		||||
 | 
			
		||||
    /** Shows a message bubble next to a particular component.
 | 
			
		||||
 | 
			
		||||
        This shows the bubble with its stem pointing at the given component.
 | 
			
		||||
 | 
			
		||||
        @param component                        the component that you want to point at
 | 
			
		||||
        @param message                          the text to display
 | 
			
		||||
        @param numMillisecondsBeforeRemoving    how long to leave it on the screen before removing itself
 | 
			
		||||
                                                from its parent component. If this is 0 or less, it
 | 
			
		||||
                                                will stay there until manually removed.
 | 
			
		||||
        @param removeWhenMouseClicked           if this is true, the bubble will disappear as soon as a
 | 
			
		||||
                                                mouse button is pressed (anywhere on the screen)
 | 
			
		||||
        @param deleteSelfAfterUse               if true, then the component will delete itself after
 | 
			
		||||
                                                it becomes invisible
 | 
			
		||||
    */
 | 
			
		||||
    void showAt (Component* component,
 | 
			
		||||
                 const AttributedString& message,
 | 
			
		||||
                 int numMillisecondsBeforeRemoving,
 | 
			
		||||
                 bool removeWhenMouseClicked = true,
 | 
			
		||||
                 bool deleteSelfAfterUse = false);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void getContentSize (int& w, int& h) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paintContent (Graphics& g, int w, int h) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    int fadeOutLength, mouseClickCounter;
 | 
			
		||||
    TextLayout textLayout;
 | 
			
		||||
    int64 expiryTime;
 | 
			
		||||
    bool deleteAfterUse;
 | 
			
		||||
 | 
			
		||||
    void createLayout (const AttributedString&);
 | 
			
		||||
    void init (int, bool, bool);
 | 
			
		||||
    void hide (bool fadeOut);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (BubbleMessageComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,167 +1,167 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A component that lets the user choose a colour.
 | 
			
		||||
 | 
			
		||||
    This shows RGB sliders and a colourspace that the user can pick colours from.
 | 
			
		||||
 | 
			
		||||
    This class is also a ChangeBroadcaster, so listeners can register to be told
 | 
			
		||||
    when the colour changes.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ColourSelector  : public Component,
 | 
			
		||||
                                  public ChangeBroadcaster
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Options for the type of selector to show. These are passed into the constructor. */
 | 
			
		||||
    enum ColourSelectorOptions
 | 
			
		||||
    {
 | 
			
		||||
        showAlphaChannel    = 1 << 0,   /**< if set, the colour's alpha channel can be changed as well as its RGB. */
 | 
			
		||||
 | 
			
		||||
        showColourAtTop     = 1 << 1,   /**< if set, a swatch of the colour is shown at the top of the component. */
 | 
			
		||||
        editableColour      = 1 << 2,   /**< if set, the colour shows at the top of the component is editable. */
 | 
			
		||||
        showSliders         = 1 << 3,   /**< if set, RGB sliders are shown at the bottom of the component. */
 | 
			
		||||
        showColourspace     = 1 << 4    /**< if set, a big HSV selector is shown. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a ColourSelector object.
 | 
			
		||||
 | 
			
		||||
        The flags are a combination of values from the ColourSelectorOptions enum, specifying
 | 
			
		||||
        which of the selector's features should be visible.
 | 
			
		||||
 | 
			
		||||
        The edgeGap value specifies the amount of space to leave around the edge.
 | 
			
		||||
 | 
			
		||||
        gapAroundColourSpaceComponent indicates how much of a gap to put around the
 | 
			
		||||
        colourspace and hue selector components.
 | 
			
		||||
    */
 | 
			
		||||
    ColourSelector (int flags = (showAlphaChannel | showColourAtTop | showSliders | showColourspace),
 | 
			
		||||
                    int edgeGap = 4,
 | 
			
		||||
                    int gapAroundColourSpaceComponent = 7);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ColourSelector() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the colour that the user has currently selected.
 | 
			
		||||
 | 
			
		||||
        The ColourSelector class is also a ChangeBroadcaster, so listeners can
 | 
			
		||||
        register to be told when the colour changes.
 | 
			
		||||
 | 
			
		||||
        @see setCurrentColour
 | 
			
		||||
    */
 | 
			
		||||
    Colour getCurrentColour() const;
 | 
			
		||||
 | 
			
		||||
    /** Changes the colour that is currently being shown.
 | 
			
		||||
 | 
			
		||||
        @param newColour           the new colour to show
 | 
			
		||||
        @param notificationType    whether to send a notification of the change to listeners.
 | 
			
		||||
                                   A notification will only be sent if the colour has changed.
 | 
			
		||||
    */
 | 
			
		||||
    void setCurrentColour (Colour newColour, NotificationType notificationType = sendNotification);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Tells the selector how many preset colour swatches you want to have on the component.
 | 
			
		||||
 | 
			
		||||
        To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
 | 
			
		||||
        setSwatchColour(), to return the number of colours you want, and to set and retrieve
 | 
			
		||||
        their values.
 | 
			
		||||
    */
 | 
			
		||||
    virtual int getNumSwatches() const;
 | 
			
		||||
 | 
			
		||||
    /** Called by the selector to find out the colour of one of the swatches.
 | 
			
		||||
 | 
			
		||||
        Your subclass should return the colour of the swatch with the given index.
 | 
			
		||||
 | 
			
		||||
        To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
 | 
			
		||||
        setSwatchColour(), to return the number of colours you want, and to set and retrieve
 | 
			
		||||
        their values.
 | 
			
		||||
    */
 | 
			
		||||
    virtual Colour getSwatchColour (int index) const;
 | 
			
		||||
 | 
			
		||||
    /** Called by the selector when the user puts a new colour into one of the swatches.
 | 
			
		||||
 | 
			
		||||
        Your subclass should change the colour of the swatch with the given index.
 | 
			
		||||
 | 
			
		||||
        To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
 | 
			
		||||
        setSwatchColour(), to return the number of colours you want, and to set and retrieve
 | 
			
		||||
        their values.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void setSwatchColour (int index, const Colour& newColour);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the keyboard.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId              = 0x1007000,    /**< the colour used to fill the component's background. */
 | 
			
		||||
        labelTextColourId               = 0x1007001     /**< the colour used for the labels next to the sliders. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    // These need to be public otherwise the Projucer's live-build engine will complain
 | 
			
		||||
    class ColourSpaceView;
 | 
			
		||||
    class HueSelectorComp;
 | 
			
		||||
    class ColourPreviewComp;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class SwatchComponent;
 | 
			
		||||
 | 
			
		||||
    Colour colour;
 | 
			
		||||
    float h, s, v;
 | 
			
		||||
    std::unique_ptr<Slider> sliders[4];
 | 
			
		||||
    std::unique_ptr<ColourSpaceView> colourSpace;
 | 
			
		||||
    std::unique_ptr<HueSelectorComp> hueSelector;
 | 
			
		||||
    std::unique_ptr<ColourPreviewComp> previewComponent;
 | 
			
		||||
    OwnedArray<SwatchComponent> swatchComponents;
 | 
			
		||||
    const int flags;
 | 
			
		||||
    int edgeGap;
 | 
			
		||||
 | 
			
		||||
    void setHue (float newH);
 | 
			
		||||
    void setSV (float newS, float newV);
 | 
			
		||||
    void updateHSV();
 | 
			
		||||
    void update (NotificationType);
 | 
			
		||||
    void changeColour();
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    void resized() override;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourSelector)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A component that lets the user choose a colour.
 | 
			
		||||
 | 
			
		||||
    This shows RGB sliders and a colourspace that the user can pick colours from.
 | 
			
		||||
 | 
			
		||||
    This class is also a ChangeBroadcaster, so listeners can register to be told
 | 
			
		||||
    when the colour changes.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  ColourSelector  : public Component,
 | 
			
		||||
                                  public ChangeBroadcaster
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Options for the type of selector to show. These are passed into the constructor. */
 | 
			
		||||
    enum ColourSelectorOptions
 | 
			
		||||
    {
 | 
			
		||||
        showAlphaChannel    = 1 << 0,   /**< if set, the colour's alpha channel can be changed as well as its RGB. */
 | 
			
		||||
 | 
			
		||||
        showColourAtTop     = 1 << 1,   /**< if set, a swatch of the colour is shown at the top of the component. */
 | 
			
		||||
        editableColour      = 1 << 2,   /**< if set, the colour shows at the top of the component is editable. */
 | 
			
		||||
        showSliders         = 1 << 3,   /**< if set, RGB sliders are shown at the bottom of the component. */
 | 
			
		||||
        showColourspace     = 1 << 4    /**< if set, a big HSV selector is shown. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a ColourSelector object.
 | 
			
		||||
 | 
			
		||||
        The flags are a combination of values from the ColourSelectorOptions enum, specifying
 | 
			
		||||
        which of the selector's features should be visible.
 | 
			
		||||
 | 
			
		||||
        The edgeGap value specifies the amount of space to leave around the edge.
 | 
			
		||||
 | 
			
		||||
        gapAroundColourSpaceComponent indicates how much of a gap to put around the
 | 
			
		||||
        colourspace and hue selector components.
 | 
			
		||||
    */
 | 
			
		||||
    ColourSelector (int flags = (showAlphaChannel | showColourAtTop | showSliders | showColourspace),
 | 
			
		||||
                    int edgeGap = 4,
 | 
			
		||||
                    int gapAroundColourSpaceComponent = 7);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~ColourSelector() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns the colour that the user has currently selected.
 | 
			
		||||
 | 
			
		||||
        The ColourSelector class is also a ChangeBroadcaster, so listeners can
 | 
			
		||||
        register to be told when the colour changes.
 | 
			
		||||
 | 
			
		||||
        @see setCurrentColour
 | 
			
		||||
    */
 | 
			
		||||
    Colour getCurrentColour() const;
 | 
			
		||||
 | 
			
		||||
    /** Changes the colour that is currently being shown.
 | 
			
		||||
 | 
			
		||||
        @param newColour           the new colour to show
 | 
			
		||||
        @param notificationType    whether to send a notification of the change to listeners.
 | 
			
		||||
                                   A notification will only be sent if the colour has changed.
 | 
			
		||||
    */
 | 
			
		||||
    void setCurrentColour (Colour newColour, NotificationType notificationType = sendNotification);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Tells the selector how many preset colour swatches you want to have on the component.
 | 
			
		||||
 | 
			
		||||
        To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
 | 
			
		||||
        setSwatchColour(), to return the number of colours you want, and to set and retrieve
 | 
			
		||||
        their values.
 | 
			
		||||
    */
 | 
			
		||||
    virtual int getNumSwatches() const;
 | 
			
		||||
 | 
			
		||||
    /** Called by the selector to find out the colour of one of the swatches.
 | 
			
		||||
 | 
			
		||||
        Your subclass should return the colour of the swatch with the given index.
 | 
			
		||||
 | 
			
		||||
        To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
 | 
			
		||||
        setSwatchColour(), to return the number of colours you want, and to set and retrieve
 | 
			
		||||
        their values.
 | 
			
		||||
    */
 | 
			
		||||
    virtual Colour getSwatchColour (int index) const;
 | 
			
		||||
 | 
			
		||||
    /** Called by the selector when the user puts a new colour into one of the swatches.
 | 
			
		||||
 | 
			
		||||
        Your subclass should change the colour of the swatch with the given index.
 | 
			
		||||
 | 
			
		||||
        To enable swatches, you'll need to override getNumSwatches(), getSwatchColour(), and
 | 
			
		||||
        setSwatchColour(), to return the number of colours you want, and to set and retrieve
 | 
			
		||||
        their values.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void setSwatchColour (int index, const Colour& newColour);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the keyboard.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId              = 0x1007000,    /**< the colour used to fill the component's background. */
 | 
			
		||||
        labelTextColourId               = 0x1007001     /**< the colour used for the labels next to the sliders. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    // These need to be public otherwise the Projucer's live-build engine will complain
 | 
			
		||||
    class ColourSpaceView;
 | 
			
		||||
    class HueSelectorComp;
 | 
			
		||||
    class ColourPreviewComp;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class SwatchComponent;
 | 
			
		||||
 | 
			
		||||
    Colour colour;
 | 
			
		||||
    float h, s, v;
 | 
			
		||||
    std::unique_ptr<Slider> sliders[4];
 | 
			
		||||
    std::unique_ptr<ColourSpaceView> colourSpace;
 | 
			
		||||
    std::unique_ptr<HueSelectorComp> hueSelector;
 | 
			
		||||
    std::unique_ptr<ColourPreviewComp> previewComponent;
 | 
			
		||||
    OwnedArray<SwatchComponent> swatchComponents;
 | 
			
		||||
    const int flags;
 | 
			
		||||
    int edgeGap;
 | 
			
		||||
 | 
			
		||||
    void setHue (float newH);
 | 
			
		||||
    void setSV (float newS, float newV);
 | 
			
		||||
    void updateHSV();
 | 
			
		||||
    void update (NotificationType);
 | 
			
		||||
    void changeColour();
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    void resized() override;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ColourSelector)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,480 +1,480 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class KeyMappingEditorComponent::ChangeKeyButton  : public Button
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ChangeKeyButton (KeyMappingEditorComponent& kec, CommandID command,
 | 
			
		||||
                     const String& keyName, int keyIndex)
 | 
			
		||||
        : Button (keyName),
 | 
			
		||||
          owner (kec),
 | 
			
		||||
          commandID (command),
 | 
			
		||||
          keyNum (keyIndex)
 | 
			
		||||
    {
 | 
			
		||||
        setWantsKeyboardFocus (false);
 | 
			
		||||
        setTriggeredOnMouseDown (keyNum >= 0);
 | 
			
		||||
 | 
			
		||||
        setTooltip (keyIndex < 0 ? TRANS("Adds a new key-mapping")
 | 
			
		||||
                                 : TRANS("Click to change this key-mapping"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void paintButton (Graphics& g, bool /*isOver*/, bool /*isDown*/) override
 | 
			
		||||
    {
 | 
			
		||||
        getLookAndFeel().drawKeymapChangeButton (g, getWidth(), getHeight(), *this,
 | 
			
		||||
                                                 keyNum >= 0 ? getName() : String());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void clicked() override
 | 
			
		||||
    {
 | 
			
		||||
        if (keyNum >= 0)
 | 
			
		||||
        {
 | 
			
		||||
            Component::SafePointer<ChangeKeyButton> button (this);
 | 
			
		||||
            PopupMenu m;
 | 
			
		||||
 | 
			
		||||
            m.addItem (TRANS("Change this key-mapping"),
 | 
			
		||||
                       [button]
 | 
			
		||||
                       {
 | 
			
		||||
                           if (button != nullptr)
 | 
			
		||||
                               button.getComponent()->assignNewKey();
 | 
			
		||||
                       });
 | 
			
		||||
 | 
			
		||||
            m.addSeparator();
 | 
			
		||||
 | 
			
		||||
            m.addItem (TRANS("Remove this key-mapping"),
 | 
			
		||||
                       [button]
 | 
			
		||||
                       {
 | 
			
		||||
                           if (button != nullptr)
 | 
			
		||||
                               button->owner.getMappings().removeKeyPress (button->commandID,
 | 
			
		||||
                                                                           button->keyNum);
 | 
			
		||||
                       });
 | 
			
		||||
 | 
			
		||||
            m.showMenuAsync (PopupMenu::Options().withTargetComponent (this));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            assignNewKey();  // + button pressed..
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using Button::clicked;
 | 
			
		||||
 | 
			
		||||
    void fitToContent (const int h) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (keyNum < 0)
 | 
			
		||||
            setSize (h, h);
 | 
			
		||||
        else
 | 
			
		||||
            setSize (jlimit (h * 4, h * 8, 6 + Font ((float) h * 0.6f).getStringWidth (getName())), h);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class KeyEntryWindow  : public AlertWindow
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        KeyEntryWindow (KeyMappingEditorComponent& kec)
 | 
			
		||||
            : AlertWindow (TRANS("New key-mapping"),
 | 
			
		||||
                           TRANS("Please press a key combination now..."),
 | 
			
		||||
                           MessageBoxIconType::NoIcon),
 | 
			
		||||
              owner (kec)
 | 
			
		||||
        {
 | 
			
		||||
            addButton (TRANS("OK"), 1);
 | 
			
		||||
            addButton (TRANS("Cancel"), 0);
 | 
			
		||||
 | 
			
		||||
            // (avoid return + escape keys getting processed by the buttons..)
 | 
			
		||||
            for (auto* child : getChildren())
 | 
			
		||||
                child->setWantsKeyboardFocus (false);
 | 
			
		||||
 | 
			
		||||
            setWantsKeyboardFocus (true);
 | 
			
		||||
            grabKeyboardFocus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool keyPressed (const KeyPress& key) override
 | 
			
		||||
        {
 | 
			
		||||
            lastPress = key;
 | 
			
		||||
            String message (TRANS("Key") + ": " + owner.getDescriptionForKeyPress (key));
 | 
			
		||||
 | 
			
		||||
            auto previousCommand = owner.getMappings().findCommandForKeyPress (key);
 | 
			
		||||
 | 
			
		||||
            if (previousCommand != 0)
 | 
			
		||||
                message << "\n\n("
 | 
			
		||||
                        << TRANS("Currently assigned to \"CMDN\"")
 | 
			
		||||
                            .replace ("CMDN", TRANS (owner.getCommandManager().getNameOfCommand (previousCommand)))
 | 
			
		||||
                        << ')';
 | 
			
		||||
 | 
			
		||||
            setMessage (message);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool keyStateChanged (bool) override
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        KeyPress lastPress;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        KeyMappingEditorComponent& owner;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (KeyEntryWindow)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static void assignNewKeyCallback (int result, ChangeKeyButton* button, KeyPress newKey)
 | 
			
		||||
    {
 | 
			
		||||
        if (result != 0 && button != nullptr)
 | 
			
		||||
            button->setNewKey (newKey, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setNewKey (const KeyPress& newKey, bool dontAskUser)
 | 
			
		||||
    {
 | 
			
		||||
        if (newKey.isValid())
 | 
			
		||||
        {
 | 
			
		||||
            auto previousCommand = owner.getMappings().findCommandForKeyPress (newKey);
 | 
			
		||||
 | 
			
		||||
            if (previousCommand == 0 || dontAskUser)
 | 
			
		||||
            {
 | 
			
		||||
                owner.getMappings().removeKeyPress (newKey);
 | 
			
		||||
 | 
			
		||||
                if (keyNum >= 0)
 | 
			
		||||
                    owner.getMappings().removeKeyPress (commandID, keyNum);
 | 
			
		||||
 | 
			
		||||
                owner.getMappings().addKeyPress (commandID, newKey, keyNum);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
 | 
			
		||||
                                              TRANS("Change key-mapping"),
 | 
			
		||||
                                              TRANS("This key is already assigned to the command \"CMDN\"")
 | 
			
		||||
                                                  .replace ("CMDN", owner.getCommandManager().getNameOfCommand (previousCommand))
 | 
			
		||||
                                                + "\n\n"
 | 
			
		||||
                                                + TRANS("Do you want to re-assign it to this new command instead?"),
 | 
			
		||||
                                              TRANS("Re-assign"),
 | 
			
		||||
                                              TRANS("Cancel"),
 | 
			
		||||
                                              this,
 | 
			
		||||
                                              ModalCallbackFunction::forComponent (assignNewKeyCallback,
 | 
			
		||||
                                                                                   this, KeyPress (newKey)));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void keyChosen (int result, ChangeKeyButton* button)
 | 
			
		||||
    {
 | 
			
		||||
        if (button != nullptr && button->currentKeyEntryWindow != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            if (result != 0)
 | 
			
		||||
            {
 | 
			
		||||
                button->currentKeyEntryWindow->setVisible (false);
 | 
			
		||||
                button->setNewKey (button->currentKeyEntryWindow->lastPress, false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            button->currentKeyEntryWindow.reset();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void assignNewKey()
 | 
			
		||||
    {
 | 
			
		||||
        currentKeyEntryWindow.reset (new KeyEntryWindow (owner));
 | 
			
		||||
        currentKeyEntryWindow->enterModalState (true, ModalCallbackFunction::forComponent (keyChosen, this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
    const CommandID commandID;
 | 
			
		||||
    const int keyNum;
 | 
			
		||||
    std::unique_ptr<KeyEntryWindow> currentKeyEntryWindow;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChangeKeyButton)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class KeyMappingEditorComponent::ItemComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ItemComponent (KeyMappingEditorComponent& kec, CommandID command)
 | 
			
		||||
        : owner (kec), commandID (command)
 | 
			
		||||
    {
 | 
			
		||||
        setInterceptsMouseClicks (false, true);
 | 
			
		||||
 | 
			
		||||
        const bool isReadOnly = owner.isCommandReadOnly (commandID);
 | 
			
		||||
 | 
			
		||||
        auto keyPresses = owner.getMappings().getKeyPressesAssignedToCommand (commandID);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < jmin ((int) maxNumAssignments, keyPresses.size()); ++i)
 | 
			
		||||
            addKeyPressButton (owner.getDescriptionForKeyPress (keyPresses.getReference (i)), i, isReadOnly);
 | 
			
		||||
 | 
			
		||||
        addKeyPressButton ("Change Key Mapping", -1, isReadOnly);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addKeyPressButton (const String& desc, const int index, const bool isReadOnly)
 | 
			
		||||
    {
 | 
			
		||||
        auto* b = new ChangeKeyButton (owner, commandID, desc, index);
 | 
			
		||||
        keyChangeButtons.add (b);
 | 
			
		||||
 | 
			
		||||
        b->setEnabled (! isReadOnly);
 | 
			
		||||
        b->setVisible (keyChangeButtons.size() <= (int) maxNumAssignments);
 | 
			
		||||
        addChildComponent (b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void paint (Graphics& g) override
 | 
			
		||||
    {
 | 
			
		||||
        g.setFont ((float) getHeight() * 0.7f);
 | 
			
		||||
        g.setColour (owner.findColour (KeyMappingEditorComponent::textColourId));
 | 
			
		||||
 | 
			
		||||
        g.drawFittedText (TRANS (owner.getCommandManager().getNameOfCommand (commandID)),
 | 
			
		||||
                          4, 0, jmax (40, getChildComponent (0)->getX() - 5), getHeight(),
 | 
			
		||||
                          Justification::centredLeft, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resized() override
 | 
			
		||||
    {
 | 
			
		||||
        int x = getWidth() - 4;
 | 
			
		||||
 | 
			
		||||
        for (int i = keyChangeButtons.size(); --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            auto* b = keyChangeButtons.getUnchecked(i);
 | 
			
		||||
 | 
			
		||||
            b->fitToContent (getHeight() - 2);
 | 
			
		||||
            b->setTopRightPosition (x, 1);
 | 
			
		||||
            x = b->getX() - 5;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
 | 
			
		||||
    {
 | 
			
		||||
        return createIgnoredAccessibilityHandler (*this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
    OwnedArray<ChangeKeyButton> keyChangeButtons;
 | 
			
		||||
    const CommandID commandID;
 | 
			
		||||
 | 
			
		||||
    enum { maxNumAssignments = 3 };
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ItemComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class KeyMappingEditorComponent::MappingItem  : public TreeViewItem
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    MappingItem (KeyMappingEditorComponent& kec, CommandID command)
 | 
			
		||||
        : owner (kec), commandID (command)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    String getUniqueName() const override                      { return String ((int) commandID) + "_id"; }
 | 
			
		||||
    bool mightContainSubItems() override                       { return false; }
 | 
			
		||||
    int getItemHeight() const override                         { return 20; }
 | 
			
		||||
    std::unique_ptr<Component> createItemComponent() override  { return std::make_unique<ItemComponent> (owner, commandID); }
 | 
			
		||||
    String getAccessibilityName() override                     { return TRANS (owner.getCommandManager().getNameOfCommand (commandID)); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
    const CommandID commandID;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MappingItem)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class KeyMappingEditorComponent::CategoryItem  : public TreeViewItem
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CategoryItem (KeyMappingEditorComponent& kec, const String& name)
 | 
			
		||||
        : owner (kec), categoryName (name)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    String getUniqueName() const override       { return categoryName + "_cat"; }
 | 
			
		||||
    bool mightContainSubItems() override        { return true; }
 | 
			
		||||
    int getItemHeight() const override          { return 22; }
 | 
			
		||||
    String getAccessibilityName() override      { return categoryName; }
 | 
			
		||||
 | 
			
		||||
    void paintItem (Graphics& g, int width, int height) override
 | 
			
		||||
    {
 | 
			
		||||
        g.setFont (Font ((float) height * 0.7f, Font::bold));
 | 
			
		||||
        g.setColour (owner.findColour (KeyMappingEditorComponent::textColourId));
 | 
			
		||||
 | 
			
		||||
        g.drawText (TRANS (categoryName), 2, 0, width - 2, height, Justification::centredLeft, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void itemOpennessChanged (bool isNowOpen) override
 | 
			
		||||
    {
 | 
			
		||||
        if (isNowOpen)
 | 
			
		||||
        {
 | 
			
		||||
            if (getNumSubItems() == 0)
 | 
			
		||||
                for (auto command : owner.getCommandManager().getCommandsInCategory (categoryName))
 | 
			
		||||
                    if (owner.shouldCommandBeIncluded (command))
 | 
			
		||||
                        addSubItem (new MappingItem (owner, command));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            clearSubItems();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
    String categoryName;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CategoryItem)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class KeyMappingEditorComponent::TopLevelItem   : public TreeViewItem,
 | 
			
		||||
                                                  private ChangeListener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    TopLevelItem (KeyMappingEditorComponent& kec)   : owner (kec)
 | 
			
		||||
    {
 | 
			
		||||
        setLinesDrawnForSubItems (false);
 | 
			
		||||
        owner.getMappings().addChangeListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~TopLevelItem() override
 | 
			
		||||
    {
 | 
			
		||||
        owner.getMappings().removeChangeListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool mightContainSubItems() override             { return true; }
 | 
			
		||||
    String getUniqueName() const override            { return "keys"; }
 | 
			
		||||
 | 
			
		||||
    void changeListenerCallback (ChangeBroadcaster*) override
 | 
			
		||||
    {
 | 
			
		||||
        const OpennessRestorer opennessRestorer (*this);
 | 
			
		||||
        clearSubItems();
 | 
			
		||||
 | 
			
		||||
        for (auto category : owner.getCommandManager().getCommandCategories())
 | 
			
		||||
        {
 | 
			
		||||
            int count = 0;
 | 
			
		||||
 | 
			
		||||
            for (auto command : owner.getCommandManager().getCommandsInCategory (category))
 | 
			
		||||
                if (owner.shouldCommandBeIncluded (command))
 | 
			
		||||
                    ++count;
 | 
			
		||||
 | 
			
		||||
            if (count > 0)
 | 
			
		||||
                addSubItem (new CategoryItem (owner, category));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void resetKeyMappingsToDefaultsCallback (int result, KeyMappingEditorComponent* owner)
 | 
			
		||||
{
 | 
			
		||||
    if (result != 0 && owner != nullptr)
 | 
			
		||||
        owner->getMappings().resetToDefaultMappings();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
KeyMappingEditorComponent::KeyMappingEditorComponent (KeyPressMappingSet& mappingManager,
 | 
			
		||||
                                                      const bool showResetToDefaultButton)
 | 
			
		||||
    : mappings (mappingManager),
 | 
			
		||||
      resetButton (TRANS ("reset to defaults"))
 | 
			
		||||
{
 | 
			
		||||
    treeItem.reset (new TopLevelItem (*this));
 | 
			
		||||
 | 
			
		||||
    if (showResetToDefaultButton)
 | 
			
		||||
    {
 | 
			
		||||
        addAndMakeVisible (resetButton);
 | 
			
		||||
 | 
			
		||||
        resetButton.onClick = [this]
 | 
			
		||||
        {
 | 
			
		||||
            AlertWindow::showOkCancelBox (MessageBoxIconType::QuestionIcon,
 | 
			
		||||
                                          TRANS("Reset to defaults"),
 | 
			
		||||
                                          TRANS("Are you sure you want to reset all the key-mappings to their default state?"),
 | 
			
		||||
                                          TRANS("Reset"),
 | 
			
		||||
                                          {}, this,
 | 
			
		||||
                                          ModalCallbackFunction::forComponent (resetKeyMappingsToDefaultsCallback, this));
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addAndMakeVisible (tree);
 | 
			
		||||
    tree.setTitle ("Key Mappings");
 | 
			
		||||
    tree.setColour (TreeView::backgroundColourId, findColour (backgroundColourId));
 | 
			
		||||
    tree.setRootItemVisible (false);
 | 
			
		||||
    tree.setDefaultOpenness (true);
 | 
			
		||||
    tree.setRootItem (treeItem.get());
 | 
			
		||||
    tree.setIndentSize (12);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KeyMappingEditorComponent::~KeyMappingEditorComponent()
 | 
			
		||||
{
 | 
			
		||||
    tree.setRootItem (nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void KeyMappingEditorComponent::setColours (Colour mainBackground,
 | 
			
		||||
                                            Colour textColour)
 | 
			
		||||
{
 | 
			
		||||
    setColour (backgroundColourId, mainBackground);
 | 
			
		||||
    setColour (textColourId, textColour);
 | 
			
		||||
    tree.setColour (TreeView::backgroundColourId, mainBackground);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KeyMappingEditorComponent::parentHierarchyChanged()
 | 
			
		||||
{
 | 
			
		||||
    treeItem->changeListenerCallback (nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KeyMappingEditorComponent::resized()
 | 
			
		||||
{
 | 
			
		||||
    int h = getHeight();
 | 
			
		||||
 | 
			
		||||
    if (resetButton.isVisible())
 | 
			
		||||
    {
 | 
			
		||||
        const int buttonHeight = 20;
 | 
			
		||||
        h -= buttonHeight + 8;
 | 
			
		||||
        int x = getWidth() - 8;
 | 
			
		||||
 | 
			
		||||
        resetButton.changeWidthToFitText (buttonHeight);
 | 
			
		||||
        resetButton.setTopRightPosition (x, h + 6);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree.setBounds (0, 0, getWidth(), h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool KeyMappingEditorComponent::shouldCommandBeIncluded (const CommandID commandID)
 | 
			
		||||
{
 | 
			
		||||
    auto* ci = mappings.getCommandManager().getCommandForID (commandID);
 | 
			
		||||
 | 
			
		||||
    return ci != nullptr && (ci->flags & ApplicationCommandInfo::hiddenFromKeyEditor) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool KeyMappingEditorComponent::isCommandReadOnly (const CommandID commandID)
 | 
			
		||||
{
 | 
			
		||||
    auto* ci = mappings.getCommandManager().getCommandForID (commandID);
 | 
			
		||||
 | 
			
		||||
    return ci != nullptr && (ci->flags & ApplicationCommandInfo::readOnlyInKeyEditor) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String KeyMappingEditorComponent::getDescriptionForKeyPress (const KeyPress& key)
 | 
			
		||||
{
 | 
			
		||||
    return key.getTextDescription();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class KeyMappingEditorComponent::ChangeKeyButton  : public Button
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ChangeKeyButton (KeyMappingEditorComponent& kec, CommandID command,
 | 
			
		||||
                     const String& keyName, int keyIndex)
 | 
			
		||||
        : Button (keyName),
 | 
			
		||||
          owner (kec),
 | 
			
		||||
          commandID (command),
 | 
			
		||||
          keyNum (keyIndex)
 | 
			
		||||
    {
 | 
			
		||||
        setWantsKeyboardFocus (false);
 | 
			
		||||
        setTriggeredOnMouseDown (keyNum >= 0);
 | 
			
		||||
 | 
			
		||||
        setTooltip (keyIndex < 0 ? TRANS("Adds a new key-mapping")
 | 
			
		||||
                                 : TRANS("Click to change this key-mapping"));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void paintButton (Graphics& g, bool /*isOver*/, bool /*isDown*/) override
 | 
			
		||||
    {
 | 
			
		||||
        getLookAndFeel().drawKeymapChangeButton (g, getWidth(), getHeight(), *this,
 | 
			
		||||
                                                 keyNum >= 0 ? getName() : String());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void clicked() override
 | 
			
		||||
    {
 | 
			
		||||
        if (keyNum >= 0)
 | 
			
		||||
        {
 | 
			
		||||
            Component::SafePointer<ChangeKeyButton> button (this);
 | 
			
		||||
            PopupMenu m;
 | 
			
		||||
 | 
			
		||||
            m.addItem (TRANS("Change this key-mapping"),
 | 
			
		||||
                       [button]
 | 
			
		||||
                       {
 | 
			
		||||
                           if (button != nullptr)
 | 
			
		||||
                               button.getComponent()->assignNewKey();
 | 
			
		||||
                       });
 | 
			
		||||
 | 
			
		||||
            m.addSeparator();
 | 
			
		||||
 | 
			
		||||
            m.addItem (TRANS("Remove this key-mapping"),
 | 
			
		||||
                       [button]
 | 
			
		||||
                       {
 | 
			
		||||
                           if (button != nullptr)
 | 
			
		||||
                               button->owner.getMappings().removeKeyPress (button->commandID,
 | 
			
		||||
                                                                           button->keyNum);
 | 
			
		||||
                       });
 | 
			
		||||
 | 
			
		||||
            m.showMenuAsync (PopupMenu::Options().withTargetComponent (this));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            assignNewKey();  // + button pressed..
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using Button::clicked;
 | 
			
		||||
 | 
			
		||||
    void fitToContent (const int h) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        if (keyNum < 0)
 | 
			
		||||
            setSize (h, h);
 | 
			
		||||
        else
 | 
			
		||||
            setSize (jlimit (h * 4, h * 8, 6 + Font ((float) h * 0.6f).getStringWidth (getName())), h);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class KeyEntryWindow  : public AlertWindow
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        KeyEntryWindow (KeyMappingEditorComponent& kec)
 | 
			
		||||
            : AlertWindow (TRANS("New key-mapping"),
 | 
			
		||||
                           TRANS("Please press a key combination now..."),
 | 
			
		||||
                           MessageBoxIconType::NoIcon),
 | 
			
		||||
              owner (kec)
 | 
			
		||||
        {
 | 
			
		||||
            addButton (TRANS("OK"), 1);
 | 
			
		||||
            addButton (TRANS("Cancel"), 0);
 | 
			
		||||
 | 
			
		||||
            // (avoid return + escape keys getting processed by the buttons..)
 | 
			
		||||
            for (auto* child : getChildren())
 | 
			
		||||
                child->setWantsKeyboardFocus (false);
 | 
			
		||||
 | 
			
		||||
            setWantsKeyboardFocus (true);
 | 
			
		||||
            grabKeyboardFocus();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool keyPressed (const KeyPress& key) override
 | 
			
		||||
        {
 | 
			
		||||
            lastPress = key;
 | 
			
		||||
            String message (TRANS("Key") + ": " + owner.getDescriptionForKeyPress (key));
 | 
			
		||||
 | 
			
		||||
            auto previousCommand = owner.getMappings().findCommandForKeyPress (key);
 | 
			
		||||
 | 
			
		||||
            if (previousCommand != 0)
 | 
			
		||||
                message << "\n\n("
 | 
			
		||||
                        << TRANS("Currently assigned to \"CMDN\"")
 | 
			
		||||
                            .replace ("CMDN", TRANS (owner.getCommandManager().getNameOfCommand (previousCommand)))
 | 
			
		||||
                        << ')';
 | 
			
		||||
 | 
			
		||||
            setMessage (message);
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        bool keyStateChanged (bool) override
 | 
			
		||||
        {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        KeyPress lastPress;
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        KeyMappingEditorComponent& owner;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (KeyEntryWindow)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    static void assignNewKeyCallback (int result, ChangeKeyButton* button, KeyPress newKey)
 | 
			
		||||
    {
 | 
			
		||||
        if (result != 0 && button != nullptr)
 | 
			
		||||
            button->setNewKey (newKey, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setNewKey (const KeyPress& newKey, bool dontAskUser)
 | 
			
		||||
    {
 | 
			
		||||
        if (newKey.isValid())
 | 
			
		||||
        {
 | 
			
		||||
            auto previousCommand = owner.getMappings().findCommandForKeyPress (newKey);
 | 
			
		||||
 | 
			
		||||
            if (previousCommand == 0 || dontAskUser)
 | 
			
		||||
            {
 | 
			
		||||
                owner.getMappings().removeKeyPress (newKey);
 | 
			
		||||
 | 
			
		||||
                if (keyNum >= 0)
 | 
			
		||||
                    owner.getMappings().removeKeyPress (commandID, keyNum);
 | 
			
		||||
 | 
			
		||||
                owner.getMappings().addKeyPress (commandID, newKey, keyNum);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                AlertWindow::showOkCancelBox (MessageBoxIconType::WarningIcon,
 | 
			
		||||
                                              TRANS("Change key-mapping"),
 | 
			
		||||
                                              TRANS("This key is already assigned to the command \"CMDN\"")
 | 
			
		||||
                                                  .replace ("CMDN", owner.getCommandManager().getNameOfCommand (previousCommand))
 | 
			
		||||
                                                + "\n\n"
 | 
			
		||||
                                                + TRANS("Do you want to re-assign it to this new command instead?"),
 | 
			
		||||
                                              TRANS("Re-assign"),
 | 
			
		||||
                                              TRANS("Cancel"),
 | 
			
		||||
                                              this,
 | 
			
		||||
                                              ModalCallbackFunction::forComponent (assignNewKeyCallback,
 | 
			
		||||
                                                                                   this, KeyPress (newKey)));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void keyChosen (int result, ChangeKeyButton* button)
 | 
			
		||||
    {
 | 
			
		||||
        if (button != nullptr && button->currentKeyEntryWindow != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            if (result != 0)
 | 
			
		||||
            {
 | 
			
		||||
                button->currentKeyEntryWindow->setVisible (false);
 | 
			
		||||
                button->setNewKey (button->currentKeyEntryWindow->lastPress, false);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            button->currentKeyEntryWindow.reset();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void assignNewKey()
 | 
			
		||||
    {
 | 
			
		||||
        currentKeyEntryWindow.reset (new KeyEntryWindow (owner));
 | 
			
		||||
        currentKeyEntryWindow->enterModalState (true, ModalCallbackFunction::forComponent (keyChosen, this));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
    const CommandID commandID;
 | 
			
		||||
    const int keyNum;
 | 
			
		||||
    std::unique_ptr<KeyEntryWindow> currentKeyEntryWindow;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ChangeKeyButton)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class KeyMappingEditorComponent::ItemComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ItemComponent (KeyMappingEditorComponent& kec, CommandID command)
 | 
			
		||||
        : owner (kec), commandID (command)
 | 
			
		||||
    {
 | 
			
		||||
        setInterceptsMouseClicks (false, true);
 | 
			
		||||
 | 
			
		||||
        const bool isReadOnly = owner.isCommandReadOnly (commandID);
 | 
			
		||||
 | 
			
		||||
        auto keyPresses = owner.getMappings().getKeyPressesAssignedToCommand (commandID);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < jmin ((int) maxNumAssignments, keyPresses.size()); ++i)
 | 
			
		||||
            addKeyPressButton (owner.getDescriptionForKeyPress (keyPresses.getReference (i)), i, isReadOnly);
 | 
			
		||||
 | 
			
		||||
        addKeyPressButton ("Change Key Mapping", -1, isReadOnly);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addKeyPressButton (const String& desc, const int index, const bool isReadOnly)
 | 
			
		||||
    {
 | 
			
		||||
        auto* b = new ChangeKeyButton (owner, commandID, desc, index);
 | 
			
		||||
        keyChangeButtons.add (b);
 | 
			
		||||
 | 
			
		||||
        b->setEnabled (! isReadOnly);
 | 
			
		||||
        b->setVisible (keyChangeButtons.size() <= (int) maxNumAssignments);
 | 
			
		||||
        addChildComponent (b);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void paint (Graphics& g) override
 | 
			
		||||
    {
 | 
			
		||||
        g.setFont ((float) getHeight() * 0.7f);
 | 
			
		||||
        g.setColour (owner.findColour (KeyMappingEditorComponent::textColourId));
 | 
			
		||||
 | 
			
		||||
        g.drawFittedText (TRANS (owner.getCommandManager().getNameOfCommand (commandID)),
 | 
			
		||||
                          4, 0, jmax (40, getChildComponent (0)->getX() - 5), getHeight(),
 | 
			
		||||
                          Justification::centredLeft, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resized() override
 | 
			
		||||
    {
 | 
			
		||||
        int x = getWidth() - 4;
 | 
			
		||||
 | 
			
		||||
        for (int i = keyChangeButtons.size(); --i >= 0;)
 | 
			
		||||
        {
 | 
			
		||||
            auto* b = keyChangeButtons.getUnchecked(i);
 | 
			
		||||
 | 
			
		||||
            b->fitToContent (getHeight() - 2);
 | 
			
		||||
            b->setTopRightPosition (x, 1);
 | 
			
		||||
            x = b->getX() - 5;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
 | 
			
		||||
    {
 | 
			
		||||
        return createIgnoredAccessibilityHandler (*this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
    OwnedArray<ChangeKeyButton> keyChangeButtons;
 | 
			
		||||
    const CommandID commandID;
 | 
			
		||||
 | 
			
		||||
    enum { maxNumAssignments = 3 };
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (ItemComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class KeyMappingEditorComponent::MappingItem  : public TreeViewItem
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    MappingItem (KeyMappingEditorComponent& kec, CommandID command)
 | 
			
		||||
        : owner (kec), commandID (command)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    String getUniqueName() const override                      { return String ((int) commandID) + "_id"; }
 | 
			
		||||
    bool mightContainSubItems() override                       { return false; }
 | 
			
		||||
    int getItemHeight() const override                         { return 20; }
 | 
			
		||||
    std::unique_ptr<Component> createItemComponent() override  { return std::make_unique<ItemComponent> (owner, commandID); }
 | 
			
		||||
    String getAccessibilityName() override                     { return TRANS (owner.getCommandManager().getNameOfCommand (commandID)); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
    const CommandID commandID;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (MappingItem)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class KeyMappingEditorComponent::CategoryItem  : public TreeViewItem
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CategoryItem (KeyMappingEditorComponent& kec, const String& name)
 | 
			
		||||
        : owner (kec), categoryName (name)
 | 
			
		||||
    {}
 | 
			
		||||
 | 
			
		||||
    String getUniqueName() const override       { return categoryName + "_cat"; }
 | 
			
		||||
    bool mightContainSubItems() override        { return true; }
 | 
			
		||||
    int getItemHeight() const override          { return 22; }
 | 
			
		||||
    String getAccessibilityName() override      { return categoryName; }
 | 
			
		||||
 | 
			
		||||
    void paintItem (Graphics& g, int width, int height) override
 | 
			
		||||
    {
 | 
			
		||||
        g.setFont (Font ((float) height * 0.7f, Font::bold));
 | 
			
		||||
        g.setColour (owner.findColour (KeyMappingEditorComponent::textColourId));
 | 
			
		||||
 | 
			
		||||
        g.drawText (TRANS (categoryName), 2, 0, width - 2, height, Justification::centredLeft, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void itemOpennessChanged (bool isNowOpen) override
 | 
			
		||||
    {
 | 
			
		||||
        if (isNowOpen)
 | 
			
		||||
        {
 | 
			
		||||
            if (getNumSubItems() == 0)
 | 
			
		||||
                for (auto command : owner.getCommandManager().getCommandsInCategory (categoryName))
 | 
			
		||||
                    if (owner.shouldCommandBeIncluded (command))
 | 
			
		||||
                        addSubItem (new MappingItem (owner, command));
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            clearSubItems();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
    String categoryName;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (CategoryItem)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class KeyMappingEditorComponent::TopLevelItem   : public TreeViewItem,
 | 
			
		||||
                                                  private ChangeListener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    TopLevelItem (KeyMappingEditorComponent& kec)   : owner (kec)
 | 
			
		||||
    {
 | 
			
		||||
        setLinesDrawnForSubItems (false);
 | 
			
		||||
        owner.getMappings().addChangeListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~TopLevelItem() override
 | 
			
		||||
    {
 | 
			
		||||
        owner.getMappings().removeChangeListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool mightContainSubItems() override             { return true; }
 | 
			
		||||
    String getUniqueName() const override            { return "keys"; }
 | 
			
		||||
 | 
			
		||||
    void changeListenerCallback (ChangeBroadcaster*) override
 | 
			
		||||
    {
 | 
			
		||||
        const OpennessRestorer opennessRestorer (*this);
 | 
			
		||||
        clearSubItems();
 | 
			
		||||
 | 
			
		||||
        for (auto category : owner.getCommandManager().getCommandCategories())
 | 
			
		||||
        {
 | 
			
		||||
            int count = 0;
 | 
			
		||||
 | 
			
		||||
            for (auto command : owner.getCommandManager().getCommandsInCategory (category))
 | 
			
		||||
                if (owner.shouldCommandBeIncluded (command))
 | 
			
		||||
                    ++count;
 | 
			
		||||
 | 
			
		||||
            if (count > 0)
 | 
			
		||||
                addSubItem (new CategoryItem (owner, category));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KeyMappingEditorComponent& owner;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
static void resetKeyMappingsToDefaultsCallback (int result, KeyMappingEditorComponent* owner)
 | 
			
		||||
{
 | 
			
		||||
    if (result != 0 && owner != nullptr)
 | 
			
		||||
        owner->getMappings().resetToDefaultMappings();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
KeyMappingEditorComponent::KeyMappingEditorComponent (KeyPressMappingSet& mappingManager,
 | 
			
		||||
                                                      const bool showResetToDefaultButton)
 | 
			
		||||
    : mappings (mappingManager),
 | 
			
		||||
      resetButton (TRANS ("reset to defaults"))
 | 
			
		||||
{
 | 
			
		||||
    treeItem.reset (new TopLevelItem (*this));
 | 
			
		||||
 | 
			
		||||
    if (showResetToDefaultButton)
 | 
			
		||||
    {
 | 
			
		||||
        addAndMakeVisible (resetButton);
 | 
			
		||||
 | 
			
		||||
        resetButton.onClick = [this]
 | 
			
		||||
        {
 | 
			
		||||
            AlertWindow::showOkCancelBox (MessageBoxIconType::QuestionIcon,
 | 
			
		||||
                                          TRANS("Reset to defaults"),
 | 
			
		||||
                                          TRANS("Are you sure you want to reset all the key-mappings to their default state?"),
 | 
			
		||||
                                          TRANS("Reset"),
 | 
			
		||||
                                          {}, this,
 | 
			
		||||
                                          ModalCallbackFunction::forComponent (resetKeyMappingsToDefaultsCallback, this));
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    addAndMakeVisible (tree);
 | 
			
		||||
    tree.setTitle ("Key Mappings");
 | 
			
		||||
    tree.setColour (TreeView::backgroundColourId, findColour (backgroundColourId));
 | 
			
		||||
    tree.setRootItemVisible (false);
 | 
			
		||||
    tree.setDefaultOpenness (true);
 | 
			
		||||
    tree.setRootItem (treeItem.get());
 | 
			
		||||
    tree.setIndentSize (12);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KeyMappingEditorComponent::~KeyMappingEditorComponent()
 | 
			
		||||
{
 | 
			
		||||
    tree.setRootItem (nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void KeyMappingEditorComponent::setColours (Colour mainBackground,
 | 
			
		||||
                                            Colour textColour)
 | 
			
		||||
{
 | 
			
		||||
    setColour (backgroundColourId, mainBackground);
 | 
			
		||||
    setColour (textColourId, textColour);
 | 
			
		||||
    tree.setColour (TreeView::backgroundColourId, mainBackground);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KeyMappingEditorComponent::parentHierarchyChanged()
 | 
			
		||||
{
 | 
			
		||||
    treeItem->changeListenerCallback (nullptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KeyMappingEditorComponent::resized()
 | 
			
		||||
{
 | 
			
		||||
    int h = getHeight();
 | 
			
		||||
 | 
			
		||||
    if (resetButton.isVisible())
 | 
			
		||||
    {
 | 
			
		||||
        const int buttonHeight = 20;
 | 
			
		||||
        h -= buttonHeight + 8;
 | 
			
		||||
        int x = getWidth() - 8;
 | 
			
		||||
 | 
			
		||||
        resetButton.changeWidthToFitText (buttonHeight);
 | 
			
		||||
        resetButton.setTopRightPosition (x, h + 6);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    tree.setBounds (0, 0, getWidth(), h);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
bool KeyMappingEditorComponent::shouldCommandBeIncluded (const CommandID commandID)
 | 
			
		||||
{
 | 
			
		||||
    auto* ci = mappings.getCommandManager().getCommandForID (commandID);
 | 
			
		||||
 | 
			
		||||
    return ci != nullptr && (ci->flags & ApplicationCommandInfo::hiddenFromKeyEditor) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool KeyMappingEditorComponent::isCommandReadOnly (const CommandID commandID)
 | 
			
		||||
{
 | 
			
		||||
    auto* ci = mappings.getCommandManager().getCommandForID (commandID);
 | 
			
		||||
 | 
			
		||||
    return ci != nullptr && (ci->flags & ApplicationCommandInfo::readOnlyInKeyEditor) != 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String KeyMappingEditorComponent::getDescriptionForKeyPress (const KeyPress& key)
 | 
			
		||||
{
 | 
			
		||||
    return key.getTextDescription();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,132 +1,132 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A component to allow editing of the keymaps stored by a KeyPressMappingSet
 | 
			
		||||
    object.
 | 
			
		||||
 | 
			
		||||
    @see KeyPressMappingSet
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  KeyMappingEditorComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a KeyMappingEditorComponent.
 | 
			
		||||
 | 
			
		||||
        @param mappingSet   this is the set of mappings to display and edit. Make sure the
 | 
			
		||||
                            mappings object is not deleted before this component!
 | 
			
		||||
        @param showResetToDefaultButton     if true, then at the bottom of the list, the
 | 
			
		||||
                                            component will include a 'reset to defaults' button.
 | 
			
		||||
    */
 | 
			
		||||
    KeyMappingEditorComponent (KeyPressMappingSet& mappingSet,
 | 
			
		||||
                               bool showResetToDefaultButton);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~KeyMappingEditorComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets up the colours to use for parts of the component.
 | 
			
		||||
 | 
			
		||||
        @param mainBackground       colour to use for most of the background
 | 
			
		||||
        @param textColour           colour to use for the text
 | 
			
		||||
    */
 | 
			
		||||
    void setColours (Colour mainBackground,
 | 
			
		||||
                     Colour textColour);
 | 
			
		||||
 | 
			
		||||
    /** Returns the KeyPressMappingSet that this component is acting upon. */
 | 
			
		||||
    KeyPressMappingSet& getMappings() const noexcept                { return mappings; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the ApplicationCommandManager that this component is connected to. */
 | 
			
		||||
    ApplicationCommandManager& getCommandManager() const noexcept   { return mappings.getCommandManager(); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Can be overridden if some commands need to be excluded from the list.
 | 
			
		||||
 | 
			
		||||
        By default this will use the KeyPressMappingSet's shouldCommandBeVisibleInEditor()
 | 
			
		||||
        method to decide what to return, but you can override it to handle special cases.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool shouldCommandBeIncluded (CommandID commandID);
 | 
			
		||||
 | 
			
		||||
    /** Can be overridden to indicate that some commands are shown as read-only.
 | 
			
		||||
 | 
			
		||||
        By default this will use the KeyPressMappingSet's shouldCommandBeReadOnlyInEditor()
 | 
			
		||||
        method to decide what to return, but you can override it to handle special cases.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool isCommandReadOnly (CommandID commandID);
 | 
			
		||||
 | 
			
		||||
    /** This can be overridden to let you change the format of the string used
 | 
			
		||||
        to describe a keypress.
 | 
			
		||||
 | 
			
		||||
        This is handy if you're using non-standard KeyPress objects, e.g. for custom
 | 
			
		||||
        keys that are triggered by something else externally. If you override the
 | 
			
		||||
        method, be sure to let the base class's method handle keys you're not
 | 
			
		||||
        interested in.
 | 
			
		||||
    */
 | 
			
		||||
    virtual String getDescriptionForKeyPress (const KeyPress& key);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the editor.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId  = 0x100ad00,    /**< The background colour to fill the editor background. */
 | 
			
		||||
        textColourId        = 0x100ad01,    /**< The colour for the text. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentHierarchyChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    KeyPressMappingSet& mappings;
 | 
			
		||||
    TreeView tree;
 | 
			
		||||
    TextButton resetButton;
 | 
			
		||||
 | 
			
		||||
    class TopLevelItem;
 | 
			
		||||
    class ChangeKeyButton;
 | 
			
		||||
    class MappingItem;
 | 
			
		||||
    class CategoryItem;
 | 
			
		||||
    class ItemComponent;
 | 
			
		||||
    std::unique_ptr<TopLevelItem> treeItem;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KeyMappingEditorComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A component to allow editing of the keymaps stored by a KeyPressMappingSet
 | 
			
		||||
    object.
 | 
			
		||||
 | 
			
		||||
    @see KeyPressMappingSet
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  KeyMappingEditorComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a KeyMappingEditorComponent.
 | 
			
		||||
 | 
			
		||||
        @param mappingSet   this is the set of mappings to display and edit. Make sure the
 | 
			
		||||
                            mappings object is not deleted before this component!
 | 
			
		||||
        @param showResetToDefaultButton     if true, then at the bottom of the list, the
 | 
			
		||||
                                            component will include a 'reset to defaults' button.
 | 
			
		||||
    */
 | 
			
		||||
    KeyMappingEditorComponent (KeyPressMappingSet& mappingSet,
 | 
			
		||||
                               bool showResetToDefaultButton);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~KeyMappingEditorComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets up the colours to use for parts of the component.
 | 
			
		||||
 | 
			
		||||
        @param mainBackground       colour to use for most of the background
 | 
			
		||||
        @param textColour           colour to use for the text
 | 
			
		||||
    */
 | 
			
		||||
    void setColours (Colour mainBackground,
 | 
			
		||||
                     Colour textColour);
 | 
			
		||||
 | 
			
		||||
    /** Returns the KeyPressMappingSet that this component is acting upon. */
 | 
			
		||||
    KeyPressMappingSet& getMappings() const noexcept                { return mappings; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the ApplicationCommandManager that this component is connected to. */
 | 
			
		||||
    ApplicationCommandManager& getCommandManager() const noexcept   { return mappings.getCommandManager(); }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Can be overridden if some commands need to be excluded from the list.
 | 
			
		||||
 | 
			
		||||
        By default this will use the KeyPressMappingSet's shouldCommandBeVisibleInEditor()
 | 
			
		||||
        method to decide what to return, but you can override it to handle special cases.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool shouldCommandBeIncluded (CommandID commandID);
 | 
			
		||||
 | 
			
		||||
    /** Can be overridden to indicate that some commands are shown as read-only.
 | 
			
		||||
 | 
			
		||||
        By default this will use the KeyPressMappingSet's shouldCommandBeReadOnlyInEditor()
 | 
			
		||||
        method to decide what to return, but you can override it to handle special cases.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool isCommandReadOnly (CommandID commandID);
 | 
			
		||||
 | 
			
		||||
    /** This can be overridden to let you change the format of the string used
 | 
			
		||||
        to describe a keypress.
 | 
			
		||||
 | 
			
		||||
        This is handy if you're using non-standard KeyPress objects, e.g. for custom
 | 
			
		||||
        keys that are triggered by something else externally. If you override the
 | 
			
		||||
        method, be sure to let the base class's method handle keys you're not
 | 
			
		||||
        interested in.
 | 
			
		||||
    */
 | 
			
		||||
    virtual String getDescriptionForKeyPress (const KeyPress& key);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** A set of colour IDs to use to change the colour of various aspects of the editor.
 | 
			
		||||
 | 
			
		||||
        These constants can be used either via the Component::setColour(), or LookAndFeel::setColour()
 | 
			
		||||
        methods.
 | 
			
		||||
 | 
			
		||||
        @see Component::setColour, Component::findColour, LookAndFeel::setColour, LookAndFeel::findColour
 | 
			
		||||
    */
 | 
			
		||||
    enum ColourIds
 | 
			
		||||
    {
 | 
			
		||||
        backgroundColourId  = 0x100ad00,    /**< The background colour to fill the editor background. */
 | 
			
		||||
        textColourId        = 0x100ad01,    /**< The colour for the text. */
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentHierarchyChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    KeyPressMappingSet& mappings;
 | 
			
		||||
    TreeView tree;
 | 
			
		||||
    TextButton resetButton;
 | 
			
		||||
 | 
			
		||||
    class TopLevelItem;
 | 
			
		||||
    class ChangeKeyButton;
 | 
			
		||||
    class MappingItem;
 | 
			
		||||
    class CategoryItem;
 | 
			
		||||
    class ItemComponent;
 | 
			
		||||
    std::unique_ptr<TopLevelItem> treeItem;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (KeyMappingEditorComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,497 +1,497 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR
 | 
			
		||||
 | 
			
		||||
namespace LiveConstantEditor
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class AllComponentRepainter  : private Timer,
 | 
			
		||||
                               private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    AllComponentRepainter()  {}
 | 
			
		||||
    ~AllComponentRepainter() override  { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_SINGLETON (AllComponentRepainter, false)
 | 
			
		||||
 | 
			
		||||
    void trigger()
 | 
			
		||||
    {
 | 
			
		||||
        if (! isTimerRunning())
 | 
			
		||||
            startTimer (100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        stopTimer();
 | 
			
		||||
 | 
			
		||||
        Array<Component*> alreadyDone;
 | 
			
		||||
 | 
			
		||||
        for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;)
 | 
			
		||||
            if (auto* c = TopLevelWindow::getTopLevelWindow(i))
 | 
			
		||||
                repaintAndResizeAllComps (c, alreadyDone);
 | 
			
		||||
 | 
			
		||||
        auto& desktop = Desktop::getInstance();
 | 
			
		||||
 | 
			
		||||
        for (int i = desktop.getNumComponents(); --i >= 0;)
 | 
			
		||||
            if (auto* c = desktop.getComponent(i))
 | 
			
		||||
                repaintAndResizeAllComps (c, alreadyDone);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void repaintAndResizeAllComps (Component::SafePointer<Component> c,
 | 
			
		||||
                                          Array<Component*>& alreadyDone)
 | 
			
		||||
    {
 | 
			
		||||
        if (c->isVisible() && ! alreadyDone.contains (c))
 | 
			
		||||
        {
 | 
			
		||||
            c->repaint();
 | 
			
		||||
            c->resized();
 | 
			
		||||
 | 
			
		||||
            for (int i = c->getNumChildComponents(); --i >= 0;)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* child = c->getChildComponent(i))
 | 
			
		||||
                {
 | 
			
		||||
                    repaintAndResizeAllComps (child, alreadyDone);
 | 
			
		||||
                    alreadyDone.add (child);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (c == nullptr)
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (AllComponentRepainter)
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (ValueList)
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
int64 parseInt (String s)
 | 
			
		||||
{
 | 
			
		||||
    s = s.trimStart();
 | 
			
		||||
 | 
			
		||||
    if (s.startsWithChar ('-'))
 | 
			
		||||
        return -parseInt (s.substring (1));
 | 
			
		||||
 | 
			
		||||
    if (s.startsWith ("0x"))
 | 
			
		||||
        return s.substring(2).getHexValue64();
 | 
			
		||||
 | 
			
		||||
    return s.getLargeIntValue();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double parseDouble (const String& s)
 | 
			
		||||
{
 | 
			
		||||
    return s.retainCharacters ("0123456789.eE-").getDoubleValue();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String intToString (int   v, bool preferHex)    { return preferHex ? "0x" + String::toHexString (v) : String (v); }
 | 
			
		||||
String intToString (int64 v, bool preferHex)    { return preferHex ? "0x" + String::toHexString (v) : String (v); }
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
LiveValueBase::LiveValueBase (const char* file, int line)
 | 
			
		||||
    : sourceFile (file), sourceLine (line)
 | 
			
		||||
{
 | 
			
		||||
    name = File (sourceFile).getFileName() + " : " + String (sourceLine);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LiveValueBase::~LiveValueBase()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
LivePropertyEditorBase::LivePropertyEditorBase (LiveValueBase& v, CodeDocument& d)
 | 
			
		||||
    : value (v), document (d), sourceEditor (document, &tokeniser)
 | 
			
		||||
{
 | 
			
		||||
    setSize (600, 100);
 | 
			
		||||
 | 
			
		||||
    addAndMakeVisible (name);
 | 
			
		||||
    addAndMakeVisible (resetButton);
 | 
			
		||||
    addAndMakeVisible (valueEditor);
 | 
			
		||||
    addAndMakeVisible (sourceEditor);
 | 
			
		||||
 | 
			
		||||
    findOriginalValueInCode();
 | 
			
		||||
    selectOriginalValue();
 | 
			
		||||
 | 
			
		||||
    name.setFont (13.0f);
 | 
			
		||||
    name.setText (v.name, dontSendNotification);
 | 
			
		||||
    valueEditor.setMultiLine (v.isString());
 | 
			
		||||
    valueEditor.setReturnKeyStartsNewLine (v.isString());
 | 
			
		||||
    valueEditor.setText (v.getStringValue (wasHex), dontSendNotification);
 | 
			
		||||
    valueEditor.onTextChange = [this] { applyNewValue (valueEditor.getText()); };
 | 
			
		||||
    sourceEditor.setReadOnly (true);
 | 
			
		||||
    sourceEditor.setFont (sourceEditor.getFont().withHeight (13.0f));
 | 
			
		||||
    resetButton.onClick = [this] { applyNewValue (value.getOriginalStringValue (wasHex)); };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    g.setColour (Colours::white);
 | 
			
		||||
    g.fillRect (getLocalBounds().removeFromBottom (1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::resized()
 | 
			
		||||
{
 | 
			
		||||
    auto r = getLocalBounds().reduced (0, 3).withTrimmedBottom (1);
 | 
			
		||||
 | 
			
		||||
    auto left = r.removeFromLeft (jmax (200, r.getWidth() / 3));
 | 
			
		||||
 | 
			
		||||
    auto top = left.removeFromTop (25);
 | 
			
		||||
    resetButton.setBounds (top.removeFromRight (35).reduced (0, 3));
 | 
			
		||||
    name.setBounds (top);
 | 
			
		||||
 | 
			
		||||
    if (customComp != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        valueEditor.setBounds (left.removeFromTop (25));
 | 
			
		||||
        left.removeFromTop (2);
 | 
			
		||||
        customComp->setBounds (left);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        valueEditor.setBounds (left);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    r.removeFromLeft (4);
 | 
			
		||||
    sourceEditor.setBounds (r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::applyNewValue (const String& s)
 | 
			
		||||
{
 | 
			
		||||
    value.setStringValue (s);
 | 
			
		||||
 | 
			
		||||
    document.replaceSection (valueStart.getPosition(), valueEnd.getPosition(), value.getCodeValue (wasHex));
 | 
			
		||||
    document.clearUndoHistory();
 | 
			
		||||
    selectOriginalValue();
 | 
			
		||||
 | 
			
		||||
    valueEditor.setText (s, dontSendNotification);
 | 
			
		||||
    AllComponentRepainter::getInstance()->trigger();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::selectOriginalValue()
 | 
			
		||||
{
 | 
			
		||||
    sourceEditor.selectRegion (valueStart, valueEnd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::findOriginalValueInCode()
 | 
			
		||||
{
 | 
			
		||||
    CodeDocument::Position pos (document, value.sourceLine, 0);
 | 
			
		||||
    auto line = pos.getLineText();
 | 
			
		||||
    auto p = line.getCharPointer();
 | 
			
		||||
 | 
			
		||||
    p = CharacterFunctions::find (p, CharPointer_ASCII ("JUCE_LIVE_CONSTANT"));
 | 
			
		||||
 | 
			
		||||
    if (p.isEmpty())
 | 
			
		||||
    {
 | 
			
		||||
        // Not sure how this would happen - some kind of mix-up between source code and line numbers..
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    p += (int) (sizeof ("JUCE_LIVE_CONSTANT") - 1);
 | 
			
		||||
    p.incrementToEndOfWhitespace();
 | 
			
		||||
 | 
			
		||||
    if (! CharacterFunctions::find (p, CharPointer_ASCII ("JUCE_LIVE_CONSTANT")).isEmpty())
 | 
			
		||||
    {
 | 
			
		||||
        // Aargh! You've added two JUCE_LIVE_CONSTANT macros on the same line!
 | 
			
		||||
        // They're identified by their line number, so you must make sure each
 | 
			
		||||
        // one goes on a separate line!
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (p.getAndAdvance() == '(')
 | 
			
		||||
    {
 | 
			
		||||
        auto start = p, end = p;
 | 
			
		||||
 | 
			
		||||
        int depth = 1;
 | 
			
		||||
 | 
			
		||||
        while (! end.isEmpty())
 | 
			
		||||
        {
 | 
			
		||||
            auto c = end.getAndAdvance();
 | 
			
		||||
 | 
			
		||||
            if (c == '(')  ++depth;
 | 
			
		||||
            if (c == ')')  --depth;
 | 
			
		||||
 | 
			
		||||
            if (depth == 0)
 | 
			
		||||
            {
 | 
			
		||||
                --end;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (end > start)
 | 
			
		||||
        {
 | 
			
		||||
            valueStart = CodeDocument::Position (document, value.sourceLine, (int) (start - line.getCharPointer()));
 | 
			
		||||
            valueEnd   = CodeDocument::Position (document, value.sourceLine, (int) (end   - line.getCharPointer()));
 | 
			
		||||
 | 
			
		||||
            valueStart.setPositionMaintained (true);
 | 
			
		||||
            valueEnd.setPositionMaintained (true);
 | 
			
		||||
 | 
			
		||||
            wasHex = String (start, end).containsIgnoreCase ("0x");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class ValueListHolderComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ValueListHolderComponent (ValueList& l) : valueList (l)
 | 
			
		||||
    {
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addItem (int width, LiveValueBase& v, CodeDocument& doc)
 | 
			
		||||
    {
 | 
			
		||||
        addAndMakeVisible (editors.add (v.createPropertyComponent (doc)));
 | 
			
		||||
        layout (width);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void layout (int width)
 | 
			
		||||
    {
 | 
			
		||||
        setSize (width, editors.size() * itemHeight);
 | 
			
		||||
        resized();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resized() override
 | 
			
		||||
    {
 | 
			
		||||
        auto r = getLocalBounds().reduced (2, 0);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < editors.size(); ++i)
 | 
			
		||||
            editors.getUnchecked(i)->setBounds (r.removeFromTop (itemHeight));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum { itemHeight = 120 };
 | 
			
		||||
 | 
			
		||||
    ValueList& valueList;
 | 
			
		||||
    OwnedArray<LivePropertyEditorBase> editors;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class ValueList::EditorWindow  : public DocumentWindow,
 | 
			
		||||
                                 private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    EditorWindow (ValueList& list)
 | 
			
		||||
        : DocumentWindow ("Live Values", Colours::lightgrey, DocumentWindow::closeButton)
 | 
			
		||||
    {
 | 
			
		||||
        setLookAndFeel (&lookAndFeel);
 | 
			
		||||
        setUsingNativeTitleBar (true);
 | 
			
		||||
 | 
			
		||||
        viewport.setViewedComponent (new ValueListHolderComponent (list), true);
 | 
			
		||||
        viewport.setSize (700, 600);
 | 
			
		||||
        viewport.setScrollBarsShown (true, false);
 | 
			
		||||
 | 
			
		||||
        setContentNonOwned (&viewport, true);
 | 
			
		||||
        setResizable (true, false);
 | 
			
		||||
        setResizeLimits (500, 400, 10000, 10000);
 | 
			
		||||
        centreWithSize (getWidth(), getHeight());
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~EditorWindow() override
 | 
			
		||||
    {
 | 
			
		||||
        setLookAndFeel (nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void closeButtonPressed() override
 | 
			
		||||
    {
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateItems (ValueList& list)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* l = dynamic_cast<ValueListHolderComponent*> (viewport.getViewedComponent()))
 | 
			
		||||
        {
 | 
			
		||||
            while (l->getNumChildComponents() < list.values.size())
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* v = list.values [l->getNumChildComponents()])
 | 
			
		||||
                    l->addItem (viewport.getMaximumVisibleWidth(), *v, list.getDocument (v->sourceFile));
 | 
			
		||||
                else
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setVisible (true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resized() override
 | 
			
		||||
    {
 | 
			
		||||
        DocumentWindow::resized();
 | 
			
		||||
 | 
			
		||||
        if (auto* l = dynamic_cast<ValueListHolderComponent*> (viewport.getViewedComponent()))
 | 
			
		||||
            l->layout (viewport.getMaximumVisibleWidth());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Viewport viewport;
 | 
			
		||||
    LookAndFeel_V3 lookAndFeel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
ValueList::ValueList()  {}
 | 
			
		||||
ValueList::~ValueList() { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
void ValueList::addValue (LiveValueBase* v)
 | 
			
		||||
{
 | 
			
		||||
    values.add (v);
 | 
			
		||||
    triggerAsyncUpdate();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ValueList::handleAsyncUpdate()
 | 
			
		||||
{
 | 
			
		||||
    if (editorWindow == nullptr)
 | 
			
		||||
        editorWindow = new EditorWindow (*this);
 | 
			
		||||
 | 
			
		||||
    editorWindow->updateItems (*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CodeDocument& ValueList::getDocument (const File& file)
 | 
			
		||||
{
 | 
			
		||||
    const int index = documentFiles.indexOf (file.getFullPathName());
 | 
			
		||||
 | 
			
		||||
    if (index >= 0)
 | 
			
		||||
        return *documents.getUnchecked (index);
 | 
			
		||||
 | 
			
		||||
    auto* doc = documents.add (new CodeDocument());
 | 
			
		||||
    documentFiles.add (file);
 | 
			
		||||
    doc->replaceAllContent (file.loadFileAsString());
 | 
			
		||||
    doc->clearUndoHistory();
 | 
			
		||||
    return *doc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct ColourEditorComp  : public Component,
 | 
			
		||||
                           private ChangeListener
 | 
			
		||||
{
 | 
			
		||||
    ColourEditorComp (LivePropertyEditorBase& e)  : editor (e)
 | 
			
		||||
    {
 | 
			
		||||
        setMouseCursor (MouseCursor::PointingHandCursor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Colour getColour() const
 | 
			
		||||
    {
 | 
			
		||||
        return Colour ((uint32) parseInt (editor.value.getStringValue (false)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void paint (Graphics& g) override
 | 
			
		||||
    {
 | 
			
		||||
        g.fillCheckerBoard (getLocalBounds().toFloat(), 6.0f, 6.0f,
 | 
			
		||||
                            Colour (0xffdddddd).overlaidWith (getColour()),
 | 
			
		||||
                            Colour (0xffffffff).overlaidWith (getColour()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void mouseDown (const MouseEvent&) override
 | 
			
		||||
    {
 | 
			
		||||
        auto colourSelector = std::make_unique<ColourSelector>();
 | 
			
		||||
        colourSelector->setName ("Colour");
 | 
			
		||||
        colourSelector->setCurrentColour (getColour());
 | 
			
		||||
        colourSelector->addChangeListener (this);
 | 
			
		||||
        colourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
 | 
			
		||||
        colourSelector->setSize (300, 400);
 | 
			
		||||
 | 
			
		||||
        CallOutBox::launchAsynchronously (std::move (colourSelector), getScreenBounds(), nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void changeListenerCallback (ChangeBroadcaster* source) override
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* cs = dynamic_cast<ColourSelector*> (source))
 | 
			
		||||
            editor.applyNewValue (getAsString (cs->getCurrentColour(), true));
 | 
			
		||||
 | 
			
		||||
        repaint();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LivePropertyEditorBase& editor;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Component* createColourEditor (LivePropertyEditorBase& editor)
 | 
			
		||||
{
 | 
			
		||||
    return new ColourEditorComp (editor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct SliderComp   : public Component
 | 
			
		||||
{
 | 
			
		||||
    SliderComp (LivePropertyEditorBase& e, bool useFloat)
 | 
			
		||||
        : editor (e), isFloat (useFloat)
 | 
			
		||||
    {
 | 
			
		||||
        slider.setTextBoxStyle (Slider::NoTextBox, true, 0, 0);
 | 
			
		||||
        addAndMakeVisible (slider);
 | 
			
		||||
        updateRange();
 | 
			
		||||
        slider.onDragEnd = [this] { updateRange(); };
 | 
			
		||||
        slider.onValueChange = [this]
 | 
			
		||||
        {
 | 
			
		||||
            editor.applyNewValue (isFloat ? getAsString ((double) slider.getValue(), editor.wasHex)
 | 
			
		||||
                                          : getAsString ((int64)  slider.getValue(), editor.wasHex));
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void updateRange()
 | 
			
		||||
    {
 | 
			
		||||
        double v = isFloat ? parseDouble (editor.value.getStringValue (false))
 | 
			
		||||
                           : (double) parseInt (editor.value.getStringValue (false));
 | 
			
		||||
 | 
			
		||||
        double range = isFloat ? 10 : 100;
 | 
			
		||||
 | 
			
		||||
        slider.setRange (v - range, v + range);
 | 
			
		||||
        slider.setValue (v, dontSendNotification);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resized() override
 | 
			
		||||
    {
 | 
			
		||||
        slider.setBounds (getLocalBounds().removeFromTop (25));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LivePropertyEditorBase& editor;
 | 
			
		||||
    Slider slider;
 | 
			
		||||
    bool isFloat;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct BoolSliderComp  : public SliderComp
 | 
			
		||||
{
 | 
			
		||||
    BoolSliderComp (LivePropertyEditorBase& e)
 | 
			
		||||
        : SliderComp (e, false)
 | 
			
		||||
    {
 | 
			
		||||
        slider.onValueChange = [this] { editor.applyNewValue (slider.getValue() > 0.5 ? "true" : "false"); };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateRange() override
 | 
			
		||||
    {
 | 
			
		||||
        slider.setRange (0.0, 1.0, dontSendNotification);
 | 
			
		||||
        slider.setValue (editor.value.getStringValue (false) == "true", dontSendNotification);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Component* createIntegerSlider (LivePropertyEditorBase& editor)  { return new SliderComp (editor, false); }
 | 
			
		||||
Component* createFloatSlider   (LivePropertyEditorBase& editor)  { return new SliderComp (editor, true);  }
 | 
			
		||||
Component* createBoolSlider    (LivePropertyEditorBase& editor)  { return new BoolSliderComp (editor); }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR
 | 
			
		||||
 | 
			
		||||
namespace LiveConstantEditor
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class AllComponentRepainter  : private Timer,
 | 
			
		||||
                               private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    AllComponentRepainter()  {}
 | 
			
		||||
    ~AllComponentRepainter() override  { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_SINGLETON (AllComponentRepainter, false)
 | 
			
		||||
 | 
			
		||||
    void trigger()
 | 
			
		||||
    {
 | 
			
		||||
        if (! isTimerRunning())
 | 
			
		||||
            startTimer (100);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        stopTimer();
 | 
			
		||||
 | 
			
		||||
        Array<Component*> alreadyDone;
 | 
			
		||||
 | 
			
		||||
        for (int i = TopLevelWindow::getNumTopLevelWindows(); --i >= 0;)
 | 
			
		||||
            if (auto* c = TopLevelWindow::getTopLevelWindow(i))
 | 
			
		||||
                repaintAndResizeAllComps (c, alreadyDone);
 | 
			
		||||
 | 
			
		||||
        auto& desktop = Desktop::getInstance();
 | 
			
		||||
 | 
			
		||||
        for (int i = desktop.getNumComponents(); --i >= 0;)
 | 
			
		||||
            if (auto* c = desktop.getComponent(i))
 | 
			
		||||
                repaintAndResizeAllComps (c, alreadyDone);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void repaintAndResizeAllComps (Component::SafePointer<Component> c,
 | 
			
		||||
                                          Array<Component*>& alreadyDone)
 | 
			
		||||
    {
 | 
			
		||||
        if (c->isVisible() && ! alreadyDone.contains (c))
 | 
			
		||||
        {
 | 
			
		||||
            c->repaint();
 | 
			
		||||
            c->resized();
 | 
			
		||||
 | 
			
		||||
            for (int i = c->getNumChildComponents(); --i >= 0;)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* child = c->getChildComponent(i))
 | 
			
		||||
                {
 | 
			
		||||
                    repaintAndResizeAllComps (child, alreadyDone);
 | 
			
		||||
                    alreadyDone.add (child);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                if (c == nullptr)
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (AllComponentRepainter)
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (ValueList)
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
int64 parseInt (String s)
 | 
			
		||||
{
 | 
			
		||||
    s = s.trimStart();
 | 
			
		||||
 | 
			
		||||
    if (s.startsWithChar ('-'))
 | 
			
		||||
        return -parseInt (s.substring (1));
 | 
			
		||||
 | 
			
		||||
    if (s.startsWith ("0x"))
 | 
			
		||||
        return s.substring(2).getHexValue64();
 | 
			
		||||
 | 
			
		||||
    return s.getLargeIntValue();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double parseDouble (const String& s)
 | 
			
		||||
{
 | 
			
		||||
    return s.retainCharacters ("0123456789.eE-").getDoubleValue();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String intToString (int   v, bool preferHex)    { return preferHex ? "0x" + String::toHexString (v) : String (v); }
 | 
			
		||||
String intToString (int64 v, bool preferHex)    { return preferHex ? "0x" + String::toHexString (v) : String (v); }
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
LiveValueBase::LiveValueBase (const char* file, int line)
 | 
			
		||||
    : sourceFile (file), sourceLine (line)
 | 
			
		||||
{
 | 
			
		||||
    name = File (sourceFile).getFileName() + " : " + String (sourceLine);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LiveValueBase::~LiveValueBase()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
LivePropertyEditorBase::LivePropertyEditorBase (LiveValueBase& v, CodeDocument& d)
 | 
			
		||||
    : value (v), document (d), sourceEditor (document, &tokeniser)
 | 
			
		||||
{
 | 
			
		||||
    setSize (600, 100);
 | 
			
		||||
 | 
			
		||||
    addAndMakeVisible (name);
 | 
			
		||||
    addAndMakeVisible (resetButton);
 | 
			
		||||
    addAndMakeVisible (valueEditor);
 | 
			
		||||
    addAndMakeVisible (sourceEditor);
 | 
			
		||||
 | 
			
		||||
    findOriginalValueInCode();
 | 
			
		||||
    selectOriginalValue();
 | 
			
		||||
 | 
			
		||||
    name.setFont (13.0f);
 | 
			
		||||
    name.setText (v.name, dontSendNotification);
 | 
			
		||||
    valueEditor.setMultiLine (v.isString());
 | 
			
		||||
    valueEditor.setReturnKeyStartsNewLine (v.isString());
 | 
			
		||||
    valueEditor.setText (v.getStringValue (wasHex), dontSendNotification);
 | 
			
		||||
    valueEditor.onTextChange = [this] { applyNewValue (valueEditor.getText()); };
 | 
			
		||||
    sourceEditor.setReadOnly (true);
 | 
			
		||||
    sourceEditor.setFont (sourceEditor.getFont().withHeight (13.0f));
 | 
			
		||||
    resetButton.onClick = [this] { applyNewValue (value.getOriginalStringValue (wasHex)); };
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    g.setColour (Colours::white);
 | 
			
		||||
    g.fillRect (getLocalBounds().removeFromBottom (1));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::resized()
 | 
			
		||||
{
 | 
			
		||||
    auto r = getLocalBounds().reduced (0, 3).withTrimmedBottom (1);
 | 
			
		||||
 | 
			
		||||
    auto left = r.removeFromLeft (jmax (200, r.getWidth() / 3));
 | 
			
		||||
 | 
			
		||||
    auto top = left.removeFromTop (25);
 | 
			
		||||
    resetButton.setBounds (top.removeFromRight (35).reduced (0, 3));
 | 
			
		||||
    name.setBounds (top);
 | 
			
		||||
 | 
			
		||||
    if (customComp != nullptr)
 | 
			
		||||
    {
 | 
			
		||||
        valueEditor.setBounds (left.removeFromTop (25));
 | 
			
		||||
        left.removeFromTop (2);
 | 
			
		||||
        customComp->setBounds (left);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        valueEditor.setBounds (left);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    r.removeFromLeft (4);
 | 
			
		||||
    sourceEditor.setBounds (r);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::applyNewValue (const String& s)
 | 
			
		||||
{
 | 
			
		||||
    value.setStringValue (s);
 | 
			
		||||
 | 
			
		||||
    document.replaceSection (valueStart.getPosition(), valueEnd.getPosition(), value.getCodeValue (wasHex));
 | 
			
		||||
    document.clearUndoHistory();
 | 
			
		||||
    selectOriginalValue();
 | 
			
		||||
 | 
			
		||||
    valueEditor.setText (s, dontSendNotification);
 | 
			
		||||
    AllComponentRepainter::getInstance()->trigger();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::selectOriginalValue()
 | 
			
		||||
{
 | 
			
		||||
    sourceEditor.selectRegion (valueStart, valueEnd);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void LivePropertyEditorBase::findOriginalValueInCode()
 | 
			
		||||
{
 | 
			
		||||
    CodeDocument::Position pos (document, value.sourceLine, 0);
 | 
			
		||||
    auto line = pos.getLineText();
 | 
			
		||||
    auto p = line.getCharPointer();
 | 
			
		||||
 | 
			
		||||
    p = CharacterFunctions::find (p, CharPointer_ASCII ("JUCE_LIVE_CONSTANT"));
 | 
			
		||||
 | 
			
		||||
    if (p.isEmpty())
 | 
			
		||||
    {
 | 
			
		||||
        // Not sure how this would happen - some kind of mix-up between source code and line numbers..
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
        return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    p += (int) (sizeof ("JUCE_LIVE_CONSTANT") - 1);
 | 
			
		||||
    p.incrementToEndOfWhitespace();
 | 
			
		||||
 | 
			
		||||
    if (! CharacterFunctions::find (p, CharPointer_ASCII ("JUCE_LIVE_CONSTANT")).isEmpty())
 | 
			
		||||
    {
 | 
			
		||||
        // Aargh! You've added two JUCE_LIVE_CONSTANT macros on the same line!
 | 
			
		||||
        // They're identified by their line number, so you must make sure each
 | 
			
		||||
        // one goes on a separate line!
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (p.getAndAdvance() == '(')
 | 
			
		||||
    {
 | 
			
		||||
        auto start = p, end = p;
 | 
			
		||||
 | 
			
		||||
        int depth = 1;
 | 
			
		||||
 | 
			
		||||
        while (! end.isEmpty())
 | 
			
		||||
        {
 | 
			
		||||
            auto c = end.getAndAdvance();
 | 
			
		||||
 | 
			
		||||
            if (c == '(')  ++depth;
 | 
			
		||||
            if (c == ')')  --depth;
 | 
			
		||||
 | 
			
		||||
            if (depth == 0)
 | 
			
		||||
            {
 | 
			
		||||
                --end;
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (end > start)
 | 
			
		||||
        {
 | 
			
		||||
            valueStart = CodeDocument::Position (document, value.sourceLine, (int) (start - line.getCharPointer()));
 | 
			
		||||
            valueEnd   = CodeDocument::Position (document, value.sourceLine, (int) (end   - line.getCharPointer()));
 | 
			
		||||
 | 
			
		||||
            valueStart.setPositionMaintained (true);
 | 
			
		||||
            valueEnd.setPositionMaintained (true);
 | 
			
		||||
 | 
			
		||||
            wasHex = String (start, end).containsIgnoreCase ("0x");
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class ValueListHolderComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    ValueListHolderComponent (ValueList& l) : valueList (l)
 | 
			
		||||
    {
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void addItem (int width, LiveValueBase& v, CodeDocument& doc)
 | 
			
		||||
    {
 | 
			
		||||
        addAndMakeVisible (editors.add (v.createPropertyComponent (doc)));
 | 
			
		||||
        layout (width);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void layout (int width)
 | 
			
		||||
    {
 | 
			
		||||
        setSize (width, editors.size() * itemHeight);
 | 
			
		||||
        resized();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resized() override
 | 
			
		||||
    {
 | 
			
		||||
        auto r = getLocalBounds().reduced (2, 0);
 | 
			
		||||
 | 
			
		||||
        for (int i = 0; i < editors.size(); ++i)
 | 
			
		||||
            editors.getUnchecked(i)->setBounds (r.removeFromTop (itemHeight));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    enum { itemHeight = 120 };
 | 
			
		||||
 | 
			
		||||
    ValueList& valueList;
 | 
			
		||||
    OwnedArray<LivePropertyEditorBase> editors;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class ValueList::EditorWindow  : public DocumentWindow,
 | 
			
		||||
                                 private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    EditorWindow (ValueList& list)
 | 
			
		||||
        : DocumentWindow ("Live Values", Colours::lightgrey, DocumentWindow::closeButton)
 | 
			
		||||
    {
 | 
			
		||||
        setLookAndFeel (&lookAndFeel);
 | 
			
		||||
        setUsingNativeTitleBar (true);
 | 
			
		||||
 | 
			
		||||
        viewport.setViewedComponent (new ValueListHolderComponent (list), true);
 | 
			
		||||
        viewport.setSize (700, 600);
 | 
			
		||||
        viewport.setScrollBarsShown (true, false);
 | 
			
		||||
 | 
			
		||||
        setContentNonOwned (&viewport, true);
 | 
			
		||||
        setResizable (true, false);
 | 
			
		||||
        setResizeLimits (500, 400, 10000, 10000);
 | 
			
		||||
        centreWithSize (getWidth(), getHeight());
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~EditorWindow() override
 | 
			
		||||
    {
 | 
			
		||||
        setLookAndFeel (nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void closeButtonPressed() override
 | 
			
		||||
    {
 | 
			
		||||
        setVisible (false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateItems (ValueList& list)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* l = dynamic_cast<ValueListHolderComponent*> (viewport.getViewedComponent()))
 | 
			
		||||
        {
 | 
			
		||||
            while (l->getNumChildComponents() < list.values.size())
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* v = list.values [l->getNumChildComponents()])
 | 
			
		||||
                    l->addItem (viewport.getMaximumVisibleWidth(), *v, list.getDocument (v->sourceFile));
 | 
			
		||||
                else
 | 
			
		||||
                    break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setVisible (true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resized() override
 | 
			
		||||
    {
 | 
			
		||||
        DocumentWindow::resized();
 | 
			
		||||
 | 
			
		||||
        if (auto* l = dynamic_cast<ValueListHolderComponent*> (viewport.getViewedComponent()))
 | 
			
		||||
            l->layout (viewport.getMaximumVisibleWidth());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Viewport viewport;
 | 
			
		||||
    LookAndFeel_V3 lookAndFeel;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
ValueList::ValueList()  {}
 | 
			
		||||
ValueList::~ValueList() { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
void ValueList::addValue (LiveValueBase* v)
 | 
			
		||||
{
 | 
			
		||||
    values.add (v);
 | 
			
		||||
    triggerAsyncUpdate();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ValueList::handleAsyncUpdate()
 | 
			
		||||
{
 | 
			
		||||
    if (editorWindow == nullptr)
 | 
			
		||||
        editorWindow = new EditorWindow (*this);
 | 
			
		||||
 | 
			
		||||
    editorWindow->updateItems (*this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
CodeDocument& ValueList::getDocument (const File& file)
 | 
			
		||||
{
 | 
			
		||||
    const int index = documentFiles.indexOf (file.getFullPathName());
 | 
			
		||||
 | 
			
		||||
    if (index >= 0)
 | 
			
		||||
        return *documents.getUnchecked (index);
 | 
			
		||||
 | 
			
		||||
    auto* doc = documents.add (new CodeDocument());
 | 
			
		||||
    documentFiles.add (file);
 | 
			
		||||
    doc->replaceAllContent (file.loadFileAsString());
 | 
			
		||||
    doc->clearUndoHistory();
 | 
			
		||||
    return *doc;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct ColourEditorComp  : public Component,
 | 
			
		||||
                           private ChangeListener
 | 
			
		||||
{
 | 
			
		||||
    ColourEditorComp (LivePropertyEditorBase& e)  : editor (e)
 | 
			
		||||
    {
 | 
			
		||||
        setMouseCursor (MouseCursor::PointingHandCursor);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Colour getColour() const
 | 
			
		||||
    {
 | 
			
		||||
        return Colour ((uint32) parseInt (editor.value.getStringValue (false)));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void paint (Graphics& g) override
 | 
			
		||||
    {
 | 
			
		||||
        g.fillCheckerBoard (getLocalBounds().toFloat(), 6.0f, 6.0f,
 | 
			
		||||
                            Colour (0xffdddddd).overlaidWith (getColour()),
 | 
			
		||||
                            Colour (0xffffffff).overlaidWith (getColour()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void mouseDown (const MouseEvent&) override
 | 
			
		||||
    {
 | 
			
		||||
        auto colourSelector = std::make_unique<ColourSelector>();
 | 
			
		||||
        colourSelector->setName ("Colour");
 | 
			
		||||
        colourSelector->setCurrentColour (getColour());
 | 
			
		||||
        colourSelector->addChangeListener (this);
 | 
			
		||||
        colourSelector->setColour (ColourSelector::backgroundColourId, Colours::transparentBlack);
 | 
			
		||||
        colourSelector->setSize (300, 400);
 | 
			
		||||
 | 
			
		||||
        CallOutBox::launchAsynchronously (std::move (colourSelector), getScreenBounds(), nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void changeListenerCallback (ChangeBroadcaster* source) override
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* cs = dynamic_cast<ColourSelector*> (source))
 | 
			
		||||
            editor.applyNewValue (getAsString (cs->getCurrentColour(), true));
 | 
			
		||||
 | 
			
		||||
        repaint();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LivePropertyEditorBase& editor;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Component* createColourEditor (LivePropertyEditorBase& editor)
 | 
			
		||||
{
 | 
			
		||||
    return new ColourEditorComp (editor);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct SliderComp   : public Component
 | 
			
		||||
{
 | 
			
		||||
    SliderComp (LivePropertyEditorBase& e, bool useFloat)
 | 
			
		||||
        : editor (e), isFloat (useFloat)
 | 
			
		||||
    {
 | 
			
		||||
        slider.setTextBoxStyle (Slider::NoTextBox, true, 0, 0);
 | 
			
		||||
        addAndMakeVisible (slider);
 | 
			
		||||
        updateRange();
 | 
			
		||||
        slider.onDragEnd = [this] { updateRange(); };
 | 
			
		||||
        slider.onValueChange = [this]
 | 
			
		||||
        {
 | 
			
		||||
            editor.applyNewValue (isFloat ? getAsString ((double) slider.getValue(), editor.wasHex)
 | 
			
		||||
                                          : getAsString ((int64)  slider.getValue(), editor.wasHex));
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void updateRange()
 | 
			
		||||
    {
 | 
			
		||||
        double v = isFloat ? parseDouble (editor.value.getStringValue (false))
 | 
			
		||||
                           : (double) parseInt (editor.value.getStringValue (false));
 | 
			
		||||
 | 
			
		||||
        double range = isFloat ? 10 : 100;
 | 
			
		||||
 | 
			
		||||
        slider.setRange (v - range, v + range);
 | 
			
		||||
        slider.setValue (v, dontSendNotification);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void resized() override
 | 
			
		||||
    {
 | 
			
		||||
        slider.setBounds (getLocalBounds().removeFromTop (25));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    LivePropertyEditorBase& editor;
 | 
			
		||||
    Slider slider;
 | 
			
		||||
    bool isFloat;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct BoolSliderComp  : public SliderComp
 | 
			
		||||
{
 | 
			
		||||
    BoolSliderComp (LivePropertyEditorBase& e)
 | 
			
		||||
        : SliderComp (e, false)
 | 
			
		||||
    {
 | 
			
		||||
        slider.onValueChange = [this] { editor.applyNewValue (slider.getValue() > 0.5 ? "true" : "false"); };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateRange() override
 | 
			
		||||
    {
 | 
			
		||||
        slider.setRange (0.0, 1.0, dontSendNotification);
 | 
			
		||||
        slider.setValue (editor.value.getStringValue (false) == "true", dontSendNotification);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Component* createIntegerSlider (LivePropertyEditorBase& editor)  { return new SliderComp (editor, false); }
 | 
			
		||||
Component* createFloatSlider   (LivePropertyEditorBase& editor)  { return new SliderComp (editor, true);  }
 | 
			
		||||
Component* createBoolSlider    (LivePropertyEditorBase& editor)  { return new BoolSliderComp (editor); }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,305 +1,305 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR && ! defined (DOXYGEN)
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** You can safely ignore all the stuff in this namespace - it's a bunch of boilerplate
 | 
			
		||||
    code used to implement the JUCE_LIVE_CONSTANT functionality.
 | 
			
		||||
*/
 | 
			
		||||
namespace LiveConstantEditor
 | 
			
		||||
{
 | 
			
		||||
    int64 parseInt (String);
 | 
			
		||||
    double parseDouble (const String&);
 | 
			
		||||
    String intToString (int, bool preferHex);
 | 
			
		||||
    String intToString (int64, bool preferHex);
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    static void setFromString (Type& v,           const String& s)    { v = static_cast<Type> (s); }
 | 
			
		||||
    inline void setFromString (char& v,           const String& s)    { v = (char)           parseInt (s); }
 | 
			
		||||
    inline void setFromString (unsigned char& v,  const String& s)    { v = (unsigned char)  parseInt (s); }
 | 
			
		||||
    inline void setFromString (short& v,          const String& s)    { v = (short)          parseInt (s); }
 | 
			
		||||
    inline void setFromString (unsigned short& v, const String& s)    { v = (unsigned short) parseInt (s); }
 | 
			
		||||
    inline void setFromString (int& v,            const String& s)    { v = (int)            parseInt (s); }
 | 
			
		||||
    inline void setFromString (unsigned int& v,   const String& s)    { v = (unsigned int)   parseInt (s); }
 | 
			
		||||
    inline void setFromString (long& v,           const String& s)    { v = (long)           parseInt (s); }
 | 
			
		||||
    inline void setFromString (unsigned long& v,  const String& s)    { v = (unsigned long)  parseInt (s); }
 | 
			
		||||
    inline void setFromString (int64& v,          const String& s)    { v = (int64)          parseInt (s); }
 | 
			
		||||
    inline void setFromString (uint64& v,         const String& s)    { v = (uint64)         parseInt (s); }
 | 
			
		||||
    inline void setFromString (double& v,         const String& s)    { v = parseDouble (s); }
 | 
			
		||||
    inline void setFromString (float& v,          const String& s)    { v = (float) parseDouble (s); }
 | 
			
		||||
    inline void setFromString (bool& v,           const String& s)    { v = (s == "true"); }
 | 
			
		||||
    inline void setFromString (String& v,         const String& s)    { v = s; }
 | 
			
		||||
    inline void setFromString (Colour& v,         const String& s)    { v = Colour ((uint32) parseInt (s)); }
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    inline String getAsString (const Type& v, bool)              { return String (v); }
 | 
			
		||||
    inline String getAsString (char v, bool preferHex)           { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (unsigned char v, bool preferHex)  { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (short v, bool preferHex)          { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (unsigned short v, bool preferHex) { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (int v, bool preferHex)            { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (unsigned int v, bool preferHex)   { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (bool v, bool)                     { return v ? "true" : "false"; }
 | 
			
		||||
    inline String getAsString (int64 v, bool preferHex)          { return intToString ((int64) v, preferHex); }
 | 
			
		||||
    inline String getAsString (uint64 v, bool preferHex)         { return intToString ((int64) v, preferHex); }
 | 
			
		||||
    inline String getAsString (Colour v, bool)                   { return intToString ((int) v.getARGB(), true); }
 | 
			
		||||
 | 
			
		||||
    template <typename Type>    struct isStringType              { enum { value = 0 }; };
 | 
			
		||||
    template <>                 struct isStringType<String>      { enum { value = 1 }; };
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    inline String getAsCode (Type& v, bool preferHex)       { return getAsString (v, preferHex); }
 | 
			
		||||
    inline String getAsCode (Colour v, bool)                { return "Colour (0x" + String::toHexString ((int) v.getARGB()).paddedLeft ('0', 8) + ")"; }
 | 
			
		||||
    inline String getAsCode (const String& v, bool)         { return CppTokeniserFunctions::addEscapeChars(v).quoted(); }
 | 
			
		||||
    inline String getAsCode (const char* v, bool)           { return getAsCode (String (v), false); }
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    inline const char* castToCharPointer (const Type&)      { return ""; }
 | 
			
		||||
    inline const char* castToCharPointer (const String& s)  { return s.toRawUTF8(); }
 | 
			
		||||
 | 
			
		||||
    struct LivePropertyEditorBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JUCE_API  LiveValueBase
 | 
			
		||||
    {
 | 
			
		||||
        LiveValueBase (const char* file, int line);
 | 
			
		||||
        virtual ~LiveValueBase();
 | 
			
		||||
 | 
			
		||||
        virtual LivePropertyEditorBase* createPropertyComponent (CodeDocument&) = 0;
 | 
			
		||||
        virtual String getStringValue (bool preferHex) const = 0;
 | 
			
		||||
        virtual String getCodeValue (bool preferHex) const = 0;
 | 
			
		||||
        virtual void setStringValue (const String&) = 0;
 | 
			
		||||
        virtual String getOriginalStringValue (bool preferHex) const = 0;
 | 
			
		||||
        virtual bool isString() const = 0;
 | 
			
		||||
 | 
			
		||||
        String name, sourceFile;
 | 
			
		||||
        int sourceLine;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (LiveValueBase)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JUCE_API  LivePropertyEditorBase  : public Component
 | 
			
		||||
    {
 | 
			
		||||
        LivePropertyEditorBase (LiveValueBase&, CodeDocument&);
 | 
			
		||||
 | 
			
		||||
        void paint (Graphics&) override;
 | 
			
		||||
        void resized() override;
 | 
			
		||||
 | 
			
		||||
        void applyNewValue (const String&);
 | 
			
		||||
        void selectOriginalValue();
 | 
			
		||||
        void findOriginalValueInCode();
 | 
			
		||||
 | 
			
		||||
        LiveValueBase& value;
 | 
			
		||||
        Label name;
 | 
			
		||||
        TextEditor valueEditor;
 | 
			
		||||
        TextButton resetButton { "reset" };
 | 
			
		||||
        CodeDocument& document;
 | 
			
		||||
        CPlusPlusCodeTokeniser tokeniser;
 | 
			
		||||
        CodeEditorComponent sourceEditor;
 | 
			
		||||
        CodeDocument::Position valueStart, valueEnd;
 | 
			
		||||
        std::unique_ptr<Component> customComp;
 | 
			
		||||
        bool wasHex = false;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (LivePropertyEditorBase)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Component* createColourEditor (LivePropertyEditorBase&);
 | 
			
		||||
    Component* createIntegerSlider (LivePropertyEditorBase&);
 | 
			
		||||
    Component* createFloatSlider (LivePropertyEditorBase&);
 | 
			
		||||
    Component* createBoolSlider (LivePropertyEditorBase&);
 | 
			
		||||
 | 
			
		||||
    template <typename Type> struct CustomEditor    { static Component* create (LivePropertyEditorBase&)   { return nullptr; } };
 | 
			
		||||
    template <> struct CustomEditor<char>           { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<unsigned char>  { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<int>            { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<unsigned int>   { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<short>          { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<unsigned short> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<int64>          { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<uint64>         { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<float>          { static Component* create (LivePropertyEditorBase& e) { return createFloatSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<double>         { static Component* create (LivePropertyEditorBase& e) { return createFloatSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<Colour>         { static Component* create (LivePropertyEditorBase& e) { return createColourEditor (e); } };
 | 
			
		||||
    template <> struct CustomEditor<bool>           { static Component* create (LivePropertyEditorBase& e) { return createBoolSlider (e); } };
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    struct LivePropertyEditor  : public LivePropertyEditorBase
 | 
			
		||||
    {
 | 
			
		||||
        template <typename ValueType>
 | 
			
		||||
        LivePropertyEditor (ValueType& v, CodeDocument& d)  : LivePropertyEditorBase (v, d)
 | 
			
		||||
        {
 | 
			
		||||
            customComp.reset (CustomEditor<Type>::create (*this));
 | 
			
		||||
            addAndMakeVisible (customComp.get());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    struct LiveValue  : public LiveValueBase
 | 
			
		||||
    {
 | 
			
		||||
        LiveValue (const char* file, int line, const Type& initialValue)
 | 
			
		||||
            : LiveValueBase (file, line), value (initialValue), originalValue (initialValue)
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        operator Type() const noexcept   { return value; }
 | 
			
		||||
        Type get() const noexcept        { return value; }
 | 
			
		||||
        operator const char*() const     { return castToCharPointer (value); }
 | 
			
		||||
 | 
			
		||||
        LivePropertyEditorBase* createPropertyComponent (CodeDocument& doc) override
 | 
			
		||||
        {
 | 
			
		||||
            return new LivePropertyEditor<Type> (*this, doc);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String getStringValue (bool preferHex) const override           { return getAsString (value, preferHex); }
 | 
			
		||||
        String getCodeValue (bool preferHex) const override             { return getAsCode (value, preferHex); }
 | 
			
		||||
        String getOriginalStringValue (bool preferHex) const override   { return getAsString (originalValue, preferHex); }
 | 
			
		||||
        void setStringValue (const String& s) override                  { setFromString (value, s); }
 | 
			
		||||
        bool isString() const override                                  { return isStringType<Type>::value; }
 | 
			
		||||
 | 
			
		||||
        Type value, originalValue;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (LiveValue)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class JUCE_API ValueList  : private AsyncUpdater,
 | 
			
		||||
                                private DeletedAtShutdown
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ValueList();
 | 
			
		||||
        ~ValueList() override;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_SINGLETON (ValueList, false)
 | 
			
		||||
 | 
			
		||||
        template <typename Type>
 | 
			
		||||
        LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue)
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedLock sl (lock);
 | 
			
		||||
            using ValueType = LiveValue<Type>;
 | 
			
		||||
 | 
			
		||||
            for (auto* v : values)
 | 
			
		||||
                if (v->sourceLine == line && v->sourceFile == file)
 | 
			
		||||
                    return *static_cast<ValueType*> (v);
 | 
			
		||||
 | 
			
		||||
            auto v = new ValueType (file, line, initialValue);
 | 
			
		||||
            addValue (v);
 | 
			
		||||
            return *v;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        OwnedArray<LiveValueBase> values;
 | 
			
		||||
        OwnedArray<CodeDocument> documents;
 | 
			
		||||
        Array<File> documentFiles;
 | 
			
		||||
        class EditorWindow;
 | 
			
		||||
        Component::SafePointer<EditorWindow> editorWindow;
 | 
			
		||||
        CriticalSection lock;
 | 
			
		||||
 | 
			
		||||
        CodeDocument& getDocument (const File&);
 | 
			
		||||
        void addValue (LiveValueBase*);
 | 
			
		||||
        void handleAsyncUpdate() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    inline LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue)
 | 
			
		||||
    {
 | 
			
		||||
        // If you hit this assertion then the __FILE__ macro is providing a
 | 
			
		||||
        // relative path instead of an absolute path. On Windows this will be
 | 
			
		||||
        // a path relative to the build directory rather than the currently
 | 
			
		||||
        // running application. To fix this you must compile with the /FC flag.
 | 
			
		||||
        jassert (File::isAbsolutePath (file));
 | 
			
		||||
 | 
			
		||||
        return ValueList::getInstance()->getValue (file, line, initialValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline LiveValue<String>& getValue (const char* file, int line, const char* initialValue)
 | 
			
		||||
    {
 | 
			
		||||
        return getValue (file, line, String (initialValue));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR || DOXYGEN
 | 
			
		||||
 /**
 | 
			
		||||
    This macro wraps a primitive constant value in some cunning boilerplate code that allows
 | 
			
		||||
    its value to be interactively tweaked in a popup window while your application is running.
 | 
			
		||||
 | 
			
		||||
    In a release build, this macro disappears and is replaced by only the constant that it
 | 
			
		||||
    wraps, but if JUCE_ENABLE_LIVE_CONSTANT_EDITOR is enabled, it injects a class wrapper
 | 
			
		||||
    that automatically pops-up a window containing an editor that allows the value to be
 | 
			
		||||
    tweaked at run-time. The editor window will also force all visible components to be
 | 
			
		||||
    resized and repainted whenever a value is changed, so that if you use this to wrap
 | 
			
		||||
    a colour or layout parameter, you'll be able to immediately see the effects of changing it.
 | 
			
		||||
 | 
			
		||||
    The editor will also load the original source-file that contains each JUCE_LIVE_CONSTANT
 | 
			
		||||
    macro, and will display a preview of the modified source code as you adjust the values.
 | 
			
		||||
 | 
			
		||||
    Things to note:
 | 
			
		||||
 | 
			
		||||
    - Only one of these per line! The __FILE__ and __LINE__ macros are used to identify
 | 
			
		||||
      the value, so things will get confused if you have more than one per line
 | 
			
		||||
    - Obviously because it needs to load the source code based on the __FILE__ macro,
 | 
			
		||||
      it'll only work if the source files are stored locally in the same location as they
 | 
			
		||||
      were when you compiled the program.
 | 
			
		||||
    - It's only designed to cope with simple types: primitives, string literals, and
 | 
			
		||||
      the Colour class, so if you try using it for other classes or complex expressions,
 | 
			
		||||
      good luck!
 | 
			
		||||
    - The editor window will get popped up whenever a new value is used for the first
 | 
			
		||||
      time. You can close the window, but there's no way to get it back without restarting
 | 
			
		||||
      the app!
 | 
			
		||||
 | 
			
		||||
    e.g. in this example the colours, font size, and text used in the paint method can
 | 
			
		||||
    all be adjusted live:
 | 
			
		||||
    @code
 | 
			
		||||
    void MyComp::paint (Graphics& g) override
 | 
			
		||||
    {
 | 
			
		||||
        g.fillAll (JUCE_LIVE_CONSTANT (Colour (0xffddddff)));
 | 
			
		||||
 | 
			
		||||
        Colour fontColour = JUCE_LIVE_CONSTANT (Colour (0xff005500));
 | 
			
		||||
        float fontSize = JUCE_LIVE_CONSTANT (16.0f);
 | 
			
		||||
 | 
			
		||||
        g.setColour (fontColour);
 | 
			
		||||
        g.setFont (fontSize);
 | 
			
		||||
 | 
			
		||||
        g.drawFittedText (JUCE_LIVE_CONSTANT ("Hello world!"),
 | 
			
		||||
                          getLocalBounds(), Justification::centred, 2);
 | 
			
		||||
    }
 | 
			
		||||
    @endcode
 | 
			
		||||
 */
 | 
			
		||||
 #define JUCE_LIVE_CONSTANT(initialValue) \
 | 
			
		||||
    (juce::LiveConstantEditor::getValue (__FILE__, __LINE__ - 1, initialValue).get())
 | 
			
		||||
#else
 | 
			
		||||
 #define JUCE_LIVE_CONSTANT(initialValue) \
 | 
			
		||||
    (initialValue)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR && ! defined (DOXYGEN)
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** You can safely ignore all the stuff in this namespace - it's a bunch of boilerplate
 | 
			
		||||
    code used to implement the JUCE_LIVE_CONSTANT functionality.
 | 
			
		||||
*/
 | 
			
		||||
namespace LiveConstantEditor
 | 
			
		||||
{
 | 
			
		||||
    int64 parseInt (String);
 | 
			
		||||
    double parseDouble (const String&);
 | 
			
		||||
    String intToString (int, bool preferHex);
 | 
			
		||||
    String intToString (int64, bool preferHex);
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    static void setFromString (Type& v,           const String& s)    { v = static_cast<Type> (s); }
 | 
			
		||||
    inline void setFromString (char& v,           const String& s)    { v = (char)           parseInt (s); }
 | 
			
		||||
    inline void setFromString (unsigned char& v,  const String& s)    { v = (unsigned char)  parseInt (s); }
 | 
			
		||||
    inline void setFromString (short& v,          const String& s)    { v = (short)          parseInt (s); }
 | 
			
		||||
    inline void setFromString (unsigned short& v, const String& s)    { v = (unsigned short) parseInt (s); }
 | 
			
		||||
    inline void setFromString (int& v,            const String& s)    { v = (int)            parseInt (s); }
 | 
			
		||||
    inline void setFromString (unsigned int& v,   const String& s)    { v = (unsigned int)   parseInt (s); }
 | 
			
		||||
    inline void setFromString (long& v,           const String& s)    { v = (long)           parseInt (s); }
 | 
			
		||||
    inline void setFromString (unsigned long& v,  const String& s)    { v = (unsigned long)  parseInt (s); }
 | 
			
		||||
    inline void setFromString (int64& v,          const String& s)    { v = (int64)          parseInt (s); }
 | 
			
		||||
    inline void setFromString (uint64& v,         const String& s)    { v = (uint64)         parseInt (s); }
 | 
			
		||||
    inline void setFromString (double& v,         const String& s)    { v = parseDouble (s); }
 | 
			
		||||
    inline void setFromString (float& v,          const String& s)    { v = (float) parseDouble (s); }
 | 
			
		||||
    inline void setFromString (bool& v,           const String& s)    { v = (s == "true"); }
 | 
			
		||||
    inline void setFromString (String& v,         const String& s)    { v = s; }
 | 
			
		||||
    inline void setFromString (Colour& v,         const String& s)    { v = Colour ((uint32) parseInt (s)); }
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    inline String getAsString (const Type& v, bool)              { return String (v); }
 | 
			
		||||
    inline String getAsString (char v, bool preferHex)           { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (unsigned char v, bool preferHex)  { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (short v, bool preferHex)          { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (unsigned short v, bool preferHex) { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (int v, bool preferHex)            { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (unsigned int v, bool preferHex)   { return intToString ((int) v, preferHex); }
 | 
			
		||||
    inline String getAsString (bool v, bool)                     { return v ? "true" : "false"; }
 | 
			
		||||
    inline String getAsString (int64 v, bool preferHex)          { return intToString ((int64) v, preferHex); }
 | 
			
		||||
    inline String getAsString (uint64 v, bool preferHex)         { return intToString ((int64) v, preferHex); }
 | 
			
		||||
    inline String getAsString (Colour v, bool)                   { return intToString ((int) v.getARGB(), true); }
 | 
			
		||||
 | 
			
		||||
    template <typename Type>    struct isStringType              { enum { value = 0 }; };
 | 
			
		||||
    template <>                 struct isStringType<String>      { enum { value = 1 }; };
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    inline String getAsCode (Type& v, bool preferHex)       { return getAsString (v, preferHex); }
 | 
			
		||||
    inline String getAsCode (Colour v, bool)                { return "Colour (0x" + String::toHexString ((int) v.getARGB()).paddedLeft ('0', 8) + ")"; }
 | 
			
		||||
    inline String getAsCode (const String& v, bool)         { return CppTokeniserFunctions::addEscapeChars(v).quoted(); }
 | 
			
		||||
    inline String getAsCode (const char* v, bool)           { return getAsCode (String (v), false); }
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    inline const char* castToCharPointer (const Type&)      { return ""; }
 | 
			
		||||
    inline const char* castToCharPointer (const String& s)  { return s.toRawUTF8(); }
 | 
			
		||||
 | 
			
		||||
    struct LivePropertyEditorBase;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JUCE_API  LiveValueBase
 | 
			
		||||
    {
 | 
			
		||||
        LiveValueBase (const char* file, int line);
 | 
			
		||||
        virtual ~LiveValueBase();
 | 
			
		||||
 | 
			
		||||
        virtual LivePropertyEditorBase* createPropertyComponent (CodeDocument&) = 0;
 | 
			
		||||
        virtual String getStringValue (bool preferHex) const = 0;
 | 
			
		||||
        virtual String getCodeValue (bool preferHex) const = 0;
 | 
			
		||||
        virtual void setStringValue (const String&) = 0;
 | 
			
		||||
        virtual String getOriginalStringValue (bool preferHex) const = 0;
 | 
			
		||||
        virtual bool isString() const = 0;
 | 
			
		||||
 | 
			
		||||
        String name, sourceFile;
 | 
			
		||||
        int sourceLine;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (LiveValueBase)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JUCE_API  LivePropertyEditorBase  : public Component
 | 
			
		||||
    {
 | 
			
		||||
        LivePropertyEditorBase (LiveValueBase&, CodeDocument&);
 | 
			
		||||
 | 
			
		||||
        void paint (Graphics&) override;
 | 
			
		||||
        void resized() override;
 | 
			
		||||
 | 
			
		||||
        void applyNewValue (const String&);
 | 
			
		||||
        void selectOriginalValue();
 | 
			
		||||
        void findOriginalValueInCode();
 | 
			
		||||
 | 
			
		||||
        LiveValueBase& value;
 | 
			
		||||
        Label name;
 | 
			
		||||
        TextEditor valueEditor;
 | 
			
		||||
        TextButton resetButton { "reset" };
 | 
			
		||||
        CodeDocument& document;
 | 
			
		||||
        CPlusPlusCodeTokeniser tokeniser;
 | 
			
		||||
        CodeEditorComponent sourceEditor;
 | 
			
		||||
        CodeDocument::Position valueStart, valueEnd;
 | 
			
		||||
        std::unique_ptr<Component> customComp;
 | 
			
		||||
        bool wasHex = false;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (LivePropertyEditorBase)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Component* createColourEditor (LivePropertyEditorBase&);
 | 
			
		||||
    Component* createIntegerSlider (LivePropertyEditorBase&);
 | 
			
		||||
    Component* createFloatSlider (LivePropertyEditorBase&);
 | 
			
		||||
    Component* createBoolSlider (LivePropertyEditorBase&);
 | 
			
		||||
 | 
			
		||||
    template <typename Type> struct CustomEditor    { static Component* create (LivePropertyEditorBase&)   { return nullptr; } };
 | 
			
		||||
    template <> struct CustomEditor<char>           { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<unsigned char>  { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<int>            { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<unsigned int>   { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<short>          { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<unsigned short> { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<int64>          { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<uint64>         { static Component* create (LivePropertyEditorBase& e) { return createIntegerSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<float>          { static Component* create (LivePropertyEditorBase& e) { return createFloatSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<double>         { static Component* create (LivePropertyEditorBase& e) { return createFloatSlider (e); } };
 | 
			
		||||
    template <> struct CustomEditor<Colour>         { static Component* create (LivePropertyEditorBase& e) { return createColourEditor (e); } };
 | 
			
		||||
    template <> struct CustomEditor<bool>           { static Component* create (LivePropertyEditorBase& e) { return createBoolSlider (e); } };
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    struct LivePropertyEditor  : public LivePropertyEditorBase
 | 
			
		||||
    {
 | 
			
		||||
        template <typename ValueType>
 | 
			
		||||
        LivePropertyEditor (ValueType& v, CodeDocument& d)  : LivePropertyEditorBase (v, d)
 | 
			
		||||
        {
 | 
			
		||||
            customComp.reset (CustomEditor<Type>::create (*this));
 | 
			
		||||
            addAndMakeVisible (customComp.get());
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    struct LiveValue  : public LiveValueBase
 | 
			
		||||
    {
 | 
			
		||||
        LiveValue (const char* file, int line, const Type& initialValue)
 | 
			
		||||
            : LiveValueBase (file, line), value (initialValue), originalValue (initialValue)
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        operator Type() const noexcept   { return value; }
 | 
			
		||||
        Type get() const noexcept        { return value; }
 | 
			
		||||
        operator const char*() const     { return castToCharPointer (value); }
 | 
			
		||||
 | 
			
		||||
        LivePropertyEditorBase* createPropertyComponent (CodeDocument& doc) override
 | 
			
		||||
        {
 | 
			
		||||
            return new LivePropertyEditor<Type> (*this, doc);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        String getStringValue (bool preferHex) const override           { return getAsString (value, preferHex); }
 | 
			
		||||
        String getCodeValue (bool preferHex) const override             { return getAsCode (value, preferHex); }
 | 
			
		||||
        String getOriginalStringValue (bool preferHex) const override   { return getAsString (originalValue, preferHex); }
 | 
			
		||||
        void setStringValue (const String& s) override                  { setFromString (value, s); }
 | 
			
		||||
        bool isString() const override                                  { return isStringType<Type>::value; }
 | 
			
		||||
 | 
			
		||||
        Type value, originalValue;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_NON_COPYABLE (LiveValue)
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class JUCE_API ValueList  : private AsyncUpdater,
 | 
			
		||||
                                private DeletedAtShutdown
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ValueList();
 | 
			
		||||
        ~ValueList() override;
 | 
			
		||||
 | 
			
		||||
        JUCE_DECLARE_SINGLETON (ValueList, false)
 | 
			
		||||
 | 
			
		||||
        template <typename Type>
 | 
			
		||||
        LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue)
 | 
			
		||||
        {
 | 
			
		||||
            const ScopedLock sl (lock);
 | 
			
		||||
            using ValueType = LiveValue<Type>;
 | 
			
		||||
 | 
			
		||||
            for (auto* v : values)
 | 
			
		||||
                if (v->sourceLine == line && v->sourceFile == file)
 | 
			
		||||
                    return *static_cast<ValueType*> (v);
 | 
			
		||||
 | 
			
		||||
            auto v = new ValueType (file, line, initialValue);
 | 
			
		||||
            addValue (v);
 | 
			
		||||
            return *v;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        OwnedArray<LiveValueBase> values;
 | 
			
		||||
        OwnedArray<CodeDocument> documents;
 | 
			
		||||
        Array<File> documentFiles;
 | 
			
		||||
        class EditorWindow;
 | 
			
		||||
        Component::SafePointer<EditorWindow> editorWindow;
 | 
			
		||||
        CriticalSection lock;
 | 
			
		||||
 | 
			
		||||
        CodeDocument& getDocument (const File&);
 | 
			
		||||
        void addValue (LiveValueBase*);
 | 
			
		||||
        void handleAsyncUpdate() override;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    template <typename Type>
 | 
			
		||||
    inline LiveValue<Type>& getValue (const char* file, int line, const Type& initialValue)
 | 
			
		||||
    {
 | 
			
		||||
        // If you hit this assertion then the __FILE__ macro is providing a
 | 
			
		||||
        // relative path instead of an absolute path. On Windows this will be
 | 
			
		||||
        // a path relative to the build directory rather than the currently
 | 
			
		||||
        // running application. To fix this you must compile with the /FC flag.
 | 
			
		||||
        jassert (File::isAbsolutePath (file));
 | 
			
		||||
 | 
			
		||||
        return ValueList::getInstance()->getValue (file, line, initialValue);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    inline LiveValue<String>& getValue (const char* file, int line, const char* initialValue)
 | 
			
		||||
    {
 | 
			
		||||
        return getValue (file, line, String (initialValue));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if JUCE_ENABLE_LIVE_CONSTANT_EDITOR || DOXYGEN
 | 
			
		||||
 /**
 | 
			
		||||
    This macro wraps a primitive constant value in some cunning boilerplate code that allows
 | 
			
		||||
    its value to be interactively tweaked in a popup window while your application is running.
 | 
			
		||||
 | 
			
		||||
    In a release build, this macro disappears and is replaced by only the constant that it
 | 
			
		||||
    wraps, but if JUCE_ENABLE_LIVE_CONSTANT_EDITOR is enabled, it injects a class wrapper
 | 
			
		||||
    that automatically pops-up a window containing an editor that allows the value to be
 | 
			
		||||
    tweaked at run-time. The editor window will also force all visible components to be
 | 
			
		||||
    resized and repainted whenever a value is changed, so that if you use this to wrap
 | 
			
		||||
    a colour or layout parameter, you'll be able to immediately see the effects of changing it.
 | 
			
		||||
 | 
			
		||||
    The editor will also load the original source-file that contains each JUCE_LIVE_CONSTANT
 | 
			
		||||
    macro, and will display a preview of the modified source code as you adjust the values.
 | 
			
		||||
 | 
			
		||||
    Things to note:
 | 
			
		||||
 | 
			
		||||
    - Only one of these per line! The __FILE__ and __LINE__ macros are used to identify
 | 
			
		||||
      the value, so things will get confused if you have more than one per line
 | 
			
		||||
    - Obviously because it needs to load the source code based on the __FILE__ macro,
 | 
			
		||||
      it'll only work if the source files are stored locally in the same location as they
 | 
			
		||||
      were when you compiled the program.
 | 
			
		||||
    - It's only designed to cope with simple types: primitives, string literals, and
 | 
			
		||||
      the Colour class, so if you try using it for other classes or complex expressions,
 | 
			
		||||
      good luck!
 | 
			
		||||
    - The editor window will get popped up whenever a new value is used for the first
 | 
			
		||||
      time. You can close the window, but there's no way to get it back without restarting
 | 
			
		||||
      the app!
 | 
			
		||||
 | 
			
		||||
    e.g. in this example the colours, font size, and text used in the paint method can
 | 
			
		||||
    all be adjusted live:
 | 
			
		||||
    @code
 | 
			
		||||
    void MyComp::paint (Graphics& g) override
 | 
			
		||||
    {
 | 
			
		||||
        g.fillAll (JUCE_LIVE_CONSTANT (Colour (0xffddddff)));
 | 
			
		||||
 | 
			
		||||
        Colour fontColour = JUCE_LIVE_CONSTANT (Colour (0xff005500));
 | 
			
		||||
        float fontSize = JUCE_LIVE_CONSTANT (16.0f);
 | 
			
		||||
 | 
			
		||||
        g.setColour (fontColour);
 | 
			
		||||
        g.setFont (fontSize);
 | 
			
		||||
 | 
			
		||||
        g.drawFittedText (JUCE_LIVE_CONSTANT ("Hello world!"),
 | 
			
		||||
                          getLocalBounds(), Justification::centred, 2);
 | 
			
		||||
    }
 | 
			
		||||
    @endcode
 | 
			
		||||
 */
 | 
			
		||||
 #define JUCE_LIVE_CONSTANT(initialValue) \
 | 
			
		||||
    (juce::LiveConstantEditor::getValue (__FILE__, __LINE__ - 1, initialValue).get())
 | 
			
		||||
#else
 | 
			
		||||
 #define JUCE_LIVE_CONSTANT(initialValue) \
 | 
			
		||||
    (initialValue)
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,156 +1,156 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
PreferencesPanel::PreferencesPanel()
 | 
			
		||||
    : buttonSize (70)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PreferencesPanel::~PreferencesPanel()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int PreferencesPanel::getButtonSize() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return buttonSize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::setButtonSize (int newSize)
 | 
			
		||||
{
 | 
			
		||||
    buttonSize = newSize;
 | 
			
		||||
    resized();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void PreferencesPanel::addSettingsPage (const String& title,
 | 
			
		||||
                                        const Drawable* icon,
 | 
			
		||||
                                        const Drawable* overIcon,
 | 
			
		||||
                                        const Drawable* downIcon)
 | 
			
		||||
{
 | 
			
		||||
    auto* button = new DrawableButton (title, DrawableButton::ImageAboveTextLabel);
 | 
			
		||||
    buttons.add (button);
 | 
			
		||||
 | 
			
		||||
    button->setImages (icon, overIcon, downIcon);
 | 
			
		||||
    button->setRadioGroupId (1);
 | 
			
		||||
    button->onClick = [this] { clickedPage(); };
 | 
			
		||||
    button->setClickingTogglesState (true);
 | 
			
		||||
    button->setWantsKeyboardFocus (false);
 | 
			
		||||
    addAndMakeVisible (button);
 | 
			
		||||
 | 
			
		||||
    resized();
 | 
			
		||||
 | 
			
		||||
    if (currentPage == nullptr)
 | 
			
		||||
        setCurrentPage (title);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::addSettingsPage (const String& title, const void* imageData, int imageDataSize)
 | 
			
		||||
{
 | 
			
		||||
    DrawableImage icon, iconOver, iconDown;
 | 
			
		||||
    icon.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
 | 
			
		||||
 | 
			
		||||
    iconOver.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
 | 
			
		||||
    iconOver.setOverlayColour (Colours::black.withAlpha (0.12f));
 | 
			
		||||
 | 
			
		||||
    iconDown.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
 | 
			
		||||
    iconDown.setOverlayColour (Colours::black.withAlpha (0.25f));
 | 
			
		||||
 | 
			
		||||
    addSettingsPage (title, &icon, &iconOver, &iconDown);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void PreferencesPanel::showInDialogBox (const String& dialogTitle, int dialogWidth, int dialogHeight, Colour backgroundColour)
 | 
			
		||||
{
 | 
			
		||||
    setSize (dialogWidth, dialogHeight);
 | 
			
		||||
 | 
			
		||||
    DialogWindow::LaunchOptions o;
 | 
			
		||||
    o.content.setNonOwned (this);
 | 
			
		||||
    o.dialogTitle                   = dialogTitle;
 | 
			
		||||
    o.dialogBackgroundColour        = backgroundColour;
 | 
			
		||||
    o.escapeKeyTriggersCloseButton  = false;
 | 
			
		||||
    o.useNativeTitleBar             = false;
 | 
			
		||||
    o.resizable                     = false;
 | 
			
		||||
 | 
			
		||||
    o.launchAsync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void PreferencesPanel::resized()
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < buttons.size(); ++i)
 | 
			
		||||
        buttons.getUnchecked(i)->setBounds (i * buttonSize, 0, buttonSize, buttonSize);
 | 
			
		||||
 | 
			
		||||
    if (currentPage != nullptr)
 | 
			
		||||
        currentPage->setBounds (getLocalBounds().withTop (buttonSize + 5));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    g.setColour (Colours::grey);
 | 
			
		||||
    g.fillRect (0, buttonSize + 2, getWidth(), 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::setCurrentPage (const String& pageName)
 | 
			
		||||
{
 | 
			
		||||
    if (currentPageName != pageName)
 | 
			
		||||
    {
 | 
			
		||||
        currentPageName = pageName;
 | 
			
		||||
 | 
			
		||||
        currentPage.reset();
 | 
			
		||||
        currentPage.reset (createComponentForPage (pageName));
 | 
			
		||||
 | 
			
		||||
        if (currentPage != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            addAndMakeVisible (currentPage.get());
 | 
			
		||||
            currentPage->toBack();
 | 
			
		||||
            resized();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (auto* b : buttons)
 | 
			
		||||
        {
 | 
			
		||||
            if (b->getName() == pageName)
 | 
			
		||||
            {
 | 
			
		||||
                b->setToggleState (true, dontSendNotification);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::clickedPage()
 | 
			
		||||
{
 | 
			
		||||
    for (auto* b : buttons)
 | 
			
		||||
    {
 | 
			
		||||
        if (b->getToggleState())
 | 
			
		||||
        {
 | 
			
		||||
            setCurrentPage (b->getName());
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
PreferencesPanel::PreferencesPanel()
 | 
			
		||||
    : buttonSize (70)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PreferencesPanel::~PreferencesPanel()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int PreferencesPanel::getButtonSize() const noexcept
 | 
			
		||||
{
 | 
			
		||||
    return buttonSize;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::setButtonSize (int newSize)
 | 
			
		||||
{
 | 
			
		||||
    buttonSize = newSize;
 | 
			
		||||
    resized();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void PreferencesPanel::addSettingsPage (const String& title,
 | 
			
		||||
                                        const Drawable* icon,
 | 
			
		||||
                                        const Drawable* overIcon,
 | 
			
		||||
                                        const Drawable* downIcon)
 | 
			
		||||
{
 | 
			
		||||
    auto* button = new DrawableButton (title, DrawableButton::ImageAboveTextLabel);
 | 
			
		||||
    buttons.add (button);
 | 
			
		||||
 | 
			
		||||
    button->setImages (icon, overIcon, downIcon);
 | 
			
		||||
    button->setRadioGroupId (1);
 | 
			
		||||
    button->onClick = [this] { clickedPage(); };
 | 
			
		||||
    button->setClickingTogglesState (true);
 | 
			
		||||
    button->setWantsKeyboardFocus (false);
 | 
			
		||||
    addAndMakeVisible (button);
 | 
			
		||||
 | 
			
		||||
    resized();
 | 
			
		||||
 | 
			
		||||
    if (currentPage == nullptr)
 | 
			
		||||
        setCurrentPage (title);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::addSettingsPage (const String& title, const void* imageData, int imageDataSize)
 | 
			
		||||
{
 | 
			
		||||
    DrawableImage icon, iconOver, iconDown;
 | 
			
		||||
    icon.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
 | 
			
		||||
 | 
			
		||||
    iconOver.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
 | 
			
		||||
    iconOver.setOverlayColour (Colours::black.withAlpha (0.12f));
 | 
			
		||||
 | 
			
		||||
    iconDown.setImage (ImageCache::getFromMemory (imageData, imageDataSize));
 | 
			
		||||
    iconDown.setOverlayColour (Colours::black.withAlpha (0.25f));
 | 
			
		||||
 | 
			
		||||
    addSettingsPage (title, &icon, &iconOver, &iconDown);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void PreferencesPanel::showInDialogBox (const String& dialogTitle, int dialogWidth, int dialogHeight, Colour backgroundColour)
 | 
			
		||||
{
 | 
			
		||||
    setSize (dialogWidth, dialogHeight);
 | 
			
		||||
 | 
			
		||||
    DialogWindow::LaunchOptions o;
 | 
			
		||||
    o.content.setNonOwned (this);
 | 
			
		||||
    o.dialogTitle                   = dialogTitle;
 | 
			
		||||
    o.dialogBackgroundColour        = backgroundColour;
 | 
			
		||||
    o.escapeKeyTriggersCloseButton  = false;
 | 
			
		||||
    o.useNativeTitleBar             = false;
 | 
			
		||||
    o.resizable                     = false;
 | 
			
		||||
 | 
			
		||||
    o.launchAsync();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void PreferencesPanel::resized()
 | 
			
		||||
{
 | 
			
		||||
    for (int i = 0; i < buttons.size(); ++i)
 | 
			
		||||
        buttons.getUnchecked(i)->setBounds (i * buttonSize, 0, buttonSize, buttonSize);
 | 
			
		||||
 | 
			
		||||
    if (currentPage != nullptr)
 | 
			
		||||
        currentPage->setBounds (getLocalBounds().withTop (buttonSize + 5));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    g.setColour (Colours::grey);
 | 
			
		||||
    g.fillRect (0, buttonSize + 2, getWidth(), 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::setCurrentPage (const String& pageName)
 | 
			
		||||
{
 | 
			
		||||
    if (currentPageName != pageName)
 | 
			
		||||
    {
 | 
			
		||||
        currentPageName = pageName;
 | 
			
		||||
 | 
			
		||||
        currentPage.reset();
 | 
			
		||||
        currentPage.reset (createComponentForPage (pageName));
 | 
			
		||||
 | 
			
		||||
        if (currentPage != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            addAndMakeVisible (currentPage.get());
 | 
			
		||||
            currentPage->toBack();
 | 
			
		||||
            resized();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for (auto* b : buttons)
 | 
			
		||||
        {
 | 
			
		||||
            if (b->getName() == pageName)
 | 
			
		||||
            {
 | 
			
		||||
                b->setToggleState (true, dontSendNotification);
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PreferencesPanel::clickedPage()
 | 
			
		||||
{
 | 
			
		||||
    for (auto* b : buttons)
 | 
			
		||||
    {
 | 
			
		||||
        if (b->getToggleState())
 | 
			
		||||
        {
 | 
			
		||||
            setCurrentPage (b->getName());
 | 
			
		||||
            break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,147 +1,147 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A component with a set of buttons at the top for changing between pages of
 | 
			
		||||
    preferences.
 | 
			
		||||
 | 
			
		||||
    This is just a handy way of writing a Mac-style preferences panel where you
 | 
			
		||||
    have a row of buttons along the top for the different preference categories,
 | 
			
		||||
    each button having an icon above its name. Clicking these will show an
 | 
			
		||||
    appropriate prefs page below it.
 | 
			
		||||
 | 
			
		||||
    You can either put one of these inside your own component, or just use the
 | 
			
		||||
    showInDialogBox() method to show it in a window and run it modally.
 | 
			
		||||
 | 
			
		||||
    To use it, just add a set of named pages with the addSettingsPage() method,
 | 
			
		||||
    and implement the createComponentForPage() method to create suitable components
 | 
			
		||||
    for each of these pages.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  PreferencesPanel  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an empty panel.
 | 
			
		||||
 | 
			
		||||
        Use addSettingsPage() to add some pages to it in your constructor.
 | 
			
		||||
    */
 | 
			
		||||
    PreferencesPanel();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~PreferencesPanel() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a page using a set of drawables to define the page's icon.
 | 
			
		||||
 | 
			
		||||
        Note that the other version of this method is much easier if you're using
 | 
			
		||||
        an image instead of a custom drawable.
 | 
			
		||||
 | 
			
		||||
        @param pageTitle    the name of this preferences page - you'll need to
 | 
			
		||||
                            make sure your createComponentForPage() method creates
 | 
			
		||||
                            a suitable component when it is passed this name
 | 
			
		||||
        @param normalIcon   the drawable to display in the page's button normally
 | 
			
		||||
        @param overIcon     the drawable to display in the page's button when the mouse is over
 | 
			
		||||
        @param downIcon     the drawable to display in the page's button when the button is down
 | 
			
		||||
        @see DrawableButton
 | 
			
		||||
    */
 | 
			
		||||
    void addSettingsPage (const String& pageTitle,
 | 
			
		||||
                          const Drawable* normalIcon,
 | 
			
		||||
                          const Drawable* overIcon,
 | 
			
		||||
                          const Drawable* downIcon);
 | 
			
		||||
 | 
			
		||||
    /** Creates a page using a set of drawables to define the page's icon.
 | 
			
		||||
 | 
			
		||||
        The other version of this method gives you more control over the icon, but this
 | 
			
		||||
        one is much easier if you're just loading it from a file.
 | 
			
		||||
 | 
			
		||||
        @param pageTitle        the name of this preferences page - you'll need to
 | 
			
		||||
                                make sure your createComponentForPage() method creates
 | 
			
		||||
                                a suitable component when it is passed this name
 | 
			
		||||
        @param imageData        a block of data containing an image file, e.g. a jpeg, png or gif.
 | 
			
		||||
                                For this to look good, you'll probably want to use a nice
 | 
			
		||||
                                transparent png file.
 | 
			
		||||
        @param imageDataSize    the size of the image data, in bytes
 | 
			
		||||
    */
 | 
			
		||||
    void addSettingsPage (const String& pageTitle,
 | 
			
		||||
                          const void* imageData,
 | 
			
		||||
                          int imageDataSize);
 | 
			
		||||
 | 
			
		||||
    /** Utility method to display this panel in a DialogWindow.
 | 
			
		||||
 | 
			
		||||
        Calling this will create a DialogWindow containing this panel with the
 | 
			
		||||
        given size and title, and will run it modally, returning when the user
 | 
			
		||||
        closes the dialog box.
 | 
			
		||||
    */
 | 
			
		||||
    void showInDialogBox (const String& dialogTitle,
 | 
			
		||||
                          int dialogWidth,
 | 
			
		||||
                          int dialogHeight,
 | 
			
		||||
                          Colour backgroundColour = Colours::white);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Subclasses must override this to return a component for each preferences page.
 | 
			
		||||
 | 
			
		||||
        The subclass should return a pointer to a new component representing the named
 | 
			
		||||
        page, which the panel will then display.
 | 
			
		||||
 | 
			
		||||
        The panel will delete the component later when the user goes to another page
 | 
			
		||||
        or deletes the panel.
 | 
			
		||||
    */
 | 
			
		||||
    virtual Component* createComponentForPage (const String& pageName) = 0;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the current page being displayed. */
 | 
			
		||||
    void setCurrentPage (const String& pageName);
 | 
			
		||||
 | 
			
		||||
    /** Returns the size of the buttons shown along the top. */
 | 
			
		||||
    int getButtonSize() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Changes the size of the buttons shown along the top. */
 | 
			
		||||
    void setButtonSize (int newSize);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    String currentPageName;
 | 
			
		||||
    std::unique_ptr<Component> currentPage;
 | 
			
		||||
    OwnedArray<DrawableButton> buttons;
 | 
			
		||||
    int buttonSize;
 | 
			
		||||
 | 
			
		||||
    void clickedPage();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreferencesPanel)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A component with a set of buttons at the top for changing between pages of
 | 
			
		||||
    preferences.
 | 
			
		||||
 | 
			
		||||
    This is just a handy way of writing a Mac-style preferences panel where you
 | 
			
		||||
    have a row of buttons along the top for the different preference categories,
 | 
			
		||||
    each button having an icon above its name. Clicking these will show an
 | 
			
		||||
    appropriate prefs page below it.
 | 
			
		||||
 | 
			
		||||
    You can either put one of these inside your own component, or just use the
 | 
			
		||||
    showInDialogBox() method to show it in a window and run it modally.
 | 
			
		||||
 | 
			
		||||
    To use it, just add a set of named pages with the addSettingsPage() method,
 | 
			
		||||
    and implement the createComponentForPage() method to create suitable components
 | 
			
		||||
    for each of these pages.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  PreferencesPanel  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an empty panel.
 | 
			
		||||
 | 
			
		||||
        Use addSettingsPage() to add some pages to it in your constructor.
 | 
			
		||||
    */
 | 
			
		||||
    PreferencesPanel();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~PreferencesPanel() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a page using a set of drawables to define the page's icon.
 | 
			
		||||
 | 
			
		||||
        Note that the other version of this method is much easier if you're using
 | 
			
		||||
        an image instead of a custom drawable.
 | 
			
		||||
 | 
			
		||||
        @param pageTitle    the name of this preferences page - you'll need to
 | 
			
		||||
                            make sure your createComponentForPage() method creates
 | 
			
		||||
                            a suitable component when it is passed this name
 | 
			
		||||
        @param normalIcon   the drawable to display in the page's button normally
 | 
			
		||||
        @param overIcon     the drawable to display in the page's button when the mouse is over
 | 
			
		||||
        @param downIcon     the drawable to display in the page's button when the button is down
 | 
			
		||||
        @see DrawableButton
 | 
			
		||||
    */
 | 
			
		||||
    void addSettingsPage (const String& pageTitle,
 | 
			
		||||
                          const Drawable* normalIcon,
 | 
			
		||||
                          const Drawable* overIcon,
 | 
			
		||||
                          const Drawable* downIcon);
 | 
			
		||||
 | 
			
		||||
    /** Creates a page using a set of drawables to define the page's icon.
 | 
			
		||||
 | 
			
		||||
        The other version of this method gives you more control over the icon, but this
 | 
			
		||||
        one is much easier if you're just loading it from a file.
 | 
			
		||||
 | 
			
		||||
        @param pageTitle        the name of this preferences page - you'll need to
 | 
			
		||||
                                make sure your createComponentForPage() method creates
 | 
			
		||||
                                a suitable component when it is passed this name
 | 
			
		||||
        @param imageData        a block of data containing an image file, e.g. a jpeg, png or gif.
 | 
			
		||||
                                For this to look good, you'll probably want to use a nice
 | 
			
		||||
                                transparent png file.
 | 
			
		||||
        @param imageDataSize    the size of the image data, in bytes
 | 
			
		||||
    */
 | 
			
		||||
    void addSettingsPage (const String& pageTitle,
 | 
			
		||||
                          const void* imageData,
 | 
			
		||||
                          int imageDataSize);
 | 
			
		||||
 | 
			
		||||
    /** Utility method to display this panel in a DialogWindow.
 | 
			
		||||
 | 
			
		||||
        Calling this will create a DialogWindow containing this panel with the
 | 
			
		||||
        given size and title, and will run it modally, returning when the user
 | 
			
		||||
        closes the dialog box.
 | 
			
		||||
    */
 | 
			
		||||
    void showInDialogBox (const String& dialogTitle,
 | 
			
		||||
                          int dialogWidth,
 | 
			
		||||
                          int dialogHeight,
 | 
			
		||||
                          Colour backgroundColour = Colours::white);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Subclasses must override this to return a component for each preferences page.
 | 
			
		||||
 | 
			
		||||
        The subclass should return a pointer to a new component representing the named
 | 
			
		||||
        page, which the panel will then display.
 | 
			
		||||
 | 
			
		||||
        The panel will delete the component later when the user goes to another page
 | 
			
		||||
        or deletes the panel.
 | 
			
		||||
    */
 | 
			
		||||
    virtual Component* createComponentForPage (const String& pageName) = 0;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the current page being displayed. */
 | 
			
		||||
    void setCurrentPage (const String& pageName);
 | 
			
		||||
 | 
			
		||||
    /** Returns the size of the buttons shown along the top. */
 | 
			
		||||
    int getButtonSize() const noexcept;
 | 
			
		||||
 | 
			
		||||
    /** Changes the size of the buttons shown along the top. */
 | 
			
		||||
    void setButtonSize (int newSize);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    String currentPageName;
 | 
			
		||||
    std::unique_ptr<Component> currentPage;
 | 
			
		||||
    OwnedArray<DrawableButton> buttons;
 | 
			
		||||
    int buttonSize;
 | 
			
		||||
 | 
			
		||||
    void clickedPage();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (PreferencesPanel)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,229 +1,229 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if ! JUCE_ANDROID && ! JUCE_IOS && ! JUCE_MAC
 | 
			
		||||
bool PushNotifications::Notification::isValid() const noexcept { return true; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
PushNotifications::Notification::Notification (const Notification& other)
 | 
			
		||||
    : identifier (other.identifier),
 | 
			
		||||
      title (other.title),
 | 
			
		||||
      body (other.body),
 | 
			
		||||
      subtitle (other.subtitle),
 | 
			
		||||
      groupId (other.groupId),
 | 
			
		||||
      badgeNumber (other.badgeNumber),
 | 
			
		||||
      soundToPlay (other.soundToPlay),
 | 
			
		||||
      properties (other.properties),
 | 
			
		||||
      category (other.category),
 | 
			
		||||
      triggerIntervalSec (other.triggerIntervalSec),
 | 
			
		||||
      repeat (other.repeat),
 | 
			
		||||
      icon (other.icon),
 | 
			
		||||
      channelId (other.channelId),
 | 
			
		||||
      largeIcon (other.largeIcon),
 | 
			
		||||
      tickerText (other.tickerText),
 | 
			
		||||
      actions (other.actions),
 | 
			
		||||
      progress (other.progress),
 | 
			
		||||
      person (other.person),
 | 
			
		||||
      type (other.type),
 | 
			
		||||
      priority (other.priority),
 | 
			
		||||
      lockScreenAppearance (other.lockScreenAppearance),
 | 
			
		||||
      publicVersion (other.publicVersion.get() != nullptr ? new Notification (*other.publicVersion) : nullptr),
 | 
			
		||||
      groupSortKey (other.groupSortKey),
 | 
			
		||||
      groupSummary (other.groupSummary),
 | 
			
		||||
      accentColour (other.accentColour),
 | 
			
		||||
      ledColour (other.ledColour),
 | 
			
		||||
      ledBlinkPattern (other.ledBlinkPattern),
 | 
			
		||||
      vibrationPattern (other.vibrationPattern),
 | 
			
		||||
      shouldAutoCancel (other.shouldAutoCancel),
 | 
			
		||||
      localOnly (other.localOnly),
 | 
			
		||||
      ongoing (other.ongoing),
 | 
			
		||||
      alertOnlyOnce (other.alertOnlyOnce),
 | 
			
		||||
      timestampVisibility (other.timestampVisibility),
 | 
			
		||||
      badgeIconType (other.badgeIconType),
 | 
			
		||||
      groupAlertBehaviour (other.groupAlertBehaviour),
 | 
			
		||||
      timeoutAfterMs (other.timeoutAfterMs)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (PushNotifications)
 | 
			
		||||
 | 
			
		||||
PushNotifications::PushNotifications()
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    : pimpl (new Pimpl (*this))
 | 
			
		||||
  #endif
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PushNotifications::~PushNotifications() { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
void PushNotifications::addListener (Listener* l)      { listeners.add (l); }
 | 
			
		||||
void PushNotifications::removeListener (Listener* l)   { listeners.remove (l); }
 | 
			
		||||
 | 
			
		||||
void PushNotifications::requestPermissionsWithSettings (const PushNotifications::Settings& settings)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
 | 
			
		||||
    pimpl->requestPermissionsWithSettings (settings);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (settings);
 | 
			
		||||
    listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::requestSettingsUsed()
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
 | 
			
		||||
    pimpl->requestSettingsUsed();
 | 
			
		||||
  #else
 | 
			
		||||
    listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PushNotifications::areNotificationsEnabled() const
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    return pimpl->areNotificationsEnabled();
 | 
			
		||||
  #else
 | 
			
		||||
    return false;
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::getDeliveredNotifications() const
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->getDeliveredNotifications();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::removeAllDeliveredNotifications()
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->removeAllDeliveredNotifications();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String PushNotifications::getDeviceToken() const
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    return pimpl->getDeviceToken();
 | 
			
		||||
  #else
 | 
			
		||||
    return {};
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::setupChannels (const Array<ChannelGroup>& groups, const Array<Channel>& channels)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->setupChannels (groups, channels);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (groups, channels);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::getPendingLocalNotifications() const
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->getPendingLocalNotifications();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::removeAllPendingLocalNotifications()
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->removeAllPendingLocalNotifications();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::subscribeToTopic (const String& topic)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->subscribeToTopic (topic);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (topic);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::unsubscribeFromTopic (const String& topic)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->unsubscribeFromTopic (topic);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (topic);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void PushNotifications::sendLocalNotification (const Notification& n)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->sendLocalNotification (n);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (n);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::removeDeliveredNotification (const String& identifier)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->removeDeliveredNotification (identifier);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (identifier);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::removePendingLocalNotification (const String& identifier)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->removePendingLocalNotification (identifier);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (identifier);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::sendUpstreamMessage (const String& serverSenderId,
 | 
			
		||||
                                             const String& collapseKey,
 | 
			
		||||
                                             const String& messageId,
 | 
			
		||||
                                             const String& messageType,
 | 
			
		||||
                                             int timeToLive,
 | 
			
		||||
                                             const StringPairArray& additionalData)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->sendUpstreamMessage (serverSenderId,
 | 
			
		||||
                                collapseKey,
 | 
			
		||||
                                messageId,
 | 
			
		||||
                                messageType,
 | 
			
		||||
                                timeToLive,
 | 
			
		||||
                                additionalData);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (serverSenderId, collapseKey, messageId, messageType);
 | 
			
		||||
    ignoreUnused (timeToLive, additionalData);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
#if ! JUCE_ANDROID && ! JUCE_IOS && ! JUCE_MAC
 | 
			
		||||
bool PushNotifications::Notification::isValid() const noexcept { return true; }
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
PushNotifications::Notification::Notification (const Notification& other)
 | 
			
		||||
    : identifier (other.identifier),
 | 
			
		||||
      title (other.title),
 | 
			
		||||
      body (other.body),
 | 
			
		||||
      subtitle (other.subtitle),
 | 
			
		||||
      groupId (other.groupId),
 | 
			
		||||
      badgeNumber (other.badgeNumber),
 | 
			
		||||
      soundToPlay (other.soundToPlay),
 | 
			
		||||
      properties (other.properties),
 | 
			
		||||
      category (other.category),
 | 
			
		||||
      triggerIntervalSec (other.triggerIntervalSec),
 | 
			
		||||
      repeat (other.repeat),
 | 
			
		||||
      icon (other.icon),
 | 
			
		||||
      channelId (other.channelId),
 | 
			
		||||
      largeIcon (other.largeIcon),
 | 
			
		||||
      tickerText (other.tickerText),
 | 
			
		||||
      actions (other.actions),
 | 
			
		||||
      progress (other.progress),
 | 
			
		||||
      person (other.person),
 | 
			
		||||
      type (other.type),
 | 
			
		||||
      priority (other.priority),
 | 
			
		||||
      lockScreenAppearance (other.lockScreenAppearance),
 | 
			
		||||
      publicVersion (other.publicVersion.get() != nullptr ? new Notification (*other.publicVersion) : nullptr),
 | 
			
		||||
      groupSortKey (other.groupSortKey),
 | 
			
		||||
      groupSummary (other.groupSummary),
 | 
			
		||||
      accentColour (other.accentColour),
 | 
			
		||||
      ledColour (other.ledColour),
 | 
			
		||||
      ledBlinkPattern (other.ledBlinkPattern),
 | 
			
		||||
      vibrationPattern (other.vibrationPattern),
 | 
			
		||||
      shouldAutoCancel (other.shouldAutoCancel),
 | 
			
		||||
      localOnly (other.localOnly),
 | 
			
		||||
      ongoing (other.ongoing),
 | 
			
		||||
      alertOnlyOnce (other.alertOnlyOnce),
 | 
			
		||||
      timestampVisibility (other.timestampVisibility),
 | 
			
		||||
      badgeIconType (other.badgeIconType),
 | 
			
		||||
      groupAlertBehaviour (other.groupAlertBehaviour),
 | 
			
		||||
      timeoutAfterMs (other.timeoutAfterMs)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
JUCE_IMPLEMENT_SINGLETON (PushNotifications)
 | 
			
		||||
 | 
			
		||||
PushNotifications::PushNotifications()
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    : pimpl (new Pimpl (*this))
 | 
			
		||||
  #endif
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PushNotifications::~PushNotifications() { clearSingletonInstance(); }
 | 
			
		||||
 | 
			
		||||
void PushNotifications::addListener (Listener* l)      { listeners.add (l); }
 | 
			
		||||
void PushNotifications::removeListener (Listener* l)   { listeners.remove (l); }
 | 
			
		||||
 | 
			
		||||
void PushNotifications::requestPermissionsWithSettings (const PushNotifications::Settings& settings)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
 | 
			
		||||
    pimpl->requestPermissionsWithSettings (settings);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (settings);
 | 
			
		||||
    listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::requestSettingsUsed()
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS && (JUCE_IOS || JUCE_MAC)
 | 
			
		||||
    pimpl->requestSettingsUsed();
 | 
			
		||||
  #else
 | 
			
		||||
    listeners.call ([] (Listener& l) { l.notificationSettingsReceived ({}); });
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool PushNotifications::areNotificationsEnabled() const
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    return pimpl->areNotificationsEnabled();
 | 
			
		||||
  #else
 | 
			
		||||
    return false;
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::getDeliveredNotifications() const
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->getDeliveredNotifications();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::removeAllDeliveredNotifications()
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->removeAllDeliveredNotifications();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
String PushNotifications::getDeviceToken() const
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    return pimpl->getDeviceToken();
 | 
			
		||||
  #else
 | 
			
		||||
    return {};
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::setupChannels (const Array<ChannelGroup>& groups, const Array<Channel>& channels)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->setupChannels (groups, channels);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (groups, channels);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::getPendingLocalNotifications() const
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->getPendingLocalNotifications();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::removeAllPendingLocalNotifications()
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->removeAllPendingLocalNotifications();
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::subscribeToTopic (const String& topic)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->subscribeToTopic (topic);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (topic);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::unsubscribeFromTopic (const String& topic)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->unsubscribeFromTopic (topic);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (topic);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
void PushNotifications::sendLocalNotification (const Notification& n)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->sendLocalNotification (n);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (n);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::removeDeliveredNotification (const String& identifier)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->removeDeliveredNotification (identifier);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (identifier);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::removePendingLocalNotification (const String& identifier)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->removePendingLocalNotification (identifier);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (identifier);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void PushNotifications::sendUpstreamMessage (const String& serverSenderId,
 | 
			
		||||
                                             const String& collapseKey,
 | 
			
		||||
                                             const String& messageId,
 | 
			
		||||
                                             const String& messageType,
 | 
			
		||||
                                             int timeToLive,
 | 
			
		||||
                                             const StringPairArray& additionalData)
 | 
			
		||||
{
 | 
			
		||||
  #if JUCE_PUSH_NOTIFICATIONS
 | 
			
		||||
    pimpl->sendUpstreamMessage (serverSenderId,
 | 
			
		||||
                                collapseKey,
 | 
			
		||||
                                messageId,
 | 
			
		||||
                                messageType,
 | 
			
		||||
                                timeToLive,
 | 
			
		||||
                                additionalData);
 | 
			
		||||
  #else
 | 
			
		||||
    ignoreUnused (serverSenderId, collapseKey, messageId, messageType);
 | 
			
		||||
    ignoreUnused (timeToLive, additionalData);
 | 
			
		||||
  #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,188 +1,184 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
RecentlyOpenedFilesList::RecentlyOpenedFilesList()
 | 
			
		||||
    : maxNumberOfItems (10)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
RecentlyOpenedFilesList::~RecentlyOpenedFilesList()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void RecentlyOpenedFilesList::setMaxNumberOfItems (const int newMaxNumber)
 | 
			
		||||
{
 | 
			
		||||
    maxNumberOfItems = jmax (1, newMaxNumber);
 | 
			
		||||
 | 
			
		||||
    files.removeRange (maxNumberOfItems, getNumFiles());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int RecentlyOpenedFilesList::getNumFiles() const
 | 
			
		||||
{
 | 
			
		||||
    return files.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
File RecentlyOpenedFilesList::getFile (const int index) const
 | 
			
		||||
{
 | 
			
		||||
    return File (files [index]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::clear()
 | 
			
		||||
{
 | 
			
		||||
    files.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::addFile (const File& file)
 | 
			
		||||
{
 | 
			
		||||
    removeFile (file);
 | 
			
		||||
    files.insert (0, file.getFullPathName());
 | 
			
		||||
 | 
			
		||||
    setMaxNumberOfItems (maxNumberOfItems);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::removeFile (const File& file)
 | 
			
		||||
{
 | 
			
		||||
    files.removeString (file.getFullPathName());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::removeNonExistentFiles()
 | 
			
		||||
{
 | 
			
		||||
    for (int i = getNumFiles(); --i >= 0;)
 | 
			
		||||
        if (! getFile(i).exists())
 | 
			
		||||
            files.remove (i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
int RecentlyOpenedFilesList::createPopupMenuItems (PopupMenu& menuToAddTo,
 | 
			
		||||
                                                   const int baseItemId,
 | 
			
		||||
                                                   const bool showFullPaths,
 | 
			
		||||
                                                   const bool dontAddNonExistentFiles,
 | 
			
		||||
                                                   const File** filesToAvoid)
 | 
			
		||||
{
 | 
			
		||||
    int num = 0;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < getNumFiles(); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        const File f (getFile(i));
 | 
			
		||||
 | 
			
		||||
        if ((! dontAddNonExistentFiles) || f.exists())
 | 
			
		||||
        {
 | 
			
		||||
            bool needsAvoiding = false;
 | 
			
		||||
 | 
			
		||||
            if (filesToAvoid != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                for (const File** avoid = filesToAvoid; *avoid != nullptr; ++avoid)
 | 
			
		||||
                {
 | 
			
		||||
                    if (f == **avoid)
 | 
			
		||||
                    {
 | 
			
		||||
                        needsAvoiding = true;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (! needsAvoiding)
 | 
			
		||||
            {
 | 
			
		||||
                menuToAddTo.addItem (baseItemId + i,
 | 
			
		||||
                                     showFullPaths ? f.getFullPathName()
 | 
			
		||||
                                                   : f.getFileName());
 | 
			
		||||
                ++num;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return num;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
String RecentlyOpenedFilesList::toString() const
 | 
			
		||||
{
 | 
			
		||||
    return files.joinIntoString ("\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::restoreFromString (const String& stringifiedVersion)
 | 
			
		||||
{
 | 
			
		||||
    clear();
 | 
			
		||||
    files.addLines (stringifiedVersion);
 | 
			
		||||
 | 
			
		||||
    setMaxNumberOfItems (maxNumberOfItems);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void RecentlyOpenedFilesList::registerRecentFileNatively (const File& file)
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    JUCE_AUTORELEASEPOOL
 | 
			
		||||
    {
 | 
			
		||||
        [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL: createNSURLFromFile (file)];
 | 
			
		||||
    }
 | 
			
		||||
   #else
 | 
			
		||||
    ignoreUnused (file);
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::forgetRecentFileNatively (const File& file)
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    JUCE_AUTORELEASEPOOL
 | 
			
		||||
    {
 | 
			
		||||
        // for some reason, OSX doesn't provide a method to just remove a single file
 | 
			
		||||
        // from the recent list, so we clear them all and add them back excluding
 | 
			
		||||
        // the specified file
 | 
			
		||||
 | 
			
		||||
        auto sharedDocController = [NSDocumentController sharedDocumentController];
 | 
			
		||||
        auto recentDocumentURLs  = [sharedDocController recentDocumentURLs];
 | 
			
		||||
 | 
			
		||||
        [sharedDocController clearRecentDocuments: nil];
 | 
			
		||||
 | 
			
		||||
        auto* nsFile = createNSURLFromFile (file);
 | 
			
		||||
 | 
			
		||||
        auto reverseEnumerator = [recentDocumentURLs reverseObjectEnumerator];
 | 
			
		||||
 | 
			
		||||
        for (NSURL* url : reverseEnumerator)
 | 
			
		||||
            if (! [url isEqual:nsFile])
 | 
			
		||||
                [sharedDocController noteNewRecentDocumentURL:url];
 | 
			
		||||
    }
 | 
			
		||||
   #else
 | 
			
		||||
    ignoreUnused (file);
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::clearRecentFilesNatively()
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    JUCE_AUTORELEASEPOOL
 | 
			
		||||
    {
 | 
			
		||||
        [[NSDocumentController sharedDocumentController] clearRecentDocuments: nil];
 | 
			
		||||
    }
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
RecentlyOpenedFilesList::RecentlyOpenedFilesList()
 | 
			
		||||
    : maxNumberOfItems (10)
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void RecentlyOpenedFilesList::setMaxNumberOfItems (const int newMaxNumber)
 | 
			
		||||
{
 | 
			
		||||
    maxNumberOfItems = jmax (1, newMaxNumber);
 | 
			
		||||
 | 
			
		||||
    files.removeRange (maxNumberOfItems, getNumFiles());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
int RecentlyOpenedFilesList::getNumFiles() const
 | 
			
		||||
{
 | 
			
		||||
    return files.size();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
File RecentlyOpenedFilesList::getFile (const int index) const
 | 
			
		||||
{
 | 
			
		||||
    return File (files [index]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::clear()
 | 
			
		||||
{
 | 
			
		||||
    files.clear();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::addFile (const File& file)
 | 
			
		||||
{
 | 
			
		||||
    removeFile (file);
 | 
			
		||||
    files.insert (0, file.getFullPathName());
 | 
			
		||||
 | 
			
		||||
    setMaxNumberOfItems (maxNumberOfItems);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::removeFile (const File& file)
 | 
			
		||||
{
 | 
			
		||||
    files.removeString (file.getFullPathName());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::removeNonExistentFiles()
 | 
			
		||||
{
 | 
			
		||||
    for (int i = getNumFiles(); --i >= 0;)
 | 
			
		||||
        if (! getFile(i).exists())
 | 
			
		||||
            files.remove (i);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
int RecentlyOpenedFilesList::createPopupMenuItems (PopupMenu& menuToAddTo,
 | 
			
		||||
                                                   const int baseItemId,
 | 
			
		||||
                                                   const bool showFullPaths,
 | 
			
		||||
                                                   const bool dontAddNonExistentFiles,
 | 
			
		||||
                                                   const File** filesToAvoid)
 | 
			
		||||
{
 | 
			
		||||
    int num = 0;
 | 
			
		||||
 | 
			
		||||
    for (int i = 0; i < getNumFiles(); ++i)
 | 
			
		||||
    {
 | 
			
		||||
        const File f (getFile(i));
 | 
			
		||||
 | 
			
		||||
        if ((! dontAddNonExistentFiles) || f.exists())
 | 
			
		||||
        {
 | 
			
		||||
            bool needsAvoiding = false;
 | 
			
		||||
 | 
			
		||||
            if (filesToAvoid != nullptr)
 | 
			
		||||
            {
 | 
			
		||||
                for (const File** avoid = filesToAvoid; *avoid != nullptr; ++avoid)
 | 
			
		||||
                {
 | 
			
		||||
                    if (f == **avoid)
 | 
			
		||||
                    {
 | 
			
		||||
                        needsAvoiding = true;
 | 
			
		||||
                        break;
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (! needsAvoiding)
 | 
			
		||||
            {
 | 
			
		||||
                menuToAddTo.addItem (baseItemId + i,
 | 
			
		||||
                                     showFullPaths ? f.getFullPathName()
 | 
			
		||||
                                                   : f.getFileName());
 | 
			
		||||
                ++num;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return num;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
String RecentlyOpenedFilesList::toString() const
 | 
			
		||||
{
 | 
			
		||||
    return files.joinIntoString ("\n");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::restoreFromString (const String& stringifiedVersion)
 | 
			
		||||
{
 | 
			
		||||
    clear();
 | 
			
		||||
    files.addLines (stringifiedVersion);
 | 
			
		||||
 | 
			
		||||
    setMaxNumberOfItems (maxNumberOfItems);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void RecentlyOpenedFilesList::registerRecentFileNatively (const File& file)
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    JUCE_AUTORELEASEPOOL
 | 
			
		||||
    {
 | 
			
		||||
        [[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL: createNSURLFromFile (file)];
 | 
			
		||||
    }
 | 
			
		||||
   #else
 | 
			
		||||
    ignoreUnused (file);
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::forgetRecentFileNatively (const File& file)
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    JUCE_AUTORELEASEPOOL
 | 
			
		||||
    {
 | 
			
		||||
        // for some reason, OSX doesn't provide a method to just remove a single file
 | 
			
		||||
        // from the recent list, so we clear them all and add them back excluding
 | 
			
		||||
        // the specified file
 | 
			
		||||
 | 
			
		||||
        auto sharedDocController = [NSDocumentController sharedDocumentController];
 | 
			
		||||
        auto recentDocumentURLs  = [sharedDocController recentDocumentURLs];
 | 
			
		||||
 | 
			
		||||
        [sharedDocController clearRecentDocuments: nil];
 | 
			
		||||
 | 
			
		||||
        auto* nsFile = createNSURLFromFile (file);
 | 
			
		||||
 | 
			
		||||
        auto reverseEnumerator = [recentDocumentURLs reverseObjectEnumerator];
 | 
			
		||||
 | 
			
		||||
        for (NSURL* url : reverseEnumerator)
 | 
			
		||||
            if (! [url isEqual:nsFile])
 | 
			
		||||
                [sharedDocController noteNewRecentDocumentURL:url];
 | 
			
		||||
    }
 | 
			
		||||
   #else
 | 
			
		||||
    ignoreUnused (file);
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void RecentlyOpenedFilesList::clearRecentFilesNatively()
 | 
			
		||||
{
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    JUCE_AUTORELEASEPOOL
 | 
			
		||||
    {
 | 
			
		||||
        [[NSDocumentController sharedDocumentController] clearRecentDocuments: nil];
 | 
			
		||||
    }
 | 
			
		||||
   #endif
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,180 +1,177 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Manages a set of files for use as a list of recently-opened documents.
 | 
			
		||||
 | 
			
		||||
    This is a handy class for holding your list of recently-opened documents, with
 | 
			
		||||
    helpful methods for things like purging any non-existent files, automatically
 | 
			
		||||
    adding them to a menu, and making persistence easy.
 | 
			
		||||
 | 
			
		||||
    @see File, FileBasedDocument
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  RecentlyOpenedFilesList
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an empty list.
 | 
			
		||||
    */
 | 
			
		||||
    RecentlyOpenedFilesList();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~RecentlyOpenedFilesList();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets a limit for the number of files that will be stored in the list.
 | 
			
		||||
 | 
			
		||||
        When addFile() is called, then if there is no more space in the list, the
 | 
			
		||||
        least-recently added file will be dropped.
 | 
			
		||||
 | 
			
		||||
        @see getMaxNumberOfItems
 | 
			
		||||
    */
 | 
			
		||||
    void setMaxNumberOfItems (int newMaxNumber);
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of items that this list will store.
 | 
			
		||||
        @see setMaxNumberOfItems
 | 
			
		||||
    */
 | 
			
		||||
    int getMaxNumberOfItems() const noexcept                            { return maxNumberOfItems; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of files in the list.
 | 
			
		||||
 | 
			
		||||
        The most recently added file is always at index 0.
 | 
			
		||||
    */
 | 
			
		||||
    int getNumFiles() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns one of the files in the list.
 | 
			
		||||
 | 
			
		||||
        The most recently added file is always at index 0.
 | 
			
		||||
    */
 | 
			
		||||
    File getFile (int index) const;
 | 
			
		||||
 | 
			
		||||
    /** Returns an array of all the absolute pathnames in the list.
 | 
			
		||||
    */
 | 
			
		||||
    const StringArray& getAllFilenames() const noexcept                 { return files; }
 | 
			
		||||
 | 
			
		||||
    /** Clears all the files from the list. */
 | 
			
		||||
    void clear();
 | 
			
		||||
 | 
			
		||||
    /** Adds a file to the list.
 | 
			
		||||
 | 
			
		||||
        The file will be added at index 0. If this file is already in the list, it will
 | 
			
		||||
        be moved up to index 0, but a file can only appear once in the list.
 | 
			
		||||
 | 
			
		||||
        If the list already contains the maximum number of items that is permitted, the
 | 
			
		||||
        least-recently added file will be dropped from the end.
 | 
			
		||||
    */
 | 
			
		||||
    void addFile (const File& file);
 | 
			
		||||
 | 
			
		||||
    /** Removes a file from the list. */
 | 
			
		||||
    void removeFile (const File& file);
 | 
			
		||||
 | 
			
		||||
    /** Checks each of the files in the list, removing any that don't exist.
 | 
			
		||||
 | 
			
		||||
        You might want to call this after reloading a list of files, or before putting them
 | 
			
		||||
        on a menu.
 | 
			
		||||
    */
 | 
			
		||||
    void removeNonExistentFiles();
 | 
			
		||||
 | 
			
		||||
    /** Tells the OS to add a file to the OS-managed list of recent documents for this app.
 | 
			
		||||
 | 
			
		||||
        Not all OSes maintain a list of recent files for an application, so this
 | 
			
		||||
        function will have no effect on some OSes. Currently it's just implemented for OSX.
 | 
			
		||||
    */
 | 
			
		||||
    static void registerRecentFileNatively (const File& file);
 | 
			
		||||
 | 
			
		||||
    /** Tells the OS to remove a file from the OS-managed list of recent documents for this app.
 | 
			
		||||
 | 
			
		||||
        Not all OSes maintain a list of recent files for an application, so this
 | 
			
		||||
        function will have no effect on some OSes. Currently it's just implemented for OSX.
 | 
			
		||||
    */
 | 
			
		||||
    static void forgetRecentFileNatively (const File& file);
 | 
			
		||||
 | 
			
		||||
    /** Tells the OS to clear the OS-managed list of recent documents for this app.
 | 
			
		||||
 | 
			
		||||
        Not all OSes maintain a list of recent files for an application, so this
 | 
			
		||||
        function will have no effect on some OSes. Currently it's just implemented for OSX.
 | 
			
		||||
    */
 | 
			
		||||
    static void clearRecentFilesNatively();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Adds entries to a menu, representing each of the files in the list.
 | 
			
		||||
 | 
			
		||||
        This is handy for creating an "open recent file..." menu in your app. The
 | 
			
		||||
        menu items are numbered consecutively starting with the baseItemId value,
 | 
			
		||||
        and can either be added as complete pathnames, or just the last part of the
 | 
			
		||||
        filename.
 | 
			
		||||
 | 
			
		||||
        If dontAddNonExistentFiles is true, then each file will be checked and only those
 | 
			
		||||
        that exist will be added.
 | 
			
		||||
 | 
			
		||||
        If filesToAvoid is not a nullptr, then it is considered to be a zero-terminated array
 | 
			
		||||
        of pointers to file objects. Any files that appear in this list will not be added to
 | 
			
		||||
        the menu - the reason for this is that you might have a number of files already open,
 | 
			
		||||
        so might not want these to be shown in the menu.
 | 
			
		||||
 | 
			
		||||
        It returns the number of items that were added.
 | 
			
		||||
    */
 | 
			
		||||
    int createPopupMenuItems (PopupMenu& menuToAddItemsTo,
 | 
			
		||||
                              int baseItemId,
 | 
			
		||||
                              bool showFullPaths,
 | 
			
		||||
                              bool dontAddNonExistentFiles,
 | 
			
		||||
                              const File** filesToAvoid = nullptr);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a string that encapsulates all the files in the list.
 | 
			
		||||
 | 
			
		||||
        The string that is returned can later be passed into restoreFromString() in
 | 
			
		||||
        order to recreate the list. This is handy for persisting your list, e.g. in
 | 
			
		||||
        a PropertiesFile object.
 | 
			
		||||
 | 
			
		||||
        @see restoreFromString
 | 
			
		||||
    */
 | 
			
		||||
    String toString() const;
 | 
			
		||||
 | 
			
		||||
    /** Restores the list from a previously stringified version of the list.
 | 
			
		||||
 | 
			
		||||
        Pass in a stringified version created with toString() in order to persist/restore
 | 
			
		||||
        your list.
 | 
			
		||||
 | 
			
		||||
        @see toString
 | 
			
		||||
    */
 | 
			
		||||
    void restoreFromString (const String& stringifiedVersion);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    StringArray files;
 | 
			
		||||
    int maxNumberOfItems;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (RecentlyOpenedFilesList)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Manages a set of files for use as a list of recently-opened documents.
 | 
			
		||||
 | 
			
		||||
    This is a handy class for holding your list of recently-opened documents, with
 | 
			
		||||
    helpful methods for things like purging any non-existent files, automatically
 | 
			
		||||
    adding them to a menu, and making persistence easy.
 | 
			
		||||
 | 
			
		||||
    @see File, FileBasedDocument
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  RecentlyOpenedFilesList
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates an empty list.
 | 
			
		||||
    */
 | 
			
		||||
    RecentlyOpenedFilesList();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets a limit for the number of files that will be stored in the list.
 | 
			
		||||
 | 
			
		||||
        When addFile() is called, then if there is no more space in the list, the
 | 
			
		||||
        least-recently added file will be dropped.
 | 
			
		||||
 | 
			
		||||
        @see getMaxNumberOfItems
 | 
			
		||||
    */
 | 
			
		||||
    void setMaxNumberOfItems (int newMaxNumber);
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of items that this list will store.
 | 
			
		||||
        @see setMaxNumberOfItems
 | 
			
		||||
    */
 | 
			
		||||
    int getMaxNumberOfItems() const noexcept                            { return maxNumberOfItems; }
 | 
			
		||||
 | 
			
		||||
    /** Returns the number of files in the list.
 | 
			
		||||
 | 
			
		||||
        The most recently added file is always at index 0.
 | 
			
		||||
    */
 | 
			
		||||
    int getNumFiles() const;
 | 
			
		||||
 | 
			
		||||
    /** Returns one of the files in the list.
 | 
			
		||||
 | 
			
		||||
        The most recently added file is always at index 0.
 | 
			
		||||
    */
 | 
			
		||||
    File getFile (int index) const;
 | 
			
		||||
 | 
			
		||||
    /** Returns an array of all the absolute pathnames in the list.
 | 
			
		||||
    */
 | 
			
		||||
    const StringArray& getAllFilenames() const noexcept                 { return files; }
 | 
			
		||||
 | 
			
		||||
    /** Clears all the files from the list. */
 | 
			
		||||
    void clear();
 | 
			
		||||
 | 
			
		||||
    /** Adds a file to the list.
 | 
			
		||||
 | 
			
		||||
        The file will be added at index 0. If this file is already in the list, it will
 | 
			
		||||
        be moved up to index 0, but a file can only appear once in the list.
 | 
			
		||||
 | 
			
		||||
        If the list already contains the maximum number of items that is permitted, the
 | 
			
		||||
        least-recently added file will be dropped from the end.
 | 
			
		||||
    */
 | 
			
		||||
    void addFile (const File& file);
 | 
			
		||||
 | 
			
		||||
    /** Removes a file from the list. */
 | 
			
		||||
    void removeFile (const File& file);
 | 
			
		||||
 | 
			
		||||
    /** Checks each of the files in the list, removing any that don't exist.
 | 
			
		||||
 | 
			
		||||
        You might want to call this after reloading a list of files, or before putting them
 | 
			
		||||
        on a menu.
 | 
			
		||||
    */
 | 
			
		||||
    void removeNonExistentFiles();
 | 
			
		||||
 | 
			
		||||
    /** Tells the OS to add a file to the OS-managed list of recent documents for this app.
 | 
			
		||||
 | 
			
		||||
        Not all OSes maintain a list of recent files for an application, so this
 | 
			
		||||
        function will have no effect on some OSes. Currently it's just implemented for OSX.
 | 
			
		||||
    */
 | 
			
		||||
    static void registerRecentFileNatively (const File& file);
 | 
			
		||||
 | 
			
		||||
    /** Tells the OS to remove a file from the OS-managed list of recent documents for this app.
 | 
			
		||||
 | 
			
		||||
        Not all OSes maintain a list of recent files for an application, so this
 | 
			
		||||
        function will have no effect on some OSes. Currently it's just implemented for OSX.
 | 
			
		||||
    */
 | 
			
		||||
    static void forgetRecentFileNatively (const File& file);
 | 
			
		||||
 | 
			
		||||
    /** Tells the OS to clear the OS-managed list of recent documents for this app.
 | 
			
		||||
 | 
			
		||||
        Not all OSes maintain a list of recent files for an application, so this
 | 
			
		||||
        function will have no effect on some OSes. Currently it's just implemented for OSX.
 | 
			
		||||
    */
 | 
			
		||||
    static void clearRecentFilesNatively();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Adds entries to a menu, representing each of the files in the list.
 | 
			
		||||
 | 
			
		||||
        This is handy for creating an "open recent file..." menu in your app. The
 | 
			
		||||
        menu items are numbered consecutively starting with the baseItemId value,
 | 
			
		||||
        and can either be added as complete pathnames, or just the last part of the
 | 
			
		||||
        filename.
 | 
			
		||||
 | 
			
		||||
        If dontAddNonExistentFiles is true, then each file will be checked and only those
 | 
			
		||||
        that exist will be added.
 | 
			
		||||
 | 
			
		||||
        If filesToAvoid is not a nullptr, then it is considered to be a zero-terminated array
 | 
			
		||||
        of pointers to file objects. Any files that appear in this list will not be added to
 | 
			
		||||
        the menu - the reason for this is that you might have a number of files already open,
 | 
			
		||||
        so might not want these to be shown in the menu.
 | 
			
		||||
 | 
			
		||||
        It returns the number of items that were added.
 | 
			
		||||
    */
 | 
			
		||||
    int createPopupMenuItems (PopupMenu& menuToAddItemsTo,
 | 
			
		||||
                              int baseItemId,
 | 
			
		||||
                              bool showFullPaths,
 | 
			
		||||
                              bool dontAddNonExistentFiles,
 | 
			
		||||
                              const File** filesToAvoid = nullptr);
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Returns a string that encapsulates all the files in the list.
 | 
			
		||||
 | 
			
		||||
        The string that is returned can later be passed into restoreFromString() in
 | 
			
		||||
        order to recreate the list. This is handy for persisting your list, e.g. in
 | 
			
		||||
        a PropertiesFile object.
 | 
			
		||||
 | 
			
		||||
        @see restoreFromString
 | 
			
		||||
    */
 | 
			
		||||
    String toString() const;
 | 
			
		||||
 | 
			
		||||
    /** Restores the list from a previously stringified version of the list.
 | 
			
		||||
 | 
			
		||||
        Pass in a stringified version created with toString() in order to persist/restore
 | 
			
		||||
        your list.
 | 
			
		||||
 | 
			
		||||
        @see toString
 | 
			
		||||
    */
 | 
			
		||||
    void restoreFromString (const String& stringifiedVersion);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    StringArray files;
 | 
			
		||||
    int maxNumberOfItems;
 | 
			
		||||
 | 
			
		||||
    JUCE_LEAK_DETECTOR (RecentlyOpenedFilesList)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,101 +1,101 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
SplashScreen::SplashScreen (const String& title, const Image& image, bool useDropShadow)
 | 
			
		||||
    : Component (title),
 | 
			
		||||
      backgroundImage (image),
 | 
			
		||||
      clickCountToDelete (0)
 | 
			
		||||
{
 | 
			
		||||
    // You must supply a valid image here!
 | 
			
		||||
    jassert (backgroundImage.isValid());
 | 
			
		||||
 | 
			
		||||
    setOpaque (! backgroundImage.hasAlphaChannel());
 | 
			
		||||
 | 
			
		||||
   #if JUCE_IOS || JUCE_ANDROID
 | 
			
		||||
    const bool useFullScreen = true;
 | 
			
		||||
   #else
 | 
			
		||||
    const bool useFullScreen = false;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    makeVisible (image.getWidth(), image.getHeight(), useDropShadow, useFullScreen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SplashScreen::SplashScreen (const String& title, int width, int height, bool useDropShadow)
 | 
			
		||||
    : Component (title),
 | 
			
		||||
      clickCountToDelete (0)
 | 
			
		||||
{
 | 
			
		||||
    makeVisible (width, height, useDropShadow, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SplashScreen::makeVisible (int w, int h, bool useDropShadow, bool fullscreen)
 | 
			
		||||
{
 | 
			
		||||
    clickCountToDelete = Desktop::getInstance().getMouseButtonClickCounter();
 | 
			
		||||
    creationTime = Time::getCurrentTime();
 | 
			
		||||
 | 
			
		||||
    const Rectangle<int> screenSize = Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea;
 | 
			
		||||
    const int width  = (fullscreen ? screenSize.getWidth()   : w);
 | 
			
		||||
    const int height = (fullscreen ? screenSize.getHeight()  : h);
 | 
			
		||||
 | 
			
		||||
    setAlwaysOnTop (true);
 | 
			
		||||
    setVisible (true);
 | 
			
		||||
    centreWithSize (width, height);
 | 
			
		||||
    addToDesktop (useDropShadow ? ComponentPeer::windowHasDropShadow : 0);
 | 
			
		||||
 | 
			
		||||
    if (fullscreen)
 | 
			
		||||
        getPeer()->setFullScreen (true);
 | 
			
		||||
 | 
			
		||||
    toFront (false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SplashScreen::~SplashScreen() {}
 | 
			
		||||
 | 
			
		||||
void SplashScreen::deleteAfterDelay (RelativeTime timeout, bool removeOnMouseClick)
 | 
			
		||||
{
 | 
			
		||||
    // Note that this method must be safe to call from non-GUI threads
 | 
			
		||||
    if (! removeOnMouseClick)
 | 
			
		||||
        clickCountToDelete = std::numeric_limits<int>::max();
 | 
			
		||||
 | 
			
		||||
    minimumVisibleTime = timeout;
 | 
			
		||||
 | 
			
		||||
    startTimer (50);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SplashScreen::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    g.setOpacity (1.0f);
 | 
			
		||||
    g.drawImage (backgroundImage, getLocalBounds().toFloat(), RectanglePlacement (RectanglePlacement::fillDestination));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SplashScreen::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    if (Time::getCurrentTime() > creationTime + minimumVisibleTime
 | 
			
		||||
         || Desktop::getInstance().getMouseButtonClickCounter() > clickCountToDelete)
 | 
			
		||||
        delete this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
SplashScreen::SplashScreen (const String& title, const Image& image, bool useDropShadow)
 | 
			
		||||
    : Component (title),
 | 
			
		||||
      backgroundImage (image),
 | 
			
		||||
      clickCountToDelete (0)
 | 
			
		||||
{
 | 
			
		||||
    // You must supply a valid image here!
 | 
			
		||||
    jassert (backgroundImage.isValid());
 | 
			
		||||
 | 
			
		||||
    setOpaque (! backgroundImage.hasAlphaChannel());
 | 
			
		||||
 | 
			
		||||
   #if JUCE_IOS || JUCE_ANDROID
 | 
			
		||||
    const bool useFullScreen = true;
 | 
			
		||||
   #else
 | 
			
		||||
    const bool useFullScreen = false;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
    makeVisible (image.getWidth(), image.getHeight(), useDropShadow, useFullScreen);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SplashScreen::SplashScreen (const String& title, int width, int height, bool useDropShadow)
 | 
			
		||||
    : Component (title),
 | 
			
		||||
      clickCountToDelete (0)
 | 
			
		||||
{
 | 
			
		||||
    makeVisible (width, height, useDropShadow, false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SplashScreen::makeVisible (int w, int h, bool useDropShadow, bool fullscreen)
 | 
			
		||||
{
 | 
			
		||||
    clickCountToDelete = Desktop::getInstance().getMouseButtonClickCounter();
 | 
			
		||||
    creationTime = Time::getCurrentTime();
 | 
			
		||||
 | 
			
		||||
    const Rectangle<int> screenSize = Desktop::getInstance().getDisplays().getPrimaryDisplay()->userArea;
 | 
			
		||||
    const int width  = (fullscreen ? screenSize.getWidth()   : w);
 | 
			
		||||
    const int height = (fullscreen ? screenSize.getHeight()  : h);
 | 
			
		||||
 | 
			
		||||
    setAlwaysOnTop (true);
 | 
			
		||||
    setVisible (true);
 | 
			
		||||
    centreWithSize (width, height);
 | 
			
		||||
    addToDesktop (useDropShadow ? ComponentPeer::windowHasDropShadow : 0);
 | 
			
		||||
 | 
			
		||||
    if (fullscreen)
 | 
			
		||||
        getPeer()->setFullScreen (true);
 | 
			
		||||
 | 
			
		||||
    toFront (false);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SplashScreen::~SplashScreen() {}
 | 
			
		||||
 | 
			
		||||
void SplashScreen::deleteAfterDelay (RelativeTime timeout, bool removeOnMouseClick)
 | 
			
		||||
{
 | 
			
		||||
    // Note that this method must be safe to call from non-GUI threads
 | 
			
		||||
    if (! removeOnMouseClick)
 | 
			
		||||
        clickCountToDelete = std::numeric_limits<int>::max();
 | 
			
		||||
 | 
			
		||||
    minimumVisibleTime = timeout;
 | 
			
		||||
 | 
			
		||||
    startTimer (50);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SplashScreen::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    g.setOpacity (1.0f);
 | 
			
		||||
    g.drawImage (backgroundImage, getLocalBounds().toFloat(), RectanglePlacement (RectanglePlacement::fillDestination));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SplashScreen::timerCallback()
 | 
			
		||||
{
 | 
			
		||||
    if (Time::getCurrentTime() > creationTime + minimumVisibleTime
 | 
			
		||||
         || Desktop::getInstance().getMouseButtonClickCounter() > clickCountToDelete)
 | 
			
		||||
        delete this;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,156 +1,156 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** A component for showing a splash screen while your app starts up.
 | 
			
		||||
 | 
			
		||||
    This will automatically position itself, and can be told to delete itself after
 | 
			
		||||
    being on-screen for a minimum length of time.
 | 
			
		||||
 | 
			
		||||
    To use it, just create one of these in your JUCEApplicationBase::initialise() method,
 | 
			
		||||
    and when your initialisation tasks have finished running, call its deleteAfterDelay()
 | 
			
		||||
    method to make it automatically get rid of itself.
 | 
			
		||||
 | 
			
		||||
    Note that although you could call deleteAfterDelay() as soon as you create the
 | 
			
		||||
    SplashScreen object, if you've got a long initialisation procedure, you probably
 | 
			
		||||
    don't want the splash to time-out and disappear before the initialisation has
 | 
			
		||||
    finished, which is why it makes sense to not call this method until the end of
 | 
			
		||||
    your init tasks.
 | 
			
		||||
 | 
			
		||||
    E.g. @code
 | 
			
		||||
 | 
			
		||||
    void MyApp::initialise (const String& commandLine)
 | 
			
		||||
    {
 | 
			
		||||
        splash = new SplashScreen ("Welcome to my app!",
 | 
			
		||||
                                   ImageFileFormat::loadFrom (File ("/foobar/splash.jpg")),
 | 
			
		||||
                                   true);
 | 
			
		||||
 | 
			
		||||
        // now kick off your initialisation work on some kind of thread or task, and
 | 
			
		||||
        launchBackgroundInitialisationThread();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MyApp::myInitialisationWorkFinished()
 | 
			
		||||
    {
 | 
			
		||||
        // ..assuming this is some kind of callback method that is triggered when
 | 
			
		||||
        // your background initialisation threads have finished, and it's time to open
 | 
			
		||||
        // your main window, etc..
 | 
			
		||||
 | 
			
		||||
        splash->deleteAfterDelay (RelativeTime::seconds (4), false);
 | 
			
		||||
 | 
			
		||||
        ...etc...
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  SplashScreen  : public Component,
 | 
			
		||||
                                private Timer,
 | 
			
		||||
                                private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a SplashScreen object.
 | 
			
		||||
 | 
			
		||||
        When called, the constructor will position the SplashScreen in the centre of the
 | 
			
		||||
        display, and after the time specified, it will automatically delete itself.
 | 
			
		||||
 | 
			
		||||
        Bear in mind that if you call this during your JUCEApplicationBase::initialise()
 | 
			
		||||
        method and then block the message thread by performing some kind of task, then
 | 
			
		||||
        obviously neither your splash screen nor any other GUI will appear until you
 | 
			
		||||
        allow the message thread to resume and do its work. So if you have time-consuming
 | 
			
		||||
        tasks to do during startup, use a background thread for them.
 | 
			
		||||
 | 
			
		||||
        After creating one of these (or your subclass of it), you should do your app's
 | 
			
		||||
        initialisation work, and then call the deleteAfterDelay() method to tell this object
 | 
			
		||||
        to delete itself after the user has had chance to get a good look at it.
 | 
			
		||||
 | 
			
		||||
        If you're writing a custom splash screen class, there's another protected constructor
 | 
			
		||||
        that your subclass can call, which doesn't take an image.
 | 
			
		||||
 | 
			
		||||
        @param title            the name to give the component
 | 
			
		||||
        @param backgroundImage  an image to draw on the component. The component's size
 | 
			
		||||
                                will be set to the size of this image, and if the image is
 | 
			
		||||
                                semi-transparent, the component will be made non-opaque
 | 
			
		||||
        @param useDropShadow    if true, the window will have a drop shadow
 | 
			
		||||
 | 
			
		||||
    */
 | 
			
		||||
    SplashScreen (const String& title,
 | 
			
		||||
                  const Image& backgroundImage,
 | 
			
		||||
                  bool useDropShadow);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~SplashScreen() override;
 | 
			
		||||
 | 
			
		||||
    /** Tells the component to auto-delete itself after a timeout period, or when the
 | 
			
		||||
        mouse is clicked.
 | 
			
		||||
 | 
			
		||||
        You should call this after finishing your app's initialisation work.
 | 
			
		||||
 | 
			
		||||
        Note that although you could call deleteAfterDelay() as soon as you create the
 | 
			
		||||
        SplashScreen object, if you've got a long initialisation procedure, you probably
 | 
			
		||||
        don't want the splash to time-out and disappear before your initialisation has
 | 
			
		||||
        finished, which is why it makes sense to not call this method and start the
 | 
			
		||||
        self-delete timer until you're ready.
 | 
			
		||||
 | 
			
		||||
        It's safe to call this method from a non-GUI thread as long as there's no danger that
 | 
			
		||||
        the object may be being deleted at the same time.
 | 
			
		||||
 | 
			
		||||
        @param minimumTotalTimeToDisplayFor    how long the splash screen should stay visible for.
 | 
			
		||||
                                Note that this time is measured from the construction-time of this
 | 
			
		||||
                                object, not from the time that the deleteAfterDelay() method is
 | 
			
		||||
                                called, so if you call this method after a long initialisation
 | 
			
		||||
                                period, it may be deleted without any further delay.
 | 
			
		||||
        @param removeOnMouseClick   if true, the window will be deleted as soon as the user clicks
 | 
			
		||||
                                the mouse (anywhere)
 | 
			
		||||
    */
 | 
			
		||||
    void deleteAfterDelay (RelativeTime minimumTotalTimeToDisplayFor,
 | 
			
		||||
                           bool removeOnMouseClick);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This constructor is for use by custom sub-classes that don't want to provide an image. */
 | 
			
		||||
    SplashScreen (const String& title, int width, int height, bool useDropShadow);
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Image backgroundImage;
 | 
			
		||||
    Time creationTime;
 | 
			
		||||
    RelativeTime minimumVisibleTime;
 | 
			
		||||
    int clickCountToDelete;
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
    void makeVisible (int w, int h, bool shadow, bool fullscreen);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SplashScreen)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** A component for showing a splash screen while your app starts up.
 | 
			
		||||
 | 
			
		||||
    This will automatically position itself, and can be told to delete itself after
 | 
			
		||||
    being on-screen for a minimum length of time.
 | 
			
		||||
 | 
			
		||||
    To use it, just create one of these in your JUCEApplicationBase::initialise() method,
 | 
			
		||||
    and when your initialisation tasks have finished running, call its deleteAfterDelay()
 | 
			
		||||
    method to make it automatically get rid of itself.
 | 
			
		||||
 | 
			
		||||
    Note that although you could call deleteAfterDelay() as soon as you create the
 | 
			
		||||
    SplashScreen object, if you've got a long initialisation procedure, you probably
 | 
			
		||||
    don't want the splash to time-out and disappear before the initialisation has
 | 
			
		||||
    finished, which is why it makes sense to not call this method until the end of
 | 
			
		||||
    your init tasks.
 | 
			
		||||
 | 
			
		||||
    E.g. @code
 | 
			
		||||
 | 
			
		||||
    void MyApp::initialise (const String& commandLine)
 | 
			
		||||
    {
 | 
			
		||||
        splash = new SplashScreen ("Welcome to my app!",
 | 
			
		||||
                                   ImageFileFormat::loadFrom (File ("/foobar/splash.jpg")),
 | 
			
		||||
                                   true);
 | 
			
		||||
 | 
			
		||||
        // now kick off your initialisation work on some kind of thread or task, and
 | 
			
		||||
        launchBackgroundInitialisationThread();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MyApp::myInitialisationWorkFinished()
 | 
			
		||||
    {
 | 
			
		||||
        // ..assuming this is some kind of callback method that is triggered when
 | 
			
		||||
        // your background initialisation threads have finished, and it's time to open
 | 
			
		||||
        // your main window, etc..
 | 
			
		||||
 | 
			
		||||
        splash->deleteAfterDelay (RelativeTime::seconds (4), false);
 | 
			
		||||
 | 
			
		||||
        ...etc...
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @endcode
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  SplashScreen  : public Component,
 | 
			
		||||
                                private Timer,
 | 
			
		||||
                                private DeletedAtShutdown
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a SplashScreen object.
 | 
			
		||||
 | 
			
		||||
        When called, the constructor will position the SplashScreen in the centre of the
 | 
			
		||||
        display, and after the time specified, it will automatically delete itself.
 | 
			
		||||
 | 
			
		||||
        Bear in mind that if you call this during your JUCEApplicationBase::initialise()
 | 
			
		||||
        method and then block the message thread by performing some kind of task, then
 | 
			
		||||
        obviously neither your splash screen nor any other GUI will appear until you
 | 
			
		||||
        allow the message thread to resume and do its work. So if you have time-consuming
 | 
			
		||||
        tasks to do during startup, use a background thread for them.
 | 
			
		||||
 | 
			
		||||
        After creating one of these (or your subclass of it), you should do your app's
 | 
			
		||||
        initialisation work, and then call the deleteAfterDelay() method to tell this object
 | 
			
		||||
        to delete itself after the user has had chance to get a good look at it.
 | 
			
		||||
 | 
			
		||||
        If you're writing a custom splash screen class, there's another protected constructor
 | 
			
		||||
        that your subclass can call, which doesn't take an image.
 | 
			
		||||
 | 
			
		||||
        @param title            the name to give the component
 | 
			
		||||
        @param backgroundImage  an image to draw on the component. The component's size
 | 
			
		||||
                                will be set to the size of this image, and if the image is
 | 
			
		||||
                                semi-transparent, the component will be made non-opaque
 | 
			
		||||
        @param useDropShadow    if true, the window will have a drop shadow
 | 
			
		||||
 | 
			
		||||
    */
 | 
			
		||||
    SplashScreen (const String& title,
 | 
			
		||||
                  const Image& backgroundImage,
 | 
			
		||||
                  bool useDropShadow);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~SplashScreen() override;
 | 
			
		||||
 | 
			
		||||
    /** Tells the component to auto-delete itself after a timeout period, or when the
 | 
			
		||||
        mouse is clicked.
 | 
			
		||||
 | 
			
		||||
        You should call this after finishing your app's initialisation work.
 | 
			
		||||
 | 
			
		||||
        Note that although you could call deleteAfterDelay() as soon as you create the
 | 
			
		||||
        SplashScreen object, if you've got a long initialisation procedure, you probably
 | 
			
		||||
        don't want the splash to time-out and disappear before your initialisation has
 | 
			
		||||
        finished, which is why it makes sense to not call this method and start the
 | 
			
		||||
        self-delete timer until you're ready.
 | 
			
		||||
 | 
			
		||||
        It's safe to call this method from a non-GUI thread as long as there's no danger that
 | 
			
		||||
        the object may be being deleted at the same time.
 | 
			
		||||
 | 
			
		||||
        @param minimumTotalTimeToDisplayFor    how long the splash screen should stay visible for.
 | 
			
		||||
                                Note that this time is measured from the construction-time of this
 | 
			
		||||
                                object, not from the time that the deleteAfterDelay() method is
 | 
			
		||||
                                called, so if you call this method after a long initialisation
 | 
			
		||||
                                period, it may be deleted without any further delay.
 | 
			
		||||
        @param removeOnMouseClick   if true, the window will be deleted as soon as the user clicks
 | 
			
		||||
                                the mouse (anywhere)
 | 
			
		||||
    */
 | 
			
		||||
    void deleteAfterDelay (RelativeTime minimumTotalTimeToDisplayFor,
 | 
			
		||||
                           bool removeOnMouseClick);
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This constructor is for use by custom sub-classes that don't want to provide an image. */
 | 
			
		||||
    SplashScreen (const String& title, int width, int height, bool useDropShadow);
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Image backgroundImage;
 | 
			
		||||
    Time creationTime;
 | 
			
		||||
    RelativeTime minimumVisibleTime;
 | 
			
		||||
    int clickCountToDelete;
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override;
 | 
			
		||||
    void makeVisible (int w, int h, bool shadow, bool fullscreen);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SplashScreen)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,42 +1,42 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_MAC
 | 
			
		||||
 | 
			
		||||
SystemTrayIconComponent::SystemTrayIconComponent()
 | 
			
		||||
{
 | 
			
		||||
    addToDesktop (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SystemTrayIconComponent::~SystemTrayIconComponent()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_MAC
 | 
			
		||||
 | 
			
		||||
SystemTrayIconComponent::SystemTrayIconComponent()
 | 
			
		||||
{
 | 
			
		||||
    addToDesktop (0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
SystemTrayIconComponent::~SystemTrayIconComponent()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,116 +1,116 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_MAC || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    This component sits in the taskbar tray as a small icon.
 | 
			
		||||
 | 
			
		||||
    (NB: The exact behaviour of this class will differ between OSes, and it
 | 
			
		||||
    isn't fully implemented for all OSes)
 | 
			
		||||
 | 
			
		||||
    To use it, just create one of these components, but don't attempt to make it
 | 
			
		||||
    visible, add it to a parent, or put it on the desktop.
 | 
			
		||||
 | 
			
		||||
    You can then call setIconImage() to create an icon for it in the taskbar.
 | 
			
		||||
 | 
			
		||||
    To change the icon's tooltip, you can use setIconTooltip().
 | 
			
		||||
 | 
			
		||||
    To respond to mouse-events, you can override the normal mouseDown(),
 | 
			
		||||
    mouseUp(), mouseDoubleClick() and mouseMove() methods, and although the x, y
 | 
			
		||||
    position will not be valid, you can use this to respond to clicks. Traditionally
 | 
			
		||||
    you'd use a left-click to show your application's window, and a right-click
 | 
			
		||||
    to show a pop-up menu.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  SystemTrayIconComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Constructor. */
 | 
			
		||||
    SystemTrayIconComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~SystemTrayIconComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the image shown in the taskbar.
 | 
			
		||||
 | 
			
		||||
        On Windows and Linux a full colour Image is used as an icon.
 | 
			
		||||
        On macOS a template image is used, where all non-transparent regions will be
 | 
			
		||||
        rendered in a monochrome colour selected dynamically by the operating system.
 | 
			
		||||
 | 
			
		||||
        @param colourImage     An colour image to use as an icon on Windows and Linux
 | 
			
		||||
        @param templateImage   A template image to use as an icon on macOS
 | 
			
		||||
    */
 | 
			
		||||
    void setIconImage (const Image& colourImage, const Image& templateImage);
 | 
			
		||||
 | 
			
		||||
    /** Changes the icon's tooltip (if the current OS supports this). */
 | 
			
		||||
    void setIconTooltip (const String& tooltip);
 | 
			
		||||
 | 
			
		||||
    /** Highlights the icon (if the current OS supports this). */
 | 
			
		||||
    void setHighlighted (bool);
 | 
			
		||||
 | 
			
		||||
    /** Shows a floating text bubble pointing to the icon (if the current OS supports this). */
 | 
			
		||||
    void showInfoBubble (const String& title, const String& content);
 | 
			
		||||
 | 
			
		||||
    /** Hides the icon's floating text bubble (if the current OS supports this). */
 | 
			
		||||
    void hideInfoBubble();
 | 
			
		||||
 | 
			
		||||
    /** Returns the raw handle to whatever kind of internal OS structure is
 | 
			
		||||
        involved in showing this icon.
 | 
			
		||||
        @see ComponentPeer::getNativeHandle()
 | 
			
		||||
    */
 | 
			
		||||
    void* getNativeHandle() const;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_LINUX || JUCE_BSD
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    /** Shows a menu attached to the OSX menu bar icon. */
 | 
			
		||||
    void showDropdownMenu (const PopupMenu& menu);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_PUBLIC_IN_DLL_BUILD (class Pimpl)
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    [[deprecated ("The new setIconImage function signature requires different images for macOS and the other platforms.")]]
 | 
			
		||||
    void setIconImage (const Image& newImage);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SystemTrayIconComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WINDOWS || JUCE_LINUX || JUCE_BSD || JUCE_MAC || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    This component sits in the taskbar tray as a small icon.
 | 
			
		||||
 | 
			
		||||
    (NB: The exact behaviour of this class will differ between OSes, and it
 | 
			
		||||
    isn't fully implemented for all OSes)
 | 
			
		||||
 | 
			
		||||
    To use it, just create one of these components, but don't attempt to make it
 | 
			
		||||
    visible, add it to a parent, or put it on the desktop.
 | 
			
		||||
 | 
			
		||||
    You can then call setIconImage() to create an icon for it in the taskbar.
 | 
			
		||||
 | 
			
		||||
    To change the icon's tooltip, you can use setIconTooltip().
 | 
			
		||||
 | 
			
		||||
    To respond to mouse-events, you can override the normal mouseDown(),
 | 
			
		||||
    mouseUp(), mouseDoubleClick() and mouseMove() methods, and although the x, y
 | 
			
		||||
    position will not be valid, you can use this to respond to clicks. Traditionally
 | 
			
		||||
    you'd use a left-click to show your application's window, and a right-click
 | 
			
		||||
    to show a pop-up menu.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  SystemTrayIconComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Constructor. */
 | 
			
		||||
    SystemTrayIconComponent();
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~SystemTrayIconComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Changes the image shown in the taskbar.
 | 
			
		||||
 | 
			
		||||
        On Windows and Linux a full colour Image is used as an icon.
 | 
			
		||||
        On macOS a template image is used, where all non-transparent regions will be
 | 
			
		||||
        rendered in a monochrome colour selected dynamically by the operating system.
 | 
			
		||||
 | 
			
		||||
        @param colourImage     An colour image to use as an icon on Windows and Linux
 | 
			
		||||
        @param templateImage   A template image to use as an icon on macOS
 | 
			
		||||
    */
 | 
			
		||||
    void setIconImage (const Image& colourImage, const Image& templateImage);
 | 
			
		||||
 | 
			
		||||
    /** Changes the icon's tooltip (if the current OS supports this). */
 | 
			
		||||
    void setIconTooltip (const String& tooltip);
 | 
			
		||||
 | 
			
		||||
    /** Highlights the icon (if the current OS supports this). */
 | 
			
		||||
    void setHighlighted (bool);
 | 
			
		||||
 | 
			
		||||
    /** Shows a floating text bubble pointing to the icon (if the current OS supports this). */
 | 
			
		||||
    void showInfoBubble (const String& title, const String& content);
 | 
			
		||||
 | 
			
		||||
    /** Hides the icon's floating text bubble (if the current OS supports this). */
 | 
			
		||||
    void hideInfoBubble();
 | 
			
		||||
 | 
			
		||||
    /** Returns the raw handle to whatever kind of internal OS structure is
 | 
			
		||||
        involved in showing this icon.
 | 
			
		||||
        @see ComponentPeer::getNativeHandle()
 | 
			
		||||
    */
 | 
			
		||||
    void* getNativeHandle() const;
 | 
			
		||||
 | 
			
		||||
   #if JUCE_LINUX || JUCE_BSD
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    /** Shows a menu attached to the OSX menu bar icon. */
 | 
			
		||||
    void showDropdownMenu (const PopupMenu& menu);
 | 
			
		||||
   #endif
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    JUCE_PUBLIC_IN_DLL_BUILD (class Pimpl)
 | 
			
		||||
    std::unique_ptr<Pimpl> pimpl;
 | 
			
		||||
 | 
			
		||||
    [[deprecated ("The new setIconImage function signature requires different images for macOS and the other platforms.")]]
 | 
			
		||||
    void setIconImage (const Image& newImage);
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (SystemTrayIconComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,287 +1,287 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WEB_BROWSER || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A component that displays an embedded web browser.
 | 
			
		||||
 | 
			
		||||
    The browser itself will be platform-dependent. On Mac and iOS it will be
 | 
			
		||||
    WebKit, on Android it will be Chrome, and on Linux it will be WebKit.
 | 
			
		||||
 | 
			
		||||
    On Windows it will be IE, but if JUCE_USE_WIN_WEBVIEW2 is enabled then using
 | 
			
		||||
    the WindowsWebView2WebBrowserComponent wrapper instead of this class directly
 | 
			
		||||
    will attempt to use the Microsoft Edge (Chromium) WebView2. See the documentation
 | 
			
		||||
    of that class for more information about its requirements.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  WebBrowserComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a WebBrowserComponent.
 | 
			
		||||
 | 
			
		||||
        Once it's created and visible, send the browser to a URL using goToURL().
 | 
			
		||||
 | 
			
		||||
        @param unloadPageWhenBrowserIsHidden  if this is true, then when the browser
 | 
			
		||||
                            component is taken offscreen, it'll clear the current page
 | 
			
		||||
                            and replace it with a blank page - this can be handy to stop
 | 
			
		||||
                            the browser using resources in the background when it's not
 | 
			
		||||
                            actually being used.
 | 
			
		||||
    */
 | 
			
		||||
    explicit WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~WebBrowserComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sends the browser to a particular URL.
 | 
			
		||||
 | 
			
		||||
        @param url      the URL to go to.
 | 
			
		||||
        @param headers  an optional set of parameters to put in the HTTP header. If
 | 
			
		||||
                        you supply this, it should be a set of string in the form
 | 
			
		||||
                        "HeaderKey: HeaderValue"
 | 
			
		||||
        @param postData an optional block of data that will be attached to the HTTP
 | 
			
		||||
                        POST request
 | 
			
		||||
    */
 | 
			
		||||
    void goToURL (const String& url,
 | 
			
		||||
                  const StringArray* headers = nullptr,
 | 
			
		||||
                  const MemoryBlock* postData = nullptr);
 | 
			
		||||
 | 
			
		||||
    /** Stops the current page loading. */
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
    /** Sends the browser back one page. */
 | 
			
		||||
    void goBack();
 | 
			
		||||
 | 
			
		||||
    /** Sends the browser forward one page. */
 | 
			
		||||
    void goForward();
 | 
			
		||||
 | 
			
		||||
    /** Refreshes the browser. */
 | 
			
		||||
    void refresh();
 | 
			
		||||
 | 
			
		||||
    /** Clear cookies that the OS has stored for the WebComponents of this application */
 | 
			
		||||
    static void clearCookies();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This callback is called when the browser is about to navigate
 | 
			
		||||
        to a new location.
 | 
			
		||||
 | 
			
		||||
        You can override this method to perform some action when the user
 | 
			
		||||
        tries to go to a particular URL. To allow the operation to carry on,
 | 
			
		||||
        return true, or return false to stop the navigation happening.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool pageAboutToLoad (const String& newURL)             { ignoreUnused (newURL); return true; }
 | 
			
		||||
 | 
			
		||||
    /** This callback happens when the browser has finished loading a page. */
 | 
			
		||||
    virtual void pageFinishedLoading (const String& url)            { ignoreUnused (url); }
 | 
			
		||||
 | 
			
		||||
    /** This callback happens when a network error was encountered while
 | 
			
		||||
        trying to load a page.
 | 
			
		||||
 | 
			
		||||
        You can override this method to show some other error page by calling
 | 
			
		||||
        goToURL. Return true to allow the browser to carry on to the internal
 | 
			
		||||
        browser error page.
 | 
			
		||||
 | 
			
		||||
        The errorInfo contains some platform dependent string describing the
 | 
			
		||||
        error.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool pageLoadHadNetworkError (const String& errorInfo)  { ignoreUnused (errorInfo); return true; }
 | 
			
		||||
 | 
			
		||||
    /** This callback occurs when a script or other activity in the browser asks for
 | 
			
		||||
        the window to be closed.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void windowCloseRequest()                               {}
 | 
			
		||||
 | 
			
		||||
    /** This callback occurs when the browser attempts to load a URL in a new window.
 | 
			
		||||
        This won't actually load the window but gives you a chance to either launch a
 | 
			
		||||
        new window yourself or just load the URL into the current window with goToURL().
 | 
			
		||||
     */
 | 
			
		||||
    virtual void newWindowAttemptingToLoad (const String& newURL)   { ignoreUnused (newURL); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentHierarchyChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void visibilityChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void focusGained (FocusChangeType) override;
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    friend class WindowsWebView2WebBrowserComponent;
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    struct ConstructWithoutPimpl
 | 
			
		||||
    {
 | 
			
		||||
        explicit ConstructWithoutPimpl (bool unloadOnHide) : unloadWhenHidden (unloadOnHide) {}
 | 
			
		||||
        const bool unloadWhenHidden;
 | 
			
		||||
    };
 | 
			
		||||
    explicit WebBrowserComponent (ConstructWithoutPimpl);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    std::unique_ptr<Pimpl> browser;
 | 
			
		||||
    bool blankPageShown = false, unloadPageWhenHidden;
 | 
			
		||||
    String lastURL;
 | 
			
		||||
    StringArray lastHeaders;
 | 
			
		||||
    MemoryBlock lastPostData;
 | 
			
		||||
 | 
			
		||||
    void reloadLastURL();
 | 
			
		||||
    void checkWindowAssociation();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebBrowserComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** Class used to create a set of preferences to pass to the WindowsWebView2WebBrowserComponent
 | 
			
		||||
    wrapper constructor to modify aspects of its behaviour and settings.
 | 
			
		||||
 | 
			
		||||
    You can chain together a series of calls to this class's methods to create a set of whatever
 | 
			
		||||
    preferences you want to specify.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  WebView2Preferences
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets a custom location for the WebView2Loader.dll that is not a part of the
 | 
			
		||||
        standard system DLL search paths.
 | 
			
		||||
    */
 | 
			
		||||
    WebView2Preferences withDLLLocation (const File& location) const   { return with (&WebView2Preferences::dllLocation, location); }
 | 
			
		||||
 | 
			
		||||
    /** Sets a non-default location for storing user data for the browser instance. */
 | 
			
		||||
    WebView2Preferences withUserDataFolder (const File& folder) const  { return with (&WebView2Preferences::userDataFolder, folder); }
 | 
			
		||||
 | 
			
		||||
    /** If this is set, the status bar usually displayed in the lower-left of the webview
 | 
			
		||||
        will be disabled.
 | 
			
		||||
    */
 | 
			
		||||
    WebView2Preferences withStatusBarDisabled() const                  { return with (&WebView2Preferences::disableStatusBar, true); }
 | 
			
		||||
 | 
			
		||||
    /** If this is set, a blank page will be displayed on error instead of the default
 | 
			
		||||
        built-in error page.
 | 
			
		||||
    */
 | 
			
		||||
    WebView2Preferences withBuiltInErrorPageDisabled() const           { return with (&WebView2Preferences::disableBuiltInErrorPage, true); }
 | 
			
		||||
 | 
			
		||||
    /** Sets the background colour that WebView2 renders underneath all web content.
 | 
			
		||||
 | 
			
		||||
        This colour must either be fully opaque or transparent. On Windows 7 this
 | 
			
		||||
        colour must be opaque.
 | 
			
		||||
    */
 | 
			
		||||
    WebView2Preferences withBackgroundColour (const Colour& colour) const
 | 
			
		||||
    {
 | 
			
		||||
        // the background colour must be either fully opaque or transparent!
 | 
			
		||||
        jassert (colour.isOpaque() || colour.isTransparent());
 | 
			
		||||
 | 
			
		||||
        return with (&WebView2Preferences::backgroundColour, colour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    File getDLLLocation() const                          { return dllLocation; }
 | 
			
		||||
    File getUserDataFolder() const                       { return userDataFolder; }
 | 
			
		||||
    bool getIsStatusBarDisabled() const noexcept         { return disableStatusBar; }
 | 
			
		||||
    bool getIsBuiltInErrorPageDisabled() const noexcept  { return disableBuiltInErrorPage; }
 | 
			
		||||
    Colour getBackgroundColour() const                   { return backgroundColour; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename Member, typename Item>
 | 
			
		||||
    WebView2Preferences with (Member&& member, Item&& item) const
 | 
			
		||||
    {
 | 
			
		||||
        auto options = *this;
 | 
			
		||||
        options.*member = std::forward<Item> (item);
 | 
			
		||||
 | 
			
		||||
        return options;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    File dllLocation, userDataFolder;
 | 
			
		||||
    bool disableStatusBar = false, disableBuiltInErrorPage = false;
 | 
			
		||||
    Colour backgroundColour = Colours::white;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
    If you have enabled the JUCE_USE_WIN_WEBVIEW2 flag then this wrapper will attempt to
 | 
			
		||||
    use the Microsoft Edge (Chromium) WebView2 control instead of IE on Windows. It will
 | 
			
		||||
    behave the same as WebBrowserComponent on all other platforms and will fall back to
 | 
			
		||||
    IE on Windows if the WebView2 requirements are not met.
 | 
			
		||||
 | 
			
		||||
    This requires Microsoft Edge (minimum version 82.0.488.0) to be installed at runtime.
 | 
			
		||||
 | 
			
		||||
    Currently this also requires that WebView2Loader.dll, which can be found in the
 | 
			
		||||
    Microsoft.Web.WebView package, is installed at runtime. As this is not a standard
 | 
			
		||||
    system DLL, we can't rely on it being found via the normal system DLL search paths.
 | 
			
		||||
    Therefore in order to use WebView2 you need to ensure that WebView2Loader.dll is
 | 
			
		||||
    installed either to a location covered by the Windows DLL system search paths or
 | 
			
		||||
    to the folder specified in the WebView2Preferences.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class WindowsWebView2WebBrowserComponent  : public WebBrowserComponent
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a WebBrowserComponent that is compatible with the WebView2 control
 | 
			
		||||
        on Windows.
 | 
			
		||||
 | 
			
		||||
        @param unloadPageWhenBrowserIsHidden  if this is true, then when the browser
 | 
			
		||||
                               component is taken offscreen, it'll clear the current page
 | 
			
		||||
                               and replace it with a blank page - this can be handy to stop
 | 
			
		||||
                               the browser using resources in the background when it's not
 | 
			
		||||
                               actually being used.
 | 
			
		||||
        @param preferences     a set of preferences used to control aspects of the webview's
 | 
			
		||||
                               behaviour.
 | 
			
		||||
 | 
			
		||||
        @see WebView2Preferences
 | 
			
		||||
    */
 | 
			
		||||
    WindowsWebView2WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true,
 | 
			
		||||
                                        const WebView2Preferences& preferences = {});
 | 
			
		||||
 | 
			
		||||
    // This constructor has been deprecated. Use the new constructor that takes a
 | 
			
		||||
    // WebView2Preferences instead.
 | 
			
		||||
    explicit WindowsWebView2WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true,
 | 
			
		||||
                                                 const File& dllLocation = {},
 | 
			
		||||
                                                 const File& userDataFolder = {})
 | 
			
		||||
                                  : WindowsWebView2WebBrowserComponent (unloadPageWhenBrowserIsHidden,
 | 
			
		||||
                                                                        WebView2Preferences().withDLLLocation (dllLocation)
 | 
			
		||||
                                                                                             .withUserDataFolder (userDataFolder))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_WEB_BROWSER || DOXYGEN
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    A component that displays an embedded web browser.
 | 
			
		||||
 | 
			
		||||
    The browser itself will be platform-dependent. On Mac and iOS it will be
 | 
			
		||||
    WebKit, on Android it will be Chrome, and on Linux it will be WebKit.
 | 
			
		||||
 | 
			
		||||
    On Windows it will be IE, but if JUCE_USE_WIN_WEBVIEW2 is enabled then using
 | 
			
		||||
    the WindowsWebView2WebBrowserComponent wrapper instead of this class directly
 | 
			
		||||
    will attempt to use the Microsoft Edge (Chromium) WebView2. See the documentation
 | 
			
		||||
    of that class for more information about its requirements.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  WebBrowserComponent  : public Component
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a WebBrowserComponent.
 | 
			
		||||
 | 
			
		||||
        Once it's created and visible, send the browser to a URL using goToURL().
 | 
			
		||||
 | 
			
		||||
        @param unloadPageWhenBrowserIsHidden  if this is true, then when the browser
 | 
			
		||||
                            component is taken offscreen, it'll clear the current page
 | 
			
		||||
                            and replace it with a blank page - this can be handy to stop
 | 
			
		||||
                            the browser using resources in the background when it's not
 | 
			
		||||
                            actually being used.
 | 
			
		||||
    */
 | 
			
		||||
    explicit WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true);
 | 
			
		||||
 | 
			
		||||
    /** Destructor. */
 | 
			
		||||
    ~WebBrowserComponent() override;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sends the browser to a particular URL.
 | 
			
		||||
 | 
			
		||||
        @param url      the URL to go to.
 | 
			
		||||
        @param headers  an optional set of parameters to put in the HTTP header. If
 | 
			
		||||
                        you supply this, it should be a set of string in the form
 | 
			
		||||
                        "HeaderKey: HeaderValue"
 | 
			
		||||
        @param postData an optional block of data that will be attached to the HTTP
 | 
			
		||||
                        POST request
 | 
			
		||||
    */
 | 
			
		||||
    void goToURL (const String& url,
 | 
			
		||||
                  const StringArray* headers = nullptr,
 | 
			
		||||
                  const MemoryBlock* postData = nullptr);
 | 
			
		||||
 | 
			
		||||
    /** Stops the current page loading. */
 | 
			
		||||
    void stop();
 | 
			
		||||
 | 
			
		||||
    /** Sends the browser back one page. */
 | 
			
		||||
    void goBack();
 | 
			
		||||
 | 
			
		||||
    /** Sends the browser forward one page. */
 | 
			
		||||
    void goForward();
 | 
			
		||||
 | 
			
		||||
    /** Refreshes the browser. */
 | 
			
		||||
    void refresh();
 | 
			
		||||
 | 
			
		||||
    /** Clear cookies that the OS has stored for the WebComponents of this application */
 | 
			
		||||
    static void clearCookies();
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** This callback is called when the browser is about to navigate
 | 
			
		||||
        to a new location.
 | 
			
		||||
 | 
			
		||||
        You can override this method to perform some action when the user
 | 
			
		||||
        tries to go to a particular URL. To allow the operation to carry on,
 | 
			
		||||
        return true, or return false to stop the navigation happening.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool pageAboutToLoad (const String& newURL)             { ignoreUnused (newURL); return true; }
 | 
			
		||||
 | 
			
		||||
    /** This callback happens when the browser has finished loading a page. */
 | 
			
		||||
    virtual void pageFinishedLoading (const String& url)            { ignoreUnused (url); }
 | 
			
		||||
 | 
			
		||||
    /** This callback happens when a network error was encountered while
 | 
			
		||||
        trying to load a page.
 | 
			
		||||
 | 
			
		||||
        You can override this method to show some other error page by calling
 | 
			
		||||
        goToURL. Return true to allow the browser to carry on to the internal
 | 
			
		||||
        browser error page.
 | 
			
		||||
 | 
			
		||||
        The errorInfo contains some platform dependent string describing the
 | 
			
		||||
        error.
 | 
			
		||||
    */
 | 
			
		||||
    virtual bool pageLoadHadNetworkError (const String& errorInfo)  { ignoreUnused (errorInfo); return true; }
 | 
			
		||||
 | 
			
		||||
    /** This callback occurs when a script or other activity in the browser asks for
 | 
			
		||||
        the window to be closed.
 | 
			
		||||
    */
 | 
			
		||||
    virtual void windowCloseRequest()                               {}
 | 
			
		||||
 | 
			
		||||
    /** This callback occurs when the browser attempts to load a URL in a new window.
 | 
			
		||||
        This won't actually load the window but gives you a chance to either launch a
 | 
			
		||||
        new window yourself or just load the URL into the current window with goToURL().
 | 
			
		||||
     */
 | 
			
		||||
    virtual void newWindowAttemptingToLoad (const String& newURL)   { ignoreUnused (newURL); }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void paint (Graphics&) override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void resized() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void parentHierarchyChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void visibilityChanged() override;
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    void focusGained (FocusChangeType) override;
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    class Pimpl;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    friend class WindowsWebView2WebBrowserComponent;
 | 
			
		||||
 | 
			
		||||
    /** @internal */
 | 
			
		||||
    struct ConstructWithoutPimpl
 | 
			
		||||
    {
 | 
			
		||||
        explicit ConstructWithoutPimpl (bool unloadOnHide) : unloadWhenHidden (unloadOnHide) {}
 | 
			
		||||
        const bool unloadWhenHidden;
 | 
			
		||||
    };
 | 
			
		||||
    explicit WebBrowserComponent (ConstructWithoutPimpl);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    std::unique_ptr<Pimpl> browser;
 | 
			
		||||
    bool blankPageShown = false, unloadPageWhenHidden;
 | 
			
		||||
    String lastURL;
 | 
			
		||||
    StringArray lastHeaders;
 | 
			
		||||
    MemoryBlock lastPostData;
 | 
			
		||||
 | 
			
		||||
    void reloadLastURL();
 | 
			
		||||
    void checkWindowAssociation();
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (WebBrowserComponent)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/** Class used to create a set of preferences to pass to the WindowsWebView2WebBrowserComponent
 | 
			
		||||
    wrapper constructor to modify aspects of its behaviour and settings.
 | 
			
		||||
 | 
			
		||||
    You can chain together a series of calls to this class's methods to create a set of whatever
 | 
			
		||||
    preferences you want to specify.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class JUCE_API  WebView2Preferences
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Sets a custom location for the WebView2Loader.dll that is not a part of the
 | 
			
		||||
        standard system DLL search paths.
 | 
			
		||||
    */
 | 
			
		||||
    JUCE_NODISCARD WebView2Preferences withDLLLocation (const File& location) const   { return with (&WebView2Preferences::dllLocation, location); }
 | 
			
		||||
 | 
			
		||||
    /** Sets a non-default location for storing user data for the browser instance. */
 | 
			
		||||
    WebView2Preferences withUserDataFolder (const File& folder) const  { return with (&WebView2Preferences::userDataFolder, folder); }
 | 
			
		||||
 | 
			
		||||
    /** If this is set, the status bar usually displayed in the lower-left of the webview
 | 
			
		||||
        will be disabled.
 | 
			
		||||
    */
 | 
			
		||||
    JUCE_NODISCARD WebView2Preferences withStatusBarDisabled() const                  { return with (&WebView2Preferences::disableStatusBar, true); }
 | 
			
		||||
 | 
			
		||||
    /** If this is set, a blank page will be displayed on error instead of the default
 | 
			
		||||
        built-in error page.
 | 
			
		||||
    */
 | 
			
		||||
    JUCE_NODISCARD WebView2Preferences withBuiltInErrorPageDisabled() const           { return with (&WebView2Preferences::disableBuiltInErrorPage, true); }
 | 
			
		||||
 | 
			
		||||
    /** Sets the background colour that WebView2 renders underneath all web content.
 | 
			
		||||
 | 
			
		||||
        This colour must either be fully opaque or transparent. On Windows 7 this
 | 
			
		||||
        colour must be opaque.
 | 
			
		||||
    */
 | 
			
		||||
    JUCE_NODISCARD WebView2Preferences withBackgroundColour (const Colour& colour) const
 | 
			
		||||
    {
 | 
			
		||||
        // the background colour must be either fully opaque or transparent!
 | 
			
		||||
        jassert (colour.isOpaque() || colour.isTransparent());
 | 
			
		||||
 | 
			
		||||
        return with (&WebView2Preferences::backgroundColour, colour);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    File getDLLLocation() const                          { return dllLocation; }
 | 
			
		||||
    File getUserDataFolder() const                       { return userDataFolder; }
 | 
			
		||||
    bool getIsStatusBarDisabled() const noexcept         { return disableStatusBar; }
 | 
			
		||||
    bool getIsBuiltInErrorPageDisabled() const noexcept  { return disableBuiltInErrorPage; }
 | 
			
		||||
    Colour getBackgroundColour() const                   { return backgroundColour; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    template <typename Member, typename Item>
 | 
			
		||||
    WebView2Preferences with (Member&& member, Item&& item) const
 | 
			
		||||
    {
 | 
			
		||||
        auto options = *this;
 | 
			
		||||
        options.*member = std::forward<Item> (item);
 | 
			
		||||
 | 
			
		||||
        return options;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    File dllLocation, userDataFolder;
 | 
			
		||||
    bool disableStatusBar = false, disableBuiltInErrorPage = false;
 | 
			
		||||
    Colour backgroundColour = Colours::white;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
    If you have enabled the JUCE_USE_WIN_WEBVIEW2 flag then this wrapper will attempt to
 | 
			
		||||
    use the Microsoft Edge (Chromium) WebView2 control instead of IE on Windows. It will
 | 
			
		||||
    behave the same as WebBrowserComponent on all other platforms and will fall back to
 | 
			
		||||
    IE on Windows if the WebView2 requirements are not met.
 | 
			
		||||
 | 
			
		||||
    This requires Microsoft Edge (minimum version 82.0.488.0) to be installed at runtime.
 | 
			
		||||
 | 
			
		||||
    Currently this also requires that WebView2Loader.dll, which can be found in the
 | 
			
		||||
    Microsoft.Web.WebView package, is installed at runtime. As this is not a standard
 | 
			
		||||
    system DLL, we can't rely on it being found via the normal system DLL search paths.
 | 
			
		||||
    Therefore in order to use WebView2 you need to ensure that WebView2Loader.dll is
 | 
			
		||||
    installed either to a location covered by the Windows DLL system search paths or
 | 
			
		||||
    to the folder specified in the WebView2Preferences.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class WindowsWebView2WebBrowserComponent  : public WebBrowserComponent
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    /** Creates a WebBrowserComponent that is compatible with the WebView2 control
 | 
			
		||||
        on Windows.
 | 
			
		||||
 | 
			
		||||
        @param unloadPageWhenBrowserIsHidden  if this is true, then when the browser
 | 
			
		||||
                               component is taken offscreen, it'll clear the current page
 | 
			
		||||
                               and replace it with a blank page - this can be handy to stop
 | 
			
		||||
                               the browser using resources in the background when it's not
 | 
			
		||||
                               actually being used.
 | 
			
		||||
        @param preferences     a set of preferences used to control aspects of the webview's
 | 
			
		||||
                               behaviour.
 | 
			
		||||
 | 
			
		||||
        @see WebView2Preferences
 | 
			
		||||
    */
 | 
			
		||||
    WindowsWebView2WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true,
 | 
			
		||||
                                        const WebView2Preferences& preferences = {});
 | 
			
		||||
 | 
			
		||||
    // This constructor has been deprecated. Use the new constructor that takes a
 | 
			
		||||
    // WebView2Preferences instead.
 | 
			
		||||
    explicit WindowsWebView2WebBrowserComponent (bool unloadPageWhenBrowserIsHidden = true,
 | 
			
		||||
                                                 const File& dllLocation = {},
 | 
			
		||||
                                                 const File& userDataFolder = {})
 | 
			
		||||
                                  : WindowsWebView2WebBrowserComponent (unloadPageWhenBrowserIsHidden,
 | 
			
		||||
                                                                        WebView2Preferences().withDLLLocation (dllLocation)
 | 
			
		||||
                                                                                             .withUserDataFolder (userDataFolder))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -1,176 +1,176 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class AndroidViewComponent::Pimpl  : public ComponentMovementWatcher
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (const LocalRef<jobject>& v, Component& comp)
 | 
			
		||||
        : ComponentMovementWatcher (&comp),
 | 
			
		||||
          view (v),
 | 
			
		||||
          owner (comp)
 | 
			
		||||
    {
 | 
			
		||||
        if (owner.isShowing())
 | 
			
		||||
            componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl() override
 | 
			
		||||
    {
 | 
			
		||||
        removeFromParent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
 | 
			
		||||
    {
 | 
			
		||||
        auto* topComp = owner.getTopLevelComponent();
 | 
			
		||||
 | 
			
		||||
        if (topComp->getPeer() != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto pos = topComp->getLocalPoint (&owner, Point<int>());
 | 
			
		||||
 | 
			
		||||
            Rectangle<int> r (pos.x, pos.y, owner.getWidth(), owner.getHeight());
 | 
			
		||||
            r *= Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale;
 | 
			
		||||
 | 
			
		||||
            getEnv()->CallVoidMethod (view, AndroidView.layout, r.getX(), r.getY(),
 | 
			
		||||
                                      r.getRight(), r.getBottom());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentPeerChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        auto* peer = owner.getPeer();
 | 
			
		||||
 | 
			
		||||
        if (currentPeer != peer)
 | 
			
		||||
        {
 | 
			
		||||
            removeFromParent();
 | 
			
		||||
            currentPeer = peer;
 | 
			
		||||
 | 
			
		||||
            addToParent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        enum
 | 
			
		||||
        {
 | 
			
		||||
            VISIBLE   = 0,
 | 
			
		||||
            INVISIBLE = 4
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        getEnv()->CallVoidMethod (view, AndroidView.setVisibility, owner.isShowing() ? VISIBLE : INVISIBLE);
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
    void componentVisibilityChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentBroughtToFront (Component& comp) override
 | 
			
		||||
    {
 | 
			
		||||
        ComponentMovementWatcher::componentBroughtToFront (comp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rectangle<int> getViewBounds() const
 | 
			
		||||
    {
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
        int width  = env->CallIntMethod (view, AndroidView.getWidth);
 | 
			
		||||
        int height = env->CallIntMethod (view, AndroidView.getHeight);
 | 
			
		||||
 | 
			
		||||
        return Rectangle<int> (width, height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GlobalRef view;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void addToParent()
 | 
			
		||||
    {
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            jobject peerView = (jobject) currentPeer->getNativeHandle();
 | 
			
		||||
 | 
			
		||||
            // NB: Assuming a parent is always of ViewGroup type
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
            env->CallVoidMethod (peerView, AndroidViewGroup.addView, view.get());
 | 
			
		||||
            componentMovedOrResized (false, false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void removeFromParent()
 | 
			
		||||
    {
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
        auto parentView = env->CallObjectMethod (view, AndroidView.getParent);
 | 
			
		||||
 | 
			
		||||
        if (parentView != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            // Assuming a parent is always of ViewGroup type
 | 
			
		||||
            env->CallVoidMethod (parentView, AndroidViewGroup.removeView, view.get());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Component& owner;
 | 
			
		||||
    ComponentPeer* currentPeer = nullptr;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
AndroidViewComponent::AndroidViewComponent()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AndroidViewComponent::~AndroidViewComponent() {}
 | 
			
		||||
 | 
			
		||||
void AndroidViewComponent::setView (void* view)
 | 
			
		||||
{
 | 
			
		||||
    if (view != getView())
 | 
			
		||||
    {
 | 
			
		||||
        pimpl.reset();
 | 
			
		||||
 | 
			
		||||
        if (view != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            // explicitly create a new local ref here so that we don't
 | 
			
		||||
            // delete the users pointer
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
            auto localref = LocalRef<jobject>(env->NewLocalRef((jobject) view));
 | 
			
		||||
 | 
			
		||||
            pimpl.reset (new Pimpl (localref, *this));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* AndroidViewComponent::getView() const
 | 
			
		||||
{
 | 
			
		||||
    return pimpl == nullptr ? nullptr : (void*) pimpl->view;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AndroidViewComponent::resizeToFitView()
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        setBounds (pimpl->getViewBounds());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AndroidViewComponent::paint (Graphics&) {}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class AndroidViewComponent::Pimpl  : public ComponentMovementWatcher
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (const LocalRef<jobject>& v, Component& comp)
 | 
			
		||||
        : ComponentMovementWatcher (&comp),
 | 
			
		||||
          view (v),
 | 
			
		||||
          owner (comp)
 | 
			
		||||
    {
 | 
			
		||||
        if (owner.isShowing())
 | 
			
		||||
            componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl() override
 | 
			
		||||
    {
 | 
			
		||||
        removeFromParent();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
 | 
			
		||||
    {
 | 
			
		||||
        auto* topComp = owner.getTopLevelComponent();
 | 
			
		||||
 | 
			
		||||
        if (topComp->getPeer() != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto pos = topComp->getLocalPoint (&owner, Point<int>());
 | 
			
		||||
 | 
			
		||||
            Rectangle<int> r (pos.x, pos.y, owner.getWidth(), owner.getHeight());
 | 
			
		||||
            r *= Desktop::getInstance().getDisplays().getPrimaryDisplay()->scale;
 | 
			
		||||
 | 
			
		||||
            getEnv()->CallVoidMethod (view, AndroidView.layout, r.getX(), r.getY(),
 | 
			
		||||
                                      r.getRight(), r.getBottom());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentPeerChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        auto* peer = owner.getPeer();
 | 
			
		||||
 | 
			
		||||
        if (currentPeer != peer)
 | 
			
		||||
        {
 | 
			
		||||
            removeFromParent();
 | 
			
		||||
            currentPeer = peer;
 | 
			
		||||
 | 
			
		||||
            addToParent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        enum
 | 
			
		||||
        {
 | 
			
		||||
            VISIBLE   = 0,
 | 
			
		||||
            INVISIBLE = 4
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        getEnv()->CallVoidMethod (view, AndroidView.setVisibility, owner.isShowing() ? VISIBLE : INVISIBLE);
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
    void componentVisibilityChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentBroughtToFront (Component& comp) override
 | 
			
		||||
    {
 | 
			
		||||
        ComponentMovementWatcher::componentBroughtToFront (comp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rectangle<int> getViewBounds() const
 | 
			
		||||
    {
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
        int width  = env->CallIntMethod (view, AndroidView.getWidth);
 | 
			
		||||
        int height = env->CallIntMethod (view, AndroidView.getHeight);
 | 
			
		||||
 | 
			
		||||
        return Rectangle<int> (width, height);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GlobalRef view;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void addToParent()
 | 
			
		||||
    {
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            jobject peerView = (jobject) currentPeer->getNativeHandle();
 | 
			
		||||
 | 
			
		||||
            // NB: Assuming a parent is always of ViewGroup type
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
 | 
			
		||||
            env->CallVoidMethod (peerView, AndroidViewGroup.addView, view.get());
 | 
			
		||||
            componentMovedOrResized (false, false);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void removeFromParent()
 | 
			
		||||
    {
 | 
			
		||||
        auto* env = getEnv();
 | 
			
		||||
        auto parentView = env->CallObjectMethod (view, AndroidView.getParent);
 | 
			
		||||
 | 
			
		||||
        if (parentView != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            // Assuming a parent is always of ViewGroup type
 | 
			
		||||
            env->CallVoidMethod (parentView, AndroidViewGroup.removeView, view.get());
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Component& owner;
 | 
			
		||||
    ComponentPeer* currentPeer = nullptr;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
AndroidViewComponent::AndroidViewComponent()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
AndroidViewComponent::~AndroidViewComponent() {}
 | 
			
		||||
 | 
			
		||||
void AndroidViewComponent::setView (void* view)
 | 
			
		||||
{
 | 
			
		||||
    if (view != getView())
 | 
			
		||||
    {
 | 
			
		||||
        pimpl.reset();
 | 
			
		||||
 | 
			
		||||
        if (view != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            // explicitly create a new local ref here so that we don't
 | 
			
		||||
            // delete the users pointer
 | 
			
		||||
            auto* env = getEnv();
 | 
			
		||||
            auto localref = LocalRef<jobject>(env->NewLocalRef((jobject) view));
 | 
			
		||||
 | 
			
		||||
            pimpl.reset (new Pimpl (localref, *this));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* AndroidViewComponent::getView() const
 | 
			
		||||
{
 | 
			
		||||
    return pimpl == nullptr ? nullptr : (void*) pimpl->view;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AndroidViewComponent::resizeToFitView()
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        setBounds (pimpl->getViewBounds());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void AndroidViewComponent::paint (Graphics&) {}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
 
 | 
			
		||||
@@ -1,151 +1,151 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class SystemTrayIconComponent::Pimpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (const Image& im, Window windowH)  : image (im)
 | 
			
		||||
    {
 | 
			
		||||
        XWindowSystemUtilities::ScopedXLock xLock;
 | 
			
		||||
 | 
			
		||||
        auto* display = XWindowSystem::getInstance()->getDisplay();
 | 
			
		||||
 | 
			
		||||
        auto* screen = X11Symbols::getInstance()->xDefaultScreenOfDisplay (display);
 | 
			
		||||
        auto screenNumber = X11Symbols::getInstance()->xScreenNumberOfScreen (screen);
 | 
			
		||||
 | 
			
		||||
        String screenAtom ("_NET_SYSTEM_TRAY_S");
 | 
			
		||||
        screenAtom << screenNumber;
 | 
			
		||||
        Atom selectionAtom = XWindowSystemUtilities::Atoms::getCreating (display, screenAtom.toUTF8());
 | 
			
		||||
 | 
			
		||||
        X11Symbols::getInstance()->xGrabServer (display);
 | 
			
		||||
        auto managerWin = X11Symbols::getInstance()->xGetSelectionOwner (display, selectionAtom);
 | 
			
		||||
 | 
			
		||||
        if (managerWin != None)
 | 
			
		||||
            X11Symbols::getInstance()->xSelectInput (display, managerWin, StructureNotifyMask);
 | 
			
		||||
 | 
			
		||||
        X11Symbols::getInstance()->xUngrabServer (display);
 | 
			
		||||
        X11Symbols::getInstance()->xFlush (display);
 | 
			
		||||
 | 
			
		||||
        if (managerWin != None)
 | 
			
		||||
        {
 | 
			
		||||
            XEvent ev = { 0 };
 | 
			
		||||
            ev.xclient.type = ClientMessage;
 | 
			
		||||
            ev.xclient.window = managerWin;
 | 
			
		||||
            ev.xclient.message_type = XWindowSystemUtilities::Atoms::getCreating (display, "_NET_SYSTEM_TRAY_OPCODE");
 | 
			
		||||
            ev.xclient.format = 32;
 | 
			
		||||
            ev.xclient.data.l[0] = CurrentTime;
 | 
			
		||||
            ev.xclient.data.l[1] = 0 /*SYSTEM_TRAY_REQUEST_DOCK*/;
 | 
			
		||||
            ev.xclient.data.l[2] = (long) windowH;
 | 
			
		||||
            ev.xclient.data.l[3] = 0;
 | 
			
		||||
            ev.xclient.data.l[4] = 0;
 | 
			
		||||
 | 
			
		||||
            X11Symbols::getInstance()->xSendEvent (display, managerWin, False, NoEventMask, &ev);
 | 
			
		||||
            X11Symbols::getInstance()->xSync (display, False);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // For older KDE's ...
 | 
			
		||||
        long atomData = 1;
 | 
			
		||||
        Atom trayAtom = XWindowSystemUtilities::Atoms::getCreating (display, "KWM_DOCKWINDOW");
 | 
			
		||||
        X11Symbols::getInstance()->xChangeProperty (display, windowH, trayAtom, trayAtom,
 | 
			
		||||
                                                    32, PropModeReplace, (unsigned char*) &atomData, 1);
 | 
			
		||||
 | 
			
		||||
        // For more recent KDE's...
 | 
			
		||||
        trayAtom = XWindowSystemUtilities::Atoms::getCreating (display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR");
 | 
			
		||||
        X11Symbols::getInstance()->xChangeProperty (display, windowH, trayAtom, XA_WINDOW,
 | 
			
		||||
                                                    32, PropModeReplace, (unsigned char*) &windowH, 1);
 | 
			
		||||
 | 
			
		||||
        // A minimum size must be specified for GNOME and Xfce, otherwise the icon is displayed with a width of 1
 | 
			
		||||
        if (auto* hints = X11Symbols::getInstance()->xAllocSizeHints())
 | 
			
		||||
        {
 | 
			
		||||
            hints->flags = PMinSize;
 | 
			
		||||
            hints->min_width = 22;
 | 
			
		||||
            hints->min_height = 22;
 | 
			
		||||
            X11Symbols::getInstance()->xSetWMNormalHints (display, windowH, hints);
 | 
			
		||||
            X11Symbols::getInstance()->xFree (hints);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Image image;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void SystemTrayIconComponent::setIconImage (const Image& colourImage, const Image&)
 | 
			
		||||
{
 | 
			
		||||
    pimpl.reset();
 | 
			
		||||
 | 
			
		||||
    if (colourImage.isValid())
 | 
			
		||||
    {
 | 
			
		||||
        if (! isOnDesktop())
 | 
			
		||||
            addToDesktop (0);
 | 
			
		||||
 | 
			
		||||
        pimpl.reset (new Pimpl (colourImage, (Window) getWindowHandle()));
 | 
			
		||||
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
        toFront (false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    repaint();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        g.drawImage (pimpl->image, getLocalBounds().toFloat(),
 | 
			
		||||
                     RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setIconTooltip (const String& /*tooltip*/)
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setHighlighted (bool)
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/)
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::hideInfoBubble()
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SystemTrayIconComponent::getNativeHandle() const
 | 
			
		||||
{
 | 
			
		||||
    return getWindowHandle();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class SystemTrayIconComponent::Pimpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (const Image& im, Window windowH)  : image (im)
 | 
			
		||||
    {
 | 
			
		||||
        XWindowSystemUtilities::ScopedXLock xLock;
 | 
			
		||||
 | 
			
		||||
        auto* display = XWindowSystem::getInstance()->getDisplay();
 | 
			
		||||
 | 
			
		||||
        auto* screen = X11Symbols::getInstance()->xDefaultScreenOfDisplay (display);
 | 
			
		||||
        auto screenNumber = X11Symbols::getInstance()->xScreenNumberOfScreen (screen);
 | 
			
		||||
 | 
			
		||||
        String screenAtom ("_NET_SYSTEM_TRAY_S");
 | 
			
		||||
        screenAtom << screenNumber;
 | 
			
		||||
        Atom selectionAtom = XWindowSystemUtilities::Atoms::getCreating (display, screenAtom.toUTF8());
 | 
			
		||||
 | 
			
		||||
        X11Symbols::getInstance()->xGrabServer (display);
 | 
			
		||||
        auto managerWin = X11Symbols::getInstance()->xGetSelectionOwner (display, selectionAtom);
 | 
			
		||||
 | 
			
		||||
        if (managerWin != None)
 | 
			
		||||
            X11Symbols::getInstance()->xSelectInput (display, managerWin, StructureNotifyMask);
 | 
			
		||||
 | 
			
		||||
        X11Symbols::getInstance()->xUngrabServer (display);
 | 
			
		||||
        X11Symbols::getInstance()->xFlush (display);
 | 
			
		||||
 | 
			
		||||
        if (managerWin != None)
 | 
			
		||||
        {
 | 
			
		||||
            XEvent ev = { 0 };
 | 
			
		||||
            ev.xclient.type = ClientMessage;
 | 
			
		||||
            ev.xclient.window = managerWin;
 | 
			
		||||
            ev.xclient.message_type = XWindowSystemUtilities::Atoms::getCreating (display, "_NET_SYSTEM_TRAY_OPCODE");
 | 
			
		||||
            ev.xclient.format = 32;
 | 
			
		||||
            ev.xclient.data.l[0] = CurrentTime;
 | 
			
		||||
            ev.xclient.data.l[1] = 0 /*SYSTEM_TRAY_REQUEST_DOCK*/;
 | 
			
		||||
            ev.xclient.data.l[2] = (long) windowH;
 | 
			
		||||
            ev.xclient.data.l[3] = 0;
 | 
			
		||||
            ev.xclient.data.l[4] = 0;
 | 
			
		||||
 | 
			
		||||
            X11Symbols::getInstance()->xSendEvent (display, managerWin, False, NoEventMask, &ev);
 | 
			
		||||
            X11Symbols::getInstance()->xSync (display, False);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        // For older KDE's ...
 | 
			
		||||
        long atomData = 1;
 | 
			
		||||
        Atom trayAtom = XWindowSystemUtilities::Atoms::getCreating (display, "KWM_DOCKWINDOW");
 | 
			
		||||
        X11Symbols::getInstance()->xChangeProperty (display, windowH, trayAtom, trayAtom,
 | 
			
		||||
                                                    32, PropModeReplace, (unsigned char*) &atomData, 1);
 | 
			
		||||
 | 
			
		||||
        // For more recent KDE's...
 | 
			
		||||
        trayAtom = XWindowSystemUtilities::Atoms::getCreating (display, "_KDE_NET_WM_SYSTEM_TRAY_WINDOW_FOR");
 | 
			
		||||
        X11Symbols::getInstance()->xChangeProperty (display, windowH, trayAtom, XA_WINDOW,
 | 
			
		||||
                                                    32, PropModeReplace, (unsigned char*) &windowH, 1);
 | 
			
		||||
 | 
			
		||||
        // A minimum size must be specified for GNOME and Xfce, otherwise the icon is displayed with a width of 1
 | 
			
		||||
        if (auto* hints = X11Symbols::getInstance()->xAllocSizeHints())
 | 
			
		||||
        {
 | 
			
		||||
            hints->flags = PMinSize;
 | 
			
		||||
            hints->min_width = 22;
 | 
			
		||||
            hints->min_height = 22;
 | 
			
		||||
            X11Symbols::getInstance()->xSetWMNormalHints (display, windowH, hints);
 | 
			
		||||
            X11Symbols::getInstance()->xFree (hints);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Image image;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void SystemTrayIconComponent::setIconImage (const Image& colourImage, const Image&)
 | 
			
		||||
{
 | 
			
		||||
    pimpl.reset();
 | 
			
		||||
 | 
			
		||||
    if (colourImage.isValid())
 | 
			
		||||
    {
 | 
			
		||||
        if (! isOnDesktop())
 | 
			
		||||
            addToDesktop (0);
 | 
			
		||||
 | 
			
		||||
        pimpl.reset (new Pimpl (colourImage, (Window) getWindowHandle()));
 | 
			
		||||
 | 
			
		||||
        setVisible (true);
 | 
			
		||||
        toFront (false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    repaint();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        g.drawImage (pimpl->image, getLocalBounds().toFloat(),
 | 
			
		||||
                     RectanglePlacement::xLeft | RectanglePlacement::yTop | RectanglePlacement::onlyReduceInSize);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setIconTooltip (const String& /*tooltip*/)
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setHighlighted (bool)
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/)
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::hideInfoBubble()
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SystemTrayIconComponent::getNativeHandle() const
 | 
			
		||||
{
 | 
			
		||||
    return getWindowHandle();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -47,12 +47,17 @@ namespace
 | 
			
		||||
        io_iterator_t iter = 0;
 | 
			
		||||
        io_object_t iod = 0;
 | 
			
		||||
 | 
			
		||||
        const auto defaultPort =
 | 
			
		||||
               #if defined (MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_12_0
 | 
			
		||||
                kIOMainPortDefault;
 | 
			
		||||
               #else
 | 
			
		||||
                kIOMasterPortDefault;
 | 
			
		||||
               #endif
 | 
			
		||||
        const auto defaultPort = []
 | 
			
		||||
        {
 | 
			
		||||
           #if defined (MAC_OS_VERSION_12_0) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_12_0
 | 
			
		||||
            if (@available (macOS 12.0, *))
 | 
			
		||||
                return kIOMainPortDefault;
 | 
			
		||||
           #endif
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
            return kIOMasterPortDefault;
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
        }();
 | 
			
		||||
 | 
			
		||||
        if (IOServiceGetMatchingServices (defaultPort, dict, &iter) == kIOReturnSuccess
 | 
			
		||||
             && iter != 0)
 | 
			
		||||
 
 | 
			
		||||
@@ -1,346 +0,0 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
/**
 | 
			
		||||
    Creates a floating carbon window that can be used to hold a carbon UI.
 | 
			
		||||
 | 
			
		||||
    This is a handy class that's designed to be inlined where needed, e.g.
 | 
			
		||||
    in the audio plugin hosting code.
 | 
			
		||||
 | 
			
		||||
    @tags{GUI}
 | 
			
		||||
*/
 | 
			
		||||
class CarbonViewWrapperComponent  : public Component,
 | 
			
		||||
                                    public ComponentMovementWatcher,
 | 
			
		||||
                                    public Timer
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    CarbonViewWrapperComponent()
 | 
			
		||||
        : ComponentMovementWatcher (this),
 | 
			
		||||
          carbonWindow (nil),
 | 
			
		||||
          keepPluginWindowWhenHidden (false),
 | 
			
		||||
          wrapperWindow (nil),
 | 
			
		||||
          embeddedView (0),
 | 
			
		||||
          recursiveResize (false),
 | 
			
		||||
          repaintChildOnCreation (true)
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~CarbonViewWrapperComponent()
 | 
			
		||||
    {
 | 
			
		||||
        jassert (embeddedView == 0); // must call deleteWindow() in the subclass's destructor!
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual HIViewRef attachView (WindowRef windowRef, HIViewRef rootView) = 0;
 | 
			
		||||
    virtual void removeView (HIViewRef embeddedView) = 0;
 | 
			
		||||
    virtual void handleMouseDown (int, int) {}
 | 
			
		||||
    virtual void handlePaint() {}
 | 
			
		||||
 | 
			
		||||
    virtual bool getEmbeddedViewSize (int& w, int& h)
 | 
			
		||||
    {
 | 
			
		||||
        if (embeddedView == 0)
 | 
			
		||||
            return false;
 | 
			
		||||
 | 
			
		||||
        HIRect bounds;
 | 
			
		||||
        HIViewGetBounds (embeddedView, &bounds);
 | 
			
		||||
        w = jmax (1, roundToInt (bounds.size.width));
 | 
			
		||||
        h = jmax (1, roundToInt (bounds.size.height));
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void createWindow()
 | 
			
		||||
    {
 | 
			
		||||
        if (wrapperWindow == nil)
 | 
			
		||||
        {
 | 
			
		||||
            Rect r;
 | 
			
		||||
            r.left   = (short) getScreenX();
 | 
			
		||||
            r.top    = (short) getScreenY();
 | 
			
		||||
            r.right  = (short) (r.left + getWidth());
 | 
			
		||||
            r.bottom = (short) (r.top + getHeight());
 | 
			
		||||
 | 
			
		||||
            CreateNewWindow (kDocumentWindowClass,
 | 
			
		||||
                             (WindowAttributes) (kWindowStandardHandlerAttribute | kWindowCompositingAttribute
 | 
			
		||||
                                                  | kWindowNoShadowAttribute | kWindowNoTitleBarAttribute),
 | 
			
		||||
                             &r, &wrapperWindow);
 | 
			
		||||
 | 
			
		||||
            jassert (wrapperWindow != 0);
 | 
			
		||||
            if (wrapperWindow == 0)
 | 
			
		||||
                return;
 | 
			
		||||
 | 
			
		||||
            carbonWindow = [[NSWindow alloc] initWithWindowRef: wrapperWindow];
 | 
			
		||||
 | 
			
		||||
            [getOwnerWindow() addChildWindow: carbonWindow
 | 
			
		||||
                                     ordered: NSWindowAbove];
 | 
			
		||||
 | 
			
		||||
            embeddedView = attachView (wrapperWindow, HIViewGetRoot (wrapperWindow));
 | 
			
		||||
 | 
			
		||||
            // Check for the plugin creating its own floating window, and if there is one,
 | 
			
		||||
            // we need to reparent it to make it visible..
 | 
			
		||||
            if (carbonWindow.childWindows.count > 0)
 | 
			
		||||
                if (NSWindow* floatingChildWindow = [[carbonWindow childWindows] objectAtIndex: 0])
 | 
			
		||||
                    [getOwnerWindow() addChildWindow: floatingChildWindow
 | 
			
		||||
                                             ordered: NSWindowAbove];
 | 
			
		||||
 | 
			
		||||
            EventTypeSpec windowEventTypes[] =
 | 
			
		||||
            {
 | 
			
		||||
                { kEventClassWindow, kEventWindowGetClickActivation },
 | 
			
		||||
                { kEventClassWindow, kEventWindowHandleDeactivate },
 | 
			
		||||
                { kEventClassWindow, kEventWindowBoundsChanging },
 | 
			
		||||
                { kEventClassMouse,  kEventMouseDown },
 | 
			
		||||
                { kEventClassMouse,  kEventMouseMoved },
 | 
			
		||||
                { kEventClassMouse,  kEventMouseDragged },
 | 
			
		||||
                { kEventClassMouse,  kEventMouseUp },
 | 
			
		||||
                { kEventClassWindow, kEventWindowDrawContent },
 | 
			
		||||
                { kEventClassWindow, kEventWindowShown },
 | 
			
		||||
                { kEventClassWindow, kEventWindowHidden }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            EventHandlerUPP upp = NewEventHandlerUPP (carbonEventCallback);
 | 
			
		||||
            InstallWindowEventHandler (wrapperWindow, upp,
 | 
			
		||||
                                       sizeof (windowEventTypes) / sizeof (EventTypeSpec),
 | 
			
		||||
                                       windowEventTypes, this, &eventHandlerRef);
 | 
			
		||||
 | 
			
		||||
            setOurSizeToEmbeddedViewSize();
 | 
			
		||||
            setEmbeddedWindowToOurSize();
 | 
			
		||||
 | 
			
		||||
            creationTime = Time::getCurrentTime();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void deleteWindow()
 | 
			
		||||
    {
 | 
			
		||||
        removeView (embeddedView);
 | 
			
		||||
        embeddedView = 0;
 | 
			
		||||
 | 
			
		||||
        if (wrapperWindow != nil)
 | 
			
		||||
        {
 | 
			
		||||
            NSWindow* ownerWindow = getOwnerWindow();
 | 
			
		||||
 | 
			
		||||
            if ([[ownerWindow childWindows] count] > 0)
 | 
			
		||||
            {
 | 
			
		||||
                [ownerWindow removeChildWindow: carbonWindow];
 | 
			
		||||
                [carbonWindow close];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            RemoveEventHandler (eventHandlerRef);
 | 
			
		||||
            DisposeWindow (wrapperWindow);
 | 
			
		||||
            wrapperWindow = nil;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void setOurSizeToEmbeddedViewSize()
 | 
			
		||||
    {
 | 
			
		||||
        int w, h;
 | 
			
		||||
        if (getEmbeddedViewSize (w, h))
 | 
			
		||||
        {
 | 
			
		||||
            if (w != getWidth() || h != getHeight())
 | 
			
		||||
            {
 | 
			
		||||
                startTimer (50);
 | 
			
		||||
                setSize (w, h);
 | 
			
		||||
 | 
			
		||||
                if (Component* p = getParentComponent())
 | 
			
		||||
                    p->setSize (w, h);
 | 
			
		||||
            }
 | 
			
		||||
            else
 | 
			
		||||
            {
 | 
			
		||||
                startTimer (jlimit (50, 500, getTimerInterval() + 20));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            stopTimer();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setEmbeddedWindowToOurSize()
 | 
			
		||||
    {
 | 
			
		||||
        if (! recursiveResize)
 | 
			
		||||
        {
 | 
			
		||||
            recursiveResize = true;
 | 
			
		||||
 | 
			
		||||
            if (embeddedView != 0)
 | 
			
		||||
            {
 | 
			
		||||
                HIRect r;
 | 
			
		||||
                r.origin.x = 0;
 | 
			
		||||
                r.origin.y = 0;
 | 
			
		||||
                r.size.width  = (float) getWidth();
 | 
			
		||||
                r.size.height = (float) getHeight();
 | 
			
		||||
                HIViewSetFrame (embeddedView, &r);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if (wrapperWindow != nil)
 | 
			
		||||
            {
 | 
			
		||||
                jassert (getTopLevelComponent()->getDesktopScaleFactor() == 1.0f);
 | 
			
		||||
                Rectangle<int> screenBounds (getScreenBounds() * Desktop::getInstance().getGlobalScaleFactor());
 | 
			
		||||
 | 
			
		||||
                Rect wr;
 | 
			
		||||
                wr.left   = (short) screenBounds.getX();
 | 
			
		||||
                wr.top    = (short) screenBounds.getY();
 | 
			
		||||
                wr.right  = (short) screenBounds.getRight();
 | 
			
		||||
                wr.bottom = (short) screenBounds.getBottom();
 | 
			
		||||
 | 
			
		||||
                SetWindowBounds (wrapperWindow, kWindowContentRgn, &wr);
 | 
			
		||||
 | 
			
		||||
                // This group stuff is mainly a workaround for Mackie plugins like FinalMix..
 | 
			
		||||
                WindowGroupRef group = GetWindowGroup (wrapperWindow);
 | 
			
		||||
                WindowRef attachedWindow;
 | 
			
		||||
 | 
			
		||||
                if (GetIndexedWindow (group, 2, kWindowGroupContentsReturnWindows, &attachedWindow) == noErr)
 | 
			
		||||
                {
 | 
			
		||||
                    SelectWindow (attachedWindow);
 | 
			
		||||
                    ActivateWindow (attachedWindow, TRUE);
 | 
			
		||||
                    HideWindow (wrapperWindow);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                ShowWindow (wrapperWindow);
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            recursiveResize = false;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
 | 
			
		||||
    {
 | 
			
		||||
        setEmbeddedWindowToOurSize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // (overridden to intercept movements of the top-level window)
 | 
			
		||||
    void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized) override
 | 
			
		||||
    {
 | 
			
		||||
        ComponentMovementWatcher::componentMovedOrResized (component, wasMoved, wasResized);
 | 
			
		||||
 | 
			
		||||
        if (&component == getTopLevelComponent())
 | 
			
		||||
            setEmbeddedWindowToOurSize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentPeerChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        deleteWindow();
 | 
			
		||||
        createWindow();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentVisibilityChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        if (isShowing())
 | 
			
		||||
            createWindow();
 | 
			
		||||
        else if (! keepPluginWindowWhenHidden)
 | 
			
		||||
            deleteWindow();
 | 
			
		||||
 | 
			
		||||
        setEmbeddedWindowToOurSize();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void recursiveHIViewRepaint (HIViewRef view)
 | 
			
		||||
    {
 | 
			
		||||
        HIViewSetNeedsDisplay (view, true);
 | 
			
		||||
        HIViewRef child = HIViewGetFirstSubview (view);
 | 
			
		||||
 | 
			
		||||
        while (child != 0)
 | 
			
		||||
        {
 | 
			
		||||
            recursiveHIViewRepaint (child);
 | 
			
		||||
            child = HIViewGetNextView (child);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        if (isShowing())
 | 
			
		||||
        {
 | 
			
		||||
            setOurSizeToEmbeddedViewSize();
 | 
			
		||||
 | 
			
		||||
            // To avoid strange overpainting problems when the UI is first opened, we'll
 | 
			
		||||
            // repaint it a few times during the first second that it's on-screen..
 | 
			
		||||
            if (repaintChildOnCreation && (Time::getCurrentTime() - creationTime).inMilliseconds() < 1000)
 | 
			
		||||
                recursiveHIViewRepaint (HIViewGetRoot (wrapperWindow));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setRepaintsChildHIViewWhenCreated (bool b) noexcept
 | 
			
		||||
    {
 | 
			
		||||
        repaintChildOnCreation = b;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    OSStatus carbonEventHandler (EventHandlerCallRef /*nextHandlerRef*/, EventRef event)
 | 
			
		||||
    {
 | 
			
		||||
        switch (GetEventKind (event))
 | 
			
		||||
        {
 | 
			
		||||
            case kEventWindowHandleDeactivate:
 | 
			
		||||
                ActivateWindow (wrapperWindow, TRUE);
 | 
			
		||||
                return noErr;
 | 
			
		||||
 | 
			
		||||
            case kEventWindowGetClickActivation:
 | 
			
		||||
            {
 | 
			
		||||
                getTopLevelComponent()->toFront (false);
 | 
			
		||||
                [carbonWindow makeKeyAndOrderFront: nil];
 | 
			
		||||
 | 
			
		||||
                ClickActivationResult howToHandleClick = kActivateAndHandleClick;
 | 
			
		||||
 | 
			
		||||
                SetEventParameter (event, kEventParamClickActivation, typeClickActivationResult,
 | 
			
		||||
                                   sizeof (ClickActivationResult), &howToHandleClick);
 | 
			
		||||
 | 
			
		||||
                if (embeddedView != 0)
 | 
			
		||||
                    HIViewSetNeedsDisplay (embeddedView, true);
 | 
			
		||||
 | 
			
		||||
                return noErr;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return eventNotHandledErr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static pascal OSStatus carbonEventCallback (EventHandlerCallRef nextHandlerRef, EventRef event, void* userData)
 | 
			
		||||
    {
 | 
			
		||||
        return ((CarbonViewWrapperComponent*) userData)->carbonEventHandler (nextHandlerRef, event);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    NSWindow* carbonWindow;
 | 
			
		||||
    bool keepPluginWindowWhenHidden;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
    WindowRef wrapperWindow;
 | 
			
		||||
    HIViewRef embeddedView;
 | 
			
		||||
    bool recursiveResize, repaintChildOnCreation;
 | 
			
		||||
    Time creationTime;
 | 
			
		||||
 | 
			
		||||
    EventHandlerRef eventHandlerRef;
 | 
			
		||||
 | 
			
		||||
    NSWindow* getOwnerWindow() const    { return [((NSView*) getWindowHandle()) window]; }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
// Non-public utility function that hosts can use if they need to get hold of the
 | 
			
		||||
// internals of a carbon wrapper window..
 | 
			
		||||
void* getCarbonWindow (Component* possibleCarbonComponent)
 | 
			
		||||
{
 | 
			
		||||
    if (CarbonViewWrapperComponent* cv = dynamic_cast<CarbonViewWrapperComponent*> (possibleCarbonComponent))
 | 
			
		||||
        return cv->carbonWindow;
 | 
			
		||||
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -26,85 +26,6 @@
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
static const auto nsViewFrameChangedSelector = @selector (frameChanged:);
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
struct NSViewCallbackInterface
 | 
			
		||||
{
 | 
			
		||||
    virtual ~NSViewCallbackInterface() = default;
 | 
			
		||||
    virtual void frameChanged() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct NSViewFrameChangeCallbackClass   : public ObjCClass<NSObject>
 | 
			
		||||
{
 | 
			
		||||
    NSViewFrameChangeCallbackClass()
 | 
			
		||||
        : ObjCClass ("JUCE_NSViewCallback_")
 | 
			
		||||
    {
 | 
			
		||||
        addIvar<NSViewCallbackInterface*> ("target");
 | 
			
		||||
 | 
			
		||||
        addMethod (nsViewFrameChangedSelector, frameChanged, "v@:@");
 | 
			
		||||
 | 
			
		||||
        registerClass();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void setTarget (id self, NSViewCallbackInterface* c)
 | 
			
		||||
    {
 | 
			
		||||
        object_setInstanceVariable (self, "target", c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static void frameChanged (id self, SEL, NSNotification*)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* target = getIvar<NSViewCallbackInterface*> (self, "target"))
 | 
			
		||||
            target->frameChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (NSViewFrameChangeCallbackClass)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class NSViewFrameWatcher : private NSViewCallbackInterface
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    NSViewFrameWatcher (NSView* viewToWatch, std::function<void()> viewResizedIn)
 | 
			
		||||
        : viewResized (std::move (viewResizedIn)), callback (makeCallbackForView (viewToWatch))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~NSViewFrameWatcher() override
 | 
			
		||||
    {
 | 
			
		||||
        [[NSNotificationCenter defaultCenter] removeObserver: callback];
 | 
			
		||||
        [callback release];
 | 
			
		||||
        callback = nil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (NSViewFrameWatcher)
 | 
			
		||||
    JUCE_DECLARE_NON_MOVEABLE (NSViewFrameWatcher)
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    id makeCallbackForView (NSView* view)
 | 
			
		||||
    {
 | 
			
		||||
        static NSViewFrameChangeCallbackClass cls;
 | 
			
		||||
        auto* result = [cls.createInstance() init];
 | 
			
		||||
        NSViewFrameChangeCallbackClass::setTarget (result, this);
 | 
			
		||||
 | 
			
		||||
        [[NSNotificationCenter defaultCenter]  addObserver: result
 | 
			
		||||
                                                  selector: nsViewFrameChangedSelector
 | 
			
		||||
                                                      name: NSViewFrameDidChangeNotification
 | 
			
		||||
                                                    object: view];
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void frameChanged() override { viewResized(); }
 | 
			
		||||
 | 
			
		||||
    std::function<void()> viewResized;
 | 
			
		||||
    id callback;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class NSViewAttachment  : public ReferenceCountedObject,
 | 
			
		||||
                          public ComponentMovementWatcher
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										111
									
								
								deps/juce/modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								deps/juce/modules/juce_gui_extra/native/juce_mac_NSViewFrameWatcher.h
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,111 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
#if JUCE_MAC
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
const auto nsViewFrameChangedSelector = @selector (frameChanged:);
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
struct NSViewCallbackInterface
 | 
			
		||||
{
 | 
			
		||||
    virtual ~NSViewCallbackInterface() = default;
 | 
			
		||||
    virtual void frameChanged() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct NSViewFrameChangeCallbackClass   : public ObjCClass<NSObject>
 | 
			
		||||
{
 | 
			
		||||
    NSViewFrameChangeCallbackClass()
 | 
			
		||||
        : ObjCClass ("JUCE_NSViewCallback_")
 | 
			
		||||
    {
 | 
			
		||||
        addIvar<NSViewCallbackInterface*> ("target");
 | 
			
		||||
 | 
			
		||||
        addMethod (nsViewFrameChangedSelector, frameChanged);
 | 
			
		||||
 | 
			
		||||
        registerClass();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void setTarget (id self, NSViewCallbackInterface* c)
 | 
			
		||||
    {
 | 
			
		||||
        object_setInstanceVariable (self, "target", c);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static void frameChanged (id self, SEL, NSNotification*)
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* target = getIvar<NSViewCallbackInterface*> (self, "target"))
 | 
			
		||||
            target->frameChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (NSViewFrameChangeCallbackClass)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class NSViewFrameWatcher : private NSViewCallbackInterface
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    NSViewFrameWatcher (NSView* viewToWatch, std::function<void()> viewResizedIn)
 | 
			
		||||
        : viewResized (std::move (viewResizedIn)), callback (makeCallbackForView (viewToWatch))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~NSViewFrameWatcher() override
 | 
			
		||||
    {
 | 
			
		||||
        [[NSNotificationCenter defaultCenter] removeObserver: callback];
 | 
			
		||||
        [callback release];
 | 
			
		||||
        callback = nil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE (NSViewFrameWatcher)
 | 
			
		||||
    JUCE_DECLARE_NON_MOVEABLE (NSViewFrameWatcher)
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    id makeCallbackForView (NSView* view)
 | 
			
		||||
    {
 | 
			
		||||
        static NSViewFrameChangeCallbackClass cls;
 | 
			
		||||
        auto* result = [cls.createInstance() init];
 | 
			
		||||
        NSViewFrameChangeCallbackClass::setTarget (result, this);
 | 
			
		||||
 | 
			
		||||
        [[NSNotificationCenter defaultCenter]  addObserver: result
 | 
			
		||||
                                                  selector: nsViewFrameChangedSelector
 | 
			
		||||
                                                      name: NSViewFrameDidChangeNotification
 | 
			
		||||
                                                    object: view];
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void frameChanged() override { viewResized(); }
 | 
			
		||||
 | 
			
		||||
    std::function<void()> viewResized;
 | 
			
		||||
    id callback;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@@ -1,444 +1,445 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wunguarded-availability", "-Wdeprecated-declarations")
 | 
			
		||||
 | 
			
		||||
extern NSMenu* createNSMenu (const PopupMenu&, const String& name, int topLevelMenuId,
 | 
			
		||||
                             int topLevelIndex, bool addDelegate);
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct StatusItemContainer   : public Timer
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    StatusItemContainer (SystemTrayIconComponent& iconComp, const Image& im)
 | 
			
		||||
        : owner (iconComp), statusIcon (imageToNSImage (im))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void configureIcon() = 0;
 | 
			
		||||
    virtual void setHighlighted (bool shouldHighlight) = 0;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void setIconSize()
 | 
			
		||||
    {
 | 
			
		||||
        [statusIcon.get() setSize: NSMakeSize (20.0f, 20.0f)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateIcon (const Image& newImage)
 | 
			
		||||
    {
 | 
			
		||||
        statusIcon.reset (imageToNSImage (newImage));
 | 
			
		||||
        setIconSize();
 | 
			
		||||
        configureIcon();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void showMenu (const PopupMenu& menu)
 | 
			
		||||
    {
 | 
			
		||||
        if (NSMenu* m = createNSMenu (menu, "MenuBarItem", -2, -3, true))
 | 
			
		||||
        {
 | 
			
		||||
            setHighlighted (true);
 | 
			
		||||
            stopTimer();
 | 
			
		||||
 | 
			
		||||
            // There's currently no good alternative to this.
 | 
			
		||||
            [statusItem.get() popUpStatusItemMenu: m];
 | 
			
		||||
 | 
			
		||||
            startTimer (1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        stopTimer();
 | 
			
		||||
        setHighlighted (false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    SystemTrayIconComponent& owner;
 | 
			
		||||
 | 
			
		||||
    NSUniquePtr<NSStatusItem> statusItem;
 | 
			
		||||
    NSUniquePtr<NSImage> statusIcon;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StatusItemContainer)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct ButtonBasedStatusItem   : public StatusItemContainer
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ButtonBasedStatusItem (SystemTrayIconComponent& iconComp, const Image& im)
 | 
			
		||||
        : StatusItemContainer (iconComp, im)
 | 
			
		||||
    {
 | 
			
		||||
        static ButtonEventForwarderClass cls;
 | 
			
		||||
        eventForwarder.reset ([cls.createInstance() init]);
 | 
			
		||||
        ButtonEventForwarderClass::setOwner (eventForwarder.get(), this);
 | 
			
		||||
 | 
			
		||||
        setIconSize();
 | 
			
		||||
        configureIcon();
 | 
			
		||||
 | 
			
		||||
        statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]);
 | 
			
		||||
        auto button = [statusItem.get() button];
 | 
			
		||||
        button.image = statusIcon.get();
 | 
			
		||||
        button.target = eventForwarder.get();
 | 
			
		||||
        button.action = @selector (handleEvent:);
 | 
			
		||||
       #if defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_12
 | 
			
		||||
        [button sendActionOn: NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskScrollWheel];
 | 
			
		||||
       #else
 | 
			
		||||
        [button sendActionOn: NSLeftMouseDownMask | NSRightMouseDownMask | NSScrollWheelMask];
 | 
			
		||||
       #endif
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void configureIcon() override
 | 
			
		||||
    {
 | 
			
		||||
        [statusIcon.get() setTemplate: true];
 | 
			
		||||
        [statusItem.get() button].image = statusIcon.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setHighlighted (bool shouldHighlight) override
 | 
			
		||||
    {
 | 
			
		||||
        [[statusItem.get() button] setHighlighted: shouldHighlight];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void handleEvent()
 | 
			
		||||
    {
 | 
			
		||||
        auto e = [NSApp currentEvent];
 | 
			
		||||
        NSEventType type = [e type];
 | 
			
		||||
 | 
			
		||||
        const bool isLeft  = (type == NSEventTypeLeftMouseDown);
 | 
			
		||||
        const bool isRight = (type == NSEventTypeRightMouseDown);
 | 
			
		||||
 | 
			
		||||
        if (owner.isCurrentlyBlockedByAnotherModalComponent())
 | 
			
		||||
        {
 | 
			
		||||
            if (isLeft || isRight)
 | 
			
		||||
                if (auto* current = Component::getCurrentlyModalComponent())
 | 
			
		||||
                    current->inputAttemptWhenModal();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            auto eventMods = ComponentPeer::getCurrentModifiersRealtime();
 | 
			
		||||
 | 
			
		||||
            if (([e modifierFlags] & NSEventModifierFlagCommand) != 0)
 | 
			
		||||
                eventMods = eventMods.withFlags (ModifierKeys::commandModifier);
 | 
			
		||||
 | 
			
		||||
            auto now = Time::getCurrentTime();
 | 
			
		||||
            auto mouseSource = Desktop::getInstance().getMainMouseSource();
 | 
			
		||||
            auto pressure = (float) e.pressure;
 | 
			
		||||
 | 
			
		||||
            if (isLeft || isRight)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseDown ({ mouseSource, {},
 | 
			
		||||
                                   eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier
 | 
			
		||||
                                                               : ModifierKeys::rightButtonModifier),
 | 
			
		||||
                                   pressure,
 | 
			
		||||
                                   MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
 | 
			
		||||
                                   MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
 | 
			
		||||
                                   &owner, &owner, now, {}, now, 1, false });
 | 
			
		||||
 | 
			
		||||
                owner.mouseUp   ({ mouseSource, {},
 | 
			
		||||
                                   eventMods.withoutMouseButtons(),
 | 
			
		||||
                                   pressure,
 | 
			
		||||
                                   MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
 | 
			
		||||
                                   MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
 | 
			
		||||
                                   &owner, &owner, now, {}, now, 1, false });
 | 
			
		||||
            }
 | 
			
		||||
            else if (type == NSEventTypeMouseMoved)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseMove (MouseEvent (mouseSource, {}, eventMods, pressure,
 | 
			
		||||
                                             MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
 | 
			
		||||
                                             MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
 | 
			
		||||
                                             &owner, &owner, now, {}, now, 1, false));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class ButtonEventForwarderClass   : public ObjCClass<NSObject>
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ButtonEventForwarderClass() : ObjCClass<NSObject> ("JUCEButtonEventForwarderClass_")
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<ButtonBasedStatusItem*> ("owner");
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (handleEvent:), handleEvent, "v@:@");
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static ButtonBasedStatusItem* getOwner (id self)               { return getIvar<ButtonBasedStatusItem*> (self, "owner"); }
 | 
			
		||||
        static void setOwner (id self, ButtonBasedStatusItem* owner)   { object_setInstanceVariable (self, "owner", owner); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        static void handleEvent (id self, SEL, id)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* owner = getOwner (self))
 | 
			
		||||
                owner->handleEvent();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    NSUniquePtr<NSObject> eventForwarder;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct ViewBasedStatusItem   : public StatusItemContainer
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ViewBasedStatusItem (SystemTrayIconComponent& iconComp, const Image& im)
 | 
			
		||||
        : StatusItemContainer (iconComp, im)
 | 
			
		||||
    {
 | 
			
		||||
        static SystemTrayViewClass cls;
 | 
			
		||||
        view.reset ([cls.createInstance() init]);
 | 
			
		||||
        SystemTrayViewClass::setOwner (view.get(), this);
 | 
			
		||||
        SystemTrayViewClass::setImage (view.get(), statusIcon.get());
 | 
			
		||||
 | 
			
		||||
        setIconSize();
 | 
			
		||||
 | 
			
		||||
        statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]);
 | 
			
		||||
        [statusItem.get() setView: view.get()];
 | 
			
		||||
 | 
			
		||||
        SystemTrayViewClass::frameChanged (view.get(), SEL(), nullptr);
 | 
			
		||||
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
        [[NSNotificationCenter defaultCenter]  addObserver: view.get()
 | 
			
		||||
                                                  selector: @selector (frameChanged:)
 | 
			
		||||
                                                      name: NSWindowDidMoveNotification
 | 
			
		||||
                                                    object: nil];
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~ViewBasedStatusItem() override
 | 
			
		||||
    {
 | 
			
		||||
        [[NSNotificationCenter defaultCenter] removeObserver: view.get()];
 | 
			
		||||
        [[NSStatusBar systemStatusBar] removeStatusItem: statusItem.get()];
 | 
			
		||||
        SystemTrayViewClass::setOwner (view.get(), nullptr);
 | 
			
		||||
        SystemTrayViewClass::setImage (view.get(), nil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void configureIcon() override
 | 
			
		||||
    {
 | 
			
		||||
        SystemTrayViewClass::setImage (view.get(), statusIcon.get());
 | 
			
		||||
        [statusItem.get() setView: view.get()];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setHighlighted (bool shouldHighlight) override
 | 
			
		||||
    {
 | 
			
		||||
        isHighlighted = shouldHighlight;
 | 
			
		||||
        [view.get() setNeedsDisplay: true];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void handleStatusItemAction (NSEvent* e)
 | 
			
		||||
    {
 | 
			
		||||
        NSEventType type = [e type];
 | 
			
		||||
 | 
			
		||||
        const bool isLeft  = (type == NSEventTypeLeftMouseDown  || type == NSEventTypeLeftMouseUp);
 | 
			
		||||
        const bool isRight = (type == NSEventTypeRightMouseDown || type == NSEventTypeRightMouseUp);
 | 
			
		||||
 | 
			
		||||
        if (owner.isCurrentlyBlockedByAnotherModalComponent())
 | 
			
		||||
        {
 | 
			
		||||
            if (isLeft || isRight)
 | 
			
		||||
                if (auto* current = Component::getCurrentlyModalComponent())
 | 
			
		||||
                    current->inputAttemptWhenModal();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            auto eventMods = ComponentPeer::getCurrentModifiersRealtime();
 | 
			
		||||
 | 
			
		||||
            if (([e modifierFlags] & NSEventModifierFlagCommand) != 0)
 | 
			
		||||
                eventMods = eventMods.withFlags (ModifierKeys::commandModifier);
 | 
			
		||||
 | 
			
		||||
            auto now = Time::getCurrentTime();
 | 
			
		||||
            auto mouseSource = Desktop::getInstance().getMainMouseSource();
 | 
			
		||||
            auto pressure = (float) e.pressure;
 | 
			
		||||
 | 
			
		||||
            if (isLeft || isRight)  // Only mouse up is sent by the OS, so simulate a down/up
 | 
			
		||||
            {
 | 
			
		||||
                setHighlighted (true);
 | 
			
		||||
                startTimer (150);
 | 
			
		||||
 | 
			
		||||
                owner.mouseDown (MouseEvent (mouseSource, {},
 | 
			
		||||
                                             eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier
 | 
			
		||||
                                                                         : ModifierKeys::rightButtonModifier),
 | 
			
		||||
                                             pressure, MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
 | 
			
		||||
                                             MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
 | 
			
		||||
                                             &owner, &owner, now, {}, now, 1, false));
 | 
			
		||||
 | 
			
		||||
                owner.mouseUp (MouseEvent (mouseSource, {}, eventMods.withoutMouseButtons(), pressure,
 | 
			
		||||
                                           MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
 | 
			
		||||
                                           MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
 | 
			
		||||
                                           &owner, &owner, now, {}, now, 1, false));
 | 
			
		||||
            }
 | 
			
		||||
            else if (type == NSEventTypeMouseMoved)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseMove (MouseEvent (mouseSource, {}, eventMods, pressure,
 | 
			
		||||
                                             MouseInputSource::invalidOrientation, MouseInputSource::invalidRotation,
 | 
			
		||||
                                             MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
 | 
			
		||||
                                             &owner, &owner, now, {}, now, 1, false));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct SystemTrayViewClass : public ObjCClass<NSControl>
 | 
			
		||||
    {
 | 
			
		||||
        SystemTrayViewClass()  : ObjCClass<NSControl> ("JUCESystemTrayView_")
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<ViewBasedStatusItem*> ("owner");
 | 
			
		||||
            addIvar<NSImage*> ("image");
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (mouseDown:),      handleEventDown, "v@:@");
 | 
			
		||||
            addMethod (@selector (rightMouseDown:), handleEventDown, "v@:@");
 | 
			
		||||
            addMethod (@selector (drawRect:),       drawRect,        "v@:@");
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
            addMethod (@selector (frameChanged:),   frameChanged,    "v@:@");
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static ViewBasedStatusItem* getOwner (id self)               { return getIvar<ViewBasedStatusItem*> (self, "owner"); }
 | 
			
		||||
        static NSImage* getImage (id self)                           { return getIvar<NSImage*> (self, "image"); }
 | 
			
		||||
        static void setOwner (id self, ViewBasedStatusItem* owner)   { object_setInstanceVariable (self, "owner", owner); }
 | 
			
		||||
        static void setImage (id self, NSImage* image)               { object_setInstanceVariable (self, "image", image); }
 | 
			
		||||
 | 
			
		||||
        static void frameChanged (id self, SEL, NSNotification*)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* owner = getOwner (self))
 | 
			
		||||
            {
 | 
			
		||||
                NSRect r = [[[owner->statusItem.get() view] window] frame];
 | 
			
		||||
                NSRect sr = [[[NSScreen screens] objectAtIndex: 0] frame];
 | 
			
		||||
                r.origin.y = sr.size.height - r.origin.y - r.size.height;
 | 
			
		||||
                owner->owner.setBounds (convertToRectInt (r));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        static void handleEventDown (id self, SEL, NSEvent* e)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* owner = getOwner (self))
 | 
			
		||||
                owner->handleStatusItemAction (e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void drawRect (id self, SEL, NSRect)
 | 
			
		||||
        {
 | 
			
		||||
            NSRect bounds = [self bounds];
 | 
			
		||||
 | 
			
		||||
            if (auto* owner = getOwner (self))
 | 
			
		||||
                [owner->statusItem.get() drawStatusBarBackgroundInRect: bounds
 | 
			
		||||
                                                         withHighlight: owner->isHighlighted];
 | 
			
		||||
 | 
			
		||||
            if (NSImage* const im = getImage (self))
 | 
			
		||||
            {
 | 
			
		||||
                NSSize imageSize = [im size];
 | 
			
		||||
 | 
			
		||||
                [im drawInRect: NSMakeRect (bounds.origin.x + ((bounds.size.width  - imageSize.width)  / 2.0f),
 | 
			
		||||
                                            bounds.origin.y + ((bounds.size.height - imageSize.height) / 2.0f),
 | 
			
		||||
                                            imageSize.width, imageSize.height)
 | 
			
		||||
                      fromRect: NSZeroRect
 | 
			
		||||
                     operation: NSCompositingOperationSourceOver
 | 
			
		||||
                      fraction: 1.0f];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    NSUniquePtr<NSControl> view;
 | 
			
		||||
    bool isHighlighted = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class SystemTrayIconComponent::Pimpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Pimpl (SystemTrayIconComponent& iconComp, const Image& im)
 | 
			
		||||
    {
 | 
			
		||||
        if (std::floor (NSFoundationVersionNumber) > NSFoundationVersionNumber10_10)
 | 
			
		||||
            statusItemHolder = std::make_unique<ButtonBasedStatusItem> (iconComp, im);
 | 
			
		||||
        else
 | 
			
		||||
            statusItemHolder = std::make_unique<ViewBasedStatusItem> (iconComp, im);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    std::unique_ptr<StatusItemContainer> statusItemHolder;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void SystemTrayIconComponent::setIconImage (const Image&, const Image& templateImage)
 | 
			
		||||
{
 | 
			
		||||
    if (templateImage.isValid())
 | 
			
		||||
    {
 | 
			
		||||
        if (pimpl == nullptr)
 | 
			
		||||
            pimpl.reset (new Pimpl (*this, templateImage));
 | 
			
		||||
        else
 | 
			
		||||
            pimpl->statusItemHolder->updateIcon (templateImage);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        pimpl.reset();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setIconTooltip (const String&)
 | 
			
		||||
{
 | 
			
		||||
    // xxx not yet implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setHighlighted (bool shouldHighlight)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->statusItemHolder->setHighlighted (shouldHighlight);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/)
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::hideInfoBubble()
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SystemTrayIconComponent::getNativeHandle() const
 | 
			
		||||
{
 | 
			
		||||
    return pimpl != nullptr ? pimpl->statusItemHolder->statusItem.get() : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::showDropdownMenu (const PopupMenu& menu)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->statusItemHolder->showMenu (menu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
 | 
			
		||||
extern NSMenu* createNSMenu (const PopupMenu&, const String& name, int topLevelMenuId,
 | 
			
		||||
                             int topLevelIndex, bool addDelegate);
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct StatusItemContainer   : public Timer
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    StatusItemContainer (SystemTrayIconComponent& iconComp, const Image& im)
 | 
			
		||||
        : owner (iconComp), statusIcon (imageToNSImage (ScaledImage (im)))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    virtual void configureIcon() = 0;
 | 
			
		||||
    virtual void setHighlighted (bool shouldHighlight) = 0;
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void setIconSize()
 | 
			
		||||
    {
 | 
			
		||||
        [statusIcon.get() setSize: NSMakeSize (20.0f, 20.0f)];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateIcon (const Image& newImage)
 | 
			
		||||
    {
 | 
			
		||||
        statusIcon.reset (imageToNSImage (ScaledImage (newImage)));
 | 
			
		||||
        setIconSize();
 | 
			
		||||
        configureIcon();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void showMenu (const PopupMenu& menu)
 | 
			
		||||
    {
 | 
			
		||||
        if (NSMenu* m = createNSMenu (menu, "MenuBarItem", -2, -3, true))
 | 
			
		||||
        {
 | 
			
		||||
            setHighlighted (true);
 | 
			
		||||
            stopTimer();
 | 
			
		||||
 | 
			
		||||
            // There's currently no good alternative to this.
 | 
			
		||||
            [statusItem.get() popUpStatusItemMenu: m];
 | 
			
		||||
 | 
			
		||||
            startTimer (1);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void timerCallback() override
 | 
			
		||||
    {
 | 
			
		||||
        stopTimer();
 | 
			
		||||
        setHighlighted (false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    SystemTrayIconComponent& owner;
 | 
			
		||||
 | 
			
		||||
    NSUniquePtr<NSStatusItem> statusItem;
 | 
			
		||||
    NSUniquePtr<NSImage> statusIcon;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (StatusItemContainer)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct API_AVAILABLE (macos (10.10)) ButtonBasedStatusItem : public StatusItemContainer
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ButtonBasedStatusItem (SystemTrayIconComponent& iconComp, const Image& im)
 | 
			
		||||
        : StatusItemContainer (iconComp, im)
 | 
			
		||||
    {
 | 
			
		||||
        static ButtonEventForwarderClass cls;
 | 
			
		||||
        eventForwarder.reset ([cls.createInstance() init]);
 | 
			
		||||
        ButtonEventForwarderClass::setOwner (eventForwarder.get(), this);
 | 
			
		||||
 | 
			
		||||
        setIconSize();
 | 
			
		||||
        configureIcon();
 | 
			
		||||
 | 
			
		||||
        statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]);
 | 
			
		||||
        auto button = [statusItem.get() button];
 | 
			
		||||
        button.image = statusIcon.get();
 | 
			
		||||
        button.target = eventForwarder.get();
 | 
			
		||||
        button.action = @selector (handleEvent:);
 | 
			
		||||
        [button sendActionOn: NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskScrollWheel];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~ButtonBasedStatusItem() override
 | 
			
		||||
    {
 | 
			
		||||
        [statusItem.get() button].image = nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void configureIcon() override
 | 
			
		||||
    {
 | 
			
		||||
        [statusIcon.get() setTemplate: true];
 | 
			
		||||
        [statusItem.get() button].image = statusIcon.get();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setHighlighted (bool shouldHighlight) override
 | 
			
		||||
    {
 | 
			
		||||
        [[statusItem.get() button] setHighlighted: shouldHighlight];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void handleEvent()
 | 
			
		||||
    {
 | 
			
		||||
        auto e = [NSApp currentEvent];
 | 
			
		||||
        NSEventType type = [e type];
 | 
			
		||||
 | 
			
		||||
        const bool isLeft  = (type == NSEventTypeLeftMouseDown);
 | 
			
		||||
        const bool isRight = (type == NSEventTypeRightMouseDown);
 | 
			
		||||
 | 
			
		||||
        if (owner.isCurrentlyBlockedByAnotherModalComponent())
 | 
			
		||||
        {
 | 
			
		||||
            if (isLeft || isRight)
 | 
			
		||||
                if (auto* current = Component::getCurrentlyModalComponent())
 | 
			
		||||
                    current->inputAttemptWhenModal();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            auto eventMods = ComponentPeer::getCurrentModifiersRealtime();
 | 
			
		||||
 | 
			
		||||
            if (([e modifierFlags] & NSEventModifierFlagCommand) != 0)
 | 
			
		||||
                eventMods = eventMods.withFlags (ModifierKeys::commandModifier);
 | 
			
		||||
 | 
			
		||||
            auto now = Time::getCurrentTime();
 | 
			
		||||
            auto mouseSource = Desktop::getInstance().getMainMouseSource();
 | 
			
		||||
            auto pressure = (float) e.pressure;
 | 
			
		||||
 | 
			
		||||
            if (isLeft || isRight)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseDown ({ mouseSource, {},
 | 
			
		||||
                                   eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier
 | 
			
		||||
                                                               : ModifierKeys::rightButtonModifier),
 | 
			
		||||
                                   pressure,
 | 
			
		||||
                                   MouseInputSource::defaultOrientation, MouseInputSource::defaultRotation,
 | 
			
		||||
                                   MouseInputSource::defaultTiltX, MouseInputSource::defaultTiltY,
 | 
			
		||||
                                   &owner, &owner, now, {}, now, 1, false });
 | 
			
		||||
 | 
			
		||||
                owner.mouseUp   ({ mouseSource, {},
 | 
			
		||||
                                   eventMods.withoutMouseButtons(),
 | 
			
		||||
                                   pressure,
 | 
			
		||||
                                   MouseInputSource::defaultOrientation, MouseInputSource::defaultRotation,
 | 
			
		||||
                                   MouseInputSource::defaultTiltX, MouseInputSource::defaultTiltY,
 | 
			
		||||
                                   &owner, &owner, now, {}, now, 1, false });
 | 
			
		||||
            }
 | 
			
		||||
            else if (type == NSEventTypeMouseMoved)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseMove (MouseEvent (mouseSource, {}, eventMods, pressure,
 | 
			
		||||
                                             MouseInputSource::defaultOrientation, MouseInputSource::defaultRotation,
 | 
			
		||||
                                             MouseInputSource::defaultTiltX, MouseInputSource::defaultTiltY,
 | 
			
		||||
                                             &owner, &owner, now, {}, now, 1, false));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    class ButtonEventForwarderClass   : public ObjCClass<NSObject>
 | 
			
		||||
    {
 | 
			
		||||
    public:
 | 
			
		||||
        ButtonEventForwarderClass() : ObjCClass<NSObject> ("JUCEButtonEventForwarderClass_")
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<ButtonBasedStatusItem*> ("owner");
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (handleEvent:), handleEvent);
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static ButtonBasedStatusItem* getOwner (id self)               { return getIvar<ButtonBasedStatusItem*> (self, "owner"); }
 | 
			
		||||
        static void setOwner (id self, ButtonBasedStatusItem* owner)   { object_setInstanceVariable (self, "owner", owner); }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        static void handleEvent (id self, SEL, id)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* owner = getOwner (self))
 | 
			
		||||
                owner->handleEvent();
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    NSUniquePtr<NSObject> eventForwarder;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
struct ViewBasedStatusItem   : public StatusItemContainer
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    ViewBasedStatusItem (SystemTrayIconComponent& iconComp, const Image& im)
 | 
			
		||||
        : StatusItemContainer (iconComp, im)
 | 
			
		||||
    {
 | 
			
		||||
        static SystemTrayViewClass cls;
 | 
			
		||||
        view.reset ([cls.createInstance() init]);
 | 
			
		||||
        SystemTrayViewClass::setOwner (view.get(), this);
 | 
			
		||||
        SystemTrayViewClass::setImage (view.get(), statusIcon.get());
 | 
			
		||||
 | 
			
		||||
        setIconSize();
 | 
			
		||||
 | 
			
		||||
        statusItem.reset ([[[NSStatusBar systemStatusBar] statusItemWithLength: NSSquareStatusItemLength] retain]);
 | 
			
		||||
        [statusItem.get() setView: view.get()];
 | 
			
		||||
 | 
			
		||||
        SystemTrayViewClass::frameChanged (view.get(), SEL(), nullptr);
 | 
			
		||||
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
        [[NSNotificationCenter defaultCenter]  addObserver: view.get()
 | 
			
		||||
                                                  selector: @selector (frameChanged:)
 | 
			
		||||
                                                      name: NSWindowDidMoveNotification
 | 
			
		||||
                                                    object: nil];
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~ViewBasedStatusItem() override
 | 
			
		||||
    {
 | 
			
		||||
        [[NSNotificationCenter defaultCenter] removeObserver: view.get()];
 | 
			
		||||
        [[NSStatusBar systemStatusBar] removeStatusItem: statusItem.get()];
 | 
			
		||||
        SystemTrayViewClass::setOwner (view.get(), nullptr);
 | 
			
		||||
        SystemTrayViewClass::setImage (view.get(), nil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void configureIcon() override
 | 
			
		||||
    {
 | 
			
		||||
        SystemTrayViewClass::setImage (view.get(), statusIcon.get());
 | 
			
		||||
        [statusItem.get() setView: view.get()];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setHighlighted (bool shouldHighlight) override
 | 
			
		||||
    {
 | 
			
		||||
        isHighlighted = shouldHighlight;
 | 
			
		||||
        [view.get() setNeedsDisplay: true];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    void handleStatusItemAction (NSEvent* e)
 | 
			
		||||
    {
 | 
			
		||||
        NSEventType type = [e type];
 | 
			
		||||
 | 
			
		||||
        const bool isLeft  = (type == NSEventTypeLeftMouseDown  || type == NSEventTypeLeftMouseUp);
 | 
			
		||||
        const bool isRight = (type == NSEventTypeRightMouseDown || type == NSEventTypeRightMouseUp);
 | 
			
		||||
 | 
			
		||||
        if (owner.isCurrentlyBlockedByAnotherModalComponent())
 | 
			
		||||
        {
 | 
			
		||||
            if (isLeft || isRight)
 | 
			
		||||
                if (auto* current = Component::getCurrentlyModalComponent())
 | 
			
		||||
                    current->inputAttemptWhenModal();
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            auto eventMods = ComponentPeer::getCurrentModifiersRealtime();
 | 
			
		||||
 | 
			
		||||
            if (([e modifierFlags] & NSEventModifierFlagCommand) != 0)
 | 
			
		||||
                eventMods = eventMods.withFlags (ModifierKeys::commandModifier);
 | 
			
		||||
 | 
			
		||||
            auto now = Time::getCurrentTime();
 | 
			
		||||
            auto mouseSource = Desktop::getInstance().getMainMouseSource();
 | 
			
		||||
            auto pressure = (float) e.pressure;
 | 
			
		||||
 | 
			
		||||
            if (isLeft || isRight)  // Only mouse up is sent by the OS, so simulate a down/up
 | 
			
		||||
            {
 | 
			
		||||
                setHighlighted (true);
 | 
			
		||||
                startTimer (150);
 | 
			
		||||
 | 
			
		||||
                owner.mouseDown (MouseEvent (mouseSource, {},
 | 
			
		||||
                                             eventMods.withFlags (isLeft ? ModifierKeys::leftButtonModifier
 | 
			
		||||
                                                                         : ModifierKeys::rightButtonModifier),
 | 
			
		||||
                                             pressure, MouseInputSource::defaultOrientation, MouseInputSource::defaultRotation,
 | 
			
		||||
                                             MouseInputSource::defaultTiltX, MouseInputSource::defaultTiltY,
 | 
			
		||||
                                             &owner, &owner, now, {}, now, 1, false));
 | 
			
		||||
 | 
			
		||||
                owner.mouseUp (MouseEvent (mouseSource, {}, eventMods.withoutMouseButtons(), pressure,
 | 
			
		||||
                                           MouseInputSource::defaultOrientation, MouseInputSource::defaultRotation,
 | 
			
		||||
                                           MouseInputSource::defaultTiltX, MouseInputSource::defaultTiltY,
 | 
			
		||||
                                           &owner, &owner, now, {}, now, 1, false));
 | 
			
		||||
            }
 | 
			
		||||
            else if (type == NSEventTypeMouseMoved)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseMove (MouseEvent (mouseSource, {}, eventMods, pressure,
 | 
			
		||||
                                             MouseInputSource::defaultOrientation, MouseInputSource::defaultRotation,
 | 
			
		||||
                                             MouseInputSource::defaultTiltX, MouseInputSource::defaultTiltY,
 | 
			
		||||
                                             &owner, &owner, now, {}, now, 1, false));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct SystemTrayViewClass : public ObjCClass<NSControl>
 | 
			
		||||
    {
 | 
			
		||||
        SystemTrayViewClass()  : ObjCClass<NSControl> ("JUCESystemTrayView_")
 | 
			
		||||
        {
 | 
			
		||||
            addIvar<ViewBasedStatusItem*> ("owner");
 | 
			
		||||
            addIvar<NSImage*> ("image");
 | 
			
		||||
 | 
			
		||||
            addMethod (@selector (mouseDown:),      handleEventDown);
 | 
			
		||||
            addMethod (@selector (rightMouseDown:), handleEventDown);
 | 
			
		||||
            addMethod (@selector (drawRect:),       drawRect);
 | 
			
		||||
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
            addMethod (@selector (frameChanged:),   frameChanged);
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
            registerClass();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static ViewBasedStatusItem* getOwner (id self)               { return getIvar<ViewBasedStatusItem*> (self, "owner"); }
 | 
			
		||||
        static NSImage* getImage (id self)                           { return getIvar<NSImage*> (self, "image"); }
 | 
			
		||||
        static void setOwner (id self, ViewBasedStatusItem* owner)   { object_setInstanceVariable (self, "owner", owner); }
 | 
			
		||||
        static void setImage (id self, NSImage* image)               { object_setInstanceVariable (self, "image", image); }
 | 
			
		||||
 | 
			
		||||
        static void frameChanged (id self, SEL, NSNotification*)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* owner = getOwner (self))
 | 
			
		||||
            {
 | 
			
		||||
                NSRect r = [[[owner->statusItem.get() view] window] frame];
 | 
			
		||||
                NSRect sr = [[[NSScreen screens] objectAtIndex: 0] frame];
 | 
			
		||||
                r.origin.y = sr.size.height - r.origin.y - r.size.height;
 | 
			
		||||
                owner->owner.setBounds (convertToRectInt (r));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    private:
 | 
			
		||||
        static void handleEventDown (id self, SEL, NSEvent* e)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* owner = getOwner (self))
 | 
			
		||||
                owner->handleStatusItemAction (e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        static void drawRect (id self, SEL, NSRect)
 | 
			
		||||
        {
 | 
			
		||||
            NSRect bounds = [self bounds];
 | 
			
		||||
 | 
			
		||||
            if (auto* owner = getOwner (self))
 | 
			
		||||
                [owner->statusItem.get() drawStatusBarBackgroundInRect: bounds
 | 
			
		||||
                                                         withHighlight: owner->isHighlighted];
 | 
			
		||||
 | 
			
		||||
            if (NSImage* const im = getImage (self))
 | 
			
		||||
            {
 | 
			
		||||
                NSSize imageSize = [im size];
 | 
			
		||||
 | 
			
		||||
                [im drawInRect: NSMakeRect (bounds.origin.x + ((bounds.size.width  - imageSize.width)  / 2.0f),
 | 
			
		||||
                                            bounds.origin.y + ((bounds.size.height - imageSize.height) / 2.0f),
 | 
			
		||||
                                            imageSize.width, imageSize.height)
 | 
			
		||||
                      fromRect: NSZeroRect
 | 
			
		||||
                     operation: NSCompositingOperationSourceOver
 | 
			
		||||
                      fraction: 1.0f];
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    NSUniquePtr<NSControl> view;
 | 
			
		||||
    bool isHighlighted = false;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class SystemTrayIconComponent::Pimpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    Pimpl (SystemTrayIconComponent& iconComp, const Image& im)
 | 
			
		||||
    {
 | 
			
		||||
        if (@available (macOS 10.10, *))
 | 
			
		||||
            statusItemHolder = std::make_unique<ButtonBasedStatusItem> (iconComp, im);
 | 
			
		||||
        else
 | 
			
		||||
            statusItemHolder = std::make_unique<ViewBasedStatusItem> (iconComp, im);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    std::unique_ptr<StatusItemContainer> statusItemHolder;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void SystemTrayIconComponent::setIconImage (const Image&, const Image& templateImage)
 | 
			
		||||
{
 | 
			
		||||
    if (templateImage.isValid())
 | 
			
		||||
    {
 | 
			
		||||
        if (pimpl == nullptr)
 | 
			
		||||
            pimpl.reset (new Pimpl (*this, templateImage));
 | 
			
		||||
        else
 | 
			
		||||
            pimpl->statusItemHolder->updateIcon (templateImage);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        pimpl.reset();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setIconTooltip (const String&)
 | 
			
		||||
{
 | 
			
		||||
    // xxx not yet implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setHighlighted (bool shouldHighlight)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->statusItemHolder->setHighlighted (shouldHighlight);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::showInfoBubble (const String& /*title*/, const String& /*content*/)
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::hideInfoBubble()
 | 
			
		||||
{
 | 
			
		||||
    // xxx Not implemented!
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SystemTrayIconComponent::getNativeHandle() const
 | 
			
		||||
{
 | 
			
		||||
    return pimpl != nullptr ? pimpl->statusItemHolder->statusItem.get() : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::showDropdownMenu (const PopupMenu& menu)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->statusItemHolder->showMenu (menu);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -2,15 +2,15 @@
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
@@ -26,17 +26,9 @@
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
#if JUCE_IOS || (defined (MAC_OS_X_VERSION_10_10) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_10)
 | 
			
		||||
 #define JUCE_USE_WKWEBVIEW 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if (defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
 | 
			
		||||
 #define WKWEBVIEW_OPENPANEL_SUPPORTED 1
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
static NSURL* appendParametersToFileURL (const URL& url, NSURL* fileUrl)
 | 
			
		||||
{
 | 
			
		||||
    if (@available (macOS 10.9, *))
 | 
			
		||||
    if (@available (macOS 10.10, *))
 | 
			
		||||
    {
 | 
			
		||||
        const auto parameterNames = url.getParameterNames();
 | 
			
		||||
        const auto parameterValues = url.getParameterValues();
 | 
			
		||||
@@ -115,295 +107,125 @@ static NSMutableURLRequest* getRequestForURL (const String& url, const StringArr
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#if JUCE_MAC
 | 
			
		||||
 | 
			
		||||
#if JUCE_USE_WKWEBVIEW
 | 
			
		||||
 using WebViewBase = ObjCClass<WKWebView>;
 | 
			
		||||
#else
 | 
			
		||||
 using WebViewBase = ObjCClass<WebView>;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
struct WebViewKeyEquivalentResponder : public WebViewBase
 | 
			
		||||
template <class WebViewClass>
 | 
			
		||||
struct WebViewKeyEquivalentResponder : public ObjCClass<WebViewClass>
 | 
			
		||||
{
 | 
			
		||||
    WebViewKeyEquivalentResponder()
 | 
			
		||||
        : WebViewBase ("WebViewKeyEquivalentResponder_")
 | 
			
		||||
        : ObjCClass<WebViewClass> ("WebViewKeyEquivalentResponder_")
 | 
			
		||||
    {
 | 
			
		||||
        addMethod (@selector (performKeyEquivalent:), performKeyEquivalent, @encode (BOOL), "@:@");
 | 
			
		||||
        registerClass();
 | 
			
		||||
    }
 | 
			
		||||
        this->addMethod (@selector (performKeyEquivalent:),
 | 
			
		||||
                         [] (id self, SEL selector, NSEvent* event)
 | 
			
		||||
                         {
 | 
			
		||||
                             const auto isCommandDown = [event]
 | 
			
		||||
                             {
 | 
			
		||||
                                 const auto modifierFlags = [event modifierFlags];
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static BOOL performKeyEquivalent (id self, SEL selector, NSEvent* event)
 | 
			
		||||
    {
 | 
			
		||||
        NSResponder* first = [[self window] firstResponder];
 | 
			
		||||
                                 if (@available (macOS 10.12, *))
 | 
			
		||||
                                     return (modifierFlags & NSEventModifierFlagDeviceIndependentFlagsMask) == NSEventModifierFlagCommand;
 | 
			
		||||
 | 
			
		||||
       #if (defined (MAC_OS_X_VERSION_10_12) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_12)
 | 
			
		||||
        constexpr auto mask = NSEventModifierFlagDeviceIndependentFlagsMask;
 | 
			
		||||
        constexpr auto key  = NSEventModifierFlagCommand;
 | 
			
		||||
       #else
 | 
			
		||||
        constexpr auto mask = NSDeviceIndependentModifierFlagsMask;
 | 
			
		||||
        constexpr auto key  = NSCommandKeyMask;
 | 
			
		||||
       #endif
 | 
			
		||||
                                 JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
                                 return (modifierFlags & NSDeviceIndependentModifierFlagsMask) == NSCommandKeyMask;
 | 
			
		||||
                                 JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
                             }();
 | 
			
		||||
 | 
			
		||||
        if (([event modifierFlags] & mask) == key)
 | 
			
		||||
        {
 | 
			
		||||
            auto sendAction = [&] (SEL actionSelector) -> BOOL
 | 
			
		||||
            {
 | 
			
		||||
                return [NSApp sendAction: actionSelector
 | 
			
		||||
                                      to: first
 | 
			
		||||
                                    from: self];
 | 
			
		||||
            };
 | 
			
		||||
                             if (isCommandDown)
 | 
			
		||||
                             {
 | 
			
		||||
                                 auto sendAction = [&] (SEL actionSelector) -> BOOL
 | 
			
		||||
                                 {
 | 
			
		||||
                                     return [NSApp sendAction:actionSelector
 | 
			
		||||
                                                           to:[[self window] firstResponder]
 | 
			
		||||
                                                         from:self];
 | 
			
		||||
                                 };
 | 
			
		||||
 | 
			
		||||
            if ([[event charactersIgnoringModifiers] isEqualToString: @"x"])  return sendAction (@selector (cut:));
 | 
			
		||||
            if ([[event charactersIgnoringModifiers] isEqualToString: @"c"])  return sendAction (@selector (copy:));
 | 
			
		||||
            if ([[event charactersIgnoringModifiers] isEqualToString: @"v"])  return sendAction (@selector (paste:));
 | 
			
		||||
            if ([[event charactersIgnoringModifiers] isEqualToString: @"a"])  return sendAction (@selector (selectAll:));
 | 
			
		||||
        }
 | 
			
		||||
                                 if ([[event charactersIgnoringModifiers] isEqualToString:@"x"])
 | 
			
		||||
                                     return sendAction (@selector (cut:));
 | 
			
		||||
                                 if ([[event charactersIgnoringModifiers] isEqualToString:@"c"])
 | 
			
		||||
                                     return sendAction (@selector (copy:));
 | 
			
		||||
                                 if ([[event charactersIgnoringModifiers] isEqualToString:@"v"])
 | 
			
		||||
                                     return sendAction (@selector (paste:));
 | 
			
		||||
                                 if ([[event charactersIgnoringModifiers] isEqualToString:@"a"])
 | 
			
		||||
                                     return sendAction (@selector (selectAll:));
 | 
			
		||||
                             }
 | 
			
		||||
 | 
			
		||||
        return sendSuperclassMessage<BOOL> (self, selector, event);
 | 
			
		||||
                             return ObjCClass<WebViewClass>::template sendSuperclassMessage<BOOL> (self, selector, event);
 | 
			
		||||
                         });
 | 
			
		||||
        this->registerClass();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#if JUCE_USE_WKWEBVIEW
 | 
			
		||||
 | 
			
		||||
struct WebViewDelegateClass  : public ObjCClass<NSObject>
 | 
			
		||||
{
 | 
			
		||||
    WebViewDelegateClass()  : ObjCClass<NSObject> ("JUCEWebViewDelegate_")
 | 
			
		||||
    {
 | 
			
		||||
        addIvar<WebBrowserComponent*> ("owner");
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:decidePolicyForNavigationAction:decisionHandler:),  decidePolicyForNavigationAction, "v@:@@@");
 | 
			
		||||
        addMethod (@selector (webView:didFinishNavigation:),                              didFinishNavigation,             "v@:@@");
 | 
			
		||||
        addMethod (@selector (webView:didFailNavigation:withError:),                      didFailNavigation,               "v@:@@@");
 | 
			
		||||
        addMethod (@selector (webView:didFailProvisionalNavigation:withError:),           didFailProvisionalNavigation,    "v@:@@@");
 | 
			
		||||
        addMethod (@selector (webViewDidClose:),                                          webViewDidClose,                 "v@:@");
 | 
			
		||||
        addMethod (@selector (webView:createWebViewWithConfiguration:forNavigationAction:
 | 
			
		||||
                              windowFeatures:),                                           createWebView,                   "@@:@@@@");
 | 
			
		||||
 | 
			
		||||
       #if WKWEBVIEW_OPENPANEL_SUPPORTED
 | 
			
		||||
        addMethod (@selector (webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:), runOpenPanel, "v@:@@@@");
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        registerClass();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void setOwner (id self, WebBrowserComponent* owner)   { object_setInstanceVariable (self, "owner", owner); }
 | 
			
		||||
    static WebBrowserComponent* getOwner (id self)               { return getIvar<WebBrowserComponent*> (self, "owner"); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static void decidePolicyForNavigationAction (id self, SEL, WKWebView*, WKNavigationAction* navigationAction,
 | 
			
		||||
                                                 void (^decisionHandler)(WKNavigationActionPolicy))
 | 
			
		||||
    {
 | 
			
		||||
        if (getOwner (self)->pageAboutToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString])))
 | 
			
		||||
            decisionHandler (WKNavigationActionPolicyAllow);
 | 
			
		||||
        else
 | 
			
		||||
            decisionHandler (WKNavigationActionPolicyCancel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void didFinishNavigation (id self, SEL, WKWebView* webview, WKNavigation*)
 | 
			
		||||
    {
 | 
			
		||||
        getOwner (self)->pageFinishedLoading (nsStringToJuce ([[webview URL] absoluteString]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void displayError (WebBrowserComponent* owner, NSError* error)
 | 
			
		||||
    {
 | 
			
		||||
        if ([error code] != NSURLErrorCancelled)
 | 
			
		||||
        {
 | 
			
		||||
            auto errorString = nsStringToJuce ([error localizedDescription]);
 | 
			
		||||
            bool proceedToErrorPage = owner->pageLoadHadNetworkError (errorString);
 | 
			
		||||
 | 
			
		||||
            // WKWebView doesn't have an internal error page, so make a really simple one ourselves
 | 
			
		||||
            if (proceedToErrorPage)
 | 
			
		||||
                owner->goToURL ("data:text/plain;charset=UTF-8," + errorString);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void didFailNavigation (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
 | 
			
		||||
    {
 | 
			
		||||
        displayError (getOwner (self), error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void didFailProvisionalNavigation (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
 | 
			
		||||
    {
 | 
			
		||||
        displayError (getOwner (self), error);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void webViewDidClose (id self, SEL, WKWebView*)
 | 
			
		||||
    {
 | 
			
		||||
        getOwner (self)->windowCloseRequest();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static WKWebView* createWebView (id self, SEL, WKWebView*, WKWebViewConfiguration*,
 | 
			
		||||
                                     WKNavigationAction* navigationAction, WKWindowFeatures*)
 | 
			
		||||
    {
 | 
			
		||||
        getOwner (self)->newWindowAttemptingToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString]));
 | 
			
		||||
        return nil;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
   #if WKWEBVIEW_OPENPANEL_SUPPORTED
 | 
			
		||||
    static void runOpenPanel (id, SEL, WKWebView*, WKOpenPanelParameters* parameters, WKFrameInfo*,
 | 
			
		||||
                              void (^completionHandler)(NSArray<NSURL*>*))
 | 
			
		||||
    {
 | 
			
		||||
        using CompletionHandlerType = decltype (completionHandler);
 | 
			
		||||
 | 
			
		||||
        class DeletedFileChooserWrapper   : private DeletedAtShutdown
 | 
			
		||||
        {
 | 
			
		||||
        public:
 | 
			
		||||
            DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, CompletionHandlerType h)
 | 
			
		||||
                : chooser (std::move (fc)), handler (h)
 | 
			
		||||
            {
 | 
			
		||||
                [handler retain];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ~DeletedFileChooserWrapper()
 | 
			
		||||
            {
 | 
			
		||||
                callHandler (nullptr);
 | 
			
		||||
                [handler release];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            void callHandler (NSArray<NSURL*>* urls)
 | 
			
		||||
            {
 | 
			
		||||
                if (handlerCalled)
 | 
			
		||||
                    return;
 | 
			
		||||
 | 
			
		||||
                handler (urls);
 | 
			
		||||
                handlerCalled = true;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            std::unique_ptr<FileChooser> chooser;
 | 
			
		||||
 | 
			
		||||
        private:
 | 
			
		||||
            CompletionHandlerType handler;
 | 
			
		||||
            bool handlerCalled = false;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        auto chooser = std::make_unique<FileChooser> (TRANS("Select the file you want to upload..."),
 | 
			
		||||
                                                      File::getSpecialLocation (File::userHomeDirectory), "*");
 | 
			
		||||
        auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), completionHandler);
 | 
			
		||||
 | 
			
		||||
        auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
 | 
			
		||||
                    | ([parameters allowsMultipleSelection] ? FileBrowserComponent::canSelectMultipleItems : 0);
 | 
			
		||||
 | 
			
		||||
        #if (defined (MAC_OS_X_VERSION_10_14) && MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_14)
 | 
			
		||||
         if ([parameters allowsDirectories])
 | 
			
		||||
             flags |= FileBrowserComponent::canSelectDirectories;
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
        wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
 | 
			
		||||
        {
 | 
			
		||||
            auto results = wrapper->chooser->getResults();
 | 
			
		||||
            auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) results.size()];
 | 
			
		||||
 | 
			
		||||
            for (auto& f : results)
 | 
			
		||||
                [urls addObject: [NSURL fileURLWithPath: juceStringToNS (f.getFullPathName())]];
 | 
			
		||||
 | 
			
		||||
            wrapper->callHandler (urls);
 | 
			
		||||
            delete wrapper;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
   #endif
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class WebBrowserComponent::Pimpl
 | 
			
		||||
                                   #if JUCE_MAC
 | 
			
		||||
                                    : public NSViewComponent
 | 
			
		||||
                                   #else
 | 
			
		||||
                                    : public UIViewComponent
 | 
			
		||||
                                   #endif
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (WebBrowserComponent* owner)
 | 
			
		||||
    {
 | 
			
		||||
       #if JUCE_MAC
 | 
			
		||||
        static WebViewKeyEquivalentResponder webviewClass;
 | 
			
		||||
        webView = (WKWebView*) webviewClass.createInstance();
 | 
			
		||||
 | 
			
		||||
        webView = [webView initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)];
 | 
			
		||||
       #else
 | 
			
		||||
        webView = [[WKWebView alloc] initWithFrame: CGRectMake (0, 0, 100.0f, 100.0f)];
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        static WebViewDelegateClass cls;
 | 
			
		||||
        webViewDelegate = [cls.createInstance() init];
 | 
			
		||||
        WebViewDelegateClass::setOwner (webViewDelegate, owner);
 | 
			
		||||
 | 
			
		||||
        [webView setNavigationDelegate: webViewDelegate];
 | 
			
		||||
        [webView setUIDelegate:         webViewDelegate];
 | 
			
		||||
 | 
			
		||||
        setView (webView);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl()
 | 
			
		||||
    {
 | 
			
		||||
        [webView setNavigationDelegate: nil];
 | 
			
		||||
        [webView setUIDelegate:         nil];
 | 
			
		||||
 | 
			
		||||
        [webViewDelegate release];
 | 
			
		||||
 | 
			
		||||
        setView (nil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void goToURL (const String& url,
 | 
			
		||||
                  const StringArray* headers,
 | 
			
		||||
                  const MemoryBlock* postData)
 | 
			
		||||
    {
 | 
			
		||||
        auto trimmed = url.trimStart();
 | 
			
		||||
 | 
			
		||||
        if (trimmed.startsWithIgnoreCase ("javascript:"))
 | 
			
		||||
        {
 | 
			
		||||
            [webView evaluateJavaScript: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))
 | 
			
		||||
                     completionHandler: nil];
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        stop();
 | 
			
		||||
 | 
			
		||||
        if (trimmed.startsWithIgnoreCase ("file:"))
 | 
			
		||||
        {
 | 
			
		||||
            auto file = URL (url).getLocalFile();
 | 
			
		||||
 | 
			
		||||
            if (NSURL* nsUrl = [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())])
 | 
			
		||||
                [webView loadFileURL: appendParametersToFileURL (url, nsUrl) allowingReadAccessToURL: nsUrl];
 | 
			
		||||
        }
 | 
			
		||||
        else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData))
 | 
			
		||||
        {
 | 
			
		||||
            [webView loadRequest: request];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void goBack()       { [webView goBack]; }
 | 
			
		||||
    void goForward()    { [webView goForward]; }
 | 
			
		||||
 | 
			
		||||
    void stop()         { [webView stopLoading]; }
 | 
			
		||||
    void refresh()      { [webView reload]; }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    WKWebView* webView = nil;
 | 
			
		||||
    id webViewDelegate;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
#if JUCE_MAC
 | 
			
		||||
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
struct DownloadClickDetectorClass  : public ObjCClass<NSObject>
 | 
			
		||||
{
 | 
			
		||||
    DownloadClickDetectorClass()  : ObjCClass<NSObject> ("JUCEWebClickDetector_")
 | 
			
		||||
    DownloadClickDetectorClass()  : ObjCClass ("JUCEWebClickDetector_")
 | 
			
		||||
    {
 | 
			
		||||
        addIvar<WebBrowserComponent*> ("owner");
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:didFailLoadWithError:forFrame:),            didFailLoadWithError);
 | 
			
		||||
        addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:), didFailLoadWithError);
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:decidePolicyForNavigationAction:request:frame:decisionListener:),
 | 
			
		||||
                   decidePolicyForNavigationAction, "v@:@@@@@");
 | 
			
		||||
                   [] (id self, SEL, WebView*, NSDictionary* actionInformation, NSURLRequest*, WebFrame*, id<WebPolicyDecisionListener> listener)
 | 
			
		||||
                   {
 | 
			
		||||
                       if (getOwner (self)->pageAboutToLoad (getOriginalURL (actionInformation)))
 | 
			
		||||
                           [listener use];
 | 
			
		||||
                       else
 | 
			
		||||
                           [listener ignore];
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:decidePolicyForNewWindowAction:request:newFrameName:decisionListener:),
 | 
			
		||||
                   decidePolicyForNewWindowAction, "v@:@@@@@");
 | 
			
		||||
        addMethod (@selector (webView:didFinishLoadForFrame:), didFinishLoadForFrame, "v@:@@");
 | 
			
		||||
        addMethod (@selector (webView:didFailLoadWithError:forFrame:),  didFailLoadWithError,  "v@:@@@");
 | 
			
		||||
        addMethod (@selector (webView:didFailProvisionalLoadWithError:forFrame:),  didFailLoadWithError,  "v@:@@@");
 | 
			
		||||
        addMethod (@selector (webView:willCloseFrame:), willCloseFrame, "v@:@@");
 | 
			
		||||
        addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:), runOpenPanel, "v@:@@", @encode (BOOL));
 | 
			
		||||
                   [] (id self, SEL, WebView*, NSDictionary* actionInformation, NSURLRequest*, NSString*, id<WebPolicyDecisionListener> listener)
 | 
			
		||||
                   {
 | 
			
		||||
                       getOwner (self)->newWindowAttemptingToLoad (getOriginalURL (actionInformation));
 | 
			
		||||
                       [listener ignore];
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:didFinishLoadForFrame:),
 | 
			
		||||
                   [] (id self, SEL, WebView* sender, WebFrame* frame)
 | 
			
		||||
                   {
 | 
			
		||||
                       if ([frame isEqual:[sender mainFrame]])
 | 
			
		||||
                       {
 | 
			
		||||
                           NSURL* url = [[[frame dataSource] request] URL];
 | 
			
		||||
                           getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
 | 
			
		||||
                       }
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:willCloseFrame:),
 | 
			
		||||
                   [] (id self, SEL, WebView*, WebFrame*)
 | 
			
		||||
                   {
 | 
			
		||||
                       getOwner (self)->windowCloseRequest();
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:runOpenPanelForFileButtonWithResultListener:allowMultipleFiles:),
 | 
			
		||||
                   [] (id, SEL, WebView*, id<WebOpenPanelResultListener> resultListener, BOOL allowMultipleFiles)
 | 
			
		||||
                   {
 | 
			
		||||
                       struct DeletedFileChooserWrapper : private DeletedAtShutdown
 | 
			
		||||
                       {
 | 
			
		||||
                           DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, id<WebOpenPanelResultListener> rl)
 | 
			
		||||
                               : chooser (std::move (fc)), listener (rl)
 | 
			
		||||
                           {
 | 
			
		||||
                               [listener.get() retain];
 | 
			
		||||
                           }
 | 
			
		||||
 | 
			
		||||
                           std::unique_ptr<FileChooser> chooser;
 | 
			
		||||
                           ObjCObjectHandle<id<WebOpenPanelResultListener>> listener;
 | 
			
		||||
                       };
 | 
			
		||||
 | 
			
		||||
                       auto chooser = std::make_unique<FileChooser> (TRANS ("Select the file you want to upload..."),
 | 
			
		||||
                                                                     File::getSpecialLocation (File::userHomeDirectory),
 | 
			
		||||
                                                                     "*");
 | 
			
		||||
                       auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), resultListener);
 | 
			
		||||
 | 
			
		||||
                       auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
 | 
			
		||||
                                    | (allowMultipleFiles ? FileBrowserComponent::canSelectMultipleItems : 0);
 | 
			
		||||
 | 
			
		||||
                       wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
 | 
			
		||||
                       {
 | 
			
		||||
                           for (auto& f : wrapper->chooser->getResults())
 | 
			
		||||
                               [wrapper->listener.get() chooseFilename: juceStringToNS (f.getFullPathName())];
 | 
			
		||||
 | 
			
		||||
                           delete wrapper;
 | 
			
		||||
                       });
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        registerClass();
 | 
			
		||||
    }
 | 
			
		||||
@@ -420,31 +242,6 @@ private:
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void decidePolicyForNavigationAction (id self, SEL, WebView*, NSDictionary* actionInformation,
 | 
			
		||||
                                                 NSURLRequest*, WebFrame*, id<WebPolicyDecisionListener> listener)
 | 
			
		||||
    {
 | 
			
		||||
        if (getOwner (self)->pageAboutToLoad (getOriginalURL (actionInformation)))
 | 
			
		||||
            [listener use];
 | 
			
		||||
        else
 | 
			
		||||
            [listener ignore];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void decidePolicyForNewWindowAction (id self, SEL, WebView*, NSDictionary* actionInformation,
 | 
			
		||||
                                                NSURLRequest*, NSString*, id<WebPolicyDecisionListener> listener)
 | 
			
		||||
    {
 | 
			
		||||
        getOwner (self)->newWindowAttemptingToLoad (getOriginalURL (actionInformation));
 | 
			
		||||
        [listener ignore];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void didFinishLoadForFrame (id self, SEL, WebView* sender, WebFrame* frame)
 | 
			
		||||
    {
 | 
			
		||||
        if ([frame isEqual: [sender mainFrame]])
 | 
			
		||||
        {
 | 
			
		||||
            NSURL* url = [[[frame dataSource] request] URL];
 | 
			
		||||
            getOwner (self)->pageFinishedLoading (nsStringToJuce ([url absoluteString]));
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void didFailLoadWithError (id self, SEL, WebView* sender, NSError* error, WebFrame* frame)
 | 
			
		||||
    {
 | 
			
		||||
        if ([frame isEqual: [sender mainFrame]] && error != nullptr && [error code] != NSURLErrorCancelled)
 | 
			
		||||
@@ -457,61 +254,123 @@ private:
 | 
			
		||||
                getOwner (self)->goToURL ("data:text/plain;charset=UTF-8," + errorString);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void willCloseFrame (id self, SEL, WebView*, WebFrame*)
 | 
			
		||||
    {
 | 
			
		||||
        getOwner (self)->windowCloseRequest();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void runOpenPanel (id, SEL, WebView*, id<WebOpenPanelResultListener> resultListener, BOOL allowMultipleFiles)
 | 
			
		||||
    {
 | 
			
		||||
        struct DeletedFileChooserWrapper   : private DeletedAtShutdown
 | 
			
		||||
        {
 | 
			
		||||
            DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, id<WebOpenPanelResultListener> rl)
 | 
			
		||||
                : chooser (std::move (fc)), listener (rl)
 | 
			
		||||
            {
 | 
			
		||||
                [listener retain];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            ~DeletedFileChooserWrapper()
 | 
			
		||||
            {
 | 
			
		||||
                [listener release];
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            std::unique_ptr<FileChooser> chooser;
 | 
			
		||||
            id<WebOpenPanelResultListener> listener;
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        auto chooser = std::make_unique<FileChooser> (TRANS("Select the file you want to upload..."),
 | 
			
		||||
                                                      File::getSpecialLocation (File::userHomeDirectory), "*");
 | 
			
		||||
        auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), resultListener);
 | 
			
		||||
 | 
			
		||||
        auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
 | 
			
		||||
                    | (allowMultipleFiles ? FileBrowserComponent::canSelectMultipleItems : 0);
 | 
			
		||||
 | 
			
		||||
        wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
 | 
			
		||||
        {
 | 
			
		||||
            for (auto& f : wrapper->chooser->getResults())
 | 
			
		||||
                [wrapper->listener chooseFilename: juceStringToNS (f.getFullPathName())];
 | 
			
		||||
 | 
			
		||||
            delete wrapper;
 | 
			
		||||
        });
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#else
 | 
			
		||||
 | 
			
		||||
struct WebViewDelegateClass  : public ObjCClass<NSObject>
 | 
			
		||||
struct API_AVAILABLE (macos (10.10)) WebViewDelegateClass  : public ObjCClass<NSObject>
 | 
			
		||||
{
 | 
			
		||||
    WebViewDelegateClass()  : ObjCClass<NSObject> ("JUCEWebViewDelegate_")
 | 
			
		||||
    WebViewDelegateClass()  : ObjCClass ("JUCEWebViewDelegate_")
 | 
			
		||||
    {
 | 
			
		||||
        addIvar<WebBrowserComponent*> ("owner");
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:),
 | 
			
		||||
                   shouldRecognizeSimultaneouslyWithGestureRecognizer, "c@:@@");
 | 
			
		||||
        addMethod (@selector (webView:decidePolicyForNavigationAction:decisionHandler:),
 | 
			
		||||
                   [] (id self, SEL, WKWebView*, WKNavigationAction* navigationAction, void (^decisionHandler) (WKNavigationActionPolicy))
 | 
			
		||||
                   {
 | 
			
		||||
                       if (getOwner (self)->pageAboutToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString])))
 | 
			
		||||
                           decisionHandler (WKNavigationActionPolicyAllow);
 | 
			
		||||
                       else
 | 
			
		||||
                           decisionHandler (WKNavigationActionPolicyCancel);
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:shouldStartLoadWithRequest:navigationType:),  shouldStartLoadWithRequest, "c@:@@@");
 | 
			
		||||
        addMethod (@selector (webViewDidFinishLoad:),                               webViewDidFinishLoad,       "v@:@");
 | 
			
		||||
        addMethod (@selector (webView:didFinishNavigation:),
 | 
			
		||||
                   [] (id self, SEL, WKWebView* webview, WKNavigation*)
 | 
			
		||||
                   {
 | 
			
		||||
                       getOwner (self)->pageFinishedLoading (nsStringToJuce ([[webview URL] absoluteString]));
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:didFailNavigation:withError:),
 | 
			
		||||
                   [] (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
 | 
			
		||||
                   {
 | 
			
		||||
                       displayError (getOwner (self), error);
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:didFailProvisionalNavigation:withError:),
 | 
			
		||||
                   [] (id self, SEL, WKWebView*, WKNavigation*, NSError* error)
 | 
			
		||||
                   {
 | 
			
		||||
                       displayError (getOwner (self), error);
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webViewDidClose:),
 | 
			
		||||
                   [] (id self, SEL, WKWebView*)
 | 
			
		||||
                   {
 | 
			
		||||
                       getOwner (self)->windowCloseRequest();
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        addMethod (@selector (webView:createWebViewWithConfiguration:forNavigationAction:windowFeatures:),
 | 
			
		||||
                   [] (id self, SEL, WKWebView*, WKWebViewConfiguration*, WKNavigationAction* navigationAction, WKWindowFeatures*)
 | 
			
		||||
                   {
 | 
			
		||||
                       getOwner (self)->newWindowAttemptingToLoad (nsStringToJuce ([[[navigationAction request] URL] absoluteString]));
 | 
			
		||||
                       return nil;
 | 
			
		||||
                   });
 | 
			
		||||
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
        if (@available (macOS 10.12, *))
 | 
			
		||||
        {
 | 
			
		||||
            addMethod (@selector (webView:runOpenPanelWithParameters:initiatedByFrame:completionHandler:),
 | 
			
		||||
                       [] (id, SEL, WKWebView*, WKOpenPanelParameters* parameters, WKFrameInfo*, void (^completionHandler)(NSArray<NSURL*>*))
 | 
			
		||||
                       {
 | 
			
		||||
                           using CompletionHandlerType = decltype (completionHandler);
 | 
			
		||||
 | 
			
		||||
                           class DeletedFileChooserWrapper   : private DeletedAtShutdown
 | 
			
		||||
                           {
 | 
			
		||||
                           public:
 | 
			
		||||
                               DeletedFileChooserWrapper (std::unique_ptr<FileChooser> fc, CompletionHandlerType h)
 | 
			
		||||
                                   : chooser (std::move (fc)), handler (h)
 | 
			
		||||
                               {
 | 
			
		||||
                                   [handler.get() retain];
 | 
			
		||||
                               }
 | 
			
		||||
 | 
			
		||||
                               ~DeletedFileChooserWrapper()
 | 
			
		||||
                               {
 | 
			
		||||
                                   callHandler (nullptr);
 | 
			
		||||
                               }
 | 
			
		||||
 | 
			
		||||
                               void callHandler (NSArray<NSURL*>* urls)
 | 
			
		||||
                               {
 | 
			
		||||
                                   if (handlerCalled)
 | 
			
		||||
                                       return;
 | 
			
		||||
 | 
			
		||||
                                   handler.get() (urls);
 | 
			
		||||
                                   handlerCalled = true;
 | 
			
		||||
                               }
 | 
			
		||||
 | 
			
		||||
                               std::unique_ptr<FileChooser> chooser;
 | 
			
		||||
 | 
			
		||||
                           private:
 | 
			
		||||
                               ObjCObjectHandle<CompletionHandlerType> handler;
 | 
			
		||||
                               bool handlerCalled = false;
 | 
			
		||||
                           };
 | 
			
		||||
 | 
			
		||||
                           auto chooser = std::make_unique<FileChooser> (TRANS("Select the file you want to upload..."),
 | 
			
		||||
                                                                         File::getSpecialLocation (File::userHomeDirectory), "*");
 | 
			
		||||
                           auto* wrapper = new DeletedFileChooserWrapper (std::move (chooser), completionHandler);
 | 
			
		||||
 | 
			
		||||
                           auto flags = FileBrowserComponent::openMode | FileBrowserComponent::canSelectFiles
 | 
			
		||||
                                        | ([parameters allowsMultipleSelection] ? FileBrowserComponent::canSelectMultipleItems : 0);
 | 
			
		||||
 | 
			
		||||
                          #if JUCE_MAC
 | 
			
		||||
                           if (@available (macOS 10.14, *))
 | 
			
		||||
                           {
 | 
			
		||||
                               if ([parameters allowsDirectories])
 | 
			
		||||
                                   flags |= FileBrowserComponent::canSelectDirectories;
 | 
			
		||||
                           }
 | 
			
		||||
                          #endif
 | 
			
		||||
 | 
			
		||||
                           wrapper->chooser->launchAsync (flags, [wrapper] (const FileChooser&)
 | 
			
		||||
                           {
 | 
			
		||||
                               auto results = wrapper->chooser->getResults();
 | 
			
		||||
                               auto urls = [NSMutableArray arrayWithCapacity: (NSUInteger) results.size()];
 | 
			
		||||
 | 
			
		||||
                               for (auto& f : results)
 | 
			
		||||
                                   [urls addObject: [NSURL fileURLWithPath: juceStringToNS (f.getFullPathName())]];
 | 
			
		||||
 | 
			
		||||
                               wrapper->callHandler (urls);
 | 
			
		||||
                               delete wrapper;
 | 
			
		||||
                           });
 | 
			
		||||
                       });
 | 
			
		||||
        }
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
        registerClass();
 | 
			
		||||
    }
 | 
			
		||||
@@ -520,86 +379,70 @@ struct WebViewDelegateClass  : public ObjCClass<NSObject>
 | 
			
		||||
    static WebBrowserComponent* getOwner (id self)               { return getIvar<WebBrowserComponent*> (self, "owner"); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static BOOL shouldRecognizeSimultaneouslyWithGestureRecognizer (id, SEL, UIGestureRecognizer*, UIGestureRecognizer*)
 | 
			
		||||
    static void displayError (WebBrowserComponent* owner, NSError* error)
 | 
			
		||||
    {
 | 
			
		||||
        return YES;
 | 
			
		||||
    }
 | 
			
		||||
        if ([error code] != NSURLErrorCancelled)
 | 
			
		||||
        {
 | 
			
		||||
            auto errorString = nsStringToJuce ([error localizedDescription]);
 | 
			
		||||
            bool proceedToErrorPage = owner->pageLoadHadNetworkError (errorString);
 | 
			
		||||
 | 
			
		||||
    static BOOL shouldStartLoadWithRequest (id self, SEL, UIWebView*, NSURLRequest* request, UIWebViewNavigationType)
 | 
			
		||||
    {
 | 
			
		||||
        return getOwner (self)->pageAboutToLoad (nsStringToJuce ([[request URL] absoluteString]));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void webViewDidFinishLoad (id self, SEL, UIWebView* webView)
 | 
			
		||||
    {
 | 
			
		||||
        getOwner (self)->pageFinishedLoading (nsStringToJuce ([[[webView request] URL] absoluteString]));
 | 
			
		||||
            // WKWebView doesn't have an internal error page, so make a really simple one ourselves
 | 
			
		||||
            if (proceedToErrorPage)
 | 
			
		||||
                owner->goToURL ("data:text/plain;charset=UTF-8," + errorString);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class WebBrowserComponent::Pimpl
 | 
			
		||||
                                   #if JUCE_MAC
 | 
			
		||||
                                    : public NSViewComponent
 | 
			
		||||
                                   #else
 | 
			
		||||
                                    : public UIViewComponent
 | 
			
		||||
                                   #endif
 | 
			
		||||
struct WebViewBase
 | 
			
		||||
{
 | 
			
		||||
    virtual ~WebViewBase() = default;
 | 
			
		||||
 | 
			
		||||
    virtual void goToURL (const String&, const StringArray*, const MemoryBlock*) = 0;
 | 
			
		||||
    virtual void goBack() = 0;
 | 
			
		||||
    virtual void goForward() = 0;
 | 
			
		||||
    virtual void stop() = 0;
 | 
			
		||||
    virtual void refresh() = 0;
 | 
			
		||||
 | 
			
		||||
    virtual id getWebView() = 0;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#if JUCE_MAC
 | 
			
		||||
JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wdeprecated-declarations")
 | 
			
		||||
class WebViewImpl  : public WebViewBase
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (WebBrowserComponent* owner)
 | 
			
		||||
    WebViewImpl (WebBrowserComponent* owner)
 | 
			
		||||
    {
 | 
			
		||||
       #if JUCE_MAC
 | 
			
		||||
        static WebViewKeyEquivalentResponder webviewClass;
 | 
			
		||||
        webView = (WebView*) webviewClass.createInstance();
 | 
			
		||||
        static WebViewKeyEquivalentResponder<WebView> webviewClass;
 | 
			
		||||
 | 
			
		||||
        webView = [webView initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
 | 
			
		||||
                               frameName: nsEmptyString()
 | 
			
		||||
                               groupName: nsEmptyString()];
 | 
			
		||||
        webView.reset ([webviewClass.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)
 | 
			
		||||
                                                          frameName: nsEmptyString()
 | 
			
		||||
                                                          groupName: nsEmptyString()]);
 | 
			
		||||
 | 
			
		||||
        static DownloadClickDetectorClass cls;
 | 
			
		||||
        clickListener = [cls.createInstance() init];
 | 
			
		||||
        DownloadClickDetectorClass::setOwner (clickListener, owner);
 | 
			
		||||
        clickListener.reset ([cls.createInstance() init]);
 | 
			
		||||
        DownloadClickDetectorClass::setOwner (clickListener.get(), owner);
 | 
			
		||||
 | 
			
		||||
        [webView setPolicyDelegate:    clickListener];
 | 
			
		||||
        [webView setFrameLoadDelegate: clickListener];
 | 
			
		||||
        [webView setUIDelegate:        clickListener];
 | 
			
		||||
       #else
 | 
			
		||||
        webView = [[UIWebView alloc] initWithFrame: CGRectMake (0, 0, 1.0f, 1.0f)];
 | 
			
		||||
 | 
			
		||||
        static WebViewDelegateClass cls;
 | 
			
		||||
        webViewDelegate = [cls.createInstance() init];
 | 
			
		||||
        WebViewDelegateClass::setOwner (webViewDelegate, owner);
 | 
			
		||||
 | 
			
		||||
        [webView setDelegate: webViewDelegate];
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        setView (webView);
 | 
			
		||||
        [webView.get() setPolicyDelegate:    clickListener.get()];
 | 
			
		||||
        [webView.get() setFrameLoadDelegate: clickListener.get()];
 | 
			
		||||
        [webView.get() setUIDelegate:        clickListener.get()];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl()
 | 
			
		||||
    ~WebViewImpl() override
 | 
			
		||||
    {
 | 
			
		||||
       #if JUCE_MAC
 | 
			
		||||
        [webView setPolicyDelegate:    nil];
 | 
			
		||||
        [webView setFrameLoadDelegate: nil];
 | 
			
		||||
        [webView setUIDelegate:        nil];
 | 
			
		||||
 | 
			
		||||
        [clickListener release];
 | 
			
		||||
       #else
 | 
			
		||||
        [webView setDelegate: nil];
 | 
			
		||||
        [webViewDelegate release];
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        setView (nil);
 | 
			
		||||
        [webView.get() setPolicyDelegate:    nil];
 | 
			
		||||
        [webView.get() setFrameLoadDelegate: nil];
 | 
			
		||||
        [webView.get() setUIDelegate:        nil];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void goToURL (const String& url,
 | 
			
		||||
                  const StringArray* headers,
 | 
			
		||||
                  const MemoryBlock* postData)
 | 
			
		||||
                  const MemoryBlock* postData) override
 | 
			
		||||
    {
 | 
			
		||||
        if (url.trimStart().startsWithIgnoreCase ("javascript:"))
 | 
			
		||||
        {
 | 
			
		||||
            [webView stringByEvaluatingJavaScriptFromString: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))];
 | 
			
		||||
            [webView.get() stringByEvaluatingJavaScriptFromString: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))];
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -623,51 +466,146 @@ public:
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if (NSMutableURLRequest* request = getRequest())
 | 
			
		||||
        {
 | 
			
		||||
           #if JUCE_MAC
 | 
			
		||||
            [[webView mainFrame] loadRequest: request];
 | 
			
		||||
           #else
 | 
			
		||||
            [webView loadRequest: request];
 | 
			
		||||
           #endif
 | 
			
		||||
 | 
			
		||||
           #if JUCE_IOS
 | 
			
		||||
            [webView setScalesPageToFit: YES];
 | 
			
		||||
           #endif
 | 
			
		||||
        }
 | 
			
		||||
            [[webView.get() mainFrame] loadRequest: request];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void goBack()       { [webView goBack]; }
 | 
			
		||||
    void goForward()    { [webView goForward]; }
 | 
			
		||||
    void goBack() override      { [webView.get() goBack]; }
 | 
			
		||||
    void goForward() override   { [webView.get() goForward]; }
 | 
			
		||||
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    void stop()         { [webView stopLoading: nil]; }
 | 
			
		||||
    void refresh()      { [webView reload: nil]; }
 | 
			
		||||
   #else
 | 
			
		||||
    void stop()         { [webView stopLoading]; }
 | 
			
		||||
    void refresh()      { [webView reload]; }
 | 
			
		||||
   #endif
 | 
			
		||||
    void stop() override        { [webView.get() stopLoading: nil]; }
 | 
			
		||||
    void refresh() override     { [webView.get() reload: nil]; }
 | 
			
		||||
 | 
			
		||||
    id getWebView() override    { return webView.get(); }
 | 
			
		||||
 | 
			
		||||
    void mouseMove (const MouseEvent&)
 | 
			
		||||
    {
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wundeclared-selector")
 | 
			
		||||
        // WebKit doesn't capture mouse-moves itself, so it seems the only way to make
 | 
			
		||||
        // them work is to push them via this non-public method..
 | 
			
		||||
        if ([webView respondsToSelector: @selector (_updateMouseoverWithFakeEvent)])
 | 
			
		||||
            [webView performSelector:    @selector (_updateMouseoverWithFakeEvent)];
 | 
			
		||||
        if ([webView.get() respondsToSelector: @selector (_updateMouseoverWithFakeEvent)])
 | 
			
		||||
            [webView.get() performSelector:    @selector (_updateMouseoverWithFakeEvent)];
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
   #if JUCE_MAC
 | 
			
		||||
    WebView* webView = nil;
 | 
			
		||||
    id clickListener;
 | 
			
		||||
   #else
 | 
			
		||||
    UIWebView* webView = nil;
 | 
			
		||||
    id webViewDelegate;
 | 
			
		||||
   #endif
 | 
			
		||||
    ObjCObjectHandle<WebView*> webView;
 | 
			
		||||
    ObjCObjectHandle<id> clickListener;
 | 
			
		||||
};
 | 
			
		||||
JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
class API_AVAILABLE (macos (10.11)) WKWebViewImpl : public WebViewBase
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    WKWebViewImpl (WebBrowserComponent* owner)
 | 
			
		||||
    {
 | 
			
		||||
        #if JUCE_MAC
 | 
			
		||||
         static WebViewKeyEquivalentResponder<WKWebView> webviewClass;
 | 
			
		||||
 | 
			
		||||
         webView.reset ([webviewClass.createInstance() initWithFrame: NSMakeRect (0, 0, 100.0f, 100.0f)]);
 | 
			
		||||
        #else
 | 
			
		||||
         webView.reset ([[WKWebView alloc] initWithFrame: CGRectMake (0, 0, 100.0f, 100.0f)]);
 | 
			
		||||
        #endif
 | 
			
		||||
 | 
			
		||||
         static WebViewDelegateClass cls;
 | 
			
		||||
         webViewDelegate.reset ([cls.createInstance() init]);
 | 
			
		||||
         WebViewDelegateClass::setOwner (webViewDelegate.get(), owner);
 | 
			
		||||
 | 
			
		||||
         [webView.get() setNavigationDelegate: webViewDelegate.get()];
 | 
			
		||||
         [webView.get() setUIDelegate:         webViewDelegate.get()];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~WKWebViewImpl() override
 | 
			
		||||
    {
 | 
			
		||||
        [webView.get() setNavigationDelegate: nil];
 | 
			
		||||
        [webView.get() setUIDelegate:         nil];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void goToURL (const String& url,
 | 
			
		||||
                  const StringArray* headers,
 | 
			
		||||
                  const MemoryBlock* postData) override
 | 
			
		||||
    {
 | 
			
		||||
        auto trimmed = url.trimStart();
 | 
			
		||||
 | 
			
		||||
        if (trimmed.startsWithIgnoreCase ("javascript:"))
 | 
			
		||||
        {
 | 
			
		||||
            [webView.get() evaluateJavaScript: juceStringToNS (url.fromFirstOccurrenceOf (":", false, false))
 | 
			
		||||
                            completionHandler: nil];
 | 
			
		||||
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        stop();
 | 
			
		||||
 | 
			
		||||
        if (trimmed.startsWithIgnoreCase ("file:"))
 | 
			
		||||
        {
 | 
			
		||||
            auto file = URL (url).getLocalFile();
 | 
			
		||||
 | 
			
		||||
            if (NSURL* nsUrl = [NSURL fileURLWithPath: juceStringToNS (file.getFullPathName())])
 | 
			
		||||
                [webView.get() loadFileURL: appendParametersToFileURL (url, nsUrl) allowingReadAccessToURL: nsUrl];
 | 
			
		||||
        }
 | 
			
		||||
        else if (NSMutableURLRequest* request = getRequestForURL (url, headers, postData))
 | 
			
		||||
        {
 | 
			
		||||
            [webView.get() loadRequest: request];
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void goBack() override      { [webView.get() goBack]; }
 | 
			
		||||
    void goForward() override   { [webView.get() goForward]; }
 | 
			
		||||
 | 
			
		||||
    void stop() override        { [webView.get() stopLoading]; }
 | 
			
		||||
    void refresh() override     { [webView.get() reload]; }
 | 
			
		||||
 | 
			
		||||
    id getWebView() override    { return webView.get(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    ObjCObjectHandle<WKWebView*> webView;
 | 
			
		||||
    ObjCObjectHandle<id> webViewDelegate;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
#endif
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class WebBrowserComponent::Pimpl
 | 
			
		||||
                                   #if JUCE_MAC
 | 
			
		||||
                                    : public NSViewComponent
 | 
			
		||||
                                   #else
 | 
			
		||||
                                    : public UIViewComponent
 | 
			
		||||
                                   #endif
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (WebBrowserComponent* owner)
 | 
			
		||||
    {
 | 
			
		||||
        if (@available (macOS 10.11, *))
 | 
			
		||||
            webView = std::make_unique<WKWebViewImpl> (owner);
 | 
			
		||||
       #if JUCE_MAC
 | 
			
		||||
        else
 | 
			
		||||
            webView = std::make_unique<WebViewImpl> (owner);
 | 
			
		||||
       #endif
 | 
			
		||||
 | 
			
		||||
        setView (webView->getWebView());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl()
 | 
			
		||||
    {
 | 
			
		||||
        webView = nullptr;
 | 
			
		||||
        setView (nil);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void goToURL (const String& url,
 | 
			
		||||
                  const StringArray* headers,
 | 
			
		||||
                  const MemoryBlock* postData)
 | 
			
		||||
    {
 | 
			
		||||
        webView->goToURL (url, headers, postData);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void goBack()      { webView->goBack(); }
 | 
			
		||||
    void goForward()   { webView->goForward(); }
 | 
			
		||||
 | 
			
		||||
    void stop()        { webView->stop(); }
 | 
			
		||||
    void refresh()     { webView->refresh(); }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::unique_ptr<WebViewBase> webView;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden)
 | 
			
		||||
@@ -678,9 +616,7 @@ WebBrowserComponent::WebBrowserComponent (bool unloadWhenHidden)
 | 
			
		||||
    addAndMakeVisible (browser.get());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
WebBrowserComponent::~WebBrowserComponent()
 | 
			
		||||
{
 | 
			
		||||
}
 | 
			
		||||
WebBrowserComponent::~WebBrowserComponent() = default;
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void WebBrowserComponent::goToURL (const String& url,
 | 
			
		||||
 
 | 
			
		||||
@@ -1,496 +1,497 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
extern int64 getMouseEventTime();
 | 
			
		||||
 | 
			
		||||
JUCE_DECLARE_UUID_GETTER (IOleObject,       "00000112-0000-0000-C000-000000000046")
 | 
			
		||||
JUCE_DECLARE_UUID_GETTER (IOleWindow,       "00000114-0000-0000-C000-000000000046")
 | 
			
		||||
JUCE_DECLARE_UUID_GETTER (IOleInPlaceSite,  "00000119-0000-0000-C000-000000000046")
 | 
			
		||||
 | 
			
		||||
namespace ActiveXHelpers
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceIStorage   : public ComBaseClassHelper<IStorage>
 | 
			
		||||
    {
 | 
			
		||||
        JuceIStorage() {}
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT CreateStream (const WCHAR*, DWORD, DWORD, DWORD, IStream**)           { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT OpenStream (const WCHAR*, void*, DWORD, DWORD, IStream**)             { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT CreateStorage (const WCHAR*, DWORD, DWORD, DWORD, IStorage**)         { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT OpenStorage (const WCHAR*, IStorage*, DWORD, SNB, DWORD, IStorage**)  { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT CopyTo (DWORD, IID const*, SNB, IStorage*)                            { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT MoveElementTo (const OLECHAR*,IStorage*, const OLECHAR*, DWORD)       { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT Commit (DWORD)                                                        { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT Revert()                                                              { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT EnumElements (DWORD, void*, DWORD, IEnumSTATSTG**)                    { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT DestroyElement (const OLECHAR*)                                       { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT RenameElement (const WCHAR*, const WCHAR*)                            { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetElementTimes (const WCHAR*, FILETIME const*, FILETIME const*, FILETIME const*)    { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetClass (REFCLSID)                                                   { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT SetStateBits (DWORD, DWORD)                                           { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT Stat (STATSTG*, DWORD)                                                { return E_NOTIMPL; }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceOleInPlaceFrame   : public ComBaseClassHelper<IOleInPlaceFrame>
 | 
			
		||||
    {
 | 
			
		||||
        JuceOleInPlaceFrame (HWND hwnd)   : window (hwnd) {}
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetWindow (HWND* lphwnd)                                 { *lphwnd = window; return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT ContextSensitiveHelp (BOOL)                              { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT GetBorder (LPRECT)                                       { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT RequestBorderSpace (LPCBORDERWIDTHS)                     { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetBorderSpace (LPCBORDERWIDTHS)                         { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetActiveObject (IOleInPlaceActiveObject* a, LPCOLESTR)  { activeObject = a; return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT InsertMenus (HMENU, LPOLEMENUGROUPWIDTHS)                { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetMenu (HMENU, HOLEMENU, HWND)                          { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT RemoveMenus (HMENU)                                      { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetStatusText (LPCOLESTR)                                { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT EnableModeless (BOOL)                                    { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT TranslateAccelerator (LPMSG, WORD)                       { return E_NOTIMPL; }
 | 
			
		||||
 | 
			
		||||
        HRESULT OfferKeyTranslation (LPMSG lpmsg)
 | 
			
		||||
        {
 | 
			
		||||
            if (activeObject != nullptr)
 | 
			
		||||
                return activeObject->TranslateAcceleratorW (lpmsg);
 | 
			
		||||
 | 
			
		||||
            return S_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        HWND window;
 | 
			
		||||
        ComSmartPtr<IOleInPlaceActiveObject> activeObject;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceIOleInPlaceSite   : public ComBaseClassHelper<IOleInPlaceSite>
 | 
			
		||||
    {
 | 
			
		||||
        JuceIOleInPlaceSite (HWND hwnd)
 | 
			
		||||
            : window (hwnd),
 | 
			
		||||
              frame (new JuceOleInPlaceFrame (window))
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        ~JuceIOleInPlaceSite()
 | 
			
		||||
        {
 | 
			
		||||
            frame->Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetWindow (HWND* lphwnd)      { *lphwnd = window; return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT ContextSensitiveHelp (BOOL)   { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT CanInPlaceActivate()          { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT OnInPlaceActivate()           { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT OnUIActivate()                { return S_OK; }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetWindowContext (LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc, LPRECT, LPRECT, LPOLEINPLACEFRAMEINFO lpFrameInfo)
 | 
			
		||||
        {
 | 
			
		||||
            /* Note: If you call AddRef on the frame here, then some types of object (e.g. web browser control) cause leaks..
 | 
			
		||||
               If you don't call AddRef then others crash (e.g. QuickTime).. Bit of a catch-22, so letting it leak is probably preferable.
 | 
			
		||||
            */
 | 
			
		||||
            if (lplpFrame != nullptr) { frame->AddRef(); *lplpFrame = frame; }
 | 
			
		||||
            if (lplpDoc != nullptr)   *lplpDoc = nullptr;
 | 
			
		||||
            lpFrameInfo->fMDIApp = FALSE;
 | 
			
		||||
            lpFrameInfo->hwndFrame = window;
 | 
			
		||||
            lpFrameInfo->haccel = nullptr;
 | 
			
		||||
            lpFrameInfo->cAccelEntries = 0;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Scroll (SIZE)                 { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT OnUIDeactivate (BOOL)         { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT OnInPlaceDeactivate()         { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT DiscardUndoState()            { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT DeactivateAndUndo()           { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT OnPosRectChange (LPCRECT)     { return S_OK; }
 | 
			
		||||
 | 
			
		||||
        LRESULT offerEventToActiveXControl (::MSG& msg)
 | 
			
		||||
        {
 | 
			
		||||
            if (frame != nullptr)
 | 
			
		||||
                return frame->OfferKeyTranslation (&msg);
 | 
			
		||||
 | 
			
		||||
            return S_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        HWND window;
 | 
			
		||||
        JuceOleInPlaceFrame* frame;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceIOleClientSite  : public ComBaseClassHelper<IOleClientSite>
 | 
			
		||||
    {
 | 
			
		||||
        JuceIOleClientSite (HWND window)  : inplaceSite (new JuceIOleInPlaceSite (window))
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        ~JuceIOleClientSite()
 | 
			
		||||
        {
 | 
			
		||||
            inplaceSite->Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT QueryInterface (REFIID type, void** result)
 | 
			
		||||
        {
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
            if (type == __uuidof (IOleInPlaceSite))
 | 
			
		||||
            {
 | 
			
		||||
                inplaceSite->AddRef();
 | 
			
		||||
                *result = static_cast<IOleInPlaceSite*> (inplaceSite);
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ComBaseClassHelper <IOleClientSite>::QueryInterface (type, result);
 | 
			
		||||
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT SaveObject()                                  { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT GetMoniker (DWORD, DWORD, IMoniker**)         { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT GetContainer (LPOLECONTAINER* ppContainer)    { *ppContainer = nullptr; return E_NOINTERFACE; }
 | 
			
		||||
        JUCE_COMRESULT ShowObject()                                  { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT OnShowWindow (BOOL)                           { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT RequestNewObjectLayout()                      { return E_NOTIMPL; }
 | 
			
		||||
 | 
			
		||||
        LRESULT offerEventToActiveXControl (::MSG& msg)
 | 
			
		||||
        {
 | 
			
		||||
            if (inplaceSite != nullptr)
 | 
			
		||||
                return inplaceSite->offerEventToActiveXControl (msg);
 | 
			
		||||
 | 
			
		||||
            return S_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JuceIOleInPlaceSite* inplaceSite;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    static Array<ActiveXControlComponent*> activeXComps;
 | 
			
		||||
 | 
			
		||||
    static HWND getHWND (const ActiveXControlComponent* const component)
 | 
			
		||||
    {
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
        HWND hwnd = {};
 | 
			
		||||
        const IID iid = __uuidof (IOleWindow);
 | 
			
		||||
 | 
			
		||||
        if (auto* window = (IOleWindow*) component->queryInterface (&iid))
 | 
			
		||||
        {
 | 
			
		||||
            window->GetWindow (&hwnd);
 | 
			
		||||
            window->Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return hwnd;
 | 
			
		||||
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void offerActiveXMouseEventToPeer (ComponentPeer* peer, HWND hwnd, UINT message, LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        switch (message)
 | 
			
		||||
        {
 | 
			
		||||
            case WM_MOUSEMOVE:
 | 
			
		||||
            case WM_LBUTTONDOWN:
 | 
			
		||||
            case WM_MBUTTONDOWN:
 | 
			
		||||
            case WM_RBUTTONDOWN:
 | 
			
		||||
            case WM_LBUTTONUP:
 | 
			
		||||
            case WM_MBUTTONUP:
 | 
			
		||||
            case WM_RBUTTONUP:
 | 
			
		||||
            {
 | 
			
		||||
                RECT activeXRect, peerRect;
 | 
			
		||||
                GetWindowRect (hwnd, &activeXRect);
 | 
			
		||||
                GetWindowRect ((HWND) peer->getNativeHandle(), &peerRect);
 | 
			
		||||
 | 
			
		||||
                peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse,
 | 
			
		||||
                                        { (float) (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left),
 | 
			
		||||
                                          (float) (GET_Y_LPARAM (lParam) + activeXRect.top  - peerRect.top) },
 | 
			
		||||
                                        ComponentPeer::getCurrentModifiersRealtime(),
 | 
			
		||||
                                        MouseInputSource::invalidPressure,
 | 
			
		||||
                                        MouseInputSource::invalidOrientation,
 | 
			
		||||
                                        getMouseEventTime());
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class ActiveXControlComponent::Pimpl  : public ComponentMovementWatcher,
 | 
			
		||||
                                        public ComponentPeer::ScaleFactorListener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (HWND hwnd, ActiveXControlComponent& activeXComp)
 | 
			
		||||
        : ComponentMovementWatcher (&activeXComp),
 | 
			
		||||
          owner (activeXComp),
 | 
			
		||||
          storage (new ActiveXHelpers::JuceIStorage()),
 | 
			
		||||
          clientSite (new ActiveXHelpers::JuceIOleClientSite (hwnd))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl() override
 | 
			
		||||
    {
 | 
			
		||||
        if (control != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            control->Close (OLECLOSE_NOSAVE);
 | 
			
		||||
            control->Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        clientSite->Release();
 | 
			
		||||
        storage->Release();
 | 
			
		||||
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
            currentPeer->removeScaleFactorListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setControlBounds (Rectangle<int> newBounds) const
 | 
			
		||||
    {
 | 
			
		||||
        if (controlHWND != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = owner.getTopLevelComponent()->getPeer())
 | 
			
		||||
                newBounds = (newBounds.toDouble() * peer->getPlatformScaleFactor()).toNearestInt();
 | 
			
		||||
 | 
			
		||||
            MoveWindow (controlHWND, newBounds.getX(), newBounds.getY(), newBounds.getWidth(), newBounds.getHeight(), TRUE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setControlVisible (bool shouldBeVisible) const
 | 
			
		||||
    {
 | 
			
		||||
        if (controlHWND != nullptr)
 | 
			
		||||
            ShowWindow (controlHWND, shouldBeVisible ? SW_SHOWNA : SW_HIDE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    using ComponentMovementWatcher::componentMovedOrResized;
 | 
			
		||||
 | 
			
		||||
    void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* peer = owner.getTopLevelComponent()->getPeer())
 | 
			
		||||
            setControlBounds (peer->getAreaCoveredBy (owner));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentPeerChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
            currentPeer->removeScaleFactorListener (this);
 | 
			
		||||
 | 
			
		||||
        componentMovedOrResized (true, true);
 | 
			
		||||
 | 
			
		||||
        currentPeer = owner.getTopLevelComponent()->getPeer();
 | 
			
		||||
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
            currentPeer->addScaleFactorListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using ComponentMovementWatcher::componentVisibilityChanged;
 | 
			
		||||
 | 
			
		||||
    void componentVisibilityChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        setControlVisible (owner.isShowing());
 | 
			
		||||
        componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void nativeScaleFactorChanged (double /*newScaleFactor*/) override
 | 
			
		||||
    {
 | 
			
		||||
        componentMovedOrResized (true, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // intercepts events going to an activeX control, so we can sneakily use the mouse events
 | 
			
		||||
    static LRESULT CALLBACK activeXHookWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        for (auto* ax : ActiveXHelpers::activeXComps)
 | 
			
		||||
        {
 | 
			
		||||
            if (ax->control != nullptr && ax->control->controlHWND == hwnd)
 | 
			
		||||
            {
 | 
			
		||||
                switch (message)
 | 
			
		||||
                {
 | 
			
		||||
                    case WM_MOUSEMOVE:
 | 
			
		||||
                    case WM_LBUTTONDOWN:
 | 
			
		||||
                    case WM_MBUTTONDOWN:
 | 
			
		||||
                    case WM_RBUTTONDOWN:
 | 
			
		||||
                    case WM_LBUTTONUP:
 | 
			
		||||
                    case WM_MBUTTONUP:
 | 
			
		||||
                    case WM_RBUTTONUP:
 | 
			
		||||
                    case WM_LBUTTONDBLCLK:
 | 
			
		||||
                    case WM_MBUTTONDBLCLK:
 | 
			
		||||
                    case WM_RBUTTONDBLCLK:
 | 
			
		||||
                        if (ax->isShowing())
 | 
			
		||||
                        {
 | 
			
		||||
                            if (auto* peer = ax->getPeer())
 | 
			
		||||
                            {
 | 
			
		||||
                                ActiveXHelpers::offerActiveXMouseEventToPeer (peer, hwnd, message, lParam);
 | 
			
		||||
 | 
			
		||||
                                if (! ax->areMouseEventsAllowed())
 | 
			
		||||
                                    return 0;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    default:
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return CallWindowProc (ax->control->originalWndProc, hwnd, message, wParam, lParam);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return DefWindowProc (hwnd, message, wParam, lParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ActiveXControlComponent& owner;
 | 
			
		||||
    ComponentPeer* currentPeer = nullptr;
 | 
			
		||||
    HWND controlHWND = {};
 | 
			
		||||
    IStorage* storage = nullptr;
 | 
			
		||||
    ActiveXHelpers::JuceIOleClientSite* clientSite = nullptr;
 | 
			
		||||
    IOleObject* control = nullptr;
 | 
			
		||||
    WNDPROC originalWndProc = nullptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
ActiveXControlComponent::ActiveXControlComponent()
 | 
			
		||||
{
 | 
			
		||||
    ActiveXHelpers::activeXComps.add (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActiveXControlComponent::~ActiveXControlComponent()
 | 
			
		||||
{
 | 
			
		||||
    deleteControl();
 | 
			
		||||
    ActiveXHelpers::activeXComps.removeFirstMatchingValue (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ActiveXControlComponent::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    if (control == nullptr)
 | 
			
		||||
        g.fillAll (Colours::lightgrey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ActiveXControlComponent::createControl (const void* controlIID)
 | 
			
		||||
{
 | 
			
		||||
    deleteControl();
 | 
			
		||||
 | 
			
		||||
    if (auto* peer = getPeer())
 | 
			
		||||
    {
 | 
			
		||||
        auto controlBounds = peer->getAreaCoveredBy (*this);
 | 
			
		||||
        auto hwnd = (HWND) peer->getNativeHandle();
 | 
			
		||||
 | 
			
		||||
        std::unique_ptr<Pimpl> newControl (new Pimpl (hwnd, *this));
 | 
			
		||||
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
        HRESULT hr = OleCreate (*(const IID*) controlIID, __uuidof (IOleObject), 1 /*OLERENDER_DRAW*/, nullptr,
 | 
			
		||||
                                newControl->clientSite, newControl->storage,
 | 
			
		||||
                                (void**) &(newControl->control));
 | 
			
		||||
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
        if (hr == S_OK)
 | 
			
		||||
        {
 | 
			
		||||
            newControl->control->SetHostNames (L"JUCE", nullptr);
 | 
			
		||||
 | 
			
		||||
            if (OleSetContainedObject (newControl->control, TRUE) == S_OK)
 | 
			
		||||
            {
 | 
			
		||||
                RECT rect;
 | 
			
		||||
                rect.left   = controlBounds.getX();
 | 
			
		||||
                rect.top    = controlBounds.getY();
 | 
			
		||||
                rect.right  = controlBounds.getRight();
 | 
			
		||||
                rect.bottom = controlBounds.getBottom();
 | 
			
		||||
 | 
			
		||||
                if (newControl->control->DoVerb (OLEIVERB_SHOW, nullptr, newControl->clientSite, 0, hwnd, &rect) == S_OK)
 | 
			
		||||
                {
 | 
			
		||||
                    control.reset (newControl.release());
 | 
			
		||||
                    control->controlHWND = ActiveXHelpers::getHWND (this);
 | 
			
		||||
 | 
			
		||||
                    if (control->controlHWND != nullptr)
 | 
			
		||||
                    {
 | 
			
		||||
                        control->setControlBounds (controlBounds);
 | 
			
		||||
 | 
			
		||||
                        control->originalWndProc = (WNDPROC) GetWindowLongPtr ((HWND) control->controlHWND, GWLP_WNDPROC);
 | 
			
		||||
                        SetWindowLongPtr ((HWND) control->controlHWND, GWLP_WNDPROC, (LONG_PTR) Pimpl::activeXHookWndProc);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // the component must have already been added to a real window when you call this!
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ActiveXControlComponent::deleteControl()
 | 
			
		||||
{
 | 
			
		||||
    control = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* ActiveXControlComponent::queryInterface (const void* iid) const
 | 
			
		||||
{
 | 
			
		||||
    void* result = nullptr;
 | 
			
		||||
 | 
			
		||||
    if (control != nullptr && control->control != nullptr
 | 
			
		||||
         && SUCCEEDED (control->control->QueryInterface (*(const IID*) iid, &result)))
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ActiveXControlComponent::setMouseEventsAllowed (const bool eventsCanReachControl)
 | 
			
		||||
{
 | 
			
		||||
    mouseEventsAllowed = eventsCanReachControl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
intptr_t ActiveXControlComponent::offerEventToActiveXControl (void* ptr)
 | 
			
		||||
{
 | 
			
		||||
    if (control != nullptr && control->clientSite != nullptr)
 | 
			
		||||
        return (intptr_t) control->clientSite->offerEventToActiveXControl (*reinterpret_cast<::MSG*> (ptr));
 | 
			
		||||
 | 
			
		||||
    return S_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
intptr_t ActiveXControlComponent::offerEventToActiveXControlStatic (void* ptr)
 | 
			
		||||
{
 | 
			
		||||
    for (auto* ax : ActiveXHelpers::activeXComps)
 | 
			
		||||
    {
 | 
			
		||||
        auto result = ax->offerEventToActiveXControl (ptr);
 | 
			
		||||
 | 
			
		||||
        if (result != S_FALSE)
 | 
			
		||||
            return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return S_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LRESULT juce_offerEventToActiveXControl (::MSG& msg)
 | 
			
		||||
{
 | 
			
		||||
    if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
 | 
			
		||||
        return ActiveXControlComponent::offerEventToActiveXControlStatic (&msg);
 | 
			
		||||
 | 
			
		||||
    return S_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
extern int64 getMouseEventTime();
 | 
			
		||||
 | 
			
		||||
JUCE_DECLARE_UUID_GETTER (IOleObject,       "00000112-0000-0000-C000-000000000046")
 | 
			
		||||
JUCE_DECLARE_UUID_GETTER (IOleWindow,       "00000114-0000-0000-C000-000000000046")
 | 
			
		||||
JUCE_DECLARE_UUID_GETTER (IOleInPlaceSite,  "00000119-0000-0000-C000-000000000046")
 | 
			
		||||
 | 
			
		||||
namespace ActiveXHelpers
 | 
			
		||||
{
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceIStorage   : public ComBaseClassHelper<IStorage>
 | 
			
		||||
    {
 | 
			
		||||
        JuceIStorage() {}
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT CreateStream (const WCHAR*, DWORD, DWORD, DWORD, IStream**)           { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT OpenStream (const WCHAR*, void*, DWORD, DWORD, IStream**)             { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT CreateStorage (const WCHAR*, DWORD, DWORD, DWORD, IStorage**)         { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT OpenStorage (const WCHAR*, IStorage*, DWORD, SNB, DWORD, IStorage**)  { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT CopyTo (DWORD, IID const*, SNB, IStorage*)                            { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT MoveElementTo (const OLECHAR*,IStorage*, const OLECHAR*, DWORD)       { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT Commit (DWORD)                                                        { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT Revert()                                                              { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT EnumElements (DWORD, void*, DWORD, IEnumSTATSTG**)                    { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT DestroyElement (const OLECHAR*)                                       { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT RenameElement (const WCHAR*, const WCHAR*)                            { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetElementTimes (const WCHAR*, FILETIME const*, FILETIME const*, FILETIME const*)    { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetClass (REFCLSID)                                                   { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT SetStateBits (DWORD, DWORD)                                           { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT Stat (STATSTG*, DWORD)                                                { return E_NOTIMPL; }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceOleInPlaceFrame   : public ComBaseClassHelper<IOleInPlaceFrame>
 | 
			
		||||
    {
 | 
			
		||||
        JuceOleInPlaceFrame (HWND hwnd)   : window (hwnd) {}
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetWindow (HWND* lphwnd)                                 { *lphwnd = window; return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT ContextSensitiveHelp (BOOL)                              { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT GetBorder (LPRECT)                                       { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT RequestBorderSpace (LPCBORDERWIDTHS)                     { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetBorderSpace (LPCBORDERWIDTHS)                         { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetActiveObject (IOleInPlaceActiveObject* a, LPCOLESTR)  { activeObject = a; return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT InsertMenus (HMENU, LPOLEMENUGROUPWIDTHS)                { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetMenu (HMENU, HOLEMENU, HWND)                          { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT RemoveMenus (HMENU)                                      { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT SetStatusText (LPCOLESTR)                                { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT EnableModeless (BOOL)                                    { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT TranslateAccelerator (LPMSG, WORD)                       { return E_NOTIMPL; }
 | 
			
		||||
 | 
			
		||||
        HRESULT OfferKeyTranslation (LPMSG lpmsg)
 | 
			
		||||
        {
 | 
			
		||||
            if (activeObject != nullptr)
 | 
			
		||||
                return activeObject->TranslateAcceleratorW (lpmsg);
 | 
			
		||||
 | 
			
		||||
            return S_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        HWND window;
 | 
			
		||||
        ComSmartPtr<IOleInPlaceActiveObject> activeObject;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceIOleInPlaceSite   : public ComBaseClassHelper<IOleInPlaceSite>
 | 
			
		||||
    {
 | 
			
		||||
        JuceIOleInPlaceSite (HWND hwnd)
 | 
			
		||||
            : window (hwnd),
 | 
			
		||||
              frame (new JuceOleInPlaceFrame (window))
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        ~JuceIOleInPlaceSite()
 | 
			
		||||
        {
 | 
			
		||||
            frame->Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetWindow (HWND* lphwnd)      { *lphwnd = window; return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT ContextSensitiveHelp (BOOL)   { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT CanInPlaceActivate()          { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT OnInPlaceActivate()           { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT OnUIActivate()                { return S_OK; }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT GetWindowContext (LPOLEINPLACEFRAME* lplpFrame, LPOLEINPLACEUIWINDOW* lplpDoc, LPRECT, LPRECT, LPOLEINPLACEFRAMEINFO lpFrameInfo)
 | 
			
		||||
        {
 | 
			
		||||
            /* Note: If you call AddRef on the frame here, then some types of object (e.g. web browser control) cause leaks..
 | 
			
		||||
               If you don't call AddRef then others crash (e.g. QuickTime).. Bit of a catch-22, so letting it leak is probably preferable.
 | 
			
		||||
            */
 | 
			
		||||
            if (lplpFrame != nullptr) { frame->AddRef(); *lplpFrame = frame; }
 | 
			
		||||
            if (lplpDoc != nullptr)   *lplpDoc = nullptr;
 | 
			
		||||
            lpFrameInfo->fMDIApp = FALSE;
 | 
			
		||||
            lpFrameInfo->hwndFrame = window;
 | 
			
		||||
            lpFrameInfo->haccel = nullptr;
 | 
			
		||||
            lpFrameInfo->cAccelEntries = 0;
 | 
			
		||||
            return S_OK;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT Scroll (SIZE)                 { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT OnUIDeactivate (BOOL)         { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT OnInPlaceDeactivate()         { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT DiscardUndoState()            { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT DeactivateAndUndo()           { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT OnPosRectChange (LPCRECT)     { return S_OK; }
 | 
			
		||||
 | 
			
		||||
        LRESULT offerEventToActiveXControl (::MSG& msg)
 | 
			
		||||
        {
 | 
			
		||||
            if (frame != nullptr)
 | 
			
		||||
                return frame->OfferKeyTranslation (&msg);
 | 
			
		||||
 | 
			
		||||
            return S_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        HWND window;
 | 
			
		||||
        JuceOleInPlaceFrame* frame;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    struct JuceIOleClientSite  : public ComBaseClassHelper<IOleClientSite>
 | 
			
		||||
    {
 | 
			
		||||
        JuceIOleClientSite (HWND window)  : inplaceSite (new JuceIOleInPlaceSite (window))
 | 
			
		||||
        {}
 | 
			
		||||
 | 
			
		||||
        ~JuceIOleClientSite()
 | 
			
		||||
        {
 | 
			
		||||
            inplaceSite->Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT QueryInterface (REFIID type, void** result)
 | 
			
		||||
        {
 | 
			
		||||
            JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
            if (type == __uuidof (IOleInPlaceSite))
 | 
			
		||||
            {
 | 
			
		||||
                inplaceSite->AddRef();
 | 
			
		||||
                *result = static_cast<IOleInPlaceSite*> (inplaceSite);
 | 
			
		||||
                return S_OK;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            return ComBaseClassHelper <IOleClientSite>::QueryInterface (type, result);
 | 
			
		||||
 | 
			
		||||
            JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JUCE_COMRESULT SaveObject()                                  { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT GetMoniker (DWORD, DWORD, IMoniker**)         { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT GetContainer (LPOLECONTAINER* ppContainer)    { *ppContainer = nullptr; return E_NOINTERFACE; }
 | 
			
		||||
        JUCE_COMRESULT ShowObject()                                  { return S_OK; }
 | 
			
		||||
        JUCE_COMRESULT OnShowWindow (BOOL)                           { return E_NOTIMPL; }
 | 
			
		||||
        JUCE_COMRESULT RequestNewObjectLayout()                      { return E_NOTIMPL; }
 | 
			
		||||
 | 
			
		||||
        LRESULT offerEventToActiveXControl (::MSG& msg)
 | 
			
		||||
        {
 | 
			
		||||
            if (inplaceSite != nullptr)
 | 
			
		||||
                return inplaceSite->offerEventToActiveXControl (msg);
 | 
			
		||||
 | 
			
		||||
            return S_FALSE;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        JuceIOleInPlaceSite* inplaceSite;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    static Array<ActiveXControlComponent*> activeXComps;
 | 
			
		||||
 | 
			
		||||
    static HWND getHWND (const ActiveXControlComponent* const component)
 | 
			
		||||
    {
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
        HWND hwnd = {};
 | 
			
		||||
        const IID iid = __uuidof (IOleWindow);
 | 
			
		||||
 | 
			
		||||
        if (auto* window = (IOleWindow*) component->queryInterface (&iid))
 | 
			
		||||
        {
 | 
			
		||||
            window->GetWindow (&hwnd);
 | 
			
		||||
            window->Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return hwnd;
 | 
			
		||||
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static void offerActiveXMouseEventToPeer (ComponentPeer* peer, HWND hwnd, UINT message, LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        switch (message)
 | 
			
		||||
        {
 | 
			
		||||
            case WM_MOUSEMOVE:
 | 
			
		||||
            case WM_LBUTTONDOWN:
 | 
			
		||||
            case WM_MBUTTONDOWN:
 | 
			
		||||
            case WM_RBUTTONDOWN:
 | 
			
		||||
            case WM_LBUTTONUP:
 | 
			
		||||
            case WM_MBUTTONUP:
 | 
			
		||||
            case WM_RBUTTONUP:
 | 
			
		||||
            {
 | 
			
		||||
                RECT activeXRect, peerRect;
 | 
			
		||||
                GetWindowRect (hwnd, &activeXRect);
 | 
			
		||||
                GetWindowRect ((HWND) peer->getNativeHandle(), &peerRect);
 | 
			
		||||
 | 
			
		||||
                peer->handleMouseEvent (MouseInputSource::InputSourceType::mouse,
 | 
			
		||||
                                        { (float) (GET_X_LPARAM (lParam) + activeXRect.left - peerRect.left),
 | 
			
		||||
                                          (float) (GET_Y_LPARAM (lParam) + activeXRect.top  - peerRect.top) },
 | 
			
		||||
                                        ComponentPeer::getCurrentModifiersRealtime(),
 | 
			
		||||
                                        MouseInputSource::defaultPressure,
 | 
			
		||||
                                        MouseInputSource::defaultOrientation,
 | 
			
		||||
                                        getMouseEventTime());
 | 
			
		||||
                break;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            default:
 | 
			
		||||
                break;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class ActiveXControlComponent::Pimpl  : public ComponentMovementWatcher,
 | 
			
		||||
                                        public ComponentPeer::ScaleFactorListener
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (HWND hwnd, ActiveXControlComponent& activeXComp)
 | 
			
		||||
        : ComponentMovementWatcher (&activeXComp),
 | 
			
		||||
          owner (activeXComp),
 | 
			
		||||
          storage (new ActiveXHelpers::JuceIStorage()),
 | 
			
		||||
          clientSite (new ActiveXHelpers::JuceIOleClientSite (hwnd))
 | 
			
		||||
    {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl() override
 | 
			
		||||
    {
 | 
			
		||||
        if (control != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            control->Close (OLECLOSE_NOSAVE);
 | 
			
		||||
            control->Release();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        clientSite->Release();
 | 
			
		||||
        storage->Release();
 | 
			
		||||
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
            currentPeer->removeScaleFactorListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setControlBounds (Rectangle<int> newBounds) const
 | 
			
		||||
    {
 | 
			
		||||
        if (controlHWND != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            if (auto* peer = owner.getTopLevelComponent()->getPeer())
 | 
			
		||||
                newBounds = (newBounds.toDouble() * peer->getPlatformScaleFactor()).toNearestInt();
 | 
			
		||||
 | 
			
		||||
            MoveWindow (controlHWND, newBounds.getX(), newBounds.getY(), newBounds.getWidth(), newBounds.getHeight(), TRUE);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setControlVisible (bool shouldBeVisible) const
 | 
			
		||||
    {
 | 
			
		||||
        if (controlHWND != nullptr)
 | 
			
		||||
            ShowWindow (controlHWND, shouldBeVisible ? SW_SHOWNA : SW_HIDE);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    //==============================================================================
 | 
			
		||||
    using ComponentMovementWatcher::componentMovedOrResized;
 | 
			
		||||
 | 
			
		||||
    void componentMovedOrResized (bool /*wasMoved*/, bool /*wasResized*/) override
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* peer = owner.getTopLevelComponent()->getPeer())
 | 
			
		||||
            setControlBounds (peer->getAreaCoveredBy (owner));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentPeerChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
            currentPeer->removeScaleFactorListener (this);
 | 
			
		||||
 | 
			
		||||
        componentMovedOrResized (true, true);
 | 
			
		||||
 | 
			
		||||
        currentPeer = owner.getTopLevelComponent()->getPeer();
 | 
			
		||||
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
            currentPeer->addScaleFactorListener (this);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using ComponentMovementWatcher::componentVisibilityChanged;
 | 
			
		||||
 | 
			
		||||
    void componentVisibilityChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        setControlVisible (owner.isShowing());
 | 
			
		||||
        componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void nativeScaleFactorChanged (double /*newScaleFactor*/) override
 | 
			
		||||
    {
 | 
			
		||||
        componentMovedOrResized (true, true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // intercepts events going to an activeX control, so we can sneakily use the mouse events
 | 
			
		||||
    static LRESULT CALLBACK activeXHookWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        for (auto* ax : ActiveXHelpers::activeXComps)
 | 
			
		||||
        {
 | 
			
		||||
            if (ax->control != nullptr && ax->control->controlHWND == hwnd)
 | 
			
		||||
            {
 | 
			
		||||
                switch (message)
 | 
			
		||||
                {
 | 
			
		||||
                    case WM_MOUSEMOVE:
 | 
			
		||||
                    case WM_LBUTTONDOWN:
 | 
			
		||||
                    case WM_MBUTTONDOWN:
 | 
			
		||||
                    case WM_RBUTTONDOWN:
 | 
			
		||||
                    case WM_LBUTTONUP:
 | 
			
		||||
                    case WM_MBUTTONUP:
 | 
			
		||||
                    case WM_RBUTTONUP:
 | 
			
		||||
                    case WM_LBUTTONDBLCLK:
 | 
			
		||||
                    case WM_MBUTTONDBLCLK:
 | 
			
		||||
                    case WM_RBUTTONDBLCLK:
 | 
			
		||||
                        if (ax->isShowing())
 | 
			
		||||
                        {
 | 
			
		||||
                            if (auto* peer = ax->getPeer())
 | 
			
		||||
                            {
 | 
			
		||||
                                ActiveXHelpers::offerActiveXMouseEventToPeer (peer, hwnd, message, lParam);
 | 
			
		||||
 | 
			
		||||
                                if (! ax->areMouseEventsAllowed())
 | 
			
		||||
                                    return 0;
 | 
			
		||||
                            }
 | 
			
		||||
                        }
 | 
			
		||||
                        break;
 | 
			
		||||
 | 
			
		||||
                    default:
 | 
			
		||||
                        break;
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                return CallWindowProc (ax->control->originalWndProc, hwnd, message, wParam, lParam);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return DefWindowProc (hwnd, message, wParam, lParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ActiveXControlComponent& owner;
 | 
			
		||||
    ComponentPeer* currentPeer = nullptr;
 | 
			
		||||
    HWND controlHWND = {};
 | 
			
		||||
    IStorage* storage = nullptr;
 | 
			
		||||
    ActiveXHelpers::JuceIOleClientSite* clientSite = nullptr;
 | 
			
		||||
    IOleObject* control = nullptr;
 | 
			
		||||
    WNDPROC originalWndProc = nullptr;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
ActiveXControlComponent::ActiveXControlComponent()
 | 
			
		||||
{
 | 
			
		||||
    ActiveXHelpers::activeXComps.add (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
ActiveXControlComponent::~ActiveXControlComponent()
 | 
			
		||||
{
 | 
			
		||||
    deleteControl();
 | 
			
		||||
    ActiveXHelpers::activeXComps.removeFirstMatchingValue (this);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ActiveXControlComponent::paint (Graphics& g)
 | 
			
		||||
{
 | 
			
		||||
    if (control == nullptr)
 | 
			
		||||
        g.fillAll (Colours::lightgrey);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool ActiveXControlComponent::createControl (const void* controlIID)
 | 
			
		||||
{
 | 
			
		||||
    deleteControl();
 | 
			
		||||
 | 
			
		||||
    if (auto* peer = getPeer())
 | 
			
		||||
    {
 | 
			
		||||
        auto controlBounds = peer->getAreaCoveredBy (*this);
 | 
			
		||||
        auto hwnd = (HWND) peer->getNativeHandle();
 | 
			
		||||
 | 
			
		||||
        std::unique_ptr<Pimpl> newControl (new Pimpl (hwnd, *this));
 | 
			
		||||
 | 
			
		||||
        JUCE_BEGIN_IGNORE_WARNINGS_GCC_LIKE ("-Wlanguage-extension-token")
 | 
			
		||||
 | 
			
		||||
        HRESULT hr = OleCreate (*(const IID*) controlIID, __uuidof (IOleObject), 1 /*OLERENDER_DRAW*/, nullptr,
 | 
			
		||||
                                newControl->clientSite, newControl->storage,
 | 
			
		||||
                                (void**) &(newControl->control));
 | 
			
		||||
 | 
			
		||||
        JUCE_END_IGNORE_WARNINGS_GCC_LIKE
 | 
			
		||||
 | 
			
		||||
        if (hr == S_OK)
 | 
			
		||||
        {
 | 
			
		||||
            newControl->control->SetHostNames (L"JUCE", nullptr);
 | 
			
		||||
 | 
			
		||||
            if (OleSetContainedObject (newControl->control, TRUE) == S_OK)
 | 
			
		||||
            {
 | 
			
		||||
                RECT rect;
 | 
			
		||||
                rect.left   = controlBounds.getX();
 | 
			
		||||
                rect.top    = controlBounds.getY();
 | 
			
		||||
                rect.right  = controlBounds.getRight();
 | 
			
		||||
                rect.bottom = controlBounds.getBottom();
 | 
			
		||||
 | 
			
		||||
                if (newControl->control->DoVerb (OLEIVERB_SHOW, nullptr, newControl->clientSite, 0, hwnd, &rect) == S_OK)
 | 
			
		||||
                {
 | 
			
		||||
                    control.reset (newControl.release());
 | 
			
		||||
                    control->controlHWND = ActiveXHelpers::getHWND (this);
 | 
			
		||||
 | 
			
		||||
                    if (control->controlHWND != nullptr)
 | 
			
		||||
                    {
 | 
			
		||||
                        control->setControlBounds (controlBounds);
 | 
			
		||||
 | 
			
		||||
                        control->originalWndProc = (WNDPROC) GetWindowLongPtr ((HWND) control->controlHWND, GWLP_WNDPROC);
 | 
			
		||||
                        SetWindowLongPtr ((HWND) control->controlHWND, GWLP_WNDPROC, (LONG_PTR) Pimpl::activeXHookWndProc);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    return true;
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        // the component must have already been added to a real window when you call this!
 | 
			
		||||
        jassertfalse;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return false;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ActiveXControlComponent::deleteControl()
 | 
			
		||||
{
 | 
			
		||||
    control = nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* ActiveXControlComponent::queryInterface (const void* iid) const
 | 
			
		||||
{
 | 
			
		||||
    void* result = nullptr;
 | 
			
		||||
 | 
			
		||||
    if (control != nullptr && control->control != nullptr
 | 
			
		||||
         && SUCCEEDED (control->control->QueryInterface (*(const IID*) iid, &result)))
 | 
			
		||||
        return result;
 | 
			
		||||
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void ActiveXControlComponent::setMouseEventsAllowed (const bool eventsCanReachControl)
 | 
			
		||||
{
 | 
			
		||||
    mouseEventsAllowed = eventsCanReachControl;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
intptr_t ActiveXControlComponent::offerEventToActiveXControl (void* ptr)
 | 
			
		||||
{
 | 
			
		||||
    if (control != nullptr && control->clientSite != nullptr)
 | 
			
		||||
        return (intptr_t) control->clientSite->offerEventToActiveXControl (*reinterpret_cast<::MSG*> (ptr));
 | 
			
		||||
 | 
			
		||||
    return S_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
intptr_t ActiveXControlComponent::offerEventToActiveXControlStatic (void* ptr)
 | 
			
		||||
{
 | 
			
		||||
    for (auto* ax : ActiveXHelpers::activeXComps)
 | 
			
		||||
    {
 | 
			
		||||
        auto result = ax->offerEventToActiveXControl (ptr);
 | 
			
		||||
 | 
			
		||||
        if (result != S_FALSE)
 | 
			
		||||
            return result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return S_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
LRESULT juce_offerEventToActiveXControl (::MSG& msg);
 | 
			
		||||
LRESULT juce_offerEventToActiveXControl (::MSG& msg)
 | 
			
		||||
{
 | 
			
		||||
    if (msg.message >= WM_KEYFIRST && msg.message <= WM_KEYLAST)
 | 
			
		||||
        return ActiveXControlComponent::offerEventToActiveXControlStatic (&msg);
 | 
			
		||||
 | 
			
		||||
    return S_FALSE;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,175 +1,181 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class HWNDComponent::Pimpl  : public ComponentMovementWatcher
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (HWND h, Component& comp)
 | 
			
		||||
        : ComponentMovementWatcher (&comp),
 | 
			
		||||
          hwnd (h),
 | 
			
		||||
          owner (comp)
 | 
			
		||||
    {
 | 
			
		||||
        if (owner.isShowing())
 | 
			
		||||
            componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl() override
 | 
			
		||||
    {
 | 
			
		||||
        removeFromParent();
 | 
			
		||||
        DestroyWindow (hwnd);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentMovedOrResized (bool wasMoved, bool wasResized) override
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* peer = owner.getTopLevelComponent()->getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            auto area = (peer->getAreaCoveredBy (owner).toFloat() * peer->getPlatformScaleFactor()).getSmallestIntegerContainer();
 | 
			
		||||
 | 
			
		||||
            UINT flagsToSend =  SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER;
 | 
			
		||||
 | 
			
		||||
            if (! wasMoved)   flagsToSend |= SWP_NOMOVE;
 | 
			
		||||
            if (! wasResized) flagsToSend |= SWP_NOSIZE;
 | 
			
		||||
 | 
			
		||||
            ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
 | 
			
		||||
 | 
			
		||||
            SetWindowPos (hwnd, nullptr, area.getX(), area.getY(), area.getWidth(), area.getHeight(), flagsToSend);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using ComponentMovementWatcher::componentMovedOrResized;
 | 
			
		||||
 | 
			
		||||
    void componentPeerChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        auto* peer = owner.getPeer();
 | 
			
		||||
 | 
			
		||||
        if (currentPeer != peer)
 | 
			
		||||
        {
 | 
			
		||||
            removeFromParent();
 | 
			
		||||
            currentPeer = peer;
 | 
			
		||||
 | 
			
		||||
            addToParent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto isShowing = owner.isShowing();
 | 
			
		||||
 | 
			
		||||
        ShowWindow (hwnd, isShowing ? SW_SHOWNA : SW_HIDE);
 | 
			
		||||
 | 
			
		||||
        if (isShowing)
 | 
			
		||||
            InvalidateRect (hwnd, nullptr, 0);
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
    void componentVisibilityChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using ComponentMovementWatcher::componentVisibilityChanged;
 | 
			
		||||
 | 
			
		||||
    void componentBroughtToFront (Component& comp) override
 | 
			
		||||
    {
 | 
			
		||||
        ComponentMovementWatcher::componentBroughtToFront (comp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rectangle<int> getHWNDBounds() const
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* peer = owner.getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
 | 
			
		||||
 | 
			
		||||
            RECT r;
 | 
			
		||||
            GetWindowRect (hwnd, &r);
 | 
			
		||||
            Rectangle<int> windowRectangle (r.right - r.left, r.bottom - r.top);
 | 
			
		||||
 | 
			
		||||
            return (windowRectangle.toFloat() / peer->getPlatformScaleFactor()).toNearestInt();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HWND hwnd;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void addToParent()
 | 
			
		||||
    {
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto windowFlags = GetWindowLongPtr (hwnd, -16);
 | 
			
		||||
 | 
			
		||||
            using FlagType = decltype (windowFlags);
 | 
			
		||||
 | 
			
		||||
            windowFlags &= ~(FlagType) WS_POPUP;
 | 
			
		||||
            windowFlags |= (FlagType) WS_CHILD;
 | 
			
		||||
 | 
			
		||||
            SetWindowLongPtr (hwnd, -16, windowFlags);
 | 
			
		||||
            SetParent (hwnd, (HWND) currentPeer->getNativeHandle());
 | 
			
		||||
 | 
			
		||||
            componentMovedOrResized (true, true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void removeFromParent()
 | 
			
		||||
    {
 | 
			
		||||
        ShowWindow (hwnd, SW_HIDE);
 | 
			
		||||
        SetParent (hwnd, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Component& owner;
 | 
			
		||||
    ComponentPeer* currentPeer = nullptr;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
HWNDComponent::HWNDComponent()  {}
 | 
			
		||||
HWNDComponent::~HWNDComponent() {}
 | 
			
		||||
 | 
			
		||||
void HWNDComponent::paint (Graphics&) {}
 | 
			
		||||
 | 
			
		||||
void HWNDComponent::setHWND (void* hwnd)
 | 
			
		||||
{
 | 
			
		||||
    if (hwnd != getHWND())
 | 
			
		||||
    {
 | 
			
		||||
        pimpl.reset();
 | 
			
		||||
 | 
			
		||||
        if (hwnd != nullptr)
 | 
			
		||||
            pimpl.reset (new Pimpl ((HWND) hwnd, *this));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* HWNDComponent::getHWND() const
 | 
			
		||||
{
 | 
			
		||||
    return pimpl == nullptr ? nullptr : (void*) pimpl->hwnd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HWNDComponent::resizeToFit()
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        setBounds (pimpl->getHWNDBounds());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
class HWNDComponent::Pimpl  : public ComponentMovementWatcher
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (HWND h, Component& comp)
 | 
			
		||||
        : ComponentMovementWatcher (&comp),
 | 
			
		||||
          hwnd (h),
 | 
			
		||||
          owner (comp)
 | 
			
		||||
    {
 | 
			
		||||
        if (owner.isShowing())
 | 
			
		||||
            componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl() override
 | 
			
		||||
    {
 | 
			
		||||
        removeFromParent();
 | 
			
		||||
        DestroyWindow (hwnd);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void componentMovedOrResized (bool wasMoved, bool wasResized) override
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* peer = owner.getTopLevelComponent()->getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            auto area = (peer->getAreaCoveredBy (owner).toFloat() * peer->getPlatformScaleFactor()).getSmallestIntegerContainer();
 | 
			
		||||
 | 
			
		||||
            UINT flagsToSend =  SWP_NOACTIVATE | SWP_NOZORDER | SWP_NOOWNERZORDER;
 | 
			
		||||
 | 
			
		||||
            if (! wasMoved)   flagsToSend |= SWP_NOMOVE;
 | 
			
		||||
            if (! wasResized) flagsToSend |= SWP_NOSIZE;
 | 
			
		||||
 | 
			
		||||
            ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
 | 
			
		||||
 | 
			
		||||
            SetWindowPos (hwnd, nullptr, area.getX(), area.getY(), area.getWidth(), area.getHeight(), flagsToSend);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using ComponentMovementWatcher::componentMovedOrResized;
 | 
			
		||||
 | 
			
		||||
    void componentPeerChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        auto* peer = owner.getPeer();
 | 
			
		||||
 | 
			
		||||
        if (currentPeer != peer)
 | 
			
		||||
        {
 | 
			
		||||
            removeFromParent();
 | 
			
		||||
            currentPeer = peer;
 | 
			
		||||
 | 
			
		||||
            addToParent();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        auto isShowing = owner.isShowing();
 | 
			
		||||
 | 
			
		||||
        ShowWindow (hwnd, isShowing ? SW_SHOWNA : SW_HIDE);
 | 
			
		||||
 | 
			
		||||
        if (isShowing)
 | 
			
		||||
            InvalidateRect (hwnd, nullptr, 0);
 | 
			
		||||
     }
 | 
			
		||||
 | 
			
		||||
    void componentVisibilityChanged() override
 | 
			
		||||
    {
 | 
			
		||||
        componentPeerChanged();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    using ComponentMovementWatcher::componentVisibilityChanged;
 | 
			
		||||
 | 
			
		||||
    void componentBroughtToFront (Component& comp) override
 | 
			
		||||
    {
 | 
			
		||||
        ComponentMovementWatcher::componentBroughtToFront (comp);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Rectangle<int> getHWNDBounds() const
 | 
			
		||||
    {
 | 
			
		||||
        if (auto* peer = owner.getPeer())
 | 
			
		||||
        {
 | 
			
		||||
            ScopedThreadDPIAwarenessSetter threadDpiAwarenessSetter { hwnd };
 | 
			
		||||
 | 
			
		||||
            RECT r;
 | 
			
		||||
            GetWindowRect (hwnd, &r);
 | 
			
		||||
            Rectangle<int> windowRectangle (r.right - r.left, r.bottom - r.top);
 | 
			
		||||
 | 
			
		||||
            return (windowRectangle.toFloat() / peer->getPlatformScaleFactor()).toNearestInt();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return {};
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    HWND hwnd;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    void addToParent()
 | 
			
		||||
    {
 | 
			
		||||
        if (currentPeer != nullptr)
 | 
			
		||||
        {
 | 
			
		||||
            auto windowFlags = GetWindowLongPtr (hwnd, -16);
 | 
			
		||||
 | 
			
		||||
            using FlagType = decltype (windowFlags);
 | 
			
		||||
 | 
			
		||||
            windowFlags &= ~(FlagType) WS_POPUP;
 | 
			
		||||
            windowFlags |= (FlagType) WS_CHILD;
 | 
			
		||||
 | 
			
		||||
            SetWindowLongPtr (hwnd, -16, windowFlags);
 | 
			
		||||
            SetParent (hwnd, (HWND) currentPeer->getNativeHandle());
 | 
			
		||||
 | 
			
		||||
            componentMovedOrResized (true, true);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void removeFromParent()
 | 
			
		||||
    {
 | 
			
		||||
        ShowWindow (hwnd, SW_HIDE);
 | 
			
		||||
        SetParent (hwnd, nullptr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Component& owner;
 | 
			
		||||
    ComponentPeer* currentPeer = nullptr;
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
HWNDComponent::HWNDComponent()  {}
 | 
			
		||||
HWNDComponent::~HWNDComponent() {}
 | 
			
		||||
 | 
			
		||||
void HWNDComponent::paint (Graphics&) {}
 | 
			
		||||
 | 
			
		||||
void HWNDComponent::setHWND (void* hwnd)
 | 
			
		||||
{
 | 
			
		||||
    if (hwnd != getHWND())
 | 
			
		||||
    {
 | 
			
		||||
        pimpl.reset();
 | 
			
		||||
 | 
			
		||||
        if (hwnd != nullptr)
 | 
			
		||||
            pimpl.reset (new Pimpl ((HWND) hwnd, *this));
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* HWNDComponent::getHWND() const
 | 
			
		||||
{
 | 
			
		||||
    return pimpl == nullptr ? nullptr : (void*) pimpl->hwnd;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HWNDComponent::resizeToFit()
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        setBounds (pimpl->getHWNDBounds());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void HWNDComponent::updateHWNDBounds()
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->componentMovedOrResized (true, true);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
@@ -1,242 +1,242 @@
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2020 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 6 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy (both effective as of the 16th June 2020).
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-6-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
extern void* getUser32Function (const char*);
 | 
			
		||||
 | 
			
		||||
namespace IconConverters
 | 
			
		||||
{
 | 
			
		||||
    extern HICON createHICONFromImage (const Image&, BOOL isIcon, int hotspotX, int hotspotY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class SystemTrayIconComponent::Pimpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (SystemTrayIconComponent& owner_, HICON hicon, HWND hwnd)
 | 
			
		||||
        : owner (owner_),
 | 
			
		||||
          originalWndProc ((WNDPROC) GetWindowLongPtr (hwnd, GWLP_WNDPROC)),
 | 
			
		||||
          taskbarCreatedMessage (RegisterWindowMessage (TEXT ("TaskbarCreated")))
 | 
			
		||||
    {
 | 
			
		||||
        SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR) hookedWndProc);
 | 
			
		||||
 | 
			
		||||
        zerostruct (iconData);
 | 
			
		||||
        iconData.cbSize = sizeof (iconData);
 | 
			
		||||
        iconData.hWnd = hwnd;
 | 
			
		||||
        iconData.uID = (UINT) (pointer_sized_int) hwnd;
 | 
			
		||||
        iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
 | 
			
		||||
        iconData.uCallbackMessage = WM_TRAYNOTIFY;
 | 
			
		||||
        iconData.hIcon = hicon;
 | 
			
		||||
 | 
			
		||||
        notify (NIM_ADD);
 | 
			
		||||
 | 
			
		||||
        // In order to receive the "TaskbarCreated" message, we need to request that it's not filtered out.
 | 
			
		||||
        // (Need to load dynamically, as ChangeWindowMessageFilter is only available in Vista and later)
 | 
			
		||||
        typedef BOOL (WINAPI* ChangeWindowMessageFilterType) (UINT, DWORD);
 | 
			
		||||
 | 
			
		||||
        if (ChangeWindowMessageFilterType changeWindowMessageFilter
 | 
			
		||||
                = (ChangeWindowMessageFilterType) getUser32Function ("ChangeWindowMessageFilter"))
 | 
			
		||||
            changeWindowMessageFilter (taskbarCreatedMessage, 1 /* MSGFLT_ADD */);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl()
 | 
			
		||||
    {
 | 
			
		||||
        SetWindowLongPtr (iconData.hWnd, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
 | 
			
		||||
 | 
			
		||||
        iconData.uFlags = 0;
 | 
			
		||||
        notify (NIM_DELETE);
 | 
			
		||||
        DestroyIcon (iconData.hIcon);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateIcon (HICON hicon)
 | 
			
		||||
    {
 | 
			
		||||
        HICON oldIcon = iconData.hIcon;
 | 
			
		||||
 | 
			
		||||
        iconData.hIcon = hicon;
 | 
			
		||||
        iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
 | 
			
		||||
        notify (NIM_MODIFY);
 | 
			
		||||
 | 
			
		||||
        DestroyIcon (oldIcon);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setToolTip (const String& toolTip)
 | 
			
		||||
    {
 | 
			
		||||
        iconData.uFlags = NIF_TIP;
 | 
			
		||||
        toolTip.copyToUTF16 (iconData.szTip, sizeof (iconData.szTip) - 1);
 | 
			
		||||
        notify (NIM_MODIFY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void handleTaskBarEvent (const LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        if (owner.isCurrentlyBlockedByAnotherModalComponent())
 | 
			
		||||
        {
 | 
			
		||||
            if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN
 | 
			
		||||
                 || lParam == WM_LBUTTONDBLCLK || lParam == WM_RBUTTONDBLCLK)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* current = Component::getCurrentlyModalComponent())
 | 
			
		||||
                    current->inputAttemptWhenModal();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            ModifierKeys eventMods (ComponentPeer::getCurrentModifiersRealtime());
 | 
			
		||||
 | 
			
		||||
            if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK)
 | 
			
		||||
                eventMods = eventMods.withFlags (ModifierKeys::leftButtonModifier);
 | 
			
		||||
            else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK)
 | 
			
		||||
                eventMods = eventMods.withFlags (ModifierKeys::rightButtonModifier);
 | 
			
		||||
            else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
 | 
			
		||||
                eventMods = eventMods.withoutMouseButtons();
 | 
			
		||||
 | 
			
		||||
            const Time eventTime (getMouseEventTime());
 | 
			
		||||
 | 
			
		||||
            const MouseEvent e (Desktop::getInstance().getMainMouseSource(), {}, eventMods,
 | 
			
		||||
                                MouseInputSource::invalidPressure, MouseInputSource::invalidOrientation,
 | 
			
		||||
                                MouseInputSource::invalidRotation, MouseInputSource::invalidTiltX, MouseInputSource::invalidTiltY,
 | 
			
		||||
                                &owner, &owner, eventTime, {}, eventTime, 1, false);
 | 
			
		||||
 | 
			
		||||
            if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
 | 
			
		||||
            {
 | 
			
		||||
                SetFocus (iconData.hWnd);
 | 
			
		||||
                SetForegroundWindow (iconData.hWnd);
 | 
			
		||||
                owner.mouseDown (e);
 | 
			
		||||
            }
 | 
			
		||||
            else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseUp (e);
 | 
			
		||||
            }
 | 
			
		||||
            else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_RBUTTONDBLCLK)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseDoubleClick (e);
 | 
			
		||||
            }
 | 
			
		||||
            else if (lParam == WM_MOUSEMOVE)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseMove (e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static Pimpl* getPimpl (HWND hwnd)
 | 
			
		||||
    {
 | 
			
		||||
        if (JuceWindowIdentifier::isJUCEWindow (hwnd))
 | 
			
		||||
            if (ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8))
 | 
			
		||||
                if (SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (&(peer->getComponent())))
 | 
			
		||||
                    return iconComp->pimpl.get();
 | 
			
		||||
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static LRESULT CALLBACK hookedWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        if (Pimpl* const p = getPimpl (hwnd))
 | 
			
		||||
            return p->windowProc  (hwnd, message, wParam, lParam);
 | 
			
		||||
 | 
			
		||||
        return DefWindowProcW (hwnd, message, wParam, lParam);
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
    LRESULT windowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        if (message == WM_TRAYNOTIFY)
 | 
			
		||||
        {
 | 
			
		||||
            handleTaskBarEvent (lParam);
 | 
			
		||||
        }
 | 
			
		||||
        else if (message == taskbarCreatedMessage)
 | 
			
		||||
        {
 | 
			
		||||
            iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
 | 
			
		||||
            notify (NIM_ADD);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return CallWindowProc (originalWndProc, hwnd, message, wParam, lParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void showBubble (const String& title, const String& content)
 | 
			
		||||
    {
 | 
			
		||||
        iconData.uFlags = 0x10 /*NIF_INFO*/;
 | 
			
		||||
        title.copyToUTF16 (iconData.szInfoTitle, sizeof (iconData.szInfoTitle) - 1);
 | 
			
		||||
        content.copyToUTF16 (iconData.szInfo, sizeof (iconData.szInfo) - 1);
 | 
			
		||||
        notify (NIM_MODIFY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SystemTrayIconComponent& owner;
 | 
			
		||||
    NOTIFYICONDATA iconData;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    WNDPROC originalWndProc;
 | 
			
		||||
    const DWORD taskbarCreatedMessage;
 | 
			
		||||
    enum { WM_TRAYNOTIFY = WM_USER + 100 };
 | 
			
		||||
 | 
			
		||||
    void notify (DWORD message) noexcept    { Shell_NotifyIcon (message, &iconData); }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void SystemTrayIconComponent::setIconImage (const Image& colourImage, const Image&)
 | 
			
		||||
{
 | 
			
		||||
    if (colourImage.isValid())
 | 
			
		||||
    {
 | 
			
		||||
        HICON hicon = IconConverters::createHICONFromImage (colourImage, TRUE, 0, 0);
 | 
			
		||||
 | 
			
		||||
        if (pimpl == nullptr)
 | 
			
		||||
            pimpl.reset (new Pimpl (*this, hicon, (HWND) getWindowHandle()));
 | 
			
		||||
        else
 | 
			
		||||
            pimpl->updateIcon (hicon);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        pimpl.reset();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setIconTooltip (const String& tooltip)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->setToolTip (tooltip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setHighlighted (bool)
 | 
			
		||||
{
 | 
			
		||||
    // N/A on Windows.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::showInfoBubble (const String& title, const String& content)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->showBubble (title, content);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::hideInfoBubble()
 | 
			
		||||
{
 | 
			
		||||
    showInfoBubble (String(), String());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SystemTrayIconComponent::getNativeHandle() const
 | 
			
		||||
{
 | 
			
		||||
    return pimpl != nullptr ? &(pimpl->iconData) : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
/*
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
 | 
			
		||||
   This file is part of the JUCE library.
 | 
			
		||||
   Copyright (c) 2022 - Raw Material Software Limited
 | 
			
		||||
 | 
			
		||||
   JUCE is an open source library subject to commercial or open-source
 | 
			
		||||
   licensing.
 | 
			
		||||
 | 
			
		||||
   By using JUCE, you agree to the terms of both the JUCE 7 End-User License
 | 
			
		||||
   Agreement and JUCE Privacy Policy.
 | 
			
		||||
 | 
			
		||||
   End User License Agreement: www.juce.com/juce-7-licence
 | 
			
		||||
   Privacy Policy: www.juce.com/juce-privacy-policy
 | 
			
		||||
 | 
			
		||||
   Or: You may also use this code under the terms of the GPL v3 (see
 | 
			
		||||
   www.gnu.org/licenses).
 | 
			
		||||
 | 
			
		||||
   JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
 | 
			
		||||
   EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
 | 
			
		||||
   DISCLAIMED.
 | 
			
		||||
 | 
			
		||||
  ==============================================================================
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
namespace juce
 | 
			
		||||
{
 | 
			
		||||
 | 
			
		||||
extern void* getUser32Function (const char*);
 | 
			
		||||
 | 
			
		||||
namespace IconConverters
 | 
			
		||||
{
 | 
			
		||||
    extern HICON createHICONFromImage (const Image&, BOOL isIcon, int hotspotX, int hotspotY);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
class SystemTrayIconComponent::Pimpl
 | 
			
		||||
{
 | 
			
		||||
public:
 | 
			
		||||
    Pimpl (SystemTrayIconComponent& owner_, HICON hicon, HWND hwnd)
 | 
			
		||||
        : owner (owner_),
 | 
			
		||||
          originalWndProc ((WNDPROC) GetWindowLongPtr (hwnd, GWLP_WNDPROC)),
 | 
			
		||||
          taskbarCreatedMessage (RegisterWindowMessage (TEXT ("TaskbarCreated")))
 | 
			
		||||
    {
 | 
			
		||||
        SetWindowLongPtr (hwnd, GWLP_WNDPROC, (LONG_PTR) hookedWndProc);
 | 
			
		||||
 | 
			
		||||
        zerostruct (iconData);
 | 
			
		||||
        iconData.cbSize = sizeof (iconData);
 | 
			
		||||
        iconData.hWnd = hwnd;
 | 
			
		||||
        iconData.uID = (UINT) (pointer_sized_int) hwnd;
 | 
			
		||||
        iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
 | 
			
		||||
        iconData.uCallbackMessage = WM_TRAYNOTIFY;
 | 
			
		||||
        iconData.hIcon = hicon;
 | 
			
		||||
 | 
			
		||||
        notify (NIM_ADD);
 | 
			
		||||
 | 
			
		||||
        // In order to receive the "TaskbarCreated" message, we need to request that it's not filtered out.
 | 
			
		||||
        // (Need to load dynamically, as ChangeWindowMessageFilter is only available in Vista and later)
 | 
			
		||||
        typedef BOOL (WINAPI* ChangeWindowMessageFilterType) (UINT, DWORD);
 | 
			
		||||
 | 
			
		||||
        if (ChangeWindowMessageFilterType changeWindowMessageFilter
 | 
			
		||||
                = (ChangeWindowMessageFilterType) getUser32Function ("ChangeWindowMessageFilter"))
 | 
			
		||||
            changeWindowMessageFilter (taskbarCreatedMessage, 1 /* MSGFLT_ADD */);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    ~Pimpl()
 | 
			
		||||
    {
 | 
			
		||||
        SetWindowLongPtr (iconData.hWnd, GWLP_WNDPROC, (LONG_PTR) originalWndProc);
 | 
			
		||||
 | 
			
		||||
        iconData.uFlags = 0;
 | 
			
		||||
        notify (NIM_DELETE);
 | 
			
		||||
        DestroyIcon (iconData.hIcon);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void updateIcon (HICON hicon)
 | 
			
		||||
    {
 | 
			
		||||
        HICON oldIcon = iconData.hIcon;
 | 
			
		||||
 | 
			
		||||
        iconData.hIcon = hicon;
 | 
			
		||||
        iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
 | 
			
		||||
        notify (NIM_MODIFY);
 | 
			
		||||
 | 
			
		||||
        DestroyIcon (oldIcon);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void setToolTip (const String& toolTip)
 | 
			
		||||
    {
 | 
			
		||||
        iconData.uFlags = NIF_TIP;
 | 
			
		||||
        toolTip.copyToUTF16 (iconData.szTip, sizeof (iconData.szTip) - 1);
 | 
			
		||||
        notify (NIM_MODIFY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void handleTaskBarEvent (const LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        if (owner.isCurrentlyBlockedByAnotherModalComponent())
 | 
			
		||||
        {
 | 
			
		||||
            if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN
 | 
			
		||||
                 || lParam == WM_LBUTTONDBLCLK || lParam == WM_RBUTTONDBLCLK)
 | 
			
		||||
            {
 | 
			
		||||
                if (auto* current = Component::getCurrentlyModalComponent())
 | 
			
		||||
                    current->inputAttemptWhenModal();
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else
 | 
			
		||||
        {
 | 
			
		||||
            ModifierKeys eventMods (ComponentPeer::getCurrentModifiersRealtime());
 | 
			
		||||
 | 
			
		||||
            if (lParam == WM_LBUTTONDOWN || lParam == WM_LBUTTONDBLCLK)
 | 
			
		||||
                eventMods = eventMods.withFlags (ModifierKeys::leftButtonModifier);
 | 
			
		||||
            else if (lParam == WM_RBUTTONDOWN || lParam == WM_RBUTTONDBLCLK)
 | 
			
		||||
                eventMods = eventMods.withFlags (ModifierKeys::rightButtonModifier);
 | 
			
		||||
            else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
 | 
			
		||||
                eventMods = eventMods.withoutMouseButtons();
 | 
			
		||||
 | 
			
		||||
            const Time eventTime (getMouseEventTime());
 | 
			
		||||
 | 
			
		||||
            const MouseEvent e (Desktop::getInstance().getMainMouseSource(), {}, eventMods,
 | 
			
		||||
                                MouseInputSource::defaultPressure, MouseInputSource::defaultOrientation,
 | 
			
		||||
                                MouseInputSource::defaultRotation, MouseInputSource::defaultTiltX, MouseInputSource::defaultTiltY,
 | 
			
		||||
                                &owner, &owner, eventTime, {}, eventTime, 1, false);
 | 
			
		||||
 | 
			
		||||
            if (lParam == WM_LBUTTONDOWN || lParam == WM_RBUTTONDOWN)
 | 
			
		||||
            {
 | 
			
		||||
                SetFocus (iconData.hWnd);
 | 
			
		||||
                SetForegroundWindow (iconData.hWnd);
 | 
			
		||||
                owner.mouseDown (e);
 | 
			
		||||
            }
 | 
			
		||||
            else if (lParam == WM_LBUTTONUP || lParam == WM_RBUTTONUP)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseUp (e);
 | 
			
		||||
            }
 | 
			
		||||
            else if (lParam == WM_LBUTTONDBLCLK || lParam == WM_RBUTTONDBLCLK)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseDoubleClick (e);
 | 
			
		||||
            }
 | 
			
		||||
            else if (lParam == WM_MOUSEMOVE)
 | 
			
		||||
            {
 | 
			
		||||
                owner.mouseMove (e);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static Pimpl* getPimpl (HWND hwnd)
 | 
			
		||||
    {
 | 
			
		||||
        if (JuceWindowIdentifier::isJUCEWindow (hwnd))
 | 
			
		||||
            if (ComponentPeer* peer = (ComponentPeer*) GetWindowLongPtr (hwnd, 8))
 | 
			
		||||
                if (SystemTrayIconComponent* const iconComp = dynamic_cast<SystemTrayIconComponent*> (&(peer->getComponent())))
 | 
			
		||||
                    return iconComp->pimpl.get();
 | 
			
		||||
 | 
			
		||||
        return nullptr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    static LRESULT CALLBACK hookedWndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        if (Pimpl* const p = getPimpl (hwnd))
 | 
			
		||||
            return p->windowProc  (hwnd, message, wParam, lParam);
 | 
			
		||||
 | 
			
		||||
        return DefWindowProcW (hwnd, message, wParam, lParam);
 | 
			
		||||
   }
 | 
			
		||||
 | 
			
		||||
    LRESULT windowProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 | 
			
		||||
    {
 | 
			
		||||
        if (message == WM_TRAYNOTIFY)
 | 
			
		||||
        {
 | 
			
		||||
            handleTaskBarEvent (lParam);
 | 
			
		||||
        }
 | 
			
		||||
        else if (message == taskbarCreatedMessage)
 | 
			
		||||
        {
 | 
			
		||||
            iconData.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
 | 
			
		||||
            notify (NIM_ADD);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return CallWindowProc (originalWndProc, hwnd, message, wParam, lParam);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void showBubble (const String& title, const String& content)
 | 
			
		||||
    {
 | 
			
		||||
        iconData.uFlags = 0x10 /*NIF_INFO*/;
 | 
			
		||||
        title.copyToUTF16 (iconData.szInfoTitle, sizeof (iconData.szInfoTitle) - 1);
 | 
			
		||||
        content.copyToUTF16 (iconData.szInfo, sizeof (iconData.szInfo) - 1);
 | 
			
		||||
        notify (NIM_MODIFY);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    SystemTrayIconComponent& owner;
 | 
			
		||||
    NOTIFYICONDATA iconData;
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    WNDPROC originalWndProc;
 | 
			
		||||
    const DWORD taskbarCreatedMessage;
 | 
			
		||||
    enum { WM_TRAYNOTIFY = WM_USER + 100 };
 | 
			
		||||
 | 
			
		||||
    void notify (DWORD message) noexcept    { Shell_NotifyIcon (message, &iconData); }
 | 
			
		||||
 | 
			
		||||
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Pimpl)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
//==============================================================================
 | 
			
		||||
void SystemTrayIconComponent::setIconImage (const Image& colourImage, const Image&)
 | 
			
		||||
{
 | 
			
		||||
    if (colourImage.isValid())
 | 
			
		||||
    {
 | 
			
		||||
        HICON hicon = IconConverters::createHICONFromImage (colourImage, TRUE, 0, 0);
 | 
			
		||||
 | 
			
		||||
        if (pimpl == nullptr)
 | 
			
		||||
            pimpl.reset (new Pimpl (*this, hicon, (HWND) getWindowHandle()));
 | 
			
		||||
        else
 | 
			
		||||
            pimpl->updateIcon (hicon);
 | 
			
		||||
    }
 | 
			
		||||
    else
 | 
			
		||||
    {
 | 
			
		||||
        pimpl.reset();
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setIconTooltip (const String& tooltip)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->setToolTip (tooltip);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::setHighlighted (bool)
 | 
			
		||||
{
 | 
			
		||||
    // N/A on Windows.
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::showInfoBubble (const String& title, const String& content)
 | 
			
		||||
{
 | 
			
		||||
    if (pimpl != nullptr)
 | 
			
		||||
        pimpl->showBubble (title, content);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void SystemTrayIconComponent::hideInfoBubble()
 | 
			
		||||
{
 | 
			
		||||
    showInfoBubble (String(), String());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void* SystemTrayIconComponent::getNativeHandle() const
 | 
			
		||||
{
 | 
			
		||||
    return pimpl != nullptr ? &(pimpl->iconData) : nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace juce
 | 
			
		||||
 
 | 
			
		||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Reference in New Issue
	
	Block a user