#include <dali-toolkit/internal/text/segmentation.h>
#include <dali-toolkit/internal/text/shaper.h>
#include <dali-toolkit/internal/text/text-controller-impl.h>
+#include <dali-toolkit/internal/text/markup-processor.h>
namespace Dali
{
Size& layoutSize,
LogicalModelPtr& logicalModel,
VisualModelPtr& visualModel,
- MetricsPtr& metrics )
+ MetricsPtr& metrics,
+ bool markupProcessorEnabled )
{
logicalModel = LogicalModel::New();
visualModel = VisualModel::New();
+ MarkupProcessData markupProcessData( logicalModel->mColorRuns,
+ logicalModel->mFontDescriptionRuns );
+
+ Length textSize = 0u;
+ const uint8_t* utf8 = NULL;
+ if( markupProcessorEnabled )
+ {
+ ProcessMarkupString( text, markupProcessData );
+ textSize = markupProcessData.markupProcessedText.size();
+
+ // This is a bit horrible but std::string returns a (signed) char*
+ utf8 = reinterpret_cast<const uint8_t*>( markupProcessData.markupProcessedText.c_str() );
+ }
+ else
+ {
+ textSize = text.size();
+
+ // This is a bit horrible but std::string returns a (signed) char*
+ utf8 = reinterpret_cast<const uint8_t*>( text.c_str() );
+ }
+
// 1) Convert to utf32
Vector<Character>& utf32Characters = logicalModel->mText;
- utf32Characters.Resize( text.size() );
+ utf32Characters.Resize( textSize );
- const uint32_t numberOfCharacters = ( text.size() == 0) ? 0 :
- Utf8ToUtf32( reinterpret_cast<const uint8_t* const>( text.c_str() ),
- text.size(),
- &utf32Characters[0u] );
- utf32Characters.Resize( numberOfCharacters );
+ // Transform a text array encoded in utf8 into an array encoded in utf32.
+ // It returns the actual number of characters.
+ Length characterCount = Utf8ToUtf32( utf8, textSize, utf32Characters.Begin() );
+ utf32Characters.Resize( characterCount );
// 2) Set the break and paragraph info.
Vector<LineBreakInfo>& lineBreakInfo = logicalModel->mLineBreakInfo;
- lineBreakInfo.Resize( numberOfCharacters );
+ lineBreakInfo.Resize( characterCount );
SetLineBreakInfo( utf32Characters,
0u,
- numberOfCharacters,
+ characterCount,
lineBreakInfo );
- if( 0u == numberOfCharacters )
+ if( 0u == characterCount )
{
// Nothing else to do if the number of characters is zero.
return;
// Retrieves the word break info. The word break info is used to layout the text (where to wrap the text in lines).
Vector<WordBreakInfo>& wordBreakInfo = logicalModel->mWordBreakInfo;
- wordBreakInfo.Resize( numberOfCharacters );
+ wordBreakInfo.Resize( characterCount );
SetWordBreakInfo( utf32Characters,
0u,
- numberOfCharacters,
+ characterCount,
wordBreakInfo );
// 3) Set the script info.
Vector<ScriptRun>& scripts = logicalModel->mScriptRuns;
multilanguageSupport.SetScripts( utf32Characters,
0u,
- numberOfCharacters,
+ characterCount,
scripts );
// 4) Set the font info
fontDescription,
TextAbstraction::FontClient::DEFAULT_POINT_SIZE,
0u,
- numberOfCharacters,
+ characterCount,
validFonts );
// 5) Set the bidirectional info per paragraph.
scripts,
lineBreakInfo,
0u,
- numberOfCharacters,
+ characterCount,
bidirectionalInfo );
// Create the paragraph info.
logicalModel->CreateParagraphInfo( 0u,
- numberOfCharacters );
+ characterCount );
// 6) Set character directions.
Vector<CharacterDirection>& characterDirections = logicalModel->mCharacterDirections;
{
// Only set the character directions if there is right to left characters.
GetCharactersDirection( bidirectionalInfo,
- numberOfCharacters,
+ characterCount,
0u,
- numberOfCharacters,
+ characterCount,
characterDirections );
characterDirections,
bidirectionalInfo,
0u,
- numberOfCharacters,
+ characterCount,
mirroredUtf32Characters );
}
else
validFonts,
0u,
0u,
- numberOfCharacters,
+ characterCount,
glyphs,
glyphsToCharactersMap,
charactersPerGlyph,
newParagraphGlyphs );
// Create the 'number of glyphs' per character and the glyph to character conversion tables.
- visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, numberOfCharacters );
- visualModel->CreateCharacterToGlyphTable( 0u, 0u, numberOfCharacters );
+ visualModel->CreateGlyphsPerCharacterTable( 0u, 0u, characterCount );
+ visualModel->CreateCharacterToGlyphTable( 0u, 0u, characterCount );
const Length numberOfGlyphs = glyphs.Count();
numberOfGlyphs,
Text::HorizontalAlignment::BEGIN,
Text::LineWrap::WORD,
- outlineWidth );
+ outlineWidth,
+ true );
Vector<LineRun>& lines = visualModel->mLines;
Vector<Vector2>& glyphPositions = visualModel->mGlyphPositions;
glyphPositions.Resize( numberOfGlyphs );
- layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( numberOfCharacters - 1u ) ) );
+ layoutParameters.isLastNewParagraph = TextAbstraction::IsNewParagraph( *( utf32Characters.Begin() + ( characterCount - 1u ) ) );
// The initial glyph and the number of glyphs to layout.
layoutParameters.startGlyphIndex = 0u;
bidirectionalLineInfo.Reserve( numberOfLines ); // Reserve because is not known yet how many lines have right to left characters.
ReorderLines( bidirectionalInfo,
0u,
- numberOfCharacters,
+ characterCount,
lines,
bidirectionalLineInfo );
// Re-layout the text. Reorder those lines with right to left characters.
layoutEngine.ReLayoutRightToLeftLines( layoutParameters,
0u,
- numberOfCharacters,
+ characterCount,
glyphPositions );
}
}
float alignmentOffset = 0.f;
layoutEngine.Align( textArea,
0u,
- numberOfCharacters,
+ characterCount,
Text::HorizontalAlignment::BEGIN,
lines,
alignmentOffset );
* @param[out] logicalModel Pointer to a logical text model instance.
* @param[out] visualModel Pointer to a visual text model instance.
* @param[out] metrics Pointer to a wrapper around FontClient used to get metrics.
+ * @param[in] markupProcessorEnabled Enable markup processor to use markup text.
*/
void CreateTextModel( const std::string& text,
const Size& textArea,
Size& layoutSize,
LogicalModelPtr& logicalModel,
VisualModelPtr& visualModel,
- MetricsPtr& metrics );
+ MetricsPtr& metrics,
+ bool markupProcessorEnabled );
/**
* @brief Configures the text @p controller similarly to the one configured by the text-label.
struct GetCharactersDirectionData
{
- std::string description; ///< Description of the test.
- std::string text; ///< Input text.
- unsigned int startIndex; ///< The index from where the model is updated.
- unsigned int numberOfCharacters; ///< The number of characters.
- bool* directions; ///< The expected directions.
+ std::string description; ///< Description of the test.
+ std::string text; ///< Input text.
+ unsigned int startIndex; ///< The index from where the model is updated.
+ unsigned int numberOfCharacters; ///< The number of characters.
+ bool* directions; ///< The expected directions.
+ bool markupProcessorEnabled; ///< Enable markup processor to use markup text.
};
bool SetBidirectionalInfoTest( const SetBidirectionalInfoData& data )
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// 2) Clear the bidirectional paragraph info data.
Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// 2) Clear the bidirectional line info data.
uint32_t startRemoveIndex = logicalModel->mBidirectionalLineInfo.Count();
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// 2) Call the GetMirroredText() function for the whole text
Vector<Character> mirroredText;
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ data.markupProcessorEnabled );
Vector<BidirectionalParagraphInfoRun>& bidirectionalInfo = logicalModel->mBidirectionalParagraphInfo;
true, true, true, true, true, true, true, true, true, true,
true, true, false, false, false, false, false };
+ bool directions06[] = {
+ true, true, true, true, true, true, true, true, true, true,
+ false, false, false, false, false, false, false, false, false, false,
+ false, false, false, false, false, false };
+
struct GetCharactersDirectionData data[] =
{
{
"",
0u,
0u,
- directions01
+ directions01,
+ false
},
{
"Left to right characters only",
"Hello world\nhello world demo",
0u,
28u,
- directions02
+ directions02,
+ false
},
{
"Right to left characters only",
"שלום עולם\nשלום עולם",
0u,
19u,
- directions03
+ directions03,
+ false
},
{
"Mix of bidirectional text",
"Hello world\nhello world שלום עולם\nשלום עולם hello world",
0u,
55u,
- directions04
+ directions04,
+ false
},
{
"Mix of bidirectional text. With more paragraphs.",
" مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
0u,
227u,
- directions05
+ directions05,
+ false
},
{
"Mix of bidirectional text. With more paragraphs. Update first paragraph.",
" مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
0u,
17u,
- directions05
+ directions05,
+ false
},
{
"Mix of bidirectional text. With more paragraphs. Update from character 29",
" مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
29u,
134u,
- directions05
+ directions05,
+ false
},
{
"Mix of bidirectional text. With more paragraphs. Update from character 163",
" مرحبا بالعالم שלום עולם hello world hello world\nبالعالم שלום hello world demo עולם\nשלום مرحبا بالعالم עולם hello",
163u,
35u,
- directions05
+ directions05,
+ false
+ },
+ {
+ "Mix of bidirectional text. With brackets and LRM",
+ "שלום עולם ‎(hello)[world]‎",
+ 0u,
+ 26u,
+ directions06,
+ true
}
};
- const unsigned int numberOfTests = 8u;
+ const unsigned int numberOfTests = 9u;
for( unsigned int index = 0u; index < numberOfTests; ++index )
{
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// 2) Clear the paragraphs.
Vector<ParagraphRun>& paragraphs = logicalModel->mParagraphInfo;
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// 2) Find the paragraphs.
Vector<ParagraphRunIndex> paragraphs;
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
for( unsigned int index = 0; index < data.numberOfTests; ++index )
{
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
for( unsigned int index = 0u; index < data.numberOfIndices; ++index )
{
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
for( unsigned int index = 0u; index < data.numberOfIndices; ++index )
{
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
for( unsigned int index = 0; index < data.numberOfTests; ++index )
{
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
for( unsigned int index = 0; index < data.numberOfTests; ++index )
{
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
GetCursorPositionParameters parameters;
parameters.visualModel = visualModel;
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
for( unsigned int index = 0; index < data.numberOfTests; ++index )
{
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// 2) Clear the layout.
Vector<LineRun>& lines = visualModel->mLines;
totalNumberOfGlyphs,
Text::HorizontalAlignment::BEGIN,
Text::LineWrap::WORD,
- outlineWidth );
+ outlineWidth,
+ true );
layoutParameters.isLastNewParagraph = isLastNewParagraph;
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// 2) Call the ReLayoutRightToLeftLines() method.
Layout::Engine engine;
visualModel->mGlyphs.Count(),
Text::HorizontalAlignment::BEGIN,
Text::LineWrap::WORD,
- outlineWidth );
+ outlineWidth,
+ true );
layoutParameters.numberOfBidirectionalInfoRuns = logicalModel->mBidirectionalLineInfo.Count();
layoutParameters.lineBidirectionalInfoRunsBuffer = logicalModel->mBidirectionalLineInfo.Begin();
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// Call the Align method.
Layout::Engine engine;
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
// 2) Clear the model.
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
layoutSize,
logicalModel,
visualModel,
- metrics );
+ metrics,
+ false );
Vector<GlyphIndex>& charactersToGlyph = visualModel->mCharactersToGlyph;
Vector<Length>& glyphsPerCharacter = visualModel->mGlyphsPerCharacter;
using namespace Dali;
using namespace Toolkit;
+namespace
+{
+
void TestLayoutItemOrder( std::vector< Control >& controls, LayoutGroup& layoutGroup )
{
for( auto&& iter : controls )
}
}
+// Turns the given control into a Root layout control and adds it to the stage.
+void SetupRootLayoutControl( Control& rootControl )
+{
+ rootControl = Control::New();
+ auto absoluteLayout = AbsoluteLayout::New();
+ DevelControl::SetLayout( rootControl, absoluteLayout );
+ rootControl.SetName( "RootAbsoluteLayout" );
+ Stage stage = Stage::GetCurrent();
+ stage.Add( rootControl );
+}
+
+} // unnamed namespace
+
void utc_dali_toolkit_layouting_startup(void)
{
test_return_value = TET_UNDEF;
{
hbox.Add( iter );
}
+
hbox.SetParentOrigin( ParentOrigin::CENTER );
hbox.SetAnchorPoint( AnchorPoint::CENTER );
stage.Add( hbox );
Control control1 = CreateLeafControl( 40, 40 );
rootControl.Add( control1 );
+
auto hbox = Control::New();
auto hboxLayout = LinearLayout::New();
hboxLayout.SetOrientation( LinearLayout::Orientation::HORIZONTAL );
DALI_TEST_EQUALS( hboxLayout.IsLayoutAnimated(), false, TEST_LOCATION );
DALI_TEST_EQUALS( DevelControl::GetLayout( control2 ).IsLayoutAnimated(), false, TEST_LOCATION );
+ tet_infoline(" Set hBoxLayout to animate");
hboxLayout.SetAnimateLayout( true );
+ tet_infoline(" Set absoluteLayout not to animate");
absoluteLayout.SetAnimateLayout( false );
DALI_TEST_EQUALS( absoluteLayout.IsLayoutAnimated(), false, TEST_LOCATION );
END_TEST;
}
+int UtcDaliLayouting_HboxLayout09(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline(" UtcDaliLayouting_HboxLayout07 - Set alignment");
+
+ Stage stage = Stage::GetCurrent();
+ auto hbox = Control::New();
+ auto hboxLayout = LinearLayout::New();
+ DevelControl::SetLayout( hbox, hboxLayout );
+ hbox.SetName( "HBox");
+
+ std::vector< Control > controls;
+ controls.push_back( CreateLeafControl( 40, 40 ) );
+ controls.push_back( CreateLeafControl( 60, 60 ) );
+
+ for( auto&& iter : controls )
+ {
+ hbox.Add( iter );
+ }
+ hbox.SetParentOrigin( ParentOrigin::CENTER );
+ hbox.SetAnchorPoint( AnchorPoint::CENTER );
+ stage.Add( hbox );
+
+ // Check default orientation
+ DALI_TEST_EQUALS( static_cast<unsigned int>( hboxLayout.GetOrientation() ), static_cast<unsigned int>( LinearLayout::Orientation::HORIZONTAL ), TEST_LOCATION );
+ // Check default alignment
+ DALI_TEST_EQUALS( hboxLayout.GetAlignment(), ( Dali::Toolkit::LinearLayout::Alignment::BEGIN | Dali::Toolkit::LinearLayout::Alignment::CENTER_VERTICAL ), TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::BEGIN );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 40.0f, 370.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::END );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 380.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 420.0f, 370.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 190.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 230.0f, 370.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::BEGIN | Dali::Toolkit::LinearLayout::Alignment::TOP );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 40.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::END | Dali::Toolkit::LinearLayout::Alignment::TOP );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 380.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 420.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL | Dali::Toolkit::LinearLayout::Alignment::TOP );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 190.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 230.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::BEGIN | Dali::Toolkit::LinearLayout::Alignment::BOTTOM );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 760.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 40.0f, 740.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::END | Dali::Toolkit::LinearLayout::Alignment::BOTTOM );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 380.0f, 760.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 420.0f, 740.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL | Dali::Toolkit::LinearLayout::Alignment::BOTTOM );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 190.0f, 760.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 230.0f, 740.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL | Dali::Toolkit::LinearLayout::Alignment::CENTER_VERTICAL );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 190.0f, 380.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 230.0f, 370.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetOrientation( LinearLayout::Orientation::VERTICAL );
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::BEGIN );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 390.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::END );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 440.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 420.0f, 390.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 220.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 210.0f, 390.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::BEGIN | Dali::Toolkit::LinearLayout::Alignment::TOP );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::END | Dali::Toolkit::LinearLayout::Alignment::TOP );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 440.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 420.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL | Dali::Toolkit::LinearLayout::Alignment::TOP );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 220.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 210.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::BEGIN | Dali::Toolkit::LinearLayout::Alignment::BOTTOM );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 700.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 740.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::END | Dali::Toolkit::LinearLayout::Alignment::BOTTOM );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 440.0f, 700.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 420.0f, 740.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL | Dali::Toolkit::LinearLayout::Alignment::BOTTOM );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 220.0f, 700.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 210.0f, 740.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ hboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL | Dali::Toolkit::LinearLayout::Alignment::CENTER_VERTICAL );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 220.0f, 350.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 210.0f, 390.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ DALI_TEST_EQUALS( controls[0].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 40.0f, 40.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( controls[1].GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 60.0f, 60.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ END_TEST;
+}
+
namespace
{
const char* TEST_IMAGE_FILE_NAME = TEST_RESOURCE_DIR "/broken.png";
auto vbox = Control::New();
auto vboxLayout = LinearLayout::New();
vboxLayout.SetOrientation( LinearLayout::Orientation::VERTICAL );
+ vboxLayout.SetAlignment( LinearLayout::Alignment::TOP | LinearLayout::Alignment::CENTER_HORIZONTAL );
DevelControl::SetLayout( vbox, vboxLayout );
vbox.SetName( "Vbox");
auto vbox = Control::New();
auto vboxLayout = LinearLayout::New();
vboxLayout.SetOrientation( LinearLayout::Orientation::VERTICAL );
+ vboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::TOP | Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL );
DevelControl::SetLayout( vbox, vboxLayout );
vbox.SetName( "Vbox");
rootControl.Add( vbox );
auto vboxLayout = LinearLayout::New();
vboxLayout.SetCellPadding( LayoutSize( 0, 10 ) );
vboxLayout.SetOrientation( LinearLayout::Orientation::VERTICAL );
+ vboxLayout.SetAlignment( Dali::Toolkit::LinearLayout::Alignment::TOP | Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL );
DALI_TEST_EQUALS( vboxLayout.GetCellPadding(), LayoutSize( 0, 10 ), TEST_LOCATION );
END_TEST;
}
+
+int UtcDaliLayouting_LayoutGroup01(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliLayouting_LayoutGroup01 - Test adding a control to a layout then adding a TextLabel to that control");
+
+ Control rootControl;
+ SetupRootLayoutControl( rootControl );
+
+ // Create a parent layout
+ auto hbox = Control::New();
+ auto hboxLayout = LinearLayout::New();
+ hbox.SetName( "HBox");
+ rootControl.Add( hbox );
+ DevelControl::SetLayout( hbox, hboxLayout );
+ hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+ hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+ hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // LinearLayout will eventually do this internally.
+
+ tet_infoline("Add a control without SetLayout being called");
+
+ auto control = Control::New();
+ control.SetName("Control1");
+ hbox.Add( control );
+ control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+ control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+
+ tet_infoline("Add a Textlabel to the control");
+ auto textLabel = TextLabel::New("Test text");
+ textLabel.SetName("TextLabel");
+ control.Add( textLabel );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Test text is it's natural size");
+ DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ tet_infoline("Test control is width of it's parent and height of it's child");
+ DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 600.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliLayouting_LayoutGroup02(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliLayouting_LayoutGroup02 - Test control is the size of it's largest child");
+
+ Control rootControl;
+ SetupRootLayoutControl( rootControl );
+
+ // Create a parent layout
+ auto hbox = Control::New();
+ auto hboxLayout = LinearLayout::New();
+ hbox.SetName( "HBox");
+ rootControl.Add( hbox );
+ DevelControl::SetLayout( hbox, hboxLayout );
+ hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+ hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+ hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // LinearLayout will eventually do this internally.
+
+ tet_infoline("Add a control without SetLayout being called");
+
+ auto control = Control::New();
+ control.SetName("Control1");
+ hbox.Add( control );
+ control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+ control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+
+ tet_infoline("Add a Textlabel to the control");
+ auto textLabel = TextLabel::New("Test text");
+ textLabel.SetName("TextLabel");
+ control.Add( textLabel );
+
+ tet_infoline("Add another Textlabel to the control");
+ auto largeTextLabel = TextLabel::New("Test large text");
+ largeTextLabel.SetName("TextLabel-Large");
+ control.Add( largeTextLabel );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Test text is it's natural size");
+ DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ tet_infoline("Test text is centered in the control, the control is the size of the largest child");
+ DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ tet_infoline("Test large text is it's natural size");
+ DALI_TEST_EQUALS( largeTextLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 382.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ tet_infoline("Test text is aligned to start as is the size of the control");
+ DALI_TEST_EQUALS( largeTextLabel.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ tet_infoline("Test control is width of it's parent and height of it's largest child");
+ DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 382.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliLayouting_LayoutGroup03(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliLayouting_LayoutGroup03 - Test control witha LayoutGroup as a leaf");
+
+ Control rootControl;
+ SetupRootLayoutControl( rootControl );
+
+ // Create a parent layout
+ auto hbox = Control::New();
+ auto hboxLayout = LinearLayout::New();
+ hbox.SetName( "HBox");
+ rootControl.Add( hbox );
+ DevelControl::SetLayout( hbox, hboxLayout );
+ hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+ hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+ hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // LinearLayout will eventually do this internally.
+
+ tet_infoline("Add a control without SetLayout being called");
+
+ auto control = Control::New();
+ control.SetName("Control1");
+ hbox.Add( control );
+ control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::MATCH_PARENT );
+ control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, 100 );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Test control is width of it's parent and exact given height");
+ DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 600.0f, 100.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::POSITION ), Vector3( 0.0f, 0.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliLayouting_LayoutGroupWithPadding01(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliLayouting_LayoutGroupWithPadding01 - Test adding a control to a layout that has padding");
+
+ Control rootControl;
+ SetupRootLayoutControl( rootControl );
+
+ // Create a parent layout
+ auto hbox = Control::New();
+ auto hboxLayout = LinearLayout::New();
+ hbox.SetName( "HBox");
+ rootControl.Add( hbox );
+ DevelControl::SetLayout( hbox, hboxLayout );
+ hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+ hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+ hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // LinearLayout will eventually do this internally.
+
+ tet_infoline("Add a control without SetLayout being called");
+
+ auto control = Control::New();
+ control.SetName("Control1");
+ hbox.Add( control );
+ control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+ control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+
+ const Extents CONTROL_PADDING = Extents(5, 10, 20, 2 );
+ tet_printf( "Adding Padding to control");
+ control.SetProperty( Toolkit::Control::Property::PADDING, CONTROL_PADDING );
+
+ tet_infoline("Add a Textlabel to the control");
+ auto textLabel = TextLabel::New("Test text");
+ textLabel.SetName("TextLabel");
+ control.Add( textLabel );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Test text is it's natural size");
+ DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ tet_infoline("Test control is size of it's child and control it's own padding");
+ DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 245.0f, 86.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ END_TEST;
+}
+
+int UtcDaliLayouting_LayoutGroupWithChildMargin01(void)
+{
+ ToolkitTestApplication application;
+ tet_infoline("UtcDaliLayouting_LayoutGroupWithChildMargin01 - Test adding a control with padding to a layout that has padding");
+
+ Control rootControl;
+ SetupRootLayoutControl( rootControl );
+
+ // Create a parent layout
+ auto hbox = Control::New();
+ auto hboxLayout = LinearLayout::New();
+ hbox.SetName( "HBox");
+ rootControl.Add( hbox );
+ DevelControl::SetLayout( hbox, hboxLayout );
+ hbox.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, 600 );
+ hbox.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+ hbox.SetAnchorPoint( AnchorPoint::TOP_LEFT ); // LinearLayout will eventually do this internally.
+
+ tet_infoline("Add a control without SetLayout being called");
+
+ auto control = Control::New();
+ control.SetName("Control1");
+ hbox.Add( control );
+ control.SetProperty( LayoutItem::ChildProperty::WIDTH_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+ control.SetProperty( LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, ChildLayoutData::WRAP_CONTENT );
+
+ const Extents CONTROL_PADDING = Extents(5, 10, 20, 2 );
+ tet_printf( "Adding Padding to control");
+ control.SetProperty( Toolkit::Control::Property::PADDING, CONTROL_PADDING );
+
+ tet_infoline("Add a Textlabel to the control");
+ auto textLabel = TextLabel::New("Test text");
+ const Extents CHILD_MARGIN = Extents( 10, 0, 5, 0 );
+ textLabel.SetProperty( Toolkit::Control::Property::MARGIN, CHILD_MARGIN );
+ textLabel.SetName("TextLabel");
+ control.Add( textLabel );
+
+ // Ensure layouting happens
+ application.SendNotification();
+ application.Render();
+
+ tet_infoline("Test text is it's natural size");
+ DALI_TEST_EQUALS( textLabel.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 230.0f, 64.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+ tet_infoline("Test control is width of it's parent and height of it's child");
+ DALI_TEST_EQUALS( control.GetProperty<Vector3>( Actor::Property::SIZE ), Vector3( 255.0f, 91.0f, 0.0f ), 0.0001f, TEST_LOCATION );
+
+ END_TEST;
+}
tet_result(TET_FAIL);
}
+ label.SetProperty( TextLabel::Property::TEXT, "Hello world " );
+ label.SetProperty( DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT, false );
+ label.SetSize( 400.0f, 10.f );
+
+ try
+ {
+ // Render the text.
+ application.SendNotification();
+ application.Render();
+ }
+ catch( ... )
+ {
+ tet_result(TET_FAIL);
+ }
+
END_TEST;
}
* | color | VECTOR4 | No | The color of the background (the default value is Color::CYAN) |
*/
BACKGROUND,
+
+ /**
+ * @brief Ignore spaces after text.
+ * @details Name "ignoreSpacesAfterText", type (Property::BOLEAN), Read/Write
+ * @note The default value is true
+ */
+ IGNORE_SPACES_AFTER_TEXT,
};
} // namespace Property
{
}
+LayoutGroupPtr LayoutGroup::New( Handle& owner )
+{
+ LayoutGroupPtr layoutPtr = new LayoutGroup();
+ return layoutPtr;
+}
+
LayoutGroup::~LayoutGroup()
{
// An object with a unique_ptr to an opaque structure must define it's destructor in the translation unit
#if defined( DEBUG_ENABLED )
if ( control )
{
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChild natural size(%f, %f)\n", control.GetNaturalSize().width, control.GetNaturalSize().height );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::MeasureChild(%s) natural size(%f, %f)\n",
+ control.GetName().c_str(), control.GetNaturalSize().width, control.GetNaturalSize().height );
}
#endif
LayoutItemPtr childLayout;
Toolkit::Control control = Toolkit::Control::DownCast( child );
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner control(%s)\n", control?control.GetName().c_str():"Invalid" );
+#if defined(DEBUG_ENABLED)
+ auto parent = Toolkit::Control::DownCast( GetOwner() );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::ChildAddedToOwner control(%s) owner(%s)\n", control?control.GetName().c_str():"Invalid", parent?parent.GetName().c_str():"Invalid" );
+#endif
if( control ) // Can only support adding Controls, not Actors to layout
{
if( ! childLayout )
{
// If the child doesn't already have a layout, then create a LayoutItem for it.
- childLayout = LayoutItem::New( control );
+ childLayout = LayoutGroup::New( control );
childLayout->SetAnimateLayout( IsLayoutAnimated() ); // @todo this essentially forces animation inheritance. Bad?
#if defined(DEBUG_ENABLED)
auto desiredSize = control.GetNaturalSize();
for( auto&& child : mImpl->mChildren )
{
LayoutGroupPtr parentGroup( dynamic_cast< LayoutGroup* >( child.child.Get() ) );
- if( !parentGroup )
+ if( parentGroup && ( 0 == parentGroup->GetChildCount() ) ) // A leaf LayoutGroup will have no children.
{
// Change state only in case of leaf children
child.child->SetAnimateLayout( animateLayout );
}
}
+void LayoutGroup::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
+{
+ DALI_LOG_STREAM( gLogFilter, Debug::Verbose,
+ "LayoutGroup::OnMeasure Actor Id:" << Actor::DownCast(GetOwner()).GetId() <<
+ " Owner:" << Actor::DownCast(GetOwner()).GetName() <<
+ " MeasureSpecs( width:"<<widthMeasureSpec<<", height:"<<heightMeasureSpec );
+
+ auto childCount = GetChildCount();
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure child count(%u)\n", childCount);
+
+ auto widthMode = widthMeasureSpec.GetMode();
+ auto heightMode = heightMeasureSpec.GetMode();
+ LayoutLength widthSpecSize = widthMeasureSpec.GetSize();
+ LayoutLength heightSpecSize = heightMeasureSpec.GetSize();
+
+ bool exactWidth ( false );
+ bool exactHeight ( false );
+
+ // Default Layouting behaviour if not overridden
+ // EXACT, width and height as provided.
+ // MATCH_PARENT, width and hewidthSpecSizeight that of parent
+
+ // WRAP_CONTENT, take width of widest child and height size of longest child (within given limit)
+ // UNSPECIFIED, take width of widest child and height size of longest child.
+
+ LayoutLength layoutWidth( 0 );
+ LayoutLength layoutHeight( 0 );
+
+ // If LayoutGroup has children then measure children to get max dimensions
+ if ( childCount > 0 )
+ {
+ for( unsigned int i=0; i<childCount; ++i )
+ {
+ auto childLayout = GetChildAt( i );
+ if( childLayout )
+ {
+ auto childOwner = childLayout->GetOwner();
+
+ // Get size of child
+ MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
+ auto childWidth = childLayout->GetMeasuredWidth();
+ auto childHeight = childLayout->GetMeasuredHeight();
+ auto childMargin = childLayout->GetMargin();
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure child width[%d] height(%d)\n", childWidth.mValue, childHeight.mValue );
+
+ layoutWidth = std::max( layoutWidth, childWidth + childMargin.start + childMargin.end );
+ layoutHeight = std::max( layoutHeight, childHeight + childMargin.top + childMargin.bottom );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure calculated child width[%d] calculated height(%d)\n", layoutWidth.mValue, layoutHeight.mValue );
+ }
+ }
+
+ Extents padding = GetPadding();
+ layoutWidth += padding.start + padding.end;
+ layoutHeight += padding.top + padding.bottom;
+ }
+ else
+ {
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure Getting default size as a leaf\n" );
+ // LayoutGroup does not contain any children so must be a leaf
+ layoutWidth = GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec );
+ layoutHeight = GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec );
+ }
+
+ // Can't exceed specified width
+ if( widthMode == MeasureSpec::Mode::EXACTLY )
+ {
+ exactWidth = true;
+ }
+ else if ( widthMode == MeasureSpec::Mode::AT_MOST )
+ {
+ layoutWidth = std::min( layoutWidth, widthSpecSize );
+ }
+
+ // Can't exceed specified height
+ if( heightMode == MeasureSpec::Mode::EXACTLY )
+ {
+ exactHeight = true;
+ }
+ else if ( heightMode == MeasureSpec::Mode::AT_MOST )
+ {
+ layoutHeight = std::min( layoutHeight, heightSpecSize );
+ }
+
+ layoutWidth = std::max( layoutWidth, GetSuggestedMinimumWidth() );
+ layoutHeight = std::max( layoutHeight, GetSuggestedMinimumHeight() );
+
+ if( exactWidth )
+ {
+ layoutWidth = widthSpecSize;
+ }
+
+ if( exactHeight )
+ {
+ layoutHeight = heightSpecSize;
+ }
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnMeasure Measured size(%d,%d) for : %s \n", layoutWidth.mValue, layoutHeight.mValue, Actor::DownCast(GetOwner()).GetName().c_str() );
+ SetMeasuredDimensions( MeasuredSize( layoutWidth ), MeasuredSize( layoutHeight ) );
+}
+
+void LayoutGroup::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
+{
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnLayout\n");
+
+ auto count = GetChildCount();
+
+ for( unsigned int childIndex = 0; childIndex < count; childIndex++)
+ {
+ LayoutItemPtr childLayout = GetChildAt( childIndex );
+ if( childLayout != nullptr )
+ {
+
+ auto childOwner = childLayout->GetOwner();
+ auto childWidth = childLayout->GetMeasuredWidth();
+ auto childHeight = childLayout->GetMeasuredHeight();
+ auto childMargin = childLayout->GetMargin();
+ auto control = Toolkit::Control::DownCast( childOwner );
+ Extents padding = GetPadding();
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnLayout child width[%d] height(%d)\n", childWidth.mValue, childHeight.mValue );
+
+ auto childPosition = control.GetProperty< Vector3 >( Actor::Property::POSITION );
+ auto anchorPoint = control.GetProperty< Vector3 >( Actor::Property::ANCHOR_POINT );
+
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnLayout child[%s] position(%f,%f)\n", control.GetName().c_str(), childPosition.x, childPosition.y );
+
+ // Margin and Padding only supported when child anchor point is TOP_LEFT.
+ int paddingAndMarginOffsetX = ( AnchorPoint::TOP_LEFT == anchorPoint ) ? ( padding.top + childMargin.top ) : 0;
+ int paddingAndMarginOffsetY = ( AnchorPoint::TOP_LEFT == anchorPoint ) ? ( padding.start + childMargin.start ) : 0;
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutGroup::OnLayout paddingMargin offset(%d,%d)\n", paddingAndMarginOffsetX, paddingAndMarginOffsetY );
+
+ LayoutLength childLeft = childPosition.x + paddingAndMarginOffsetX;
+ LayoutLength childTop = childPosition.y + paddingAndMarginOffsetY;
+
+ childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
+ }
+ }
+}
+
+
} // namespace Internal
} // namespace Toolkit
} // namespace Dali
*/
LayoutGroup();
+ /**
+ * @brief Construct
+ *
+ * @param[in] owner The owner (container view / child view / visual ) of this layout
+ * @return a new LayoutGroup object
+ */
+ static LayoutGroupPtr New( Handle& owner );
+
protected:
/**
* Virtual destructor may only be called by Unreference()
LayoutLength widthUsed,
MeasureSpec parentHeightMeasureSpec,
LayoutLength heightUsed );
+ /**
+ * @copydoc LayoutItem::OnMeasure
+ */
+ virtual void OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec ) override;
+
+ /**
+ * @copydoc LayoutItem::OnLayout
+ */
+ virtual void OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom ) override;
private:
/**
{
}
+LayoutGroup LayoutGroup::New( Handle& handle )
+{
+ Internal::LayoutGroupPtr layout = Internal::LayoutGroup::New( handle );
+ return LayoutGroup( layout.Get() );
+}
+
LayoutGroup LayoutGroup::DownCast( BaseHandle handle )
{
return LayoutGroup( dynamic_cast< Dali::Toolkit::Internal::LayoutGroup* >( handle.GetObjectPtr() ) );
~LayoutGroup() = default;
/**
+ * @brief Create an initialized LayoutGroup
+ *
+ * @param[in] handle A handle to the object that this layout for, e.g. a Control or a Visual::Base
+ */
+ static LayoutGroup New( Handle& handle );
+
+ /**
* @brief Copy constructor
*/
LayoutGroup(const LayoutGroup& copy) = default;
void LayoutItem::SetAnimateLayout( bool animateLayout )
{
+ DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetAnimateLayout animateLayout(%s)\n", (animateLayout)?"true":"false" );
+
+ auto owner = GetOwner();
+ auto actor = Actor::DownCast(owner);
+
+ if( actor )
+ {
+ DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetAnimateLayout animateLayout(%s) owner(%s)\n", (animateLayout)?"true":"false", actor.GetName().c_str() );
+ }
+
mImpl->mAnimated = animateLayout;
OnAnimationStateChanged( animateLayout );
#if defined(DEBUG_ENABLED)
std::ostringstream o;
o<<widthMeasureSpec<<","<<heightMeasureSpec;
- DALI_LOG_INFO( gLayoutFilter, Debug::Concise, "Calling %s OnMeasure( %s )\n", Actor::DownCast(GetOwner()).GetName().c_str(), o.str().c_str());
+ DALI_LOG_INFO( gLayoutFilter, Debug::Concise, "LayoutItem::Measure Calling %s OnMeasure( %s )\n", Actor::DownCast(GetOwner()).GetName().c_str(), o.str().c_str());
#endif
OnMeasure( widthMeasureSpec, heightMeasureSpec );
mImpl->ClearPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT );
// flag not set, setMeasuredDimension() was not invoked, we raise an exception to warn the developer
DALI_ASSERT_ALWAYS( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURED_DIMENSION_SET ) &&
- "Layout's OnMeasure() did not set the measured dimension by calling setMeasuredDimension()" );
+ "Layout's OnMeasure() mension()" );
mImpl->SetPrivateFlag( Impl::PRIVATE_FLAG_LAYOUT_REQUIRED );
}
void LayoutItem::Layout( LayoutLength l, LayoutLength t, LayoutLength r, LayoutLength b )
{
+ DALI_LOG_TRACE_METHOD( gLayoutFilter );
+
if( mImpl->GetPrivateFlag( Impl::PRIVATE_FLAG_MEASURE_NEEDED_BEFORE_LAYOUT ) )
{
OnMeasure( mImpl->mOldWidthMeasureSpec, mImpl->mOldHeightMeasureSpec );
{
Extents padding = control.GetProperty<Extents>( Toolkit::Control::Property::PADDING );
- DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutBase::Padding for %s : (%d,%d,%d,%d) \n",
+ DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::Padding for %s : (%d,%d,%d,%d) \n",
control.GetName().c_str(),
padding.start, padding.end, padding.top, padding.bottom
);
void LayoutItem::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec)
{
+ DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::OnMeasure\n");
+
SetMeasuredDimensions( GetDefaultSize( GetSuggestedMinimumWidth(), widthMeasureSpec ),
GetDefaultSize( GetSuggestedMinimumHeight(), heightMeasureSpec ) );
}
void LayoutItem::SetMeasuredDimensions( MeasuredSize measuredWidth, MeasuredSize measuredHeight )
{
- DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutBase::SetMeasuredDimensions width(%d) height(%d) \n",
+ DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetMeasuredDimensions width(%d) height(%d) \n",
MeasureSpec::IntType( measuredWidth.GetSize() ),
MeasureSpec::IntType( measuredHeight.GetSize() )
);
auto actor = Actor::DownCast(owner);
if( actor )
{
+ DALI_LOG_INFO( gLayoutFilter, Debug::Verbose, "LayoutItem::SetFrame owner(%s) (%d, %d, %d, %d)\n", actor.GetName().c_str(),
+ left.mValue, top.mValue, right.mValue, bottom.mValue );
if( mImpl->mAnimated )
{
auto animation = Animation::New( 0.5f );
GetImplementation(*this).SetCellPadding( size );
}
-LayoutSize LinearLayout::GetCellPadding()
+LayoutSize LinearLayout::GetCellPadding() const
{
return GetImplementation(*this).GetCellPadding();
}
GetImplementation(*this).SetOrientation( orientation );
}
-LinearLayout::Orientation LinearLayout::GetOrientation()
+LinearLayout::Orientation LinearLayout::GetOrientation() const
{
return GetImplementation(*this).GetOrientation();
}
+void LinearLayout::SetAlignment( unsigned int alignment )
+{
+ GetImplementation(*this).SetAlignment( alignment );
+}
+
+unsigned int LinearLayout::GetAlignment() const
+{
+ return GetImplementation(*this).GetAlignment();
+}
+
LinearLayout::LinearLayout( Dali::Toolkit::Internal::LinearLayout* object )
: LayoutGroup( object )
{
};
/**
+ * @brief Enumeration for the alignment of the linear layout items.
+ */
+ struct Alignment
+ {
+ enum Type
+ {
+ BEGIN = 0x1, ///< At the left/right edge of the container (maps to LTR/RTL direction for horizontal orientation)
+ END = 0x2, ///< At the right/left edge of the container (maps to LTR/RTL direction for horizontal orientation)
+ CENTER_HORIZONTAL = 0x4, ///< At the horizontal center of the container
+ TOP = 0x8, ///< At the top edge of the container
+ BOTTOM = 0x10, ///< At the bottom edge of the container
+ CENTER_VERTICAL = 0x20 ///< At the vertical center of the container
+ };
+ };
+
+ /**
* @brief Creates an uninitialized LinearLayout handle.
*
* Initialize it using LinearLayout::New().
*
* @return The padding between cells.
*/
- LayoutSize GetCellPadding();
+ LayoutSize GetCellPadding() const;
/**
* @brief Set the orientation in the layout
*
* @return The orientation.
*/
- Orientation GetOrientation();
+ Orientation GetOrientation() const;
+
+ /**
+ * @brief Set the alignment in the layout
+ *
+ * @param[in] alignment The alignment.
+ */
+ void SetAlignment( unsigned int alignment );
+
+ /**
+ * @brief Get the alignment in the layout
+ *
+ * @return The alignment.
+ */
+ unsigned int GetAlignment() const;
public: // Not intended for application developers
DALI_DEVEL_PROPERTY_REGISTRATION_READ_ONLY( Toolkit, TextLabel, "textDirection", INTEGER, TEXT_DIRECTION )
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "verticalLineAlignment", INTEGER, VERTICAL_LINE_ALIGNMENT )
DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "textBackground", MAP, BACKGROUND )
+DALI_DEVEL_PROPERTY_REGISTRATION( Toolkit, TextLabel, "ignoreSpacesAfterText", BOOLEAN, IGNORE_SPACES_AFTER_TEXT )
DALI_ANIMATABLE_PROPERTY_REGISTRATION_WITH_DEFAULT( Toolkit, TextLabel, "textColor", Color::BLACK, TEXT_COLOR )
DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorRed", TEXT_COLOR_RED, TEXT_COLOR, 0 )
DALI_ANIMATABLE_PROPERTY_COMPONENT_REGISTRATION( Toolkit, TextLabel, "textColorGreen", TEXT_COLOR_GREEN, TEXT_COLOR, 1 )
}
break;
}
+ case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT:
+ {
+ impl.mController->SetIgnoreSpacesAfterText(value.Get< bool >());
+ break;
+ }
}
// Request relayout when text update is needed. It's necessary to call it
GetBackgroundProperties( impl.mController, value, Text::EffectStyle::DEFAULT );
break;
}
+ case Toolkit::DevelTextLabel::Property::IGNORE_SPACES_AFTER_TEXT:
+ {
+ value = impl.mController->IsIgnoreSpacesAfterText();
+ break;
+ }
}
}
// Store current width and height needed to contain all children.
totalWidth = maxPosition.x - minPosition.x;
totalHeight = maxPosition.y - minPosition.y;
- DALI_LOG_INFO( gLogFilter, Debug::Concise, "AbsoluteLayout::OnMeasure child width(%f) height(%f) \n", (float)totalWidth, (float)totalHeight );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "AbsoluteLayout::OnMeasure child width(%f) height(%f) \n", (float)totalWidth, (float)totalHeight );
if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
{
// Absolute layout positions it's children at their Actor positions.
// Children could overlap or spill outside the parent, as is the nature of absolute positions.
auto count = GetChildCount();
+ DALI_LOG_INFO( gLogFilter, Debug::Concise, "AbsoluteLayout::OnLayout child count(%d)\n", count );
for( unsigned int i = 0; i < count; i++)
{
: LayoutGroup(),
mTotalHeight( 0 ),
mTotalWidth( 0 ),
- mNumColumns( AUTO_FIT ),
- mNumRows( AUTO_FIT ),
+ mNumColumns( 1 ),
+ mNumRows( 1 ),
mRequestedColumnWidth( 0 ),
mRequestedNumColumns( AUTO_FIT )
{
Toolkit::Control control = Toolkit::Control::DownCast( root );
if( control )
{
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::Measuring leaf\n" );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::Measuring control\n" );
Internal::Control& controlImpl = GetImplementation( control );
Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
Toolkit::Control control = Toolkit::Control::DownCast( root );
if( control )
{
- DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayout on leaf\n" );
+ DALI_LOG_INFO( gLogFilter, Debug::Verbose, "LayoutController::PerformLayout on control[%s]\n", control.GetName().c_str() );
Internal::Control& controlImpl = GetImplementation( control );
Internal::Control::Impl& controlDataImpl = Internal::Control::Impl::Get( controlImpl );
LayoutItemPtr layout = controlDataImpl.GetLayout();
namespace Internal
{
+const int HORIZONTAL_ALIGNMENT_MASK = ( Dali::Toolkit::LinearLayout::Alignment::BEGIN | Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL | Dali::Toolkit::LinearLayout::Alignment::END );
+const int VERTICAL_ALIGNMENT_MASK = ( Dali::Toolkit::LinearLayout::Alignment::TOP | Dali::Toolkit::LinearLayout::Alignment::CENTER_VERTICAL | Dali::Toolkit::LinearLayout::Alignment::BOTTOM );
+
LinearLayoutPtr LinearLayout::New()
{
LinearLayoutPtr layout( new LinearLayout() );
: LayoutGroup(),
mCellPadding( 0, 0 ),
mOrientation( Dali::Toolkit::LinearLayout::Orientation::HORIZONTAL ),
+ mAlignment( Dali::Toolkit::LinearLayout::Alignment::BEGIN | Dali::Toolkit::LinearLayout::Alignment::CENTER_VERTICAL ),
mTotalLength( 0 )
{
}
}
}
-LayoutSize LinearLayout::GetCellPadding()
+LayoutSize LinearLayout::GetCellPadding() const
{
return mCellPadding;
}
}
}
-Dali::Toolkit::LinearLayout::Orientation LinearLayout::GetOrientation()
+Dali::Toolkit::LinearLayout::Orientation LinearLayout::GetOrientation() const
{
return mOrientation;
}
+void LinearLayout::SetAlignment( unsigned int alignment )
+{
+ if ( mAlignment != alignment )
+ {
+ mAlignment = alignment;
+ RequestLayout();
+ }
+}
+
+unsigned int LinearLayout::GetAlignment() const
+{
+ return mAlignment;
+}
+
void LinearLayout::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
{
#if defined(DEBUG_ENABLED)
auto count = GetChildCount();
+ switch ( mAlignment & HORIZONTAL_ALIGNMENT_MASK )
+ {
+ case Dali::Toolkit::LinearLayout::Alignment::BEGIN:
+ default:
+ {
+ // mTotalLength contains the padding already
+ // In case of RTL map BEGIN alignment to the right edge
+ if ( isLayoutRtl ) {
+ childLeft = LayoutLength( padding.start ) + right - left - mTotalLength;
+ }
+ else {
+ childLeft = LayoutLength( padding.start );
+ }
+ break;
+ }
+ case Dali::Toolkit::LinearLayout::Alignment::END:
+ {
+ // mTotalLength contains the padding already
+ // In case of RTL map END alignment to the left edge
+ if ( isLayoutRtl ) {
+ childLeft = LayoutLength( padding.start );
+ }
+ else {
+ childLeft = LayoutLength( padding.start ) + right - left - mTotalLength;
+ }
+ break;
+ }
+ case Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL:
+ {
+ // mTotalLength contains the padding already
+ childLeft = LayoutLength( padding.start ) + ( right - left - mTotalLength ) / 2;
+ break;
+ }
+ }
+
int start = 0;
int dir = 1;
- // In case of RTL, start drawing from the last child and apply right alignment.
- // @TODO Should we have also support Actor HorizontalAlignment|VerticalAlignment in general for LinearLayout?
+ // In case of RTL, start drawing from the last child.
if( isLayoutRtl ) {
start = count - 1;
dir = -1;
- childLeft = padding.start + right - left - mTotalLength;
}
for( unsigned int i = 0; i < count; i++)
auto childHeight = childLayout->GetMeasuredHeight();
auto childMargin = childLayout->GetMargin();
- childTop = LayoutLength(padding.top) + ((childSpace - childHeight) / 2) + childMargin.top - childMargin.bottom;
-
+ switch ( mAlignment & VERTICAL_ALIGNMENT_MASK )
+ {
+ case Dali::Toolkit::LinearLayout::Alignment::TOP:
+ {
+ childTop = LayoutLength( padding.top ) + childMargin.top;
+ break;
+ }
+ case Dali::Toolkit::LinearLayout::Alignment::BOTTOM:
+ {
+ childTop = height - padding.bottom - childHeight - childMargin.bottom;
+ break;
+ }
+ case Dali::Toolkit::LinearLayout::Alignment::CENTER_VERTICAL:
+ default:
+ {
+ childTop = LayoutLength( padding.top ) + ( ( childSpace - childHeight ) / 2 ) + childMargin.top - childMargin.bottom;
+ break;
+ }
+ }
childLeft += childMargin.start;
childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
childLeft += childWidth + childMargin.end + mCellPadding.width;
LayoutLength childTop( padding.top );
LayoutLength childLeft( padding.start );
- // Where bottom of child should go
+ // Where end of child should go
auto width = right - left;
// Space available for child
auto childSpace = width - padding.start - padding.end;
auto count = GetChildCount();
+ switch ( mAlignment & VERTICAL_ALIGNMENT_MASK )
+ {
+ case Dali::Toolkit::LinearLayout::Alignment::TOP:
+ {
+ // mTotalLength contains the padding already
+ childTop = LayoutLength( padding.top );
+ break;
+ }
+ case Dali::Toolkit::LinearLayout::Alignment::BOTTOM:
+ {
+ // mTotalLength contains the padding already
+ childTop = LayoutLength( padding.top ) + bottom - top - mTotalLength;
+ break;
+ }
+ case Dali::Toolkit::LinearLayout::Alignment::CENTER_VERTICAL:
+ default:
+ {
+ // mTotalLength contains the padding already
+ childTop = LayoutLength( padding.top ) + ( bottom - top - mTotalLength ) / 2;
+ break;
+ }
+ }
+
for( unsigned int childIndex = 0; childIndex < count; childIndex++)
{
LayoutItemPtr childLayout = GetChildAt( childIndex );
auto childMargin = childLayout->GetMargin();
childTop += childMargin.top;
- childLeft = LayoutLength( padding.start ) + ( childSpace - childWidth ) / 2 + childMargin.start - childMargin.end;
-
+ switch ( mAlignment & HORIZONTAL_ALIGNMENT_MASK )
+ {
+ case Dali::Toolkit::LinearLayout::Alignment::BEGIN:
+ default:
+ {
+ childLeft = LayoutLength( padding.start ) + childMargin.start;
+ break;
+ }
+ case Dali::Toolkit::LinearLayout::Alignment::END:
+ {
+ childLeft = width - padding.end - childWidth - childMargin.end;
+ break;
+ }
+ case Dali::Toolkit::LinearLayout::Alignment::CENTER_HORIZONTAL:
+ {
+ childLeft = LayoutLength( padding.start ) + ( childSpace - childWidth ) / 2 + childMargin.start - childMargin.end;
+ break;
+ }
+ }
childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
childTop += childHeight + childMargin.bottom + mCellPadding.height;
}
class LinearLayout final : public LayoutGroup
{
public:
+ /**
+ * Creates a pointer to a LinearLayout implementation.
+ */
static LinearLayoutPtr New();
public:
+ /**
+ * @brief Set the padding between cells in the layout
+ *
+ * @param[in] size The padding between cells.
+ */
void SetCellPadding( LayoutSize size );
- LayoutSize GetCellPadding();
+
+ /**
+ * @brief Get the padding between cells in the layout
+ *
+ * @return The padding between cells.
+ */
+ LayoutSize GetCellPadding() const;
+
+ /**
+ * @brief Set the orientation in the layout
+ *
+ * @param[in] orientation The orientation.
+ */
void SetOrientation( Dali::Toolkit::LinearLayout::Orientation orientation );
- Dali::Toolkit::LinearLayout::Orientation GetOrientation();
+
+ /**
+ * @brief Get the orientation in the layout
+ *
+ * @return The orientation.
+ */
+ Dali::Toolkit::LinearLayout::Orientation GetOrientation() const;
+
+ /**
+ * @brief Set the alignment in the layout
+ *
+ * @param[in] alignment The alignment.
+ */
+ void SetAlignment( unsigned int alignment );
+
+ /**
+ * @brief Get the alignment in the layout
+ *
+ * @return The alignment.
+ */
+ unsigned int GetAlignment() const;
protected:
+ /**
+ * Default Constructor
+ */
LinearLayout();
+
+ /**
+ * Destructor
+ */
virtual ~LinearLayout();
/**
private:
LayoutSize mCellPadding;
Dali::Toolkit::LinearLayout::Orientation mOrientation;
+ unsigned int mAlignment;
LayoutLength mTotalLength;
};
// Get the line break info for the current character.
const LineBreakInfo lineBreakInfo = hasCharacters ? *( parameters.lineBreakInfoBuffer + characterLastIndex ) : TextAbstraction::LINE_NO_BREAK;
- // Get the word break info for the current character.
- const WordBreakInfo wordBreakInfo = *( parameters.wordBreakInfoBuffer + characterLastIndex );
-
// Increase the number of characters.
tmpLineLayout.numberOfCharacters += charactersPerGlyph;
tmpLineLayout.wsLengthEndOfLine = 0.f;
}
+ // If calculation is end but wsLengthEndOfLine is exist, it means end of text is space.
+ // Merge remained length.
+ if ( !parameters.ignoreSpaceAfterText && glyphIndex == lastGlyphOfParagraphPlusOne-1 && tmpLineLayout.wsLengthEndOfLine > 0 )
+ {
+ tmpLineLayout.length += tmpLineLayout.wsLengthEndOfLine;
+ tmpLineLayout.wsLengthEndOfLine = 0u;
+ }
+
// Save the current extra width to compare with the next one
mPreviousCharacterExtraWidth = tmpExtraWidth;
// Check if the accumulated length fits in the width of the box.
- if( ( completelyFill || isMultiline ) && !isWhiteSpace &&
+ if( ( completelyFill || isMultiline ) && !(parameters.ignoreSpaceAfterText && isWhiteSpace) &&
( tmpExtraBearing + lineLayout.length + lineLayout.wsLengthEndOfLine + tmpLineLayout.length + tmpExtraWidth > parameters.boundingBox.width ) )
{
// Current word does not fit in the box's width.
}
if( isMultiline &&
- ( TextAbstraction::WORD_BREAK == wordBreakInfo ) )
+ ( TextAbstraction::LINE_ALLOW_BREAK == lineBreakInfo ) )
{
oneWordLaidOut = isWordLaidOut;
DALI_LOG_INFO( gLogFilter, Debug::Verbose, " One word laid-out\n" );
Length totalNumberOfGlyphs,
Text::HorizontalAlignment::Type horizontalAlignment,
Text::LineWrap::Mode lineWrapMode,
- float outlineWidth )
+ float outlineWidth,
+ bool ignoreSpaceAfterText )
: boundingBox( boundingBox ),
textBuffer( textBuffer ),
lineBreakInfoBuffer( lineBreakInfoBuffer ),
startLineIndex( 0u ),
estimatedNumberOfLines( 0u ),
lineWrapMode( lineWrapMode ),
+ outlineWidth( outlineWidth ),
isLastNewParagraph( false ),
- outlineWidth( outlineWidth )
+ ignoreSpaceAfterText( ignoreSpaceAfterText )
{}
Vector2 boundingBox; ///< The size of the box containing the text.
LineIndex startLineIndex; ///< The line index where to insert the new lines.
Length estimatedNumberOfLines; ///< The estimated number of lines.
Text::LineWrap::Mode lineWrapMode; ///< The line wrap mode for moving to next line.
- bool isLastNewParagraph; ///< Whether the last character is a new paragraph character.
float outlineWidth; ///< The outline width.
+ bool isLastNewParagraph:1; ///< Whether the last character is a new paragraph character.
+ bool ignoreSpaceAfterText:1; ///< Whether ignoring spaces after text or not. Default is true.
};
} // namespace Layout
return mImpl->mModel->mVerticalAlignment;
}
+bool Controller::IsIgnoreSpacesAfterText() const
+{
+ return mImpl->mModel->mIgnoreSpacesAfterText;
+}
+
+void Controller::SetIgnoreSpacesAfterText( bool ignore )
+{
+ mImpl->mModel->mIgnoreSpacesAfterText = ignore;
+}
+
void Controller::SetLineWrapMode( Text::LineWrap::Mode lineWrapMode )
{
if( lineWrapMode != mImpl->mModel->mLineWrapMode )
totalNumberOfGlyphs,
mImpl->mModel->mHorizontalAlignment,
mImpl->mModel->mLineWrapMode,
- outlineWidth );
+ outlineWidth,
+ mImpl->mModel->mIgnoreSpacesAfterText );
// Resize the vector of positions to have the same size than the vector of glyphs.
Vector<Vector2>& glyphPositions = mImpl->mModel->mVisualModel->mGlyphPositions;
*/
void SetVerticalLineAlignment( Toolkit::DevelText::VerticalLineAlignment::Type alignment );
+ /**
+ * @brief Retrieves ignoreSpaceAfterText value from model
+ * @return The value of ignoreSpaceAfterText
+ */
+ bool IsIgnoreSpacesAfterText() const;
+
+ /**
+ * @brief Sets ignoreSpaceAfterText value to model
+ * @param[in] ignore The value of ignoreSpacesAfterText for the text
+ */
+ void SetIgnoreSpacesAfterText( bool ignore );
+
public: // Relayout.
/**
mVerticalLineAlignment( DevelText::VerticalLineAlignment::TOP ),
mLineWrapMode( Text::LineWrap::WORD ),
mAlignmentOffset( 0.0f ),
- mElideEnabled( false )
+ mElideEnabled( false ),
+ mIgnoreSpacesAfterText( true )
{
mLogicalModel = LogicalModel::New();
mVisualModel = VisualModel::New();
* 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.
*/
- Vector2 mScrollPosition; ///< The text is offset by this position when scrolling.
- Vector2 mScrollPositionLast; ///< The last offset value of mScrollPosition
- HorizontalAlignment::Type mHorizontalAlignment; ///< The layout's horizontal alignment.
- VerticalAlignment::Type mVerticalAlignment; ///< The layout's vertical alignment.
- DevelText::VerticalLineAlignment::Type mVerticalLineAlignment; ///< The layout's vertical line alignment.
- Text::LineWrap::Mode mLineWrapMode; ///< The text wrap mode
- float mAlignmentOffset; ///< The alignment offset.
- bool mElideEnabled:1; ///< Whether the text's elide is enabled.
+ Vector2 mScrollPosition; ///< The text is offset by this position when scrolling.
+ Vector2 mScrollPositionLast; ///< The last offset value of mScrollPosition
+ HorizontalAlignment::Type mHorizontalAlignment; ///< The layout's horizontal alignment.
+ VerticalAlignment::Type mVerticalAlignment; ///< The layout's vertical alignment.
+ DevelText::VerticalLineAlignment::Type mVerticalLineAlignment; ///< The layout's vertical line alignment.
+ Text::LineWrap::Mode mLineWrapMode; ///< The text wrap mode
+ float mAlignmentOffset; ///< The alignment offset.
+ bool mElideEnabled:1; ///< Whether the text's elide is enabled.
+ bool mIgnoreSpacesAfterText:1; ///< Whether ignoring spaces after text or not. Default is true.
};
} // namespace Text
{
/**
- * @brief Placeholder text Propeties used by Text controls to show placeholder
+ * @brief Placeholder text Properties used by Text controls to show placeholder
* @SINCE_1_2.62
*
*/
const unsigned int TOOLKIT_MAJOR_VERSION = 1;
const unsigned int TOOLKIT_MINOR_VERSION = 3;
-const unsigned int TOOLKIT_MICRO_VERSION = 38;
+const unsigned int TOOLKIT_MICRO_VERSION = 39;
const char * const TOOLKIT_BUILD_DATE = __DATE__ " " __TIME__;
#ifdef DEBUG_ENABLED
"enableAutoScroll":false,
"autoScrollLoopCount":2,
"autoScrollGap":50,
- "autoScrollSpeed":80
+ "autoScrollSpeed":80,
+ "ignoreSpacesAfterText":false
},
"TextLabelFontSize0":
Name: dali-toolkit
Summary: Dali 3D engine Toolkit
-Version: 1.3.38
+Version: 1.3.39
Release: 1
Group: System/Libraries
License: Apache-2.0 and BSD-3-Clause and MIT