diff --git a/Cirrious.FluentLayout/Cirrious.FluentLayouts.Touch.csproj b/Cirrious.FluentLayout/Cirrious.FluentLayouts.Touch.csproj index 3dba747..b412bf0 100644 --- a/Cirrious.FluentLayout/Cirrious.FluentLayouts.Touch.csproj +++ b/Cirrious.FluentLayout/Cirrious.FluentLayouts.Touch.csproj @@ -1,59 +1,44 @@  - - - Debug - AnyCPU - {75D2DA9D-DFD4-49A1-98FB-FE0F0677EF0F} - {FEACFBD2-3405-455C-9665-78FE426C6842};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - Library - Cirrious.FluentLayouts.Touch - Resources - Cirrious.FluentLayouts.Touch - Xamarin.iOS - v1.0 - - - true - full - false - bin\iPhoneSimulator\Debug - DEBUG - prompt - 4 - false - None - true - - - none - true - bin\iPhoneSimulator\Release - prompt - 4 - false - None - - - - - - - - - - - - - - - - - - - - - - - - + + + xamarin.ios10;xamarin.mac20 + https://github.com/FluentLayout/Cirrious.FluentLayout + $(AssemblyName) ($(TargetFramework)) + xamarin ios mac constraints + MS-PL + 7.3 + $(NoWarn);1591;1701;1591;1702;1705;VSX1000;NU1603 + https://github.com/FluentLayout/Cirrious.FluentLayout + git + True + True + true + true + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + full + true + + + + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Cirrious.FluentLayout/Platforms/Mac/AdvancedFluentLayoutExtensions.cs b/Cirrious.FluentLayout/Platforms/Mac/AdvancedFluentLayoutExtensions.cs new file mode 100644 index 0000000..7f5d679 --- /dev/null +++ b/Cirrious.FluentLayout/Platforms/Mac/AdvancedFluentLayoutExtensions.cs @@ -0,0 +1,227 @@ +// AdvancedFluentLayoutExtensions.cs +// (c) Copyright Cirrious Ltd. http://www.cirrious.com +// MvvmCross is licensed using Microsoft Public License (Ms-PL) +// Contributions and inspirations noted in readme.md and license.txt +// +// Project Lead - Stuart Lodge, @slodge, me@slodge.com + +using System; +using System.Collections.Generic; +using System.Linq; +using AppKit; +using Cirrious.FluentLayouts.Touch.Extensions; + +namespace Cirrious.FluentLayouts.Touch +{ + public static class AdvancedFluentLayoutExtensions + { + const float DefaultMargin = 0; + const float DefaultScale = 1; + + public static FluentLayout AtTopOf(this NSView view, NSView parentView, nfloat? margin = null) => + view.Top().EqualTo().TopOf(parentView).Plus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout AtLeftOf(this NSView view, NSView parentView, nfloat? margin = null) => + view.Left().EqualTo().LeftOf(parentView).Plus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout AtRightOf(this NSView view, NSView parentView, nfloat? margin = null) => + view.Right().EqualTo().RightOf(parentView).Minus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout AtBottomOf(this NSView view, NSView parentView, nfloat? margin = null) => + view.Bottom().EqualTo().BottomOf(parentView).Minus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout AtLeadingOf(this NSView view, NSView parentView, nfloat? margin = null) => + view.Leading().EqualTo().LeadingOf(parentView).Plus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout AtTrailingOf(this NSView view, NSView parentView, nfloat? margin = null) => + view.Trailing().EqualTo().TrailingOf(parentView).Minus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout Below(this NSView view, NSView previous, nfloat? margin = null) => + view.Top().EqualTo().BottomOf(previous).Plus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout Above(this NSView view, NSView previous, nfloat? margin = null) => + view.Bottom().EqualTo().TopOf(previous).Minus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout WithSameLeft(this NSView view, NSView previous) => view.Left().EqualTo().LeftOf(previous); + + public static FluentLayout WithSameTop(this NSView view, NSView previous) => view.Top().EqualTo().TopOf(previous); + + public static FluentLayout WithSameCenterX(this NSView view, NSView previous) => view.CenterX().EqualTo().CenterXOf(previous); + + public static FluentLayout WithSameCenterY(this NSView view, NSView previous) => view.CenterY().EqualTo().CenterYOf(previous); + + public static FluentLayout WithSameRight(this NSView view, NSView previous) => view.Right().EqualTo().RightOf(previous); + + public static FluentLayout WithSameWidth(this NSView view, NSView previous) => view.Width().EqualTo().WidthOf(previous); + + public static FluentLayout WithSameBottom(this NSView view, NSView previous) => view.Bottom().EqualTo().BottomOf(previous); + + public static FluentLayout WithSameLeading(this NSView view, NSView previous) => view.Leading().EqualTo().LeadingOf(previous); + + public static FluentLayout WithSameTrailing(this NSView view, NSView previous) => view.Trailing().EqualTo().TrailingOf(previous); + + public static FluentLayout WithRelativeWidth(this NSView view, NSView previous, nfloat? scale = null) => + view.Width().EqualTo().WidthOf(previous).WithMultiplier(scale.GetValueOrDefault(DefaultScale)); + + public static FluentLayout WithSameHeight(this NSView view, NSView previous) => view.Height().EqualTo().HeightOf(previous); + + public static FluentLayout WithRelativeHeight(this NSView view, NSView previous, nfloat? scale = null) => + view.Height().EqualTo().HeightOf(previous).WithMultiplier(scale.GetValueOrDefault(DefaultScale)); + + public static FluentLayout ToRightOf(this NSView view, NSView previous, nfloat? margin = null) => + view.Left().EqualTo().RightOf(previous).Plus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout ToLeftOf(this NSView view, NSView previous, nfloat? margin = null) => + view.Right().EqualTo().LeftOf(previous).Minus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout ToTrailingOf(this NSView view, NSView previous, nfloat? margin = null) => + view.Leading().EqualTo().TrailingOf(previous).Plus(margin.GetValueOrDefault(DefaultMargin)); + + public static FluentLayout ToLeadingOf(this NSView view, NSView previous, nfloat? margin = null) => + view.Trailing().EqualTo().LeadingOf(previous).Minus(margin.GetValueOrDefault(DefaultMargin)); + + //public static FluentLayout ToLeftMargin(this NSView view, NSView previous) => + // view.Leading().EqualTo().LeadingMarginOf(previous); + + //public static FluentLayout ToRightMargin(this NSView view, NSView previous) => + // view.Trailing().EqualTo().TrailingMarginOf(previous); + + //public static FluentLayout ToTopMargin(this NSView view, NSView previous) => + // view.Top().EqualTo().TopMarginOf(previous); + + //public static FluentLayout ToBottomMargin(this NSView view, NSView previous) => + // view.Bottom().EqualTo().BottomMarginOf(previous); + + public static FluentLayout ToLeftOfCenterOf(this NSView view, NSView previous, nfloat? margin = null) => + view.Right().EqualTo().CenterXOf(previous).Minus(margin.GetValueOrDefault(0)); + + public static FluentLayout ToRightOfCenterOf(this NSView view, NSView previous, nfloat? margin = null) => + view.Left().EqualTo().CenterXOf(previous).Plus(margin.GetValueOrDefault(0)); + + public static FluentLayout AboveCenterOf(this NSView view, NSView previous, nfloat? margin = null) => + view.Bottom().EqualTo().CenterYOf(previous).Minus(margin.GetValueOrDefault(0)); + + public static FluentLayout BelowCenterOf(this NSView view, NSView previous, nfloat? margin = null) => + view.Top().EqualTo().CenterYOf(previous).Plus(margin.GetValueOrDefault(0)); + + public static IEnumerable FullWidthOf(this NSView view, NSView parent, nfloat? margin = null) + { + var marginValue = margin.GetValueOrDefault(DefaultMargin); + + return new List + { + view.AtLeftOf(parent, marginValue).WithIdentifier("Left"), + view.AtRightOf(parent, marginValue).WithIdentifier("Right") + }; + } + + public static IEnumerable FullHeightOf(this NSView view, NSView parent, nfloat? margin = null) + { + var marginValue = margin.GetValueOrDefault(DefaultMargin); + + return new List + { + view.AtTopOf(parent, marginValue).WithIdentifier("Top"), + view.AtBottomOf(parent, marginValue).WithIdentifier("Bottom") + }; + } + + public static IEnumerable FullSizeOf(this NSView view, NSView parent, nfloat? margin = null) => + FullSizeOf(view, parent, new Margins((float)margin.GetValueOrDefault(DefaultMargin))); + + public static IEnumerable FullSizeOf(this NSView view, NSView parent, Margins margins) + { + margins = margins ?? new Margins(); + + return new List + { + view.AtTopOf(parent, margins.Top).WithIdentifier("Top"), + view.AtBottomOf(parent, margins.Bottom).WithIdentifier("Bottom"), + view.AtLeftOf(parent, margins.Left).WithIdentifier("Left"), + view.AtRightOf(parent, margins.Right).WithIdentifier("Right") + }; + } + + public static FluentLayout GetLayoutById(this IEnumerable layouts, string identifier) => + layouts.FirstOrDefault(x => x.Identifier.Equals(identifier)); + + public static IEnumerable VerticalStackPanelConstraints(this NSView parentView, Margins margins, params NSView[] views) => + AdvancedVerticalStackPanelConstraints(parentView, margins, views: views); + + /// + /// Vertical stack panel constraints with support for children independent left, right and top margins + /// and a multiplier factor for all margins applied. The multiplier can be useful when dealing with iPad screens. + /// Example: + /// + /// scrollView.AddConstraints(scrollView.AdvancedVerticalStackPanelConstraints(null, + /// childrenLeftMargins: new float[] { 15, 0, 15, 0, 0, 15 }, + /// childrenTopMargins: new float[] { 15, 5, 15, 5, 8, 15, 22, 8, 8, 28, 28 }, + /// marginMultiplier: 2f, + /// views: scrollView.Subviews) + /// ); + /// + public static IEnumerable AdvancedVerticalStackPanelConstraints(this NSView parentView, + Margins margins, + float[] childrenLeftMargins = null, + float[] childrenTopMargins = null, + float[] childrenRightMargins = null, + float marginMultiplier = 1, + params NSView[] views) + { + string previousIdentifierPrefix = null; + margins = margins ?? new Margins(); + var layouts = new List(); + + var count = views.Length; + for (var i = 0; i < count; i++) + { + var view = views[i]; + var viewIdentifierPrefix = $"{parentView.AccessibilityIdentifier ?? "VerticalStackPanel"}-{view.AccessibilityIdentifier ?? i.ToString()}-"; + + float childLeftMargin; + childrenLeftMargins.TryGetElement(i, out childLeftMargin); + var marginLeft = Math.Max(margins.Left, childLeftMargin) * marginMultiplier; + layouts.Add(view.Left() + .EqualTo() + .LeftOf(parentView) + .Plus(marginLeft) + .WithIdentifier(viewIdentifierPrefix + "Left")); + + float childRightMargin; + childrenRightMargins.TryGetElement(i, out childRightMargin); + var marginRight = Math.Max(margins.Right, childRightMargin) * marginMultiplier; + layouts.Add(view.Width() + .EqualTo() + .WidthOf(parentView) + .Minus(marginRight + marginLeft) + .WithIdentifier(viewIdentifierPrefix + "Width")); + + float childTopMargin; + childrenTopMargins.TryGetElement(i, out childTopMargin); + + layouts.Add(i == 0 + ? view.Top() + .EqualTo() + .TopOf(parentView) + .Plus(Math.Max(margins.Top, childTopMargin)*marginMultiplier) + .WithIdentifier(viewIdentifierPrefix + "Top") + : view.Top() + .EqualTo() + .BottomOf(views[i - 1]) + .Plus(Math.Max(margins.VSpacing, childTopMargin)*marginMultiplier) + .WithIdentifier(viewIdentifierPrefix + "Top")); + + previousIdentifierPrefix = viewIdentifierPrefix; + } + + if (parentView is NSScrollView) + layouts.Add(views[views.Length - 1].Bottom() + .EqualTo() + .BottomOf(parentView) + .Minus(margins.Bottom * marginMultiplier) + .WithIdentifier(previousIdentifierPrefix + "Bottom")); + + return layouts; + } + } +} diff --git a/Cirrious.FluentLayout/Platforms/Mac/Extensions/NSViewExtensions.cs b/Cirrious.FluentLayout/Platforms/Mac/Extensions/NSViewExtensions.cs new file mode 100644 index 0000000..7333934 --- /dev/null +++ b/Cirrious.FluentLayout/Platforms/Mac/Extensions/NSViewExtensions.cs @@ -0,0 +1,13 @@ +using AppKit; + +namespace Cirrious.FluentLayouts.Touch.Extensions +{ + public static class NSViewExtensions + { + public static void AddSubviews(this NSView view, params NSView[] subviews) + { + foreach (var subview in subviews) + view.AddSubview(subview); + } + } +} diff --git a/Cirrious.FluentLayout/FluentLayout.cs b/Cirrious.FluentLayout/Platforms/Mac/FluentLayout.cs similarity index 86% rename from Cirrious.FluentLayout/FluentLayout.cs rename to Cirrious.FluentLayout/Platforms/Mac/FluentLayout.cs index 4b3d858..d84abf7 100644 --- a/Cirrious.FluentLayout/FluentLayout.cs +++ b/Cirrious.FluentLayout/Platforms/Mac/FluentLayout.cs @@ -7,7 +7,7 @@ using System; using System.Collections.Generic; -using UIKit; +using AppKit; using Foundation; namespace Cirrious.FluentLayouts.Touch @@ -15,7 +15,7 @@ namespace Cirrious.FluentLayouts.Touch public class FluentLayout { public FluentLayout( - UIView view, + NSView view, NSLayoutAttribute attribute, NSLayoutRelation relation, NSObject secondItem, @@ -27,10 +27,10 @@ public class FluentLayout Relation = relation; SecondItem = secondItem; SecondAttribute = secondAttribute; - Priority = (float) UILayoutPriority.Required; + Priority = (float) NSLayoutPriority.Required; } - public FluentLayout(UIView view, + public FluentLayout(NSView view, NSLayoutAttribute attribute, NSLayoutRelation relation, nfloat constant = default(nfloat)) @@ -40,10 +40,10 @@ public class FluentLayout Attribute = attribute; Relation = relation; Constant = constant; - Priority = (float) UILayoutPriority.Required; + Priority = (float) NSLayoutPriority.Required; } - public UIView View { get; } + public NSView View { get; } public nfloat Multiplier { get; private set; } = 1f; @@ -95,7 +95,7 @@ public string Identifier _identifier = value; if (Constraint.IsValueCreated) - Constraint.Value.SetIdentifier(_identifier); + Constraint.Value.Identifier = _identifier; } } @@ -119,7 +119,7 @@ private NSLayoutConstraint CreateConstraint() constraint.Priority = Priority; if (!string.IsNullOrWhiteSpace(Identifier)) - constraint.SetIdentifier(Identifier); + constraint.Identifier = Identifier; return constraint; } @@ -148,7 +148,7 @@ public FluentLayout SetPriority(float priority) return this; } - public FluentLayout SetPriority(UILayoutPriority priority) + public FluentLayout SetPriority(NSLayoutPriority priority) { Priority = (float) priority; return this; @@ -188,13 +188,13 @@ public FluentLayout WithIdentifier(string identifier) public FluentLayout WidthOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Width); - public FluentLayout TrailingMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.TrailingMargin); + //public FluentLayout TrailingMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.TrailingMargin); - public FluentLayout LeadingMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.LeadingMargin); + //public FluentLayout LeadingMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.LeadingMargin); - public FluentLayout TopMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.TopMargin); + //public FluentLayout TopMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.TopMargin); - public FluentLayout BottomMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.BottomMargin); + //public FluentLayout BottomMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.BottomMargin); private FluentLayout SetSecondItem(NSObject view2, NSLayoutAttribute attribute2) { diff --git a/Cirrious.FluentLayout/Platforms/Mac/FluentLayoutExtensions.cs b/Cirrious.FluentLayout/Platforms/Mac/FluentLayoutExtensions.cs new file mode 100644 index 0000000..6583161 --- /dev/null +++ b/Cirrious.FluentLayout/Platforms/Mac/FluentLayoutExtensions.cs @@ -0,0 +1,72 @@ +// FluentLayoutExtensions.cs +// (c) Copyright Cirrious Ltd. http://www.cirrious.com +// MvvmCross is licensed using Microsoft Public License (Ms-PL) +// Contributions and inspirations noted in readme.md and license.txt +// +// Project Lead - Stuart Lodge, @slodge, me@slodge.com + +using System.Collections.Generic; +using System.Linq; +using AppKit; + +namespace Cirrious.FluentLayouts.Touch +{ + public static class FluentLayoutExtensions + { + public static void SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(this NSView view) + { + foreach (var subview in view.Subviews) + { + subview.TranslatesAutoresizingMaskIntoConstraints = false; + } + } + + public static NSViewAndLayoutAttribute Left(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Left); + + public static NSViewAndLayoutAttribute Right(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Right); + + public static NSViewAndLayoutAttribute Top(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Top); + + public static NSViewAndLayoutAttribute Bottom(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Bottom); + + public static NSViewAndLayoutAttribute Baseline(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Baseline); + + public static NSViewAndLayoutAttribute Trailing(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Trailing); + + public static NSViewAndLayoutAttribute Leading(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Leading); + + public static NSViewAndLayoutAttribute CenterX(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.CenterX); + + public static NSViewAndLayoutAttribute CenterY(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.CenterY); + + public static NSViewAndLayoutAttribute Height(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Height); + + public static NSViewAndLayoutAttribute Width(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.Width); + + public static NSViewAndLayoutAttribute WithLayoutAttribute(this NSView view, NSLayoutAttribute attribute) => new NSViewAndLayoutAttribute(view, attribute); + + //public static NSViewAndLayoutAttribute LeadingMargin(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.LeadingMargin); + + //public static NSViewAndLayoutAttribute TrailingMargin(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.TrailingMargin); + + //public static NSViewAndLayoutAttribute TopMargin(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.TopMargin); + + //public static NSViewAndLayoutAttribute BottomMargin(this NSView view) => view.WithLayoutAttribute(NSLayoutAttribute.BottomMargin); + + public static void AddConstraints(this NSView view, params FluentLayout[] fluentLayouts) => view.AddConstraints(fluentLayouts.AsEnumerable()); + + public static void AddConstraints(this NSView view, IEnumerable fluentLayouts) => + view.AddConstraints(fluentLayouts + .Where(fluent => fluent != null) + .Select(fluent => fluent.Constraint.Value) + .ToArray()); + + public static void RemoveConstraints(this NSView view, params FluentLayout[] fluentLayouts) => view.RemoveConstraints(fluentLayouts.AsEnumerable()); + + public static void RemoveConstraints(this NSView view, IEnumerable fluentLayouts) => + view.RemoveConstraints(fluentLayouts + .Where(fluent => fluent != null) + .Select(fluent => fluent.Constraint.Value) + .ToArray()); + } +} diff --git a/Cirrious.FluentLayout/Platforms/Mac/NSViewAndLayoutAttribute.cs b/Cirrious.FluentLayout/Platforms/Mac/NSViewAndLayoutAttribute.cs new file mode 100644 index 0000000..1b04829 --- /dev/null +++ b/Cirrious.FluentLayout/Platforms/Mac/NSViewAndLayoutAttribute.cs @@ -0,0 +1,33 @@ +// UIViewAndLayoutAttribute.cs +// (c) Copyright Cirrious Ltd. http://www.cirrious.com +// MvvmCross is licensed using Microsoft Public License (Ms-PL) +// Contributions and inspirations noted in readme.md and license.txt +// +// Project Lead - Stuart Lodge, @slodge, me@slodge.com + +using AppKit; +using System; + +namespace Cirrious.FluentLayouts.Touch +{ + public class NSViewAndLayoutAttribute + { + public NSViewAndLayoutAttribute(NSView view, NSLayoutAttribute attribute) + { + Attribute = attribute; + View = view; + } + + public NSView View { get; } + public NSLayoutAttribute Attribute { get; } + + public FluentLayout EqualTo(nfloat constant = default(nfloat)) => + new FluentLayout(View, Attribute, NSLayoutRelation.Equal, constant); + + public FluentLayout GreaterThanOrEqualTo(nfloat constant = default(nfloat)) => + new FluentLayout(View, Attribute, NSLayoutRelation.GreaterThanOrEqual, constant); + + public FluentLayout LessThanOrEqualTo(nfloat constant = default(nfloat)) => + new FluentLayout(View, Attribute, NSLayoutRelation.LessThanOrEqual, constant); + } +} \ No newline at end of file diff --git a/Cirrious.FluentLayout/Platforms/Mac/RowSet-WorkInProgress/RowSet.cs b/Cirrious.FluentLayout/Platforms/Mac/RowSet-WorkInProgress/RowSet.cs new file mode 100644 index 0000000..417441e --- /dev/null +++ b/Cirrious.FluentLayout/Platforms/Mac/RowSet-WorkInProgress/RowSet.cs @@ -0,0 +1,167 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using AppKit; + +namespace Cirrious.FluentLayouts.Touch.RowSet +{ + public class RowSetTemplate + { + public float TopMargin { get; set; } + public float BottomMargin { get; set; } + public float VInterspacing { get; set; } + + public IEnumerable Generate(NSView container, params Row[] rows) + { + for (var i = 0; i < rows.Length; i++) + { + var verticalGenerators = new List>(); + + var isFirst = i == 0; + if (isFirst) + verticalGenerators.Add(view => view.AtTopOf(container, TopMargin)); + else + { + var previousRowView = rows[i - 1].Views.First(); + verticalGenerators.Add(view => view.Below(previousRowView, VInterspacing)); + } + + var isLast = i == rows.Length - 1; + if (isLast) + verticalGenerators.Add(view => view.AtBottomOf(container, BottomMargin)); + + foreach (var view in rows[i].Views) + { + foreach (var verticalGenerator in verticalGenerators) + yield return verticalGenerator(view); + } + + foreach (var horizontalConstraint in rows[i].Template.Generate(container, rows[i].Views.ToArray())) + yield return horizontalConstraint; + } + } + } + + public class Row + { + public Row() + { + } + + public Row(IRowTemplate rowTemplate, params NSView[] views) + { + Template = rowTemplate; + Views = views; + } + + public IRowTemplate Template { get; set; } + public IEnumerable Views { get; set; } + } + + public interface IRowTemplate + { + IEnumerable Generate(NSView container, params NSView[] views); + } + + public class RowTemplate : IRowTemplate + { + public float LeftMargin { get; set; } + public float RightMargin { get; set; } + public float HInterspacing { get; set; } + + public class Column + { + public static readonly Column Default = new WeightedWidthColumn(); + } + + public class FixedWidthColumn + : Column + { + public float Width { get; set; } + + public FixedWidthColumn(float width) + { + Width = width; + } + } + + public class WeightedWidthColumn + : Column + { + public float Weight { get; set; } + + public WeightedWidthColumn(float weight = 1.0f) + { + Weight = weight; + } + } + + private readonly Dictionary _columnDefinitions = new Dictionary(); + + public void ColumnWidth(int position, float width) + { + _columnDefinitions[position] = new FixedWidthColumn(width); + } + + public void ColumnWeight(int position, float weight) + { + _columnDefinitions[position] = new WeightedWidthColumn(weight); + } + + public IEnumerable Generate(NSView container, params NSView[] views) + { + WeightedWidthColumn firstWeightedColumn = null; + NSView firstWeightedView = null; + + for (var i = 0; i < views.Length; i++) + { + var view = views[i]; + var column = GetColumn(i); + + if (i == 0) + { + yield return view.AtLeftOf(container, LeftMargin); + } + else + { + yield return view.ToRightOf(views[i - 1], HInterspacing); + } + + if (i == views.Length - 1) + { + yield return view.AtRightOf(container, RightMargin); + } + + var weightedColumn = column as WeightedWidthColumn; + if (weightedColumn != null) + { + if (firstWeightedColumn == null) + { + firstWeightedColumn = weightedColumn; + firstWeightedView = view; + } + else + { + var multiplier = weightedColumn.Weight / firstWeightedColumn.Weight; + yield return view.WithRelativeWidth(firstWeightedView, multiplier); + } + } + + var fixedColumn = column as FixedWidthColumn; + if (fixedColumn != null) + { + yield return view.Width().EqualTo(fixedColumn.Width); + } + } + } + + private Column GetColumn(int index) + { + Column column; + if (_columnDefinitions.TryGetValue(index, out column)) + return column; + + return Column.Default; + } + } +} diff --git a/Cirrious.FluentLayout/Extensions/ArrayExtensions.cs b/Cirrious.FluentLayout/Platforms/Shared/Extensions/ArrayExtensions.cs similarity index 100% rename from Cirrious.FluentLayout/Extensions/ArrayExtensions.cs rename to Cirrious.FluentLayout/Platforms/Shared/Extensions/ArrayExtensions.cs diff --git a/Cirrious.FluentLayout/Margins.cs b/Cirrious.FluentLayout/Platforms/Shared/Margins.cs similarity index 100% rename from Cirrious.FluentLayout/Margins.cs rename to Cirrious.FluentLayout/Platforms/Shared/Margins.cs diff --git a/Cirrious.FluentLayout/NfloatExtensions.cs b/Cirrious.FluentLayout/Platforms/Shared/NfloatExtensions.cs similarity index 100% rename from Cirrious.FluentLayout/NfloatExtensions.cs rename to Cirrious.FluentLayout/Platforms/Shared/NfloatExtensions.cs diff --git a/Cirrious.FluentLayout/AdvancedFluentLayoutExtensions.cs b/Cirrious.FluentLayout/Platforms/iOS/AdvancedFluentLayoutExtensions.cs similarity index 100% rename from Cirrious.FluentLayout/AdvancedFluentLayoutExtensions.cs rename to Cirrious.FluentLayout/Platforms/iOS/AdvancedFluentLayoutExtensions.cs diff --git a/Cirrious.FluentLayout/Platforms/iOS/FluentLayout.cs b/Cirrious.FluentLayout/Platforms/iOS/FluentLayout.cs new file mode 100644 index 0000000..7f6bca0 --- /dev/null +++ b/Cirrious.FluentLayout/Platforms/iOS/FluentLayout.cs @@ -0,0 +1,219 @@ +// FluentLayout.cs +// (c) Copyright Cirrious Ltd. http://www.cirrious.com +// MvvmCross is licensed using Microsoft Public License (Ms-PL) +// Contributions and inspirations noted in readme.md and license.txt +// +// Project Lead - Stuart Lodge, @slodge, me@slodge.com + +using System; +using System.Collections.Generic; +using UIKit; +using Foundation; + +namespace Cirrious.FluentLayouts.Touch +{ + public class FluentLayout + { + public FluentLayout( + UIView view, + NSLayoutAttribute attribute, + NSLayoutRelation relation, + NSObject secondItem, + NSLayoutAttribute secondAttribute) + { + Constraint = new Lazy(CreateConstraint); + View = view; + Attribute = attribute; + Relation = relation; + SecondItem = secondItem; + SecondAttribute = secondAttribute; + Priority = (float)UILayoutPriority.Required; + } + + public FluentLayout(UIView view, + NSLayoutAttribute attribute, + NSLayoutRelation relation, + nfloat constant = default(nfloat)) + { + Constraint = new Lazy(CreateConstraint); + View = view; + Attribute = attribute; + Relation = relation; + Constant = constant; + Priority = (float)UILayoutPriority.Required; + } + + public UIView View { get; } + + public nfloat Multiplier { get; private set; } = 1f; + + private nfloat _constant; + public nfloat Constant + { + get { return _constant; } + set + { + _constant = value; + + if (Constraint.IsValueCreated) + Constraint.Value.Constant = _constant; + } + } + + private float _priority; + public float Priority + { + get { return _priority; } + set + { + _priority = value; + + if (Constraint.IsValueCreated) + Constraint.Value.Priority = _priority; + } + } + + private bool _active = true; + public bool Active + { + get { return _active; } + set + { + _active = value; + + if (Constraint.IsValueCreated) + Constraint.Value.Active = _active; + } + } + + private string _identifier; + public string Identifier + { + get { return _identifier; } + set + { + _identifier = value; + + if (Constraint.IsValueCreated) + Constraint.Value.SetIdentifier(_identifier); + } + } + + public NSLayoutAttribute Attribute { get; private set; } + public NSLayoutRelation Relation { get; private set; } + public NSObject SecondItem { get; private set; } + public NSLayoutAttribute SecondAttribute { get; private set; } + + internal Lazy Constraint { get; } + + private NSLayoutConstraint CreateConstraint() + { + var constraint = NSLayoutConstraint.Create( + View, + Attribute, + Relation, + SecondItem, + SecondAttribute, + Multiplier, + Constant); + constraint.Priority = Priority; + + if (!string.IsNullOrWhiteSpace(Identifier)) + constraint.SetIdentifier(Identifier); + + return constraint; + } + + public FluentLayout Plus(nfloat constant) + { + Constant += constant; + return this; + } + + public FluentLayout Minus(nfloat constant) + { + Constant -= constant; + return this; + } + + public FluentLayout WithMultiplier(nfloat multiplier) + { + Multiplier = multiplier; + return this; + } + + public FluentLayout SetPriority(float priority) + { + Priority = priority; + return this; + } + + public FluentLayout SetPriority(UILayoutPriority priority) + { + Priority = (float)priority; + return this; + } + + public FluentLayout SetActive(bool active) + { + Active = active; + return this; + } + + public FluentLayout WithIdentifier(string identifier) + { + Identifier = identifier; + return this; + } + + public FluentLayout LeftOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Left); + + public FluentLayout RightOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Right); + + public FluentLayout TopOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Top); + + public FluentLayout BottomOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Bottom); + + public FluentLayout BaselineOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Baseline); + + public FluentLayout TrailingOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Trailing); + + public FluentLayout LeadingOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Leading); + + public FluentLayout CenterXOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.CenterX); + + public FluentLayout CenterYOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.CenterY); + + public FluentLayout HeightOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Height); + + public FluentLayout WidthOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.Width); + + public FluentLayout TrailingMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.TrailingMargin); + + public FluentLayout LeadingMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.LeadingMargin); + + public FluentLayout TopMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.TopMargin); + + public FluentLayout BottomMarginOf(NSObject view2) => SetSecondItem(view2, NSLayoutAttribute.BottomMargin); + + private FluentLayout SetSecondItem(NSObject view2, NSLayoutAttribute attribute2) + { + ThrowIfSecondItemAlreadySet(); + SecondAttribute = attribute2; + SecondItem = view2; + return this; + } + + private void ThrowIfSecondItemAlreadySet() + { + if (SecondItem != null) + throw new Exception("You cannot set the second item in a layout relation more than once"); + } + + [Obsolete("This method will be removed in future versions, please let us know if you still need it!")] + public IEnumerable ToLayoutConstraints() + { + yield return Constraint.Value; + } + } +} \ No newline at end of file diff --git a/Cirrious.FluentLayout/FluentLayoutExtensions.cs b/Cirrious.FluentLayout/Platforms/iOS/FluentLayoutExtensions.cs similarity index 100% rename from Cirrious.FluentLayout/FluentLayoutExtensions.cs rename to Cirrious.FluentLayout/Platforms/iOS/FluentLayoutExtensions.cs diff --git a/Cirrious.FluentLayout/RowSet-WorkInProgress/RowSet.cs b/Cirrious.FluentLayout/Platforms/iOS/RowSet-WorkInProgress/RowSet.cs similarity index 100% rename from Cirrious.FluentLayout/RowSet-WorkInProgress/RowSet.cs rename to Cirrious.FluentLayout/Platforms/iOS/RowSet-WorkInProgress/RowSet.cs diff --git a/Cirrious.FluentLayout/UIViewAndLayoutAttribute.cs b/Cirrious.FluentLayout/Platforms/iOS/UIViewAndLayoutAttribute.cs similarity index 100% rename from Cirrious.FluentLayout/UIViewAndLayoutAttribute.cs rename to Cirrious.FluentLayout/Platforms/iOS/UIViewAndLayoutAttribute.cs diff --git a/Cirrious.FluentLayout/Properties/AssemblyInfo.cs b/Cirrious.FluentLayout/Properties/AssemblyInfo.cs deleted file mode 100644 index b56a76e..0000000 --- a/Cirrious.FluentLayout/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,46 +0,0 @@ -// AssemblyInfo.cs -// (c) Copyright Cirrious Ltd. http://www.cirrious.com -// MvvmCross is licensed using Microsoft Public License (Ms-PL) -// Contributions and inspirations noted in readme.md and license.txt -// -// Project Lead - Stuart Lodge, @slodge, me@slodge.com - -using System.Reflection; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. - -[assembly: AssemblyTitle("Cirrious.FluentLayout")] -[assembly: AssemblyDescription("Easy API for using AutoLayout in iOS")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("Cirrious.FluentLayout")] -[assembly: AssemblyCopyright("Copyright © 2018")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. - -[assembly: ComVisible(false)] - -// The following GUID is for the ID of the typelib if this project is exposed to COM - -[assembly: Guid("deb03d05-a92d-4319-b09d-3f890065a6ce")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] - -[assembly: AssemblyVersion("2.6.0.0")] -[assembly: AssemblyFileVersion("2.6.0.0")] \ No newline at end of file diff --git a/QuickLayout.Mac/AppDelegate.cs b/QuickLayout.Mac/AppDelegate.cs new file mode 100644 index 0000000..a7b46be --- /dev/null +++ b/QuickLayout.Mac/AppDelegate.cs @@ -0,0 +1,11 @@ +using Foundation; +using MvvmCross.Platforms.Mac.Core; +using QuickLayout.Core; + +namespace QuickLayout.Mac +{ + [Register("AppDelegate")] + public class AppDelegate : MvxApplicationDelegate, App> + { + } +} diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png new file mode 100644 index 0000000..d0b5a80 Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png new file mode 100644 index 0000000..f4c8d29 Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-128@2x.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png new file mode 100644 index 0000000..ebb5a0f Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png new file mode 100644 index 0000000..0986d31 Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-16@2x.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png new file mode 100644 index 0000000..f4c8d29 Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png new file mode 100644 index 0000000..a142c83 Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-256@2x.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png new file mode 100644 index 0000000..0986d31 Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png new file mode 100644 index 0000000..412d6ca Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-32@2x.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png new file mode 100644 index 0000000..a142c83 Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png new file mode 100644 index 0000000..e99022a Binary files /dev/null and b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png differ diff --git a/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/Contents.json b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..6b28545 --- /dev/null +++ b/QuickLayout.Mac/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,68 @@ +{ + "images": [ + { + "filename": "AppIcon-16.png", + "size": "16x16", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-16@2x.png", + "size": "16x16", + "scale": "2x", + "idiom": "mac" + }, + { + "filename": "AppIcon-32.png", + "size": "32x32", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-32@2x.png", + "size": "32x32", + "scale": "2x", + "idiom": "mac" + }, + { + "filename": "AppIcon-128.png", + "size": "128x128", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-128@2x.png", + "size": "128x128", + "scale": "2x", + "idiom": "mac" + }, + { + "filename": "AppIcon-256.png", + "size": "256x256", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-256@2x.png", + "size": "256x256", + "scale": "2x", + "idiom": "mac" + }, + { + "filename": "AppIcon-512.png", + "size": "512x512", + "scale": "1x", + "idiom": "mac" + }, + { + "filename": "AppIcon-512@2x.png", + "size": "512x512", + "scale": "2x", + "idiom": "mac" + } + ], + "info": { + "version": 1, + "author": "xcode" + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Assets.xcassets/Contents.json b/QuickLayout.Mac/Assets.xcassets/Contents.json new file mode 100644 index 0000000..4caf392 --- /dev/null +++ b/QuickLayout.Mac/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Converters/FloatToIntConverter.cs b/QuickLayout.Mac/Converters/FloatToIntConverter.cs new file mode 100644 index 0000000..739f692 --- /dev/null +++ b/QuickLayout.Mac/Converters/FloatToIntConverter.cs @@ -0,0 +1,19 @@ +using System; +using System.Globalization; +using MvvmCross.Converters; + +namespace QuickLayout.Mac.Converters +{ + public class FloatToIntConverter : MvxValueConverter + { + protected override int Convert(float value, Type targetType, object parameter, CultureInfo culture) + { + return (int)value; + } + + protected override float ConvertBack(int value, Type targetType, object parameter, CultureInfo culture) + { + return value; + } + } +} diff --git a/QuickLayout.Mac/Converters/FloatToNFloatConverter.cs b/QuickLayout.Mac/Converters/FloatToNFloatConverter.cs new file mode 100644 index 0000000..ff1141a --- /dev/null +++ b/QuickLayout.Mac/Converters/FloatToNFloatConverter.cs @@ -0,0 +1,14 @@ +using System; +using System.Globalization; +using MvvmCross.Converters; + +namespace QuickLayout.Mac.Converters +{ + public class FloatToNFloatConverter : MvxValueConverter + { + public override object Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + return new nfloat((float)value); + } + } +} diff --git a/QuickLayout.Mac/Entitlements.plist b/QuickLayout.Mac/Entitlements.plist new file mode 100644 index 0000000..9ae5993 --- /dev/null +++ b/QuickLayout.Mac/Entitlements.plist @@ -0,0 +1,6 @@ + + + + + + diff --git a/QuickLayout.Mac/Info.plist b/QuickLayout.Mac/Info.plist new file mode 100644 index 0000000..71dd39a --- /dev/null +++ b/QuickLayout.Mac/Info.plist @@ -0,0 +1,30 @@ + + + + + CFBundleName + QuickLayout.Mac + CFBundleIdentifier + com.quicklayout.QuickLayout-Mac + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSMinimumSystemVersion + 10.14 + CFBundleDevelopmentRegion + en + CFBundleInfoDictionaryVersion + 6.0 + CFBundlePackageType + APPL + CFBundleSignature + ???? + NSHumanReadableCopyright + ${AuthorCopyright:HtmlEncode} + NSPrincipalClass + NSApplication + XSAppIconAssets + Assets.xcassets/AppIcon.appiconset + + diff --git a/QuickLayout.Mac/LinkerPleaseInclude.cs b/QuickLayout.Mac/LinkerPleaseInclude.cs new file mode 100644 index 0000000..7fe8da4 --- /dev/null +++ b/QuickLayout.Mac/LinkerPleaseInclude.cs @@ -0,0 +1,122 @@ +using System; +using System.Collections.Specialized; +using System.Windows.Input; +using AppKit; +using CoreGraphics; +using Foundation; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Navigation; +using MvvmCross.Platforms.Mac.Views; +using MvvmCross.ViewModels; + +namespace QuickLayout.Mac +{ + // This class is never actually executed, but when Xamarin linking is enabled it does ensure types and properties + // are preserved in the deployed app + [Foundation.Preserve(AllMembers = true)] + public class LinkerPleaseInclude + { + public void Include(MvxTaskBasedBindingContext c) + { + c.Dispose(); + var c2 = new MvxTaskBasedBindingContext(); + c2.Dispose(); + } + + public void Include(NSButton uiButton) + { + uiButton.Activated += (s, e) => uiButton.Title = uiButton.Title; + } + + //public void Include(NSBarButtonItem barButton) + //{ + // barButton.Clicked += (s, e) => + // barButton.Title = barButton.Title + ""; + //} + + public void Include(NSTextField textField) + { + textField.StringValue = textField.StringValue + ""; + textField.EditingBegan += (sender, args) => { textField.StringValue = ""; }; + textField.EditingEnded += (sender, args) => { textField.StringValue = ""; }; + } + + public void Include(NSTextView textView) + { + textView.Value = textView.Value + ""; + textView.TextStorage.DidProcessEditing += (sender, e) => textView.Value = ""; + textView.TextDidChange += (sender, args) => { textView.Value = ""; }; + } + + public void Include(NSImageView imageView) + { + imageView.Image = new NSImage(imageView.Image.CGImage, new CGSize(2, 2)); + } + + public void Include(NSDatePicker date) + { + date.DateValue = date.DateValue.AddSeconds(1); + date.Activated += (sender, args) => { date.DateValue = NSDate.DistantFuture; }; + } + + public void Include(NSSlider slider) + { + slider.DoubleValue = slider.DoubleValue + 1; + slider.Activated += (sender, args) => { slider.DoubleValue = 1; }; + } + + public void Include(MvxViewController vc) + { + vc.Title = vc.Title + ""; + } + + public void Include(NSStepper s) + { + s.IntValue = s.IntValue + 1; + s.Activated += (sender, args) => { s.IntValue = 0; }; + } + + public void Include(INotifyCollectionChanged changed) + { + changed.CollectionChanged += (s, e) => { var test = $"{e.Action}{e.NewItems}{e.NewStartingIndex}{e.OldItems}{e.OldStartingIndex}"; }; + } + + public void Include(ICommand command) + { + command.CanExecuteChanged += (s, e) => { if (command.CanExecute(null)) command.Execute(null); }; + } + + public void Include(MvvmCross.IoC.MvxPropertyInjector injector) + { + injector = new MvvmCross.IoC.MvxPropertyInjector(); + } + + public void Include(System.ComponentModel.INotifyPropertyChanged changed) + { + changed.PropertyChanged += (sender, e) => { var test = e.PropertyName; }; + } + + public void Include(MvxNavigationService service, IMvxViewModelLoader loader) + { + service = new MvxNavigationService(null, loader); + } + + public void Include(ConsoleColor color) + { + Console.Write(""); + Console.WriteLine(""); + color = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Red; + Console.ForegroundColor = ConsoleColor.Yellow; + Console.ForegroundColor = ConsoleColor.Magenta; + Console.ForegroundColor = ConsoleColor.White; + Console.ForegroundColor = ConsoleColor.Gray; + Console.ForegroundColor = ConsoleColor.DarkGray; + } + + public void Include(MvvmCross.Plugin.MethodBinding.Plugin p) + { + var _ = p; + } + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Main.cs b/QuickLayout.Mac/Main.cs new file mode 100644 index 0000000..efa4a28 --- /dev/null +++ b/QuickLayout.Mac/Main.cs @@ -0,0 +1,14 @@ +using AppKit; + +namespace QuickLayout.Mac +{ + static class MainClass + { + static void Main(string[] args) + { + NSApplication.Init(); + NSApplication.SharedApplication.Delegate = new AppDelegate(); + NSApplication.Main(args); + } + } +} diff --git a/QuickLayout.Mac/QuickLayout.Mac.csproj b/QuickLayout.Mac/QuickLayout.Mac.csproj new file mode 100644 index 0000000..fbaa5cc --- /dev/null +++ b/QuickLayout.Mac/QuickLayout.Mac.csproj @@ -0,0 +1,125 @@ + + + + Debug + AnyCPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3} + {A3F8F2AB-B479-4A4A-A458-A89E7DC349F1};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + Exe + QuickLayout.Mac + QuickLayout.Mac + v2.0 + Xamarin.Mac + Resources + + + true + full + false + bin\Debug + DEBUG; + prompt + 4 + false + Mac Developer + false + false + false + true + true + + + + + + pdbonly + true + bin\Release + + prompt + 4 + false + true + false + true + true + true + SdkOnly + + + + + PackageReference + + + + + + + + + + + + 6.4.0 + + + 6.4.0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {849AFB57-994A-42D9-A786-EF34FC951CDE} + QuickLayout.Core + + + {75D2DA9D-DFD4-49A1-98FB-FE0F0677EF0F} + Cirrious.FluentLayouts.Touch + + + + \ No newline at end of file diff --git a/QuickLayout.Mac/Views/AdvancedVerticalStackView.cs b/QuickLayout.Mac/Views/AdvancedVerticalStackView.cs new file mode 100644 index 0000000..764e7ef --- /dev/null +++ b/QuickLayout.Mac/Views/AdvancedVerticalStackView.cs @@ -0,0 +1,98 @@ +using System.Collections.Generic; +using System.Reflection; +using AppKit; +using Cirrious.FluentLayouts.Touch; +using CoreGraphics; +using Foundation; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Mac.Views +{ + [Register("AdvancedVerticalStackView")] + public class AdvancedVerticalStackView : MvxViewController + { + public override void LoadView() + { + var scrollView = new NSScrollView(new CGRect(0, 0, 1000, 1000)) + { + BackgroundColor = NSColor.White, + HasHorizontalScroller = false, + AutoresizingMask = NSViewResizingMask.HeightSizable, + }; + View = scrollView; + + var container = new FlippedView(scrollView.ContentView.Bounds) + { + TranslatesAutoresizingMaskIntoConstraints = false + }; + scrollView.DocumentView = container; + + var set = this.CreateBindingSet(); + + var topMargins = new List(); + var leftMargins = new List(); + var rightMargins = new List(); + + foreach (var propertyInfo in typeof(DetailsViewModel).GetProperties(BindingFlags.Instance | BindingFlags.Public)) + { + if (propertyInfo.PropertyType != typeof(string)) + continue; + + topMargins.Add(20); + leftMargins.Add(0); + rightMargins.Add(0); + var introLabel = new NSTextField + { + StringValue = propertyInfo.Name + ":", + Editable = false, + TranslatesAutoresizingMaskIntoConstraints = false, + }; + container.AddSubview(introLabel); + + topMargins.Add(0); + leftMargins.Add(25); + rightMargins.Add(25); + var textField = new NSTextField + { + TranslatesAutoresizingMaskIntoConstraints = false, + BackgroundColor = NSColor.LightGray + }; + container.AddSubview(textField); + + topMargins.Add(0); + leftMargins.Add(40); + rightMargins.Add(40); + var label = new NSTextField + { + TranslatesAutoresizingMaskIntoConstraints = false, + Editable = false, + BackgroundColor = NSColor.Yellow, + Alignment = NSTextAlignment.Center + }; + container.AddSubview(label); + + set.Bind(label).To(propertyInfo.Name); + set.Bind(textField).To(propertyInfo.Name); + } + set.Apply(); + + scrollView.ContentView.AddConstraints( + container.AtTopOf(scrollView.ContentView), + container.AtLeftOf(scrollView.ContentView), + container.AtRightOf(scrollView.ContentView) + ); + + var constraints = container.AdvancedVerticalStackPanelConstraints( + new Margins(20, 10, 20, 10, 5, 5), + leftMargins.ToArray(), + topMargins.ToArray(), + rightMargins.ToArray(), + 1, + container.Subviews); + container.AddConstraints(constraints); + } + } +} + diff --git a/QuickLayout.Mac/Views/DetailsView.cs b/QuickLayout.Mac/Views/DetailsView.cs new file mode 100644 index 0000000..3ca254e --- /dev/null +++ b/QuickLayout.Mac/Views/DetailsView.cs @@ -0,0 +1,75 @@ +using System.Reflection; +using AppKit; +using Cirrious.FluentLayouts.Touch; +using CoreGraphics; +using Foundation; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Mac.Views +{ + [Register("DetailsView")] + public class DetailsView : MvxViewController + { + public override void LoadView() + { + var scrollView = new NSScrollView(new CGRect(0, 0, 1000, 1000)) + { + BackgroundColor = NSColor.White, + HasHorizontalScroller = false, + AutoresizingMask = NSViewResizingMask.HeightSizable, + }; + View = scrollView; + + var container = new FlippedView(scrollView.ContentView.Bounds) + { + TranslatesAutoresizingMaskIntoConstraints = false + }; + scrollView.DocumentView = container; + + var set = this.CreateBindingSet(); + + foreach (var propertyInfo in typeof(DetailsViewModel).GetProperties(BindingFlags.Instance | BindingFlags.Public)) + { + if (propertyInfo.PropertyType != typeof(string)) + continue; + + var introLabel = new NSTextField + { + StringValue = propertyInfo.Name + ":", + TranslatesAutoresizingMaskIntoConstraints = false, + Editable = false + }; + container.AddSubview(introLabel); + var textField = new NSTextField + { + TranslatesAutoresizingMaskIntoConstraints = false, + BackgroundColor = NSColor.LightGray + }; + container.AddSubview(textField); + var label = new NSTextField + { + TranslatesAutoresizingMaskIntoConstraints = false, + BackgroundColor = NSColor.Yellow + }; + container.AddSubview(label); + + set.Bind(label).To(propertyInfo.Name); + set.Bind(textField).To(propertyInfo.Name); + } + set.Apply(); + + var constraints = container.VerticalStackPanelConstraints( + new Margins(20, 10, 20, 10, 5, 5), + container.Subviews); + container.AddConstraints(constraints); + + scrollView.ContentView.AddConstraints( + container.AtTopOf(scrollView.ContentView), + container.AtLeftOf(scrollView.ContentView), + container.AtRightOf(scrollView.ContentView) + ); + } + } +} diff --git a/QuickLayout.Mac/Views/DirectionFormView.cs b/QuickLayout.Mac/Views/DirectionFormView.cs new file mode 100644 index 0000000..8b83b94 --- /dev/null +++ b/QuickLayout.Mac/Views/DirectionFormView.cs @@ -0,0 +1,74 @@ +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Foundation; +using MvvmCross.Platforms.Mac.Views; + +namespace QuickLayout.Mac.Views +{ + [Register("DirectionFormView")] + public class DirectionFormView : MvxViewController + { + public override void LoadView() + { + View = new NSView(); + + var east = new NSTextField { Editable = false, StringValue = "East" }; + View.AddSubview(east); + + var west = new NSTextField { Editable = false, StringValue = "West" }; + View.AddSubview(west); + + var north = new NSTextField { Editable = false, StringValue = "North" }; + View.AddSubview(north); + + var south = new NSTextField { Editable = false, StringValue = "South" }; + View.AddSubview(south); + + var northEast = new NSTextField { Editable = false, StringValue = "NorthEast" }; + View.AddSubview(northEast); + + var northWest = new NSTextField { Editable = false, StringValue = "NorthWest" }; + View.AddSubview(northWest); + + var southEast = new NSTextField { Editable = false, StringValue = "SouthEast" }; + View.AddSubview(southEast); + + var southWest = new NSTextField { Editable = false, StringValue = "SouthWest" }; + View.AddSubview(southWest); + + var center = new NSTextField { Editable = false, StringValue = "Center" }; + View.AddSubview(center); + + View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + View.AddConstraints( + west.AtLeftOf(View), //.ToLeftMargin(View), + west.WithSameCenterY(View), + + east.AtRightOf(View),//.ToRightMargin(View), + east.WithSameCenterY(View), + + north.AtTopOf(View),//.ToTopMargin(View), + north.WithSameCenterX(View), + + south.AtBottomOf(View),//.ToBottomMargin(View), + south.WithSameCenterX(View), + + northWest.AtLeftOf(View), //.ToLeftMargin(View), + northWest.AtTopOf(View), //ToTopMargin(View), + + northEast.AtRightOf(View),//.ToRightMargin(View), + northEast.AtTopOf(View), //.ToTopMargin(View), + + southWest.AtLeftOf(View), //.ToLeftMargin(View), + southWest.AtBottomOf(View), //.ToBottomMargin(View), + + southEast.AtRightOf(View), //.ToRightMargin(View), + southEast.AtBottomOf(View), //.ToBottomMargin(View), + + center.WithSameCenterX(View), + center.WithSameCenterY(View) + ); + } + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Views/FirstView.cs b/QuickLayout.Mac/Views/FirstView.cs new file mode 100644 index 0000000..5518601 --- /dev/null +++ b/QuickLayout.Mac/Views/FirstView.cs @@ -0,0 +1,87 @@ +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Foundation; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Presenters.Attributes; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Mac.Views +{ + [Register("FirstView")] + [MvxWindowPresentation] + public class FirstView : MvxViewController + { + private NSButton _viewForm, _viewFormGrid, _viewDetails, _viewSearch, _viewTip, _viewUpdateConstaints, _viewAdvancedVerticalStack, _fullSize, _directionFormView, _rightToLeft, _viewCenterConstraints; + + public override void LoadView() + { + View = new NSView(); + + _viewForm = new NSButton(); + _viewForm.Title = "Form"; + View.AddSubview(_viewForm); + + _viewFormGrid = new NSButton(); + _viewFormGrid.Title = "FormGrid"; + View.AddSubview(_viewFormGrid); + + _viewDetails = new NSButton(); + _viewDetails.Title = "Details"; + View.AddSubview(_viewDetails); + + _viewSearch = new NSButton(); + _viewSearch.Title = "Search"; + View.AddSubview(_viewSearch); + + _viewTip = new NSButton(); + _viewTip.Title = "Tip"; + View.AddSubview(_viewTip); + + _viewUpdateConstaints = new NSButton(); + _viewUpdateConstaints.Title = "Update Live Constraints"; + View.AddSubview(_viewUpdateConstaints); + + _viewAdvancedVerticalStack = new NSButton(); + _viewAdvancedVerticalStack.Title = "Advanced Vertical Stack Panel"; + View.AddSubview(_viewAdvancedVerticalStack); + + _fullSize = new NSButton(); + _fullSize.Title = "Full Size (animated)"; + View.AddSubview(_fullSize); + + _directionFormView = new NSButton(); + _directionFormView.Title = "Directions"; + View.AddSubview(_directionFormView); + + _rightToLeft = new NSButton(); + _rightToLeft.Title = "Right-To-Left Support"; + View.AddSubview(_rightToLeft); + + _viewCenterConstraints = new NSButton(); + _viewCenterConstraints.Title = "View Contraining to centers"; + View.AddSubview(_viewCenterConstraints); + + View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + var set = this.CreateBindingSet(); + set.Bind(_viewForm).To("GoForm"); + set.Bind(_viewFormGrid).To("GoFormGrid"); + set.Bind(_viewDetails).To("GoDetails"); + set.Bind(_viewSearch).To("GoSearch"); + set.Bind(_viewTip).To("GoTip"); + set.Bind(_viewUpdateConstaints).To("GoUpdateConstraints"); + set.Bind(_viewAdvancedVerticalStack).To("GoAdvancedVerticalStack"); + set.Bind(_fullSize).To("GoFullSize"); + set.Bind(_directionFormView).To("GoDirectionForm"); + set.Bind(_rightToLeft).To("GoRightToLeft"); + set.Bind(_viewCenterConstraints).To("GoCenterConstraints"); + set.Apply(); + + var constraints = View.VerticalStackPanelConstraints( + new Margins(20, 10, 20, 10, 5, 5), + View.Subviews); + View.AddConstraints(constraints); + } + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Views/FlippedView.cs b/QuickLayout.Mac/Views/FlippedView.cs new file mode 100644 index 0000000..7fb80d5 --- /dev/null +++ b/QuickLayout.Mac/Views/FlippedView.cs @@ -0,0 +1,32 @@ +using System; +using AppKit; +using CoreGraphics; +using Foundation; + +namespace QuickLayout.Mac.Views +{ + public class FlippedView : NSView + { + public FlippedView() + { + } + + public FlippedView(NSCoder coder) : base(coder) + { + } + + public FlippedView(CGRect frameRect) : base(frameRect) + { + } + + protected FlippedView(NSObjectFlag t) : base(t) + { + } + + protected internal FlippedView(IntPtr handle) : base(handle) + { + } + + public override bool IsFlipped => true; + } +} diff --git a/QuickLayout.Mac/Views/FormGridView.cs b/QuickLayout.Mac/Views/FormGridView.cs new file mode 100644 index 0000000..e40c05b --- /dev/null +++ b/QuickLayout.Mac/Views/FormGridView.cs @@ -0,0 +1,135 @@ +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Cirrious.FluentLayouts.Touch.RowSet; +using CoreGraphics; +using Foundation; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Mac.Views +{ + [Register("FormGridView")] + public class FormGridView : MvxViewController + { + private NSTextField _debugLabel; + + public override void LoadView() + { + var scrollView = new NSScrollView(new CGRect(0, 0, 1000, 1000)) + { + BackgroundColor = NSColor.White, + HasHorizontalScroller = false, + AutoresizingMask = NSViewResizingMask.HeightSizable, + }; + View = scrollView; + + var container = new FlippedView(scrollView.ContentView.Bounds) + { + TranslatesAutoresizingMaskIntoConstraints = false + }; + scrollView.DocumentView = container; + + var _forceTheWidthView = new NSView(); + container.AddSubview(_forceTheWidthView); + + var fNameLabel = new NSTextField { StringValue = "First", Editable = false }; + container.AddSubview(fNameLabel); + + var sNameLabel = new NSTextField { StringValue = "Last", Editable = false }; + container.AddSubview(sNameLabel); + + var numberLabel = new NSTextField { StringValue = "#", Editable = false }; + container.AddSubview(numberLabel); + + var streetLabel = new NSTextField { StringValue = "Street", Editable = false }; + container.AddSubview(streetLabel); + + var townLabel = new NSTextField { StringValue = "Town", Editable = false }; + container.AddSubview(townLabel); + + var zipLabel = new NSTextField { StringValue = "Zip", Editable = false }; + container.AddSubview(zipLabel); + + var fNameField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + container.AddSubview(fNameField); + + var sNameField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + container.AddSubview(sNameField); + + var numberField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + container.AddSubview(numberField); + + var streetField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + container.AddSubview(streetField); + + var townField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + container.AddSubview(townField); + + var zipField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + container.AddSubview(zipField); + + _debugLabel = new NSTextField() { BackgroundColor = NSColor.White, MaximumNumberOfLines = 0, LineBreakMode = NSLineBreakMode.ByWordWrapping }; + container.AddSubview(_debugLabel); + + var set = this.CreateBindingSet(); + set.Bind(fNameField).To(vm => vm.FirstName); + set.Bind(sNameField).To(vm => vm.LastName); + set.Bind(numberField).To(vm => vm.Number); + set.Bind(streetField).To(vm => vm.Street); + set.Bind(townField).To(vm => vm.Town); + set.Bind(zipField).To(vm => vm.Zip); + set.Bind(_debugLabel).To("FirstName + ' ' + LastName + ', ' + Number + ' ' + Street + ' ' + Town + ' ' + Zip"); + set.Apply(); + + View = container; + container.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + var rowSet = new RowSetTemplate() + { + TopMargin = 10f, + BottomMargin = 20f, + VInterspacing = 10f + }; + var equalWeightRowTemplate = new RowTemplate() + { + HInterspacing = 12f, + LeftMargin = 6f, + RightMargin = 24f + }; + var addressRowTemplate = new RowTemplate() + { + HInterspacing = 12f, + LeftMargin = 6f, + RightMargin = 24f + }; + addressRowTemplate.ColumnWeight(0, 0.3f); + var townAndZipRowTemplate = new RowTemplate() + { + HInterspacing = 12f, + LeftMargin = 6f, + RightMargin = 24f + }; + townAndZipRowTemplate.ColumnWidth(1, 120f); + + scrollView.ContentView.AddConstraints( + container.AtTopOf(scrollView.ContentView), + container.AtLeftOf(scrollView.ContentView), + container.AtRightOf(scrollView.ContentView) + ); + + container.AddConstraints( + rowSet.Generate(View, + new Row(equalWeightRowTemplate, _forceTheWidthView), + new Row(equalWeightRowTemplate, fNameLabel, sNameLabel), + new Row(equalWeightRowTemplate, fNameField, sNameField), + new Row(addressRowTemplate, numberLabel, streetLabel), + new Row(addressRowTemplate, numberField, streetField), + new Row(townAndZipRowTemplate, townLabel, zipLabel), + new Row(townAndZipRowTemplate, townField, zipField), + new Row(equalWeightRowTemplate, _debugLabel) + )); + container.AddConstraints(_forceTheWidthView.Width().EqualTo().WidthOf(container).Minus(30f)); + } + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Views/FormView.cs b/QuickLayout.Mac/Views/FormView.cs new file mode 100644 index 0000000..d04ff58 --- /dev/null +++ b/QuickLayout.Mac/Views/FormView.cs @@ -0,0 +1,128 @@ +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Foundation; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Mac.Views +{ + [Register("FormView")] + public class FormView : MvxViewController + { + public override void LoadView() + { + View = new NSView(); + + var fNameLabel = new NSTextField { StringValue = "First", Editable = false }; + View.AddSubview(fNameLabel); + + var sNameLabel = new NSTextField { StringValue = "Last", Editable = false }; + View.AddSubview(sNameLabel); + + var numberLabel = new NSTextField { StringValue = "#", Editable = false }; + View.AddSubview(numberLabel); + + var streetLabel = new NSTextField { StringValue = "Street", Editable = false }; + View.AddSubview(streetLabel); + + var townLabel = new NSTextField { StringValue = "Town", Editable = false }; + View.AddSubview(townLabel); + + var zipLabel = new NSTextField { StringValue = "Zip", Editable = false }; + View.AddSubview(zipLabel); + + var fNameField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(fNameField); + + var sNameField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(sNameField); + + var numberField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(numberField); + + var streetField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(streetField); + + var townField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(townField); + + var zipField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(zipField); + + var debug = new NSTextField() { BackgroundColor = NSColor.White, MaximumNumberOfLines = 0 }; + View.AddSubview(debug); + + var set = this.CreateBindingSet(); + set.Bind(fNameField).To(vm => vm.FirstName); + set.Bind(sNameField).To(vm => vm.LastName); + set.Bind(numberField).To(vm => vm.Number); + set.Bind(streetField).To(vm => vm.Street); + set.Bind(townField).To(vm => vm.Town); + set.Bind(zipField).To(vm => vm.Zip); + set.Bind(debug).To("FirstName + ' ' + LastName + ', ' + Number + ' ' + Street + ' ' + Town + ' ' + Zip"); + set.Apply(); + + View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + var hMargin = 10; + var vMargin = 10; + + View.AddConstraints( + + fNameLabel.AtTopOf(View, vMargin), + fNameLabel.AtLeftOf(View, hMargin), + fNameLabel.ToLeftOf(sNameLabel, hMargin), + + sNameLabel.WithSameTop(fNameLabel), + sNameLabel.AtRightOf(View, hMargin), + sNameLabel.WithSameWidth(fNameLabel), + + fNameField.WithSameWidth(fNameLabel), + fNameField.WithSameLeft(fNameLabel), + fNameField.Below(fNameLabel, vMargin), + + sNameField.WithSameLeft(sNameLabel), + sNameField.WithSameWidth(sNameLabel), + sNameField.WithSameTop(fNameField), + + numberLabel.WithSameLeft(fNameLabel), + numberLabel.ToLeftOf(streetLabel, hMargin), + numberLabel.Below(fNameField, vMargin), + numberLabel.WithRelativeWidth(streetLabel, 0.3f), + + streetLabel.WithSameTop(numberLabel), + streetLabel.AtRightOf(View, hMargin), + + numberField.WithSameLeft(numberLabel), + numberField.WithSameWidth(numberLabel), + numberField.Below(numberLabel, vMargin), + + streetField.WithSameLeft(streetLabel), + streetField.WithSameWidth(streetLabel), + streetField.WithSameTop(numberField), + + townLabel.WithSameLeft(fNameLabel), + townLabel.WithSameRight(streetLabel), + townLabel.Below(numberField, vMargin), + + townField.WithSameLeft(townLabel), + townField.WithSameWidth(townLabel), + townField.Below(townLabel, vMargin), + + zipLabel.WithSameLeft(fNameLabel), + zipLabel.WithSameWidth(townLabel), + zipLabel.Below(townField, vMargin), + + zipField.WithSameLeft(townLabel), + zipField.WithSameWidth(zipLabel), + zipField.Below(zipLabel, vMargin), + + debug.WithSameLeft(townLabel), + debug.WithSameWidth(zipLabel), + debug.AtBottomOf(View, vMargin) + + ); + } + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Views/FullSizeView.cs b/QuickLayout.Mac/Views/FullSizeView.cs new file mode 100644 index 0000000..c91cdcb --- /dev/null +++ b/QuickLayout.Mac/Views/FullSizeView.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Cirrious.FluentLayouts.Touch.Extensions; +using Foundation; +using MvvmCross.Platforms.Mac.Views; + +namespace QuickLayout.Mac.Views +{ + [Register("FullSizeView")] + public class FullSizeView : MvxViewController + { + private IEnumerable _cyanLayouts; + + public override void LoadView() + { + View = new NSView(); + + var cyan = new NSColoredView(NSColor.Cyan); + var red = new NSColoredView(NSColor.Red); + var yellow = new NSColoredView(NSColor.Yellow); + var brown = new NSColoredView(NSColor.Brown); + var green = new NSColoredView(NSColor.Green); + var clickMe = new NSTextField { StringValue = "Tap me", Alignment = NSTextAlignment.Center, Editable = false }; + + View.AddSubviews(cyan, red, yellow, brown, green, clickMe); + View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + _cyanLayouts = cyan.FullSizeOf(View, 20); + + View.AddConstraints(_cyanLayouts); + View.AddConstraints(red.FullSizeOf(cyan, new Margins(10, 30))); + View.AddConstraints(yellow.FullSizeOf(red, 5)); + View.AddConstraints(brown.FullSizeOf(yellow, new Margins(20, 40, 50, 10))); + View.AddConstraints(green.FullSizeOf(brown, 10)); + View.AddConstraints( + clickMe.WithSameCenterX(green), + clickMe.WithSameCenterY(green) + ); + + View.AddGestureRecognizer(new NSClickGestureRecognizer(AnimateRandom)); + } + + private void AnimateRandom() + { + var random = new Random(); + + NSAnimationContext.RunAnimation(context => + { + context.Duration = 0.3; + context.AllowsImplicitAnimation = true; + + _cyanLayouts.GetLayoutById("Top").Constant = random.Next(5, 150); + _cyanLayouts.GetLayoutById("Bottom").Constant = random.Next(-150, -5); + _cyanLayouts.GetLayoutById("Left").Constant = random.Next(5, 50); + _cyanLayouts.GetLayoutById("Right").Constant = random.Next(-50, -5); + + View.LayoutSubtreeIfNeeded(); + }); + } + } +} diff --git a/QuickLayout.Mac/Views/NSColoredView.cs b/QuickLayout.Mac/Views/NSColoredView.cs new file mode 100644 index 0000000..68f08a5 --- /dev/null +++ b/QuickLayout.Mac/Views/NSColoredView.cs @@ -0,0 +1,13 @@ +using AppKit; + +namespace QuickLayout.Mac.Views +{ + public class NSColoredView : NSView + { + public NSColoredView(NSColor color) + { + this.WantsLayer = true; + this.Layer.BackgroundColor = color.CGColor; + } + } +} diff --git a/QuickLayout.Mac/Views/RightToLeftView.cs b/QuickLayout.Mac/Views/RightToLeftView.cs new file mode 100644 index 0000000..0f08ad5 --- /dev/null +++ b/QuickLayout.Mac/Views/RightToLeftView.cs @@ -0,0 +1,145 @@ +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Foundation; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Mac.Views +{ + [Register("RightToLeftView")] + public class RightToLeftView : MvxViewController + { + public RightToLeftView() + { + // TODO: Implement RTL + //SetRTL(false); + } + + public override void LoadView() + { + View = new NSView(); + + var fNameLabel = new NSTextField { Editable = false, StringValue = "First" }; + View.AddSubview(fNameLabel); + + var sNameLabel = new NSTextField { Editable = false, StringValue = "Last" }; + View.AddSubview(sNameLabel); + + var numberLabel = new NSTextField { Editable = false, StringValue = "#" }; + View.AddSubview(numberLabel); + + var streetLabel = new NSTextField { Editable = false, StringValue = "Street" }; + View.AddSubview(streetLabel); + + var townLabel = new NSTextField { Editable = false, StringValue = "Town" }; + View.AddSubview(townLabel); + + var zipLabel = new NSTextField { Editable = false, StringValue = "Zip" }; + View.AddSubview(zipLabel); + + var fNameField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(fNameField); + + var sNameField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(sNameField); + + var numberField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(numberField); + + var streetField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(streetField); + + var townField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(townField); + + var zipField = new NSTextField() { BackgroundColor = NSColor.LightGray }; + View.AddSubview(zipField); + + var debug = new NSTextField { Editable = false, BackgroundColor = NSColor.White, MaximumNumberOfLines = 0 }; + View.AddSubview(debug); + + var set = this.CreateBindingSet(); + set.Bind(fNameField).To(vm => vm.FirstName); + set.Bind(sNameField).To(vm => vm.LastName); + set.Bind(numberField).To(vm => vm.Number); + set.Bind(streetField).To(vm => vm.Street); + set.Bind(townField).To(vm => vm.Town); + set.Bind(zipField).To(vm => vm.Zip); + set.Bind(debug).To("FirstName + ' ' + LastName + ', ' + Number + ' ' + Street + ' ' + Town + ' ' + Zip"); + set.Apply(); + + View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + var hMargin = 10; + var vMargin = 10; + + + View.AddConstraints( + + fNameLabel.AtTopOf(View, vMargin), + fNameLabel.AtLeadingOf(View, hMargin), + fNameLabel.ToLeadingOf(sNameLabel, hMargin), + + sNameLabel.WithSameTop(fNameLabel), + sNameLabel.AtTrailingOf(View, hMargin), + sNameLabel.WithSameWidth(fNameLabel), + + fNameField.WithSameWidth(fNameLabel), + fNameField.WithSameLeading(fNameLabel), + fNameField.Below(fNameLabel, vMargin), + + sNameField.WithSameLeading(sNameLabel), + sNameField.WithSameWidth(sNameLabel), + sNameField.WithSameTop(fNameField), + + numberLabel.WithSameLeading(fNameLabel), + numberLabel.ToLeadingOf(streetLabel, hMargin), + numberLabel.Below(fNameField, vMargin), + numberLabel.WithRelativeWidth(streetLabel, 0.3f), + + streetLabel.WithSameTop(numberLabel), + streetLabel.AtTrailingOf(View, hMargin), + + numberField.WithSameLeading(numberLabel), + numberField.WithSameWidth(numberLabel), + numberField.Below(numberLabel, vMargin), + + streetField.WithSameLeading(streetLabel), + streetField.WithSameWidth(streetLabel), + streetField.WithSameTop(numberField), + + townLabel.WithSameLeading(fNameLabel), + townLabel.WithSameTrailing(streetLabel), + townLabel.Below(numberField, vMargin), + + townField.WithSameLeading(townLabel), + townField.WithSameWidth(townLabel), + townField.Below(townLabel, vMargin), + + zipLabel.WithSameLeading(fNameLabel), + zipLabel.WithSameWidth(townLabel), + zipLabel.Below(townField, vMargin), + + zipField.WithSameLeading(townLabel), + zipField.WithSameWidth(zipLabel), + zipField.Below(zipLabel, vMargin), + + debug.WithSameLeading(townLabel), + debug.WithSameWidth(zipLabel), + debug.AtBottomOf(View, vMargin) + + ); + } + + // TODO: implement RTL + //[DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")] + //internal extern static IntPtr IntPtr_objc_msgSend(IntPtr receiver, IntPtr selector, NSSemanticContentAttribute arg1); + + //private static void SetRTL(bool isRTL) + //{ + // Selector selector = new Selector("setSemanticContentAttribute:"); + // IntPtr_objc_msgSend(NSView.Appearance.Handle, selector.Handle, isRTL ? NSSemanticContentAttribute.ForceRightToLeft : NSSemanticContentAttribute.ForceLeftToRight); + //} + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Views/SearchView.cs b/QuickLayout.Mac/Views/SearchView.cs new file mode 100644 index 0000000..46eae73 --- /dev/null +++ b/QuickLayout.Mac/Views/SearchView.cs @@ -0,0 +1,48 @@ +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Foundation; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Mac.Views +{ + [Register("SearchView")] + public class SearchView : MvxViewController + { + public override void LoadView() + { + View = new NSView(); + + var button = new NSButton(); + button.Title = "Search"; + View.AddSubview(button); + + var text = new NSTextField(); + View.AddSubview(text); + + View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + var set = this.CreateBindingSet(); + set.Bind(button).To("Search"); + set.Bind(text).To(vm => vm.SearchText); + set.Apply(); + + var hPadding = 10; + var vPadding = 10; + var ButtonWidth = 100; + + View.AddConstraints( + + button.AtTopOf(View).Plus(vPadding), + button.AtRightOf(View).Minus(hPadding), + button.Width().EqualTo(ButtonWidth), + + text.AtLeftOf(View, hPadding), + text.ToLeftOf(button, hPadding), + text.WithSameTop(button) + + ); + } + } +} diff --git a/QuickLayout.Mac/Views/TipView.cs b/QuickLayout.Mac/Views/TipView.cs new file mode 100644 index 0000000..ddd51ba --- /dev/null +++ b/QuickLayout.Mac/Views/TipView.cs @@ -0,0 +1,73 @@ +using Cirrious.FluentLayouts.Touch; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Views; +using Foundation; +using AppKit; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Touch.Views +{ + [Register("TipView")] + public class TipView : MvxViewController + { + public override void LoadView() + { + View = new NSView(); + + var subTotal = new NSTextField(); + var numberFormatter = new NSNumberFormatter(); + numberFormatter.NumberStyle = NSNumberFormatterStyle.Decimal; + subTotal.Formatter = numberFormatter; + View.AddSubview(subTotal); + + var seek = new NSSlider() + { + MinValue = 0, + MaxValue = 100, + }; + View.AddSubview(seek); + + var seekLabel = new NSTextField { Editable = false }; + View.AddSubview(seekLabel); + + var tipLabel = new NSTextField { Editable = false }; + View.AddSubview(tipLabel); + + var totalLabel = new NSTextField { Editable = false }; + View.AddSubview(totalLabel); + + var set = this.CreateBindingSet(); + set.Bind(subTotal).To(vm => vm.SubTotal); + set.Bind(seek).To(vm => vm.Generosity); + set.Bind(seekLabel).To(vm => vm.Generosity); + set.Bind(tipLabel).To(vm => vm.Tip); + set.Bind(totalLabel).To("SubTotal + Tip"); + set.Apply(); + + View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + var margin = 10; + View.AddConstraints( + subTotal.AtLeftOf(View, margin), + subTotal.AtTopOf(View, margin), + subTotal.AtRightOf(View, margin), + + seek.WithSameLeft(subTotal), + seek.Below(subTotal, margin), + seek.ToLeftOf(seekLabel, margin), + seek.WithRelativeWidth(seekLabel, 3), + + seekLabel.WithSameRight(subTotal), + seekLabel.WithSameTop(seek), + + tipLabel.Below(seek, margin), + tipLabel.WithSameLeft(seek), + tipLabel.WithSameWidth(totalLabel), + + totalLabel.WithSameTop(tipLabel), + totalLabel.ToRightOf(tipLabel, margin), + totalLabel.WithSameRight(subTotal) + ); + } + } +} \ No newline at end of file diff --git a/QuickLayout.Mac/Views/ToCenterConstraintsView.cs b/QuickLayout.Mac/Views/ToCenterConstraintsView.cs new file mode 100644 index 0000000..4777190 --- /dev/null +++ b/QuickLayout.Mac/Views/ToCenterConstraintsView.cs @@ -0,0 +1,54 @@ +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Cirrious.FluentLayouts.Touch.Extensions; +using Foundation; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; + +namespace QuickLayout.Mac.Views +{ + [Register("ToCenterConstraintsView")] + public class ToCenterConstraintsView : MvxViewController + { + public override void LoadView() + { + View = new NSView(); + + NSView firstContainer = new NSColoredView(NSColor.Blue) + { + TranslatesAutoresizingMaskIntoConstraints = false, + }, + + secondContainer = new NSColoredView(NSColor.Red) + { + TranslatesAutoresizingMaskIntoConstraints = false, + }, + + thirdContainer = new NSColoredView(NSColor.Yellow) + { + TranslatesAutoresizingMaskIntoConstraints = false, + AlphaValue = .5f + }; + + View.AddSubviews(firstContainer, secondContainer, thirdContainer); + + View.AddConstraints(new FluentLayout[] + { + firstContainer.AtTopOf(View), + firstContainer.AtLeftOf(View), + firstContainer.AboveCenterOf(View, 10f), + firstContainer.ToLeftOfCenterOf(View, 10f), + + secondContainer.AtBottomOf(View), + secondContainer.AtRightOf(View), + secondContainer.ToRightOfCenterOf(View, 10f), + secondContainer.BelowCenterOf(View, 10f), + + thirdContainer.ToRightOfCenterOf(firstContainer), + thirdContainer.ToLeftOfCenterOf(secondContainer), + thirdContainer.AboveCenterOf(secondContainer), + thirdContainer.BelowCenterOf(firstContainer) + }); + } + } +} diff --git a/QuickLayout.Mac/Views/UpdateConstraintsView.cs b/QuickLayout.Mac/Views/UpdateConstraintsView.cs new file mode 100644 index 0000000..fb3f659 --- /dev/null +++ b/QuickLayout.Mac/Views/UpdateConstraintsView.cs @@ -0,0 +1,65 @@ +using AppKit; +using Cirrious.FluentLayouts.Touch; +using Cirrious.FluentLayouts.Touch.Extensions; +using Foundation; +using MvvmCross.Binding; +using MvvmCross.Binding.BindingContext; +using MvvmCross.Platforms.Mac.Views; +using QuickLayout.Core.ViewModels; +using QuickLayout.Mac.Converters; + +namespace QuickLayout.Mac.Views +{ + [Register("UpdateConstraintsView")] + public class UpdateConstraintsView : MvxViewController + { + FluentLayout heightLayout; + + public override void LoadView() + { + View = new NSView(); + + var label = new NSTextField + { + Editable = false, + StringValue = "Update this label's height constraint height constant and active settings", + BackgroundColor = NSColor.White, + TextColor = NSColor.Black, + LineBreakMode = NSLineBreakMode.ByWordWrapping, + MaximumNumberOfLines = 0 + }; + var toggleHeight = new NSButton(); + toggleHeight.SetButtonType(NSButtonType.Switch); + + var heightConstant = new NSSlider { MinValue = 0, MaxValue = 600 }; + + View.AddSubviews(label, toggleHeight, heightConstant); + + View.SubviewsDoNotTranslateAutoresizingMaskIntoConstraints(); + + heightLayout = label.Height().EqualTo(200).WithIdentifier("foo"); + + var margin = 10; + View.AddConstraints( + heightConstant.AtTopOf(View, margin), + heightConstant.AtLeftOf(View, margin), + heightConstant.AtRightOf(View, margin), + + toggleHeight.Below(heightConstant, margin), + toggleHeight.WithSameLeft(heightConstant), + + label.AtLeftOf(View, margin), + label.Below(toggleHeight, margin), + label.AtRightOf(View, margin), + heightLayout + ); + + var set = this.CreateBindingSet(); + set.Bind(heightLayout).For(layout => layout.Active).To(vm => vm.Active); + set.Bind(heightLayout).For(layout => layout.Constant).To(vm => vm.Constant).Mode(MvxBindingMode.OneWay).WithConversion(); + set.Bind(toggleHeight).For(t => t.State).To(vm => vm.Active); + set.Bind(heightConstant).To(vm => vm.Constant).WithConversion(); + set.Apply(); + } + } +} diff --git a/QuickLayout.sln b/QuickLayout.sln index 1d5b138..1a5b596 100644 --- a/QuickLayout.sln +++ b/QuickLayout.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLayout.Touch", "QuickL EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cirrious.FluentLayouts.Touch", "Cirrious.FluentLayout\Cirrious.FluentLayouts.Touch.csproj", "{75D2DA9D-DFD4-49A1-98FB-FE0F0677EF0F}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "QuickLayout.Mac", "QuickLayout.Mac\QuickLayout.Mac.csproj", "{1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Ad-Hoc|Any CPU = Ad-Hoc|Any CPU @@ -105,6 +107,38 @@ Global {849AFB57-994A-42D9-A786-EF34FC951CDE}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU {849AFB57-994A-42D9-A786-EF34FC951CDE}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU {849AFB57-994A-42D9-A786-EF34FC951CDE}.Release|Mixed Platforms.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Ad-Hoc|Any CPU.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Ad-Hoc|Any CPU.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Ad-Hoc|iPhone.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Ad-Hoc|iPhone.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Ad-Hoc|iPhoneSimulator.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Ad-Hoc|iPhoneSimulator.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Ad-Hoc|Mixed Platforms.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Ad-Hoc|Mixed Platforms.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.AppStore|Any CPU.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.AppStore|Any CPU.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.AppStore|iPhone.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.AppStore|iPhone.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.AppStore|iPhoneSimulator.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.AppStore|iPhoneSimulator.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.AppStore|Mixed Platforms.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.AppStore|Mixed Platforms.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Debug|iPhone.ActiveCfg = Debug|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Debug|iPhone.Build.0 = Debug|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Debug|iPhoneSimulator.ActiveCfg = Debug|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Debug|iPhoneSimulator.Build.0 = Debug|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Release|Any CPU.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Release|iPhone.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Release|iPhone.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Release|iPhoneSimulator.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Release|iPhoneSimulator.Build.0 = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU + {1D3B4BBB-D676-4DA8-A237-08BEC1003FE3}.Release|Mixed Platforms.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(MonoDevelopProperties) = preSolution StartupItem = QuickLayout.Touch\QuickLayout.Touch.csproj