From 49fabc565606e00c95baacb41f009de2a532a4da Mon Sep 17 00:00:00 2001 From: Victor Cebollada Date: Tue, 15 Dec 2015 11:46:59 +0000 Subject: [PATCH] Markup procesor. Color Change-Id: I112a2492c0b6e2f20e864015d9f14ae3ae92d762 Signed-off-by: Victor Cebollada --- .../controls/text-controls/text-field-impl.cpp | 21 +++ dali-toolkit/internal/file.list | 2 + dali-toolkit/internal/text/color-run.h | 58 +++++++ dali-toolkit/internal/text/color-segmentation.cpp | 88 ++++++++++ dali-toolkit/internal/text/color-segmentation.h | 57 +++++++ dali-toolkit/internal/text/input-style.h | 47 ++++++ dali-toolkit/internal/text/logical-model-impl.cpp | 49 ++++++ dali-toolkit/internal/text/logical-model-impl.h | 19 +++ .../internal/text/markup-processor-color.cpp | 61 +++++++ .../internal/text/markup-processor-color.h | 47 ++++++ .../text/markup-processor-helper-functions.cpp | 92 +++++++++++ .../text/markup-processor-helper-functions.h | 31 ++++ dali-toolkit/internal/text/markup-processor.cpp | 81 ++++++++++ dali-toolkit/internal/text/markup-processor.h | 13 +- dali-toolkit/internal/text/segmentation.cpp | 2 +- .../internal/text/text-controller-impl.cpp | 51 +++++- dali-toolkit/internal/text/text-controller-impl.h | 30 ++++ dali-toolkit/internal/text/text-controller.cpp | 122 +++++++++++++- dali-toolkit/internal/text/text-controller.h | 20 +++ .../internal/text/text-style-run-container.h | 177 +++++++++++++++++++++ dali-toolkit/internal/text/text-view.cpp | 24 +++ dali-toolkit/internal/text/visual-model-impl.h | 2 + .../public-api/controls/text-controls/text-field.h | 1 + 23 files changed, 1083 insertions(+), 12 deletions(-) create mode 100644 dali-toolkit/internal/text/color-run.h create mode 100644 dali-toolkit/internal/text/color-segmentation.cpp create mode 100644 dali-toolkit/internal/text/color-segmentation.h create mode 100644 dali-toolkit/internal/text/input-style.h create mode 100644 dali-toolkit/internal/text/markup-processor-color.cpp create mode 100644 dali-toolkit/internal/text/markup-processor-color.h create mode 100644 dali-toolkit/internal/text/text-style-run-container.h diff --git a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp index c078a25..d15d488 100644 --- a/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp +++ b/dali-toolkit/internal/controls/text-controls/text-field-impl.cpp @@ -97,6 +97,7 @@ DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "horizontalAlignment", DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "verticalAlignment", STRING, VERTICAL_ALIGNMENT ) DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "textColor", VECTOR4, TEXT_COLOR ) DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "placeholderTextColor", VECTOR4, PLACEHOLDER_TEXT_COLOR ) +DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "inputColor", VECTOR4, INPUT_COLOR ) DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "shadowOffset", VECTOR2, SHADOW_OFFSET ) DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "shadowColor", VECTOR4, SHADOW_COLOR ) DALI_PROPERTY_REGISTRATION( Toolkit, TextField, "primaryCursorColor", VECTOR4, PRIMARY_CURSOR_COLOR ) @@ -291,6 +292,7 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr if( impl.mController->GetTextColor() != textColor ) { impl.mController->SetTextColor( textColor ); + impl.mController->SetInputColor( textColor ); impl.mRenderer.Reset(); } } @@ -311,6 +313,17 @@ void TextField::SetProperty( BaseObject* object, Property::Index index, const Pr } break; } + case Toolkit::TextField::Property::INPUT_COLOR: + { + if( impl.mController ) + { + const Vector4 inputColor = value.Get< Vector4 >(); + DALI_LOG_INFO( gLogFilter, Debug::General, "TextField %p INPUT_COLOR %f,%f,%f,%f\n", impl.mController.Get(), inputColor.r, inputColor.g, inputColor.b, inputColor.a ); + + impl.mController->SetInputColor( inputColor ); + } + break; + } case Toolkit::TextField::Property::SHADOW_OFFSET: { if( impl.mController ) @@ -683,6 +696,14 @@ Property::Value TextField::GetProperty( BaseObject* object, Property::Index inde } break; } + case Toolkit::TextField::Property::INPUT_COLOR: + { + if( impl.mController ) + { + value = impl.mController->GetInputColor(); + } + break; + } case Toolkit::TextField::Property::SHADOW_OFFSET: { if ( impl.mController ) diff --git a/dali-toolkit/internal/file.list b/dali-toolkit/internal/file.list index 0cc5763..6a8f4dc 100644 --- a/dali-toolkit/internal/file.list +++ b/dali-toolkit/internal/file.list @@ -83,8 +83,10 @@ toolkit_src_files = \ $(toolkit_src_dir)/text/bidirectional-support.cpp \ $(toolkit_src_dir)/text/character-set-conversion.cpp \ $(toolkit_src_dir)/text/clipping/text-clipper.cpp \ + $(toolkit_src_dir)/text/color-segmentation.cpp \ $(toolkit_src_dir)/text/logical-model-impl.cpp \ $(toolkit_src_dir)/text/markup-processor.cpp \ + $(toolkit_src_dir)/text/markup-processor-color.cpp \ $(toolkit_src_dir)/text/markup-processor-helper-functions.cpp \ $(toolkit_src_dir)/text/multi-language-support.cpp \ $(toolkit_src_dir)/text/segmentation.cpp \ diff --git a/dali-toolkit/internal/text/color-run.h b/dali-toolkit/internal/text/color-run.h new file mode 100644 index 0000000..860ec7b --- /dev/null +++ b/dali-toolkit/internal/text/color-run.h @@ -0,0 +1,58 @@ +#ifndef __DALI_TOOLKIT_TEXT_COLOR_RUN_H__ +#define __DALI_TOOLKIT_TEXT_COLOR_RUN_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +/** + * @brief Run of characters with the same color. + */ +struct ColorRun +{ + CharacterRun characterRun; ///< The initial character index and the number of characters of the run. + Vector4 color; ///< The color of the characters. +}; + +struct ColorGlyphRun +{ + GlyphRun glyphRun; ///< The initial glyph index and the number of glyphs of the run. + Vector4 color; ///< The color of the glyphs. +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_COLOR_RUN_H__ diff --git a/dali-toolkit/internal/text/color-segmentation.cpp b/dali-toolkit/internal/text/color-segmentation.cpp new file mode 100644 index 0000000..9169225 --- /dev/null +++ b/dali-toolkit/internal/text/color-segmentation.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// FILE HEADER +#include + +// EXTERNAL INCLUDES + +// INTERNAL INCLUDES + +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +void SetColorSegmentationInfo( const Vector& characterColorRuns, + const Vector& charactersToGlyph, + const Vector& glyphsPerCharacter, + Vector& glyphColorRuns ) +{ + const VectorBase::SizeType numberOfColorRuns = characterColorRuns.Count(); + + if( 0u == numberOfColorRuns ) + { + // Nothing to do. + return; + } + + // Resize the color runs for the glyphs. + glyphColorRuns.Resize( numberOfColorRuns ); + + // Get pointers to the buffers. + ColorGlyphRun* glyphColorRunsBuffer = glyphColorRuns.Begin(); + const GlyphIndex* const charactersToGlyphBuffer = charactersToGlyph.Begin(); + const Length* const glyphsPerCharacterBuffer = glyphsPerCharacter.Begin(); + + // Convert from characters to glyphs. + Length index = 0u; + for( Vector::ConstIterator it = characterColorRuns.Begin(), + endIt = characterColorRuns.End(); + it != endIt; + ++it, ++index ) + { + const ColorRun& colorRun = *it; + + if( 0u < colorRun.characterRun.numberOfCharacters ) + { + // Get the next color glyph run. + ColorGlyphRun& colorGlyphRun = *( glyphColorRunsBuffer + index ); + colorGlyphRun.color = colorRun.color; + + // Convert the color run index from character to glyph. + colorGlyphRun.glyphRun.glyphIndex = *( charactersToGlyphBuffer + colorRun.characterRun.characterIndex ); + + // Get the index to the last character of the run. + const CharacterIndex lastIndex = colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters - 1u; + + // Calculate the number of glyphs. + colorGlyphRun.glyphRun.numberOfGlyphs = *( charactersToGlyphBuffer + lastIndex ) + *( glyphsPerCharacterBuffer + lastIndex ) - colorGlyphRun.glyphRun.glyphIndex; + } + } +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/color-segmentation.h b/dali-toolkit/internal/text/color-segmentation.h new file mode 100644 index 0000000..9e52de1 --- /dev/null +++ b/dali-toolkit/internal/text/color-segmentation.h @@ -0,0 +1,57 @@ +#ifndef __DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H__ +#define __DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +class LogicalModel; + +/** + * @brief Creates color glyph runs. + * + * @param[in] characterColorRuns The color runs in characters (set in the mark-up string). + * @param[in] charactersToGlyph Conversion table from characters to glyphs. + * @param[in] glyphsPerCharacter Table with the number of glyphs for each character. + * @param[out] glyphColorRuns The color runs in glyphs. + */ +void SetColorSegmentationInfo( const Vector& characterColorRuns, + const Vector& charactersToGlyph, + const Vector& glyphsPerCharacter, + Vector& glyphColorRuns ); + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_COLOR_SEGMENTATION_H__ diff --git a/dali-toolkit/internal/text/input-style.h b/dali-toolkit/internal/text/input-style.h new file mode 100644 index 0000000..cd562ec --- /dev/null +++ b/dali-toolkit/internal/text/input-style.h @@ -0,0 +1,47 @@ +#ifndef __DALI_TOOLKIT_TEXT_INPUT_STYLE_H__ +#define __DALI_TOOLKIT_TEXT_INPUT_STYLE_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// EXTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +/** + * The input text's style. + */ +struct InputStyle +{ +Vector4 textColor; +}; + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_INPUT_STYLE_H__ diff --git a/dali-toolkit/internal/text/logical-model-impl.cpp b/dali-toolkit/internal/text/logical-model-impl.cpp index e8e906f..10b2a49 100644 --- a/dali-toolkit/internal/text/logical-model-impl.cpp +++ b/dali-toolkit/internal/text/logical-model-impl.cpp @@ -18,6 +18,10 @@ // CLASS HEADER #include +// INTERNAL INCLUDES +#include +#include + namespace Dali { @@ -241,6 +245,51 @@ CharacterIndex LogicalModel::GetLogicalCharacterIndex( CharacterIndex visualChar return *( mVisualToLogicalMap.Begin() + visualCharacterIndex ); } +void LogicalModel::UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters ) +{ + const Length totalNumberOfCharacters = mText.Count(); + + // Process the color runs. + Vector removedColorRuns; + UpdateCharacterRuns( index, + numberOfCharacters, + totalNumberOfCharacters, + mColorRuns, + removedColorRuns ); +} + +void LogicalModel::RetrieveStyle( CharacterIndex index, InputStyle& style ) +{ + unsigned int runIndex = 0u; + unsigned int lastRunIndex = 0u; + bool overriden = false; + + // Set the text color. + for( Vector::ConstIterator it = mColorRuns.Begin(), + endIt = mColorRuns.End(); + it != endIt; + ++it, ++runIndex ) + { + const ColorRun& colorRun = *it; + + if( ( colorRun.characterRun.characterIndex <= index ) && + ( index < colorRun.characterRun.characterIndex + colorRun.characterRun.numberOfCharacters ) ) + { + lastRunIndex = runIndex; + overriden = true; + } + } + + // Set the text's color if it's overriden. + if( overriden ) + { + style.textColor = ( *( mColorRuns.Begin() + lastRunIndex ) ).color; + } + + runIndex = 0u; + overriden = false; +} + LogicalModel::~LogicalModel() { } diff --git a/dali-toolkit/internal/text/logical-model-impl.h b/dali-toolkit/internal/text/logical-model-impl.h index 43ef817..6842cf6 100644 --- a/dali-toolkit/internal/text/logical-model-impl.h +++ b/dali-toolkit/internal/text/logical-model-impl.h @@ -26,6 +26,7 @@ // INTERNAL INCLUDES #include #include +#include #include #include @@ -40,6 +41,7 @@ namespace Text class LogicalModel; typedef IntrusivePtr LogicalModelPtr; +struct InputStyle; /** * @brief A logical text model contains layout independent information. @@ -106,6 +108,22 @@ public: */ CharacterIndex GetLogicalCharacterIndex( CharacterIndex visualCharacterIndex ) const; + /** + * @brief Updates the text's style runs with the added or removed text. + * + * @param[in] index The character's index. + * @param[in] numberOfCharacters The number of characters added or removed. If the value is negative the characters are removed. + */ + void UpdateTextStyleRuns( CharacterIndex index, int numberOfCharacters ); + + /** + * @brief Retrieves the text's style for the given character index. + * + * @param[in] index The character index. + * @param[out] style The text's style in the given style. + */ + void RetrieveStyle( CharacterIndex index, InputStyle& style ); + protected: /** @@ -131,6 +149,7 @@ public: Vector mText; Vector mScriptRuns; Vector mFontRuns; + Vector mColorRuns; Vector mLineBreakInfo; Vector mWordBreakInfo; Vector mBidirectionalParagraphInfo; diff --git a/dali-toolkit/internal/text/markup-processor-color.cpp b/dali-toolkit/internal/text/markup-processor-color.cpp new file mode 100644 index 0000000..2fd826d --- /dev/null +++ b/dali-toolkit/internal/text/markup-processor-color.cpp @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// FILE HEADER +#include + +// EXTERNAL INCLUDES +#include + +// INTERNAL INCLUDES +#include +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +namespace +{ +const std::string XHTML_VALUE_ATTRIBUTE("value"); +} + +void ProcessColorTag( const Tag& tag, ColorRun& colorRun ) +{ + for( Vector::ConstIterator it = tag.attributes.Begin(), + endIt = tag.attributes.End(); + it != endIt; + ++it ) + { + const Attribute& attribute( *it ); + if( TokenComparison( XHTML_VALUE_ATTRIBUTE, attribute.nameBuffer, attribute.nameLength ) ) + { + ColorStringToVector4( attribute.valueBuffer, attribute.valueLength, colorRun.color ); + } + } +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali diff --git a/dali-toolkit/internal/text/markup-processor-color.h b/dali-toolkit/internal/text/markup-processor-color.h new file mode 100644 index 0000000..bf3ea20 --- /dev/null +++ b/dali-toolkit/internal/text/markup-processor-color.h @@ -0,0 +1,47 @@ +#ifndef __DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H__ +#define __DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +struct Tag; +struct ColorRun; + +/** + * @brief Retrieves the color value from the tag and sets it to the color run. + * + * @param[in] tag The color tag and its attributes. + * @param[in,out] colorRun The color run. + */ +void ProcessColorTag( const Tag& tag, ColorRun& colorRun ); + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_MARKUP_PROCESSOR_COLOR_H__ diff --git a/dali-toolkit/internal/text/markup-processor-helper-functions.cpp b/dali-toolkit/internal/text/markup-processor-helper-functions.cpp index 122335e..c460747 100644 --- a/dali-toolkit/internal/text/markup-processor-helper-functions.cpp +++ b/dali-toolkit/internal/text/markup-processor-helper-functions.cpp @@ -18,6 +18,10 @@ // FILE HEADER #include +// EXTERNAL INCLUDES +#include +#include + namespace Dali { @@ -32,6 +36,20 @@ namespace const char WHITE_SPACE = 0x20; // ASCII value of the white space. const char LAST_UPPER_CASE = 0x5b; // ASCII value of the one after the last upper case character (Z). const char TO_LOWER_CASE = 32; // Value to add to a upper case character to transform it into a lower case. + +const char WEB_COLOR_TOKEN( '#' ); +const char* const HEX_COLOR_TOKEN( "0x" ); +const char* const ALPHA_ONE( "FF" ); + +const std::string BLACK_COLOR( "black" ); +const std::string WHITE_COLOR( "white" ); +const std::string RED_COLOR( "red" ); +const std::string GREEN_COLOR( "green" ); +const std::string BLUE_COLOR( "blue" ); +const std::string YELLOW_COLOR( "yellow" ); +const std::string MAGENTA_COLOR( "magenta" ); +const std::string CYAN_COLOR( "cyan" ); +const std::string TRANSPARENT_COLOR( "transparent" ); } bool TokenComparison( const std::string& string1, const char* const stringBuffer2, Length length ) @@ -63,6 +81,80 @@ void SkipWhiteSpace( const char*& markupStringBuffer, for( ; ( WHITE_SPACE >= *markupStringBuffer ) && ( markupStringBuffer < markupStringEndBuffer ); ++markupStringBuffer ); } +unsigned int StringToHex( const char* const uintStr ) +{ + return static_cast( strtoul( uintStr, NULL, 16 ) ); +} + +void UintColorToVector4( unsigned int color, Vector4& retColor ) +{ + retColor.a = static_cast( ( color & 0xFF000000 ) >> 24u ) / 255.f; + retColor.r = static_cast( ( color & 0x00FF0000 ) >> 16u ) / 255.f; + retColor.g = static_cast( ( color & 0x0000FF00 ) >> 8u ) / 255.f; + retColor.b = static_cast( color & 0x000000FF ) / 255.f; +} + +void ColorStringToVector4( const char* const colorStr, Length length, Vector4& retColor ) +{ + if( WEB_COLOR_TOKEN == *colorStr ) + { + std::string webColor( colorStr + 1u, length - 1u ); + if( 4u == length ) // 3 component web color #F00 (red) + { + webColor.insert( 2u, &( webColor[2] ), 1u ); + webColor.insert( 1u, &( webColor[1] ), 1u ); + webColor.insert( 0u, &( webColor[0] ), 1u ); + webColor.insert( 0u, ALPHA_ONE ); + } + else if( 7u == length ) // 6 component web color #FF0000 (red) + { + webColor.insert( 0u, ALPHA_ONE ); + } + + UintColorToVector4( StringToHex( webColor.c_str() ), retColor ); + } + else if( TokenComparison( HEX_COLOR_TOKEN, colorStr, 2u ) ) + { + UintColorToVector4( StringToHex( colorStr + 2u ), retColor ); + } + else if( TokenComparison( BLACK_COLOR, colorStr, length ) ) + { + retColor = Color::BLACK; + } + else if( TokenComparison( WHITE_COLOR, colorStr, length ) ) + { + retColor = Color::WHITE; + } + else if( TokenComparison( RED_COLOR, colorStr, length ) ) + { + retColor = Color::RED; + } + else if( TokenComparison( GREEN_COLOR, colorStr, length ) ) + { + retColor = Color::GREEN; + } + else if( TokenComparison( BLUE_COLOR, colorStr, length ) ) + { + retColor = Color::BLUE; + } + else if( TokenComparison( YELLOW_COLOR, colorStr, length ) ) + { + retColor = Color::YELLOW; + } + else if( TokenComparison( MAGENTA_COLOR, colorStr, length ) ) + { + retColor = Color::MAGENTA; + } + else if( TokenComparison( CYAN_COLOR, colorStr, length ) ) + { + retColor = Color::CYAN; + } + else if( TokenComparison( TRANSPARENT_COLOR, colorStr, length ) ) + { + retColor = Color::TRANSPARENT; + } +} + } // namespace Text } // namespace Toolkit diff --git a/dali-toolkit/internal/text/markup-processor-helper-functions.h b/dali-toolkit/internal/text/markup-processor-helper-functions.h index cf494d2..5934467 100644 --- a/dali-toolkit/internal/text/markup-processor-helper-functions.h +++ b/dali-toolkit/internal/text/markup-processor-helper-functions.h @@ -28,6 +28,8 @@ namespace Dali { +struct Vector4; + namespace Toolkit { @@ -82,6 +84,35 @@ bool TokenComparison( const std::string& string1, const char* const stringBuffer void SkipWhiteSpace( const char*& markupStringBuffer, const char* const markupStringEndBuffer ); +/** + * @brief Converts a string into an hexadecimal unsigned int. + * + * @param[in] uintStr An hexadecimal unsigned int packed inside a string. + * + * @return The hexadecimal value. + */ +unsigned int StringToHex( const char* const uintStr ); + +/** + * @brief Converts an ARGB color packed in 4 byte unsigned int into a Vector4 color used in Dali. + * + * @param[in] color An ARGB color packed in an unsigned int. + * @param[out] retColor A Vector4 with the converted color. + */ +void UintColorToVector4( unsigned int color, Vector4& retColor ); + +/** + * @brief Converts a color packed inside a string into an ARGB Vector4 color. + * + * The string color could be in hexadecimal ( 0xFF0000FF ), webcolor ( #0000FF or #00F ) or some constant values: + * black, white, red, green, blue, yellow, magenta, cyan, transparent. + * + * @param[in] colorStr A color packed inside a string. + * @param[in] length The length of the color string. + * @param[out] retColor A color packed inside a Vector4. + */ +void ColorStringToVector4( const char* const colorStr, Length length, Vector4& retColor ); + } // namespace Text } // namespace Toolkit diff --git a/dali-toolkit/internal/text/markup-processor.cpp b/dali-toolkit/internal/text/markup-processor.cpp index 84707ad..51a1efb 100644 --- a/dali-toolkit/internal/text/markup-processor.cpp +++ b/dali-toolkit/internal/text/markup-processor.cpp @@ -20,6 +20,7 @@ // INTERNAL INCLUDES #include +#include #include namespace Dali @@ -58,6 +59,50 @@ const char WHITE_SPACE = 0x20; // ASCII value of the white space. const unsigned int MAX_NUM_OF_ATTRIBUTES = 5u; ///< The font tag has the 'family', 'size' 'weight', 'width' and 'slant' attrubutes. +const unsigned int DEFAULT_VECTOR_SIZE = 16u; ///< Default size of run vectors. + +/** + * @brief Struct used to retrieve the style runs from the mark-up string. + */ +struct StyleStack +{ + typedef VectorBase::SizeType RunIndex; + + Vector stack; ///< Use a vector as a style stack. Stores the indices pointing where the run is stored inside the logical model. + unsigned int topIndex; ///< Points the top of the stack. + + StyleStack() + : stack(), + topIndex( 0u ) + { + stack.Resize( DEFAULT_VECTOR_SIZE ); + } + + void Push( RunIndex index ) + { + // Check if there is space inside the style stack. + const VectorBase::SizeType size = stack.Count(); + if( topIndex >= size ) + { + // Resize the style stack. + stack.Resize( 2u * size ); + } + + // Set the run index in the top of the stack. + *( stack.Begin() + topIndex ) = index; + + // Reposition the pointer to the top of the stack. + ++topIndex; + } + + RunIndex Pop() + { + // Pop the top of the stack. + --topIndex; + return *( stack.Begin() + topIndex ); + } +}; + /** * @brief Splits the tag string into the tag name and its attributes. * @@ -297,6 +342,15 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma const Length markupStringSize = markupString.size(); markupProcessData.markupProcessedText.reserve( markupStringSize ); + // Stores a struct with the index to the first character of the run, the type of run and its parameters. + StyleStack styleStack; + + // Points the next free position in the vector of runs. + StyleStack::RunIndex colorRunIndex = 0u; + + // Give an initial default value to the model's vectors. + markupProcessData.colorRuns.Reserve( DEFAULT_VECTOR_SIZE ); + // Get the mark-up string buffer. const char* markupStringBuffer = markupString.c_str(); const char* const markupStringEndBuffer = markupStringBuffer + markupStringSize; @@ -314,10 +368,29 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma if( !tag.isEndTag ) { // Create a new color run. + ColorRun colorRun; + colorRun.characterRun.numberOfCharacters = 0u; + + // Set the start character index. + colorRun.characterRun.characterIndex = characterIndex; + + // Fill the run with the attributes. + ProcessColorTag( tag, colorRun ); + + // Push the color run in the logical model. + markupProcessData.colorRuns.PushBack( colorRun ); + + // Push the index of the run into the stack. + styleStack.Push( colorRunIndex ); + + // Point the next color run. + ++colorRunIndex; } else { // Pop the top of the stack and set the number of characters of the run. + ColorRun& colorRun = *( markupProcessData.colorRuns.Begin() + styleStack.Pop() ); + colorRun.characterRun.numberOfCharacters = characterIndex - colorRun.characterRun.characterIndex; } } // else if( TokenComparison( XHTML_I_TAG, tag.buffer, tag.length ) ) @@ -437,6 +510,14 @@ void ProcessMarkupString( const std::string& markupString, MarkupProcessData& ma } // Resize the model's vectors. + if( 0u == colorRunIndex ) + { + markupProcessData.colorRuns.Clear(); + } + else + { + markupProcessData.colorRuns.Resize( colorRunIndex ); + } } } // namespace Text diff --git a/dali-toolkit/internal/text/markup-processor.h b/dali-toolkit/internal/text/markup-processor.h index 86ec1a6..966622e 100644 --- a/dali-toolkit/internal/text/markup-processor.h +++ b/dali-toolkit/internal/text/markup-processor.h @@ -19,8 +19,12 @@ */ // EXTERNAL INCLUDES +#include #include +// INTERNAL INCLUDES +#include + namespace Dali { @@ -35,11 +39,14 @@ namespace Text */ struct MarkupProcessData { - MarkupProcessData() - : markupProcessedText() + MarkupProcessData( Vector& colorRuns ) + : colorRuns( colorRuns ), + markupProcessedText() {} - std::string markupProcessedText; + Vector& colorRuns; + + std::string markupProcessedText; }; /** diff --git a/dali-toolkit/internal/text/segmentation.cpp b/dali-toolkit/internal/text/segmentation.cpp index 466991b..a7c7135 100644 --- a/dali-toolkit/internal/text/segmentation.cpp +++ b/dali-toolkit/internal/text/segmentation.cpp @@ -15,7 +15,7 @@ * */ -// CLASS HEADER +// FILE HEADER #include // EXTERNAL INCLUDES diff --git a/dali-toolkit/internal/text/text-controller-impl.cpp b/dali-toolkit/internal/text/text-controller-impl.cpp index a86688d..bc85e95 100644 --- a/dali-toolkit/internal/text/text-controller-impl.cpp +++ b/dali-toolkit/internal/text/text-controller-impl.cpp @@ -25,6 +25,7 @@ // INTERNAL INCLUDES #include #include +#include #include #include #include @@ -132,7 +133,8 @@ EventData::EventData( DecoratorPtr decorator ) mUpdateRightSelectionPosition( false ), mScrollAfterUpdatePosition( false ), mScrollAfterDelete( false ), - mAllTextSelected( false ) + mAllTextSelected( false ), + mUpdateInputStyle( false ) { mImfManager = ImfManager::Get(); } @@ -287,6 +289,20 @@ bool Controller::Impl::ProcessInputEvents() } } + if( mEventData->mUpdateInputStyle ) + { + // Set the default style first. + RetrieveDefaultInputStyle( mEventData->mInputStyle ); + + // Get the character index from the cursor index. + const CharacterIndex styleIndex = ( mEventData->mPrimaryCursorPosition > 0u ) ? mEventData->mPrimaryCursorPosition - 1u : 0u; + + // Retrieve the style from the style runs stored in the logical model. + mLogicalModel->RetrieveStyle( styleIndex, mEventData->mInputStyle ); + + mEventData->mUpdateInputStyle = false; + } + mEventData->mEventQueue.clear(); DALI_LOG_INFO( gLogFilter, Debug::Verbose, "<--Controller::ProcessInputEvents\n" ); @@ -481,6 +497,30 @@ void Controller::Impl::UpdateModel( OperationsMask operationsRequired ) } } +bool Controller::Impl::UpdateModelStyle( OperationsMask operationsRequired ) +{ + bool updated = false; + + if( COLOR & operationsRequired ) + { + // Set the color runs in glyphs. + SetColorSegmentationInfo( mLogicalModel->mColorRuns, + mVisualModel->mCharactersToGlyph, + mVisualModel->mGlyphsPerCharacter, + mVisualModel->mColorRuns ); + + updated = true; + } + + return updated; +} + +void Controller::Impl::RetrieveDefaultInputStyle( InputStyle& inputStyle ) +{ + // Set the default text's color. + inputStyle.textColor = mTextColor; +} + void Controller::Impl::GetDefaultFonts( Vector& fonts, Length numberOfCharacters ) { if( mFontDefaults ) @@ -549,6 +589,7 @@ void Controller::Impl::OnCursorKeyEvent( const Event& event ) } mEventData->mUpdateCursorPosition = true; + mEventData->mUpdateInputStyle = true; mEventData->mScrollAfterUpdatePosition = true; } @@ -578,6 +619,7 @@ void Controller::Impl::OnTapEvent( const Event& event ) mEventData->mUpdateCursorPosition = true; mEventData->mScrollAfterUpdatePosition = true; + mEventData->mUpdateInputStyle = true; // Notify the cursor position to the imf manager. if( mEventData->mImfManager ) @@ -709,6 +751,7 @@ void Controller::Impl::OnHandleEvent( const Event& event ) if( Event::GRAB_HANDLE_EVENT == event.type ) { mEventData->mUpdateCursorPosition = true; + mEventData->mUpdateInputStyle = true; if ( !IsClipboardEmpty() ) { @@ -795,6 +838,7 @@ void Controller::Impl::OnHandleEvent( const Event& event ) mEventData->mUpdateCursorPosition = mEventData->mPrimaryCursorPosition != handlePosition; mEventData->mScrollAfterUpdatePosition = mEventData->mUpdateCursorPosition; mEventData->mPrimaryCursorPosition = handlePosition; + mEventData->mUpdateInputStyle = mEventData->mUpdateCursorPosition; } else if( leftSelectionHandleEvent || rightSelectionHandleEvent ) { @@ -914,6 +958,11 @@ void Controller::Impl::RetrieveSelection( std::string& selectedText, bool delete if( deleteAfterRetrieval ) // Only delete text if copied successfully { + // Set as input style the style of the first deleted character. + mLogicalModel->RetrieveStyle( startOfSelectedText, mEventData->mInputStyle ); + + mLogicalModel->UpdateTextStyleRuns( startOfSelectedText, -static_cast( lengthOfSelectedText ) ); + // Delete text between handles Vector& currentText = mLogicalModel->mText; diff --git a/dali-toolkit/internal/text/text-controller-impl.h b/dali-toolkit/internal/text/text-controller-impl.h index 190549c..3ae0c7f 100644 --- a/dali-toolkit/internal/text/text-controller-impl.h +++ b/dali-toolkit/internal/text/text-controller-impl.h @@ -23,6 +23,7 @@ #include // INTERNAL INCLUDES +#include #include #include #include @@ -133,6 +134,8 @@ struct EventData */ std::vector mEventQueue; ///< The queue of touch events etc. + InputStyle mInputStyle; ///< The style to be set to the new inputed text. + /** * 0,0 means that the top-left corner of the layout matches the top-left corner of the UI control. * Typically this will have a negative value with scrolling occurs. @@ -163,6 +166,7 @@ struct EventData bool mScrollAfterUpdatePosition : 1; ///< Whether to scroll after the cursor position is updated. bool mScrollAfterDelete : 1; ///< Whether to scroll after delete characters. bool mAllTextSelected : 1; ///< True if the selection handles are selecting all the text. + bool mUpdateInputStyle : 1; ///< Whether to update the input style after moving the cursor. }; struct ModifyEvent @@ -355,9 +359,35 @@ struct Controller::Impl return !result; // // If NumberOfItems greater than 0, return false } + /** + * @brief Updates the logical and visual models. + * + * When text or style changes the model is set with some operations pending. + * When i.e. the text's size or a relayout is required this method is called + * with a given @p operationsRequired parameter. The operations required are + * matched with the operations pending to perform the minimum number of operations. + * + * @param[in] operationsRequired The operations required. + */ void UpdateModel( OperationsMask operationsRequired ); /** + * @brief Updates the style runs in the visual model when the text's styles changes. + * + * @param[in] operationsRequired The operations required. + * + * @return @e true if the model has been modified. + */ + bool UpdateModelStyle( OperationsMask operationsRequired ); + + /** + * @brief Retreieves the default style. + * + * @param[out] inputStyle The default style. + */ + void RetrieveDefaultInputStyle( InputStyle& inputStyle ); + + /** * @brief Retrieve the default fonts. * * @param[out] fonts The default font family, style and point sizes. diff --git a/dali-toolkit/internal/text/text-controller.cpp b/dali-toolkit/internal/text/text-controller.cpp index 27f5cbf..e273f01 100644 --- a/dali-toolkit/internal/text/text-controller.cpp +++ b/dali-toolkit/internal/text/text-controller.cpp @@ -91,9 +91,12 @@ void Controller::SetText( const std::string& text ) // Reset keyboard as text changed mImpl->ResetImfManager(); - // Remove the previously set text + // Remove the previously set text and style. ResetText(); + // Remove the style. + ClearStyleData(); + CharacterIndex lastCursorIndex = 0u; if( mImpl->mEventData ) @@ -110,7 +113,7 @@ void Controller::SetText( const std::string& text ) if( !text.empty() ) { - MarkupProcessData markupProcessData; + MarkupProcessData markupProcessData( mImpl->mLogicalModel->mColorRuns ); Length textSize = 0u; const uint8_t* utf8 = NULL; @@ -489,6 +492,20 @@ bool Controller::RemoveText( int cursorOffset, int numberOfChars ) if( ( cursorIndex + numberOfChars ) <= currentText.Count() ) { + // Update the input style and remove the text's style before removing the text. + if( mImpl->mEventData ) + { + // Set first the default input style. + mImpl->RetrieveDefaultInputStyle( mImpl->mEventData->mInputStyle ); + + // Update the input style. + mImpl->mLogicalModel->RetrieveStyle( cursorIndex, mImpl->mEventData->mInputStyle ); + + // Remove the text's style before removing the text. + mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, -numberOfChars ); + } + + // Remove the characters. Vector::Iterator first = currentText.Begin() + cursorIndex; Vector::Iterator last = first + numberOfChars; @@ -589,6 +606,48 @@ float Controller::GetUnderlineHeight() const return mImpl->mVisualModel->GetUnderlineHeight(); } +void Controller::SetInputColor( const Vector4& color ) +{ + if( mImpl->mEventData ) + { + mImpl->mEventData->mInputStyle.textColor = color; + + if( EventData::SELECTING == mImpl->mEventData->mState ) + { + const bool handlesCrossed = mImpl->mEventData->mLeftSelectionPosition > mImpl->mEventData->mRightSelectionPosition; + + // Get start and end position of selection + const CharacterIndex startOfSelectedText = handlesCrossed ? mImpl->mEventData->mRightSelectionPosition : mImpl->mEventData->mLeftSelectionPosition; + const Length lengthOfSelectedText = ( handlesCrossed ? mImpl->mEventData->mLeftSelectionPosition : mImpl->mEventData->mRightSelectionPosition ) - startOfSelectedText; + + // Add the color run. + const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count(); + mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u ); + + ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns ); + colorRun.color = color; + colorRun.characterRun.characterIndex = startOfSelectedText; + colorRun.characterRun.numberOfCharacters = lengthOfSelectedText; + + // Request to relayout. + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | COLOR ); + mImpl->RequestRelayout(); + } + } +} + +const Vector4& Controller::GetInputColor() const +{ + if( mImpl->mEventData ) + { + return mImpl->mEventData->mInputStyle.textColor; + } + + // Return the default text's color if there is no EventData. + return mImpl->mTextColor; + +} + void Controller::SetEnableCursorBlink( bool enable ) { DALI_ASSERT_DEBUG( NULL != mImpl->mEventData && "TextInput disabled" ); @@ -759,7 +818,7 @@ bool Controller::Relayout( const Size& size ) { DALI_LOG_INFO( gLogFilter, Debug::Verbose, "new size (previous size %f,%f)\n", mImpl->mVisualModel->mControlSize.width, mImpl->mVisualModel->mControlSize.height ); - // Operations that need to be done if the size changes. + // Layout operations that need to be done if the size changes. mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | LAYOUT | ALIGN | @@ -769,14 +828,28 @@ bool Controller::Relayout( const Size& size ) mImpl->mVisualModel->mControlSize = size; } - // Make sure the model is up-to-date before layouting + // Whether there are modify events. + const bool isModifyEventsEmpty = 0u == mImpl->mModifyEvents.Count(); + + // Make sure the model is up-to-date before layouting. ProcessModifyEvents(); mImpl->UpdateModel( mImpl->mOperationsPending ); + // Style operations that need to be done if the text is modified. + if( !isModifyEventsEmpty ) + { + mImpl->mOperationsPending = static_cast( mImpl->mOperationsPending | + COLOR ); + } + + // Apply the style runs if text is modified. + bool updated = mImpl->UpdateModelStyle( mImpl->mOperationsPending ); + + // Layout the text. Size layoutSize; - bool updated = DoRelayout( mImpl->mVisualModel->mControlSize, - mImpl->mOperationsPending, - layoutSize ); + updated = DoRelayout( mImpl->mVisualModel->mControlSize, + mImpl->mOperationsPending, + layoutSize ) || updated; // Do not re-do any operation until something changes. mImpl->mOperationsPending = NO_OPERATION; @@ -1473,6 +1546,35 @@ void Controller::InsertText( const std::string& text, Controller::InsertType typ // The cursor position. CharacterIndex& cursorIndex = mImpl->mEventData->mPrimaryCursorPosition; + // Update the text's style. + if( mImpl->mEventData ) + { + // Updates the text style runs. + mImpl->mLogicalModel->UpdateTextStyleRuns( cursorIndex, maxSizeOfNewText ); + + // Get the character index from the cursor index. + const CharacterIndex styleIndex = ( cursorIndex > 0u ) ? cursorIndex - 1u : 0u; + + // Retrieve the text's style for the given index. + InputStyle style; + mImpl->mLogicalModel->RetrieveStyle( styleIndex, style ); + + // Whether to add a new text color run. + const bool addColorRun = style.textColor != mImpl->mEventData->mInputStyle.textColor; + + // Add style runs. + if( addColorRun ) + { + const VectorBase::SizeType numberOfRuns = mImpl->mLogicalModel->mColorRuns.Count(); + mImpl->mLogicalModel->mColorRuns.Resize( numberOfRuns + 1u ); + + ColorRun& colorRun = *( mImpl->mLogicalModel->mColorRuns.Begin() + numberOfRuns ); + colorRun.color = mImpl->mEventData->mInputStyle.textColor; + colorRun.characterRun.characterIndex = cursorIndex; + colorRun.characterRun.numberOfCharacters = maxSizeOfNewText; + } + } + // Insert at current cursor position. Vector& modifyText = mImpl->mLogicalModel->mText; @@ -2080,6 +2182,7 @@ void Controller::ClearModelData() mImpl->mVisualModel->mGlyphsPerCharacter.Clear(); mImpl->mVisualModel->mGlyphPositions.Clear(); mImpl->mVisualModel->mLines.Clear(); + mImpl->mVisualModel->mColorRuns.Clear(); mImpl->mVisualModel->ClearCaches(); } @@ -2097,6 +2200,11 @@ void Controller::ClearFontData() mImpl->mVisualModel->ClearCaches(); } +void Controller::ClearStyleData() +{ + mImpl->mLogicalModel->mColorRuns.Clear(); +} + Controller::Controller( ControlInterface& controlInterface ) : mImpl( NULL ) { diff --git a/dali-toolkit/internal/text/text-controller.h b/dali-toolkit/internal/text/text-controller.h index 0955431..058719e 100644 --- a/dali-toolkit/internal/text/text-controller.h +++ b/dali-toolkit/internal/text/text-controller.h @@ -85,6 +85,7 @@ public: UPDATE_ACTUAL_SIZE = 0x0200, REORDER = 0x0400, ALIGN = 0x0800, + COLOR = 0x1000, ALL_OPERATIONS = 0xFFFF }; @@ -383,6 +384,20 @@ public: float GetUnderlineHeight() const; /** + * @brief Sets the input text's color. + * + * @param[in] color The input text's color. + */ + void SetInputColor( const Vector4& color ); + + /** + * @brief Retrieves the input text's color. + * + * @return The input text's color. + */ + const Vector4& GetInputColor() const; + + /** * @brief Called to enable/disable cursor blink. * * @note Only editable controls should calls this. @@ -680,6 +695,11 @@ private: void ClearFontData(); /** + * @brief Helper to clear text's style data. + */ + void ClearStyleData(); + + /** * @brief Private constructor. */ Controller( ControlInterface& controlInterface ); diff --git a/dali-toolkit/internal/text/text-style-run-container.h b/dali-toolkit/internal/text/text-style-run-container.h new file mode 100644 index 0000000..e35ccea --- /dev/null +++ b/dali-toolkit/internal/text/text-style-run-container.h @@ -0,0 +1,177 @@ +#ifndef __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__ +#define __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__ + +/* + * Copyright (c) 2015 Samsung Electronics Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +// INTERNAL INCLUDES +#include + +namespace Dali +{ + +namespace Toolkit +{ + +namespace Text +{ + +/** + * @brief Updates the number of characters and the character index of the text's style runs. + * + * If the @p numberOfCharacters is a negative value, it means the number of characters that are removed starting from the @p index. + * + * It deletes runs if all their characters are removed. + * + * @param[in] index Index to the first character updated. + * @param[in] numberOfCharacters The number of characters to be updated. + * @param[in] totalNumberOfCharacters Total number of characters of the text. + * @param[in,out] runs The text's style runs. + * @param[out] removedRuns The text's style removed runs. + */ +template< typename T > +void UpdateCharacterRuns( CharacterIndex index, + int numberOfCharacters, + Length totalNumberOfCharacters, + Vector& runs, + Vector& removedRuns ) +{ + if( 0 > numberOfCharacters ) + { + // Remove characters. + const Length numberOfRemovedCharacters = -numberOfCharacters; + + if( ( 0u == index ) && ( numberOfRemovedCharacters == totalNumberOfCharacters ) ) + { + // Set the removed runs. + removedRuns = runs; + + // All characters are removed. + runs.Clear(); + + // Nothing else to do. + return; + } + + const VectorBase::SizeType size = runs.Count(); + // Temporary vector used to remove runs. + Vector tempRuns; + // Reserve some space for the temporary vector. + tempRuns.Reserve( size ); + removedRuns.Reserve( size ); + + // Whether any run has to be removed. + bool runsRemoved = false; + + // Index to the last character added/removed. + const CharacterIndex lastIndex = index + numberOfRemovedCharacters - 1u; + + // Update the style runs + for( typename Vector::Iterator it = runs.Begin(), + endIt = runs.End(); + it != endIt; + ++it ) + { + T& run = *it; + + const CharacterIndex lastRunIndex = run.characterRun.characterIndex + run.characterRun.numberOfCharacters - 1u; + + if( lastRunIndex < index ) + { + // The style run is not affected by the removed text. + tempRuns.PushBack( run ); + continue; + } + + if( ( index <= run.characterRun.characterIndex ) && + ( lastIndex >= lastRunIndex ) ) + { + // Add the removed run into the vector. + removedRuns.PushBack( run ); + + // All the characters are removed. + runsRemoved = true; + } + else + { + if( lastIndex < run.characterRun.characterIndex ) + { + // Just move the character index. + run.characterRun.characterIndex -= numberOfRemovedCharacters; + } + else + { + if( run.characterRun.characterIndex < index ) + { + // Remove characters starting from a character within the run. + run.characterRun.numberOfCharacters -= std::min( numberOfRemovedCharacters, 1u + lastRunIndex - index ); + } + else + { + // Remove characters starting from a character located before the first index of the run. + run.characterRun.numberOfCharacters -= 1u + lastIndex - run.characterRun.characterIndex; + run.characterRun.characterIndex = index; + } + } + + tempRuns.PushBack( run ); + } + } + + // Copy the temporary vector if there are runs removed. + if( runsRemoved ) + { + runs = tempRuns; + } + } + else + { + // Add characters. + + // Update the style runs + for( typename Vector::Iterator it = runs.Begin(), + endIt = runs.End(); + it != endIt; + ++it ) + { + T& run = *it; + + // Update the number of characters of the style run. + + if( ( 0u == index ) && ( 0u == run.characterRun.characterIndex ) ) + { + run.characterRun.numberOfCharacters += numberOfCharacters; + } + else if( index <= run.characterRun.characterIndex ) + { + run.characterRun.characterIndex += numberOfCharacters; + } + else if( index <= run.characterRun.characterIndex + run.characterRun.numberOfCharacters ) + { + run.characterRun.numberOfCharacters += numberOfCharacters; + } + } + } +} + +} // namespace Text + +} // namespace Toolkit + +} // namespace Dali + +#endif // __DALI_TOOLKIT_TEXT_STYLE_RUN_CONTAINER_H__ diff --git a/dali-toolkit/internal/text/text-view.cpp b/dali-toolkit/internal/text/text-view.cpp index 88ab012..2921700 100644 --- a/dali-toolkit/internal/text/text-view.cpp +++ b/dali-toolkit/internal/text/text-view.cpp @@ -122,6 +122,30 @@ Length View::GetGlyphs( GlyphInfo* glyphs, glyphIndex, numberOfLaidOutGlyphs ); + // Set the colors. + const GlyphIndex lastLaidOutGlyphIndex = glyphIndex + numberOfLaidOutGlyphs; + + for( Vector::ConstIterator it = mImpl->mVisualModel->mColorRuns.Begin(), + endIt = mImpl->mVisualModel->mColorRuns.End(); + it != endIt; + ++it ) + { + const ColorGlyphRun& colorGlyphRun = *it; + const GlyphIndex lastGlyphIndex = colorGlyphRun.glyphRun.glyphIndex + colorGlyphRun.glyphRun.numberOfGlyphs; + + if( ( colorGlyphRun.glyphRun.glyphIndex < lastLaidOutGlyphIndex ) && + ( glyphIndex < lastGlyphIndex ) ) + { + for( GlyphIndex index = glyphIndex < colorGlyphRun.glyphRun.glyphIndex ? colorGlyphRun.glyphRun.glyphIndex : glyphIndex, + endIndex = lastLaidOutGlyphIndex < lastGlyphIndex ? lastLaidOutGlyphIndex : lastGlyphIndex; + index < endIndex; + ++index ) + { + *( glyphColors + index - glyphIndex ) = colorGlyphRun.color; + } + } + } + // Get the lines for the given range of glyphs. // The lines contain the alignment offset which needs to be added to the glyph's position. LineIndex firstLine = 0u; diff --git a/dali-toolkit/internal/text/visual-model-impl.h b/dali-toolkit/internal/text/visual-model-impl.h index 52d2d31..ca579e1 100644 --- a/dali-toolkit/internal/text/visual-model-impl.h +++ b/dali-toolkit/internal/text/visual-model-impl.h @@ -27,6 +27,7 @@ // INTERNAL INCLUDES #include +#include namespace Dali { @@ -301,6 +302,7 @@ public: Vector mGlyphPositions; ///< For each glyph, the position. Vector mLines; ///< The laid out lines. Vector mUnderlineRuns; ///< Runs of glyphs that are underlined. + Vector mColorRuns; ///< Runs of glyphs with the same color. Vector2 mControlSize; ///< The size of the UI control the decorator is adding it's decorations to. Vector4 mTextColor; ///< The text color diff --git a/dali-toolkit/public-api/controls/text-controls/text-field.h b/dali-toolkit/public-api/controls/text-controls/text-field.h index f4642cf..7332e92 100644 --- a/dali-toolkit/public-api/controls/text-controls/text-field.h +++ b/dali-toolkit/public-api/controls/text-controls/text-field.h @@ -79,6 +79,7 @@ public: VERTICAL_ALIGNMENT, ///< name "verticalAlignment", The line vertical alignment, type STRING, values "TOP", "CENTER", "BOTTOM" TEXT_COLOR, ///< name "textColor", The text color, type VECTOR4 PLACEHOLDER_TEXT_COLOR, ///< name "placeholderTextColor", The placeholder-text color, type VECTOR4 + INPUT_COLOR, ///< name "inputColor", The color of the new input text, type VECTOR4 SHADOW_OFFSET, ///< name "shadowOffset", The drop shadow offset 0 indicates no shadow, type VECTOR2 SHADOW_COLOR, ///< name "shadowColor", The color of a drop shadow, type VECTOR4 PRIMARY_CURSOR_COLOR, ///< name "primaryCursorColor", The color to apply to the primary cursor, type VECTOR4 -- 2.7.4