/*
  ==============================================================================

   This file is part of the JUCE library - "Jules' Utility Class Extensions"
   Copyright 2004-6 by Raw Material Software ltd.

  ------------------------------------------------------------------------------

   JUCE can be redistributed and/or modified under the terms of the
   GNU General Public License, as published by the Free Software Foundation;
   either version 2 of the License, or (at your option) any later version.

   JUCE is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with JUCE; if not, visit www.gnu.org/licenses or write to the
   Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
   Boston, MA 02111-1307 USA

  ------------------------------------------------------------------------------

   If you'd like to release a closed-source product which uses JUCE, commercial
   licenses are also available: visit www.rawmaterialsoftware.com/juce for
   more information.

  ==============================================================================
*/

#ifndef __JUCE_LABEL_JUCEHEADER__
#define __JUCE_LABEL_JUCEHEADER__

#include "../juce_ComponentDeletionWatcher.h"
#include "../../../events/juce_ChangeListener.h"
#include "juce_TextEditor.h"


//==============================================================================
/**
    A component that displays a text string, and can optionally become a text
    editor when clicked.
*/
class JUCE_API  Label  : public Component,
                         public ChangeBroadcaster,
                         public TextEditorListener,
                         private ComponentListener
{
public:
    //==============================================================================
    /** Creates a Label.

        @param componentName    the name to give the component
        @param labelText        the text to show in the label
    */
    Label (const String& componentName,
           const String& labelText);

    /** Destructor. */
    ~Label();

    //==============================================================================
    /** Changes the label text.

        If broadcastChangeMessage is true and the new text is different to the current
        text, then the class will broadcast a change message to any ChangeListeners.
    */
    void setText (const String& newText,
                  const bool broadcastChangeMessage);

    /** Returns the label's current text.

        @param returnActiveEditorContents   if this is true and the label is currently
                                            being edited, then this method will return the
                                            text as it's being shown in the editor. If false,
                                            then the value returned here won't be updated until
                                            the user has finished typing and pressed the return
                                            key.
    */
    const String getText (const bool returnActiveEditorContents = false) const;

    //==============================================================================
    /** Changes the font to use to draw the text.

        @see getFont
    */
    void setFont (const Font& newFont);

    /** Returns the font currently being used.

        @see setFont
    */
    const Font getFont() const;

    /** Sets up the label's colours.

        @param textColour               the colour to draw the text in
        @param backgroundColour         the colour to fill the background in
        @param editorTextColour         the colour to use for the text when it's being edited (see setEditable())
        @param editorBackgroundColour   the colour to fill the background in when it's being edited
        @param editorHighlightColour    the highlight colour to use if the label is being edited
        @param outlineColour            a colour to use to draw a border around the label (make this
                                        transparent if you don't want a border)
    */
    void setColours (const Colour& textColour,
                     const Colour& backgroundColour,
                     const Colour& editorTextColour,
                     const Colour& editorBackgroundColour,
                     const Colour& editorHighlightColour,
                     const Colour& outlineColour);

    /** Sets the style of justification to be used for positioning the text.

        (The default is Justification::centredLeft)
    */
    void setJustificationType (const Justification& justification);

    /** Returns the type of justification, as set in setJustificationType(). */
    const Justification getJustificationType() const throw()                    { return justification; }

    /** Makes this label "stick to" another component.

        This will cause the label to follow another component around, staying
        either to its left or above it.

        @param owner    the component to follow
        @param onLeft   if true, the label will stay on the left of its component; if
                        false, it will stay above it.
    */
    void attachToComponent (Component* owner,
                            const bool onLeft);

    //==============================================================================
    /** Makes the label turn into a TextEditor when clicked.

        By default this is turned off.

        If turned on, then single- or double-clicking will turn the label into
        an editor. If the user then changes the text, then the ChangeBroadcaster
        base class will be used to send change messages to any listeners that
        have registered.

        If the user changes the text, the textWasEdited() method will be called
        afterwards, and subclasses can override this if they need to do anything
        special.

        @param editOnSingleClick            if true, just clicking once on the label will start editing the text
        @param editOnDoubleClick            if true, a double-click is needed to start editing
        @param lossOfFocusDiscardsChanges   if true, clicking somewhere else while the text is being
                                            edited will discard any changes; if false, then this will
                                            commit the changes.
        @see showEditor, setEditorColours, TextEditor
    */
    void setEditable (const bool editOnSingleClick,
                      const bool editOnDoubleClick = false,
                      const bool lossOfFocusDiscardsChanges = false);

    /** Returns true if the user can edit this label's text. */
    bool isEditable() const throw()                                     { return editSingleClick || editDoubleClick; }

    /** Makes the editor appear as if the label had been clicked by the user.

        @see textWasEdited, setEditable
    */
    void showEditor();

    /** Hides the editor if it was being shown.

        @param discardCurrentEditorContents     if true, the label's text will be
                                                reset to whatever it was before the editor
                                                was shown; if false, the current contents of the
                                                editor will be used to set the label's text
                                                before it is hidden.
    */
    void hideEditor (const bool discardCurrentEditorContents);

    /** Returns true if the editor is currently focused and active. */
    bool isBeingEdited() const;

    /** Adds a listener that will be informed when the text is edited. */
    void addTextEditorListener (TextEditorListener* const newListener);

    /** Removes a listener that was added with the addTextEditorListener() method. */
    void removeTextEditorListener (TextEditorListener* const listenerToRemove);


    //==============================================================================
    /** @internal */
    void textEditorTextChanged (TextEditor& editor);
    /** @internal */
    void textEditorReturnKeyPressed (TextEditor& editor);
    /** @internal */
    void textEditorEscapeKeyPressed (TextEditor& editor);
    /** @internal */
    void textEditorFocusLost (TextEditor& editor);
    /** @internal */
    void componentMovedOrResized (Component& component, bool wasMoved, bool wasResized);
    /** @internal */
    void componentParentHierarchyChanged (Component& component);
    /** @internal */
    void componentVisibilityChanged (Component& component);

    juce_UseDebuggingNewOperator

protected:
    /** @internal */
    void resized();
    /** @internal */
    void paint (Graphics& g);
    /** @internal */
    void mouseUp (const MouseEvent& e);
    /** @internal */
    void mouseDoubleClick (const MouseEvent& e);
    /** @internal */
    void focusGained (FocusChangeType);
    /** @internal */
    void enablementChanged();

    /** Creates the TextEditor component that will be used when the user has clicked on the label.

        Subclasses can override this if they need to customise this component in some way.
    */
    virtual TextEditor* createEditorComponent();

    /** Called after the user changes the text.
    */
    virtual void textWasEdited();

private:
    String text;
    Font font;
    Colour textColour, backgroundColour;
    Colour editorTextColour, editorBackgroundColour, editorHighlightColour, outlineColour;
    Justification justification;
    TextEditor* editor;
    VoidArray textListeners;
    Component* ownerComponent;
    ComponentDeletionWatcher* deletionWatcher;

    bool editSingleClick : 1;
    bool editDoubleClick : 1;
    bool lossOfFocusDiscardsChanges : 1;
    bool leftOfOwnerComp : 1;

    bool updateFromTextEditorContents();

    Label (const Label&);
    const Label& operator= (const Label&);
};


#endif   // __JUCE_LABEL_JUCEHEADER__
