[NUI] Introduce CollectionView and related classes. (#2525)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / RecyclerView / Item / RecyclerViewItem.cs
1 /* Copyright (c) 2021 Samsung Electronics Co., Ltd.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  *
15  */
16 using System;
17 using System.ComponentModel;
18 using Tizen.NUI.BaseComponents;
19 using Tizen.NUI.Binding;
20 using Tizen.NUI.Components.Extension;
21 using Tizen.NUI.Accessibility;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// This class provides a basic item for CollectionView.
27     /// </summary>
28     [EditorBrowsable(EditorBrowsableState.Never)]
29     public partial class RecyclerViewItem : Control
30     {
31         /// <summary>
32         /// Property of boolean Enable flag.
33         /// </summary>
34         [EditorBrowsable(EditorBrowsableState.Never)]
35         public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(nameof(IsEnabled), typeof(bool), typeof(RecyclerViewItem), true, propertyChanged: (bindable, oldValue, newValue) =>
36         {
37             var instance = (RecyclerViewItem)bindable;
38             if (newValue != null)
39             {
40                 bool newEnabled = (bool)newValue;
41                 if (instance.isEnabled != newEnabled)
42                 {
43                     instance.isEnabled = newEnabled;
44                     if (instance.ItemStyle != null)
45                     {
46                         instance.ItemStyle.IsEnabled = newEnabled;
47                     }
48                     instance.UpdateState();
49                 }
50             }
51         },
52         defaultValueCreator: (bindable) => ((RecyclerViewItem)bindable).isEnabled);
53
54         /// <summary>
55         /// Property of boolean Selected flag.
56         /// </summary>
57         [EditorBrowsable(EditorBrowsableState.Never)]
58         public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(RecyclerViewItem), true, propertyChanged: (bindable, oldValue, newValue) =>
59         {
60             var instance = (RecyclerViewItem)bindable;
61             if (newValue != null)
62             {
63                 bool newSelected = (bool)newValue;
64                 if (instance.isSelected != newSelected)
65                 {
66                     instance.isSelected = newSelected;
67
68                     if (instance.ItemStyle != null)
69                     {
70                         instance.ItemStyle.IsSelected = newSelected;
71                     }
72
73                     if (instance.isSelectable)
74                     {
75                         instance.UpdateState();
76                     }
77                 }
78             }
79         },
80         defaultValueCreator: (bindable) =>
81         {
82             var instance = (RecyclerViewItem)bindable;
83             return instance.isSelectable && instance.isSelected;
84         });
85
86         /// <summary>
87         /// Property of boolean Selectable flag.
88         /// </summary>      
89         [EditorBrowsable(EditorBrowsableState.Never)]
90         public static readonly BindableProperty IsSelectableProperty = BindableProperty.Create(nameof(IsSelectable), typeof(bool), typeof(RecyclerViewItem), true, propertyChanged: (bindable, oldValue, newValue) =>
91         {
92             var instance = (RecyclerViewItem)bindable;
93             if (newValue != null)
94             {
95                 bool newSelectable = (bool)newValue;
96                 if (instance.isSelectable != newSelectable)
97                 {
98                     instance.isSelectable = newSelectable;
99
100                     if (instance.ItemStyle != null)
101                     {
102                         instance.ItemStyle.IsSelectable = newSelectable;
103                     }
104
105                     instance.UpdateState();
106                 }
107             }
108         },
109         defaultValueCreator: (bindable) => ((RecyclerViewItem)bindable).isSelectable);
110
111         private bool isSelected = false;
112         private bool isSelectable = true;
113         private bool isEnabled = true;
114         private RecyclerViewItemStyle ItemStyle => ViewStyle as RecyclerViewItemStyle;
115
116         /// <summary>
117         /// Return a copied Style instance of Toast
118         /// </summary>
119         /// <remarks>
120         /// It returns copied Style instance and changing it does not effect to the Toast.
121         /// Style setting is possible by using constructor or the function of ApplyStyle(ViewStyle viewStyle)
122         /// </remarks>
123         [EditorBrowsable(EditorBrowsableState.Never)]
124         public new RecyclerViewItemStyle Style
125         {
126             get
127             {
128                 var result = new RecyclerViewItemStyle(ItemStyle);
129                 result.CopyPropertiesFromView(this);
130                 return result;
131             }
132         }
133
134         static RecyclerViewItem() {}
135
136         /// <summary>
137         /// Creates a new instance of RecyclerViewItem.
138         /// </summary>
139         [EditorBrowsable(EditorBrowsableState.Never)]
140         public RecyclerViewItem() : base()
141         {
142             Initialize();
143         }
144
145         /// <summary>
146         /// Creates a new instance of RecyclerViewItem with style.
147         /// </summary>
148         /// <param name="style">Create RecyclerViewItem by special style defined in UX.</param>
149         [EditorBrowsable(EditorBrowsableState.Never)]
150         public RecyclerViewItem(string style) : base(style)
151         {
152             Initialize();
153         }
154
155         /// <summary>
156         /// Creates a new instance of a RecyclerViewItem with style.
157         /// </summary>
158         /// <param name="itemStyle">Create RecyclerViewItem by style customized by user.</param>
159         [EditorBrowsable(EditorBrowsableState.Never)]
160         public RecyclerViewItem(RecyclerViewItemStyle itemStyle) : base(itemStyle)
161         {
162             Initialize();
163         }
164
165         /// <summary>
166         /// An event for the RecyclerViewItem clicked signal which can be used to subscribe or unsubscribe the event handler provided by the user.
167         /// </summary>
168         [EditorBrowsable(EditorBrowsableState.Never)]
169         public event EventHandler<ClickedEventArgs> Clicked;
170
171         /// <summary>
172         /// Flag to decide RecyclerViewItem can be selected or not.
173         /// </summary>
174         [EditorBrowsable(EditorBrowsableState.Never)]
175         public bool IsSelectable
176         {
177             get => (bool)GetValue(IsSelectableProperty);
178             set => SetValue(IsSelectableProperty, value);
179         }
180
181         /// <summary>
182         /// Flag to decide selected state in RecyclerViewItem.
183         /// </summary>
184         [EditorBrowsable(EditorBrowsableState.Never)]
185         public bool IsSelected
186         {
187             get => (bool)GetValue(IsSelectedProperty);
188             set => SetValue(IsSelectedProperty, value);
189         }
190
191         /// <summary>
192         /// Flag to decide enable or disable in RecyclerViewItem.
193         /// </summary>
194         [EditorBrowsable(EditorBrowsableState.Never)]
195         public bool IsEnabled
196         {
197             get =>  (bool)GetValue(IsEnabledProperty);
198             set =>  SetValue(IsEnabledProperty, value);
199         }
200
201         /// <summary>
202         /// Data index which is binded to item.
203         /// Can access to data using this index.
204         /// </summary>
205         [EditorBrowsable(EditorBrowsableState.Never)]
206         public int Index { get; internal set; } = 0;
207
208         /// <summary>
209         /// DataTemplate of this view object
210         /// </summary>
211         [EditorBrowsable(EditorBrowsableState.Never)]
212         public DataTemplate Template { get; internal set; }
213
214         /// <summary>
215         /// State of Realization
216         /// </summary>
217         [EditorBrowsable(EditorBrowsableState.Never)]
218         public bool IsRealized { get; internal set; }
219         internal bool IsHeader { get; set; }
220         internal bool IsFooter { get; set; }
221         internal bool IsPressed  { get; set; } = false;
222
223         /// <summary>
224         /// Called after a key event is received by the view that has had its focus set.
225         /// </summary>
226         /// <param name="key">The key event.</param>
227         /// <returns>True if the key event should be consumed.</returns>
228         [EditorBrowsable(EditorBrowsableState.Never)]
229         public override bool OnKey(Key key)
230         {
231             if (!IsEnabled || null == key)
232             {
233                 return false;
234             }
235
236             if (key.State == Key.StateType.Down)
237             {
238                 if (key.KeyPressedName == "Return")
239                 {
240                     IsPressed = true;
241                     UpdateState();
242                 }
243             }
244             else if (key.State == Key.StateType.Up)
245             {
246                 if (key.KeyPressedName == "Return")
247                 {
248                     bool clicked = IsPressed && IsEnabled;
249
250                     IsPressed = false;
251
252                     if (IsSelectable)
253                     {
254                         // Extension : Extension?.SetTouchInfo(touch);
255                         if (ParentItemsView as CollectionView)
256                         {
257                             CollectionView colView = ParentItemsView as CollectionView;
258                             switch (colView.SelectionMode)
259                             {
260                                 case ItemSelectionMode.SingleSelection :
261                                     colView.SelectedItem = IsSelected ? null : BindingContext;
262                                     break;
263                                 case ItemSelectionMode.MultipleSelections :
264                                     var selectedItems = colView.SelectedItems;
265                                     if (selectedItems.Contains(BindingContext)) selectedItems.Remove(BindingContext);
266                                     else selectedItems.Add(BindingContext);
267                                     break;
268                                 case ItemSelectionMode.None :
269                                     break;
270                             }
271                         }
272                     }
273                     else
274                     {
275                         UpdateState();
276                     }
277
278                     if (clicked)
279                     {
280                         ClickedEventArgs eventArgs = new ClickedEventArgs();
281                         OnClickedInternal(eventArgs);
282                     }
283                 }
284             }
285             return base.OnKey(key);
286         }
287
288         /// <summary>
289         /// Called when the control gain key input focus. Should be overridden by derived classes if they need to customize what happens when the focus is gained.
290         /// </summary>
291         [EditorBrowsable(EditorBrowsableState.Never)]
292         public override void OnFocusGained()
293         {
294             base.OnFocusGained();
295             UpdateState();
296         }
297
298         /// <summary>
299         /// Called when the control loses key input focus. 
300         /// Should be overridden by derived classes if they need to customize
301         /// what happens when the focus is lost.
302         /// </summary>
303         [EditorBrowsable(EditorBrowsableState.Never)]
304         public override void OnFocusLost()
305         {
306             base.OnFocusLost();
307             UpdateState();
308         }
309
310         /// <summary>
311         /// Apply style to RecyclerViewItem.
312         /// </summary>
313         /// <param name="viewStyle">The style to apply.</param>
314         [EditorBrowsable(EditorBrowsableState.Never)]
315         public override void ApplyStyle(ViewStyle viewStyle)
316         {
317             styleApplied = false;
318
319             base.ApplyStyle(viewStyle);
320             if (viewStyle != null)
321             {
322                 //Extension = RecyclerViewItemStyle.CreateExtension();
323             }
324
325             styleApplied = true;
326         }
327     }
328 }