// 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.Text;
using System.Runtime.InteropServices;
using System.Collections.Generic;
using System.Linq;
using System.ComponentModel;
namespace Tizen.NUI.BaseComponents
{
///
/// A visual view control if a user adds any visual to it.
///
///
/// Example:
///
/// VisualView _visualView = new VisualView();
/// ImageVisualMap imageVisualMap1 = new ImageVisualMap();
/// imageVisualMap1.URL = "./NUISample/res/images/image-1.jpg";
/// imageVisualMap1.VisualSize = new Vector2( 300.0f, 300.0f );
/// imageVisualMap1.Offset = new Vector2( 50.0f, 50.0f );
/// imageVisualMap1.OffsetSizeMode = new Vector4( 1.0f, 1.0f, 1.0f, 1.0f );
/// imageVisualMap1.Origin = AlignType.TOP_BEGIN;
/// imageVisualMap1.AnchorPoint = AlignType.TOP_BEGIN;
/// _visualView.AddVisual("imageVisual1", imageVisualMap1);
///
///
/// 3
public class VisualView : CustomView
{
private Dictionary visualNameDictionary = null;
private Dictionary visualDictionary = null;
private Dictionary tranformDictionary = null;
private PropertyArray animateArray = null;
///
/// Constructor.
///
/// 3
public VisualView() : this(CustomViewBehaviour.ViewBehaviourDefault | CustomViewBehaviour.RequiresTouchEventsSupport)
{
}
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public VisualView(ViewStyle viewStyle) : this(CustomViewBehaviour.ViewBehaviourDefault | CustomViewBehaviour.RequiresTouchEventsSupport, viewStyle)
{
}
/// Create a VisualView with specified behaviour.
/// CustomView behaviour
[EditorBrowsable(EditorBrowsableState.Never)]
public VisualView(CustomViewBehaviour behaviour) : base(typeof(VisualView).FullName, behaviour)
{
}
/// Create a VisualView with specified behaviour and a style.
/// CustomView behaviour
/// The ViewStyle.
[EditorBrowsable(EditorBrowsableState.Never)]
public VisualView(CustomViewBehaviour behaviour, ViewStyle viewStyle) : base(typeof(VisualView).FullName, behaviour, viewStyle)
{
}
// static constructor registers the control type (for user can add kinds of visuals to it)
static VisualView()
{
// ViewRegistry registers control type with DALi type registry
// also uses introspection to find any properties that need to be registered with type registry
CustomViewRegistry.Instance.Register(CreateInstance, typeof(VisualView));
}
///
/// Gets the total number of visuals which are added by users.
///
/// 3
public int NumberOfVisuals
{
get
{
return visualDictionary.Count;
}
}
///
/// Overrides the parent method.
///
/// 3
public override void OnInitialize()
{
base.OnInitialize();
//Initialize empty
visualNameDictionary = new Dictionary();
visualDictionary = new Dictionary();
tranformDictionary = new Dictionary();
animateArray = new PropertyArray();
}
///
/// Adds or updates a visual to visual view.
///
/// The name of a visual to add. If a name is added to an existing visual name, the visual will be replaced.
/// The property map of a visual to create.
/// Thrown when visualMap is null.
/// 3
public void AddVisual(string visualName, VisualMap visualMap)
{
int visualIndex = -1;
/* If the visual had added, then replace it using RegisterVusal. */
//visual.Name = name;
foreach (var item in visualNameDictionary)
{
if (item.Value == visualName)
{
/* Find a existed visual, its key also exited. */
visualIndex = item.Key;
UnregisterVisual(visualIndex);
visualNameDictionary.Remove(visualIndex);
visualDictionary.Remove(visualIndex);
tranformDictionary.Remove(visualIndex);
break;
}
}
if (visualIndex == -1) // The visual is a new one, create index for it. */
{
using (var temp = new PropertyValue(visualName))
{
visualIndex = RegisterProperty(visualName, temp, PropertyAccessMode.ReadWrite);
}
}
if (visualIndex > 0)
{
if (visualMap == null)
{
throw new ArgumentNullException(nameof(visualMap));
}
visualMap.VisualIndex = visualIndex;
visualMap.Name = visualName;
visualMap.Parent = this;
// Register index and name
UpdateVisual(visualIndex, visualName, visualMap);
}
}
///
/// Removes a visual by name.
///
/// The name of a visual to remove.
/// 3
public void RemoveVisual(string visualName)
{
foreach (var item in visualNameDictionary)
{
if (item.Value == visualName)
{
EnableVisual(item.Key, false);
UnregisterVisual(item.Key);
tranformDictionary.Remove(item.Key);
visualDictionary.Remove(item.Key);
visualNameDictionary.Remove(item.Key);
RelayoutRequest();
break;
}
}
}
///
/// Removes all visuals of the visual view.
///
/// 3
public void RemoveAll()
{
foreach (var item in visualNameDictionary)
{
EnableVisual(item.Key, false);
UnregisterVisual(item.Key);
}
visualDictionary.Clear();
tranformDictionary.Clear();
visualNameDictionary.Clear();
RelayoutRequest();
}
///
/// Overrides the method of OnRelayout() for CustomView class.
/// Called after the size negotiation has been finished for this control.
/// The control is expected to assign this given size to itself or its children.
/// Should be overridden by derived classes if they need to layout actors differently after certain operations like add or remove actors, resize, or after changing specific properties.
///
/// As this function is called from inside the size negotiation algorithm, you cannot call RequestRelayout (the call would just be ignored).
/// The allocated size.
/// The control should add actors to this container that it is not able to allocate a size for.
/// 3
public override void OnRelayout(Vector2 size, RelayoutContainer container)
{
foreach (var item in visualDictionary)
{
if(item.Value != null)
{
item.Value.SetTransformAndSize(tranformDictionary[item.Key], size);
EnableVisual(item.Key, true);
}
}
}
///
/// Creates a visual animation (transition) with the input parameters.
///
/// The visual map to animation.
/// The property of visual to animation.
/// The destination value of property after animation.
/// The start time of visual animation.
/// The end time of visual animation.
/// The alpha function of visual animation.
/// The initial property value of visual animation.
/// Animation instance
/// Thrown when target is null.
/// 3
public Animation AnimateVisual(VisualMap target, string property, object destinationValue, int startTime, int endTime, AlphaFunction.BuiltinFunctions? alphaFunction = null, object initialValue = null)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
string strAlpha = alphaFunction?.GetDescription();
foreach (var item in visualNameDictionary.ToList())
{
if (item.Value == target.Name)
{
using (PropertyMap animator = new PropertyMap())
using (PropertyMap timePeriod = new PropertyMap())
using (PropertyValue pvDuration = new PropertyValue((endTime - startTime) / 1000.0f))
using (PropertyValue pvDelay = new PropertyValue(startTime / 1000.0f))
using (PropertyValue destVal = PropertyValue.CreateFromObject(destinationValue))
using (PropertyMap transition = new PropertyMap())
using (PropertyValue pvTarget = new PropertyValue(target.Name))
{
if (strAlpha != null)
{
using (PropertyValue pvAlpha = new PropertyValue(strAlpha))
{
animator.Add("alphaFunction", pvAlpha);
}
}
timePeriod.Add("duration", pvDuration);
timePeriod.Add("delay", pvDelay);
using (PropertyValue pvTimePeriod = new PropertyValue(timePeriod))
{
animator.Add("timePeriod", pvTimePeriod);
}
StringBuilder sb = new StringBuilder(property);
sb[0] = (char)(sb[0] | 0x20);
string _str = sb.ToString();
if (_str == "position") { _str = "offset"; }
transition.Add("target", pvTarget);
using (PropertyValue pvStr = new PropertyValue(_str))
{
transition.Add("property", pvStr);
}
if (initialValue != null)
{
using (PropertyValue initVal = PropertyValue.CreateFromObject(initialValue))
using (PropertyValue pvInitialValue = new PropertyValue(initVal))
{
transition.Add("initialValue", pvInitialValue);
}
}
transition.Add("targetValue", destVal);
using (PropertyValue pvAnimator = new PropertyValue(animator))
{
transition.Add("animator", pvAnimator);
}
using (TransitionData transitionData = new TransitionData(transition))
{
return this.CreateTransition(transitionData);
}
}
}
}
return null;
}
///
/// Adds a group visual animation (transition) map with the input parameters.
///
/// The visual map to animation.
/// The property of visual to animation.
/// The destination value of property after animation.
/// The start time of visual animation.
/// The end time of visual animation.
/// The alpha function of visual animation.
/// The initial property value of visual animation.
/// Thrown when target is null.
/// 3
public void AnimateVisualAdd(VisualMap target, string property, object destinationValue, int startTime, int endTime, AlphaFunction.BuiltinFunctions? alphaFunction = null, object initialValue = null)
{
if (target == null)
{
throw new ArgumentNullException(nameof(target));
}
string strAlpha = alphaFunction?.GetDescription();
foreach (var item in visualNameDictionary.ToList())
{
if (item.Value == target.Name)
{
using (PropertyMap animator = new PropertyMap())
using (PropertyMap timePeriod = new PropertyMap())
using (PropertyValue pvDuration = new PropertyValue((endTime - startTime) / 1000.0f))
using (PropertyValue pvDelay = new PropertyValue(startTime / 1000.0f))
using (PropertyValue destVal = PropertyValue.CreateFromObject(destinationValue))
using (PropertyMap transition = new PropertyMap())
using (PropertyValue pvTarget = new PropertyValue(target.Name))
{
if (strAlpha != null)
{
using (PropertyValue pvStrAlpha = new PropertyValue(strAlpha))
{
animator.Add("alphaFunction", pvStrAlpha);
}
}
timePeriod.Add("duration", pvDuration);
timePeriod.Add("delay", pvDelay);
using (PropertyValue pvTimePeriod = new PropertyValue(timePeriod))
{
animator.Add("timePeriod", pvTimePeriod);
}
StringBuilder sb = new StringBuilder(property);
sb[0] = (char)(sb[0] | 0x20);
string _str = sb.ToString();
if (_str == "position") { _str = "offset"; }
transition.Add("target", pvTarget);
using (PropertyValue pvStr = new PropertyValue(_str))
{
transition.Add("property", pvStr);
}
if (initialValue != null)
{
using (PropertyValue initVal = PropertyValue.CreateFromObject(initialValue))
using (PropertyValue pvInitialValue = new PropertyValue(initVal))
{
transition.Add("initialValue", pvInitialValue);
}
}
transition.Add("targetValue", destVal);
using (PropertyValue pvAnimator = new PropertyValue(animator))
{
transition.Add("animator", pvAnimator);
}
using (PropertyValue pvTransition = new PropertyValue(transition))
{
PropertyArray temp = animateArray.Add(pvTransition);
temp.Dispose();
}
}
}
}
}
///
/// Finishes to add a visual animation (transition) map and creates a transition animation.
///
/// Animation instance.
/// 3
public Animation AnimateVisualAddFinish()
{
if (animateArray == null || animateArray.Empty())
{
Tizen.Log.Fatal("NUI", "animate visual property array is empty!");
return null;
}
TransitionData transitionData = new TransitionData(animateArray);
Animation ret = this.CreateTransition(transitionData);
transitionData.Dispose();
return ret;
}
///
/// temporary fix to pass TCT.
///
/// Thrown when visualMap is null.
/// 3
public Animation VisualAnimate(Tizen.NUI.VisualAnimator visualMap)
{
if (visualMap == null)
{
throw new ArgumentNullException(nameof(visualMap));
}
foreach (var item in visualNameDictionary.ToList())
{
if (item.Value == visualMap.Target)
{
using (TransitionData transitionData = new TransitionData(visualMap.OutputVisualMap))
{
return this.CreateTransition(transitionData);
}
}
}
return null;
}
//temporary fix to pass TCT
internal void UpdateVisual(int visualIndex, string visualName, VisualMap visualMap)
{
VisualBase visual = VisualFactory.Instance.CreateVisual(visualMap.OutputVisualMap);
visualNameDictionary[visualIndex] = visualName;
visualDictionary[visualIndex] = visual;
tranformDictionary[visualIndex] = visualMap.OutputTransformMap;
if(visual != null)
{
visual.Name = visualName;
visual.DepthIndex = visualMap.DepthIndex;
RegisterVisual(visualIndex, visual);
RelayoutRequest();
NUILog.Debug("UpdateVisual() name=" + visualName);
}
else
{
NUILog.Debug("UpdateVisual() FAIL! visual create failed name=" + visualName);
}
}
static CustomView CreateInstance()
{
return new VisualView();
}
}
}