/*
* Copyright(c) 2019 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.ComponentModel;
namespace Tizen.NUI.Components
{
///
/// Layout collection of views horizontally/vertically.
///
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public partial class LinearLayoutManager : FlexibleViewLayoutManager
{
///
/// Constant value: 0.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly int HORIZONTAL = OrientationHelper.HORIZONTAL;
///
/// Constant value: 1.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly int VERTICAL = OrientationHelper.VERTICAL;
///
/// Constant value: -1.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly int NO_POSITION = FlexibleView.NO_POSITION;
///
/// Constant value: -2^31.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly int INVALID_OFFSET = -2147483648;
private const float MAX_SCROLL_FACTOR = 1 / 3f;
///
/// Current orientation.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
protected int mOrientation;
internal OrientationHelper mOrientationHelper;
private LayoutState mLayoutState;
private AnchorInfo mAnchorInfo = new AnchorInfo();
// Stashed to avoid allocation, currently only used in #fill()
private LayoutChunkResult mLayoutChunkResult = new LayoutChunkResult();
private bool mShouldReverseLayout = false;
// When LayoutManager needs to scroll to a position, it sets this variable and requests a
// layout which will check this variable and re-layout accordingly.
private int mPendingScrollPosition = NO_POSITION;
// Used to keep the offset value when {@link #scrollToPositionWithOffset(int, int)} is
// called.
private int mPendingScrollPositionOffset = INVALID_OFFSET;
///
/// Creates a LinearLayoutManager with orientation.
///
/// Layout orientation.Should be HORIZONTAL or VERTICAL
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public LinearLayoutManager(int orientation)
{
mOrientation = orientation;
mOrientationHelper = OrientationHelper.CreateOrientationHelper(this, mOrientation);
mLayoutState = new LayoutState();
mLayoutState.Offset = mOrientationHelper.GetStartAfterPadding();
}
///
/// Retrieves the first visible item position.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public int FirstVisibleItemPosition
{
get
{
FlexibleViewViewHolder child = FindFirstVisibleItemView();
return child == null ? NO_POSITION : child.LayoutPosition;
}
}
///
/// Retrieves the first complete visible item position.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public int FirstCompleteVisibleItemPosition
{
get
{
FlexibleViewViewHolder child = FindFirstCompleteVisibleItemView();
return child == null ? NO_POSITION : child.LayoutPosition;
}
}
///
/// Retrieves the last visible item position.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public int LastVisibleItemPosition
{
get
{
FlexibleViewViewHolder child = FindLastVisibleItemView();
return child == null ? NO_POSITION : child.LayoutPosition;
}
}
///
/// Retrieves the last complete visible item position.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public int LastCompleteVisibleItemPosition
{
get
{
FlexibleViewViewHolder child = FindLastCompleteVisibleItemView();
return child == null ? NO_POSITION : child.LayoutPosition;
}
}
///
/// Query if horizontal scrolling is currently supported. The default implementation returns false.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool CanScrollHorizontally()
{
return mOrientation == HORIZONTAL;
}
///
/// Query if vertical scrolling is currently supported. The default implementation returns false.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool CanScrollVertically()
{
return mOrientation == VERTICAL;
}
///
/// Lay out all relevant child views from the given adapter.
///
/// Recycler to use for fetching potentially cached views for a position
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override void OnLayoutChildren(FlexibleViewRecycler recycler)
{
mLayoutState.Recycle = false;
if (!mAnchorInfo.Valid || mPendingScrollPosition != NO_POSITION)
{
mAnchorInfo.Reset();
mAnchorInfo.LayoutFromEnd = mShouldReverseLayout;
// calculate anchor position and coordinate
UpdateAnchorInfoForLayout(recycler, mAnchorInfo);
mAnchorInfo.Valid = true;
}
int firstLayoutDirection;
if (mAnchorInfo.LayoutFromEnd)
{
firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_TAIL
: LayoutState.ITEM_DIRECTION_HEAD;
}
else
{
firstLayoutDirection = mShouldReverseLayout ? LayoutState.ITEM_DIRECTION_HEAD
: LayoutState.ITEM_DIRECTION_TAIL;
}
EnsureAnchorReady(recycler, mAnchorInfo, firstLayoutDirection);
ScrapAttachedViews(recycler);
if (mAnchorInfo.LayoutFromEnd == true)
{
UpdateLayoutStateToFillStart(mAnchorInfo.Position, mAnchorInfo.Coordinate);
Fill(recycler, mLayoutState, false, true);
Cache(recycler, mLayoutState, true);
UpdateLayoutStateToFillEnd(mAnchorInfo.Position, mAnchorInfo.Coordinate);
mLayoutState.CurrentPosition += mLayoutState.ItemDirection;
Fill(recycler, mLayoutState, false, true);
Cache(recycler, mLayoutState, true);
}
else
{
UpdateLayoutStateToFillEnd(mAnchorInfo.Position, mAnchorInfo.Coordinate);
Fill(recycler, mLayoutState, false, true);
Cache(recycler, mLayoutState, true);
UpdateLayoutStateToFillStart(mAnchorInfo.Position, mAnchorInfo.Coordinate);
mLayoutState.CurrentPosition += mLayoutState.ItemDirection;
Fill(recycler, mLayoutState, false, true);
Cache(recycler, mLayoutState, true);
}
OnLayoutCompleted();
}
///
/// Scroll horizontally by dy pixels in screen coordinates.
///
/// distance to scroll in pixels. Y increases as scroll position approaches the top.
/// Recycler to use for fetching potentially cached views for a position
/// Specify if the scroll need animation
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override float ScrollHorizontallyBy(float dx, FlexibleViewRecycler recycler, bool immediate)
{
if (mOrientation == VERTICAL)
{
return 0;
}
return ScrollBy(dx, recycler, immediate);
}
///
/// Scroll vertically by dy pixels in screen coordinates.
///
/// distance to scroll in pixels. Y increases as scroll position approaches the top.
/// Recycler to use for fetching potentially cached views for a position
/// Specify if the scroll need animation
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override float ScrollVerticallyBy(float dy, FlexibleViewRecycler recycler, bool immediate)
{
if (mOrientation == HORIZONTAL)
{
return 0;
}
return ScrollBy(dy, recycler, immediate);
}
///
/// Compute the offset of the scrollbar's thumb within the range.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override float ComputeScrollOffset()
{
FlexibleViewViewHolder startChild = FindFirstVisibleItemView();
FlexibleViewViewHolder endChild = FindLastVisibleItemView();
if (ChildCount == 0 || startChild == null || endChild == null)
{
return 0;
}
int minPosition = Math.Min(startChild.LayoutPosition, endChild.LayoutPosition);
int maxPosition = Math.Max(startChild.LayoutPosition, endChild.LayoutPosition);
int itemsBefore = mShouldReverseLayout
? Math.Max(0, ItemCount - maxPosition - 1)
: Math.Max(0, minPosition);
float laidOutArea = Math.Abs(mOrientationHelper.GetViewHolderEnd(endChild)
- mOrientationHelper.GetViewHolderStart(startChild));
int itemRange = Math.Abs(startChild.LayoutPosition - endChild.LayoutPosition) + 1;
float avgSizePerRow = laidOutArea / itemRange;
return (float)Math.Round(itemsBefore * avgSizePerRow + (mOrientationHelper.GetStartAfterPadding()
- mOrientationHelper.GetViewHolderStart(startChild)));
}
///
/// Compute the extent of the scrollbar's thumb within the range.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override float ComputeScrollExtent()
{
FlexibleViewViewHolder startChild = FindFirstVisibleItemView();
FlexibleViewViewHolder endChild = FindLastVisibleItemView();
if (ChildCount == 0 || startChild == null || endChild == null)
{
return 0;
}
float extend = mOrientationHelper.GetViewHolderEnd(endChild)
- mOrientationHelper.GetViewHolderStart(startChild);
return Math.Min(mOrientationHelper.GetTotalSpace(), extend);
}
///
/// Compute the range that the scrollbar represents.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override float ComputeScrollRange()
{
FlexibleViewViewHolder startChild = FindFirstVisibleItemView();
FlexibleViewViewHolder endChild = FindLastVisibleItemView();
if (ChildCount == 0 || startChild == null || endChild == null)
{
return 0;
}
float laidOutArea = mOrientationHelper.GetViewHolderEnd(endChild)
- mOrientationHelper.GetViewHolderStart(startChild);
int laidOutRange = Math.Abs(startChild.LayoutPosition - endChild.LayoutPosition) + 1;
// estimate a size for full list.
return laidOutArea / laidOutRange * ItemCount;
}
///
/// Scroll the FlexibleView to make the position visible.
///
/// Scroll to this adapter position
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override void ScrollToPosition(int position)
{
mPendingScrollPosition = position;
mPendingScrollPositionOffset = INVALID_OFFSET;
RelayoutRequest();
}
///
/// Scroll to the specified adapter position with the given offset from resolved layout start.
///
/// Scroll to this adapter position
/// The distance (in pixels) between the start edge of the item view and start edge of the FlexibleView.
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override void ScrollToPositionWithOffset(int position, int offset)
{
mPendingScrollPosition = position;
mPendingScrollPositionOffset = offset;
RelayoutRequest();
}
///
/// Called after a full layout calculation is finished.
///
/// 6
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public override void OnLayoutCompleted()
{
if (mPendingScrollPosition != NO_POSITION)
{
ChangeFocus(mPendingScrollPosition);
}
mPendingScrollPosition = NO_POSITION;
mPendingScrollPositionOffset = INVALID_OFFSET;
mAnchorInfo.Reset();
}
internal virtual void EnsureAnchorReady(FlexibleViewRecycler recycler, AnchorInfo anchorInfo, int itemDirection)
{
}
///
/// Retrieves a position that neighbor to current position by direction.
///
/// The anchor adapter position
/// The direction.
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
protected override int GetNextPosition(int position, FlexibleViewLayoutManager.Direction direction)
{
if (mOrientation == HORIZONTAL)
{
switch (direction)
{
case FlexibleViewLayoutManager.Direction.Left:
if (position > 0)
{
return position - 1;
}
break;
case FlexibleViewLayoutManager.Direction.Right:
if (position < ItemCount - 1)
{
return position + 1;
}
break;
}
}
else
{
switch (direction)
{
case FlexibleViewLayoutManager.Direction.Up:
if (position > 0)
{
return position - 1;
}
break;
case FlexibleViewLayoutManager.Direction.Down:
if (position < ItemCount - 1)
{
return position + 1;
}
break;
}
}
return NO_POSITION;
}
///
/// Retrieves the first visible item view.
///
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
protected override FlexibleViewViewHolder FindFirstVisibleItemView()
{
int childCount = ChildCount;
if (mShouldReverseLayout == false)
{
for (int i = 0; i < childCount; i++)
{
FlexibleViewViewHolder child = GetChildAt(i);
int end = (int)mOrientationHelper.GetViewHolderEnd(child);
if (end >= 0 && end < (int)mOrientationHelper.GetEnd())
{
return child;
}
}
}
else
{
for (int i = childCount - 1; i >= 0; i--)
{
FlexibleViewViewHolder child = GetChildAt(i);
int end = (int)mOrientationHelper.GetViewHolderEnd(child);
if (end >= 0 && end < (int)mOrientationHelper.GetEnd())
{
return child;
}
}
}
return null;
}
///
/// Retrieves the last visible item view.
///
/// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
protected override FlexibleViewViewHolder FindLastVisibleItemView()
{
int childCount = ChildCount;
if (mShouldReverseLayout == false)
{
for (int i = childCount - 1; i >= 0; i--)
{
FlexibleViewViewHolder child = GetChildAt(i);
int start = (int)mOrientationHelper.GetViewHolderStart(child);
if (start > 0 && start < (int)mOrientationHelper.GetEnd())
{
return child;
}
}
}
else
{
for (int i = 0; i < childCount; i++)
{
FlexibleViewViewHolder child = GetChildAt(i);
int start = (int)mOrientationHelper.GetViewHolderStart(child);
if (start > 0 && start < (int)mOrientationHelper.GetEnd())
{
return child;
}
}
}
return null;
}
}
}