HelpDocs
This commit is contained in:
parent
19a7fba3a6
commit
95ae04b790
9 changed files with 397 additions and 51 deletions
|
|
@ -220,6 +220,17 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
{
|
||||
OnBeforeSelect(null);
|
||||
|
||||
if (_selectedNode != null)
|
||||
{
|
||||
// Collapse the old tree
|
||||
foreach (var ancestor in _selectedNode.Parents<TreeNode>())
|
||||
{
|
||||
ancestor.Expanded = false;
|
||||
}
|
||||
|
||||
_selectedNode.Expanded = false;
|
||||
}
|
||||
|
||||
// if the current selection (before change) is !null than clear its background color
|
||||
if (_selectedNode != null)
|
||||
{
|
||||
|
|
@ -229,11 +240,22 @@ namespace MatterHackers.MatterControl.CustomWidgets
|
|||
// change the selection
|
||||
_selectedNode = value;
|
||||
|
||||
if (_selectedNode != null)
|
||||
{
|
||||
// Expand the new tree
|
||||
foreach (var ancestor in _selectedNode.Parents<TreeNode>())
|
||||
{
|
||||
ancestor.Expanded = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_selectedNode != null)
|
||||
{
|
||||
_selectedNode.HighlightRegion.BackgroundColor = theme.AccentMimimalOverlay;
|
||||
}
|
||||
|
||||
|
||||
|
||||
OnAfterSelect(null);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
136
MatterControlLib/LuceneHelpSearch.cs
Normal file
136
MatterControlLib/LuceneHelpSearch.cs
Normal file
|
|
@ -0,0 +1,136 @@
|
|||
|
||||
using System.Collections.Generic;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using Lucene.Net.Analysis.Standard;
|
||||
using Lucene.Net.Documents;
|
||||
using Lucene.Net.Index;
|
||||
using Lucene.Net.QueryParsers.Classic;
|
||||
using Lucene.Net.Search;
|
||||
using Lucene.Net.Store;
|
||||
using Lucene.Net.Util;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.MatterControl;
|
||||
using MatterHackers.MatterControl.DataStorage;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace MatterControlLib
|
||||
{
|
||||
public class LuceneHelpSearch
|
||||
{
|
||||
private static IndexWriter writer;
|
||||
private static StandardAnalyzer analyzer;
|
||||
|
||||
static LuceneHelpSearch()
|
||||
{
|
||||
// Ensures index backwards compatibility
|
||||
var AppLuceneVersion = LuceneVersion.LUCENE_48;
|
||||
|
||||
var indexLocation = System.IO.Path.Combine(ApplicationDataStorage.Instance.ApplicationTempDataPath, "LuceneIndex");
|
||||
System.IO.Directory.CreateDirectory(indexLocation);
|
||||
|
||||
var dir = FSDirectory.Open(indexLocation);
|
||||
|
||||
// create an analyzer to process the text
|
||||
analyzer = new StandardAnalyzer(AppLuceneVersion);
|
||||
|
||||
// create an index writer
|
||||
var indexConfig = new IndexWriterConfig(AppLuceneVersion, analyzer);
|
||||
|
||||
writer = new IndexWriter(dir, indexConfig);
|
||||
|
||||
//IndexDocuments();
|
||||
}
|
||||
|
||||
public LuceneHelpSearch()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
private static void ProcessHelpTree(HelpArticle context, Dictionary<string, HelpArticle> helpArticles)
|
||||
{
|
||||
helpArticles[context.Path] = context;
|
||||
|
||||
foreach (var child in context.Children)
|
||||
{
|
||||
ProcessHelpTree(child, helpArticles);
|
||||
}
|
||||
}
|
||||
|
||||
private static void IndexDocuments()
|
||||
{
|
||||
Dictionary<string, HelpArticle> helpArticles;
|
||||
|
||||
// Clear existing
|
||||
writer.DeleteAll();
|
||||
|
||||
// Build index from help-docs.zip
|
||||
using (var file = AggContext.StaticData.OpenStream(System.IO.Path.Combine("OemSettings", "help-docs.zip")))
|
||||
using (var zip = new ZipArchive(file, ZipArchiveMode.Read))
|
||||
{
|
||||
|
||||
var tocEntry = zip.Entries.FirstOrDefault(e => e.FullName == "toc.json");
|
||||
|
||||
using (var docStream = tocEntry.Open())
|
||||
{
|
||||
var reader = new System.IO.StreamReader(docStream);
|
||||
var tocText = reader.ReadToEnd();
|
||||
|
||||
var rootHelpArticle = JsonConvert.DeserializeObject<HelpArticle>(tocText);
|
||||
|
||||
helpArticles = new Dictionary<string, HelpArticle>();
|
||||
|
||||
// Walk the documents tree building up a dictionary of article paths to articles
|
||||
ProcessHelpTree(rootHelpArticle, helpArticles);
|
||||
}
|
||||
|
||||
foreach (var entry in zip.Entries)
|
||||
{
|
||||
if (entry.FullName.ToLower().EndsWith(".md"))
|
||||
{
|
||||
using (var docStream = entry.Open())
|
||||
{
|
||||
var reader = new System.IO.StreamReader(docStream);
|
||||
|
||||
string text = reader.ReadToEnd();
|
||||
|
||||
var doc = new Document();
|
||||
|
||||
// StringField indexes but doesn't tokenise
|
||||
doc.Add(new StringField("name", helpArticles[entry.FullName].Name, Field.Store.YES));
|
||||
doc.Add(new StringField("path", entry.FullName, Field.Store.YES));
|
||||
doc.Add(new TextField("body", text, Field.Store.NO));
|
||||
|
||||
writer.AddDocument(doc);
|
||||
writer.Flush(triggerMerge: false, applyAllDeletes: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
writer.Commit();
|
||||
}
|
||||
|
||||
public IEnumerable<HelpSearchResult> Search(string text)
|
||||
{
|
||||
var parser = new QueryParser(LuceneVersion.LUCENE_48, "body", analyzer);
|
||||
var query = parser.Parse(text);
|
||||
|
||||
// re-use the writer to get real-time updates
|
||||
var searcher = new IndexSearcher(writer.GetReader(applyAllDeletes: true));
|
||||
|
||||
var hits = searcher.Search(query, 20 /* top 20 */).ScoreDocs;
|
||||
|
||||
return hits.Select(hit =>
|
||||
{
|
||||
var foundDoc = searcher.Doc(hit.Doc);
|
||||
return new HelpSearchResult()
|
||||
{
|
||||
Name = foundDoc.Get("name"),
|
||||
Path = foundDoc.Get("path")
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -85,6 +85,9 @@
|
|||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="AngleSharp" Version="0.9.11" />
|
||||
<PackageReference Include="Lucene.Net" Version="4.8.0-beta00005" />
|
||||
<PackageReference Include="Lucene.Net.Analysis.Common" Version="4.8.0-beta00005" />
|
||||
<PackageReference Include="Lucene.Net.QueryParser" Version="4.8.0-beta00005" />
|
||||
<PackageReference Include="Markdig" Version="0.15.2" />
|
||||
<PackageReference Include="MIConvexHull" Version="1.1.18.1016" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Binder" Version="2.1.1" />
|
||||
|
|
|
|||
|
|
@ -45,6 +45,16 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
if (gradientBackground != null)
|
||||
{
|
||||
graphics2D.Render(gradientBackground, this.LocalBounds.Left, 0);
|
||||
|
||||
var bounds = this.LocalBounds;
|
||||
|
||||
if (bounds.Width > gradientBackground.Width)
|
||||
{
|
||||
// Fill anything outside of the gradient region with the opaque background
|
||||
graphics2D.FillRectangle(
|
||||
new RectangleDouble(gradientBackground.Width, bounds.Bottom, bounds.Right, bounds.Top),
|
||||
this.BackgroundColor);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -32,11 +32,13 @@ using System.Collections.Generic;
|
|||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using MatterControlLib;
|
||||
using MatterHackers.Agg;
|
||||
using MatterHackers.Agg.Platform;
|
||||
using MatterHackers.Agg.UI;
|
||||
using MatterHackers.DataConverters3D;
|
||||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.CustomWidgets;
|
||||
using MatterHackers.MatterControl.Library;
|
||||
using MatterHackers.MatterControl.PartPreviewWindow.PlusTab;
|
||||
using MatterHackers.MatterControl.PrintLibrary;
|
||||
|
|
@ -45,6 +47,24 @@ using MatterHackers.VectorMath;
|
|||
|
||||
namespace MatterHackers.MatterControl.PartPreviewWindow
|
||||
{
|
||||
public class HelpSearchResult
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public string Path { get; set; }
|
||||
}
|
||||
|
||||
public class HelpSearchResultRow : SettingsRow
|
||||
{
|
||||
public HelpSearchResultRow(HelpSearchResult searchResult, ThemeConfig theme)
|
||||
: base(searchResult.Name, null, theme)
|
||||
{
|
||||
this.SearchResult = searchResult;
|
||||
}
|
||||
|
||||
public HelpSearchResult SearchResult { get; }
|
||||
}
|
||||
|
||||
public class MainViewWidget : FlowLayoutWidget
|
||||
{
|
||||
private EventHandler unregisterEvents;
|
||||
|
|
@ -75,6 +95,83 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
Padding = new BorderDouble(left: 8)
|
||||
};
|
||||
|
||||
GuiWidget searchButton = null;
|
||||
|
||||
var searchPanel = new SearchInputBox(theme)
|
||||
{
|
||||
Width = 200,
|
||||
HAnchor = HAnchor.Absolute,
|
||||
Visible = false,
|
||||
Padding = new BorderDouble(10, 3)
|
||||
};
|
||||
searchPanel.searchInput.ActualTextEditWidget.EnterPressed += (s, e) =>
|
||||
{
|
||||
searchPanel.BackgroundColor = theme.SectionBackgroundColor;
|
||||
|
||||
// TODO:
|
||||
//System.Diagnostics.Debugger.Break();
|
||||
|
||||
var rightPanel = new VerticalResizeContainer(theme, GrabBarSide.Left)
|
||||
{
|
||||
HAnchor = HAnchor.Absolute,
|
||||
VAnchor = VAnchor.Absolute,
|
||||
Width = 500,
|
||||
Height = 200,
|
||||
BackgroundColor = theme.SectionBackgroundColor
|
||||
};
|
||||
rightPanel.BoundsChanged += (s2, e2) =>
|
||||
{
|
||||
if (rightPanel.Parent != null)
|
||||
{
|
||||
rightPanel.Position = new Vector2(rightPanel.Parent.Width - rightPanel.Width, rightPanel.Position.Y);
|
||||
}
|
||||
};
|
||||
|
||||
var searcher = new LuceneHelpSearch();
|
||||
|
||||
foreach (var searchResult in searcher.Search(searchPanel.searchInput.Text))
|
||||
{
|
||||
var resultsRow = new HelpSearchResultRow(searchResult, theme);
|
||||
resultsRow.Click += this.ResultsRow_Click;
|
||||
|
||||
rightPanel.AddChild(resultsRow);
|
||||
}
|
||||
|
||||
this.Parents<SystemWindow>().FirstOrDefault().ShowRightSplitPopup(
|
||||
new MatePoint(searchPanel),
|
||||
new MatePoint(rightPanel));
|
||||
};
|
||||
searchPanel.ResetButton.Click += (s, e) =>
|
||||
{
|
||||
searchPanel.BackgroundColor = Color.Transparent;
|
||||
searchPanel.Visible = false;
|
||||
searchButton.Visible = true;
|
||||
searchPanel.searchInput.Text = "";
|
||||
|
||||
// TODO:
|
||||
//this.ClearSearch();
|
||||
};
|
||||
|
||||
extensionArea.AddChild(searchPanel);
|
||||
|
||||
searchButton = theme.CreateSearchButton();
|
||||
searchButton.Name = "App Search Button";
|
||||
searchButton.Click += (s, e) =>
|
||||
{
|
||||
if (searchPanel.Visible)
|
||||
{
|
||||
// TODO
|
||||
var a = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
searchPanel.Visible = true;
|
||||
searchButton.Visible = false;
|
||||
searchPanel.searchInput.Focus();
|
||||
}
|
||||
};
|
||||
extensionArea.AddChild(searchButton);
|
||||
|
||||
tabControl = new ChromeTabs(extensionArea, theme)
|
||||
{
|
||||
VAnchor = VAnchor.Stretch,
|
||||
|
|
@ -265,6 +362,37 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
ApplicationController.Instance.MainView = this;
|
||||
}
|
||||
|
||||
private void ResultsRow_Click(object sender, MouseEventArgs e)
|
||||
{
|
||||
var helpDocsTab = this.tabControl.AllTabs.FirstOrDefault(t => t.Key == "HelpDocs") as ChromeTab;
|
||||
if (helpDocsTab == null)
|
||||
{
|
||||
var helpTreePanel = new HelpTreePanel(theme)
|
||||
{
|
||||
HAnchor = HAnchor.Stretch,
|
||||
VAnchor = VAnchor.Stretch
|
||||
};
|
||||
|
||||
helpDocsTab = new ChromeTab("HelpDocs", "Help".Localize(), tabControl, helpTreePanel, theme, hasClose: false)
|
||||
{
|
||||
MinimumSize = new Vector2(0, theme.TabButtonHeight),
|
||||
Name = "Library Tab",
|
||||
Padding = new BorderDouble(15, 0),
|
||||
};
|
||||
|
||||
this.TabControl.AddTab(helpDocsTab);
|
||||
}
|
||||
|
||||
this.TabControl.ActiveTab = helpDocsTab;
|
||||
|
||||
if (helpDocsTab.TabContent is HelpTreePanel treePanel)
|
||||
{
|
||||
treePanel.ActiveNodePath = (sender as HelpSearchResultRow).SearchResult.Path;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
private void SetInitialTab()
|
||||
{
|
||||
// Initial tab selection - workspace load will reset if applicable
|
||||
|
|
|
|||
|
|
@ -197,7 +197,29 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
}
|
||||
}
|
||||
|
||||
private static void RightHorizontalSplitPopup(SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds)
|
||||
{
|
||||
// Calculate left for right aligned split
|
||||
Vector2 popupPosition = new Vector2(systemWindow.Width - popup.Widget.Width, 0);
|
||||
|
||||
Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position);
|
||||
|
||||
popup.Widget.Height = anchorLeft.Y;
|
||||
|
||||
popup.Widget.Position = popupPosition;
|
||||
}
|
||||
|
||||
public static void ShowPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), int borderWidth = 1)
|
||||
{
|
||||
ShowPopup(systemWindow, anchor, popup, altBounds, borderWidth, BestPopupPosition);
|
||||
}
|
||||
|
||||
public static void ShowRightSplitPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds = default(RectangleDouble), int borderWidth = 1)
|
||||
{
|
||||
ShowPopup(systemWindow, anchor, popup, altBounds, borderWidth, RightHorizontalSplitPopup);
|
||||
}
|
||||
|
||||
public static void ShowPopup(this SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds, int borderWidth, Action<SystemWindow, MatePoint, MatePoint, RectangleDouble> layoutHelper)
|
||||
{
|
||||
var hookedParents = new HashSet<GuiWidget>();
|
||||
|
||||
|
|
@ -216,44 +238,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
{
|
||||
if (anchor.Widget?.Parent != null)
|
||||
{
|
||||
// Calculate left aligned screen space position (using widgetRelativeTo.parent)
|
||||
Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position);
|
||||
anchorLeft += new Vector2(altBounds.Left, altBounds.Bottom);
|
||||
|
||||
Vector2 popupPosition = anchorLeft;
|
||||
|
||||
var bounds = altBounds == default(RectangleDouble) ? anchor.Widget.LocalBounds : altBounds;
|
||||
|
||||
Vector2 xPosition = GetXAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds);
|
||||
|
||||
Vector2 screenPosition;
|
||||
|
||||
screenPosition = anchorLeft + xPosition;
|
||||
|
||||
// Constrain
|
||||
if (screenPosition.X + popup.Widget.Width > systemWindow.Width
|
||||
|| screenPosition.X < 0)
|
||||
{
|
||||
xPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds);
|
||||
}
|
||||
|
||||
popupPosition += xPosition;
|
||||
|
||||
Vector2 yPosition = GetYAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds);
|
||||
|
||||
screenPosition = anchorLeft + yPosition;
|
||||
|
||||
// Constrain
|
||||
if (anchor.AltMate != null
|
||||
&& (screenPosition.Y + popup.Widget.Height > systemWindow.Height
|
||||
|| screenPosition.Y < 0))
|
||||
{
|
||||
yPosition = GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds);
|
||||
}
|
||||
|
||||
popupPosition += yPosition;
|
||||
|
||||
popup.Widget.Position = popupPosition;
|
||||
layoutHelper.Invoke(systemWindow, anchor, popup, altBounds);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -336,6 +321,48 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
popup.Widget.Invalidate();
|
||||
}
|
||||
|
||||
private static void BestPopupPosition(SystemWindow systemWindow, MatePoint anchor, MatePoint popup, RectangleDouble altBounds)
|
||||
{
|
||||
// Calculate left aligned screen space position (using widgetRelativeTo.parent)
|
||||
Vector2 anchorLeft = anchor.Widget.Parent.TransformToScreenSpace(anchor.Widget.Position);
|
||||
anchorLeft += new Vector2(altBounds.Left, altBounds.Bottom);
|
||||
|
||||
Vector2 popupPosition = anchorLeft;
|
||||
|
||||
var bounds = altBounds == default(RectangleDouble) ? anchor.Widget.LocalBounds : altBounds;
|
||||
|
||||
Vector2 xPosition = GetXAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds);
|
||||
|
||||
Vector2 screenPosition;
|
||||
|
||||
screenPosition = anchorLeft + xPosition;
|
||||
|
||||
// Constrain
|
||||
if (screenPosition.X + popup.Widget.Width > systemWindow.Width
|
||||
|| screenPosition.X < 0)
|
||||
{
|
||||
xPosition = GetXAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds);
|
||||
}
|
||||
|
||||
popupPosition += xPosition;
|
||||
|
||||
Vector2 yPosition = GetYAnchor(anchor.Mate, popup.Mate, popup.Widget, bounds);
|
||||
|
||||
screenPosition = anchorLeft + yPosition;
|
||||
|
||||
// Constrain
|
||||
if (anchor.AltMate != null
|
||||
&& (screenPosition.Y + popup.Widget.Height > systemWindow.Height
|
||||
|| screenPosition.Y < 0))
|
||||
{
|
||||
yPosition = GetYAnchor(anchor.AltMate, popup.AltMate, popup.Widget, bounds);
|
||||
}
|
||||
|
||||
popupPosition += yPosition;
|
||||
|
||||
popup.Widget.Position = popupPosition;
|
||||
}
|
||||
|
||||
private static Vector2 GetYAnchor(MateOptions anchor, MateOptions popup, GuiWidget popupWidget, RectangleDouble bounds)
|
||||
{
|
||||
if (anchor.Top && popup.Bottom)
|
||||
|
|
|
|||
|
|
@ -114,6 +114,7 @@ namespace MatterHackers.MatterControl.PartPreviewWindow
|
|||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// make sure the buttons state is set correctly
|
||||
printer.Connection.CommunicationStateChanged += SetPrintButtonStyle;
|
||||
startPrintButton.Closed += (s, e) => printer.Connection.CommunicationStateChanged -= SetPrintButtonStyle;
|
||||
|
|
|
|||
|
|
@ -33,9 +33,6 @@ using MatterHackers.Agg.UI;
|
|||
using MatterHackers.Localizations;
|
||||
using MatterHackers.MatterControl.CustomWidgets;
|
||||
using MatterHackers.MatterControl.PrinterCommunication;
|
||||
using MatterHackers.MatterControl.PrinterControls.PrinterConnections;
|
||||
using MatterHackers.MatterControl.SlicerConfiguration;
|
||||
using MatterHackers.SerialPortCommunication.FrostedSerial;
|
||||
|
||||
namespace MatterHackers.MatterControl.ActionBar
|
||||
{
|
||||
|
|
|
|||
|
|
@ -40,6 +40,19 @@ using MatterHackers.MatterControl.PrintLibrary;
|
|||
|
||||
namespace MatterHackers.MatterControl
|
||||
{
|
||||
public class HelpArticleTreeNode : TreeNode
|
||||
{
|
||||
public HelpArticleTreeNode(HelpArticle helpArticle, ThemeConfig theme)
|
||||
: base (theme, useIcon: false)
|
||||
{
|
||||
this.HelpArticle = helpArticle;
|
||||
this.Text = helpArticle.Name;
|
||||
this.Tag = helpArticle;
|
||||
}
|
||||
|
||||
public HelpArticle HelpArticle { get; }
|
||||
}
|
||||
|
||||
public class HelpTreePanel : SearchableTreePanel
|
||||
{
|
||||
private string guideKey = null;
|
||||
|
|
@ -318,13 +331,13 @@ namespace MatterHackers.MatterControl
|
|||
private TreeNode initialSelection = null;
|
||||
private TreeNode rootNode;
|
||||
|
||||
private Dictionary<string, HelpArticleTreeNode> nodesByPath = new Dictionary<string, HelpArticleTreeNode>();
|
||||
|
||||
private TreeNode ProcessTree(HelpArticle container)
|
||||
{
|
||||
var treeNode = new TreeNode(theme, false)
|
||||
{
|
||||
Text = container.Name,
|
||||
Tag = container
|
||||
};
|
||||
var treeNode = new HelpArticleTreeNode(container, theme);
|
||||
|
||||
nodesByPath[container.Path] = treeNode;
|
||||
|
||||
foreach (var item in container.Children.OrderBy(i => i.Children.Count == 0).ThenBy(i => i.Name))
|
||||
{
|
||||
|
|
@ -334,12 +347,9 @@ namespace MatterHackers.MatterControl
|
|||
}
|
||||
else
|
||||
{
|
||||
var newNode = new TreeNode(theme, false)
|
||||
{
|
||||
Text = item.Name,
|
||||
Tag = item
|
||||
var newNode = new HelpArticleTreeNode(item, theme);
|
||||
|
||||
};
|
||||
nodesByPath[item.Path] = newNode;
|
||||
|
||||
if (item.Name == guideKey
|
||||
|| (guideKey != null
|
||||
|
|
@ -356,6 +366,18 @@ namespace MatterHackers.MatterControl
|
|||
return treeNode;
|
||||
}
|
||||
|
||||
public string ActiveNodePath
|
||||
{
|
||||
get => treeView.SelectedNode?.Tag as string;
|
||||
set
|
||||
{
|
||||
if (nodesByPath.TryGetValue(value, out HelpArticleTreeNode treeNode))
|
||||
{
|
||||
treeView.SelectedNode = treeNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Color ChildBorderColor { get; private set; }
|
||||
|
||||
private void AddContent(GuiWidget column, string text, bool left, bool bold)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue