diff options
author | Dominique Louis <savagesoftware@gmail.com> | 2018-07-10 17:57:50 +0300 |
---|---|---|
committer | Dominique Louis <savagesoftware@gmail.com> | 2018-09-03 20:40:45 +0300 |
commit | 8c91aaf515db6d64e422ec466b13599ee9c87706 (patch) | |
tree | 74b0ed5c0a8fd3065e2d4856a9c56f1e4f7e0950 | |
parent | 017c948e29a0be922186a72b80a377d2f6370cf0 (diff) |
[Mac] Initial Request Resource Implementation.
14 files changed, 742 insertions, 18 deletions
diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePopOverControl.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePopOverControl.cs index e6aa30c..e519d21 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePopOverControl.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/BasePopOverControl.cs @@ -20,6 +20,7 @@ namespace Xamarin.PropertyEditing.Mac var iconView = new NSImageView { Image = PropertyEditorPanel.ThemeManager.GetImageForTheme (imageNamed), + ImageScaling = NSImageScale.None, TranslatesAutoresizingMaskIntoConstraints = false, }; diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs index 77a2cb3..6c69c56 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/PropertyButton.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.ComponentModel; using AppKit; using CoreGraphics; using Xamarin.PropertyEditing.Mac.Resources; @@ -38,7 +40,6 @@ namespace Xamarin.PropertyEditing.Mac Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("property-button-default-mac-10"); ImageScaling = NSImageScale.None; ToolTip = Properties.Resources.Default; - TranslatesAutoresizingMaskIntoConstraints = false; OnMouseEntered += (sender, e) => { ToggleFocusImage (true); @@ -62,7 +63,7 @@ namespace Xamarin.PropertyEditing.Mac var mi = new NSMenuItem (Properties.Resources.CustomExpressionEllipsis) { AttributedTitle = new Foundation.NSAttributedString ( Properties.Resources.CustomExpressionEllipsis, - new CoreText.CTStringAttributes () { + new CoreText.CTStringAttributes { Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1), }) }; @@ -73,11 +74,28 @@ namespace Xamarin.PropertyEditing.Mac this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem); } + if (this.viewModel.SupportsResources) { + this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem); + + var mi2 = new NSMenuItem (Properties.Resources.ResourceEllipsis) { + AttributedTitle = new Foundation.NSAttributedString ( + Properties.Resources.ResourceEllipsis, + new CoreText.CTStringAttributes { + Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1), + }) + }; + + mi2.Activated += OnResourceRequested; + this.popUpContextMenu.AddItem (mi2); + } + + this.popUpContextMenu.AddItem (NSMenuItem.SeparatorItem); + // TODO If we add more menu items consider making the Label/Command a dictionary that we can iterate over to populate everything. this.popUpContextMenu.AddItem (new CommandMenuItem (Properties.Resources.Reset, viewModel.ClearValueCommand) { AttributedTitle = new Foundation.NSAttributedString ( Properties.Resources.Reset, - new CoreText.CTStringAttributes () { + new CoreText.CTStringAttributes { Font = new CoreText.CTFont (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize + 1), }) }); @@ -187,5 +205,18 @@ namespace Xamarin.PropertyEditing.Mac customExpressionPopOver.Show (customExpressionView.Frame, (NSView)this, NSRectEdge.MinYEdge); } + + private void OnResourceRequested (object sender, EventArgs e) + { + var requestResourceView = new RequestResourceView (this.viewModel); + + var resourceSelectorPopOver = new AutoClosePopOver { + ContentViewController = new NSViewController (null, null) { View = requestResourceView }, + }; + + requestResourceView.PopOver = resourceSelectorPopOver; + + resourceSelectorPopOver.Show (requestResourceView.Frame, (NSView)this, NSRectEdge.MinYEdge); + } } } diff --git a/Xamarin.PropertyEditing.Mac/Controls/Custom/UnfocusableTextField.cs b/Xamarin.PropertyEditing.Mac/Controls/Custom/UnfocusableTextField.cs index efce5be..dd07863 100644 --- a/Xamarin.PropertyEditing.Mac/Controls/Custom/UnfocusableTextField.cs +++ b/Xamarin.PropertyEditing.Mac/Controls/Custom/UnfocusableTextField.cs @@ -21,14 +21,14 @@ namespace Xamarin.PropertyEditing.Mac void SetDefaultProperties () { + AccessibilityElement = false; Bordered = false; - Editable = false; - Selectable = false; - ControlSize = NSControlSize.Small; - Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultPropertyLabelFontSize); Cell.LineBreakMode = NSLineBreakMode.TruncatingTail; Cell.UsesSingleLineMode = true; - AccessibilityElement = false; + ControlSize = NSControlSize.Small; + Editable = false; + Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultPropertyLabelFontSize); + Selectable = false; } public override void DrawRect (CGRect dirtyRect) diff --git a/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourcePanel.cs b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourcePanel.cs new file mode 100644 index 0000000..394dec8 --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourcePanel.cs @@ -0,0 +1,147 @@ +using System; +using System.ComponentModel; +using AppKit; +using CoreGraphics; +using Xamarin.PropertyEditing.Drawing; +using Xamarin.PropertyEditing.Mac.Resources; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class RequestResourcePanel : NSView + { + internal const string ResourceImageColId = "ResourceImage"; + internal const string ResourceTypeColId = "ResourceType"; + internal const string ResourceNameColId = "ResourceName"; + internal const string ResourceValueColId = "ResourceValue"; + + private NSTableView resourceTable; + private ResourceTableDataSource dataSource; + + private ResourceSelectorViewModel viewModel; + public ResourceSelectorViewModel ViewModel => this.viewModel; + private SimpleCollectionView collectionView => this.viewModel.Resources as SimpleCollectionView; + public Resource SelectedResource { + get { + return (this.resourceTable.SelectedRow != -1) ? this.collectionView [((int)this.resourceTable.SelectedRow)] as Resource : null; + } + } + + NSProgressIndicator progressIndicator; + + NSScrollView tableContainer; + + RequestResourcePreviewPanel previewPanel; + + public event EventHandler ResourceSelected; + public event EventHandler DoubleClicked; + + private object selectedValue; + + public RequestResourcePanel (ResourceSelectorViewModel viewModel, object value) + { + this.viewModel = viewModel; + this.viewModel.PropertyChanged += OnPropertyChanged; + Initialize (value); + } + + private void OnPropertyChanged (object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof (this.viewModel.IsLoading)) { + this.progressIndicator.Hidden = !this.viewModel.IsLoading; + this.tableContainer.Hidden = !this.progressIndicator.Hidden; + if (this.viewModel.IsLoading) { + this.progressIndicator.StartAnimation (null); + } else { + this.progressIndicator.StopAnimation (null); + } + } + } + + private void Initialize (object selectedValue) + { + this.selectedValue = selectedValue; + Frame = new CGRect (10, 35, 630, 305); + + var FrameHeightHalf = (Frame.Height - 32) / 2; + var FrameWidthHalf = (Frame.Width - 32) / 2; + var FrameWidthThird = (Frame.Width - 32) / 3; + + this.progressIndicator = new NSProgressIndicator (new CGRect (FrameWidthThird, FrameHeightHalf, 32, 32)) { + Hidden = true, + Style = NSProgressIndicatorStyle.Spinning, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + AddSubview (this.progressIndicator); + + this.resourceTable = new FirstResponderTableView { + AutoresizingMask = NSViewResizingMask.WidthSizable, + HeaderView = null, + }; + + this.dataSource = new ResourceTableDataSource (viewModel); + var resourceTableDelegate = new ResourceTableDelegate (dataSource); + resourceTableDelegate.ResourceSelected += (sender, e) => { + this.previewPanel.SelectedResource = SelectedResource; + + this.selectedValue = BrushPropertyViewModel.GetCommonBrushForResource (SelectedResource); + + ResourceSelected?.Invoke (this, EventArgs.Empty); + }; + this.resourceTable.Delegate = resourceTableDelegate; + this.resourceTable.DataSource = dataSource; + + NSTableColumn resourceImages = new NSTableColumn (ResourceImageColId) { Title = LocalizationResources.ResourceTableImageColumnTitle, Width = 32 }; + this.resourceTable.AddColumn (resourceImages); + + NSTableColumn resourceTypes = new NSTableColumn (ResourceTypeColId) { Title = LocalizationResources.ResourceTableTypeColumnTitle, Width = 150 }; + this.resourceTable.AddColumn (resourceTypes); + + NSTableColumn resourceName = new NSTableColumn (ResourceNameColId) { Title = LocalizationResources.ResourceTableNameColumnTitle, Width = 150 }; + resourceTable.AddColumn (resourceName); + + NSTableColumn resourceValue = new NSTableColumn (ResourceValueColId) { Title = LocalizationResources.ResourceTableValueColumnTitle, Width = 45 }; + this.resourceTable.AddColumn (resourceValue); + + this.resourceTable.DoubleClick += (object sender, EventArgs e) => { + DoubleClicked?.Invoke (this, EventArgs.Empty); + }; + + // create a table view and a scroll view + this.tableContainer = new NSScrollView (new CGRect (0, 0, resourceTable.TableColumns ()[0].Width + resourceTable.TableColumns ()[1].Width + resourceTable.TableColumns ()[2].Width + 10, Frame.Height)) { + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.tableContainer.DocumentView = resourceTable; + AddSubview (this.tableContainer); + + this.previewPanel = new RequestResourcePreviewPanel (new CGRect (Frame.Width - FrameWidthThird, 0, FrameWidthThird, Frame.Height)); + AddSubview (this.previewPanel); + + this.DoConstraints (new NSLayoutConstraint[] { + this.tableContainer.ConstraintTo (this, (t, c) => t.Width == c.Width - 190), + this.tableContainer.ConstraintTo (this, (t, c) => t.Height == c.Height), + }); + + ReloadData (); + } + + internal void ReloadData () + { + this.resourceTable.ReloadData (); + + if (collectionView.Count > 0 && this.selectedValue != null) { + for (int i = 0; i < collectionView.Count; i++) { + var element = collectionView[i] as Resource; + var eType = element.GetType (); + var valuePropertyInfo = eType.GetProperty ("Value"); + var elementValue = valuePropertyInfo.GetValue (element); + if (elementValue == this.selectedValue) { + this.resourceTable.SelectRow (i, false); + break; + } + } + } + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourcePreviewPanel.cs b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourcePreviewPanel.cs new file mode 100644 index 0000000..8e46150 --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourcePreviewPanel.cs @@ -0,0 +1,133 @@ +using System; +using System.Collections.Generic; +using AppKit; +using CoreGraphics; +using Xamarin.PropertyEditing.Drawing; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class RequestResourcePreviewPanel : NSView + { + private NSTextField noPreviewAvailable; + private NSView previewView; + + private Resource selectedResource; + public Resource SelectedResource + { + internal get + { + return selectedResource; + } + + set + { + if (selectedResource != value) { + selectedResource = value; + + if (selectedResource != null) { + // Let's find the next View + var pView = GetPreviewView (selectedResource); + + if (pView == null) { + ShowNoPreviewText (); + } else { + noPreviewAvailable.Hidden = true; + previewView.Hidden = false; + + switch (selectedResource) { + case Resource<CommonColor> colour: + if (pView is CommonBrushView cc) { + cc.Brush = new CommonSolidBrush (colour.Value); + } + break; + + case Resource<CommonGradientBrush> gradient: + if (pView is CommonBrushView vg) { + vg.Brush = gradient.Value; + } + break; + + case Resource<CommonSolidBrush> solid: + if (pView is CommonBrushView vs) { + vs.Brush = solid.Value; + } + break; + } + + // Only 1 subview allowed (must be a better way to handle this??) + if (previewView.Subviews.Count () > 0) { + previewView.Subviews[0].RemoveFromSuperview (); + } + // Free up anything from the previous view + previewView.AddSubview (pView); + } + } else { + ShowNoPreviewText (); + } + } + } + } + + private void ShowNoPreviewText () + { + noPreviewAvailable.Hidden = false; + previewView.Hidden = true; + } + + public RequestResourcePreviewPanel (CGRect frame) : base (frame) + { + var FrameHeightHalf = (Frame.Height - 32) / 2; + var FrameWidthHalf = (Frame.Width - 32) / 2; + var FrameWidthThird = (Frame.Width - 32) / 3; + + noPreviewAvailable = new UnfocusableTextField { + BackgroundColor = NSColor.Clear, + StringValue = Properties.Resources.NoPreviewAvailable, + Frame = new CGRect (50, FrameHeightHalf, 150, 50), + }; + + AddSubview (noPreviewAvailable); + + previewView = new NSView (new CGRect (20, 0, frame.Width - 30, frame.Height)); + previewView.Hidden = true; // Hidden until a resource is selected and a preview is available for it. + AddSubview (previewView); + } + + NSView GetPreviewView (Resource resource) + { + Type[] genericArgs = null; + Type previewRenderType; + if (!PreviewValueTypes.TryGetValue (resource.RepresentationType, out previewRenderType)) { + if (resource.RepresentationType.IsConstructedGenericType) { + genericArgs = resource.RepresentationType.GetGenericArguments (); + var type = resource.RepresentationType.GetGenericTypeDefinition (); + PreviewValueTypes.TryGetValue (type, out previewRenderType); + } + } + if (previewRenderType == null) + return null; + + if (previewRenderType.IsGenericTypeDefinition) { + if (genericArgs == null) + genericArgs = resource.RepresentationType.GetGenericArguments (); + previewRenderType = previewRenderType.MakeGenericType (genericArgs); + } + + return SetUpPreviewer (previewRenderType); + } + + private NSView SetUpPreviewer (Type previewRenderType) + { + var view = (NSView)Activator.CreateInstance (previewRenderType); + view.Identifier = previewRenderType.Name; + view.Frame = new CGRect (0, 0, previewView.Frame.Width, previewView.Frame.Height); + + return view; + } + + internal static readonly Dictionary<Type, Type> PreviewValueTypes = new Dictionary<Type, Type> { + {typeof (CommonSolidBrush), typeof (CommonBrushView)}, + {typeof (CommonColor), typeof (CommonBrushView)}, + }; + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourceView.cs b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourceView.cs new file mode 100644 index 0000000..034a561 --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/RequestResourceView.cs @@ -0,0 +1,160 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Linq; +using AppKit; +using CoreGraphics; +using Foundation; +using Xamarin.PropertyEditing.Drawing; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class FirstResponderTableView : NSTableView + { + [Export ("validateProposedFirstResponder:forEvent:")] + public bool validateProposedFirstResponder (NSResponder responder, NSEvent ev) + { + return true; + } + } + + internal class RequestResourceView : BasePopOverViewModelControl + { + NSSearchField searchResources; + NSSegmentedControl segmentedControl; + NSButton showPreviewImage; + RequestResourcePanel resourceSelectorPanel; + + public NSPopover PopOver { get; internal set; } + + private bool showPreview; + public bool ShowPreview + { + get { return showPreview; } + set { + this.showPreview = value; + + Frame = this.showPreview ? new CGRect (Frame.X, Frame.Y, 640, 380) : new CGRect (Frame.X, Frame.Y, 460, 380); + + if (PopOver != null) { + PopOver.ContentSize = Frame.Size; + } + } + } + + public RequestResourceView (PropertyViewModel propertyViewModel) : base (propertyViewModel, Properties.Resources.SelectResourceTitle, "resource-editor-32") + { + Initialize (propertyViewModel); + } + + private void Initialize (PropertyViewModel propertyViewModel) + { + this.ShowPreview = true; + TranslatesAutoresizingMaskIntoConstraints = false; + + var FrameWidthThird = Frame.Width / 3; + var FrameWidthHalf = Frame.Width / 2; + var FrameHeightHalf = Frame.Height / 2; + + NSControlSize controlSize = NSControlSize.Small; + + this.searchResources = new NSSearchField { + ControlSize = controlSize, + Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize), + PlaceholderString = Properties.Resources.SearchResourcesTitle, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.searchResources.Changed += OnSearchResourcesChanged; + + AddSubview (this.searchResources); + + var vmType = propertyViewModel.GetType (); + var valuePropertyInfo = vmType.GetProperty ("Value"); + var resourceValue = valuePropertyInfo.GetValue (propertyViewModel); + var resourceSelectorPropertyInfo = vmType.GetProperty ("ResourceSelector"); + var resourceSelector = resourceSelectorPropertyInfo.GetValue (propertyViewModel) as ResourceSelectorViewModel; + + if (resourceSelector != null) { + this.resourceSelectorPanel = new RequestResourcePanel (resourceSelector, resourceValue); + } else { + this.resourceSelectorPanel = new RequestResourcePanel (new ResourceSelectorViewModel (propertyViewModel.TargetPlatform.ResourceProvider, propertyViewModel.Editors.Select (ed => ed.Target), propertyViewModel.Property), resourceValue); + } + this.resourceSelectorPanel.ResourceSelected += (sender, e) => { + propertyViewModel.Resource = this.resourceSelectorPanel.SelectedResource; + }; + this.resourceSelectorPanel.DoubleClicked += (sender, e) => { + PopOver.Close (); + }; + + AddSubview (this.resourceSelectorPanel); + + segmentedControl = NSSegmentedControl.FromLabels (new string[] { Properties.Resources.AllResources, Properties.Resources.Local, Properties.Resources.Shared }, NSSegmentSwitchTracking.SelectOne, () => { + //Switch Resource Types + switch (this.segmentedControl.SelectedSegment) { + case 0: + this.resourceSelectorPanel.ViewModel.ShowBothResourceTypes = true; + this.segmentedControl.SetImage (PropertyEditorPanel.ThemeManager.GetImageForTheme ("resource-editor-16"), 2); + break; + case 1: + this.resourceSelectorPanel.ViewModel.ShowOnlyLocalResources = true; + this.segmentedControl.SetImage (PropertyEditorPanel.ThemeManager.GetImageForTheme ("resource-editor-16"), 2); + break; + case 2: + this.resourceSelectorPanel.ViewModel.ShowOnlySystemResources = true; + this.segmentedControl.SetImage (PropertyEditorPanel.ThemeManager.GetImageForTheme ("resource-editor-16", "~sel"), 2); + break; + } + + this.resourceSelectorPanel.ReloadData (); + }); + this.segmentedControl.SetImage (PropertyEditorPanel.ThemeManager.GetImageForTheme ("resource-editor-16"), 2); + this.segmentedControl.Frame = new CGRect ((FrameWidthThird - (segmentedControl.Bounds.Width) / 2), 5, (Frame.Width - (FrameWidthThird)) - 10, 24); + this.segmentedControl.Font = NSFont.FromFontName (PropertyEditorControl.DefaultFontName, PropertyEditorControl.DefaultFontSize); + this.segmentedControl.TranslatesAutoresizingMaskIntoConstraints = false; + this.segmentedControl.SetSelected (true, 0); + this.resourceSelectorPanel.ViewModel.ShowBothResourceTypes = true; + + AddSubview (this.segmentedControl); + + this.showPreviewImage = new NSButton { + Bordered = false, + ControlSize = controlSize, + Image = NSImage.ImageNamed (NSImageName.QuickLookTemplate), + Title = string.Empty, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + + this.showPreviewImage.Activated += (o, e) => { + ShowPreview = !ShowPreview; + RepositionControls (); + }; + + AddSubview (this.showPreviewImage); + + this.Appearance = PropertyEditorPanel.ThemeManager.CurrentAppearance; + + OnSearchResourcesChanged(null, null); + + RepositionControls (); + } + + private void RepositionControls () + { + var FrameWidthThird = Frame.Width / 3; + var FrameWidthHalf = Frame.Width / 2; + var FrameHeightHalf = Frame.Height / 2; + + this.searchResources.Frame = new CGRect (FrameWidthThird, Frame.Height - 30, (Frame.Width - (FrameWidthThird)) - 10, 30); + + this.showPreviewImage.Frame = new CGRect (Frame.Width - 35, 10, 24, 24); + } + + private void OnSearchResourcesChanged (object sender, EventArgs e) + { + this.resourceSelectorPanel.ViewModel.FilterText = searchResources.Cell.Title; + this.resourceSelectorPanel.ReloadData (); + } + } +}
\ No newline at end of file diff --git a/Xamarin.PropertyEditing.Mac/Controls/RequestResource/ResourceTableDataSource.cs b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/ResourceTableDataSource.cs new file mode 100644 index 0000000..6c4ad8a --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/ResourceTableDataSource.cs @@ -0,0 +1,27 @@ +using System; +using AppKit; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class ResourceTableDataSource + : NSTableViewDataSource + { + private ResourceSelectorViewModel viewModel; + internal ResourceTableDataSource (ResourceSelectorViewModel resourceSelectorViewModel) + { + if (resourceSelectorViewModel == null) + throw new ArgumentNullException (nameof (resourceSelectorViewModel)); + + this.viewModel = resourceSelectorViewModel; + } + + public ResourceSelectorViewModel ViewModel => this.viewModel; + public nint ResourceCount => this.viewModel.Resources.Count; + + public override nint GetRowCount (NSTableView tableView) + { + return ResourceCount; + } + } +} diff --git a/Xamarin.PropertyEditing.Mac/Controls/RequestResource/ResourceTableDelegate.cs b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/ResourceTableDelegate.cs new file mode 100644 index 0000000..829f405 --- /dev/null +++ b/Xamarin.PropertyEditing.Mac/Controls/RequestResource/ResourceTableDelegate.cs @@ -0,0 +1,164 @@ +using System; +using System.Collections.Generic; +using AppKit; +using Foundation; +using Xamarin.PropertyEditing.Drawing; +using Xamarin.PropertyEditing.ViewModels; + +namespace Xamarin.PropertyEditing.Mac +{ + internal class ResourceTableDelegate + : NSTableViewDelegate + { + private ResourceTableDataSource datasource; + + const string iconIdentifier = "icon"; + const string typeIdentifier = "type"; + const string nameIdentifier = "name"; + const string valueIdentifier = "value"; + + public event EventHandler ResourceSelected; + + private nint previousRow = -1; + + public ResourceTableDelegate (ResourceTableDataSource resourceTableDatasource) + { + this.datasource = resourceTableDatasource; + } + + // the table is looking for this method, picks it up automagically + public override NSView GetViewForItem (NSTableView tableView, NSTableColumn tableColumn, nint row) + { + var resource = datasource.ViewModel.Resources [(int)row] as Resource; + + // Setup view based on the column + switch (tableColumn.Identifier) { + case RequestResourcePanel.ResourceImageColId: + if (resource.Source.Type != ResourceSourceType.Application) { + var iconView = (NSImageView)tableView.MakeView (iconIdentifier, this); + if (iconView == null) { + iconView = new NSImageView { + Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("resource-editor-32"), + ImageScaling = NSImageScale.None, + Identifier = iconIdentifier, + }; + } + return iconView; + } + + // If we get here its a local resource + return new NSView (); + + case RequestResourcePanel.ResourceTypeColId: + var typeView = (UnfocusableTextField)tableView.MakeView (typeIdentifier, this); + if (typeView == null) { + typeView = new UnfocusableTextField { + Identifier = typeIdentifier, + BackgroundColor = NSColor.Clear, + }; + } + + typeView.StringValue = resource.Source.Name; + return typeView; + + case RequestResourcePanel.ResourceNameColId: + var nameView = (UnfocusableTextField)tableView.MakeView (nameIdentifier, this); + if (nameView == null) { + nameView = new UnfocusableTextField { + BackgroundColor = NSColor.Clear, + Identifier = nameIdentifier, + }; + } + + nameView.StringValue = resource.Name; + return nameView; + + case RequestResourcePanel.ResourceValueColId: + var valueView = MakeValueView (resource, tableView); + + // If still null we have no editor yet. + valueView = valueView ?? new NSView (); + + return valueView; + + default: + return base.GetViewForItem (tableView, tableColumn, row); + } + } + + public override nfloat GetRowHeight (NSTableView tableView, nint row) + { + return PropertyEditorControl.DefaultControlHeight; + } + + public override void SelectionDidChange (NSNotification notification) + { + if (notification.Object is NSTableView tableView) { + if (previousRow != -1 + && previousRow < tableView.RowCount + && tableView.GetView (0, previousRow, false) is NSImageView previousIconColumn) { + previousIconColumn.Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("resource-editor-32"); + } + + if (tableView.SelectedRow != -1 + && tableView.GetView (0, tableView.SelectedRow, false) is NSImageView selectedIconColumn) { + selectedIconColumn.Image = PropertyEditorPanel.ThemeManager.GetImageForTheme ("resource-editor-32", "~sel"); + previousRow = tableView.SelectedRow; + } + } + ResourceSelected?.Invoke (this, EventArgs.Empty); + } + + private NSView MakeValueView (Resource resource, NSTableView tableView) + { + var view = (NSView)tableView.MakeView (valueIdentifier, this); + if (view == null) { + view = GetValueView (resource.RepresentationType); + } + + CommonBrush commonBrush = BrushPropertyViewModel.GetCommonBrushForResource (resource); + + if (commonBrush != null && view is CommonBrushView commonBrushView) { + commonBrushView.Brush = commonBrush; + } + + return view; + } + + NSView GetValueView (Type representationType) + { + Type[] genericArgs = null; + Type valueRenderType; + if (!ValueTypes.TryGetValue (representationType, out valueRenderType)) { + if (representationType.IsConstructedGenericType) { + genericArgs = representationType.GetGenericArguments (); + var type = representationType.GetGenericTypeDefinition (); + ValueTypes.TryGetValue (type, out valueRenderType); + } + } + if (valueRenderType == null) + return null; + + if (valueRenderType.IsGenericTypeDefinition) { + if (genericArgs == null) + genericArgs = representationType.GetGenericArguments (); + valueRenderType = valueRenderType.MakeGenericType (genericArgs); + } + + return SetUpRenderer (valueRenderType); + } + + // set up the editor based on the type of view model + private NSView SetUpRenderer (Type valueRenderType) + { + var view = (NSView)Activator.CreateInstance (valueRenderType); + + return view; + } + + internal static readonly Dictionary<Type, Type> ValueTypes = new Dictionary<Type, Type> { + {typeof (CommonSolidBrush), typeof (CommonBrushView)}, + {typeof (CommonColor), typeof (CommonBrushView)}, + }; + } +} diff --git a/Xamarin.PropertyEditing.Mac/PropertyEditorPanel.cs b/Xamarin.PropertyEditing.Mac/PropertyEditorPanel.cs index 932bb87..f4de90e 100644 --- a/Xamarin.PropertyEditing.Mac/PropertyEditorPanel.cs +++ b/Xamarin.PropertyEditing.Mac/PropertyEditorPanel.cs @@ -6,7 +6,7 @@ using Foundation; using AppKit; using Xamarin.PropertyEditing.ViewModels; using Xamarin.PropertyEditing.Mac.Resources; -using Xamarin.PropertyEditing.Drawing; +using System.ComponentModel; namespace Xamarin.PropertyEditing.Mac { @@ -57,8 +57,10 @@ namespace Xamarin.PropertyEditing.Mac get { return this.targetPlatform; } set { - if (this.viewModel != null) + if (this.viewModel != null) { this.viewModel.ArrangedPropertiesChanged -= OnPropertiesChanged; + this.viewModel.PropertyChanged -= OnVmPropertyChanged; + } this.targetPlatform = value; this.viewModel = new PanelViewModel (value); @@ -66,8 +68,10 @@ namespace Xamarin.PropertyEditing.Mac this.propertyTable.Delegate = new PropertyTableDelegate (this.dataSource); this.propertyTable.DataSource = this.dataSource; - if (this.viewModel != null) + if (this.viewModel != null) { this.viewModel.ArrangedPropertiesChanged += OnPropertiesChanged; + this.viewModel.PropertyChanged += OnVmPropertyChanged; + } } } @@ -208,12 +212,12 @@ namespace Xamarin.PropertyEditing.Mac { PropertyArrangeMode filterMode; Enum.TryParse<PropertyArrangeMode> (propertyArrangeMode.GetItemObject (propertyArrangeMode.SelectedIndex).ToString (), out filterMode); - viewModel.ArrangeMode = filterMode; + this.viewModel.ArrangeMode = filterMode; } private void OnPropertyFilterChanged (object sender, EventArgs e) { - viewModel.FilterText = propertyFilter.Cell.Title; + this.viewModel.FilterText = propertyFilter.Cell.Title; ((PropertyTableDelegate)this.propertyTable.Delegate).UpdateExpansions (this.propertyTable); } @@ -223,6 +227,12 @@ namespace Xamarin.PropertyEditing.Mac this.Appearance = ThemeManager.CurrentAppearance; } + private void OnVmPropertyChanged (object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof (PanelViewModel.ArrangeMode)) + OnArrageModeChanged (sender, e); + } + class FirstResponderOutlineView : NSOutlineView { [Export ("validateProposedFirstResponder:forEvent:")] diff --git a/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.Designer.cs b/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.Designer.cs index 04dc28d..eacabab 100644 --- a/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.Designer.cs +++ b/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.Designer.cs @@ -155,6 +155,30 @@ namespace Xamarin.PropertyEditing.Mac.Resources { } } + internal static string ResourceTableImageColumnTitle { + get { + return ResourceManager.GetString("ResourceTableImageColumnTitle", resourceCulture); + } + } + + internal static string ResourceTableTypeColumnTitle { + get { + return ResourceManager.GetString("ResourceTableTypeColumnTitle", resourceCulture); + } + } + + internal static string ResourceTableNameColumnTitle { + get { + return ResourceManager.GetString("ResourceTableNameColumnTitle", resourceCulture); + } + } + + internal static string ResourceTableValueColumnTitle { + get { + return ResourceManager.GetString("ResourceTableValueColumnTitle", resourceCulture); + } + } + internal static string CommonBrushTitleUnknown { get { return ResourceManager.GetString("CommonBrushTitleUnknown", resourceCulture); diff --git a/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.resx b/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.resx index 2f6f257..e768be7 100644 --- a/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.resx +++ b/Xamarin.PropertyEditing.Mac/Resources/LocalizationResources.resx @@ -77,6 +77,18 @@ <data name="ColumnResourcePreview" xml:space="preserve"> <value>Preview</value>> </data> + <data name="ResourceTableImageColumnTitle" xml:space="preserve"> + <value>Icon</value> + </data> + <data name="ResourceTableTypeColumnTitle" xml:space="preserve"> + <value>Type</value> + </data> + <data name="ResourceTableNameColumnTitle" xml:space="preserve"> + <value>Name</value> + </data> + <data name="ResourceTableValueColumnTitle" xml:space="preserve"> + <value>Value</value>> + </data> <data name="CommonBrushTitleUnknown" xml:space="preserve"> <value>Unknown</value> </data> diff --git a/Xamarin.PropertyEditing.Mac/Xamarin.PropertyEditing.Mac.csproj b/Xamarin.PropertyEditing.Mac/Xamarin.PropertyEditing.Mac.csproj index 722819e..a535738 100644 --- a/Xamarin.PropertyEditing.Mac/Xamarin.PropertyEditing.Mac.csproj +++ b/Xamarin.PropertyEditing.Mac/Xamarin.PropertyEditing.Mac.csproj @@ -129,6 +129,11 @@ <Compile Include="Controls\Custom\ShadeLayer.cs" />
<Compile Include="Controls\Custom\SolidColorBrushEditor.cs" />
<Compile Include="Controls\Custom\SolidColorBrushEditorViewController.cs" />
+ <Compile Include="Controls\RequestResource\RequestResourcePanel.cs" />
+ <Compile Include="Controls\RequestResource\RequestResourceView.cs" />
+ <Compile Include="Controls\RequestResource\ResourceTableDataSource.cs" />
+ <Compile Include="Controls\RequestResource\ResourceTableDelegate.cs" />
+ <Compile Include="Controls\RequestResource\RequestResourcePreviewPanel.cs" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controls\" />
@@ -137,6 +142,7 @@ <Compile Include="Themes\MacThemeManager.cs" />
<Compile Include="Controls\BaseEditorControl.cs" />
<Compile Include="Controls\ErrorMessageView.cs" />
+ <Folder Include="Controls\RequestResource\" />
</ItemGroup>
<ItemGroup>
<Folder Include="Controls\" />
diff --git a/Xamarin.PropertyEditing/Properties/Resources.Designer.cs b/Xamarin.PropertyEditing/Properties/Resources.Designer.cs index 85356ef..eb2c7f1 100644 --- a/Xamarin.PropertyEditing/Properties/Resources.Designer.cs +++ b/Xamarin.PropertyEditing/Properties/Resources.Designer.cs @@ -815,9 +815,15 @@ namespace Xamarin.PropertyEditing.Properties { } } - public static string GradientBrush { + public static string AllResources { get { - return ResourceManager.GetString("GradientBrush", resourceCulture); + return ResourceManager.GetString("AllResources", resourceCulture); + } + } + + public static string Shared { + get { + return ResourceManager.GetString("Shared", resourceCulture); } } } diff --git a/Xamarin.PropertyEditing/Properties/Resources.resx b/Xamarin.PropertyEditing/Properties/Resources.resx index 1544149..081dc7e 100644 --- a/Xamarin.PropertyEditing/Properties/Resources.resx +++ b/Xamarin.PropertyEditing/Properties/Resources.resx @@ -547,8 +547,11 @@ </data> <data name="InvalidRatio" xml:space="preserve"> <value>Invalid Ratio</value> - </data> - <data name="GradientBrush" xml:space="preserve"> - <value>Gradient brush</value> + </data> + <data name="AllResources" xml:space="preserve"> + <value>All Resources</value> + </data> + <data name="Shared" xml:space="preserve"> + <value>Shared</value> </data> </root>
\ No newline at end of file |