Merge pull request #3721 from jlewin/master

First pass at sub-menu
This commit is contained in:
Lars Brubaker 2018-09-11 09:05:23 -07:00 committed by GitHub
commit f5f7ea6f49
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 122 additions and 33 deletions

View file

@ -141,7 +141,7 @@ namespace MatterHackers.MatterControl
{
var popupMenu = new PopupMenu(ApplicationController.Instance.MenuTheme);
var menuItem = popupMenu.CreateMenuItem("Rename");
var menuItem = popupMenu.CreateMenuItem("Rename".Localize());
menuItem.Click += (s, e) =>
{
DialogWindow.Show(
@ -168,6 +168,8 @@ namespace MatterHackers.MatterControl
var menuTheme = ApplicationController.Instance.MenuTheme;
PopupMenu modifyMenu = popupMenu.CreateSubMenu("Modify".Localize(), ApplicationController.Instance.MenuTheme);
foreach (var nodeOperation in ApplicationController.Instance.Graph.Operations)
{
foreach (var type in nodeOperation.MappedTypes)
@ -176,27 +178,15 @@ namespace MatterHackers.MatterControl
&& (nodeOperation.IsVisible?.Invoke(selectedItem) != false)
&& nodeOperation.IsEnabled?.Invoke(selectedItem) != false)
{
var button = popupMenu.CreateMenuItem(nodeOperation.Title, nodeOperation.IconCollector?.Invoke(menuTheme));
button.Click += (s, e) =>
var subMenuItem = modifyMenu.CreateMenuItem(nodeOperation.Title, nodeOperation.IconCollector?.Invoke(menuTheme));
subMenuItem.Click += (s2, e2) =>
{
nodeOperation.Operation(selectedItem, scene).ConfigureAwait(false);
};
}
}
}
if (selectedItem.Ancestors().OfType<ComponentObject3D>().FirstOrDefault() is ComponentObject3D componentAncestor
&& !componentAncestor.Finalized)
{
var button = popupMenu.CreateMenuItem("Copy Path".Localize());
button.Click += (s, e) =>
{
var selector = "$." + string.Join(".", selectedItem.AncestorsAndSelf().TakeWhile(o => !(o is ComponentObject3D)).Select(o => $"Children<{o.GetType().Name.ToString()}>").Reverse().ToArray());
Clipboard.Instance.SetText(selector);
};
}
}
};
return popupMenu;
}

View file

@ -53,11 +53,12 @@ namespace MatterHackers.MatterControl.CustomWidgets
arrowRight = AggContext.StaticData.LoadIcon("fa-angle-right_12.png", theme.InvertIcons);
arrowDown = AggContext.StaticData.LoadIcon("fa-angle-down_12.png", theme.InvertIcons);
imageButton = new IconButton(expandable ? arrowRight : new ImageBuffer(), theme)
imageButton = new IconButton(arrowRight, theme)
{
MinimumSize = new Vector2((expandable) ? theme.ButtonHeight : 10, theme.ButtonHeight),
MinimumSize = new Vector2(theme.ButtonHeight, theme.ButtonHeight),
VAnchor = VAnchor.Center,
Selectable = false
Selectable = false,
Enabled = expandable
};
this.AddChild(imageButton);
@ -91,7 +92,7 @@ namespace MatterHackers.MatterControl.CustomWidgets
_expandable = value;
imageButton.SetIcon(_expandable ? arrowRight : new ImageBuffer());
this.MinimumSize = new Vector2((double)((_expandable) ? this.MinimumSize.X : 10), (double)this.MinimumSize.Y);
this.MinimumSize = new Vector2((_expandable) ? this.MinimumSize.X : 10, this.MinimumSize.Y);
}
}
}
@ -109,7 +110,11 @@ namespace MatterHackers.MatterControl.CustomWidgets
public override void OnClick(MouseEventArgs mouseEvent)
{
UiThread.RunOnIdle(() => this.Checked = !this.Checked);
if (this.Expandable)
{
UiThread.RunOnIdle(() => this.Checked = !this.Checked);
}
base.OnClick(mouseEvent);
}

View file

