2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Collections.ObjectModel;
5 using System.Collections.Specialized;
9 namespace Tizen.Xamarin.Forms.Extension
12 /// The ContextPopup class allows a contextual popup to be anchored at a view.
16 /// ContextPopup popup = new ContextPopup
18 /// DirectionPriorities = new ContextPopupDirectionPriorities(ContextPopupDirection.Down, ContextPopupDirection.Right, ContextPopupDirection.Left, ContextPopupDirection.Up),
20 /// popup.Items.Add(new ContextPopupItem("Text only item"));
21 /// popup.Items.Add(new ContextPopupItem("Home icon", "home"));
22 /// popup.Items.Add(new ContextPopupItem("Chat", StandardIconResource.MenuChat.Name));
23 /// popup.SelectedIndexChanged += (s, e) =>
25 /// var ctxPopup = s as ContextPopup;
26 /// Debug.WriteLine("Item with index {0} selected", ctxPopup.SelectedIndex);
27 /// Debug.WriteLine("It has label: " + (ctxPopup.SelectedItem as ContextPopupItem).Label);
30 /// Button btn = new Button
32 /// Text = "Toggle popup"
34 /// btn.Clicked += (s, e) =>
36 /// popup.Show(s as Button);
40 public class ContextPopup : BindableObject
42 IContextPopup _contextPopup;
44 ObservableCollection<ContextPopupItem> _items;
46 static ContextPopupDirectionPriorities _priorities =
47 new ContextPopupDirectionPriorities(ContextPopupDirection.Up, ContextPopupDirection.Left, ContextPopupDirection.Right, ContextPopupDirection.Down);
49 [Obsolete("OrientationProperty is obsolete as of version 2.3.5-r256-001. The orientation is always vertical.")]
50 public static readonly BindableProperty OrientationProperty = BindableProperty.Create(nameof(Orientation), typeof(ContextPopupOrientation), typeof(ContextPopup),
51 defaultValue: ContextPopupOrientation.Vertical);
54 /// BindableProperty. Identifies the IsAutoHidingEnabled bindable property.
56 public static readonly BindableProperty IsAutoHidingEnabledProperty = BindableProperty.Create(nameof(IsAutoHidingEnabled), typeof(bool), typeof(ContextPopup), defaultValue: true);
59 /// BindableProperty. Identifies the DirectionPriorities bindable property.
61 public static readonly BindableProperty DirectionPrioritiesProperty = BindableProperty.Create(nameof(DirectionPriorities), typeof(ContextPopupDirectionPriorities),
62 typeof(ContextPopup), defaultValue: _priorities);
65 /// BindableProperty. Identifies the SelectedIndex bindable property.
67 public static readonly BindableProperty SelectedIndexProperty = BindableProperty.Create(nameof(SelectedIndex), typeof(int), typeof(ContextPopup), defaultValue: -1,
68 propertyChanged: OnSelectedIndexChanged, coerceValue: CoerceSelectedIndex);
71 /// BindableProperty. Identifies the SelectedItem bindable property.
73 public static readonly BindableProperty SelectedItemProperty = BindableProperty.Create(nameof(SelectedItem), typeof(object), typeof(ContextPopup), null,
74 propertyChanged: OnSelectedItemChanged);
76 [Obsolete("ItemsSourceProperty is obsolete as of version 2.3.5-r256-001. Please use Items instead.")]
77 public static readonly BindableProperty ItemsSourceProperty = BindableProperty.Create(nameof(ItemsSource), typeof(IList), typeof(ContextPopup), default(IList));
80 /// The constructor, which creates a new ContextPopup instance.
84 _contextPopup = DependencyService.Get<IContextPopup>(DependencyFetchTarget.NewInstance);
86 _contextPopup.Dismissed += (s, e) => Dismissed?.Invoke(this, EventArgs.Empty);
87 _contextPopup.ItemSelected += (s, e) => ItemSelected?.Invoke(this, EventArgs.Empty);
89 _items = new ObservableCollection<ContextPopupItem>();
90 _items.CollectionChanged += ItemsCollectionChanged;
92 SetBinding(IsAutoHidingEnabledProperty, new Binding(nameof(IsAutoHidingEnabled), mode: BindingMode.TwoWay, source: _contextPopup));
93 SetBinding(DirectionPrioritiesProperty, new Binding(nameof(DirectionPriorities), mode: BindingMode.TwoWay, source: _contextPopup));
94 SetBinding(SelectedItemProperty, new Binding(nameof(SelectedItem), mode: BindingMode.TwoWay, source: _contextPopup));
98 /// Occurs when the ContextPopup is dismissed.
100 public event EventHandler Dismissed;
103 /// Occurs when the index of the selected ContextPopupItem changes.
105 public event EventHandler SelectedIndexChanged;
108 /// Occurs when a ContextPopupItem is selected.
110 public event EventHandler ItemSelected;
112 [Obsolete("Orientation is obsolete as of version 2.3.5-r256-001. The orientation is always vertical.")]
113 public ContextPopupOrientation Orientation
115 get { return (ContextPopupOrientation)GetValue(OrientationProperty); }
116 set { SetValue(OrientationProperty, value); }
120 /// Gets or sets whether ContextPopup should be hidden automatically or not when parent of ContextPopup is resized.
123 /// Setting IsAutoHidingEnabled to false will not be dismissed automatically whenever such as mouse clicked its background area, language i s changed, and its parent geometry is updated(changed).
125 public bool IsAutoHidingEnabled
127 get { return (bool)GetValue(IsAutoHidingEnabledProperty); }
128 set { SetValue(IsAutoHidingEnabledProperty, value); }
132 /// Gets or sets the direction priorities for the ContextPopup.<br>
133 /// The position of the ContextPopup depends on the available space.
134 /// Therefore, DirectionPriorities are used to specify desired first, second, third, and fourth priorities for positioning the ContextPopup.
136 public ContextPopupDirectionPriorities DirectionPriorities
138 get { return (ContextPopupDirectionPriorities)GetValue(DirectionPrioritiesProperty); }
139 set { SetValue(DirectionPrioritiesProperty, value); }
143 /// Gets or sets the index of the selected item of the ContextPopup.
144 /// It is -1 when no item is selected.
146 public int SelectedIndex
148 get { return (int)GetValue(SelectedIndexProperty); }
149 set { SetValue(SelectedIndexProperty, value); }
153 /// Gets or sets the selected item of the ContextPopup.
155 public ContextPopupItem SelectedItem
157 get { return (ContextPopupItem)GetValue(SelectedItemProperty); }
158 set { SetValue(SelectedItemProperty, value); }
161 [Obsolete("ItemsSource is obsolete as of version 2.3.5-r256-001. Please use Items instead.")]
162 public IList ItemsSource
164 get { return (IList)GetValue(ItemsSourceProperty); }
165 set { SetValue(ItemsSourceProperty, value); }
169 /// Gets the list of items in the ContextPopup.
171 public IList<ContextPopupItem> Items
180 /// Shows the ContextPopup. The ContextPopup is positioned at the horizontal and the vertical position of a specific anchor.
182 /// <param name="anchor">The view to which the popup should be anchored.</param>
183 public void Show(View anchor)
189 /// Shows the ContextPopup. The ContextPopup is positioned at the horizontal and the vertical position of a specific anchor with offsets.
191 /// <param name="anchor">The view to which the popup should be anchored.</param>
192 /// <param name="xOffset">The horizontal offset from the anchor.</param>
193 /// <param name="yOffset">The vertical offset from the anchor.</param>
194 public void Show(View anchor, int xOffset, int yOffset)
196 _contextPopup.Show(anchor, xOffset, yOffset);
200 /// Shows the ContextPopup. The ContextPopup is positioned at the horizontal and the vertical position of a specific anchor with offsets.
202 /// <param name="anchor">The view to which the popup should be anchored.</param>
203 /// <param name="xOffset">The horizontal offset from the anchor.</param>
204 /// <param name="yOffset">The vertical offset from the anchor.</param>
205 public void Show(View anchor, double xOffset, double yOffset)
207 Show(anchor, (int)xOffset, (int)yOffset);
211 /// Dismisses the ContextPopup.
213 public void Dismiss()
215 _contextPopup.Dismiss();
219 /// Gets the direction of the ContextPopup if it is shown.
220 /// This method returns false if it is not shown and the output argument is a default value.
222 /// <param name="direction">The direction of the ContextPopup.</param>
223 /// <returns>true if the ContextPopup is shown, false otherwise.</returns>
224 public bool TryGetContextPopupDirection(out ContextPopupDirection direction)
226 direction = default(ContextPopupDirection);
227 return _contextPopup.TryGetContextPopupDirection(out direction);
230 void ItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
234 case NotifyCollectionChangedAction.Add:
238 case NotifyCollectionChangedAction.Remove:
242 default: // Move, replace, reset
247 SelectedIndex = SelectedIndex.Clamp(-1, Items.Count - 1);
248 UpdateSelectedItem();
253 _contextPopup.ClearItems();
256 void RemoveItems(NotifyCollectionChangedEventArgs e)
258 _contextPopup.RemoveItems(e.OldItems.OfType<ContextPopupItem>());
261 void AddItems(NotifyCollectionChangedEventArgs e)
263 _contextPopup.AddItems(e.NewItems.OfType<ContextPopupItem>());
266 static void OnSelectedIndexChanged(BindableObject bindable, object oldValue, object newValue)
268 var contextPopup = (ContextPopup)bindable;
269 contextPopup.UpdateSelectedItem();
270 contextPopup.SelectedIndexChanged?.Invoke(contextPopup, EventArgs.Empty);
273 static object CoerceSelectedIndex(BindableObject bindable, object value)
275 var contextPopup = (ContextPopup)bindable;
276 return contextPopup.Items == null ? -1 : ((int)value).Clamp(-1, contextPopup.Items.Count - 1);
279 void UpdateSelectedItem()
281 if (SelectedIndex == -1)
287 SelectedItem = Items[SelectedIndex];
290 static void OnSelectedItemChanged(BindableObject bindable, object oldValue, object newValue)
292 var contextPopup = (ContextPopup)bindable;
293 contextPopup.UpdateSelectedIndex(newValue);
296 void UpdateSelectedIndex(object selectedItem)
298 SelectedIndex = Items.IndexOf(selectedItem as ContextPopupItem);
302 internal static class NumericExtensions
304 public static int Clamp(this int self, int min, int max)
306 return Math.Min(max, Math.Max(self, min));