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>
30 #if defined(DEBUG_ENABLED)
31 static Debug::Filter* gLogFilter = Debug::Filter::New( Debug::Concise, false, "LOG_LAYOUT" );
41 HboxLayoutPtr HboxLayout::New()
43 HboxLayoutPtr layout( new HboxLayout() );
47 HboxLayout::HboxLayout()
54 HboxLayout::~HboxLayout()
58 void HboxLayout::DoInitialize()
62 void HboxLayout::DoRegisterChildProperties( const std::string& containerType )
64 auto typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( containerType );
67 Property::IndexContainer indices;
68 typeInfo.GetChildPropertyIndices( indices );
70 if( std::find( indices.Begin(), indices.End(), Toolkit::HboxLayout::ChildProperty::WEIGHT ) == indices.End() )
72 ChildPropertyRegistration( typeInfo.GetName(), "weight",
73 Toolkit::HboxLayout::ChildProperty::WEIGHT, Property::FLOAT );
78 void HboxLayout::OnChildAdd( LayoutItem& child )
80 auto owner = child.GetOwner();
81 owner.SetProperty( Toolkit::HboxLayout::ChildProperty::WEIGHT, 1.0f );
84 void HboxLayout::SetCellPadding( LayoutSize size )
89 LayoutSize HboxLayout::GetCellPadding()
94 void HboxLayout::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
96 #if defined(DEBUG_ENABLED)
97 auto actor = Actor::DownCast(GetOwner());
99 std::ostringstream oss;
100 oss << "HBoxLayout::OnMeasure ";
103 oss << "Actor Id:" << actor.GetId() << " Name:" << actor.GetName() << " ";
105 oss << "widthMeasureSpec:" << widthMeasureSpec << " heightMeasureSpec:" << heightMeasureSpec << std::endl;
106 DALI_LOG_INFO( gLogFilter, Debug::Concise, oss.str().c_str() );
109 auto widthMode = widthMeasureSpec.GetMode();
110 auto heightMode = heightMeasureSpec.GetMode();
111 bool isExactly = (widthMode == MeasureSpec::Mode::EXACTLY);
112 bool matchHeight = false;
113 bool allFillParent = true;
114 LayoutLength maxHeight = 0;
115 LayoutLength alternativeMaxHeight = 0;
118 MeasuredSize::State widthState;
119 MeasuredSize::State heightState;
120 } childState = { MeasuredSize::State::MEASURED_SIZE_OK, MeasuredSize::State::MEASURED_SIZE_OK };
122 // measure children, and determine if further resolution is required
123 for( unsigned int i=0; i<GetChildCount(); ++i )
125 auto childLayout = GetChildAt( i );
128 auto childOwner = childLayout->GetOwner();
129 auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
131 MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, heightMeasureSpec, 0 );
132 auto childWidth = childLayout->GetMeasuredWidth();
133 auto childMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
134 auto length = childWidth + LayoutLength::IntType(childMargin.start + childMargin.end);
136 auto cellPadding = i<GetChildCount()-1 ? mCellPadding.width: 0;
140 mTotalLength += length;
144 auto totalLength = mTotalLength;
145 mTotalLength = std::max( totalLength, totalLength + length + cellPadding );
148 bool matchHeightLocally = false;
149 if( heightMode != MeasureSpec::Mode::EXACTLY && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT )
151 // Will have to re-measure at least this child when we know exact height.
153 matchHeightLocally = true;
156 auto marginHeight = LayoutLength( childMargin.top + childMargin.bottom );
157 auto childHeight = childLayout->GetMeasuredHeight() + marginHeight;
159 if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
161 childState.widthState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
163 if( childLayout->GetMeasuredHeightAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
165 childState.heightState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
168 maxHeight = std::max( maxHeight, childHeight );
169 allFillParent = ( allFillParent && desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT );
170 alternativeMaxHeight = std::max( alternativeMaxHeight, matchHeightLocally ? marginHeight : childHeight );
174 Extents padding = GetPadding();
175 mTotalLength += padding.start + padding.end;
176 auto widthSize = mTotalLength;
177 widthSize = std::max( widthSize, GetSuggestedMinimumWidth() );
178 MeasuredSize widthSizeAndState = ResolveSizeAndState( widthSize, widthMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK);
179 widthSize = widthSizeAndState.GetSize();
181 if( !allFillParent && heightMode != MeasureSpec::Mode::EXACTLY )
183 maxHeight = alternativeMaxHeight;
185 maxHeight += padding.top + padding.bottom;
186 maxHeight = std::max( maxHeight, GetSuggestedMinimumHeight() );
188 widthSizeAndState.SetState( childState.widthState );
190 SetMeasuredDimensions( widthSizeAndState,
191 ResolveSizeAndState( maxHeight, heightMeasureSpec, childState.heightState ) );
195 ForceUniformHeight( GetChildCount(), widthMeasureSpec );
199 void HboxLayout::ForceUniformHeight( int count, MeasureSpec widthMeasureSpec )
201 // Pretend that the linear layout has an exact size. This is the measured height of
202 // ourselves. The measured height should be the max height of the children, changed
203 // to accommodate the heightMeasureSpec from the parent
204 auto uniformMeasureSpec = MeasureSpec( GetMeasuredHeight(), MeasureSpec::Mode::EXACTLY );
205 for (int i = 0; i < count; ++i)
207 LayoutItemPtr childLayout = GetChildAt(i);
208 if( childLayout != nullptr )
210 auto childOwner = childLayout->GetOwner();
211 auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
212 auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
214 if( desiredHeight == Toolkit::ChildLayoutData::MATCH_PARENT )
216 // Temporarily force children to reuse their old measured width
217 int oldWidth = desiredWidth;
218 childOwner.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, childLayout->GetMeasuredWidth().mValue );
220 // Remeasure with new dimensions
221 MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, uniformMeasureSpec, 0);
223 childOwner.SetProperty( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION, oldWidth );
229 void HboxLayout::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
231 auto owner = GetOwner();
232 auto actor = Actor::DownCast(owner);
233 bool isLayoutRtl = actor ? actor.GetProperty<bool>( Actor::Property::LAYOUT_DIRECTION ) : false;
235 Extents padding = GetPadding();
237 LayoutLength childTop( 0 );
238 LayoutLength childLeft( padding.start );
240 // Where bottom of child should go
241 auto height = bottom - top;
243 // Space available for child
244 auto childSpace = height - padding.top - padding.bottom;
246 auto count = GetChildCount();
251 // In case of RTL, start drawing from the last child.
252 // @todo re-work to draw the first child from the right edge, and move leftwards.
253 // (Should have an alignment also)
259 for( unsigned int i = 0; i < count; i++)
261 int childIndex = start + dir * i;
262 LayoutItemPtr childLayout = GetChildAt( childIndex );
263 if( childLayout != nullptr )
265 auto childWidth = childLayout->GetMeasuredWidth();
266 auto childHeight = childLayout->GetMeasuredHeight();
268 auto childOwner = childLayout->GetOwner();
269 auto childMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
271 childTop = LayoutLength(padding.top) + ((childSpace - childHeight) / 2) + childMargin.top - childMargin.bottom;
273 childLeft += childMargin.start;
274 childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
275 childLeft += childWidth + childMargin.end + mCellPadding.width;
280 } // namespace Internal
281 } // namespace Toolkit