2 * Copyright (c) 2018 Samsung Electronics Co., Ltd.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include <dali-toolkit/internal/layouting/hbox-layout-impl.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/common/extents.h>
24 #include <dali/public-api/actors/actor.h>
25 #include <dali-toolkit/devel-api/layouting/layout-item.h>
26 #include <dali-toolkit/public-api/controls/control-impl.h>
27 #include <dali-toolkit/internal/controls/control/control-data-impl.h>
31 #if defined(DEBUG_ENABLED)
32 static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" );
43 HboxLayoutPtr HboxLayout::New()
45 HboxLayoutPtr layout( new HboxLayout() );
49 HboxLayout::HboxLayout()
56 HboxLayout::~HboxLayout()
60 void HboxLayout::DoInitialize()
64 void HboxLayout::DoRegisterChildProperties( const std::string& containerType )
66 auto typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( containerType );
69 Property::IndexContainer indices;
70 typeInfo.GetChildPropertyIndices( indices );
72 if( std::find( indices.Begin(), indices.End(), Toolkit::HboxLayout::ChildProperty::WEIGHT ) == indices.End() )
74 ChildPropertyRegistration( typeInfo.GetName(), "weight",
75 Toolkit::HboxLayout::ChildProperty::WEIGHT, Property::FLOAT );
80 void HboxLayout::OnChildAdd( LayoutItem& child )
82 auto owner = child.GetOwner();
83 owner.SetProperty( Toolkit::HboxLayout::ChildProperty::WEIGHT, 1.0f );
86 void HboxLayout::SetCellPadding( LayoutSize size )
91 LayoutSize HboxLayout::GetCellPadding()
96 void HboxLayout::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
98 #if defined(DEBUG_ENABLED)
99 auto actor = Actor::DownCast(GetOwner());
101 std::ostringstream oss;
102 oss << "HBoxLayout::OnMeasure ";
105 oss << "Actor Id:" << actor.GetId() << " Name:" << actor.GetName() << " ";
107 oss << "widthMeasureSpec:" << widthMeasureSpec << " heightMeasureSpec:" << heightMeasureSpec << std::endl;
108 DALI_LOG_INFO( gLogFilter, Debug::Concise, oss.str().c_str() );
111 DALI_LOG_INFO( gLogFilter, Debug::Concise, "HboxLayout::OnMeasure widthSize(%d) \n", widthMeasureSpec.GetSize());
113 auto widthMode = widthMeasureSpec.GetMode();
114 auto heightMode = heightMeasureSpec.GetMode();
115 bool isExactly = (widthMode == MeasureSpec::Mode::EXACTLY);
116 bool matchHeight = false;
117 bool allFillParent = true;
118 LayoutLength maxHeight = 0;
119 LayoutLength alternativeMaxHeight = 0;
122 MeasuredSize::State widthState;
123 MeasuredSize::State heightState;
124 } childState = { MeasuredSize::State::MEASURED_SIZE_OK, MeasuredSize::State::MEASURED_SIZE_OK };
126 // measure children, and determine if further resolution is required
127 for( unsigned int i=0; i<GetChildCount(); ++i )
129 auto childLayout = GetChildAt( i );
132 auto childOwner = childLayout->GetOwner();
133 auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
135 MeasureChild( childLayout, widthMeasureSpec, heightMeasureSpec );
136 auto childWidth = childLayout->GetMeasuredWidth();
137 auto childMargin = childLayout->GetMargin();
139 DALI_LOG_INFO( gLogFilter, Debug::Verbose, "HboxLayout::OnMeasure childWidth(%d)\n", MeasureSpec::IntType( childWidth ) );
141 auto length = childWidth + LayoutLength::IntType(childMargin.start + childMargin.end);
143 auto cellPadding = i<GetChildCount()-1 ? mCellPadding.width: 0;
147 mTotalLength += length;
151 auto totalLength = mTotalLength;
152 mTotalLength = std::max( totalLength, totalLength + length + cellPadding );
155 bool matchHeightLocally = false;
156 if( heightMode != MeasureSpec::Mode::EXACTLY && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT )
158 // Will have to re-measure at least this child when we know exact height.
160 matchHeightLocally = true;
163 auto marginHeight = LayoutLength( childMargin.top + childMargin.bottom );
164 auto childHeight = childLayout->GetMeasuredHeight() + marginHeight;
166 if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
168 childState.widthState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
170 if( childLayout->GetMeasuredHeightAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
172 childState.heightState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
175 maxHeight = std::max( maxHeight, childHeight );
176 allFillParent = ( allFillParent && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT );
177 alternativeMaxHeight = std::max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
181 Extents padding = GetPadding();
182 mTotalLength += padding.start + padding.end;
183 auto widthSize = mTotalLength;
184 widthSize = std::max( widthSize, GetSuggestedMinimumWidth() );
185 MeasuredSize widthSizeAndState = ResolveSizeAndState( widthSize, widthMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK);
186 widthSize = widthSizeAndState.GetSize();
188 if( !allFillParent && heightMode != MeasureSpec::Mode::EXACTLY )
190 maxHeight = alternativeMaxHeight;
192 maxHeight += padding.top + padding.bottom;
193 maxHeight = std::max( maxHeight, GetSuggestedMinimumHeight() );
195 widthSizeAndState.SetState( childState.widthState );
197 SetMeasuredDimensions( widthSizeAndState,
198 ResolveSizeAndState( maxHeight, heightMeasureSpec, childState.heightState ) );
202 ForceUniformHeight( GetChildCount(), widthMeasureSpec );
206 void HboxLayout::ForceUniformHeight( int count, MeasureSpec widthMeasureSpec )
208 // Pretend that the linear layout has an exact size. This is the measured height of
209 // ourselves. The measured height should be the max height of the children, changed
210 // to accommodate the heightMeasureSpec from the parent
211 auto uniformMeasureSpec = MeasureSpec( GetMeasuredHeight(), MeasureSpec::Mode::EXACTLY );
212 for (int i = 0; i < count; ++i)
214 LayoutItemPtr childLayout = GetChildAt(i);
215 if( childLayout != nullptr )
217 auto childOwner = childLayout->GetOwner();
218 auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
219 auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
221 if( desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT )
223 // Temporarily force children to reuse their old measured width
224 int oldWidth = desiredWidth;
225 childOwner.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, childLayout->GetMeasuredWidth().mValue );
227 // Remeasure with new dimensions
228 MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, uniformMeasureSpec, 0);
230 childOwner.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, oldWidth );
236 void HboxLayout::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
238 auto owner = GetOwner();
239 auto actor = Actor::DownCast(owner);
240 bool isLayoutRtl = actor ? actor.GetProperty<bool>( Actor::Property::LAYOUT_DIRECTION ) : false;
242 Extents padding = GetPadding();
244 LayoutLength childTop( 0 );
245 LayoutLength childLeft( padding.start );
247 // Where bottom of child should go
248 auto height = bottom - top;
250 // Space available for child
251 auto childSpace = height - padding.top - padding.bottom;
253 auto count = GetChildCount();
258 // In case of RTL, start drawing from the last child.
259 // @todo re-work to draw the first child from the right edge, and move leftwards.
260 // (Should have an alignment also)
266 for( unsigned int i = 0; i < count; i++)
268 int childIndex = start + dir * i;
269 LayoutItemPtr childLayout = GetChildAt( childIndex );
270 if( childLayout != nullptr )
272 auto childWidth = childLayout->GetMeasuredWidth();
273 auto childHeight = childLayout->GetMeasuredHeight();
275 auto childMargin = childLayout->GetMargin();
277 childTop = LayoutLength(padding.top) + ((childSpace - childHeight) / 2) + childMargin.top - childMargin.bottom;
279 childLeft += childMargin.start;
280 childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
281 childLeft += childWidth + childMargin.end + mCellPadding.width;
286 } // namespace Internal
287 } // namespace Toolkit