Skip to content

Commit

Permalink
Folder tree component
Browse files Browse the repository at this point in the history
Created a component to show a tree of folders from the file system
  • Loading branch information
tzachshabtay committed Jan 13, 2019
1 parent b94d751 commit 55bbae6
Show file tree
Hide file tree
Showing 7 changed files with 176 additions and 7 deletions.
6 changes: 6 additions & 0 deletions Source/AGS.API/UI/Controls/Tree/ITreeNodeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,5 +37,11 @@ public interface ITreeNodeView
/// </summary>
/// <value>The horizontal panel.</value>
IPanel HorizontalPanel { get; }

/// <summary>
/// An event that can be triggered to notify the tree view that this node needs to be re-rendered on screen.
/// </summary>
/// <value>The on refresh display needed event.</value>
IBlockingEvent OnRefreshDisplayNeeded { get; }
}
}
3 changes: 2 additions & 1 deletion Source/Editor/AGS.Editor/AGSEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ public static void SetupResolver()
Resolver.Override(resolver => resolver.Builder.RegisterType<KeyboardBindings>().SingleInstance());
Resolver.Override(resolver => resolver.Builder.RegisterType<ActionManager>().SingleInstance());
Resolver.Override(resolver => resolver.Builder.RegisterAssemblyTypes(typeof(GameLoader).Assembly).
Except<InspectorTreeNodeProvider>().Except<EditorShouldBlockEngineInput>().Except<EditorUIEvents>().AsImplementedInterfaces().ExternallyOwned());
Except<EditorShouldBlockEngineInput>().Except<EditorUIEvents>().AsImplementedInterfaces().ExternallyOwned());
Resolver.Override(resolver => { var editor = new AGSEditor(resolver); resolver.Builder.RegisterInstance(editor); });
Resolver.Override(resolver => resolver.RegisterType<AGSTreeNodeViewProvider, ITreeNodeViewProvider>());
}

public static IEditorPlatform Platform { get; set; }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
using System;
using System.Linq;
using System.Threading;
using AGS.API;
using AGS.Engine;

namespace AGS.Editor
{
public class FolderNodeViewProvider: ITreeNodeViewProvider
{
private readonly ITreeNodeViewProvider _inner;
private readonly IGameFactory _factory;
private const string FOLDER_HOVERED = "FolderHovered";

private static int _nextNodeId;

public FolderNodeViewProvider(ITreeNodeViewProvider inner, IGameFactory factory)
{
_inner = inner;
_factory = factory;
}

public void BeforeDisplayingNode(ITreeStringNode item, ITreeNodeView nodeView, bool isCollapsed, bool isHovered, bool isSelected)
{
isHovered |= item.Properties.Bools.GetValue(FOLDER_HOVERED);
_inner.BeforeDisplayingNode(item, nodeView, isCollapsed, isHovered, isSelected);
var folderIcon = (ILabel) nodeView.ExpandButton.TreeNode.Children.First(c => c.ID.StartsWith("FolderIcon", StringComparison.InvariantCulture));
folderIcon.Text = isSelected ? FontIcons.FolderOpen : FontIcons.Folder;
folderIcon.TextConfig.Brush = isHovered ? GameViewColors.HoveredTextBrush : GameViewColors.TextBrush;
}

public ITreeNodeView CreateNode(ITreeStringNode node, IRenderLayer layer, IObject parent)
{
var view = _inner.CreateNode(node, layer, parent);
int nodeId = Interlocked.Increment(ref _nextNodeId);
var folderIcon = _factory.UI.GetLabel($"FolderIcon_{node.Text}_{nodeId}", "", 25f, 25f, 15f, 0f, view.ExpandButton, AGSTextConfig.Clone(FontIcons.IconConfig));
folderIcon.Text = FontIcons.Folder;
folderIcon.IsPixelPerfect = false;
folderIcon.Enabled = true;
folderIcon.MouseEnter.Subscribe(() =>
{
node.Properties.Bools.SetValue(FOLDER_HOVERED, true);
view.OnRefreshDisplayNeeded.Invoke();
});
folderIcon.MouseLeave.Subscribe(() =>
{
node.Properties.Bools.SetValue(FOLDER_HOVERED, false);
view.OnRefreshDisplayNeeded.Invoke();
});
folderIcon.MouseClicked.Subscribe(async (args) => await view.TreeItem.MouseClicked.InvokeAsync(args));
return view;
}
}
}
100 changes: 100 additions & 0 deletions Source/Editor/AGS.Editor/Components/FileSelector/FolderTree.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using AGS.API;
using AGS.Engine;

