using System; using System.Collections.Generic; using System.Drawing; using System.Globalization; using System.Windows; using System.Windows.Controls; using System.Windows.Media; using InABox.Core; using FontStyle = System.Windows.FontStyle; using Image = System.Windows.Controls.Image; namespace InABox.WPF { public static class WPFUtils { public static T? FindLogicalParent(this DependencyObject dependencyObject) where T : DependencyObject { DependencyObject? parent = dependencyObject; do { parent = LogicalTreeHelper.GetParent(parent); } while(parent != null && parent is not T); return parent as T; } public static int GetRow(this Grid grid, DependencyObject dependencyObject) { while (true) { var parent = LogicalTreeHelper.GetParent(dependencyObject); if (parent == null) return -1; if (parent == grid) return Grid.GetRow(dependencyObject as UIElement); dependencyObject = parent; } } public static int GetRowSpan(this Grid grid, DependencyObject dependencyObject) { while (true) { var parent = LogicalTreeHelper.GetParent(dependencyObject); if (parent == null) return -1; if (parent == grid) return Grid.GetRowSpan(dependencyObject as UIElement); dependencyObject = parent; } } public static int GetColumn(this Grid grid, DependencyObject dependencyObject) { while (true) { var parent = LogicalTreeHelper.GetParent(dependencyObject); if (parent == null) return -1; if (parent == grid) return Grid.GetColumn(dependencyObject as UIElement); dependencyObject = parent; } } public static int GetColumnSpan(this Grid grid, DependencyObject dependencyObject) { while (true) { var parent = LogicalTreeHelper.GetParent(dependencyObject); if (parent == null) return -1; if (parent == grid) return Grid.GetColumnSpan(dependencyObject as UIElement); dependencyObject = parent; } } public static void SetGridPosition(this FrameworkElement element, int row, int column, int rowspan = 1, int colspan = 1) { element.SetValue(Grid.ColumnProperty, column); element.SetValue(Grid.ColumnSpanProperty, Math.Max(1, colspan)); element.SetValue(Grid.RowProperty, row); element.SetValue(Grid.RowSpanProperty, Math.Max(1, rowspan)); } public static IEnumerable FindVisualChildren(this DependencyObject depObj) { if (depObj != null) //ContentControl cc = depObj as ContentControl; //if (cc != null) //{ // if (cc.Content == null) // yield return null; // if (cc.Content is T) // yield return cc.Content as T; // foreach (var child in FindVisualChildren(cc.Content as DependencyObject)) // yield return child; //} //else for (var i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++) { var child = VisualTreeHelper.GetChild(depObj, i); if (child is null) continue; if (child is T t) yield return t; foreach (var childOfChild in FindVisualChildren(child)) yield return childOfChild; } } #region Menu Utils private static void ItemsControlInsert(ItemsControl menu, FrameworkElement item, int index) { if (index != -1) { menu.Items.Insert(index, item); } else { menu.Items.Add(item); } } private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, bool enabled, int index = -1) { var item = new MenuItem { Header = caption, IsEnabled = enabled }; if (image != null) item.Icon = new Image() { Source = enabled ? image.AsBitmapImage(24, 24) : image.AsGrayScale().AsBitmapImage(24, 24) }; ItemsControlInsert(menu, item, index); return item; } private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, Action? click, bool enabled, int index = -1) { var item = DoAddMenuItem(menu, caption, image, enabled, index); if (click != null) { item.Click += (o, e) => { click(); }; } return item; } private static MenuItem DoAddMenuItem(ItemsControl menu, string caption, Bitmap? image, T tag, Action click, bool enabled, int index = -1) { var item = DoAddMenuItem(menu, caption, image, enabled, index); item.Tag = tag; item.Click += (o, e) => { click((T)(o as MenuItem)!.Tag); }; return item; } public delegate void CheckToggleAction(bool isChecked); public delegate void CheckToggleAction(T tag, bool isChecked); private static MenuItem DoAddCheckItem(ItemsControl menu, string caption, CheckToggleAction click, bool isChecked, bool enabled, int index = -1) { var item = new MenuItem { Header = caption, IsEnabled = enabled, IsCheckable = true, IsChecked = isChecked }; item.Click += (o, e) => { click(item.IsChecked); }; ItemsControlInsert(menu, item, index); return item; } private static MenuItem DoAddCheckItem(ItemsControl menu, string caption, T tag, CheckToggleAction click, bool isChecked, bool enabled, int index = -1) { var item = new MenuItem { Header = caption, IsEnabled = enabled, IsCheckable = true, IsChecked = isChecked }; item.Tag = tag; item.Click += (o, e) => { click((T)(o as MenuItem)!.Tag, item.IsChecked); }; ItemsControlInsert(menu, item, index); return item; } private static Separator DoAddSeparator(ItemsControl menu, int index) { var separator = new Separator(); ItemsControlInsert(menu, separator, index); return separator; } private static Separator? DoAddSeparatorIfNeeded(ItemsControl menu, int index) { if (menu.Items.Count == 0) return null; var lastIndex = index != -1 ? index - 1 : menu.Items.Count - 1; if (lastIndex < 0 || lastIndex >= menu.Items.Count) return null; var last = menu.Items[lastIndex]; if (last is Separator) return null; var separator = new Separator(); ItemsControlInsert(menu, separator, index); return separator; } private static void DoRemoveUnnecessarySeparators(ItemsControl menu) { while(menu.Items.Count > 0 && menu.Items[0] is Separator) { menu.Items.RemoveAt(0); } while(menu.Items.Count > 0 && menu.Items[^1] is Separator) { menu.Items.RemoveAt(menu.Items.Count - 1); } } public static Separator AddSeparator(this ContextMenu menu, int index = -1) => DoAddSeparator(menu, index); public static Separator AddSeparator(this MenuItem menu, int index = -1) => DoAddSeparator(menu, index); public static Separator? AddSeparatorIfNeeded(this ContextMenu menu, int index = -1) => DoAddSeparatorIfNeeded(menu, index); public static Separator? AddSeparatorIfNeeded(this MenuItem menu, int index = -1) => DoAddSeparatorIfNeeded(menu, index); public static void RemoveUnnecessarySeparators(this ContextMenu menu) => DoRemoveUnnecessarySeparators(menu); public static void RemoveUnnecessarySeparators(this MenuItem menu) => DoRemoveUnnecessarySeparators(menu); public static MenuItem AddItem(this ContextMenu menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1) => DoAddMenuItem(menu, caption, image, click, enabled, index); public static MenuItem AddItem(this MenuItem menu, string caption, Bitmap? image, Action? click, bool enabled = true, int index = -1) => DoAddMenuItem(menu, caption, image, click, enabled, index); public static MenuItem AddItem(this ContextMenu menu, string caption, Bitmap? image, T tag, Action click, bool enabled = true, int index = -1) => DoAddMenuItem(menu, caption, image, tag, click, enabled, index); public static MenuItem AddItem(this MenuItem menu, string caption, Bitmap? image, T tag, Action click, bool enabled = true, int index = -1) => DoAddMenuItem(menu, caption, image, tag, click, enabled, index); public static MenuItem AddCheckItem(this ContextMenu menu, string caption, CheckToggleAction click, bool isChecked = false, bool enabled = true, int index = -1) => DoAddCheckItem(menu, caption, click, isChecked, enabled, index); public static MenuItem AddCheckItem(this ContextMenu menu, string caption, T tag, CheckToggleAction click, bool isChecked = false, bool enabled = true, int index = -1) => DoAddCheckItem(menu, caption, tag, click, isChecked, enabled, index); #endregion } }