-
Notifications
You must be signed in to change notification settings - Fork 14
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
208 additions
and
134 deletions.
There are no files selected for viewing
115 changes: 115 additions & 0 deletions
115
CavernSamples/FilterStudio/Graphs/ManipulatableGraph.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
using Microsoft.Msagl.Drawing; | ||
using Microsoft.Msagl.WpfGraphControl; | ||
using System; | ||
using System.Linq; | ||
using System.Windows.Controls; | ||
using System.Windows.Input; | ||
|
||
namespace FilterStudio.Graphs { | ||
/// <summary> | ||
/// A <see cref="Graph"/>-displaying control with a wide range of manipulation features for the user. | ||
/// </summary> | ||
public class ManipulatableGraph : ScrollViewer { | ||
/// <summary> | ||
/// Called when the user left-clicks anywhere in the graph control bounds, passes the clicked edge or node. | ||
/// If the click doesn't hit any graph element, the <see cref="object"/> will be null. | ||
/// </summary> | ||
/// <remarks>The clicked node is not necessarily selected. To check that, use <see cref="SelectedNode"/>.</remarks> | ||
public event Action<object> OnLeftClick; | ||
|
||
/// <summary> | ||
/// Called when the user right-clicks anywhere in the graph control bounds, passes the clicked edge or node. | ||
/// If the click doesn't hit any graph element, the <see cref="object"/> will be null. | ||
/// </summary> | ||
public event Action<object> OnRightClick; | ||
|
||
/// <summary> | ||
/// The currently selected node is determined by border line thickness. | ||
/// </summary> | ||
public StyledNode SelectedNode => (StyledNode)viewer.Graph?.Nodes.FirstOrDefault(x => x.Attr.LineWidth > 1); | ||
|
||
/// <summary> | ||
/// Handle to MSAGL. | ||
/// </summary> | ||
public Graph Graph { | ||
get => viewer.Graph; | ||
set { | ||
viewer.Graph = value; | ||
OnLeftClick?.Invoke(null); // Says nothing is selected now, nothing has a thick border on redraw | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// An inner panel that acts as a window for the graph. The <see cref="ScrollViewer"/> is the curtain, | ||
/// it keeps the graph in the bounds of the control wherever the user moves it. | ||
/// </summary> | ||
readonly DockPanel panel; | ||
|
||
/// <summary> | ||
/// Handles displaying and manipulating the graph. | ||
/// </summary> | ||
readonly GraphViewer viewer; | ||
|
||
/// <summary> | ||
/// A <see cref="Graph"/>-displaying control with a wide range of manipulation features for the user. | ||
/// </summary> | ||
public ManipulatableGraph() { | ||
VerticalScrollBarVisibility = ScrollBarVisibility.Hidden; | ||
panel = new DockPanel(); | ||
AddChild(panel); | ||
viewer = new GraphViewer(); | ||
viewer.BindToPanel(panel); | ||
} | ||
|
||
/// <summary> | ||
/// Force select a node on the graph by <paramref name="uid"/>. | ||
/// </summary> | ||
public void SelectNode(string uid) { | ||
Node node = viewer.Graph.FindNode(uid); | ||
node.Attr.LineWidth = 2; | ||
Dispatcher.BeginInvoke(() => { // Call after the graph was redrawn | ||
OnLeftClick(node); | ||
}); | ||
} | ||
|
||
/// <summary> | ||
/// Context menu options pass the selected node in their <paramref name="sender"/> parameter. Use this function to get the actually | ||
/// selected node, not the one that was last left-clicked. For edges, the source node will be selected (new nodes are intuitively | ||
/// then can be added after that to be between the edge's endpoints). | ||
/// </summary> | ||
public StyledNode GetSelectedNode(object sender) { | ||
if (sender is StyledNode hoverNode) { // Context menu, node = parallel | ||
return hoverNode; | ||
} else if (sender is Edge edge) { // Context menu, edge = inline | ||
return (StyledNode)viewer.Graph.FindNode(edge.Source); | ||
} else { // Window | ||
return SelectedNode; | ||
} | ||
} | ||
|
||
/// <summary> | ||
/// Hack to provide a Click event for MSAGL's WPF library. | ||
/// </summary> | ||
protected override void OnPreviewMouseUp(MouseButtonEventArgs e) { | ||
IViewerObject element = viewer.ObjectUnderMouseCursor; | ||
object param = null; | ||
if (element is IViewerNode vnode) { | ||
param = vnode.Node; | ||
} else if (element is IViewerEdge edge) { | ||
param = edge.Edge; | ||
} | ||
|
||
if (e.ChangedButton == MouseButton.Left) { | ||
StyledNode node = SelectedNode; | ||
if (node != null) { | ||
node.Attr.LineWidth = 1; // Nodes selected with SelectNode are not actually selected, just were widened | ||
} | ||
Dispatcher.BeginInvoke(() => { // Call after the graph has handled it | ||
OnLeftClick?.Invoke(param); | ||
}); | ||
} else { | ||
OnRightClick?.Invoke(param); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
using Microsoft.Msagl.Drawing; | ||
using System.Collections.Generic; | ||
using System.Windows; | ||
using System.Windows.Media; | ||
using System; | ||
|
||
using VoidX.WPF; | ||
|
||
using FilterStudio.Graphs; | ||
|
||
namespace FilterStudio { | ||
// Handlers of the filter graph control | ||
partial class MainWindow { | ||
/// <summary> | ||
/// When selecting a node, open it for modification. | ||
/// </summary> | ||
void GraphLeftClick(object element) { | ||
StyledNode node = graph.SelectedNode; | ||
if (node == null || node.Filter == null) { | ||
selectedNode.Text = (string)language["NNode"]; | ||
properties.ItemsSource = Array.Empty<object>(); | ||
return; | ||
} | ||
|
||
selectedNode.Text = node.LabelText; | ||
properties.ItemsSource = new ObjectToDataGrid(node.Filter.Filter, FilterPropertyChanged, e => Error(e.Message)); | ||
} | ||
|
||
/// <summary> | ||
/// Display the context menu when the graph is right clicked. | ||
/// </summary> | ||
void GraphRightClick(object element) { | ||
List<(string, Action<object, RoutedEventArgs>)> menuItems = [ | ||
((string)language["FLabe"], (_, e) => AddLabel(element, e)), | ||
((string)language["FGain"], (_, e) => AddGain(element, e)), | ||
((string)language["FDela"], (_, e) => AddDelay(element, e)), | ||
((string)language["FBiqu"], (_, e) => AddBiquad(element, e)), | ||
]; | ||
if (element is Node) { | ||
menuItems.Add((null, null)); | ||
menuItems.Add(((string)language["CoDel"], (_, e) => DeleteNode(element, e))); | ||
} | ||
QuickContextMenu.Show(menuItems); | ||
} | ||
|
||
/// <summary> | ||
/// Updates the graph based on the <see cref="rootNodes"/>. | ||
/// </summary> | ||
void ReloadGraph() { | ||
if (rootNodes != null) { | ||
graph.Graph = Parsing.ParseConfigurationFile(rootNodes, Parsing.ParseBackground((SolidColorBrush)Background)); | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.