Merge remote-tracking branch 'storage/tizen'
[platform/core/csapi/tizenfx.git] / src / ElmSharp / ElmSharp / MultiButtonEntry.cs
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 using System;
18 using System.Collections.Generic;
19
20 namespace ElmSharp
21 {
22     /// <summary>
23     /// It inherits <see cref="Layout"/>.
24     /// The MultiButtonEntry is a widget letting an user enter text and each chunk of text managed as a set of buttons.
25     /// Each text button is inserted by pressing the "return" key. If there is no space in the current row, a new button is added to the next row.
26     /// When a text button is pressed, it will become focused. Backspace removes the focus. When the multi-button entry loses focus, items longer than one line are shrunk to one line.
27     /// The typical use case of multi-button entry is composing emails/messages to a group of addresses, each of which is an item that can be clicked for further actions.
28     /// </summary>
29     public class MultiButtonEntry : Layout
30     {
31         HashSet<MultiButtonEntryItem> _children = new HashSet<MultiButtonEntryItem>();
32         List<Func<string, bool>> _filters = new List<Func<string, bool>>();
33         Func<int, string> _formatFunc = null;
34         Entry _entry = null;
35
36         Interop.Elementary.MultiButtonEntryItemFilterCallback _filterCallback;
37         Interop.Elementary.MultiButtonEntryFormatCallback _formatCallback;
38
39         SmartEvent _clicked;
40         SmartEvent _expanded;
41         SmartEvent _contracted;
42         SmartEvent _expandedStateChanged;
43         SmartEvent<MultiButtonEntryItemEventArgs> _itemSelected;
44         SmartEvent<MultiButtonEntryItemEventArgs> _itemClicked;
45         SmartEvent<MultiButtonEntryItemEventArgs> _itemLongPressed;
46         SmartEvent<MultiButtonEntryItemEventArgs> _itemAdded;
47
48         /// <summary>
49         /// Creates and initializes a new instance of the MultiButtonEntry class.
50         /// </summary>
51         /// <param name="parent">The parent is a given container which will be attached by MultiButtonEntry as a child. It's <see cref="EvasObject"/> type.</param>
52         public MultiButtonEntry(EvasObject parent) : base(parent)
53         {
54             _clicked = new SmartEvent(this, "clicked");
55             _expanded = new SmartEvent(this, "expanded");
56             _contracted = new SmartEvent(this, "contracted");
57             _expandedStateChanged = new SmartEvent(this, "expand,state,changed");
58
59             _itemSelected = new SmartEvent<MultiButtonEntryItemEventArgs>(this, "item,selected", MultiButtonEntryItemEventArgs.CreateFromSmartEvent);
60             _itemClicked = new SmartEvent<MultiButtonEntryItemEventArgs>(this, "item,clicked", MultiButtonEntryItemEventArgs.CreateFromSmartEvent);
61             _itemLongPressed = new SmartEvent<MultiButtonEntryItemEventArgs>(this, "item,longpressed", MultiButtonEntryItemEventArgs.CreateFromSmartEvent);
62             _itemAdded = new SmartEvent<MultiButtonEntryItemEventArgs>(this, "item,added", MultiButtonEntryItemEventArgs.CreateAndAddFromSmartEvent);
63
64             _filterCallback = new Interop.Elementary.MultiButtonEntryItemFilterCallback(FilterCallbackHandler);
65             _formatCallback = new Interop.Elementary.MultiButtonEntryFormatCallback(FormatCallbackHandler);
66
67             _clicked.On += (sender, e) => Clicked?.Invoke(this, EventArgs.Empty);
68             _expanded.On += (sender, e) => Expanded?.Invoke(this, EventArgs.Empty);
69             _contracted.On += (sender, e) => Contracted?.Invoke(this, EventArgs.Empty);
70             _expandedStateChanged.On += (sender, e) => ExpandedStateChanged?.Invoke(this, EventArgs.Empty);
71
72             _itemSelected.On += (sender, e) => { ItemSelected?.Invoke(this, e); };
73             _itemClicked.On += (sender, e) => { ItemClicked?.Invoke(this, e); };
74             _itemLongPressed.On += (sender, e) => { ItemLongPressed?.Invoke(this, e); };
75             _itemAdded.On += OnItemAdded;
76         }
77
78         /// <summary>
79         /// Clicked is raised when a MultiButtonEntry is clicked.
80         /// </summary>
81         public event EventHandler Clicked;
82
83         /// <summary>
84         /// Expanded is raised when a MultiButtonEntry is expanded.
85         /// </summary>
86         public event EventHandler Expanded;
87
88         /// <summary>
89         /// Contracted is raised when a MultiButtonEntry is contracted.
90         /// </summary>
91         public event EventHandler Contracted;
92
93         /// <summary>
94         /// ExpandedStateChanged is raised when shrink mode state of MultiButtonEntry is changed.
95         /// </summary>
96         public event EventHandler ExpandedStateChanged;
97
98         /// <summary>
99         /// ItemSelected is raised when an item is selected by api, user interaction, and etc.
100         /// This is also raised when a user press back space while cursor is on the first field of entry.
101         /// </summary>
102         public event EventHandler<MultiButtonEntryItemEventArgs> ItemSelected;
103
104         /// <summary>
105         /// ItemClicked is raised when an item is clicked by user interaction.
106         /// </summary>
107         public event EventHandler<MultiButtonEntryItemEventArgs> ItemClicked;
108
109         /// <summary>
110         /// ItemLongPressed is raised when MultiButtonEntry item is pressed for a long time.
111         /// </summary>
112         public event EventHandler<MultiButtonEntryItemEventArgs> ItemLongPressed;
113
114         /// <summary>
115         /// ItemAdded is raised when a new MultiButtonEntry item is added.
116         /// </summary>
117         public event EventHandler<MultiButtonEntryItemEventArgs> ItemAdded;
118
119         /// <summary>
120         /// ItemDeleted is raised when a MultiButtonEntry item is deleted.
121         /// </summary>
122         public event EventHandler<MultiButtonEntryItemEventArgs> ItemDeleted;
123
124         /// <summary>
125         /// Gets the selected item in the multibuttonentry.
126         /// </summary>
127         public MultiButtonEntryItem SelectedItem
128         {
129             get
130             {
131                 IntPtr handle = Interop.Elementary.elm_multibuttonentry_selected_item_get(RealHandle);
132                 return ItemObject.GetItemByHandle(handle) as MultiButtonEntryItem;
133             }
134         }
135
136         /// <summary>
137         /// Gets or sets whether the multibuttonentry is editable or not.
138         /// </summary>
139         public bool IsEditable
140         {
141             get
142             {
143                 return Interop.Elementary.elm_multibuttonentry_editable_get(RealHandle);
144             }
145             set
146             {
147                 Interop.Elementary.elm_multibuttonentry_editable_set(RealHandle, value);
148             }
149         }
150
151         /// <summary>
152         /// Gets or sets the multibuttonentry to expanded state.
153         /// If true, expanded state.
154         /// If false, single line state.
155         /// </summary>
156         public bool IsExpanded
157         {
158             get
159             {
160                 return Interop.Elementary.elm_multibuttonentry_expanded_get(RealHandle);
161             }
162             set
163             {
164                 Interop.Elementary.elm_multibuttonentry_expanded_set(RealHandle, value);
165             }
166         }
167
168         /// <summary>
169         /// Gets the first item in the multibuttonentry.
170         /// </summary>
171         public MultiButtonEntryItem FirstItem
172         {
173             get
174             {
175                 IntPtr handle = Interop.Elementary.elm_multibuttonentry_first_item_get(RealHandle);
176                 return ItemObject.GetItemByHandle(handle) as MultiButtonEntryItem;
177             }
178         }
179
180         /// <summary>
181         /// Gets the last item in the multibuttonentry.
182         /// </summary>
183         public MultiButtonEntryItem LastItem
184         {
185             get
186             {
187                 IntPtr handle = Interop.Elementary.elm_multibuttonentry_last_item_get(RealHandle);
188                 return ItemObject.GetItemByHandle(handle) as MultiButtonEntryItem;
189             }
190         }
191
192         /// <summary>
193         /// Gets the entry object int the multibuttonentry.
194         /// </summary>
195         public Entry Entry
196         {
197             get
198             {
199                 if (_entry == null)
200                 {
201                     _entry = new EntryInner(this);
202                 }
203
204                 return _entry;
205             }
206         }
207
208         protected override IntPtr CreateHandle(EvasObject parent)
209         {
210             return Interop.Elementary.elm_multibuttonentry_add(parent.Handle);
211         }
212
213         /// <summary>
214         /// Append a new item to the multibuttonentry.
215         /// </summary>
216         /// <param name="label">The label of new item.</param>
217         /// <returns>A MultiButtonEntryItem to the item added.</returns>
218         public MultiButtonEntryItem Append(string label)
219         {
220             var handle = Interop.Elementary.elm_multibuttonentry_item_append(RealHandle, label, null, IntPtr.Zero);
221             MultiButtonEntryItem item = ItemObject.GetItemByHandle(handle) as MultiButtonEntryItem;
222             return item;
223         }
224
225         /// <summary>
226         /// Prepend a new item to the multibuttonentry.
227         /// </summary>
228         /// <param name="label">The label of new item.</param>
229         /// <returns>A MultiButtonEntryItem to the item added.</returns>
230         public MultiButtonEntryItem Prepend(string label)
231         {
232             var handle = Interop.Elementary.elm_multibuttonentry_item_prepend(RealHandle, label, null, IntPtr.Zero);
233             MultiButtonEntryItem item = ItemObject.GetItemByHandle(handle) as MultiButtonEntryItem;
234             return item;
235         }
236
237         /// <summary>
238         /// Add a new item to the multibuttonentry before the indicated object reference.
239         /// </summary>
240         /// <param name="before">The item before which to add it.</param>
241         /// <param name="label">The label of new item.</param>
242         /// <returns>A MultiButtonEntryItem to the item added.</returns>
243         public MultiButtonEntryItem InsertBefore(MultiButtonEntryItem before, string label)
244         {
245             var handle = Interop.Elementary.elm_multibuttonentry_item_insert_before(RealHandle, before.Handle, label, null, IntPtr.Zero);
246             MultiButtonEntryItem item = ItemObject.GetItemByHandle(handle) as MultiButtonEntryItem;
247             return item;
248         }
249
250         /// <summary>
251         /// Add a new item to the multibuttonentry after the indicated object.
252         /// </summary>
253         /// <param name="after">The item after which to add it.</param>
254         /// <param name="label">The label of new item.</param>
255         /// <returns>A MultiButtonEntryItem to the item added.</returns>
256         public MultiButtonEntryItem InsertAfter(MultiButtonEntryItem after, string label)
257         {
258             var handle = Interop.Elementary.elm_multibuttonentry_item_insert_after(RealHandle, after.Handle, label, null, IntPtr.Zero);
259             MultiButtonEntryItem item = ItemObject.GetItemByHandle(handle) as MultiButtonEntryItem;
260             return item;
261         }
262
263         /// <summary>
264         /// Remove all items in the multibuttonentry.
265         /// </summary>
266         public void Clear()
267         {
268             Interop.Elementary.elm_multibuttonentry_clear(RealHandle);
269             foreach (var item in _children)
270             {
271                 item.Deleted -= Item_Deleted;
272             }
273             _children.Clear();
274         }
275
276         /// <summary>
277         /// Append an item filter function for text inserted in the Multibuttonentry.
278         /// </summary>
279         /// <param name="func">The function to use as item filter.</param>
280         public void AppendFilter(Func<string, bool> func)
281         {
282             _filters.Add(func);
283             if (_filters.Count == 1)
284             {
285                 Interop.Elementary.elm_multibuttonentry_item_filter_append(RealHandle, _filterCallback, IntPtr.Zero);
286             }
287         }
288
289         /// <summary>
290         /// Prepend a filter function for text inserted in the Multibuttonentry.
291         /// </summary>
292         /// <param name="func">The function to use as text filter.</param>
293         public void PrependFilter(Func<string, bool> func)
294         {
295             _filters.Insert(0, func);
296             if (_filters.Count == 1)
297             {
298                 Interop.Elementary.elm_multibuttonentry_item_filter_prepend(RealHandle, _filterCallback, IntPtr.Zero);
299             }
300         }
301
302         /// <summary>
303         /// Remove a filter from the list.
304         /// </summary>
305         /// <param name="func">The filter function to remove.</param>
306         public void RemoveFilter(Func<string, bool> func)
307         {
308             _filters.Remove(func);
309             if (_filters.Count == 0)
310             {
311                 Interop.Elementary.elm_multibuttonentry_item_filter_remove(RealHandle, _filterCallback, IntPtr.Zero);
312             }
313         }
314
315         /// <summary>
316         /// Set a function to format the string that will be used to display the hidden items counter.
317         /// If func is NULL, the default format will be used, which is "+ 'the hidden items counter'".
318         /// </summary>
319         /// <param name="func">The function to return string to show</param>
320         public void SetFormatCallback(Func<int, string> func)
321         {
322             if (func == null)
323             {
324                 Interop.Elementary.elm_multibuttonentry_format_function_set(RealHandle, null, IntPtr.Zero);
325             }
326             else
327             {
328                 _formatFunc = func;
329                 Interop.Elementary.elm_multibuttonentry_format_function_set(RealHandle, _formatCallback, IntPtr.Zero);
330             }
331         }
332
333         string FormatCallbackHandler(int count, IntPtr data)
334         {
335             return _formatFunc(count);
336         }
337
338         void Item_Deleted(object sender, EventArgs e)
339         {
340             var removed = sender as MultiButtonEntryItem;
341             _children.Remove(removed);
342
343             // "item,deleted" event will be called after removing the item from ItemObject has been done.
344             // ItemObject will no longer have the item instance that is deleted after this.
345             // So, ItemDelete event with the removed item should be triggered here.
346             ItemDeleted?.Invoke(this, new MultiButtonEntryItemEventArgs() { Item = removed });
347         }
348
349         void OnItemAdded(object sender, MultiButtonEntryItemEventArgs e)
350         {
351             _children.Add(e.Item);
352             e.Item.Deleted += Item_Deleted;
353             ItemAdded?.Invoke(this, e);
354         }
355
356         bool FilterCallbackHandler(IntPtr obj, string label, IntPtr itemData, IntPtr data)
357         {
358             foreach (var func in _filters)
359             {
360                 if (!func(label))
361                     return false;
362             }
363             return true;
364         }
365
366         internal class EntryInner : Entry
367         {
368             internal EntryInner(EvasObject parent) : base(parent)
369             {
370             }
371
372             protected override IntPtr CreateHandle(EvasObject parent)
373             {
374                 return Interop.Elementary.elm_multibuttonentry_entry_get(parent.Handle);
375             }
376         }
377     }
378
379     /// <summary>
380     /// It inherits System.EventArgs.
381     /// The MultiButtonEntryItemEventArgs is a argument for all events of MultiButtonEntry.
382     /// It contains Item which is <see cref="MultiButtonEntryItem"/> type.
383     /// </summary>
384     public class MultiButtonEntryItemEventArgs : EventArgs
385     {
386         /// <summary>
387         /// Gets or sets MultiButtonEntryItem item. The return type is <see cref="MultiButtonEntryItem"/>.
388         /// </summary>
389         public MultiButtonEntryItem Item { get; set; }
390
391         internal static MultiButtonEntryItemEventArgs CreateFromSmartEvent(IntPtr data, IntPtr obj, IntPtr info)
392         {
393             MultiButtonEntryItem item = ItemObject.GetItemByHandle(info) as MultiButtonEntryItem;
394             return new MultiButtonEntryItemEventArgs() { Item = item };
395         }
396
397         internal static MultiButtonEntryItemEventArgs CreateAndAddFromSmartEvent(IntPtr data, IntPtr obj, IntPtr info)
398         {
399             // Item can be added throught calling Append method and user input.
400             // And since "item.added" event will be called before xx_append() method returns,
401             // ItemObject does NOT have an item that contains handle matched to "info" at this time.
402             // So, item should be created and added internally here.
403             MultiButtonEntryItem item = new MultiButtonEntryItem(info);
404             return new MultiButtonEntryItemEventArgs() { Item = item };
405         }
406     }
407 }