Merge pull request #3622 from larsbrubaker/master
New anchor selector in align
This commit is contained in:
commit
b96bd48870
8 changed files with 638 additions and 59 deletions
342
CustomWidgets/ColorPicker/RadialColorPicker.cs
Normal file
342
CustomWidgets/ColorPicker/RadialColorPicker.cs
Normal file
|
|
@ -0,0 +1,342 @@
|
|||
/*
|
||||
Copyright (c) 2018, Lars Brubaker
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Transform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.Agg.VertexSource;
|
||||
using MatterHackers.RenderOpenGl;
|
||||
using MatterHackers.RenderOpenGl.OpenGl;
|
||||
using MatterHackers.VectorMath;
|
||||
using System;
|
||||
|
||||
namespace MatterHackers.MatterControl.CustomWidgets.ColorPicker
|
||||
{
|
||||
public static class Graphics2DOverrides
|
||||
{
|
||||
public static void Ring(this Graphics2D graphics2D, Vector2 center, double radius, double width, Color color)
|
||||
{
|
||||
var ring = new Ellipse(center, radius);
|
||||
var ringStroke = new Stroke(ring, width);
|
||||
graphics2D.Render(ringStroke, color);
|
||||
}
|
||||
}
|
||||
|
||||
public class RadialColorPicker : GuiWidget
|
||||
{
|
||||
private double colorAngle = 0;
|
||||
private bool mouseDownOnRing;
|
||||
private Vector2 unitTrianglePosition = new Vector2(0, 1);
|
||||
|
||||
public RadialColorPicker()
|
||||
{
|
||||
BackgroundColor = Color.White;
|
||||
|
||||
this.Width = 100;
|
||||
this.Height = 100;
|
||||
|
||||
if (!TriangleToWidgetTransform(0).Transform(new Vector2(1, .5)).Equals(new Vector2(88, 50), .01))
|
||||
{
|
||||
//throw new Exception("Incorect transform");
|
||||
}
|
||||
if (!TriangleToWidgetTransform(0).InverseTransform(new Vector2(88, 50)).Equals(new Vector2(1, .5), .01))
|
||||
{
|
||||
//throw new Exception("Incorect transform");
|
||||
}
|
||||
if (!TriangleToWidgetTransform(0).Transform(new Vector2(0, .5)).Equals(new Vector2(23.13, 50), .01))
|
||||
{
|
||||
//throw new Exception("Incorect transform");
|
||||
}
|
||||
}
|
||||
|
||||
public bool mouseDownOnTriangle { get; private set; }
|
||||
public double RingWidth { get => Width / 10; }
|
||||
|
||||
public Color SelectedColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return ColorF.FromHSL(colorAngle / MathHelper.Tau, 1, .5).ToColor();
|
||||
}
|
||||
}
|
||||
|
||||
public Color SelectedHueColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return ColorF.FromHSL(colorAngle / MathHelper.Tau, 1, .5).ToColor();
|
||||
}
|
||||
}
|
||||
|
||||
private double InnerRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return RingRadius - RingWidth / 2;
|
||||
}
|
||||
}
|
||||
|
||||
private double RingRadius
|
||||
{
|
||||
get
|
||||
{
|
||||
return Width / 2 - RingWidth / 2 - 2;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnDraw(Graphics2D graphics2D)
|
||||
{
|
||||
var center = new Vector2(Width / 2, Height / 2);
|
||||
var radius = new Vector2(RingRadius, RingRadius);
|
||||
|
||||
// draw the big outside ring (color part)
|
||||
DrawColorRing(graphics2D, RingRadius, RingWidth);
|
||||
|
||||
// draw the inner triangle (color part)
|
||||
DrawColorTriangle(graphics2D, InnerRadius, SelectedHueColor);
|
||||
|
||||
// draw the big ring outline
|
||||
graphics2D.Ring(center, RingRadius + RingWidth / 2, 1, Color.Black);
|
||||
graphics2D.Ring(center, RingRadius - RingWidth / 2, 1, Color.Black);
|
||||
|
||||
// draw the triangle outline
|
||||
graphics2D.Line(GetTrianglePoint(0, InnerRadius, colorAngle), GetTrianglePoint(1, InnerRadius, colorAngle), Color.Black);
|
||||
graphics2D.Line(GetTrianglePoint(1, InnerRadius, colorAngle), GetTrianglePoint(2, InnerRadius, colorAngle), Color.Black);
|
||||
graphics2D.Line(GetTrianglePoint(2, InnerRadius, colorAngle), GetTrianglePoint(0, InnerRadius, colorAngle), Color.Black);
|
||||
|
||||
// draw the color circle on the triangle
|
||||
var triangleColorCenter = TriangleToWidgetTransform(colorAngle).Transform(unitTrianglePosition);
|
||||
graphics2D.Circle(triangleColorCenter,
|
||||
RingWidth / 2 - 2,
|
||||
SelectedColor);
|
||||
graphics2D.Ring(triangleColorCenter,
|
||||
RingWidth / 2 - 2,
|
||||
2,
|
||||
Color.White);
|
||||
|
||||
// draw the color circle on the ring
|
||||
var ringColorCenter = center + Vector2.Rotate(new Vector2(RingRadius, 0), colorAngle);
|
||||
graphics2D.Circle(ringColorCenter,
|
||||
RingWidth / 2 - 2,
|
||||
SelectedHueColor);
|
||||
graphics2D.Ring(ringColorCenter,
|
||||
RingWidth / 2 - 2,
|
||||
2,
|
||||
Color.White);
|
||||
|
||||
base.OnDraw(graphics2D);
|
||||
}
|
||||
|
||||
public override void OnMouseDown(MouseEventArgs mouseEvent)
|
||||
{
|
||||
var center = new Vector2(Width / 2, Height / 2);
|
||||
var direction = mouseEvent.Position - center;
|
||||
|
||||
if (mouseEvent.Button == MouseButtons.Left)
|
||||
{
|
||||
if (direction.Length > RingRadius - RingWidth / 2
|
||||
&& direction.Length < RingRadius + RingWidth / 2)
|
||||
{
|
||||
mouseDownOnRing = true;
|
||||
|
||||
colorAngle = Math.Atan2(direction.Y, direction.X);
|
||||
if (colorAngle < 0)
|
||||
{
|
||||
colorAngle += MathHelper.Tau;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
else
|
||||
{
|
||||
var trianglePositon = WidgetToUnitTriangle(mouseEvent.Position);
|
||||
|
||||
if (trianglePositon.inside)
|
||||
{
|
||||
mouseDownOnTriangle = true;
|
||||
unitTrianglePosition = trianglePositon.position;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
base.OnMouseDown(mouseEvent);
|
||||
}
|
||||
|
||||
public override void OnMouseMove(MouseEventArgs mouseEvent)
|
||||
{
|
||||
if (mouseDownOnRing)
|
||||
{
|
||||
var center = new Vector2(Width / 2, Height / 2);
|
||||
|
||||
var direction = mouseEvent.Position - center;
|
||||
colorAngle = Math.Atan2(direction.Y, direction.X);
|
||||
if (colorAngle < 0)
|
||||
{
|
||||
colorAngle += MathHelper.Tau;
|
||||
}
|
||||
Invalidate();
|
||||
}
|
||||
else if (mouseDownOnTriangle)
|
||||
{
|
||||
unitTrianglePosition = WidgetToUnitTriangle(mouseEvent.Position).position;
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
base.OnMouseMove(mouseEvent);
|
||||
}
|
||||
|
||||
public override void OnMouseUp(MouseEventArgs mouseEvent)
|
||||
{
|
||||
mouseDownOnRing = false;
|
||||
mouseDownOnTriangle = false;
|
||||
|
||||
base.OnMouseUp(mouseEvent);
|
||||
}
|
||||
|
||||
private void DrawColorRing(Graphics2D graphics2D, double radius, double width)
|
||||
{
|
||||
if (graphics2D is Graphics2DOpenGL graphicsGL)
|
||||
{
|
||||
graphicsGL.PushOrthoProjection();
|
||||
|
||||
GL.Disable(EnableCap.Texture2D);
|
||||
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
|
||||
GL.Enable(EnableCap.Blend);
|
||||
|
||||
var outer = radius + width / 2;
|
||||
var inner = radius - width / 2;
|
||||
GL.Begin(BeginMode.TriangleStrip);
|
||||
|
||||
for (int i = 0; i <= 360; i++)
|
||||
{
|
||||
var color = ColorF.FromHSL(i / 360.0, 1, .5);
|
||||
var angle = MathHelper.DegreesToRadians(i);
|
||||
|
||||
GL.Color4(color.Red0To255, color.Green0To255, color.Blue0To255, color.Alpha0To255);
|
||||
GL.Vertex2(GetAtAngle(angle, outer));
|
||||
GL.Vertex2(GetAtAngle(angle, inner));
|
||||
}
|
||||
|
||||
GL.End();
|
||||
|
||||
graphicsGL.PopOrthoProjection();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawColorTriangle(Graphics2D graphics2D, double radius, Color color)
|
||||
{
|
||||
if (graphics2D is Graphics2DOpenGL graphicsGL)
|
||||
{
|
||||
graphicsGL.PushOrthoProjection();
|
||||
|
||||
GL.Disable(EnableCap.Texture2D);
|
||||
GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
|
||||
GL.Enable(EnableCap.Blend);
|
||||
|
||||
GL.Begin(BeginMode.Triangles);
|
||||
GL.Color4(color.Red0To255, color.Green0To255, color.Blue0To255, color.Alpha0To255);
|
||||
GL.Vertex2(GetTrianglePoint(0, radius, colorAngle));
|
||||
GL.Color4(Color.Black);
|
||||
GL.Vertex2(GetTrianglePoint(1, radius, colorAngle));
|
||||
GL.Color4(Color.White);
|
||||
GL.Vertex2(GetTrianglePoint(2, radius, colorAngle));
|
||||
|
||||
GL.End();
|
||||
|
||||
graphicsGL.PopOrthoProjection();
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2 GetAtAngle(double angle, double radius)
|
||||
{
|
||||
var start = new Vector2(radius, 0);
|
||||
|
||||
var center = new Vector2(Width / 2, Height / 2);
|
||||
return center + Vector2.Rotate(start, angle);
|
||||
}
|
||||
|
||||
private Vector2 GetTrianglePoint(int index, double radius, double pontingAngle)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return GetAtAngle(pontingAngle, radius);
|
||||
|
||||
case 1:
|
||||
return GetAtAngle(pontingAngle + MathHelper.DegreesToRadians(120), radius);
|
||||
|
||||
case 2:
|
||||
return GetAtAngle(pontingAngle + MathHelper.DegreesToRadians(240), radius);
|
||||
}
|
||||
|
||||
return Vector2.Zero;
|
||||
}
|
||||
|
||||
private Affine TriangleToWidgetTransform(double angle)
|
||||
{
|
||||
var center = new Vector2(Width / 2, Height / 2);
|
||||
var leftSize = .5;// Math.Sqrt(1.0 / 2.0);
|
||||
var cos30 = Math.Sin(MathHelper.DegreesToRadians(30));
|
||||
|
||||
Affine total = Affine.NewIdentity();
|
||||
// scale to -1 to 1 coordinates
|
||||
total *= Affine.NewScaling(1 + leftSize, 2);
|
||||
// center
|
||||
total *= Affine.NewTranslation(-leftSize, -1);
|
||||
// rotate to correct color
|
||||
total *= Affine.NewRotation(angle);
|
||||
// scale to radius
|
||||
total *= Affine.NewScaling(InnerRadius);
|
||||
// move to center
|
||||
total *= Affine.NewTranslation(center);
|
||||
return total;
|
||||
}
|
||||
|
||||
private (bool inside, Vector2 position) WidgetToUnitTriangle(Vector2 widgetPosition)
|
||||
{
|
||||
var trianglePosition = TriangleToWidgetTransform(colorAngle)
|
||||
.InverseTransform(widgetPosition);
|
||||
|
||||
bool inside = false;
|
||||
if (trianglePosition.X >= 0
|
||||
&& trianglePosition.X <=1
|
||||
&& trianglePosition.Y >= 0
|
||||
&& trianglePosition.Y <= 1)
|
||||
{
|
||||
inside = true;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
agg_basics.Clamp(trianglePosition.X, 0, 1, ref changed);
|
||||
agg_basics.Clamp(trianglePosition.Y, 0, 1, ref changed);
|
||||
|
||||
return (inside, trianglePosition);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
DesignTools/Attributes/ShowAsListAttribute.cs
Normal file
38
DesignTools/Attributes/ShowAsListAttribute.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
Copyright (c) 2018, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
|
||||
namespace MatterHackers.MatterControl.DesignTools
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ShowAsListAttribute : Attribute
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -149,6 +149,10 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
Children.Add(item.Clone());
|
||||
}
|
||||
|
||||
[ShowAsList]
|
||||
[DisplayName("Anchor")]
|
||||
public ChildrenSelector AnchorObjectSelector { get; set; } = new ChildrenSelector();
|
||||
|
||||
public bool Advanced { get; set; } = false;
|
||||
|
||||
[DisplayName("X")]
|
||||
|
|
@ -203,6 +207,39 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private IObject3D AnchorObject
|
||||
{
|
||||
get
|
||||
{
|
||||
if (AnchorObjectSelector.Count == 1)
|
||||
{
|
||||
return this.Children.Where(c => c.ID == AnchorObjectSelector[0]).FirstOrDefault();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
[JsonIgnore]
|
||||
private int AnchorObjectIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
int index = 0;
|
||||
foreach(var child in this.Children)
|
||||
{
|
||||
if(child.ID == AnchorObjectSelector[0])
|
||||
{
|
||||
return index;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static Vector3 GetPositionToAlignTo(IObject3D objectToAlignTo, FaceAlign boundingFacesToAlignTo, Vector3 extraOffset)
|
||||
{
|
||||
Vector3 positionToAlignTo = new Vector3();
|
||||
|
|
@ -258,6 +295,24 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
{
|
||||
this.DebugDepth("Rebuild");
|
||||
|
||||
var childrenIds = Children.Select(c => c.ID).ToArray();
|
||||
if(childrenIds.Length == 0)
|
||||
{
|
||||
AnchorObjectSelector.Clear();
|
||||
}
|
||||
else if (AnchorObjectSelector.Count != 1
|
||||
|| !AnchorObjectSelector.Where(i => childrenIds.Contains(i)).Any())
|
||||
{
|
||||
AnchorObjectSelector.Clear();
|
||||
AnchorObjectSelector.Add(childrenIds[0]);
|
||||
}
|
||||
|
||||
// if the count of our children changed clear our cache of the bounds
|
||||
if (Children.Count != OriginalChildrenBounds.Count)
|
||||
{
|
||||
OriginalChildrenBounds.Clear();
|
||||
}
|
||||
|
||||
using (RebuildLock())
|
||||
{
|
||||
var aabb = this.GetAxisAlignedBoundingBox();
|
||||
|
|
@ -274,82 +329,98 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
});
|
||||
}
|
||||
|
||||
var currentChildrenBounds = CurrentChildrenBounds;
|
||||
this.Children.Modify(list =>
|
||||
{
|
||||
if (list.Count == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
var firstBounds = currentChildrenBounds[0];
|
||||
int anchorIndex = AnchorObjectIndex;
|
||||
var anchorBounds = CurrentChildrenBounds[anchorIndex];
|
||||
|
||||
int i = 0;
|
||||
// first align the anchor object
|
||||
foreach (var child in list)
|
||||
{
|
||||
if (i > 0)
|
||||
if (XAlign == Align.None
|
||||
|| i == anchorIndex)
|
||||
{
|
||||
if (XAlign == Align.None)
|
||||
if (i < OriginalChildrenBounds.Count)
|
||||
{
|
||||
if (i < OriginalChildrenBounds.Count)
|
||||
{
|
||||
// make sure it is where it started
|
||||
AlignAxis(0, Align.Min, OriginalChildrenBounds[i].minXYZ.X, 0, child);
|
||||
}
|
||||
// make sure it is where it started
|
||||
AlignAxis(0, Align.Min, OriginalChildrenBounds[i].minXYZ.X, 0, child);
|
||||
}
|
||||
}
|
||||
|
||||
if (YAlign == Align.None
|
||||
|| i == anchorIndex)
|
||||
{
|
||||
if (i < OriginalChildrenBounds.Count)
|
||||
{
|
||||
AlignAxis(1, Align.Min, OriginalChildrenBounds[i].minXYZ.Y, 0, child);
|
||||
}
|
||||
}
|
||||
|
||||
if (ZAlign == Align.None
|
||||
|| i == anchorIndex)
|
||||
{
|
||||
if (i < OriginalChildrenBounds.Count)
|
||||
{
|
||||
AlignAxis(2, Align.Min, OriginalChildrenBounds[i].minXYZ.Z, 0, child);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// the align all the objects to it
|
||||
i = 0;
|
||||
foreach (var child in list)
|
||||
{
|
||||
if (XAlign != Align.None
|
||||
&& i != anchorIndex)
|
||||
{
|
||||
if (XAlign == Align.Origin)
|
||||
{
|
||||
// find the origin in world space of the child
|
||||
var firstOrigin = Vector3.Transform(Vector3.Zero, AnchorObject.WorldMatrix());
|
||||
var childOrigin = Vector3.Transform(Vector3.Zero, child.WorldMatrix());
|
||||
child.Translate(new Vector3(-(childOrigin - firstOrigin).X + (Advanced ? XOffset : 0), 0, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (XAlign == Align.Origin)
|
||||
{
|
||||
// find the origin in world space of the child
|
||||
var firstOrigin = Vector3.Transform(Vector3.Zero, this.Children.First().WorldMatrix());
|
||||
var childOrigin = Vector3.Transform(Vector3.Zero, child.WorldMatrix());
|
||||
child.Translate(new Vector3(-(childOrigin - firstOrigin).X + (Advanced ? XOffset : 0), 0, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(0, XAlign, GetAlignToOffset(currentChildrenBounds, 0, (!Advanced || XAlignTo == Align.None) ? XAlign : XAlignTo), XOffset, child);
|
||||
}
|
||||
AlignAxis(0, XAlign, GetAlignToOffset(CurrentChildrenBounds, 0, (!Advanced || XAlignTo == Align.None) ? XAlign : XAlignTo), XOffset, child);
|
||||
}
|
||||
if (YAlign == Align.None)
|
||||
}
|
||||
|
||||
if (YAlign != Align.None
|
||||
&& i != anchorIndex)
|
||||
{
|
||||
if (YAlign == Align.Origin)
|
||||
{
|
||||
if (i < OriginalChildrenBounds.Count)
|
||||
{
|
||||
AlignAxis(1, Align.Min, OriginalChildrenBounds[i].minXYZ.Y, 0, child);
|
||||
}
|
||||
// find the origin in world space of the child
|
||||
var firstOrigin = Vector3.Transform(Vector3.Zero, AnchorObject.WorldMatrix());
|
||||
var childOrigin = Vector3.Transform(Vector3.Zero, child.WorldMatrix());
|
||||
child.Translate(new Vector3(0, -(childOrigin - firstOrigin).Y + (Advanced ? YOffset : 0), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (YAlign == Align.Origin)
|
||||
{
|
||||
// find the origin in world space of the child
|
||||
var firstOrigin = Vector3.Transform(Vector3.Zero, this.Children.First().WorldMatrix());
|
||||
var childOrigin = Vector3.Transform(Vector3.Zero, child.WorldMatrix());
|
||||
child.Translate(new Vector3(0, -(childOrigin - firstOrigin).Y + (Advanced ? YOffset : 0), 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(1, YAlign, GetAlignToOffset(currentChildrenBounds, 1, (!Advanced || YAlignTo == Align.None) ? YAlign : YAlignTo), YOffset, child);
|
||||
}
|
||||
AlignAxis(1, YAlign, GetAlignToOffset(CurrentChildrenBounds, 1, (!Advanced || YAlignTo == Align.None) ? YAlign : YAlignTo), YOffset, child);
|
||||
}
|
||||
if (ZAlign == Align.None)
|
||||
}
|
||||
|
||||
if (ZAlign != Align.None
|
||||
&& i != anchorIndex)
|
||||
{
|
||||
if (ZAlign == Align.Origin)
|
||||
{
|
||||
if (i < OriginalChildrenBounds.Count)
|
||||
{
|
||||
AlignAxis(2, Align.Min, OriginalChildrenBounds[i].minXYZ.Z, 0, child);
|
||||
}
|
||||
// find the origin in world space of the child
|
||||
var firstOrigin = Vector3.Transform(Vector3.Zero, AnchorObject.WorldMatrix());
|
||||
var childOrigin = Vector3.Transform(Vector3.Zero, child.WorldMatrix());
|
||||
child.Translate(new Vector3(0, 0, -(childOrigin - firstOrigin).Z + (Advanced ? ZOffset : 0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ZAlign == Align.Origin)
|
||||
{
|
||||
// find the origin in world space of the child
|
||||
var firstOrigin = Vector3.Transform(Vector3.Zero, this.Children.First().WorldMatrix());
|
||||
var childOrigin = Vector3.Transform(Vector3.Zero, child.WorldMatrix());
|
||||
child.Translate(new Vector3(0, 0, -(childOrigin - firstOrigin).Z + (Advanced ? ZOffset : 0)));
|
||||
}
|
||||
else
|
||||
{
|
||||
AlignAxis(2, ZAlign, GetAlignToOffset(currentChildrenBounds, 2, (!Advanced || ZAlignTo == Align.None) ? ZAlign : ZAlignTo), ZOffset, child);
|
||||
}
|
||||
AlignAxis(2, ZAlign, GetAlignToOffset(CurrentChildrenBounds, 2, (!Advanced || ZAlignTo == Align.None) ? ZAlign : ZAlignTo), ZOffset, child);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
|
|
@ -440,13 +511,13 @@ namespace MatterHackers.MatterControl.DesignTools.Operations
|
|||
switch (alignTo)
|
||||
{
|
||||
case Align.Min:
|
||||
return currentChildrenBounds[0].minXYZ[axis];
|
||||
return currentChildrenBounds[AnchorObjectIndex].minXYZ[axis];
|
||||
|
||||
case Align.Center:
|
||||
return currentChildrenBounds[0].Center[axis];
|
||||
return currentChildrenBounds[AnchorObjectIndex].Center[axis];
|
||||
|
||||
case Align.Max:
|
||||
return currentChildrenBounds[0].maxXYZ[axis];
|
||||
return currentChildrenBounds[AnchorObjectIndex].maxXYZ[axis];
|
||||
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
|
|
|
|||
|
|
@ -401,8 +401,26 @@ namespace MatterHackers.MatterControl.DesignTools
|
|||
}
|
||||
else if (propertyValue is ChildrenSelector childSelector)
|
||||
{
|
||||
rowContainer = CreateSettingsColumn(property);
|
||||
rowContainer.AddChild(CreateSelector(childSelector, property.Item, theme));
|
||||
var showAsList = property.PropertyInfo.GetCustomAttributes(true).OfType<ShowAsListAttribute>().FirstOrDefault() != null;
|
||||
if (showAsList)
|
||||
{
|
||||
UIField field = new ChildrenSelectorListField(property, theme);
|
||||
|
||||
field.Initialize(0);
|
||||
field.ValueChanged += (s, e) =>
|
||||
{
|
||||
property.SetValue(new ChildrenSelector() { field.Value });
|
||||
object3D?.Invalidate(new InvalidateArgs(context.item, InvalidateType.Properties, undoBuffer));
|
||||
propertyGridModifier?.UpdateControls(new PublicPropertyChange(context, property.PropertyInfo.Name));
|
||||
};
|
||||
|
||||
rowContainer = CreateSettingsRow(property, field);
|
||||
}
|
||||
else // show the subtarct editor for boolean subtract and subtract and replace
|
||||
{
|
||||
rowContainer = CreateSettingsColumn(property);
|
||||
rowContainer.AddChild(CreateSelector(childSelector, property.Item, theme));
|
||||
}
|
||||
}
|
||||
else if (propertyValue is ImageBuffer imageBuffer)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@
|
|||
<Compile Include="ConfigurationPage\PrintLeveling\PrintLevelingWizard.cs" />
|
||||
<Compile Include="ConfigurationPage\PrintLeveling\WizardPages\LastPageInstructions.cs" />
|
||||
<Compile Include="ConfigurationPage\PrintLeveling\LevelingWizard.cs" />
|
||||
<Compile Include="CustomWidgets\ColorPicker\RadialColorPicker.cs" />
|
||||
<Compile Include="CustomWidgets\HelpArticleHeader.cs" />
|
||||
<Compile Include="CustomWidgets\InlineListItemEdit.cs" />
|
||||
<Compile Include="CustomWidgets\InlineStringEdit.cs" />
|
||||
|
|
@ -94,6 +95,7 @@
|
|||
<Compile Include="CustomWidgets\TreeView\TreeView.cs" />
|
||||
<Compile Include="DesignTools\Attributes\ShowSearchFieldAttribute.cs" />
|
||||
<Compile Include="DesignTools\Attributes\ShowUpdateButtonAttribute.cs" />
|
||||
<Compile Include="DesignTools\Attributes\ShowAsListAttribute.cs" />
|
||||
<Compile Include="DesignTools\Braille\BrailleCardObject3D.cs" />
|
||||
<Compile Include="DesignTools\Braille\BrailleGrade2.cs" />
|
||||
<Compile Include="DesignTools\Braille\BrailleGrade2Mapping.cs" />
|
||||
|
|
@ -283,6 +285,7 @@
|
|||
<Compile Include="SlicerConfiguration\SettingsRow.cs" />
|
||||
<Compile Include="SlicerConfiguration\UIFields\CharField.cs" />
|
||||
<Compile Include="SlicerConfiguration\UIFields\DirectionVectorField.cs" />
|
||||
<Compile Include="SlicerConfiguration\UIFields\ChildrenSelectorListField.cs" />
|
||||
<Compile Include="SlicerConfiguration\UIFields\EnumField.cs" />
|
||||
<Compile Include="SlicerConfiguration\UIFields\ListStringField.cs" />
|
||||
<Compile Include="SlicerConfiguration\UIFields\IconEnumField.cs" />
|
||||
|
|
|
|||
107
SlicerConfiguration/UIFields/ChildrenSelectorListField.cs
Normal file
107
SlicerConfiguration/UIFields/ChildrenSelectorListField.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
Copyright (c) 2018, Lars Brubaker, John Lewin
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.DesignTools;
|
||||
using MatterHackers.MatterControl.DesignTools.Operations;
|
||||
|
||||
namespace MatterHackers.MatterControl.SlicerConfiguration
|
||||
{
|
||||
public class ChildrenSelectorListField : UIField
|
||||
{
|
||||
private EditableProperty property;
|
||||
private ThemeConfig theme;
|
||||
private DropDownList dropDownList;
|
||||
|
||||
public ChildrenSelectorListField(EditableProperty property, ThemeConfig theme)
|
||||
{
|
||||
this.property = property;
|
||||
this.theme = theme;
|
||||
}
|
||||
|
||||
public override void Initialize(int tabIndex)
|
||||
{
|
||||
// Enum keyed on name to friendly name
|
||||
List<(string key, string value)> names = null;
|
||||
var selectedName = "";
|
||||
if (property.source is AlignObject3D item)
|
||||
{
|
||||
names = item.Children.Select(child => (child.ID, child.Name)).ToList();
|
||||
if (item.AnchorObjectSelector.Count == 1)
|
||||
{
|
||||
var selectedKey = item.AnchorObjectSelector[0];
|
||||
foreach(var name in names)
|
||||
{
|
||||
if(name.key == selectedKey)
|
||||
{
|
||||
selectedName = name.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dropDownList = new DropDownList("Name".Localize(), theme.Colors.PrimaryTextColor, Direction.Down, pointSize: theme.DefaultFontSize)
|
||||
{
|
||||
BorderColor = theme.GetBorderColor(75)
|
||||
};
|
||||
|
||||
var orderedItems = names.OrderBy(n => n.value);
|
||||
|
||||
foreach (var orderItem in orderedItems)
|
||||
{
|
||||
MenuItem newItem = dropDownList.AddItem(orderItem.value, orderItem.key);
|
||||
|
||||
var localOrderedItem = orderItem;
|
||||
newItem.Selected += (sender, e) =>
|
||||
{
|
||||
this.SetValue(localOrderedItem.key, true);
|
||||
};
|
||||
}
|
||||
|
||||
dropDownList.SelectedLabel = selectedName;
|
||||
|
||||
this.Content = dropDownList;
|
||||
}
|
||||
|
||||
protected override void OnValueChanged(FieldChangedEventArgs fieldChangedEventArgs)
|
||||
{
|
||||
if (this.Value != dropDownList.SelectedValue)
|
||||
{
|
||||
dropDownList.SelectedValue = this.Value;
|
||||
}
|
||||
|
||||
base.OnValueChanged(fieldChangedEventArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 4a3abc90d5afc01e784532ddb2fc7da06e75d1da
|
||||
Subproject commit 53964465593f3611b1aedb6214209b7667f1d9f9
|
||||
|
|
@ -1 +1 @@
|
|||
Subproject commit 82ca5114241bb398eca060bd0002e6db25035a8a
|
||||
Subproject commit 2edd3b61b87d29d1f70e9e0a36c5e25adf266726
|
||||
Loading…
Add table
Add a link
Reference in a new issue