namespace
{
-const char* const PROPERTY_NAME_RENDERING_BACKEND = "rendering-backend";
-const char* const PROPERTY_NAME_PLACEHOLDER_TEXT = "placeholder-text";
-const char* const PROPERTY_NAME_TEXT = "text";
-const char* const PROPERTY_NAME_FONT_FAMILY = "font-family";
-const char* const PROPERTY_NAME_FONT_STYLE = "font-style";
-const char* const PROPERTY_NAME_POINT_SIZE = "point-size";
-const char* const PROPERTY_NAME_EXCEED_POLICY = "exceed-policy";
-const char* const PROPERTY_NAME_PRIMARY_CURSOR_COLOR = "primary-cursor-color";
-const char* const PROPERTY_NAME_SECONDARY_CURSOR_COLOR = "secondary-cursor-color";
-const char* const PROPERTY_NAME_ENABLE_CURSOR_BLINK = "enable-cursor-blink";
-const char* const PROPERTY_NAME_CURSOR_BLINK_INTERVAL = "cursor-blink-interval";
-const char* const PROPERTY_NAME_CURSOR_BLINK_DURATION = "cursor-blink-duration";
-const char* const PROPERTY_NAME_GRAB_HANDLE_IMAGE = "grab-handle-image";
+const char* const PROPERTY_NAME_RENDERING_BACKEND = "rendering-backend";
+const char* const PROPERTY_NAME_PLACEHOLDER_TEXT = "placeholder-text";
+const char* const PROPERTY_NAME_TEXT = "text";
+const char* const PROPERTY_NAME_FONT_FAMILY = "font-family";
+const char* const PROPERTY_NAME_FONT_STYLE = "font-style";
+const char* const PROPERTY_NAME_POINT_SIZE = "point-size";
+const char* const PROPERTY_NAME_EXCEED_POLICY = "exceed-policy";
+const char* const PROPERTY_NAME_PRIMARY_CURSOR_COLOR = "primary-cursor-color";
+const char* const PROPERTY_NAME_SECONDARY_CURSOR_COLOR = "secondary-cursor-color";
+const char* const PROPERTY_NAME_ENABLE_CURSOR_BLINK = "enable-cursor-blink";
+const char* const PROPERTY_NAME_CURSOR_BLINK_INTERVAL = "cursor-blink-interval";
+const char* const PROPERTY_NAME_CURSOR_BLINK_DURATION = "cursor-blink-duration";
+const char* const PROPERTY_NAME_GRAB_HANDLE_IMAGE = "grab-handle-image";
const char* const PROPERTY_NAME_DECORATION_BOUNDING_BOX = "decoration-bounding-box";
-const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT = "horizontal-alignment";
-const char* const PROPERTY_NAME_VERTICAL_ALIGNMENT = "vertical-alignment";
+const char* const PROPERTY_NAME_HORIZONTAL_ALIGNMENT = "horizontal-alignment";
+const char* const PROPERTY_NAME_VERTICAL_ALIGNMENT = "vertical-alignment";
} // namespace
// Set Grab Handle image
field.SetProperty( TextField::Property::GRAB_HANDLE_IMAGE, "" );
+ // Check that the MAX_LENGTH property can be correctly set
+ const int maxNumberOfCharacters = 20;
+ field.SetProperty( TextField::Property::MAX_LENGTH, maxNumberOfCharacters );
+ DALI_TEST_EQUALS( field.GetProperty<int>( TextField::Property::MAX_LENGTH ), maxNumberOfCharacters, TEST_LOCATION );
+
END_TEST;
}
// EXTERNAL INCLUDES
#include <string>
+#include <cstring>
#include <dali/public-api/adaptor-framework/key.h>
#include <dali/public-api/common/stage.h>
#include <dali/public-api/images/resource-image.h>
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "font-family", STRING, FONT_FAMILY )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "font-style", STRING, FONT_STYLE )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "point-size", FLOAT, POINT_SIZE )
+DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "max-length", INTEGER, MAX_LENGTH )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "exceed-policy", INTEGER, EXCEED_POLICY )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "horizontal-alignment", STRING, HORIZONTAL_ALIGNMENT )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "vertical-alignment", STRING, VERTICAL_ALIGNMENT )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "selection-highlight-color", STRING, SELECTION_HIGHLIGHT_COLOR )
DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "decoration-bounding-box", RECTANGLE, DECORATION_BOUNDING_BOX )
+DALI_SIGNAL_REGISTRATION( Toolkit, TextField, "max-length-reached", SIGNAL_MAX_LENGTH_REACHED )
+
DALI_TYPE_REGISTRATION_END()
} // namespace
}
break;
}
+ case Toolkit::TextField::Property::MAX_LENGTH:
+ {
+ if( impl.mController )
+ {
+ impl.mController->SetMaximumNumberOfCharacters( value.Get< int >() );
+ }
+ break;
+ }
} // switch
} // textfield
}
}
break;
}
+ case Toolkit::TextField::Property::MAX_LENGTH:
+ {
+ if( impl.mController )
+ {
+ value = impl.mController->GetMaximumNumberOfCharacters();
+ }
+ break;
+ }
} //switch
}
return value;
}
+bool TextField::DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor )
+{
+ Dali::BaseHandle handle( object );
+
+ bool connected( true );
+ Toolkit::TextField field = Toolkit::TextField::DownCast( handle );
+
+ if( 0 == strcmp( signalName.c_str(), SIGNAL_MAX_LENGTH_REACHED ) )
+ {
+ field.MaxLengthReachedSignal().Connect( tracker, functor );
+ }
+ else
+ {
+ // signalName does not match any signal
+ connected = false;
+ }
+
+ return connected;
+}
+
+Toolkit::TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
+{
+ return mMaxLengthReachedSignal;
+}
+
void TextField::OnInitialize()
{
Actor self = Self();
RelayoutRequest();
}
+void TextField::MaxLengthReached()
+{
+ Dali::Toolkit::TextField handle( GetOwner() );
+ mMaxLengthReachedSignal.Emit( handle );
+}
+
void TextField::EnableClipping( bool clipping, const Vector2& size )
{
if( clipping )
*/
static Property::Value GetProperty( BaseObject* object, Property::Index index );
+ /**
+ * Connects a callback function with the object's signals.
+ * @param[in] object The object providing the signal.
+ * @param[in] tracker Used to disconnect the signal.
+ * @param[in] signalName The signal to connect to.
+ * @param[in] functor A newly allocated FunctorDelegate.
+ * @return True if the signal was connected.
+ * @post If a signal was connected, ownership of functor was passed to CallbackBase. Otherwise the caller is responsible for deleting the unused functor.
+ */
+ static bool DoConnectSignal( BaseObject* object, ConnectionTrackerInterface* tracker, const std::string& signalName, FunctorDelegate* functor );
+
+ /**
+ * @copydoc TextField::MaxLengthReachedSignal()
+ */
+ Toolkit::TextField::MaxLengthReachedSignalType& MaxLengthReachedSignal();
+
private: // From Control
/**
*/
virtual void RequestTextRelayout();
+ /**
+ * @copydoc Text::ControlInterface::MaxLengthReached()
+ */
+ virtual void MaxLengthReached();
+
private: // Implementation
/**
*/
virtual ~TextField();
-private:
-
// Undefined copy constructor and assignment operators
TextField(const TextField&);
TextField& operator=(const TextField& rhs);
private: // Data
+ // Signals
+ Toolkit::TextField::MaxLengthReachedSignalType mMaxLengthReachedSignal;
+
Text::ControllerPtr mController;
Text::RendererPtr mRenderer;
Text::DecoratorPtr mDecorator;
RelayoutRequest();
}
+void TextLabel::MaxLengthReached()
+{
+ // Pure Virtual from TextController Interface, only needed when inputting text
+}
+
TextLabel::TextLabel()
: Control( ControlBehaviour( REQUIRES_STYLE_CHANGE_SIGNALS ) ),
mRenderingBackend( DEFAULT_RENDERING_BACKEND )
*/
virtual void RequestTextRelayout();
+ /**
+ * @copydoc Text::ControlInterface::MaxLengthReached()
+ */
+ virtual void MaxLengthReached();
+
private: // Implementation
/**
* @brief Called to request a text relayout.
*/
virtual void RequestTextRelayout() = 0;
+
+ /**
+ * @brief Called when the number of characters to be inserted exceeds the maximum limit
+ */
+ virtual void MaxLengthReached() = 0;
};
} // namespace Text
mControlSize(),
mAlignmentOffset(),
mOperationsPending( NO_OPERATION ),
+ mMaximumNumberOfCharacters( 50 ),
mRecalculateNaturalSize( true )
{
mLogicalModel = LogicalModel::New();
*/
void RequestRelayout();
-
/**
* @brief Helper to move the cursor, grab handle etc.
*/
Size mControlSize; ///< The size of the control.
Vector2 mAlignmentOffset; ///< Vertical and horizontal offset of the whole text inside the control due to alignment.
OperationsMask mOperationsPending; ///< Operations pending to be done to layout the text.
+ Length mMaximumNumberOfCharacters; ///< Maximum number of characters that can be inserted.
bool mRecalculateNaturalSize:1; ///< Whether the natural size needs to be recalculated.
};
}
}
+void Controller::SetMaximumNumberOfCharacters( int maxCharacters )
+{
+ if ( maxCharacters >= 0 )
+ {
+ mImpl->mMaximumNumberOfCharacters = maxCharacters;
+ }
+}
+
+int Controller::GetMaximumNumberOfCharacters()
+{
+ return mImpl->mMaximumNumberOfCharacters;
+}
+
void Controller::SetDefaultFontFamily( const std::string& defaultFontFamily )
{
if( !mImpl->mFontDefaults )
Length characterCount = Utf8ToUtf32( utf8, text.size(), utf32Characters.Begin() );
utf32Characters.Resize( characterCount );
+ const Length numberOfCharactersInModel = mImpl->mLogicalModel->GetNumberOfCharacters();
+
+ // Restrict new text to fit within Maximum characters setting
+ Length maxSizeOfNewText = std::min ( ( mImpl->mMaximumNumberOfCharacters - numberOfCharactersInModel ), characterCount );
+
// Insert at current cursor position
- Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition;
- if( cursorIndex < modifyText.Count() )
+ Vector<Character>& modifyText = mImpl->mLogicalModel->mText;
+
+ if( cursorIndex < numberOfCharactersInModel )
{
- modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.End() );
+ modifyText.Insert( modifyText.Begin() + cursorIndex, utf32Characters.Begin(), utf32Characters.Begin()+ maxSizeOfNewText );
}
else
{
- modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.End() );
+ modifyText.Insert( modifyText.End(), utf32Characters.Begin(), utf32Characters.Begin() + maxSizeOfNewText );
}
- // Advance the cursor position
- ++cursorIndex;
+ cursorIndex += maxSizeOfNewText;
// The natural size needs to be re-calculated.
mImpl->mRecalculateNaturalSize = true;
// Queue a cursor reposition event; this must wait until after DoRelayout()
mImpl->mEventData->mUpdateCursorPosition = true;
mImpl->mEventData->mScrollAfterUpdateCursorPosition = true;
+
+ if ( characterCount > maxSizeOfNewText )
+ {
+ mImpl->mControlInterface.MaxLengthReached();
+ }
}
void Controller::DeleteTextEvent()
void GetPlaceholderText( std::string& text ) const;
/**
+ * @brief Sets the maximum number of characters that can be inserted into the TextModel
+ *
+ * @param[in] maxCharacters maximum number of characters to be accepted
+ */
+ void SetMaximumNumberOfCharacters( int maxCharacters );
+
+ /**
+ * @brief Sets the maximum number of characters that can be inserted into the TextModel
+ *
+ * @param[in] maxCharacters maximum number of characters to be accepted
+ */
+ int GetMaximumNumberOfCharacters();
+
+ /**
* @brief Set the default font family.
*
* @param[in] defaultFontFamily The default font family.
return Control::DownCast<TextField, Internal::TextField>(handle);
}
+TextField::MaxLengthReachedSignalType& TextField::MaxLengthReachedSignal()
+{
+ return Dali::Toolkit::GetImpl( *this ).MaxLengthReachedSignal();
+}
+
TextField::TextField( Internal::TextField& implementation )
: Control(implementation)
{
/**
* @brief A control which provides a single-line editable text field.
+ *
+ * * Signals
+ * | %Signal Name | Method |
+ * |------------------------|-----------------------------------------------------|
+ * | max-length-reached | @ref MaxLengthReachedSignal() |
+ *
*/
class DALI_IMPORT_API TextField : public Control
{
FONT_FAMILY, ///< name "font-family", The requested font family, type STRING
FONT_STYLE, ///< name "font-style", The requested font style e.g. Regular/Italic, type STRING
POINT_SIZE, ///< name "point-size", The size of font in points, type FLOAT
- EXCEED_POLICY, ///< name "exceed-policy" Specifies how the text is truncated when it does not fit, type INT
+ MAX_LENGTH, ///< name "max-length" The maximum number of characters that can be inserted, type INTEGER
+ EXCEED_POLICY, ///< name "exceed-policy" Specifies how the text is truncated when it does not fit, type INTEGER
HORIZONTAL_ALIGNMENT, ///< name "horizontal-alignment", The line horizontal alignment, type STRING, values "BEGIN", "CENTER", "END"
VERTICAL_ALIGNMENT, ///< name "vertical-alignment", The line vertical alignment, type STRING, values "TOP", "CENTER", "BOTTOM"
TEXT_COLOR, ///< name "text-color", The text color, type VECTOR4
SELECTION_HANDLE_PRESSED_IMAGE_LEFT, ///< name "selection-handle-pressed-image-left" The image to display when the left selection handle is pressed, type STRING
SELECTION_HANDLE_PRESSED_IMAGE_RIGHT, ///< name "selection-handle-pressed-image-right" The image to display when the right selection handle is pressed, type STRING
SELECTION_HIGHLIGHT_COLOR, ///< name "selection-highlight-color" The color of the selection highlight, type VECTOR4
- DECORATION_BOUNDING_BOX ///< name "decoration-bounding-box", The decorations (handles etc) will positioned within this area on-screen, type RECTANGLE
+ DECORATION_BOUNDING_BOX ///< name "decoration-bounding-box" The decorations (handles etc) will positioned within this area on-screen, type RECTANGLE
};
};
EXCEED_POLICY_CLIP ///< The end of text will be clipped to fit within the TextField.
};
+ // Type Defs
+
+ /// @brief Max Characters Exceed signal type;
+ typedef Signal<void ( TextField ) > MaxLengthReachedSignalType;
+
/**
* Create the TextField control.
* @return A handle to the TextField control.
*/
static TextField DownCast( BaseHandle handle );
+ // Signals
+
+ /**
+ * @brief This signal is emitted when inserted text exceeds the maximum character limit.
+ *
+ * A callback of the following type may be connected:
+ * @code
+ * void YourCallbackName( TextField textField );
+ * @endcode
+ * @return The signal to connect to.
+ */
+ MaxLengthReachedSignalType& MaxLengthReachedSignal();
+
public: // Not intended for application developers
/**