/*
* Copyright(c) 2020 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.Collections.Generic;
using System.ComponentModel;
using System.Linq;
namespace Tizen.NUI.BaseComponents
{
///
/// Class for describing the states of the view.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public class ControlState : IEquatable
{
private static readonly Dictionary stateDictionary = new Dictionary();
//Default States
///
/// All State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState All = Create("All");
///
/// Normal State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState Normal = Create("Normal");
///
/// Focused State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState Focused = Create("Focused");
///
/// Pressed State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState Pressed = Create("Pressed");
///
/// Disabled State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState Disabled = Create("Disabled");
///
/// Selected State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState Selected = Create("Selected");
///
/// DisabledSelected State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState DisabledSelected = Disabled + Selected;
///
/// DisabledFocused State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState DisabledFocused = Disabled + Focused;
///
/// SelectedFocused State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState SelectedFocused = Selected + Focused;
///
/// Other State.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly ControlState Other = Create("Other");
private List stateList = new List();
private readonly string name = "";
///
/// Gets or sets a value indicating whether it has combined states.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public bool IsCombined => stateList.Count > 1;
///
/// Default Contructor. Please use or instead.
///
// Do not open this constructor. This is only for xaml support.
[EditorBrowsable(EditorBrowsableState.Never)]
public ControlState() { }
private ControlState(string name) : this() => this.name = name;
///
/// Create an instance of the with state name.
///
/// The state name.
/// The instance which has single state.
[EditorBrowsable(EditorBrowsableState.Never)]
public static ControlState Create(string name)
{
if (name == null)
throw new ArgumentNullException(nameof(name));
if (string.IsNullOrWhiteSpace(name))
throw new ArgumentException("name cannot be empty string", nameof(name));
if (stateDictionary.TryGetValue(name, out ControlState state))
return state;
state = new ControlState(name);
state.stateList.Add(state);
stateDictionary.Add(name, state);
return state;
}
///
/// Create an instance of the with combined states.
///
/// The control state array.
/// The instance which has combined state.
[EditorBrowsable(EditorBrowsableState.Never)]
public static ControlState Create(params ControlState[] states)
{
if (states.Length == 1)
return states[0];
ControlState newState = new ControlState();
for (int i = 0; i < states.Length; i++)
{
if (states[i] == Normal)
continue;
if (states[i] == All)
return All;
newState.stateList.AddRange(states[i].stateList);
}
if (newState.stateList.Count == 0)
return Normal;
newState.stateList = newState.stateList.Distinct().ToList();
if (newState.stateList.Count == 1)
{
return newState.stateList[0];
}
return newState;
}
///
/// Determines whether a state contains a specified state.
///
/// The state to search for
/// true if the state contain a specified state, otherwise, false.
[EditorBrowsable(EditorBrowsableState.Never)]
public bool Contains(ControlState state)
{
if (state == null)
throw new ArgumentNullException(nameof(state));
if (!IsCombined)
return ReferenceEquals(this, state);
bool found;
for (int i = 0; i < state.stateList.Count; i++)
{
found = false;
for (int j = 0; j < stateList.Count; j++)
{
if (ReferenceEquals(state.stateList[i], stateList[j]))
{
found = true;
break;
}
}
if (!found) return false;
}
return true;
}
///
[EditorBrowsable(EditorBrowsableState.Never)]
public bool Equals(ControlState other)
{
if (other is null || stateList.Count != other.stateList.Count)
return false;
return Contains(other);
}
///
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj) => this.Equals(obj as ControlState);
///
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => (name.GetHashCode() * 397) ^ IsCombined.GetHashCode();
///
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString()
{
string name = "";
for (int i = 0; i < stateList.Count; i++)
{
name += ((i == 0) ? "" : ", ") + stateList[i].name;
}
return name;
}
///
/// Compares whether the two ControlStates are same or not.
///
/// A on the left hand side.
/// A on the right hand side.
/// true if the ControlStates are equal; otherwise, false.
[EditorBrowsable(EditorBrowsableState.Never)]
public static bool operator ==(ControlState lhs, ControlState rhs) => lhs.Equals(rhs);
///
/// Compares whether the two ControlStates are different or not.
///
/// A on the left hand side.
/// A on the right hand side.
/// true if the ControlStates are not equal; otherwise, false.
[EditorBrowsable(EditorBrowsableState.Never)]
public static bool operator !=(ControlState lhs, ControlState rhs) => !lhs.Equals(rhs);
///
/// The addition operator.
///
/// A on the left hand side.
/// A on the right hand side.
/// The containing the result of the addition.
[EditorBrowsable(EditorBrowsableState.Never)]
public static ControlState operator +(ControlState lhs, ControlState rhs) => Create(lhs, rhs);
///
/// The substraction operator.
///
/// A on the left hand side.
/// A on the right hand side.
/// The containing the result of the substraction.
[EditorBrowsable(EditorBrowsableState.Never)]
public static ControlState operator -(ControlState lhs, ControlState rhs)
{
if (!lhs.IsCombined)
{
return ReferenceEquals(lhs, rhs) ? Normal : lhs;
}
var rest = lhs.stateList.Except(rhs.stateList);
if (rest.Count() == 0)
{
return Normal;
}
if (rest.Count() == 1)
{
return rest.First();
}
ControlState newState = new ControlState();
newState.stateList.AddRange(rest);
return newState;
}
}
///
/// The Key/Value pair structure. this is mutable to support for xaml.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public struct StateValuePair : IEquatable>
{
///
/// The constructor with the specified state and value.
///
/// The state
/// The value associated with state.
[EditorBrowsable(EditorBrowsableState.Never)]
public StateValuePair(ControlState state, T value)
{
State = state;
Value = value;
}
///
/// The state
///
[EditorBrowsable(EditorBrowsableState.Never)]
public ControlState State { get; set; }
///
/// The value associated with state.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public T Value { get; set; }
///
[EditorBrowsable(EditorBrowsableState.Never)]
public bool Equals(StateValuePair other) => (Value.Equals(other.Value)) && (State == other.State);
///
[EditorBrowsable(EditorBrowsableState.Never)]
public override bool Equals(object obj)
{
if (!(obj is StateValuePair))
return false;
return Equals((StateValuePair)obj);
}
///
[EditorBrowsable(EditorBrowsableState.Never)]
public override int GetHashCode() => (State.GetHashCode() * 397) ^ Value.GetHashCode();
///
/// Compares whether the two StateValuePair are different or not.
///
/// A on the left hand side.
/// A on the right hand side.
/// true if the StateValuePair are equal; otherwise, false.
[EditorBrowsable(EditorBrowsableState.Never)]
public static bool operator ==(StateValuePair lhs, StateValuePair rhs) => lhs.Equals(rhs);
///
/// Compares whether the two StateValuePair are same or not.
///
/// A on the left hand side.
/// A on the right hand side.
/// true if the StateValuePair are not equal; otherwise, false.
[EditorBrowsable(EditorBrowsableState.Never)]
public static bool operator !=(StateValuePair lhs, StateValuePair rhs) => !(lhs == rhs);
///
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString() => $"[{State}, {Value}]";
}
}