2 * Copyright (c) 2014 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.
19 #include "alignment-impl.h"
22 #include <dali/public-api/object/property-input.h>
23 #include <dali/public-api/object/type-registry-helper.h>
24 #include <dali/public-api/object/type-registry.h>
25 #include <dali/public-api/size-negotiation/relayout-container.h>
28 #include <dali-toolkit/devel-api/controls/control-devel.h>
41 return Toolkit::Alignment::New();
44 DALI_TYPE_REGISTRATION_BEGIN(Toolkit::Alignment, Toolkit::Control, Create)
45 DALI_TYPE_REGISTRATION_END()
48 * @param padding The padding value
49 * @param horizontalAlignment The horizontal alignment.
50 * @param verticalAlignment The vertical alignment.
51 * @param currentSize of the object
54 inline Vector3 GetPosition(const Toolkit::Alignment::Padding& padding, Toolkit::Alignment::Type horizontalAlignment, Toolkit::Alignment::Type verticalAlignment, const Vector2& currentSize, const Vector2& parentSize)
56 Vector3 position(0.f, 0.f, 0.f);
58 switch(horizontalAlignment)
60 case Dali::Toolkit::Alignment::HORIZONTAL_LEFT:
62 position.x += padding.left;
65 case Dali::Toolkit::Alignment::HORIZONTAL_RIGHT:
67 position.x -= padding.right;
70 case Dali::Toolkit::Alignment::HORIZONTAL_CENTER: // FALLTHROUGH
71 default: // use center as default
73 if(currentSize.width + padding.left + padding.right >= parentSize.width)
75 position.x += 0.5f * (padding.left - padding.right);
81 switch(verticalAlignment)
83 case Dali::Toolkit::Alignment::VERTICAL_TOP:
85 position.y += padding.top;
88 case Dali::Toolkit::Alignment::VERTICAL_BOTTOM:
90 position.y -= padding.bottom;
93 case Dali::Toolkit::Alignment::VERTICAL_CENTER: // FALLTHROUGH
94 default: // use center as default
96 if(currentSize.height + padding.top + padding.bottom >= parentSize.height)
98 position.y += 0.5f * (padding.top - padding.bottom);
109 Toolkit::Alignment Alignment::New(Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical)
111 // Create the implementation, temporarily owned on stack
112 IntrusivePtr<Alignment> internalAlignment = new Alignment(horizontal, vertical);
114 // Pass ownership to Toolkit::Alignment
115 Toolkit::Alignment alignment(*internalAlignment);
117 // Second-phase init of the implementation
118 // This can only be done after the CustomActor connection has been made...
119 internalAlignment->Initialize();
124 void Alignment::SetAlignmentType(Toolkit::Alignment::Type type)
126 // Horizontal Alignment
127 if(type & Toolkit::Alignment::HORIZONTAL_RIGHT)
129 mHorizontal = Toolkit::Alignment::HORIZONTAL_RIGHT;
131 if(type & Toolkit::Alignment::HORIZONTAL_LEFT)
133 mHorizontal = Toolkit::Alignment::HORIZONTAL_LEFT;
135 if(type & Toolkit::Alignment::HORIZONTAL_CENTER)
137 mHorizontal = Toolkit::Alignment::HORIZONTAL_CENTER;
140 // Vertical Alignment
141 if(type & Toolkit::Alignment::VERTICAL_BOTTOM)
143 mVertical = Toolkit::Alignment::VERTICAL_BOTTOM;
145 if(type & Toolkit::Alignment::VERTICAL_TOP)
147 mVertical = Toolkit::Alignment::VERTICAL_TOP;
149 if(type & Toolkit::Alignment::VERTICAL_CENTER)
151 mVertical = Toolkit::Alignment::VERTICAL_CENTER;
157 Toolkit::Alignment::Type Alignment::GetAlignmentType() const
159 return Toolkit::Alignment::Type(mHorizontal | mVertical);
162 void Alignment::SetScaling(Toolkit::Alignment::Scaling scaling)
169 Toolkit::Alignment::Scaling Alignment::GetScaling() const
174 void Alignment::SetPadding(const Toolkit::Alignment::Padding& padding)
176 DALI_ASSERT_ALWAYS((padding.left >= 0.f) && (padding.top >= 0.f) && (padding.right >= 0.f) && (padding.bottom >= 0.f));
183 const Toolkit::Alignment::Padding& Alignment::GetPadding() const
188 void Alignment::OnInitialize()
190 DevelControl::SetAccessibilityConstructor(Self(), [](Dali::Actor actor) {
191 return std::unique_ptr<Dali::Accessibility::Accessible>(
192 new DevelControl::AccessibleImpl(actor, Dali::Accessibility::Role::FILLER));
196 void Alignment::OnRelayout(const Vector2& size, RelayoutContainer& container)
198 // lay out the actors
199 Vector3 anchorPointAndParentOrigin = Vector3::ZERO;
200 anchorPointAndParentOrigin.z = 0.5f;
201 // anchorPoint.x is initialized to 0.0, which is HORIZONTAL_LEFT
202 if(Toolkit::Alignment::HORIZONTAL_CENTER == mHorizontal)
204 anchorPointAndParentOrigin.x = 0.5f;
206 else if(Toolkit::Alignment::HORIZONTAL_RIGHT == mHorizontal)
208 anchorPointAndParentOrigin.x = 1.0f;
210 // anchorPoint.y is initialized to 0.0, which is VERTICAL_TOP
211 if(Toolkit::Alignment::VERTICAL_CENTER == mVertical)
213 anchorPointAndParentOrigin.y = 0.5f;
215 else if(Toolkit::Alignment::VERTICAL_BOTTOM == mVertical)
217 anchorPointAndParentOrigin.y = 1.0f;
220 for(unsigned int i = 0, childCount = Self().GetChildCount(); i < childCount; ++i)
222 Actor child = Self().GetChildAt(i);
224 child.SetProperty(Actor::Property::ANCHOR_POINT, anchorPointAndParentOrigin);
225 child.SetProperty(Actor::Property::PARENT_ORIGIN, anchorPointAndParentOrigin);
227 Vector2 currentChildSize(child.GetTargetSize().GetVectorXY());
228 if(currentChildSize == Vector2::ZERO)
230 currentChildSize = child.GetNaturalSize();
233 bool renegotiate = true;
234 Vector2 newChildSize;
235 newChildSize.width = size.width - (mPadding.left + mPadding.right);
236 newChildSize.height = size.height - (mPadding.top + mPadding.bottom);
238 // prevent ridiculous sizes if parent is really small or if we don't have a proper size for the actor
239 if((newChildSize.width > Math::MACHINE_EPSILON_1000) && (newChildSize.height > Math::MACHINE_EPSILON_1000) &&
240 (currentChildSize.width > Math::MACHINE_EPSILON_1000) && (currentChildSize.height > Math::MACHINE_EPSILON_1000))
242 // no point trying to squeeze actors into too small size
245 case Toolkit::Alignment::SCALE_NONE:
251 case Toolkit::Alignment::SCALE_TO_FILL:
253 // Nothing to do, newChildSize is already full size minus padding
256 case Toolkit::Alignment::SCALE_TO_FIT_KEEP_ASPECT:
258 newChildSize = currentChildSize * std::min((newChildSize.width / currentChildSize.width), (newChildSize.height / currentChildSize.height));
261 case Toolkit::Alignment::SCALE_TO_FILL_KEEP_ASPECT:
263 newChildSize = currentChildSize * std::max((newChildSize.width / currentChildSize.width), (newChildSize.height / currentChildSize.height));
266 case Toolkit::Alignment::SHRINK_TO_FIT:
268 newChildSize = Vector2(std::min(newChildSize.width, currentChildSize.width), std::min(newChildSize.height, currentChildSize.height));
271 case Toolkit::Alignment::SHRINK_TO_FIT_KEEP_ASPECT:
273 // check source size vs target size to see if we need to shrink
274 float widthScale = (newChildSize.width < currentChildSize.width) ? (newChildSize.width / currentChildSize.width) : 1.f;
275 float heightScale = (newChildSize.height < currentChildSize.height) ? (newChildSize.height / currentChildSize.height) : 1.0f;
276 // use smaller of the scales
277 float scale = std::min(widthScale, heightScale);
278 // check if we need to scale
281 // scale natural size to fit inside
282 newChildSize *= scale;
289 child.SetProperty(Actor::Property::POSITION, GetPosition(mPadding, mHorizontal, mVertical, newChildSize, currentChildSize));
293 container.Add(child, newChildSize);
298 Alignment::Alignment(Toolkit::Alignment::Type horizontal, Toolkit::Alignment::Type vertical)
299 : Control(ControlBehaviour(CONTROL_BEHAVIOUR_DEFAULT)),
300 mHorizontal(horizontal),
302 mScaling(Toolkit::Alignment::SCALE_NONE),
303 mPadding(0.f, 0.f, 0.f, 0.f)
307 Alignment::~Alignment()
311 } // namespace Internal
313 } // namespace Toolkit