namespace AGS.Editor
{
[RequiredComponent(typeof(ITreeViewComponent))]
public class FolderTree: AGSComponent
{
private ITreeViewComponent _treeView;
private string _defaultFolder;
private readonly IDevice _device;
private Folder _root;
private readonly IGameFactory _factory;

public FolderTree(IDevice device, IGameFactory factory)
{
_device = device;
_factory = factory;
}

public string DefaultFolder
{
get => _defaultFolder;
set
{
_defaultFolder = value;
buildTreeModel();
}
}

public override void Init()
{
base.Init();
Entity.Bind<ITreeViewComponent>(c => { _treeView = c; configureTreeUI(); refreshTreeUI(); }, _ => _treeView = null);
}

private async void buildTreeModel()
{
_root = await buildTreeModel(DefaultFolder);
refreshTreeUI();
}

private async Task<Folder> buildTreeModel(string path)
{
var dirs = (await Task.Run(() => _device.FileSystem.GetDirectories(path))).ToArray();
List<Folder> folders = new List<Folder>(dirs.Length);
foreach (var dir in dirs)
{
folders.Add(await buildTreeModel(dir));
}
return new Folder(Path.GetFileName(path), path, folders.ToArray());
}

private void configureTreeUI()
{
var tree = _treeView;
if (tree == null) return;
tree.NodeViewProvider = new FolderNodeViewProvider(tree.NodeViewProvider, _factory);
}

private void refreshTreeUI()
{
var root = _root;
var tree = _treeView;
if (root == null || tree == null) return;

tree.Tree = _root.ToNode(GameViewColors.ButtonTextConfig.Font);
tree.Expand(tree.Tree);
}

private class Folder
{
public Folder(string name, string fullPath, Folder[] folders)
{
Name = name;
FullPath = fullPath;
Folders = folders;
}

public string FullPath { get; }
public string Name { get; }
public Folder[] Folders { get; }

public ITreeStringNode ToNode(IFont font)
{
AGSTreeStringNode node = new AGSTreeStringNode(Name, font);
if (Folders.Length > 0)
{
node.TreeNode.AddChildren(Folders.Select(f => f.ToNode(font)).ToList());
}
return node;
}
}
}
}
5 changes: 4 additions & 1 deletion Source/Editor/AGS.Editor/Skins/FontIcons.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,5 +60,8 @@ public static void Init(IFontFactory fontLoader)

public const string RadioUnchecked = "\uf111";
public const string RadioChecked = "\uf192";

public const string Folder = "\uf07b";
public const string FolderOpen = "\uf07c";
}
}
}
13 changes: 8 additions & 5 deletions Source/Engine/AGS.Engine/UI/Controls/Tree/AGSTreeNodeView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,19 @@ public AGSTreeNodeView(IUIControl treeItem, IButton expandButton, IPanel parentP
ParentPanel = parentPanel;
VerticalPanel = verticalPanel;
HorizontalPanel = horizontalPanel;
OnRefreshDisplayNeeded = new AGSEvent();
}

public IUIControl TreeItem { get; private set; }
public IUIControl TreeItem { get; }

public IButton ExpandButton { get; private set; }
public IButton ExpandButton { get; }

public IPanel ParentPanel { get; private set; }
public IPanel ParentPanel { get; }

public IPanel VerticalPanel { get; private set; }
public IPanel VerticalPanel { get; }

public IPanel HorizontalPanel { get; private set; }
public IPanel HorizontalPanel { get; }

public IBlockingEvent OnRefreshDisplayNeeded { get; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,7 @@ public void Dispose()
view.TreeItem.MouseEnter.Unsubscribe(onMouseEnterNode);
view.TreeItem.MouseLeave.Unsubscribe(onMouseLeaveNode);
view.TreeItem.MouseClicked.Unsubscribe(onItemSelected);
view.OnRefreshDisplayNeeded.Unsubscribe(RefreshDisplay);
var expandButton = view.ExpandButton;
if (expandButton != null)
{
Expand Down Expand Up @@ -576,6 +577,7 @@ private void initView()
view.TreeItem.MouseEnter.Subscribe(onMouseEnterNode);
view.TreeItem.MouseLeave.Subscribe(onMouseLeaveNode);
view.TreeItem.MouseClicked.Subscribe(onItemSelected);
view.OnRefreshDisplayNeeded.Subscribe(RefreshDisplay);
var expandButton = view.ExpandButton;
if (expandButton != null)
{
Expand Down

0 comments on commit 55bbae6

Please sign in to comment.