diff --git a/src/Tizen.NUI/src/internal/Common/ControlStateUtility.cs b/src/Tizen.NUI/src/internal/Common/ControlStateUtility.cs
new file mode 100644
index 00000000000..c87903425fe
--- /dev/null
+++ b/src/Tizen.NUI/src/internal/Common/ControlStateUtility.cs
@@ -0,0 +1,72 @@
+/*
+ * Copyright(c) 2025 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;
+
+namespace Tizen.NUI
+{
+ ///
+ /// Manages state name and bit mask.
+ ///
+ internal static class ControlStateUtility
+ {
+ private const int MaxBitWidth = 32;
+ private static readonly Dictionary registeredStates = new Dictionary();
+ private static int nextBitPosition = 0;
+
+ ///
+ ///
+ public static long FullMask => (1L << MaxBitWidth) - 1L;
+
+ ///
+ ///
+ public static IEnumerable<(string, long)> RegisteredStates()
+ {
+ foreach (var (key, value) in registeredStates)
+ {
+ yield return (key, value);
+ }
+ }
+
+ public static long Register(string stateName)
+ {
+ if (stateName == null)
+ throw new ArgumentNullException($"{nameof(stateName)} cannot be null.", nameof(stateName));
+
+ if (string.IsNullOrWhiteSpace(stateName))
+ throw new ArgumentException($"{nameof(stateName)} cannot be whitespace.", nameof(stateName));
+
+ string trimmed = stateName.Trim().ToLowerInvariant();
+
+ if (!registeredStates.TryGetValue(trimmed, out long bitMask))
+ {
+ if (nextBitPosition + 1 > MaxBitWidth)
+ {
+ throw new ArgumentException($"The given state name '{stateName}' is not acceptable since there is no more room to register a new state.");
+ }
+
+ bitMask = 1L << nextBitPosition;
+ registeredStates.Add(trimmed, bitMask);
+
+ nextBitPosition++;
+ }
+
+ return bitMask;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Tizen.NUI/src/public/BaseComponents/ControlState.cs b/src/Tizen.NUI/src/public/BaseComponents/ControlState.cs
index 9c557e14b74..9b633b49144 100755
--- a/src/Tizen.NUI/src/public/BaseComponents/ControlState.cs
+++ b/src/Tizen.NUI/src/public/BaseComponents/ControlState.cs
@@ -1,5 +1,5 @@
/*
- * Copyright(c) 2020-2021 Samsung Electronics Co., Ltd.
+ * Copyright(c) 2020-2025 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.
@@ -16,9 +16,8 @@
*/
using System;
-using System.Collections.Generic;
+using System.Text;
using System.ComponentModel;
-using System.Linq;
namespace Tizen.NUI.BaseComponents
{
@@ -30,38 +29,37 @@ namespace Tizen.NUI.BaseComponents
[Binding.TypeConverter(typeof(ControlStateTypeConverter))]
public class ControlState : IEquatable
{
- private static readonly Dictionary stateDictionary = new Dictionary();
//Default States
///
/// The All state is used in a selector class. It represents all states, so if this state is defined in a selector, the other states are ignored.
///
/// 9
- public static readonly ControlState All = Create("All");
+ public static readonly ControlState All = new ControlState(ControlStateUtility.FullMask);
///
/// Normal State.
///
/// 9
- public static readonly ControlState Normal = Create("Normal");
+ public static readonly ControlState Normal = new ControlState(0L);
///
/// Focused State.
///
/// 9
- public static readonly ControlState Focused = Create("Focused");
+ public static readonly ControlState Focused = new ControlState(nameof(Focused));
///
/// Pressed State.
///
/// 9
- public static readonly ControlState Pressed = Create("Pressed");
+ public static readonly ControlState Pressed = new ControlState(nameof(Pressed));
///
/// Disabled State.
///
/// 9
- public static readonly ControlState Disabled = Create("Disabled");
+ public static readonly ControlState Disabled = new ControlState(nameof(Disabled));
///
/// Selected State.
///
/// 9
- public static readonly ControlState Selected = Create("Selected");
+ public static readonly ControlState Selected = new ControlState(nameof(Selected));
///
/// SelectedPressed State.
///
@@ -86,20 +84,24 @@ public class ControlState : IEquatable
/// This is used in a selector class. It represents all other states except for states that are already defined in a selector.
///
/// 9
- public static readonly ControlState Other = Create("Other");
+ public static readonly ControlState Other = new ControlState(nameof(Other));
- private List stateList = new List();
- private readonly string name = "";
+ readonly long bitFlags;
///
/// Gets or sets a value indicating whether it has combined states.
///
[EditorBrowsable(EditorBrowsableState.Never)]
- public bool IsCombined => stateList.Count > 1;
+ public bool IsCombined => bitFlags != 0L && Math.Ceiling(Math.Log2(bitFlags)) != Math.Floor(Math.Log2(bitFlags));
- private ControlState() { }
+ ControlState(long bitMask)
+ {
+ bitFlags = bitMask;
+ }
- private ControlState(string name) : this() => this.name = name;
+ private ControlState(string name) : this(ControlStateUtility.Register(name))
+ {
+ }
///
/// Create an instance of the with state name.
@@ -111,20 +113,7 @@ private ControlState() { }
/// 9
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));
-
- name = name.Trim();
-
- if (stateDictionary.TryGetValue(name, out ControlState state))
- return state;
-
- state = new ControlState(name);
- state.stateList.Add(state);
- stateDictionary.Add(name, state);
- return state;
+ return new ControlState(name);
}
///
@@ -138,7 +127,8 @@ public static ControlState Create(params ControlState[] states)
if (states.Length == 1)
return states[0];
- ControlState newState = new ControlState();
+ var newState = new ControlState(0L);
+
for (int i = 0; i < states.Length; i++)
{
if (states[i] == Normal)
@@ -147,17 +137,7 @@ public static ControlState Create(params ControlState[] states)
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];
+ newState += states[i];
}
return newState;
@@ -172,38 +152,16 @@ public static ControlState Create(params ControlState[] states)
/// 9
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;
+ if (state is null) return false;
+ return (bitFlags & state.bitFlags) == state.bitFlags;
}
///
[EditorBrowsable(EditorBrowsableState.Never)]
public bool Equals(ControlState other)
{
- if (other is null || stateList.Count != other.stateList.Count)
- return false;
-
- return Contains(other);
+ if (other is null) return false;
+ return this.bitFlags == other.bitFlags;
}
///
@@ -212,18 +170,24 @@ public bool Equals(ControlState other)
///
[EditorBrowsable(EditorBrowsableState.Never)]
- public override int GetHashCode() => (name.GetHashCode() * 397) ^ IsCombined.GetHashCode();
+ public override int GetHashCode() => bitFlags.GetHashCode();
///
[EditorBrowsable(EditorBrowsableState.Never)]
public override string ToString()
{
- string name = "";
- for (int i = 0; i < stateList.Count; i++)
+ var sbuilder = new StringBuilder();
+
+ foreach (var (name, bitMask) in ControlStateUtility.RegisteredStates())
{
- name += ((i == 0) ? "" : ", ") + stateList[i].name;
+ if ((bitFlags & bitMask) > 0)
+ {
+ if (sbuilder.Length != 0) sbuilder.Append(", ");
+ sbuilder.Append(name);
+ }
}
- return name;
+
+ return sbuilder.ToString();
}
///
@@ -247,7 +211,6 @@ public override string ToString()
// Only the left side is null.
return false;
}
- // Equals handles case of null on right side.
return lhs.Equals(rhs);
}
@@ -267,7 +230,10 @@ public override string ToString()
/// A on the right hand side.
/// The containing the result of the addition.
/// 9
- public static ControlState operator +(ControlState lhs, ControlState rhs) => Create(lhs, rhs);
+ public static ControlState operator +(ControlState lhs, ControlState rhs)
+ {
+ return Add(lhs, rhs);
+ }
///
/// The substraction operator.
@@ -279,36 +245,55 @@ public override string ToString()
[EditorBrowsable(EditorBrowsableState.Never)]
public static ControlState operator -(ControlState lhs, ControlState rhs)
{
- if (null == lhs)
+ return Remove(lhs, rhs);
+ }
+
+ ///
+ /// Add multiple states.
+ ///
+ /// The first operand object.
+ /// The second operand object.
+ /// The rest operand objects.
+ /// The operation result.
+ static ControlState Add(ControlState operand1, ControlState operand2, params ControlState[] rest)
+ {
+ if (operand1 is null)
{
- throw new ArgumentNullException(nameof(lhs));
+ throw new ArgumentNullException(nameof(operand1));
}
- else if (null == rhs)
+ if (operand2 is null)
{
- throw new ArgumentNullException(nameof(rhs));
+ throw new ArgumentNullException(nameof(operand2));
}
- if (!lhs.IsCombined)
+ long newBitFlags = operand1.bitFlags | operand2.bitFlags;
+
+ foreach (var state in rest)
{
- return ReferenceEquals(lhs, rhs) ? Normal : lhs;
+ newBitFlags |= state.bitFlags;
}
- var rest = lhs.stateList.Except(rhs.stateList);
- var count = rest.Count();
+ return new ControlState(newBitFlags);
+ }
- if (count == 0)
+ ///
+ /// Remove a state from another.
+ ///
+ /// The first operand object.
+ /// The second operand object.
+ /// The operation result.
+ static ControlState Remove(ControlState operand1, ControlState operand2)
+ {
+ if (operand1 is null)
{
- return Normal;
+ throw new ArgumentNullException(nameof(operand1));
}
-
- if (count == 1)
+ if (operand2 is null)
{
- return rest.First();
+ throw new ArgumentNullException(nameof(operand2));
}
- ControlState newState = new ControlState();
- newState.stateList.AddRange(rest);
- return newState;
+ return new ControlState(operand1.bitFlags & ~(operand2.bitFlags));
}
class ControlStateTypeConverter : Binding.TypeConverter
@@ -319,7 +304,7 @@ public override object ConvertFromInvariantString(string value)
{
value = value.Trim();
- ControlState convertedState = new ControlState();
+ ControlState convertedState = new ControlState(0L);
string[] parts = value.Split(',');
foreach (string part in parts)
{