Way to require TextEditor/Label contents be non-empty?

Hi,

Is there an existing/simple way to require a minimum content length in Labels/TextEditors? For example, if I want someone to be able to edit a preset/program name in a plugin, but I don’t want them to be able to leave a blank name.

Thanks for any help,
Andrew

How could it do that? It has to be possible for someone to clear and re-type the contents, so it can’t prevent you from having too few characters in there! Just check the content yourself when they hit return or whatever.

Thanks for the quick reply. I agree that it has its idiosyncrasies … I just wanted to check to see if anyone had done anything similar before coding the particulars. Many thanks.

Hi,
I’ve done myself a template class using TextEditor to create a generic input field with mandatory and validity checks.
It is relatively simple to make this out.
Best regards.

Hi Nicolas,
Thanks for the thoughts. Have you implemented the simple version of this (i.e. check for empty text after-the-fact and the reset to previous text if empty)? I have that in place, and when I have time I may try to implement the more elegant version (preventing field from ever seeming empty) … it is very stylistic/subjective, of course, but I don’t think the field needs to be allowed to be empty (a user can select all the text and then type the first character of the replacement text in one step … he/she doesn’t need to make an empty text field first and then start typing … I think it can be more confusing to let something look like it is allowed to be empty and then repopulate it with old/unexpected text upon hitting Enter). Thanks again.

Hi there,

Please excuse me for the time I took for answering this thread…
I paste my code just after my post. It is just what I needed and I do not claim having the best or first idea of it.
As you will see, it is just a template class contained in a header file, with a specification for String type because of its special behaviour.
Like every time, it is just a hint and a way of thought !

Best regards,
Nicolas

/*!
 * \file
 * \brief   Definition of a generic input field
 */

#ifndef __GUI_COMPONENT_INPUTFIELD_H__
#define __GUI_COMPONENT_INPUTFIELD_H__

// Includes
#include <juce.h>
#include <boost/lexical_cast.hpp>

// Namespaces
namespace gui {
namespace component {

/*!
 * \class   InputField
 * \brief   Generic input field
 */
template <typename T>
class InputField : public TextEditor,
                   private TextEditorListener
{
public:

    /*!
     * \brief       Default constructor
     * \param[in]   componentName   Name of the component
     * \param[in]   minValue        Minimum value allowed
     * \param[in]   maxValue        Maximum value allowed
     * \param[in]   mandatory       true to set this field as mandatory, false otherwise
     */
    InputField(const String& componentName, T minValue, T maxValue, bool mandatory = false)
        : TextEditor(componentName, 0),
          minValue(minValue),
          maxValue(maxValue),
          mandatory(mandatory)
    {
        // Get default background colour
        dftBgColour = findColour(TextEditor::backgroundColourId);
        // Define background colour according to mandatory state
        setColour(TextEditor::backgroundColourId, mandatory ? Colours::lightpink : dftBgColour);
        // Add this as listener of this
        addListener(this);
    }

    /*!
     * \brief   Default destructor
     */
    ~InputField()
    {
    
    }

    /*!
     * \brief   Check if this field is mandatory
     * \return  true if mandatory, false otherwise
     */
    bool isMandatory()
    {
        return mandatory;
    }

    /*!
     * \brief   Check if input of this field is valid
     * \return  true if valid, false otherwise
     */
    bool isInputValid()
    {
        // Initialize valid state
        bool inputValid = false;
        // If input empty and is not mandatory
        if (isEmpty() && !mandatory)
            inputValid = true;
        // Else if input is not empty
        else if (!isEmpty())
        {
            try
            {
                // Try to cast input into desired object type
                T value = boost::lexical_cast<T>(getText());
                // If success, input is valid
                inputValid = (value >= minValue) && (value <= maxValue);
            }
            catch (boost::bad_lexical_cast&) {}
        }
        // Return valid state
        return inputValid;
    }

    T getValue() const
    {
        // Initialize value
        T value;
        // Try to convert input field into value type
        try
        {
            value = boost::lexical_cast<T>(getText());
        }
        catch (boost::bad_lexical_cast&) {}
        // Return value
        return value;
    }

    //-------------------------------------------------------------------------
    // Overload of TextEditorListener functions
    //-------------------------------------------------------------------------

    /*!
     * \brief       Called when user changes the text
     * \param[in]   editor  Editor which fired this changed signal
     */
    void textEditorTextChanged(TextEditor& editor)
    {
        if (isEmpty() && mandatory)
            setColour(TextEditor::backgroundColourId, Colours::lightpink);
        else if (!isInputValid())
            setColour(TextEditor::backgroundColourId, Colours::red);
        else
            setColour(TextEditor::backgroundColourId, dftBgColour);
    }

private:

    Colour dftBgColour;     // Default background colour
    bool mandatory;         // Mandatory field
    T minValue;             // Allowed minimum value
    T maxValue;             // Allowed maximum value

    // Declare as non copyable, with leak detection
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InputField);
};

/*!
 * \class   InputField
 * \brief   Generic input field
 */
template <>
class InputField<String> : public TextEditor,
                           private TextEditorListener
{
public:

    /*!
     * \brief       Default constructor
     * \param[in]   componentName       Name of the component
     * \param[in]   passwordCharacter   Character used as replacement for drawn characters on screen
     * \param[in]   mandatory           true to set this field as mandatory, false otherwise
     */
    InputField(const String& componentName = String::empty,
               juce_wchar passwordCharacter = 0,
               bool mandatory = false)
        : TextEditor(componentName, passwordCharacter),
          mandatory(mandatory)
    {
        // Get default background colour
        dftBgColour = findColour(TextEditor::backgroundColourId);
        // Define background colour according to mandatory state
        setColour(TextEditor::backgroundColourId, mandatory ? Colours::lightpink : dftBgColour);
        // Add this as listener of this
        addListener(this);
    }

    /*!
     * \brief   Default destructor
     */
    ~InputField()
    {
    
    }

    /*!
     * \brief   Check if this field is mandatory
     * \return  true if mandatory, false otherwise
     */
    bool isMandatory()
    {
        return mandatory;
    }

    /*!
     * \brief   Check if input of this field is valid
     * \return  true if valid, false otherwise
     */
    bool isInputValid()
    {
        return (isEmpty() && mandatory) ? false : true;
    }

    //-------------------------------------------------------------------------
    // Overload of TextEditorListener functions
    //-------------------------------------------------------------------------

    /*!
     * \brief       Called when user changes the text
     * \param[in]   editor  Editor which fired this changed signal
     */
    void textEditorTextChanged(TextEditor& editor)
    {
        setColour(TextEditor::backgroundColourId, isInputValid() ? dftBgColour : Colours::lightpink);
    }

private:

    Colour dftBgColour;     // Default background colour
    bool mandatory;         // Mandatory field

    // Declare as non copyable, with leak detection
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR(InputField);
};

}   // namespace component
}   // namespace gui

#endif  // __GUI_COMPONENT_INPUTFIELD_H__

Thanks very much for posting your code!