From 3b37e68eccc99cf252f2acba3820987292cce7fe Mon Sep 17 00:00:00 2001 From: glopesdev Date: Mon, 15 May 2023 17:44:16 +0100 Subject: [PATCH 01/16] Add support for in-editor docs browser --- Bonsai.Editor/EditorForm.cs | 8 +- .../WorkflowEditorControl.Designer.cs | 109 ++++++++++++++---- .../GraphView/WorkflowEditorControl.cs | 18 ++- Bonsai.Editor/GraphView/WorkflowGraphView.cs | 3 +- 4 files changed, 110 insertions(+), 28 deletions(-) diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index ea082979..6e2e48ab 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -2346,8 +2346,14 @@ private async Task OpenDocumentationAsync(string assemblyName, string uid) try { + var editorControl = selectionModel.SelectedView.EditorControl; var url = await documentationProvider.GetDocumentationAsync(assemblyName, uid); - EditorDialog.OpenUrl(url); + if (editorControl.WebViewInitialized) + { + editorControl.WebView.CoreWebView2.Navigate(url.AbsoluteUri); + editorControl.ExpandWebView(); + } + else EditorDialog.OpenUrl(url); } catch (ArgumentException ex) when (ex.ParamName == nameof(assemblyName)) { diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs index c1aa4549..28c73333 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs @@ -33,16 +33,22 @@ private void InitializeComponent() this.closeToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.closeAllToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); this.splitContainer = new System.Windows.Forms.SplitContainer(); - this.webView = new Microsoft.Web.WebView2.WinForms.WebView2(); this.tabControl = new Bonsai.Editor.GraphView.WorkflowEditorTabControl(); this.workflowTabPage = new System.Windows.Forms.TabPage(); + this.browserLayoutPanel = new System.Windows.Forms.TableLayoutPanel(); + this.webView = new Microsoft.Web.WebView2.WinForms.WebView2(); + this.browserTitlePanel = new System.Windows.Forms.Panel(); + this.closeBrowserButton = new System.Windows.Forms.Button(); + this.browserLabel = new System.Windows.Forms.Label(); this.tabContextMenuStrip.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).BeginInit(); this.splitContainer.Panel1.SuspendLayout(); this.splitContainer.Panel2.SuspendLayout(); this.splitContainer.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.webView)).BeginInit(); this.tabControl.SuspendLayout(); + this.browserLayoutPanel.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.webView)).BeginInit(); + this.browserTitlePanel.SuspendLayout(); this.SuspendLayout(); // // tabContextMenuStrip @@ -76,35 +82,21 @@ private void InitializeComponent() this.splitContainer.Location = new System.Drawing.Point(0, 0); this.splitContainer.Margin = new System.Windows.Forms.Padding(2); this.splitContainer.Name = "splitContainer"; - this.splitContainer.Orientation = System.Windows.Forms.Orientation.Horizontal; + this.splitContainer.Orientation = System.Windows.Forms.Orientation.Vertical; // // splitContainer.Panel1 // - this.splitContainer.Panel1.Controls.Add(this.tabControl); + this.splitContainer.Panel1.Controls.Add(this.browserLayoutPanel); + this.splitContainer.Panel1Collapsed = true; // // splitContainer.Panel2 // - this.splitContainer.Panel2.Controls.Add(this.webView); - this.splitContainer.Panel2Collapsed = true; + this.splitContainer.Panel2.Controls.Add(this.tabControl); this.splitContainer.Size = new System.Drawing.Size(300, 200); this.splitContainer.SplitterDistance = 100; this.splitContainer.SplitterWidth = 3; this.splitContainer.TabIndex = 1; // - // webView - // - this.webView.AllowExternalDrop = true; - this.webView.CreationProperties = null; - this.webView.DefaultBackgroundColor = System.Drawing.Color.White; - this.webView.Dock = System.Windows.Forms.DockStyle.Fill; - this.webView.Location = new System.Drawing.Point(0, 0); - this.webView.Margin = new System.Windows.Forms.Padding(2); - this.webView.Name = "webView"; - this.webView.Size = new System.Drawing.Size(300, 97); - this.webView.TabIndex = 0; - this.webView.ZoomFactor = 1D; - this.webView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.webView_KeyDown); - // // tabControl // this.tabControl.AdjustRectangle = new System.Windows.Forms.Padding(0); @@ -126,11 +118,78 @@ private void InitializeComponent() this.workflowTabPage.Location = new System.Drawing.Point(4, 28); this.workflowTabPage.Name = "workflowTabPage"; this.workflowTabPage.Padding = new System.Windows.Forms.Padding(3); - this.workflowTabPage.Size = new System.Drawing.Size(292, 168); + this.workflowTabPage.Size = new System.Drawing.Size(292, 68); this.workflowTabPage.TabIndex = 0; this.workflowTabPage.Text = "Workflow"; this.workflowTabPage.UseVisualStyleBackColor = true; // + // browserLayoutPanel + // + this.browserLayoutPanel.ColumnCount = 1; + this.browserLayoutPanel.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.browserLayoutPanel.Controls.Add(this.webView, 0, 1); + this.browserLayoutPanel.Controls.Add(this.browserTitlePanel, 0, 0); + this.browserLayoutPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.browserLayoutPanel.Location = new System.Drawing.Point(0, 0); + this.browserLayoutPanel.Name = "browserLayoutPanel"; + this.browserLayoutPanel.RowCount = 2; + this.browserLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.browserLayoutPanel.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.browserLayoutPanel.Size = new System.Drawing.Size(300, 97); + this.browserLayoutPanel.TabIndex = 1; + // + // webView + // + this.webView.AllowExternalDrop = true; + this.webView.CreationProperties = null; + this.webView.DefaultBackgroundColor = System.Drawing.Color.White; + this.webView.Dock = System.Windows.Forms.DockStyle.Fill; + this.webView.Location = new System.Drawing.Point(2, 25); + this.webView.Margin = new System.Windows.Forms.Padding(2); + this.webView.Name = "webView"; + this.webView.Size = new System.Drawing.Size(296, 70); + this.webView.TabIndex = 0; + this.webView.ZoomFactor = 1D; + this.webView.KeyDown += new System.Windows.Forms.KeyEventHandler(this.webView_KeyDown); + // + // browserTitlePanel + // + this.browserTitlePanel.Controls.Add(this.closeBrowserButton); + this.browserTitlePanel.Controls.Add(this.browserLabel); + this.browserTitlePanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.browserTitlePanel.Location = new System.Drawing.Point(0, 0); + this.browserTitlePanel.Margin = new System.Windows.Forms.Padding(0); + this.browserTitlePanel.Name = "browserTitlePanel"; + this.browserTitlePanel.Size = new System.Drawing.Size(300, 23); + this.browserTitlePanel.TabIndex = 1; + // + // closeBrowserButton + // + this.closeBrowserButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Right))); + this.closeBrowserButton.BackColor = System.Drawing.SystemColors.ScrollBar; + this.closeBrowserButton.FlatAppearance.BorderSize = 0; + this.closeBrowserButton.FlatStyle = System.Windows.Forms.FlatStyle.Flat; + this.closeBrowserButton.Location = new System.Drawing.Point(271, 0); + this.closeBrowserButton.Name = "closeBrowserButton"; + this.closeBrowserButton.Size = new System.Drawing.Size(25, 23); + this.closeBrowserButton.TabIndex = 5; + this.closeBrowserButton.Text = "✕"; + this.closeBrowserButton.UseVisualStyleBackColor = false; + this.closeBrowserButton.Click += new System.EventHandler(this.closeBrowserButton_Click); + // + // browserLabel + // + this.browserLabel.BackColor = System.Drawing.SystemColors.ScrollBar; + this.browserLabel.Dock = System.Windows.Forms.DockStyle.Fill; + this.browserLabel.Location = new System.Drawing.Point(0, 0); + this.browserLabel.Margin = new System.Windows.Forms.Padding(0, 0, 3, 0); + this.browserLabel.Name = "browserLabel"; + this.browserLabel.Size = new System.Drawing.Size(300, 23); + this.browserLabel.TabIndex = 4; + this.browserLabel.Text = "Browser"; + this.browserLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; + // // WorkflowEditorControl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -144,8 +203,10 @@ private void InitializeComponent() this.splitContainer.Panel2.ResumeLayout(false); ((System.ComponentModel.ISupportInitialize)(this.splitContainer)).EndInit(); this.splitContainer.ResumeLayout(false); - ((System.ComponentModel.ISupportInitialize)(this.webView)).EndInit(); this.tabControl.ResumeLayout(false); + this.browserLayoutPanel.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.webView)).EndInit(); + this.browserTitlePanel.ResumeLayout(false); this.ResumeLayout(false); } @@ -159,5 +220,9 @@ private void InitializeComponent() private System.Windows.Forms.ToolStripMenuItem closeAllToolStripMenuItem; private System.Windows.Forms.SplitContainer splitContainer; private Microsoft.Web.WebView2.WinForms.WebView2 webView; + private System.Windows.Forms.TableLayoutPanel browserLayoutPanel; + private System.Windows.Forms.Panel browserTitlePanel; + private System.Windows.Forms.Button closeBrowserButton; + private System.Windows.Forms.Label browserLabel; } } diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index 34abc391..69709d89 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -57,7 +57,7 @@ public bool WebViewInitialized public bool WebViewCollapsed { - get { return splitContainer.Panel2Collapsed; } + get { return splitContainer.Panel1Collapsed; } } public VisualizerLayout VisualizerLayout @@ -74,12 +74,19 @@ public ExpressionBuilderGraph Workflow public void ExpandWebView() { - splitContainer.Panel2Collapsed = false; + splitContainer.Panel1Collapsed = false; + } + + public void ExpandWebView(ExpressionBuilder builder) + { + webView.Tag = builder; + browserLabel.Text = $"Browser ({ExpressionBuilder.GetElementDisplayName(builder)})"; + ExpandWebView(); } public void CollapseWebView() { - splitContainer.Panel2Collapsed = true; + splitContainer.Panel1Collapsed = true; webView.Tag = null; } @@ -463,5 +470,10 @@ private void webView_KeyDown(object sender, KeyEventArgs e) } } } + + private void closeBrowserButton_Click(object sender, EventArgs e) + { + CollapseWebView(); + } } } diff --git a/Bonsai.Editor/GraphView/WorkflowGraphView.cs b/Bonsai.Editor/GraphView/WorkflowGraphView.cs index 3f660bae..65e066b7 100644 --- a/Bonsai.Editor/GraphView/WorkflowGraphView.cs +++ b/Bonsai.Editor/GraphView/WorkflowGraphView.cs @@ -484,8 +484,7 @@ private void LaunchVisualizer(GraphNode node) { var html = MarkdownConvert.ToHtml(Font, annotationBuilder.Text); EditorControl.WebView.NavigateToString(html); - EditorControl.WebView.Tag = annotationBuilder; - EditorControl.ExpandWebView(); + EditorControl.ExpandWebView(annotationBuilder); return; } From d5a6db7e82b503e8be9bfe7d609958e05b895c73 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Mon, 15 May 2023 17:48:53 +0100 Subject: [PATCH 02/16] Add webview request for preferred color theme --- .../GraphView/WorkflowEditorControl.cs | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index 69709d89..478b8438 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -4,6 +4,7 @@ using System.Windows.Forms; using Bonsai.Expressions; using Bonsai.Design; +using Bonsai.Editor.Themes; using Microsoft.Web.WebView2.WinForms; using Microsoft.Web.WebView2.Core; @@ -14,6 +15,7 @@ partial class WorkflowEditorControl : UserControl readonly IServiceProvider serviceProvider; readonly IWorkflowEditorService editorService; readonly TabPageController workflowTab; + readonly ThemeRenderer themeRenderer; Padding? adjustMargin; bool webViewInitialized; @@ -27,6 +29,7 @@ public WorkflowEditorControl(IServiceProvider provider, bool readOnly) InitializeComponent(); serviceProvider = provider ?? throw new ArgumentNullException(nameof(provider)); editorService = (IWorkflowEditorService)provider.GetService(typeof(IWorkflowEditorService)); + themeRenderer = (ThemeRenderer)provider.GetService(typeof(ThemeRenderer)); workflowTab = InitializeTab(workflowTabPage, readOnly, null); InitializeTheme(workflowTabPage); webView.CoreWebView2InitializationCompleted += (sender, e) => @@ -37,6 +40,7 @@ public WorkflowEditorControl(IServiceProvider provider, bool readOnly) MarkdownConvert.DefaultUrl, Environment.CurrentDirectory, CoreWebView2HostResourceAccessKind.Allow); + InitializeWebViewTheme(); }; } @@ -444,6 +448,27 @@ private void InitializeTheme(TabPage tabPage) } else adjustRectangle.Bottom = adjustRectangle.Left; tabControl.AdjustRectangle = adjustRectangle; + + var colorTable = themeRenderer.ToolStripRenderer.ColorTable; + browserLabel.BackColor = closeBrowserButton.BackColor = colorTable.SeparatorDark; + browserLabel.ForeColor = closeBrowserButton.ForeColor = colorTable.ControlForeColor; + InitializeWebViewTheme(); + } + + private void InitializeWebViewTheme() + { + var colorTable = themeRenderer.ToolStripRenderer.ColorTable; + webView.BackColor = colorTable.ControlBackColor; + webView.ForeColor = colorTable.ControlForeColor; + if (webView.CoreWebView2 != null) + { + webView.CoreWebView2.Profile.PreferredColorScheme = themeRenderer.ActiveTheme switch + { + ColorTheme.Light => CoreWebView2PreferredColorScheme.Light, + ColorTheme.Dark => CoreWebView2PreferredColorScheme.Dark, + _ => CoreWebView2PreferredColorScheme.Auto + }; + } } private void CoreWebView2_ContextMenuRequested(object sender, CoreWebView2ContextMenuRequestedEventArgs e) From 25c8497d98501c2a4974c6bd4dfa24456703f846 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Mon, 15 May 2023 18:22:47 +0100 Subject: [PATCH 03/16] Ensure type definition is used for generic types --- Bonsai.Editor/EditorForm.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index 6e2e48ab..4b2c19ca 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -2331,6 +2331,11 @@ private async Task OpenDocumentationAsync(ExpressionBuilder builder) private async Task OpenDocumentationAsync(Type type) { + if (type.IsGenericType && !type.IsGenericTypeDefinition) + { + type = type.GetGenericTypeDefinition(); + } + var uid = type.FullName; var assemblyName = type.Assembly.GetName().Name; await OpenDocumentationAsync(assemblyName, uid); From 1a58044e835b6adaadb16f54ca03d90bf9d7c44c Mon Sep 17 00:00:00 2001 From: glopesdev Date: Mon, 15 May 2023 18:23:25 +0100 Subject: [PATCH 04/16] Add modifier for opening docs in external browser --- Bonsai.Editor/EditorForm.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index 4b2c19ca..7093ff4d 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -2353,7 +2353,7 @@ private async Task OpenDocumentationAsync(string assemblyName, string uid) { var editorControl = selectionModel.SelectedView.EditorControl; var url = await documentationProvider.GetDocumentationAsync(assemblyName, uid); - if (editorControl.WebViewInitialized) + if (!ModifierKeys.HasFlag(Keys.Control) && editorControl.WebViewInitialized) { editorControl.WebView.CoreWebView2.Navigate(url.AbsoluteUri); editorControl.ExpandWebView(); @@ -2383,7 +2383,7 @@ private async Task OpenDocumentationAsync(string assemblyName, string uid) private async void docsToolStripMenuItem_Click(object sender, EventArgs e) { - if (ModifierKeys != Keys.None) + if (ModifierKeys != Keys.None && ModifierKeys != Keys.Control) { return; } From 669b599fadd026c152aaf31e99f90c988e146519 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Mon, 15 May 2023 21:13:24 +0100 Subject: [PATCH 05/16] Allow search for include workflows in toolbox --- Bonsai.Editor/EditorForm.cs | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index 7093ff4d..202be6a9 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -2303,13 +2303,10 @@ private void reloadExtensionsDebugToolStripMenuItem_Click(object sender, EventAr #region Help Menu - private async Task OpenDocumentationAsync(ExpressionBuilder builder) + static bool TryGetAssemblyResource(string path, out string assemblyName, out string resourceName) { - var selectedElement = ExpressionBuilder.GetWorkflowElement(builder); - if (selectedElement is IncludeWorkflowBuilder include && - !string.IsNullOrEmpty(include.Path)) + if (!string.IsNullOrEmpty(path)) { - var path = include.Path; const char AssemblySeparator = ':'; var separatorIndex = path.IndexOf(AssemblySeparator); if (separatorIndex >= 0 && !Path.IsPathRooted(path) && path.EndsWith(BonsaiExtension)) @@ -2318,15 +2315,27 @@ private async Task OpenDocumentationAsync(ExpressionBuilder builder) var nameElements = path.Split(new[] { AssemblySeparator }, 2); if (!string.IsNullOrEmpty(nameElements[0])) { - var assemblyName = nameElements[0]; - var resourceName = string.Join(ExpressionHelper.MemberSeparator, nameElements); - await OpenDocumentationAsync(assemblyName, resourceName); - return; + assemblyName = nameElements[0]; + resourceName = string.Join(ExpressionHelper.MemberSeparator, nameElements); + return true; } } } - await OpenDocumentationAsync(selectedElement.GetType()); + assemblyName = default; + resourceName = default; + return false; + } + + private async Task OpenDocumentationAsync(ExpressionBuilder builder) + { + var selectedElement = ExpressionBuilder.GetWorkflowElement(builder); + if (selectedElement is IncludeWorkflowBuilder include && + TryGetAssemblyResource(include.Path, out string assemblyName, out string resourceName)) + { + await OpenDocumentationAsync(assemblyName, resourceName); + } + else await OpenDocumentationAsync(selectedElement.GetType()); } private async Task OpenDocumentationAsync(Type type) @@ -2393,6 +2402,14 @@ private async void docsToolStripMenuItem_Click(object sender, EventArgs e) var typeNode = toolboxTreeView.SelectedNode; if (typeNode != null && typeNode.Tag != null) { + var elementCategory = WorkflowGraphView.GetToolboxElementCategory(typeNode); + if (elementCategory == ~ElementCategory.Workflow && + TryGetAssemblyResource(typeNode.Name, out string assemblyName, out string resourceName)) + { + await OpenDocumentationAsync(assemblyName, resourceName); + return; + } + var type = Type.GetType(typeNode.Name); if (type != null) { From 896f255a28bc1082ef1416215acd8ac4e212490c Mon Sep 17 00:00:00 2001 From: glopesdev Date: Tue, 16 May 2023 00:11:09 +0100 Subject: [PATCH 06/16] Add descriptive title to docs and annotation panel --- Bonsai.Editor/EditorForm.cs | 66 ++++--------------- Bonsai.Editor/GraphModel/ElementHelper.cs | 57 ++++++++++++++++ .../GraphView/WorkflowEditorControl.cs | 13 ++-- 3 files changed, 76 insertions(+), 60 deletions(-) create mode 100644 Bonsai.Editor/GraphModel/ElementHelper.cs diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index 202be6a9..d7a1df4c 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -1531,55 +1531,6 @@ private void toolboxTreeView_ItemDrag(object sender, ItemDragEventArgs e) } } - static string GetElementName(object component) - { - var name = ExpressionBuilder.GetElementDisplayName(component); - if (component is ExternalizedProperty workflowProperty && - !string.IsNullOrWhiteSpace(workflowProperty.Name) && - workflowProperty.Name != workflowProperty.MemberName) - { - return name + " (" + workflowProperty.MemberName + ")"; - } - - var componentType = component.GetType(); - if (component is BinaryOperatorBuilder binaryOperator && binaryOperator.Operand != null) - { - var operandType = binaryOperator.Operand.GetType(); - if (operandType.IsGenericType) operandType = operandType.GetGenericArguments()[0]; - return name + " (" + ExpressionBuilder.GetElementDisplayName(operandType) + ")"; - } - else if (component is SubscribeSubject subscribeSubject && componentType.IsGenericType) - { - componentType = componentType.GetGenericArguments()[0]; - if (string.IsNullOrWhiteSpace(subscribeSubject.Name)) - { - name = name.Substring(0, name.IndexOf("`")); - } - return name + " (" + ExpressionBuilder.GetElementDisplayName(componentType) + ")"; - } - else - { - if (component is INamedElement namedExpressionBuilder && !string.IsNullOrWhiteSpace(namedExpressionBuilder.Name)) - { - name += " (" + ExpressionBuilder.GetElementDisplayName(componentType) + ")"; - } - - return name; - } - } - - static string GetElementDescription(object component) - { - if (component is WorkflowExpressionBuilder workflowExpressionBuilder) - { - var description = workflowExpressionBuilder.Description; - if (!string.IsNullOrEmpty(description)) return description; - } - - var descriptionAttribute = (DescriptionAttribute)TypeDescriptor.GetAttributes(component)[typeof(DescriptionAttribute)]; - return descriptionAttribute.Description; - } - void editorControl_Enter(object sender, EventArgs e) { var selectedView = selectionModel.SelectedView; @@ -1602,9 +1553,9 @@ private void selectionModel_SelectionChanged(object sender, EventArgs e) private void GetSelectionDescription(object[] selectedObjects, out string displayName, out string description) { - var displayNames = selectedObjects.Select(GetElementName).Distinct().Reverse().ToArray(); + var displayNames = selectedObjects.Select(ElementHelper.GetElementName).Distinct().Reverse().ToArray(); displayName = string.Join(CultureInfo.CurrentCulture.TextInfo.ListSeparator + " ", displayNames); - var objectDescriptions = selectedObjects.Select(GetElementDescription).Distinct().Reverse().ToArray(); + var objectDescriptions = selectedObjects.Select(ElementHelper.GetElementDescription).Distinct().Reverse().ToArray(); description = objectDescriptions.Length == 1 ? objectDescriptions[0] : string.Empty; } @@ -1645,8 +1596,8 @@ private void UpdatePropertyGrid() var launcher = selectedView.Launcher; if (launcher != null) { - displayName = GetElementName(launcher.Builder); - description = GetElementDescription(launcher.Builder); + displayName = ElementHelper.GetElementName(launcher.Builder); + description = ElementHelper.GetElementDescription(launcher.Builder); } else { @@ -2365,7 +2316,14 @@ private async Task OpenDocumentationAsync(string assemblyName, string uid) if (!ModifierKeys.HasFlag(Keys.Control) && editorControl.WebViewInitialized) { editorControl.WebView.CoreWebView2.Navigate(url.AbsoluteUri); - editorControl.ExpandWebView(); + var nameSeparator = uid.LastIndexOf(ExpressionHelper.MemberSeparator); + if (nameSeparator >= 0) + { + var name = uid.Substring(nameSeparator + 1); + var categoryName = GetPackageDisplayName(uid.Substring(0, nameSeparator)); + editorControl.ExpandWebView(label: $"{name} ({categoryName})"); + } + else editorControl.ExpandWebView(label: uid); } else EditorDialog.OpenUrl(url); } diff --git a/Bonsai.Editor/GraphModel/ElementHelper.cs b/Bonsai.Editor/GraphModel/ElementHelper.cs new file mode 100644 index 00000000..862e0828 --- /dev/null +++ b/Bonsai.Editor/GraphModel/ElementHelper.cs @@ -0,0 +1,57 @@ +using System.ComponentModel; +using Bonsai.Expressions; + +namespace Bonsai.Editor.GraphModel +{ + static class ElementHelper + { + public static string GetElementName(object component) + { + var name = ExpressionBuilder.GetElementDisplayName(component); + if (component is ExternalizedProperty workflowProperty && + !string.IsNullOrWhiteSpace(workflowProperty.Name) && + workflowProperty.Name != workflowProperty.MemberName) + { + return name + " (" + workflowProperty.MemberName + ")"; + } + + var componentType = component.GetType(); + if (component is BinaryOperatorBuilder binaryOperator && binaryOperator.Operand != null) + { + var operandType = binaryOperator.Operand.GetType(); + if (operandType.IsGenericType) operandType = operandType.GetGenericArguments()[0]; + return name + " (" + ExpressionBuilder.GetElementDisplayName(operandType) + ")"; + } + else if (component is SubscribeSubject subscribeSubject && componentType.IsGenericType) + { + componentType = componentType.GetGenericArguments()[0]; + if (string.IsNullOrWhiteSpace(subscribeSubject.Name)) + { + name = name.Substring(0, name.IndexOf("`")); + } + return name + " (" + ExpressionBuilder.GetElementDisplayName(componentType) + ")"; + } + else + { + if (component is INamedElement namedExpressionBuilder && !string.IsNullOrWhiteSpace(namedExpressionBuilder.Name)) + { + name += " (" + ExpressionBuilder.GetElementDisplayName(componentType) + ")"; + } + + return name; + } + } + + public static string GetElementDescription(object component) + { + if (component is WorkflowExpressionBuilder workflowExpressionBuilder) + { + var description = workflowExpressionBuilder.Description; + if (!string.IsNullOrEmpty(description)) return description; + } + + var descriptionAttribute = (DescriptionAttribute)TypeDescriptor.GetAttributes(component)[typeof(DescriptionAttribute)]; + return descriptionAttribute.Description; + } + } +} diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index 478b8438..f156e54e 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -7,6 +7,7 @@ using Bonsai.Editor.Themes; using Microsoft.Web.WebView2.WinForms; using Microsoft.Web.WebView2.Core; +using Bonsai.Editor.GraphModel; namespace Bonsai.Editor.GraphView { @@ -76,16 +77,16 @@ public ExpressionBuilderGraph Workflow set { WorkflowGraphView.Workflow = value; } } - public void ExpandWebView() + public void ExpandWebView(ExpressionBuilder builder) { - splitContainer.Panel1Collapsed = false; + webView.Tag = builder; + ExpandWebView(ElementHelper.GetElementName(builder)); } - public void ExpandWebView(ExpressionBuilder builder) + public void ExpandWebView(string label) { - webView.Tag = builder; - browserLabel.Text = $"Browser ({ExpressionBuilder.GetElementDisplayName(builder)})"; - ExpandWebView(); + browserLabel.Text = label; + splitContainer.Panel1Collapsed = false; } public void CollapseWebView() From 7f5c4d4854cf8295cd730b549081b6efe1f53273 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Tue, 16 May 2023 08:34:27 +0100 Subject: [PATCH 07/16] Ensure webview resizes with container width --- .../WorkflowEditorControl.Designer.cs | 2 +- .../GraphView/WorkflowEditorControl.cs | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs index 28c73333..0e415a89 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs @@ -93,7 +93,7 @@ private void InitializeComponent() // this.splitContainer.Panel2.Controls.Add(this.tabControl); this.splitContainer.Size = new System.Drawing.Size(300, 200); - this.splitContainer.SplitterDistance = 100; + this.splitContainer.SplitterDistance = 300; this.splitContainer.SplitterWidth = 3; this.splitContainer.TabIndex = 1; // diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index f156e54e..8b4cb850 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -87,6 +87,7 @@ public void ExpandWebView(string label) { browserLabel.Text = label; splitContainer.Panel1Collapsed = false; + EnsureWebViewSize(); } public void CollapseWebView() @@ -264,6 +265,12 @@ protected override void OnLoad(EventArgs e) base.OnLoad(e); } + protected override void OnSizeChanged(EventArgs e) + { + EnsureWebViewSize(); + base.OnSizeChanged(e); + } + protected override void OnKeyDown(KeyEventArgs e) { editorService.OnKeyDown(e); @@ -437,6 +444,21 @@ protected override void ScaleControl(SizeF factor, BoundsSpecified specified) var adjustV = displayX - marginTop - displayX / 2 - 1; adjustMargin = new Padding(adjustH, adjustV, adjustH, adjustH); } + splitContainer.SplitterDistance = (int)Math.Round(splitContainer.SplitterDistance * factor.Width); + splitContainer.Panel1MinSize = splitContainer.SplitterDistance / 2; + splitContainer.FixedPanel = FixedPanel.Panel1; + } + + private void EnsureWebViewSize() + { + if (splitContainer.FixedPanel != FixedPanel.None) + { + if (Width < 4 * splitContainer.Panel1MinSize) + { + splitContainer.SplitterDistance = Width / 2; + } + else splitContainer.SplitterDistance = 2 * splitContainer.Panel1MinSize - splitContainer.SplitterWidth; + } } private void InitializeTheme(TabPage tabPage) From a998d1078f1737573aa6511e75c86e2988edb356 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Tue, 16 May 2023 09:12:20 +0100 Subject: [PATCH 08/16] Launch editor help using documentation provider --- Bonsai.Editor/EditorForm.cs | 6 ++++-- Bonsai.Editor/Properties/Resources.Designer.cs | 9 +++++++++ Bonsai.Editor/Properties/Resources.resx | 3 +++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index d7a1df4c..23a42ae6 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -30,6 +30,7 @@ namespace Bonsai.Editor public partial class EditorForm : Form { const float DefaultEditorScale = 1.0f; + const string EditorUid = "editor"; const string BonsaiExtension = ".bonsai"; const string BonsaiPackageName = "Bonsai"; const string ExtensionsDirectory = "Extensions"; @@ -2323,7 +2324,7 @@ private async Task OpenDocumentationAsync(string assemblyName, string uid) var categoryName = GetPackageDisplayName(uid.Substring(0, nameSeparator)); editorControl.ExpandWebView(label: $"{name} ({categoryName})"); } - else editorControl.ExpandWebView(label: uid); + else editorControl.ExpandWebView(label: uid == EditorUid ? Resources.Editor_HelpLabel : uid); } else EditorDialog.OpenUrl(url); } @@ -2388,7 +2389,8 @@ private async void docsToolStripMenuItem_Click(object sender, EventArgs e) } } - EditorDialog.ShowDocs(); + var editorAssemblyName = GetType().Assembly.GetName().Name; + await OpenDocumentationAsync(editorAssemblyName, EditorUid); } private void forumToolStripMenuItem_Click(object sender, EventArgs e) diff --git a/Bonsai.Editor/Properties/Resources.Designer.cs b/Bonsai.Editor/Properties/Resources.Designer.cs index e5b34e43..295eb181 100644 --- a/Bonsai.Editor/Properties/Resources.Designer.cs +++ b/Bonsai.Editor/Properties/Resources.Designer.cs @@ -192,6 +192,15 @@ internal static string Editor_Error_Caption { } } + /// + /// Looks up a localized string similar to Help. + /// + internal static string Editor_HelpLabel { + get { + return ResourceManager.GetString("Editor_HelpLabel", resourceCulture); + } + } + /// /// Looks up a localized string similar to The workflow needs to be saved before proceeding. Do you want to save the workflow?. /// diff --git a/Bonsai.Editor/Properties/Resources.resx b/Bonsai.Editor/Properties/Resources.resx index 0eb5ce99..d5b31a13 100644 --- a/Bonsai.Editor/Properties/Resources.resx +++ b/Bonsai.Editor/Properties/Resources.resx @@ -338,4 +338,7 @@ NOTE: You will have to restart Bonsai for any changes to take effect. The specified subject definition could not be found. + + Help + \ No newline at end of file From 56156c57d8447753ff2766035d13c6defb26fc87 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Tue, 16 May 2023 10:52:15 +0100 Subject: [PATCH 09/16] Align webview label with main editor labels --- Bonsai.Editor/GraphView/WorkflowEditorControl.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index 8b4cb850..df5a5f50 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -472,6 +472,13 @@ private void InitializeTheme(TabPage tabPage) else adjustRectangle.Bottom = adjustRectangle.Left; tabControl.AdjustRectangle = adjustRectangle; + var labelOffset = browserLabel.Height - ItemHeight + 1; + if (themeRenderer.ActiveTheme == ColorTheme.Light && labelOffset < 0) + { + labelOffset += 1; + } + browserLayoutPanel.RowStyles[0].Height -= labelOffset; + var colorTable = themeRenderer.ToolStripRenderer.ColorTable; browserLabel.BackColor = closeBrowserButton.BackColor = colorTable.SeparatorDark; browserLabel.ForeColor = closeBrowserButton.ForeColor = colorTable.ControlForeColor; From 342775eaef76a87385515db2c630f7c31fe0cd3d Mon Sep 17 00:00:00 2001 From: glopesdev Date: Tue, 16 May 2023 17:58:04 +0100 Subject: [PATCH 10/16] Allow setting splitter distance above min size --- Bonsai.Editor/GraphView/WorkflowEditorControl.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index df5a5f50..fc0f6e3d 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -457,7 +457,12 @@ private void EnsureWebViewSize() { splitContainer.SplitterDistance = Width / 2; } - else splitContainer.SplitterDistance = 2 * splitContainer.Panel1MinSize - splitContainer.SplitterWidth; + else + { + splitContainer.SplitterDistance = Math.Max( + 2 * splitContainer.Panel1MinSize - splitContainer.SplitterWidth, + splitContainer.SplitterDistance); + } } } From f6369382e4489066be25af51abc74af5bff49cbc Mon Sep 17 00:00:00 2001 From: glopesdev Date: Tue, 16 May 2023 23:50:34 +0100 Subject: [PATCH 11/16] Avoid hard-coded strings in element names --- Bonsai.Editor/EditorSettings.cs | 57 +++++++++++++------------------ Bonsai.Editor/RecentlyUsedFile.cs | 2 ++ 2 files changed, 25 insertions(+), 34 deletions(-) diff --git a/Bonsai.Editor/EditorSettings.cs b/Bonsai.Editor/EditorSettings.cs index 346c8bd7..8097e8da 100644 --- a/Bonsai.Editor/EditorSettings.cs +++ b/Bonsai.Editor/EditorSettings.cs @@ -12,17 +12,6 @@ namespace Bonsai.Editor sealed class EditorSettings { const int MaxRecentFiles = 25; - const string RecentlyUsedFilesElement = "RecentlyUsedFiles"; - const string DesktopBoundsElement = "DesktopBounds"; - const string WindowStateElement = "WindowState"; - const string RecentlyUsedFileElement = "RecentlyUsedFile"; - const string FileTimestampElement = "Timestamp"; - const string FileNameElement = "Name"; - const string RectangleXElement = "X"; - const string RectangleYElement = "Y"; - const string RectangleWidthElement = "Width"; - const string RectangleHeightElement = "Height"; - const string EditorThemeElement = "EditorTheme"; const string SettingsFileName = "Bonsai.exe.settings"; static readonly string SettingsPath = Path.Combine(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location), SettingsFileName); static readonly Lazy instance = new Lazy(Load); @@ -62,39 +51,39 @@ static EditorSettings Load() while (reader.Read()) { if (reader.NodeType != XmlNodeType.Element) continue; - if (reader.Name == WindowStateElement) + if (reader.Name == nameof(WindowState)) { Enum.TryParse(reader.ReadElementContentAsString(), out FormWindowState windowState); settings.WindowState = windowState; } - else if (reader.Name == EditorThemeElement) + else if (reader.Name == nameof(EditorTheme)) { Enum.TryParse(reader.ReadElementContentAsString(), out ColorTheme editorTheme); settings.EditorTheme = editorTheme; } - else if (reader.Name == DesktopBoundsElement) + else if (reader.Name == nameof(DesktopBounds)) { - reader.ReadToFollowing(RectangleXElement); + reader.ReadToFollowing(nameof(Rectangle.X)); int.TryParse(reader.ReadElementContentAsString(), out int x); - reader.ReadToFollowing(RectangleYElement); + reader.ReadToFollowing(nameof(Rectangle.Y)); int.TryParse(reader.ReadElementContentAsString(), out int y); - reader.ReadToFollowing(RectangleWidthElement); + reader.ReadToFollowing(nameof(Rectangle.Width)); int.TryParse(reader.ReadElementContentAsString(), out int width); - reader.ReadToFollowing(RectangleHeightElement); + reader.ReadToFollowing(nameof(Rectangle.Height)); int.TryParse(reader.ReadElementContentAsString(), out int height); settings.DesktopBounds = new Rectangle(x, y, width, height); } - else if (reader.Name == RecentlyUsedFilesElement) + else if (reader.Name == nameof(RecentlyUsedFiles)) { var fileReader = reader.ReadSubtree(); - while (fileReader.ReadToFollowing(RecentlyUsedFileElement)) + while (fileReader.ReadToFollowing(nameof(RecentlyUsedFile))) { - if (fileReader.Name == RecentlyUsedFileElement) + if (fileReader.Name == nameof(RecentlyUsedFile)) { string fileName; - fileReader.ReadToFollowing(FileTimestampElement); + fileReader.ReadToFollowing(nameof(RecentlyUsedFile.Timestamp)); DateTimeOffset.TryParse(fileReader.ReadElementContentAsString(), out DateTimeOffset timestamp); - fileReader.ReadToFollowing(FileNameElement); + fileReader.ReadToFollowing(nameof(RecentlyUsedFile.Name)); fileName = fileReader.ReadElementContentAsString(); settings.recentlyUsedFiles.Add(timestamp, fileName); } @@ -114,24 +103,24 @@ public void Save() using (var writer = XmlWriter.Create(SettingsPath, new XmlWriterSettings { Indent = true })) { writer.WriteStartElement(typeof(EditorSettings).Name); - writer.WriteElementString(WindowStateElement, WindowState.ToString()); - writer.WriteElementString(EditorThemeElement, EditorTheme.ToString()); + writer.WriteElementString(nameof(WindowState), WindowState.ToString()); + writer.WriteElementString(nameof(EditorTheme), EditorTheme.ToString()); - writer.WriteStartElement(DesktopBoundsElement); - writer.WriteElementString(RectangleXElement, DesktopBounds.X.ToString(CultureInfo.InvariantCulture)); - writer.WriteElementString(RectangleYElement, DesktopBounds.Y.ToString(CultureInfo.InvariantCulture)); - writer.WriteElementString(RectangleWidthElement, DesktopBounds.Width.ToString(CultureInfo.InvariantCulture)); - writer.WriteElementString(RectangleHeightElement, DesktopBounds.Height.ToString(CultureInfo.InvariantCulture)); + writer.WriteStartElement(nameof(DesktopBounds)); + writer.WriteElementString(nameof(Rectangle.X), DesktopBounds.X.ToString(CultureInfo.InvariantCulture)); + writer.WriteElementString(nameof(Rectangle.Y), DesktopBounds.Y.ToString(CultureInfo.InvariantCulture)); + writer.WriteElementString(nameof(Rectangle.Width), DesktopBounds.Width.ToString(CultureInfo.InvariantCulture)); + writer.WriteElementString(nameof(Rectangle.Height), DesktopBounds.Height.ToString(CultureInfo.InvariantCulture)); writer.WriteEndElement(); if (recentlyUsedFiles.Count > 0) { - writer.WriteStartElement(RecentlyUsedFilesElement); + writer.WriteStartElement(nameof(RecentlyUsedFiles)); foreach (var file in recentlyUsedFiles) { - writer.WriteStartElement(RecentlyUsedFileElement); - writer.WriteElementString(FileTimestampElement, file.Timestamp.ToString("o")); - writer.WriteElementString(FileNameElement, file.FileName); + writer.WriteStartElement(nameof(RecentlyUsedFile)); + writer.WriteElementString(nameof(RecentlyUsedFile.Timestamp), file.Timestamp.ToString("o")); + writer.WriteElementString(nameof(RecentlyUsedFile.Name), file.FileName); writer.WriteEndElement(); } writer.WriteEndElement(); diff --git a/Bonsai.Editor/RecentlyUsedFile.cs b/Bonsai.Editor/RecentlyUsedFile.cs index f8b50451..0485d9f2 100644 --- a/Bonsai.Editor/RecentlyUsedFile.cs +++ b/Bonsai.Editor/RecentlyUsedFile.cs @@ -16,6 +16,8 @@ public RecentlyUsedFile(DateTimeOffset timestamp, string fileName) public DateTimeOffset Timestamp { get; private set; } public string FileName { get; private set; } + + internal string Name => FileName; } class RecentlyUsedFileCollection : IEnumerable From ea1e2f4856c380b59da1be99975715731947981c Mon Sep 17 00:00:00 2001 From: glopesdev Date: Tue, 16 May 2023 23:53:03 +0100 Subject: [PATCH 12/16] Store webview panel size in editor settings --- Bonsai.Editor/EditorForm.cs | 4 ++++ Bonsai.Editor/EditorSettings.cs | 8 ++++++++ Bonsai.Editor/GraphView/WorkflowEditorControl.cs | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index 23a42ae6..bfc82278 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -254,11 +254,15 @@ void RestoreEditorSettings() WindowState = EditorSettings.Instance.WindowState; themeRenderer.ActiveTheme = EditorSettings.Instance.EditorTheme; + editorControl.WebViewSplitterDistance = (int)Math.Round( + EditorSettings.Instance.WebViewSize * scaleFactor.Width); } void CloseEditorForm() { Application.RemoveMessageFilter(hotKeys); + EditorSettings.Instance.WebViewSize = (int)Math.Round( + editorControl.WebViewSplitterDistance * inverseScaleFactor.Width); var desktopBounds = WindowState != FormWindowState.Normal ? RestoreBounds : Bounds; EditorSettings.Instance.DesktopBounds = ScaleBounds(desktopBounds, inverseScaleFactor); if (WindowState == FormWindowState.Minimized) diff --git a/Bonsai.Editor/EditorSettings.cs b/Bonsai.Editor/EditorSettings.cs index 8097e8da..9faed310 100644 --- a/Bonsai.Editor/EditorSettings.cs +++ b/Bonsai.Editor/EditorSettings.cs @@ -33,6 +33,8 @@ public static EditorSettings Instance public ColorTheme EditorTheme { get; set; } + public int WebViewSize { get; set; } + public RecentlyUsedFileCollection RecentlyUsedFiles { get { return recentlyUsedFiles; } @@ -61,6 +63,11 @@ static EditorSettings Load() Enum.TryParse(reader.ReadElementContentAsString(), out ColorTheme editorTheme); settings.EditorTheme = editorTheme; } + else if (reader.Name == nameof(WebViewSize)) + { + int.TryParse(reader.ReadElementContentAsString(), out int webViewSize); + settings.WebViewSize = webViewSize; + } else if (reader.Name == nameof(DesktopBounds)) { reader.ReadToFollowing(nameof(Rectangle.X)); @@ -105,6 +112,7 @@ public void Save() writer.WriteStartElement(typeof(EditorSettings).Name); writer.WriteElementString(nameof(WindowState), WindowState.ToString()); writer.WriteElementString(nameof(EditorTheme), EditorTheme.ToString()); + writer.WriteElementString(nameof(WebViewSize), WebViewSize.ToString(CultureInfo.InvariantCulture)); writer.WriteStartElement(nameof(DesktopBounds)); writer.WriteElementString(nameof(Rectangle.X), DesktopBounds.X.ToString(CultureInfo.InvariantCulture)); diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index fc0f6e3d..ef5cc4a1 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -65,6 +65,12 @@ public bool WebViewCollapsed get { return splitContainer.Panel1Collapsed; } } + public int WebViewSplitterDistance + { + get { return splitContainer.SplitterDistance; } + set { splitContainer.SplitterDistance = value; } + } + public VisualizerLayout VisualizerLayout { get { return WorkflowGraphView.VisualizerLayout; } From 28e7172f8efc4c62fc0e17116c0a5e55ee7a024b Mon Sep 17 00:00:00 2001 From: glopesdev Date: Wed, 17 May 2023 07:09:14 +0100 Subject: [PATCH 13/16] Ensure toolbox help context menu is visible --- Bonsai.Editor/EditorForm.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index bfc82278..c8c52ec8 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -2001,6 +2001,7 @@ private void toolboxTreeView_MouseUp(object sender, MouseEventArgs e) renameSubjectToolStripMenuItem.Visible = false; goToDefinitionToolStripMenuItem.Visible = false; insertBeforeToolStripMenuItem.Visible = true; + toolboxDocsToolStripMenuItem.Visible = true; } toolboxContextMenuStrip.Show(toolboxTreeView, e.X, e.Y); } From a6717a869eeeb6c4774fa2009fad9a90e32de786 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Wed, 17 May 2023 08:05:58 +0100 Subject: [PATCH 14/16] Update webview size when moving splitter manually --- Bonsai.Editor/EditorForm.cs | 4 ++-- .../WorkflowEditorControl.Designer.cs | 1 + .../GraphView/WorkflowEditorControl.cs | 20 +++++++++++++++---- 3 files changed, 19 insertions(+), 6 deletions(-) diff --git a/Bonsai.Editor/EditorForm.cs b/Bonsai.Editor/EditorForm.cs index c8c52ec8..23f1bbff 100644 --- a/Bonsai.Editor/EditorForm.cs +++ b/Bonsai.Editor/EditorForm.cs @@ -254,7 +254,7 @@ void RestoreEditorSettings() WindowState = EditorSettings.Instance.WindowState; themeRenderer.ActiveTheme = EditorSettings.Instance.EditorTheme; - editorControl.WebViewSplitterDistance = (int)Math.Round( + editorControl.WebViewSize = (int)Math.Round( EditorSettings.Instance.WebViewSize * scaleFactor.Width); } @@ -262,7 +262,7 @@ void CloseEditorForm() { Application.RemoveMessageFilter(hotKeys); EditorSettings.Instance.WebViewSize = (int)Math.Round( - editorControl.WebViewSplitterDistance * inverseScaleFactor.Width); + editorControl.WebViewSize * inverseScaleFactor.Width); var desktopBounds = WindowState != FormWindowState.Normal ? RestoreBounds : Bounds; EditorSettings.Instance.DesktopBounds = ScaleBounds(desktopBounds, inverseScaleFactor); if (WindowState == FormWindowState.Minimized) diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs index 0e415a89..a46db84d 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.Designer.cs @@ -96,6 +96,7 @@ private void InitializeComponent() this.splitContainer.SplitterDistance = 300; this.splitContainer.SplitterWidth = 3; this.splitContainer.TabIndex = 1; + this.splitContainer.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer_SplitterMoved); // // tabControl // diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index ef5cc4a1..969db7b8 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -65,10 +65,14 @@ public bool WebViewCollapsed get { return splitContainer.Panel1Collapsed; } } - public int WebViewSplitterDistance + public int WebViewSize { get { return splitContainer.SplitterDistance; } - set { splitContainer.SplitterDistance = value; } + set + { + splitContainer.SplitterDistance = value; + splitContainer.Panel1MinSize = splitContainer.SplitterDistance / 2; + } } public VisualizerLayout VisualizerLayout @@ -450,8 +454,7 @@ protected override void ScaleControl(SizeF factor, BoundsSpecified specified) var adjustV = displayX - marginTop - displayX / 2 - 1; adjustMargin = new Padding(adjustH, adjustV, adjustH, adjustH); } - splitContainer.SplitterDistance = (int)Math.Round(splitContainer.SplitterDistance * factor.Width); - splitContainer.Panel1MinSize = splitContainer.SplitterDistance / 2; + WebViewSize = (int)Math.Round(splitContainer.SplitterDistance * factor.Width); splitContainer.FixedPanel = FixedPanel.Panel1; } @@ -472,6 +475,15 @@ private void EnsureWebViewSize() } } + private void splitContainer_SplitterMoved(object sender, SplitterEventArgs e) + { + var delta = PointToClient(MousePosition).X - e.X; + if (delta == 0) + { + WebViewSize = e.SplitX; + } + } + private void InitializeTheme(TabPage tabPage) { var adjustRectangle = tabControl.Margin + adjustMargin.GetValueOrDefault(); From 8b20ef90aba7bc3a912611346fc9257ddb274392 Mon Sep 17 00:00:00 2001 From: glopesdev Date: Wed, 17 May 2023 08:06:24 +0100 Subject: [PATCH 15/16] Set default webview size for main editor window --- Bonsai.Editor/EditorSettings.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Bonsai.Editor/EditorSettings.cs b/Bonsai.Editor/EditorSettings.cs index 9faed310..4cfbe70a 100644 --- a/Bonsai.Editor/EditorSettings.cs +++ b/Bonsai.Editor/EditorSettings.cs @@ -20,6 +20,7 @@ sealed class EditorSettings internal EditorSettings() { + WebViewSize = 400; } public static EditorSettings Instance From 30f3c01a67471abf802dff410b7fa642974e535c Mon Sep 17 00:00:00 2001 From: glopesdev Date: Wed, 17 May 2023 08:14:27 +0100 Subject: [PATCH 16/16] Ensure webview size is set correctly on resize --- Bonsai.Editor/GraphView/WorkflowEditorControl.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs index 969db7b8..74ac2adc 100644 --- a/Bonsai.Editor/GraphView/WorkflowEditorControl.cs +++ b/Bonsai.Editor/GraphView/WorkflowEditorControl.cs @@ -71,7 +71,7 @@ public int WebViewSize set { splitContainer.SplitterDistance = value; - splitContainer.Panel1MinSize = splitContainer.SplitterDistance / 2; + splitContainer.Panel1MinSize = value / 2; } } @@ -277,8 +277,8 @@ protected override void OnLoad(EventArgs e) protected override void OnSizeChanged(EventArgs e) { - EnsureWebViewSize(); base.OnSizeChanged(e); + EnsureWebViewSize(); } protected override void OnKeyDown(KeyEventArgs e)