@ -34,6 +34,7 @@ using MatterHackers.Agg;
using MatterHackers.Agg.Image;
using MatterHackers.Agg.Platform;
using MatterHackers.Agg.UI;
using MatterHackers.Agg.VertexSource;
using MatterHackers.ImageProcessing;
using MatterHackers.MatterControl.CustomWidgets;
using MatterHackers.MatterControl.Library;
@ -112,6 +113,73 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
return menuItem;
}
public class SubMenuItemButton : MenuItem, IIgnoredPopupChild
{
public PopupMenu PopupMenu { get; set; }
public SubMenuItemButton(GuiWidget content, ThemeConfig theme, PopupMenu menu) : base(content, theme)
{
PopupMenu = menu;
}
public override void OnDraw(Graphics2D graphics2D)
{
base.OnDraw(graphics2D);
// draw the right arrow
var x = this.LocalBounds.Right - this.LocalBounds.Height / 2;
var y = this.Size.Y / 2 + 2;
var arrow = new VertexStorage();
arrow.MoveTo(x + 3, y);
arrow.LineTo(x - 3, y + 5);
arrow.LineTo(x - 3, y - 5);
graphics2D.Render(arrow, this.Enabled ? Color.Black : Color.Gray);
}
}
private SubMenuItemButton CreateSubMenuButton(string name, PopupMenu popupMenu, ImageBuffer icon = null, string shortCut = null)
{
GuiWidget content;
var textWidget = new TextWidget(name, pointSize: theme.DefaultFontSize, textColor: theme.Colors.PrimaryTextColor)
{
Padding = MenuPadding,
};
if (shortCut != null)
{
content = new GuiWidget()
{
HAnchor = HAnchor.Stretch,
VAnchor = VAnchor.Fit
};
content.AddChild(new TextWidget(shortCut, pointSize: theme.DefaultFontSize, textColor: theme.Colors.PrimaryTextColor)
{
HAnchor = HAnchor.Right
});
content.AddChild(textWidget);
}
else
{
content = textWidget;
}
content.Selectable = false;
var menuItem = new SubMenuItemButton(content, theme, popupMenu)
{
Name = name + " Menu Item",
Image = icon
};
this.AddChild(menuItem);
return menuItem;
}
public class CheckboxMenuItem : MenuItem, IIgnoredPopupChild, ICheckbox
{
private bool _checked;
@ -158,7 +226,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
private ImageBuffer radioIconUnchecked;
public RadioMenuItem(GuiWidget widget, ThemeConfig theme)
: base (widget, theme)
: base(widget, theme)
{
}
@ -227,6 +295,39 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
public event EventHandler CheckedStateChanged;
}
public PopupMenu CreateSubMenu(string menuTitle, ThemeConfig menuTheme)
{
var subMenu = new PopupMenu(menuTheme);
var subMenuItemButton = this.CreateSubMenuButton(menuTitle, subMenu);
subMenuItemButton.Click += (s, e) =>
{
UiThread.RunOnIdle(() =>
{
var systemWindow = this.Parents<SystemWindow>().FirstOrDefault();
systemWindow.ShowPopup(
new MatePoint(subMenuItemButton)
{
Mate = new MateOptions(MateEdge.Right, MateEdge.Top),
AltMate = new MateOptions(MateEdge.Left, MateEdge.Top)
},
new MatePoint(subMenu)
{
Mate = new MateOptions(MateEdge.Left, MateEdge.Top),
AltMate = new MateOptions(MateEdge.Right, MateEdge.Top)
}
);// altBounds: new RectangleDouble(mouseEvent.X + 1, mouseEvent.Y + 1, mouseEvent.X + 1, mouseEvent.Y + 1));
});
subMenu.Closed += (s1, e1) =>
{
subMenu.ClearRemovedFlag();
};
};
return subMenu;
}
public MenuItem CreateBoolMenuItem(string name, Func<bool> getter, Action<bool> setter, bool useRadioStyle = false, IList<GuiWidget> siblingRadioButtonList = null)
{
var textWidget = new TextWidget(name, pointSize: theme.DefaultFontSize, textColor: theme.Colors.PrimaryTextColor)

View file

@ -162,10 +162,12 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
{
UiThread.RunOnIdle(() =>
{
var send = sender;
// Fired any time focus changes. Traditionally we closed the menu if the we weren't focused.
// To accommodate children (or external widgets) having focus we also query for and consider special cases
bool specialChildHasFocus = ignoredWidgets.Any(w => w.ContainsFocus || w.Focused)
|| popup.Widget.DescendantsAndSelf<DropDownList>().Any(w => w.IsOpen);
|| popup.Widget.DescendantsAndSelf<DropDownList>().Any(w => w.IsOpen)
|| popup.Widget.DescendantsAndSelf<PopupMenu.SubMenuItemButton>().Any(w => w.PopupMenu.ContainsFocus);
// If the focused changed and we've lost focus and no special cases permit, close the menu
if (!popup.Widget.ContainsFocus
@ -176,15 +178,6 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
});
}
void MouseUp(object sender, EventArgs e)
{
bool mouseUpOnIgnoredChild = ignoredWidgets.Any(w => w.MouseCaptured || w.ChildHasMouseCaptured);
if (!mouseUpOnIgnoredChild)
{
UiThread.RunOnIdle(CloseMenu);
}
}
void anchor_Closed(object sender, EventArgs e)
{
// If the owning widget closed, so should we

View file

@ -174,7 +174,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
// add the tree view
treeView = new TreeView(theme)
{
Margin = new BorderDouble(left: 18),
Margin = new BorderDouble(left: theme.DefaultContainerPadding, top: theme.DefaultContainerPadding),
};
treeView.AfterSelect += (s, e) =>
{