Merge pull request #2163 from larsbrubaker/design_tools
Making it possible to have layout engines for popup windows.
This commit is contained in:
commit
596d40e83a
4 changed files with 161 additions and 36 deletions
|
|
@ -29,6 +29,7 @@ either expressed or implied, of the FreeBSD Project.
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Font;
|
||||
using MatterHackers.Agg.ImageProcessing;
|
||||
|
|
@ -43,25 +44,32 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
{
|
||||
public class DockingTabControl : GuiWidget
|
||||
{
|
||||
public event EventHandler PinStatusChanged;
|
||||
private Dictionary<string, GuiWidget> allTabs = new Dictionary<string, GuiWidget>();
|
||||
|
||||
// TODO: Pinned state should preferably come from MCWS, default to local data if guest and be per user not printer
|
||||
private bool isPinned;
|
||||
public bool ControlIsPinned
|
||||
{
|
||||
get => isPinned;
|
||||
set {
|
||||
isPinned = value;
|
||||
PinStatusChanged?.Invoke(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
private GuiWidget topToBottom;
|
||||
|
||||
Dictionary<string, GuiWidget> allTabs = new Dictionary<string, GuiWidget>();
|
||||
protected GuiWidget widgetTodockTo;
|
||||
public DockSide DockSide { get; set; }
|
||||
|
||||
public DockingTabControl()
|
||||
public DockingTabControl(GuiWidget widgetTodockTo, DockSide dockSide)
|
||||
{
|
||||
this.widgetTodockTo = widgetTodockTo;
|
||||
this.DockSide = dockSide;
|
||||
}
|
||||
|
||||
public event EventHandler PinStatusChanged;
|
||||
|
||||
public bool ControlIsPinned
|
||||
{
|
||||
get => isPinned;
|
||||
set
|
||||
{
|
||||
isPinned = value;
|
||||
PinStatusChanged?.Invoke(this, null);
|
||||
}
|
||||
}
|
||||
|
||||
public void AddPage(string name, GuiWidget widget)
|
||||
|
|
@ -70,9 +78,25 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
Rebuild();
|
||||
}
|
||||
|
||||
void Rebuild()
|
||||
public override void Initialize()
|
||||
{
|
||||
foreach(var nameWidget in allTabs)
|
||||
base.Initialize();
|
||||
|
||||
Width = 30;
|
||||
VAnchor = VAnchor.ParentBottomTop;
|
||||
HAnchor = HAnchor.FitToChildren;
|
||||
topToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
{
|
||||
HAnchor = HAnchor.FitToChildren,
|
||||
VAnchor = VAnchor.ParentBottomTop
|
||||
};
|
||||
AddChild(topToBottom);
|
||||
}
|
||||
|
||||
private void Rebuild()
|
||||
{
|
||||
Focus();
|
||||
foreach (var nameWidget in allTabs)
|
||||
{
|
||||
nameWidget.Value.Parent?.RemoveChild(nameWidget.Value);
|
||||
nameWidget.Value.ClearRemovedFlag();
|
||||
|
|
@ -119,7 +143,7 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
else // control is floating
|
||||
{
|
||||
var rotatedLabel = new VertexSourceApplyTransform(
|
||||
new TypeFacePrinter(tabTitle, 12),
|
||||
new TypeFacePrinter(tabTitle, 12),
|
||||
Affine.NewRotation(MathHelper.DegreesToRadians(-90)));
|
||||
|
||||
var bounds = rotatedLabel.Bounds();
|
||||
|
|
@ -128,6 +152,7 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
var optionsText = new GuiWidget(bounds.Width, bounds.Height)
|
||||
{
|
||||
DoubleBuffer = true,
|
||||
Margin = new BorderDouble(3, 10)
|
||||
};
|
||||
optionsText.AfterDraw += (s, e) =>
|
||||
{
|
||||
|
|
@ -143,6 +168,7 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
{
|
||||
BackgroundColor = ActiveTheme.Instance.PrimaryBackgroundColor
|
||||
};
|
||||
settingsButton.PopupLayoutEngine = new UnpinnedLayoutEngine(settingsButton.PopupContent, widgetTodockTo, DockSide);
|
||||
topToBottom.AddChild(settingsButton);
|
||||
}
|
||||
}
|
||||
|
|
@ -157,21 +183,6 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
}
|
||||
}
|
||||
|
||||
public override void Initialize()
|
||||
{
|
||||
base.Initialize();
|
||||
|
||||
Width = 30;
|
||||
VAnchor = VAnchor.ParentBottomTop;
|
||||
HAnchor = HAnchor.FitToChildren;
|
||||
topToBottom = new FlowLayoutWidget(FlowDirection.TopToBottom)
|
||||
{
|
||||
HAnchor = HAnchor.FitToChildren,
|
||||
VAnchor = VAnchor.ParentBottomTop
|
||||
};
|
||||
AddChild(topToBottom);
|
||||
}
|
||||
|
||||
internal class ResizeContainer : FlowLayoutWidget
|
||||
{
|
||||
private double downWidth = 0;
|
||||
|
|
@ -186,14 +197,14 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
this.Cursor = Cursors.WaitCursor;
|
||||
}
|
||||
|
||||
public RGBA_Bytes BorderColor { get; set; } = ActiveTheme.Instance.TertiaryBackgroundColor;
|
||||
|
||||
public override void OnDraw(Graphics2D graphics2D)
|
||||
{
|
||||
graphics2D.FillRectangle(LocalBounds.Left, LocalBounds.Bottom, LocalBounds.Left + resizeWidth, LocalBounds.Top, this.BorderColor);
|
||||
base.OnDraw(graphics2D);
|
||||
}
|
||||
|
||||
public RGBA_Bytes BorderColor { get; set; } = ActiveTheme.Instance.TertiaryBackgroundColor;
|
||||
|
||||
public override void OnMouseDown(MouseEventArgs mouseEvent)
|
||||
{
|
||||
if (mouseEvent.Position.x < resizeWidth)
|
||||
|
|
@ -272,10 +283,119 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
|
||||
Width = 500;
|
||||
Height = 640;
|
||||
//VAnchor = VAnchor.ParentBottomTop;
|
||||
topToBottom.AddChild(child);
|
||||
|
||||
AddChild(topToBottom);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum DockSide { Left, Bottom, Right, Top };
|
||||
|
||||
public class UnpinnedLayoutEngine : IPopupLayoutEngine
|
||||
{
|
||||
protected GuiWidget widgetTodockTo;
|
||||
private GuiWidget contentWidget;
|
||||
private HashSet<GuiWidget> hookedParents = new HashSet<GuiWidget>();
|
||||
private PopupWidget popupWidget;
|
||||
|
||||
public DockSide DockSide { get; set; }
|
||||
|
||||
public UnpinnedLayoutEngine(GuiWidget contentWidget, GuiWidget widgetTodockTo, DockSide dockSide)
|
||||
{
|
||||
this.contentWidget = contentWidget;
|
||||
this.widgetTodockTo = widgetTodockTo;
|
||||
DockSide = dockSide;
|
||||
}
|
||||
|
||||
public double MaxHeight { get; private set; }
|
||||
|
||||
public void Closed()
|
||||
{
|
||||
// Unbind callbacks on parents for position_changed if we're closing
|
||||
foreach (GuiWidget widget in hookedParents)
|
||||
{
|
||||
widget.PositionChanged -= widgetRelativeTo_PositionChanged;
|
||||
widget.BoundsChanged -= widgetRelativeTo_PositionChanged;
|
||||
}
|
||||
|
||||
// Long lived originating item must be unregistered
|
||||
widgetTodockTo.Closed -= widgetRelativeTo_Closed;
|
||||
|
||||
// Restore focus to originating widget on close
|
||||
if (this.widgetTodockTo != null
|
||||
&& !widgetTodockTo.HasBeenClosed)
|
||||
{
|
||||
// On menu close, select the first scrollable parent of the widgetRelativeTo
|
||||
var scrollableParent = widgetTodockTo.Parents<ScrollableWidget>().FirstOrDefault();
|
||||
if (scrollableParent != null)
|
||||
{
|
||||
scrollableParent.Focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ShowPopup(PopupWidget popupWidget)
|
||||
{
|
||||
this.popupWidget = popupWidget;
|
||||
SystemWindow windowToAddTo = widgetTodockTo.Parents<SystemWindow>().FirstOrDefault();
|
||||
windowToAddTo?.AddChild(popupWidget);
|
||||
|
||||
GuiWidget topParent = widgetTodockTo.Parent;
|
||||
while (topParent.Parent != null
|
||||
&& topParent as SystemWindow == null)
|
||||
{
|
||||
// Regrettably we don't know who it is that is the window that will actually think it is moving relative to its parent
|
||||
// but we need to know anytime our widgetRelativeTo has been moved by any change, so we hook them all.
|
||||
if (!hookedParents.Contains(topParent))
|
||||
{
|
||||
hookedParents.Add(topParent);
|
||||
topParent.PositionChanged += widgetRelativeTo_PositionChanged;
|
||||
topParent.BoundsChanged += widgetRelativeTo_PositionChanged;
|
||||
}
|
||||
|
||||
topParent = topParent.Parent;
|
||||
}
|
||||
|
||||
widgetRelativeTo_PositionChanged(widgetTodockTo, null);
|
||||
widgetTodockTo.Closed += widgetRelativeTo_Closed;
|
||||
}
|
||||
|
||||
private void widgetRelativeTo_Closed(object sender, ClosedEventArgs e)
|
||||
{
|
||||
// If the owning widget closed, so should we
|
||||
popupWidget.CloseMenu();
|
||||
}
|
||||
|
||||
private void widgetRelativeTo_PositionChanged(object sender, EventArgs e)
|
||||
{
|
||||
if (widgetTodockTo != null)
|
||||
{
|
||||
RectangleDouble bounds = widgetTodockTo.BoundsRelativeToParent;
|
||||
|
||||
GuiWidget topParent = widgetTodockTo.Parent;
|
||||
while (topParent != null && topParent.Parent != null)
|
||||
{
|
||||
topParent.ParentToChildTransform.transform(ref bounds);
|
||||
topParent = topParent.Parent;
|
||||
}
|
||||
|
||||
switch (DockSide)
|
||||
{
|
||||
case DockSide.Left:
|
||||
throw new NotImplementedException();
|
||||
case DockSide.Bottom:
|
||||
throw new NotImplementedException();
|
||||
case DockSide.Right:
|
||||
popupWidget.LocalBounds = new RectangleDouble(bounds.Right - contentWidget.Width, bounds.Bottom, bounds.Right, bounds.Top);
|
||||
break;
|
||||
case DockSide.Top:
|
||||
throw new NotImplementedException();
|
||||
default:
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -123,6 +123,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
public bool AlignToRightEdge { get; set; }
|
||||
public RGBA_Bytes BorderColor { get; set; } = RGBA_Bytes.Gray;
|
||||
public Func<GuiWidget> DynamicPopupContent { get; set; }
|
||||
public IPopupLayoutEngine PopupLayoutEngine { get; set; }
|
||||
public Direction PopDirection { get; set; } = Direction.Down;
|
||||
|
||||
public GuiWidget PopupContent { get; set; }
|
||||
|
|
@ -149,6 +150,10 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
|
||||
public void ShowPopup()
|
||||
{
|
||||
if (PopupLayoutEngine == null)
|
||||
{
|
||||
PopupLayoutEngine = new PopupLayoutEngine(this.PopupContent, this, Vector2.Zero, this.PopDirection, 0, this.AlignToRightEdge);
|
||||
}
|
||||
menuVisible = true;
|
||||
|
||||
this.PopupContent?.ClearRemovedFlag();
|
||||
|
|
@ -165,7 +170,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
|
||||
this.BeforeShowPopup();
|
||||
|
||||
popupWidget = new PopupWidget(this.PopupContent, this, Vector2.Zero, this.PopDirection, 0, this.AlignToRightEdge)
|
||||
popupWidget = new PopupWidget(this.PopupContent, PopupLayoutEngine)
|
||||
{
|
||||
BorderWidth = 1,
|
||||
BorderColor = this.BorderColor,
|
||||
|
|
|
|||
|
|
@ -178,7 +178,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
this.gcodeViewer.Visible = false;
|
||||
leftToRight.AddChild(gcodeViewer);
|
||||
|
||||
AddSettingsTabBar(leftToRight);
|
||||
AddSettingsTabBar(leftToRight, modelViewer);
|
||||
|
||||
modelViewer.BackgroundColor = ActiveTheme.Instance.TertiaryBackgroundColor;
|
||||
gcodeViewer.BackgroundColor = ActiveTheme.Instance.TertiaryBackgroundColor;
|
||||
|
|
@ -206,9 +206,9 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
this.AnchorAll();
|
||||
}
|
||||
|
||||
private void AddSettingsTabBar(GuiWidget parent)
|
||||
private void AddSettingsTabBar(GuiWidget parent, GuiWidget widgetTodockTo)
|
||||
{
|
||||
var sideBar = new DockingTabControl()
|
||||
var sideBar = new DockingTabControl(widgetTodockTo, DockSide.Right)
|
||||
{
|
||||
ControlIsPinned = ApplicationController.Instance.PrintSettingsPinned
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 3bce91aedc18346195b8a21498096eaed47c342d
|
||||
Subproject commit b57a72d8c9ae93914b007c4725b562e2c4d8730e
|
||||
Loading…
Add table
Add a link
Reference in a new issue