Editor/Dock/TodoDock.cs
using Editor;
using Sandbox;
using System.Collections.Generic;
using System.Linq;
using Todo.CodeImport;
using Todo.Dialogs;
using Todo.List;
using Todo.Search;
using Todo.Widgets;
using Todo.Widgets.List;
using Todo.Widgets.List.Items;
namespace Todo;
[Dock( "Editor", "Todos", "checklist" )]
public sealed partial class TodoDock : Widget
{
public string SearchText = "";
public static TodoCookies Cookies;
public static TodoDock Instance;
public bool IsGroupUncollapsed => IsSearching && Cookies.UnCollapseGroupsOnSearch;
public bool IsSearching => string.IsNullOrWhiteSpace( SearchText ) is false;
int VerticalScrollHeight = 0;
TodoList List;
public TodoDock( Widget parent ) : base( parent, true )
{
Instance = this;
Cookies = new();
SearchText = Cookies.LastSearch;
DeleteOnClose = true;
MinimumSize = new( 320f, 400f );
FocusMode = FocusMode.Click;
Layout = Layout.Column();
Layout.Spacing = 4f;
Layout.Margin = 2f;
Build();
}
public void RefreshItems()
{
if ( List.IsValid() )
VerticalScrollHeight = List.VerticalScrollbar.Value;
LoadItems();
}
public void SaveAndRefresh()
{
Cookies.Save();
RefreshItems();
}
private void Build()
{
Layout.Clear( true );
LineEdit searchBar = Layout.Add( new LineEdit( this ) );
searchBar.PlaceholderText = "Search...";
searchBar.MinimumHeight = 30f;
searchBar.Text = SearchText;
searchBar.TextChanged += ( searchText ) =>
{
SearchText = searchText.ToLower().Trim();
Cookies.LastSearch = SearchText;
Cookies.Save();
RefreshItems();
};
Layout controlLayout = Layout.Add( new Widget( this ) ).Layout = Layout.Row();
controlLayout.Spacing = 4f;
Button addButton = controlLayout.Add( new Button( "Add New Entry", "add", this ), 9 );
addButton.Clicked = OpenEntryWidget;
controlLayout.Add( new ToolsControls( this ) );
List = Layout.Add( new TodoList() );
LoadItems();
}
[Shortcut( "todo.new-entry", "CTRL+W", ShortcutType.Application )]
private void OpenEntryWidget()
{
var widget = new ManualEntryCreatorDialog( null );
widget.Show();
}
private void LoadItems()
{
List.Clear();
if ( Cookies.ShowManualEntries )
{
if ( Cookies.ShowCodeEntries && IsSearching is false )
List.AddItem( new ItemText( "Manual Entries", ItemText.TextType.Title ) );
LoadManualEntries();
}
if ( Cookies.ShowCodeEntries )
{
if ( Cookies.ShowManualEntries && IsSearching is false )
List.AddItem( new ItemText( "Code Entries", ItemText.TextType.Title ) );
LoadCodeEntries();
}
if ( List.Items.Count() < 1 )
{
if ( IsSearching )
List.AddItem( new ItemText( "Couldn't Find Any Entries", ItemText.TextType.Hint ) );
else if ( (Cookies.ShowManualEntries && Cookies.ShowCodeEntries) is false )
List.AddItem( new ItemText( "Visibility Turned Off", ItemText.TextType.Hint ) );
else
List.AddItem( new ItemText( "Add New Entries With \"Add New Entry\"", ItemText.TextType.Hint ) );
}
PurgeDeadGroups();
}
private void PurgeDeadGroups()
{
HashSet<string> manualGroups = GetAllManualGroups();
HashSet<string> codeGroups = GetAllCodeGroups();
List<string> deadGroups = new List<string>();
foreach ( string group in Cookies.GroupsState.Keys )
{
if ( manualGroups.Contains( group ) || codeGroups.Contains( group ) )
continue;
deadGroups.Add( group );
}
foreach ( var deadGroup in deadGroups )
{
Cookies.GroupsState.Remove( deadGroup );
}
}
private HashSet<string> GetAllManualGroups()
{
return Cookies.Datas.Select( data => data.Group ).ToHashSet();
}
private HashSet<string> GetAllCodeGroups()
{
return FileUtility.GetAllFiles( new() { ".cs", ".razor" } ).Select( x => x.Name ).ToHashSet();
}
private void LoadManualEntries()
{
Dictionary<string, List<TodoEntry>> grouppedEntries = new();
foreach ( var item in Cookies.Datas )
{
grouppedEntries.GetOrCreate( item.Group ).Add( item );
}
List<string> sortedGroups = grouppedEntries.Keys.ToList();
sortedGroups.Sort();
foreach ( string groupName in sortedGroups )
{
if ( Cookies.GroupsState.ContainsKey( groupName ) is false )
{
Cookies.GroupsState.Add( groupName, true );
}
ItemGroup group = List.AddItem(
new ItemGroup()
{
Name = groupName,
CanBeEdited = true,
ShowProgress = true
}
);
if ( group.IsOpen is false )
continue;
int validSearches = 0;
foreach ( var entry in grouppedEntries[groupName] )
{
if ( SearchEntries.FilterEntry( entry, ref validSearches ) is false )
continue;
List.AddItem( entry );
}
if ( validSearches == 0 )
{
List.RemoveItem( group );
}
}
}
private void LoadCodeEntries()
{
Dictionary<string, List<CodeEntry>> entries =
ParseCode.ProcessFiles( FileUtility.GetAllFiles( new() { ".cs", ".razor" } ) );
List<string> sortedGroups = entries.Keys.ToList();
sortedGroups.Sort();
foreach ( var groupName in sortedGroups )
{
if ( Cookies.GroupsState.ContainsKey( groupName ) is false )
{
Cookies.GroupsState.Add( groupName, true );
}
ItemGroup group = List.AddItem(
new ItemGroup()
{
Name = groupName,
CanBeEdited = false
}
);
if ( group.IsOpen is false )
continue;
int validSearches = 0;
foreach ( var entry in entries[groupName] )
{
if ( SearchEntries.FilterCode( entry, groupName, ref validSearches ) is false )
continue;
List.AddItem( entry );
}
if ( validSearches == 0 )
{
List.RemoveItem( group );
}
}
}
[EditorEvent.Frame]
public void Frame()
{
if ( VerticalScrollHeight > 0 )
{
List.VerticalScrollbar.Value = VerticalScrollHeight;
VerticalScrollHeight = 0;
}
}
[EditorEvent.Hotload]
public void OnHotload()
{
if ( Cookies.ShowCodeEntries is false )
return;
RefreshItems();
}
}