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/vbox-layout-impl.h>
22 #include <dali/integration-api/debug.h>
23 #include <dali/public-api/common/extents.h>
24 #include <dali/devel-api/actors/actor-devel.h>
25 #include <dali/devel-api/object/handle-devel.h>
26 #include <dali-toolkit/devel-api/layouting/layout-item.h>
27 #include <dali-toolkit/public-api/controls/control-impl.h>
28 #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" );
42 VboxLayoutPtr VboxLayout::New()
44 VboxLayoutPtr layout( new VboxLayout() );
48 VboxLayout::VboxLayout()
55 VboxLayout::~VboxLayout()
59 void VboxLayout::DoInitialize()
63 void VboxLayout::DoRegisterChildProperties( const std::string& containerType )
65 auto typeInfo = Dali::TypeRegistry::Get().GetTypeInfo( containerType );
68 Property::IndexContainer indices;
69 typeInfo.GetChildPropertyIndices( indices );
71 if( std::find( indices.Begin(), indices.End(), Toolkit::VboxLayout::ChildProperty::WEIGHT ) ==
74 ChildPropertyRegistration( typeInfo.GetName(), "weight", Toolkit::VboxLayout::ChildProperty::WEIGHT, Property::FLOAT );
79 void VboxLayout::OnChildAdd( LayoutItem& child )
81 auto owner = child.GetOwner();
82 owner.SetProperty( Toolkit::VboxLayout::ChildProperty::WEIGHT, 1.0f );
85 void VboxLayout::SetCellPadding( LayoutSize size )
90 LayoutSize VboxLayout::GetCellPadding()
96 void VboxLayout::OnMeasure( MeasureSpec widthMeasureSpec, MeasureSpec heightMeasureSpec )
98 #if defined(DEBUG_ENABLED)
99 auto actor = Actor::DownCast(GetOwner());
101 std::ostringstream oss;
102 oss << "VboxLayout::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 auto widthMode = widthMeasureSpec.GetMode();
113 bool matchWidth = false;
114 bool allFillParent = true;
115 LayoutLength maxWidth = 0;
116 LayoutLength alternativeMaxWidth = 0;
120 MeasuredSize::State widthState;
121 MeasuredSize::State heightState;
122 } childState = { MeasuredSize::State::MEASURED_SIZE_OK, MeasuredSize::State::MEASURED_SIZE_OK };
124 // measure children, and determine if further resolution is required
125 for( unsigned int i=0; i<GetChildCount(); ++i )
127 auto childLayout = GetChildAt( i );
130 auto childOwner = childLayout->GetOwner();
131 auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
133 MeasureChildWithMargins( childLayout, widthMeasureSpec, 0, heightMeasureSpec, 0 );
134 auto childHeight = childLayout->GetMeasuredHeight();
135 auto childMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
136 auto length = childHeight + LayoutLength::IntType(childMargin.top + childMargin.bottom );
138 auto cellPadding = i<GetChildCount()-1 ? mCellPadding.height : 0;
139 auto totalLength = mTotalLength;
140 mTotalLength = std::max( totalLength, totalLength + length + cellPadding);
142 bool matchWidthLocally = false;
143 if( widthMode != MeasureSpec::Mode::EXACTLY && desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT )
145 // Will have to re-measure at least this child when we know exact height.
147 matchWidthLocally = true;
150 auto marginWidth = LayoutLength( childMargin.start + childMargin.end );
151 auto childWidth = childLayout->GetMeasuredWidth() + marginWidth;
153 // was combineMeasuredStates()
154 if( childLayout->GetMeasuredWidthAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
156 childState.widthState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
158 if( childLayout->GetMeasuredHeightAndState().GetState() == MeasuredSize::State::MEASURED_SIZE_TOO_SMALL )
160 childState.heightState = MeasuredSize::State::MEASURED_SIZE_TOO_SMALL;
163 maxWidth = std::max( maxWidth, childWidth );
164 allFillParent = ( allFillParent && desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT );
165 alternativeMaxWidth = std::max( alternativeMaxWidth, matchWidthLocally ? marginWidth : childWidth );
169 Extents padding = GetPadding();
170 mTotalLength += padding.top + padding.bottom;
171 auto heightSize = mTotalLength;
172 heightSize = std::max( heightSize, GetSuggestedMinimumHeight() );
173 MeasuredSize heightSizeAndState = ResolveSizeAndState( heightSize, heightMeasureSpec, MeasuredSize::State::MEASURED_SIZE_OK);
174 heightSize = heightSizeAndState.GetSize();
176 if( !allFillParent && widthMode != MeasureSpec::Mode::EXACTLY )
178 maxWidth = alternativeMaxWidth;
180 maxWidth += padding.start + padding.end;
181 maxWidth = std::max( maxWidth, GetSuggestedMinimumWidth() );
183 heightSizeAndState.SetState( childState.heightState );
185 SetMeasuredDimensions( ResolveSizeAndState( maxWidth, widthMeasureSpec, childState.widthState ),
186 heightSizeAndState );
190 ForceUniformWidth( GetChildCount(), heightMeasureSpec );
194 void VboxLayout::ForceUniformWidth( int count, MeasureSpec heightMeasureSpec )
196 // Pretend that the linear layout has an exact size. This is the measured height of
197 // ourselves. The measured height should be the max height of the children, changed
198 // to accommodate the heightMeasureSpec from the parent
199 auto uniformMeasureSpec = MeasureSpec( GetMeasuredWidth(), MeasureSpec::Mode::EXACTLY );
200 for (int i = 0; i < count; ++i)
202 LayoutItemPtr childLayout = GetChildAt(i);
203 if( childLayout != nullptr )
205 auto childOwner = childLayout->GetOwner();
206 auto desiredWidth = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::WIDTH_SPECIFICATION );
207 auto desiredHeight = childOwner.GetProperty<int>( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION );
209 if( desiredWidth == Toolkit::ChildLayoutData::MATCH_PARENT )
211 // Temporarily force children to reuse their old measured height
212 int oldHeight = desiredHeight;
213 childOwner.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, childLayout->GetMeasuredHeight().mValue );
215 // Remeasure with new dimensions
216 MeasureChildWithMargins( childLayout, uniformMeasureSpec, 0, heightMeasureSpec, 0 );
218 childOwner.SetProperty( Toolkit::LayoutItem::ChildProperty::HEIGHT_SPECIFICATION, oldHeight );
224 void VboxLayout::OnLayout( bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom )
226 auto owner = GetOwner();
227 Extents padding = GetPadding();
229 LayoutLength childTop( 0 );
230 LayoutLength childLeft( padding.start );
232 // Where bottom of child should go
233 auto width = right - left;
235 // Space available for child
236 auto childSpace = width - padding.start - padding.end;
237 auto count = GetChildCount();
239 for( unsigned int childIndex = 0; childIndex < count; childIndex++)
241 LayoutItemPtr childLayout = GetChildAt( childIndex );
242 if( childLayout != nullptr )
244 auto childWidth = childLayout->GetMeasuredWidth();
245 auto childHeight = childLayout->GetMeasuredHeight();
247 auto childOwner = childLayout->GetOwner();
248 auto childMargin = childOwner.GetProperty<Extents>( Toolkit::LayoutGroup::ChildProperty::MARGIN_SPECIFICATION );
250 childTop += childMargin.top;
251 childLeft = ( childSpace - childWidth ) / 2 + childMargin.start - childMargin.end;
253 childLayout->Layout( childLeft, childTop, childLeft + childWidth, childTop + childHeight );
254 childTop += childHeight + childMargin.bottom + mCellPadding.height;
259 } // namespace Internal
260 } // namespace Toolkit