Revert "[NUI] Rebase DevelNUI (#2507)" (#2508)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / Layouting / LayoutItem.cs
1 /*
2  * Copyright (c) 2020 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 using System;
19 using System.ComponentModel;
20 using System.Diagnostics;
21
22 using Tizen.NUI.BaseComponents;
23
24 namespace Tizen.NUI
25 {
26
27     [FlagsAttribute]
28     enum LayoutFlags : short
29     {
30         None = 0,
31         ForceLayout = 1,
32         LayoutRequired = 2,
33         MeasuredDimensionSet = 4
34     };
35
36     /// <summary>
37     /// [Draft] Base class for layouts. It is used to layout a View
38     /// It can be laid out by a LayoutGroup.
39     /// </summary>
40     public class LayoutItem : IDisposable
41     {
42         private bool disposed = false;
43         static bool LayoutDebugFrameData = false; // Debug flag
44         private MeasureSpecification OldWidthMeasureSpec; // Store measure specification to compare against later
45         private MeasureSpecification OldHeightMeasureSpec; // Store measure specification to compare against later
46
47         private LayoutFlags Flags = LayoutFlags.None;
48
49         private ILayoutParent Parent;
50
51         LayoutData _layoutPositionData;
52
53         private Extents _padding;
54         private Extents _margin;
55
56         private bool parentReplacement = false;
57         private bool setPositionByLayout = true;
58
59         /// <summary>
60         /// [Draft] Condition event that is causing this Layout to transition.
61         /// </summary>
62         internal TransitionCondition ConditionForAnimation { get; set; }
63
64         /// <summary>
65         /// [Draft] The View that this Layout has been assigned to.
66         /// </summary>
67         /// <since_tizen> 6 </since_tizen>
68         public View Owner { get; set; }  // Should not keep a View alive.
69
70         /// <summary>
71         /// [Draft] Use transition for layouting child
72         /// </summary>
73         /// <since_tizen> 6 </since_tizen>
74         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
75         [EditorBrowsable(EditorBrowsableState.Never)]
76         public bool LayoutWithTransition { get; set; }
77
78         /// <summary>
79         /// [Draft] Set position by layouting result
80         /// </summary>
81         [EditorBrowsable(EditorBrowsableState.Never)]
82         public bool SetPositionByLayout
83         {
84             get
85             {
86                 return setPositionByLayout;
87             }
88             set
89             {
90                 setPositionByLayout = value;
91                 if (Owner != null && Owner.ExcludeLayouting == value)
92                 {
93                     Owner.ExcludeLayouting = !value;
94                 }
95             }
96         }
97
98         /// <summary>
99         /// [Draft] Margin for this LayoutItem
100         /// </summary>
101         /// <since_tizen> 6 </since_tizen>
102         public Extents Margin
103         {
104             get
105             {
106                 return _margin;
107             }
108             set
109             {
110                 _margin = value;
111                 RequestLayout();
112             }
113         }
114
115         /// <summary>
116         /// [Draft] Padding for this LayoutItem
117         /// </summary>
118         /// <since_tizen> 6 </since_tizen>
119         public Extents Padding
120         {
121             get
122             {
123                 return _padding;
124             }
125             set
126             {
127                 _padding = value;
128                 RequestLayout();
129             }
130         }
131
132         /// <summary>
133         /// [Draft] Constructor
134         /// </summary>
135         /// <since_tizen> 6 </since_tizen>
136         public LayoutItem()
137         {
138             Initialize();
139         }
140
141         /// <summary>
142         /// [Draft] Set parent to this layout.
143         /// </summary>
144         /// <param name="parent">Parent to set on this Layout.</param>
145         internal void SetParent(ILayoutParent parent)
146         {
147             Parent = parent as LayoutGroup;
148         }
149
150         /// <summary>
151         /// Unparent this layout from it's owner, and remove any layout children in derived types. <br />
152         /// </summary>
153         internal void Unparent()
154         {
155             // Enable directly derived types to first remove children
156             OnUnparent();
157
158             // Remove myself from parent
159             Parent?.Remove(this);
160
161             // Remove parent reference
162             Parent = null;
163
164             // Lastly, clear layout from owning View.
165             Owner?.ResetLayout();
166         }
167
168         private void Initialize()
169         {
170             LayoutWithTransition = false;
171             _layoutPositionData = new LayoutData(this, TransitionCondition.Unspecified, 0, 0, 0, 0);
172             _padding = new Extents(0, 0, 0, 0);
173             _margin = new Extents(0, 0, 0, 0);
174         }
175
176         /// <summary>
177         /// Initialize the layout and allow derived classes to also perform any operations
178         /// </summary>
179         /// <param name="owner">Owner of this Layout.</param>
180         internal void AttachToOwner(View owner)
181         {
182             // Assign the layout owner.
183             Owner = owner;
184             OnAttachedToOwner();
185             // Add layout to parent layout if a layout container
186             View parent = Owner.GetParent() as View;
187             (parent?.Layout as LayoutGroup)?.Add(this);
188
189             // If Add or ChangeOnAdd then do not update condition
190             if (ConditionForAnimation.Equals(TransitionCondition.Unspecified))
191             {
192                 ConditionForAnimation = TransitionCondition.LayoutChanged;
193             }
194         }
195
196         /// <summary>
197         /// This is called to find out how big a layout should be. <br />
198         /// The parent supplies constraint information in the width and height parameters. <br />
199         /// The actual measurement work of a layout is performed in OnMeasure called by this
200         /// method. Therefore, only OnMeasure can and must be overridden by subclasses. <br />
201         /// </summary>
202         /// <param name="widthMeasureSpec"> Horizontal space requirements as imposed by the parent.</param>
203         /// <param name="heightMeasureSpec">Vertical space requirements as imposed by the parent.</param>
204         /// <since_tizen> 6 </since_tizen>
205         public void Measure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
206         {
207             // Check if relayouting is required.
208             bool specChanged = (widthMeasureSpec.Size != OldWidthMeasureSpec.Size) ||
209                 (heightMeasureSpec.Size != OldHeightMeasureSpec.Size) ||
210                 (widthMeasureSpec.Mode != OldWidthMeasureSpec.Mode) ||
211                 (heightMeasureSpec.Mode != OldHeightMeasureSpec.Mode);
212
213             bool isSpecExactly = (widthMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly) &&
214                 (heightMeasureSpec.Mode == MeasureSpecification.ModeType.Exactly);
215
216             bool matchesSpecSize = (MeasuredWidth.Size == widthMeasureSpec.Size) &&
217                 (MeasuredHeight.Size == heightMeasureSpec.Size);
218
219             bool needsLayout = specChanged && (!isSpecExactly || !matchesSpecSize);
220             needsLayout = needsLayout || ((Flags & LayoutFlags.ForceLayout) == LayoutFlags.ForceLayout);
221
222             if (needsLayout)
223             {
224                 OnMeasure(widthMeasureSpec, heightMeasureSpec);
225                 OnMeasureIndependentChildren(widthMeasureSpec, heightMeasureSpec);
226                 Flags = Flags | LayoutFlags.LayoutRequired;
227                 Flags &= ~LayoutFlags.ForceLayout;
228             }
229             OldWidthMeasureSpec = widthMeasureSpec;
230             OldHeightMeasureSpec = heightMeasureSpec;
231         }
232
233         /// <summary>
234         /// Assign a size and position to a layout and all of its descendants. <br />
235         /// This is the second phase of the layout mechanism.  (The first is measuring). In this phase, each parent
236         /// calls layout on all of its children to position them.  This is typically done using the child<br />
237         /// measurements that were stored in the measure pass.<br />
238         /// </summary>
239         /// <param name="left">Left position, relative to parent.</param>
240         /// <param name="top">Top position, relative to parent.</param>
241         /// <param name="right">Right position, relative to parent.</param>
242         /// <param name="bottom">Bottom position, relative to parent.</param>
243         /// <since_tizen> 6 </since_tizen>
244         public void Layout(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom)
245         {
246             Layout(left, top, right, bottom, Owner?.ExcludeLayouting ?? false);
247         }
248
249         /// <summary>
250         /// Assign a size and position to a layout and all of its descendants. <br />
251         /// This is the second phase of the layout mechanism.  (The first is measuring). In this phase, each parent
252         /// calls layout on all of its children to position them.  This is typically done using the child<br />
253         /// measurements that were stored in the measure pass.<br />
254         /// </summary>
255         /// <param name="left">Left position, relative to parent.</param>
256         /// <param name="top">Top position, relative to parent.</param>
257         /// <param name="right">Right position, relative to parent.</param>
258         /// <param name="bottom">Bottom position, relative to parent.</param>
259         /// <param name="independent">true, if this layout is not affected by parent layout.</param>
260         [EditorBrowsable(EditorBrowsableState.Never)]
261         public void Layout(LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom, bool independent)
262         {
263             bool changed = SetFrame(left.AsRoundedValue(),
264                     top.AsRoundedValue(),
265                     right.AsRoundedValue(),
266                     bottom.AsRoundedValue(), independent);
267
268             // Check if Measure needed before Layouting
269             if (changed || ((Flags & LayoutFlags.LayoutRequired) == LayoutFlags.LayoutRequired))
270             {
271                 OnLayout(changed, left, top, right, bottom);
272                 OnLayoutIndependentChildren(changed, left, top, right, bottom);
273                 // Clear flag
274                 Flags &= ~LayoutFlags.LayoutRequired;
275             }
276         }
277
278         /// <summary>
279         /// Utility to return a default size.<br />
280         /// Uses the supplied size if the MeasureSpecification imposed no constraints. Will get larger if allowed by the
281         /// MeasureSpecification.<br />
282         /// </summary>
283         /// <param name="size"> Default size for this layout.</param>
284         /// <param name="measureSpecification"> Constraints imposed by the parent.</param>
285         /// <returns>The size this layout should be.</returns>
286         /// <since_tizen> 6 </since_tizen>
287         public static LayoutLength GetDefaultSize(LayoutLength size, MeasureSpecification measureSpecification)
288         {
289             LayoutLength result = size;
290             MeasureSpecification.ModeType specMode = measureSpecification.Mode;
291             LayoutLength specSize = measureSpecification.Size;
292
293             switch (specMode)
294             {
295                 case MeasureSpecification.ModeType.Unspecified:
296                     {
297                         result = size;
298                         break;
299                     }
300                 case MeasureSpecification.ModeType.AtMost:
301                     {
302                         // Ensure the default size does not exceed the spec size unless the default size is 0.
303                         // Another container could provide a default size of 0.
304
305                         // Do not set size to 0, use specSize in this case as could be a legacy container
306                         if ((size.AsDecimal() < specSize.AsDecimal()) && (size.AsDecimal() > 0))
307                         {
308                             result = size;
309                         }
310                         else
311                         {
312                             result = specSize;
313                         }
314                         break;
315                     }
316                 case MeasureSpecification.ModeType.Exactly:
317                     {
318                         result = specSize;
319                         break;
320                     }
321             }
322
323             return result;
324         }
325
326         /// <summary>
327         /// Get the Layouts parent
328         /// </summary>
329         /// <returns>Layout parent with an LayoutParent interface</returns>
330         /// <since_tizen> 6 </since_tizen>
331         public ILayoutParent GetParent()
332         {
333             return Parent;
334         }
335
336         /// <summary>
337         /// Request that this layout is re-laid out.<br />
338         /// This will make this layout and all it's parent layouts dirty.<br />
339         /// </summary>
340         /// <since_tizen> 6 </since_tizen>
341         public void RequestLayout()
342         {
343             Flags = Flags | LayoutFlags.ForceLayout;
344             if (Parent != null)
345             {
346                 LayoutGroup layoutGroup = Parent as LayoutGroup;
347                 if (layoutGroup != null && !layoutGroup.LayoutRequested)
348                 {
349                     layoutGroup.RequestLayout();
350                 }
351             }
352
353         }
354
355         /// <summary>
356         /// Predicate to determine if this layout has been requested to re-layout.<br />
357         /// </summary>
358
359         internal bool LayoutRequested
360         {
361             get
362             {
363                 return (Flags & LayoutFlags.ForceLayout) == LayoutFlags.ForceLayout;
364             }
365         }
366
367         internal void SetReplaceFlag()
368         {
369             parentReplacement = true;
370         }
371
372         internal bool IsReplaceFlag()
373         {
374             return parentReplacement;
375         }
376
377         internal void ClearReplaceFlag()
378         {
379             parentReplacement = false;
380         }
381
382         /// <summary>
383         /// Get the measured width (without any measurement flags).<br />
384         /// This method should be used only during measurement and layout calculations.<br />
385         /// </summary>
386         /// <since_tizen> 6 </since_tizen>
387         public MeasuredSize MeasuredWidth { get; set; } = new MeasuredSize(new LayoutLength(-3), MeasuredSize.StateType.MeasuredSizeOK);
388
389         /// <summary>
390         /// Get the measured height (without any measurement flags).<br />
391         /// This method should be used only during measurement and layout calculations.<br />
392         /// </summary>
393         /// <since_tizen> 6 </since_tizen>
394         public MeasuredSize MeasuredHeight { get; set; } = new MeasuredSize(new LayoutLength(-3), MeasuredSize.StateType.MeasuredSizeOK);
395
396         /// <summary>
397         /// Returns the suggested minimum width that the layout should use.<br />
398         /// This returns the maximum of the layout's minimum width and the owner's natural width.<br />
399         /// </summary>
400         /// <since_tizen> 6 </since_tizen>
401         public LayoutLength SuggestedMinimumWidth
402         {
403             get
404             {
405                 float maximumWidth = Owner.MaximumSize.Width;
406                 float minimumWidth = Owner.MinimumSize.Width;
407
408                 float baseHeight = Owner.MaximumSize.Height > 0 ? Math.Min(Owner.MaximumSize.Height, Owner.NaturalSize.Height) : Owner.NaturalSize.Height;
409                 float baseWidth = Owner.GetWidthForHeight(baseHeight);
410
411                 float result = minimumWidth > 0 ? Math.Max(baseWidth, minimumWidth) : baseWidth;
412                 result = maximumWidth > 0 ? Math.Min(result, maximumWidth) : result;
413
414                 return new LayoutLength(result);
415             }
416         }
417
418         /// <summary>
419         /// Returns the suggested minimum height that the layout should use.<br />
420         /// This returns the maximum of the layout's minimum height and the owner's natural height.<br />
421         /// </summary>
422         /// <since_tizen> 6 </since_tizen>
423         public LayoutLength SuggestedMinimumHeight
424         {
425             get
426             {
427                 float maximumHeight = Owner.MaximumSize.Height;
428                 float minimumHeight = Owner.MinimumSize.Height;
429
430                 float baseWidth = Owner.MaximumSize.Width > 0 ? Math.Min(Owner.MaximumSize.Width, Owner.NaturalSize.Width) : Owner.NaturalSize.Width;
431                 float baseHeight = Owner.GetHeightForWidth(baseWidth);
432
433                 float result = minimumHeight > 0 ? Math.Max(baseHeight, minimumHeight) : baseHeight;
434                 result = maximumHeight > 0 ? Math.Min(result, maximumHeight) : result;
435
436                 return new LayoutLength(result);
437             }
438         }
439
440         /// <summary>
441         /// Sets the minimum width of the layout.<br />
442         /// It is not guaranteed the layout will be able to achieve this minimum width (for example, if its parent
443         /// layout constrains it with less available width).<br />
444         /// 1. if the owner's View.WidthSpecification has exact value, then that value overrides the minimum size.<br />
445         /// 2. If the owner's View.WidthSpecification is set to View.LayoutParamPolicies.WrapContent, then the view's width is set based on the suggested minimum width. (@see GetSuggestedMinimumWidth()).<br />
446         /// 3. If the owner's View.WidthSpecification is set to View.LayoutParamPolicies.MatchParent, then the parent width takes precedence over the minimum width.<br />
447         /// </summary>
448         internal LayoutLength MinimumWidth { get; set; }
449
450         /// <summary>
451         /// Sets the minimum height of the layout.<br />
452         /// It is not guaranteed the layout will be able to achieve this minimum height (for example, if its parent
453         /// layout constrains it with less available height).<br />
454         /// 1. if the owner's View.HeightSpecification has exact value, then that value overrides the minimum size.<br />
455         /// 2. If the owner's View.HeightSpecification is set to View.LayoutParamPolicies.WrapContent, then the view's height is set based on the suggested minimum height. (@see GetSuggestedMinimumHeight()).<br />
456         /// 3. If the owner's View.HeightSpecification is set to View.LayoutParamPolicies.MatchParent, then the parent height takes precedence over the minimum height.<br />
457         /// </summary>
458         internal LayoutLength MinimumHeight { get; set; }
459
460         ///<summary>
461         /// Utility to reconcile a desired size and state, with constraints imposed by a MeasureSpecification.
462         ///</summary>
463         /// <param name="size"> How big the layout wants to be.</param>
464         /// <param name="measureSpecification"> Constraints imposed by the parent.</param>
465         /// <param name="childMeasuredState"> Size information bit mask for the layout's children.</param>
466         /// <returns> A measured size, which may indicate that it is too small. </returns>
467         /// <since_tizen> 6 </since_tizen>
468         protected MeasuredSize ResolveSizeAndState(LayoutLength size, MeasureSpecification measureSpecification, MeasuredSize.StateType childMeasuredState)
469         {
470             var specMode = measureSpecification.Mode;
471             LayoutLength specSize = measureSpecification.Size;
472             MeasuredSize result = new MeasuredSize(size, childMeasuredState);
473
474             switch (specMode)
475             {
476                 case MeasureSpecification.ModeType.AtMost:
477                     {
478                         if (specSize.AsRoundedValue() < size.AsRoundedValue())
479                         {
480                             result = new MeasuredSize(specSize, MeasuredSize.StateType.MeasuredSizeTooSmall);
481                         }
482                         break;
483                     }
484
485                 case MeasureSpecification.ModeType.Exactly:
486                     {
487                         result.Size = specSize;
488                         break;
489                     }
490
491                 case MeasureSpecification.ModeType.Unspecified:
492                 default:
493                     {
494                         break;
495                     }
496             }
497             return result;
498         }
499
500         /// <summary>
501         /// This method must be called by OnMeasure(MeasureSpec,MeasureSpec) to store the measured width and measured height.
502         /// </summary>
503         /// <param name="measuredWidth">The measured width of this layout.</param>
504         /// <param name="measuredHeight">The measured height of this layout.</param>
505         /// <since_tizen> 6 </since_tizen>
506         protected void SetMeasuredDimensions(MeasuredSize measuredWidth, MeasuredSize measuredHeight)
507         {
508             MeasuredWidth = measuredWidth;
509             MeasuredHeight = measuredHeight;
510             Flags = Flags | LayoutFlags.MeasuredDimensionSet;
511         }
512
513         /// <summary>
514         /// Measure the layout and its content to determine the measured width and the
515         /// measured height.<br />
516         /// The base class implementation of measure defaults to the background size,
517         /// unless a larger size is allowed by the MeasureSpec. Subclasses should
518         /// override to provide better measurements of their content.<br />
519         /// If this method is overridden, it is the subclass's responsibility to make sure the
520         /// measured height and width are at least the layout's minimum height and width.<br />
521         /// </summary>
522         /// <param name="widthMeasureSpec">horizontal space requirements as imposed by the parent.</param>
523         /// <param name="heightMeasureSpec">vertical space requirements as imposed by the parent.</param>
524         /// <since_tizen> 6 </since_tizen>
525         protected virtual void OnMeasure(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec)
526         {
527             // GetDefaultSize will limit the MeasureSpec to the suggested minimumWidth and minimumHeight
528             SetMeasuredDimensions(GetDefaultSize(SuggestedMinimumWidth, widthMeasureSpec),
529                                    GetDefaultSize(SuggestedMinimumHeight, heightMeasureSpec));
530         }
531
532         internal virtual void OnMeasureIndependentChildren(MeasureSpecification widthMeasureSpec, MeasureSpecification heightMeasureSpec) { }
533
534         /// <summary>
535         /// Called from Layout() when this layout should assign a size and position to each of its children. <br />
536         /// Derived classes with children should override this method and call Layout() on each of their children. <br />
537         /// </summary>
538         /// <param name="changed">This is a new size or position for this layout.</param>
539         /// <param name="left">Left position, relative to parent.</param>
540         /// <param name="top">Top position, relative to parent.</param>
541         /// <param name="right">Right position, relative to parent.</param>
542         /// <param name="bottom">Bottom position, relative to parent.</param>
543         /// <since_tizen> 6 </since_tizen>
544         protected virtual void OnLayout(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom) { }
545
546         internal virtual void OnLayoutIndependentChildren(bool changed, LayoutLength left, LayoutLength top, LayoutLength right, LayoutLength bottom) { }
547
548         /// <summary>
549         /// Virtual method to allow derived classes to remove any children before it is removed from
550         /// its parent.
551         /// </summary>
552         /// <since_tizen> 6 </since_tizen>
553         protected virtual void OnUnparent() { }
554
555         /// <summary>
556         /// Virtual method called when this Layout is attached to it's owner.
557         /// Allows derived layouts to take ownership of child Views and connect to any Owner signals required.
558         /// </summary>
559         /// <since_tizen> 6 </since_tizen>
560         protected virtual void OnAttachedToOwner() { }
561
562         private bool SetFrame(float left, float top, float right, float bottom, bool independent)
563         {
564             bool changed = false;
565
566             if (_layoutPositionData.Left != left ||
567                  _layoutPositionData.Right != right ||
568                  _layoutPositionData.Top != top ||
569                  _layoutPositionData.Bottom != bottom)
570             {
571                 changed = true;
572
573                 float oldWidth = _layoutPositionData.Right - _layoutPositionData.Left;
574                 float oldHeight = _layoutPositionData.Bottom - _layoutPositionData.Top;
575                 float newWidth = right - left;
576                 float newHeight = bottom - top;
577                 bool sizeChanged = (newWidth != oldWidth) || (newHeight != oldHeight);
578
579                 // Set condition to layout changed as currently unspecified. Add, Remove would have specified a condition.
580                 if (ConditionForAnimation.Equals(TransitionCondition.Unspecified))
581                 {
582                     ConditionForAnimation = TransitionCondition.LayoutChanged;
583                 }
584
585                 // Store new layout position data
586                 _layoutPositionData = new LayoutData(this, ConditionForAnimation, left, top, right, bottom);
587
588                 Debug.WriteLineIf(LayoutDebugFrameData, "LayoutItem FramePositionData View:" + _layoutPositionData.Item.Owner.Name +
589                                                          " left:" + _layoutPositionData.Left +
590                                                          " top:" + _layoutPositionData.Top +
591                                                          " right:" + _layoutPositionData.Right +
592                                                          " bottom:" + _layoutPositionData.Bottom);
593
594                 Container onwerContainer = Owner.GetParent();
595                 View onwerView = onwerContainer is Layer ? new View(Layer.getCPtr(onwerContainer).Handle, false) : onwerContainer as View;
596
597                 if (onwerView != null && onwerView.Layout != null && onwerView.Layout.LayoutWithTransition)
598                 {
599                     NUIApplication.GetDefaultWindow().LayoutController.AddTransitionDataEntry(_layoutPositionData);
600                 }
601                 else
602                 {
603                     if (Owner.Position != null)
604                     {
605                         if(independent)
606                         {
607                             // If height or width specification is not explicitly defined,
608                             // the size of the owner view must be reset even the ExcludeLayouting is true.
609                             if (Owner.HeightSpecification < 0 || Owner.WidthSpecification < 0)
610                             {
611                                 Owner.SetSize(right - left, bottom - top);
612                             }
613                         }
614                         else
615                         {
616                             Owner.SetSize(right - left, bottom - top);
617                             Owner.SetPosition(left, top);
618                         }
619                     }
620                 }
621
622                 // Reset condition for animation ready for next transition when required.
623                 ConditionForAnimation = TransitionCondition.Unspecified;
624             }
625
626             return changed;
627         }
628
629
630         [EditorBrowsable(EditorBrowsableState.Never)]
631         protected virtual void Dispose(bool disposing)
632         {
633             if(disposed)
634             {
635                 return;
636             }
637
638             if (disposing)
639             {
640                 _margin?.Dispose();
641                 _padding?.Dispose();
642             }
643             disposed = true;
644         }
645
646         [EditorBrowsable(EditorBrowsableState.Never)]
647         public void Dispose()
648         {
649             Dispose(true);
650             global::System.GC.SuppressFinalize(this);
651         }
652     }
653 }