/// <summary> /// Adds the group archetype to add to the menu. /// </summary> /// <param name="groupArchetype">The group.</param> public void AddGroup(GroupArchetype groupArchetype) { // Get valid nodes var nodes = new List <NodeArchetype>(); foreach (var nodeArchetype in groupArchetype.Archetypes) { if ((nodeArchetype.Flags & NodeFlags.NoSpawnViaGUI) != 0) { continue; } nodes.Add(nodeArchetype); } // Check if can create group for them if (nodes.Count > 0) { var group = new VisjectCMGroup(this, groupArchetype); group.HeaderText = groupArchetype.Name; group.Close(false); for (int i = 0; i < nodes.Count; i++) { var item = new VisjectCMItem(group, groupArchetype, nodes[i]); item.Parent = group; } group.SortChildren(); group.Parent = _groupsPanel; group.DefaultIndex = _groups.Count; _groups.Add(group); } }
private void OnSearchFilterChanged() { // Skip events during setup or init stuff if (IsLayoutLocked) { return; } // Update groups for (int i = 0; i < _groups.Count; i++) { _groups[i].UpdateFilter(_searchBox.Text); _groups[i].UpdateItemSort(_selectedBox); } SortGroups(); // If no item is selected (or it's not visible anymore), select the top one if (SelectedItem == null || !SelectedItem.VisibleInHierarchy) { SelectedItem = _groups.Find(g => g.Visible)?.Children.Find(c => c.Visible && c is VisjectCMItem) as VisjectCMItem; } if (SelectedItem != null) { _panel1.ScrollViewTo(SelectedItem); } PerformLayout(); _searchBox.Focus(); }
/// <summary> /// Adds the group archetype to add to the menu. /// </summary> /// <param name="groupArchetype">The group.</param> public void AddGroup(GroupArchetype groupArchetype) { // Check if can create group for them to be spawned via GUI if (groupArchetype.Archetypes.Any(x => (x.Flags & NodeFlags.NoSpawnViaGUI) == 0)) { Profiler.BeginEvent("VisjectCM.AddGroup"); var group = new VisjectCMGroup(this, groupArchetype); group.HeaderText = groupArchetype.Name; group.Close(false); foreach (var nodeArchetype in groupArchetype.Archetypes) { var item = new VisjectCMItem(group, groupArchetype, nodeArchetype); item.Parent = group; } group.SortChildren(); group.Parent = _groupsPanel; _groups.Add(group); if (!IsLayoutLocked) { group.UnlockChildrenRecursive(); SortGroups(); group.PerformLayout(); if (_searchBox.TextLength != 0) { OnSearchFilterChanged(); } } Profiler.EndEvent(); } }
/// <summary> /// Adds the group archetypes to add to the menu. /// </summary> /// <param name="groupArchetypes">The groups.</param> public void AddGroups(IEnumerable <GroupArchetype> groupArchetypes) { // Check if can create group for them to be spawned via GUI if (groupArchetypes.Any(g => g.Archetypes.Any(x => (x.Flags & NodeFlags.NoSpawnViaGUI) == 0))) { Profiler.BeginEvent("VisjectCM.AddGroups"); var isLayoutLocked = IsLayoutLocked; LockChildrenRecursive(); Profiler.BeginEvent("Create Groups"); var groups = new List <VisjectCMGroup>(); foreach (var groupArchetype in groupArchetypes) { var group = new VisjectCMGroup(this, groupArchetype) { HeaderText = groupArchetype.Name }; group.Close(false); foreach (var nodeArchetype in groupArchetype.Archetypes) { var item = new VisjectCMItem(group, groupArchetype, nodeArchetype) { Parent = group }; } group.SortChildren(); group.Parent = _groupsPanel; _groups.Add(group); groups.Add(group); } Profiler.EndEvent(); if (!isLayoutLocked) { SortGroups(); Profiler.BeginEvent("Perform Layout"); UnlockChildrenRecursive(); foreach (var group in groups) { group.PerformLayout(); } PerformLayout(); Profiler.EndEvent(); if (_searchBox.TextLength != 0) { OnSearchFilterChanged(); } } Profiler.EndEvent(); } }
/// <summary> /// Resets the view. /// </summary> public void ResetView() { bool wasLayoutLocked = IsLayoutLocked; IsLayoutLocked = true; for (int i = 0; i < _groups.Count; i++) { _groups[i].ResetView(); } _searchBox.Clear(); SelectedItem = null; IsLayoutLocked = wasLayoutLocked; PerformLayout(); }
/// <summary> /// Resets the view. /// </summary> public void ResetView() { Profiler.BeginEvent("VisjectCM.ResetView"); LockChildrenRecursive(); _searchBox.Clear(); SelectedItem = null; for (int i = 0; i < _groups.Count; i++) { _groups[i].ResetView(); } UnlockChildrenRecursive(); SortGroups(); PerformLayout(); Profiler.EndEvent(); }
/// <summary> /// Initializes a new instance of the <see cref="VisjectCM"/> class. /// </summary> /// <param name="info">The initialization info data.</param> public VisjectCM(InitInfo info) { if (info.Groups == null) { throw new ArgumentNullException(nameof(info.Groups)); } if (info.CanSpawnNode == null) { throw new ArgumentNullException(nameof(info.CanSpawnNode)); } _parametersGetter = info.ParametersGetter; _parameterGetNodeArchetype = info.ParameterGetNodeArchetype ?? Archetypes.Parameters.Nodes[0]; // Context menu dimensions Size = new Vector2(320, 220); // Search box _searchBox = new TextBox(false, 1, 1) { Width = Width - 3, WatermarkText = "Search...", Parent = this }; _searchBox.TextChanged += OnSearchFilterChanged; // Create first panel (for scrollbar) var panel1 = new Panel(ScrollBars.Vertical) { Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2), Parent = this }; _panel1 = panel1; // Create second panel (for groups arrangement) var panel2 = new VerticalPanel { AnchorPreset = AnchorPresets.HorizontalStretchTop, IsScrollable = true, Parent = panel1 }; _groupsPanel = panel2; // Init groups int index = 0; var nodes = new List <NodeArchetype>(); foreach (var groupArchetype in info.Groups) { // Get valid nodes nodes.Clear(); foreach (var nodeArchetype in groupArchetype.Archetypes) { if (info.CanSpawnNode(nodeArchetype)) { nodes.Add(nodeArchetype); } } // Check if can create group for them if (nodes.Count > 0) { var group = new VisjectCMGroup(this, groupArchetype); group.HeaderText = groupArchetype.Name; group.Close(false); for (int i = 0; i < nodes.Count; i++) { var item = new VisjectCMItem(group, groupArchetype, nodes[i]); item.Parent = group; } group.SortChildren(); group.Parent = panel2; group.DefaultIndex = index++; _groups.Add(group); } } // Add custom nodes (special handling) if (info.CustomNodesGroup?.Archetypes != null) { for (int i = 0; i < info.CustomNodesGroup.Archetypes.Length; i++) { var nodeArchetype = info.CustomNodesGroup.Archetypes[i]; if ((nodeArchetype.Flags & NodeFlags.NoSpawnViaGUI) != 0) { continue; } var groupName = Archetypes.Custom.GetNodeGroup(nodeArchetype); // Find group to reuse VisjectCMGroup group = null; for (int j = 0; j < _groups.Count; j++) { if (string.Equals(_groups[j].Archetype.Name, groupName, StringComparison.OrdinalIgnoreCase)) { group = _groups[j]; break; } } // Create new group if name is unique if (group == null) { group = new VisjectCMGroup(this, info.CustomNodesGroup); group.HeaderText = groupName; group.Close(false); group.Parent = _groupsPanel; group.DefaultIndex = _groups.Count; _groups.Add(group); } // Add new item var item = new VisjectCMItem(group, info.CustomNodesGroup, nodeArchetype); item.Parent = group; // Order items group.SortChildren(); } } }
/// <inheritdoc /> public override bool OnKeyDown(KeyboardKeys key) { if (key == KeyboardKeys.Escape) { Hide(); return(true); } else if (key == KeyboardKeys.Return) { if (SelectedItem != null) { OnClickItem(SelectedItem); } else { Hide(); } return(true); } else if (key == KeyboardKeys.ArrowUp) { if (SelectedItem == null) { return(true); } var previousSelectedItem = GetPreviousSiblings <VisjectCMItem>(SelectedItem).FirstOrDefault(c => c.Visible) ?? (GetPreviousSiblings <VisjectCMGroup>(SelectedItem.Group).FirstOrDefault(c => c.Visible)?.Children .FindLast(c => c.Visible && c is VisjectCMItem) as VisjectCMItem); if (previousSelectedItem != null) { SelectedItem = previousSelectedItem; // Scroll into view (without smoothing) _panel1.VScrollBar.SmoothingScale = 0; _panel1.ScrollViewTo(SelectedItem); _panel1.VScrollBar.SmoothingScale = 1; } return(true); } else if (key == KeyboardKeys.ArrowDown) { if (SelectedItem == null) { return(true); } var nextSelectedItem = GetNextSiblings <VisjectCMItem>(SelectedItem).FirstOrDefault(c => c.Visible) ?? (GetNextSiblings <VisjectCMGroup>(SelectedItem.Group).FirstOrDefault(c => c.Visible)?.Children .OfType <VisjectCMItem>().FirstOrDefault(c => c.Visible)); if (nextSelectedItem != null) { SelectedItem = nextSelectedItem; _panel1.ScrollViewTo(SelectedItem); } return(true); } if (_waitingForInput) { _waitingForInput = false; _searchBox.Focus(); return(_searchBox.OnKeyDown(key)); } return(base.OnKeyDown(key)); }
/// <summary> /// Updates the surface parameters group. /// </summary> private void UpdateSurfaceParametersGroup() { // Remove the old one if (_surfaceParametersGroup != null) { _groups.Remove(_surfaceParametersGroup); _surfaceParametersGroup.Dispose(); _surfaceParametersGroup = null; } // Check if surface has any parameters var parameters = _parametersGetter != null?_parametersGetter() : null; int count = parameters?.Count(x => x.IsPublic) ?? 0; if (count > 0) { // TODO: cache the allocated memory to reduce dynamic allocations var archetypes = new NodeArchetype[count]; int archetypeIndex = 0; // ReSharper disable once PossibleNullReferenceException for (int i = 0; i < parameters.Count; i++) { if (!parameters[i].IsPublic) { continue; } var node = (NodeArchetype)_parameterGetNodeArchetype.Clone(); node.Title = "Get " + parameters[i].Name; node.DefaultValues[0] = parameters[i].ID; archetypes[archetypeIndex++] = node; } var groupArchetype = new GroupArchetype { GroupID = 6, Name = "Surface Parameters", Color = new Color(52, 73, 94), Archetypes = archetypes }; var group = new VisjectCMGroup(this, groupArchetype); group.HeaderText = groupArchetype.Name; group.Close(false); archetypeIndex = 0; for (int i = 0; i < parameters.Count; i++) { if (!parameters[i].IsPublic) { continue; } var item = new VisjectCMItem(group, groupArchetype, archetypes[archetypeIndex++]); item.Parent = group; } group.SortChildren(); group.UnlockChildrenRecursive(); group.Parent = _groupsPanel; _groups.Add(group); _surfaceParametersGroup = group; } }
/// <summary> /// Called when user clicks on an item. /// </summary> /// <param name="item">The item.</param> public void OnClickItem(VisjectCMItem item) { Hide(); OnItemClicked?.Invoke(item, _selectedBox); }
/// <summary> /// Updates the surface parameters group. /// </summary> private void UpdateSurfaceParametersGroup() { // Remove the old one if (_surfaceParametersGroup != null) { _groups.Remove(_surfaceParametersGroup); _surfaceParametersGroup.Dispose(); _surfaceParametersGroup = null; } // Check if surface has any parameters var parameters = _parametersGetter != null?_parametersGetter() : null; int count = parameters?.Count(x => x.IsPublic) ?? 0; if (count > 0) { // TODO: cache the allocated memory to reduce dynamic allocations var archetypes = new NodeArchetype[count]; int archetypeIndex = 0; // ReSharper disable once PossibleNullReferenceException for (int i = 0; i < parameters.Count; i++) { if (!parameters[i].IsPublic) { continue; } archetypes[archetypeIndex++] = new NodeArchetype { TypeID = 1, Create = Archetypes.Parameters.CreateGetNode, Title = "Get " + parameters[i].Name, Description = "Parameter value getter", Size = new Vector2(140, 60), DefaultValues = new object[] { parameters[i].ID }, Elements = new[] { NodeElementArchetype.Factory.ComboBox(2, 0, 116) } }; } var groupArchetype = new GroupArchetype { GroupID = 6, Name = "Surface Parameters", Color = new Color(52, 73, 94), Archetypes = archetypes }; var group = new VisjectCMGroup(this, groupArchetype); group.HeaderText = groupArchetype.Name; group.Close(false); archetypeIndex = 0; for (int i = 0; i < parameters.Count; i++) { if (!parameters[i].IsPublic) { continue; } var item = new VisjectCMItem(group, groupArchetype, archetypes[archetypeIndex++]); item.Parent = group; } group.SortChildren(); group.UnlockChildrenRecursive(); group.Parent = _groupsPanel; _groups.Add(group); _surfaceParametersGroup = group; } }
/// <summary> /// Initializes a new instance of the <see cref="VisjectCM"/> class. /// </summary> /// <param name="groups">The group archetypes. Cannot be null.</param> /// <param name="canSpawnNodeType">The surface node type validation helper. Cannot be null.</param> /// <param name="parametersGetter">The surface parameters getter callback. Can be null.</param> public VisjectCM(List <GroupArchetype> groups, Func <NodeArchetype, bool> canSpawnNodeType, Func <List <SurfaceParameter> > parametersGetter = null) { if (groups == null) { throw new ArgumentNullException(nameof(groups)); } if (canSpawnNodeType == null) { throw new ArgumentNullException(nameof(canSpawnNodeType)); } _parametersGetter = parametersGetter; // Context menu dimensions Size = new Vector2(320, 220); // Search box _searchBox = new TextBox(false, 1, 1) { Width = Width - 3, WatermarkText = "Search...", Parent = this }; _searchBox.TextChanged += OnSearchFilterChanged; // Create first panel (for scrollbar) var panel1 = new Panel(ScrollBars.Vertical) { Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2), Parent = this }; _panel1 = panel1; // Create second panel (for groups arrangement) var panel2 = new VerticalPanel { DockStyle = DockStyle.Top, IsScrollable = true, Parent = panel1 }; _groupsPanel = panel2; // Init groups int index = 0; var nodes = new List <NodeArchetype>(); foreach (var groupArchetype in groups) { // Get valid nodes nodes.Clear(); foreach (var nodeArchetype in groupArchetype.Archetypes) { if ((nodeArchetype.Flags & NodeFlags.NoSpawnViaGUI) != 0 || !canSpawnNodeType(nodeArchetype)) { continue; } nodes.Add(nodeArchetype); } // Check if can create group for them if (nodes.Count > 0) { var group = new VisjectCMGroup(this, groupArchetype); group.Close(false); for (int i = 0; i < nodes.Count; i++) { var item = new VisjectCMItem(group, nodes[i]); item.Parent = group; } group.SortChildren(); group.Parent = panel2; group.DefaultIndex = index++; _groups.Add(group); } } }
/// <summary> /// Initializes a new instance of the <see cref="VisjectCM"/> class. /// </summary> /// <param name="type">The surface type.</param> public VisjectCM(SurfaceType type) { Type = type; // Context menu dimensions Size = new Vector2(320, 220); // Search box _searchBox = new TextBox(false, 1, 1) { Width = Width - 3, WatermarkText = "Search...", Parent = this }; _searchBox.TextChanged += OnSearchFilterChanged; // Create first panel (for scrollbar) var panel1 = new Panel(ScrollBars.Vertical) { Bounds = new Rectangle(0, _searchBox.Bottom + 1, Width, Height - _searchBox.Bottom - 2), Parent = this }; // Create second panel (for groups arrangement) var panel2 = new VerticalPanel { DockStyle = DockStyle.Top, IsScrollable = true, Parent = panel1 }; // Init groups var groups = NodeFactory.Groups; var nodes = new List <NodeArchetype>(); foreach (var groupArchetype in groups) { // Get valid nodes nodes.Clear(); foreach (var nodeArchetype in groupArchetype.Archetypes) { if ((nodeArchetype.Flags & NodeFlags.NoSpawnViaGUI) != 0) { continue; } if (type == SurfaceType.Material) { if ((nodeArchetype.Flags & NodeFlags.VisjectOnly) != 0) { continue; } } else { if ((nodeArchetype.Flags & NodeFlags.MaterialOnly) != 0) { continue; } } nodes.Add(nodeArchetype); } // Check if can create group for them if (nodes.Count > 0) { var group = new VisjectCMGroup(this, groupArchetype); group.Close(false); for (int i = 0; i < nodes.Count; i++) { var item = new VisjectCMItem(group, nodes[i]); item.Parent = group; } group.SortChildren(); group.Parent = panel2; _groups.Add(group); } } }