Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added IUIDropDownButton and improve Json > Table UI #1006

Merged
merged 2 commits into from
Dec 22, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/app/dev/DevToys.Api/Core/IFileStorage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ public interface IFileStorage
/// </summary>
string AppCacheDirectory { get; }

// TODO: There's a problem with this API. It's not possible to know what file type the user selected. The file type can impact the data written into the file (i.e PNG vs JPEG).
/// <summary>
/// Prompt the user to select a location to save a file, and decide of the file name.
/// </summary>
Expand Down
153 changes: 153 additions & 0 deletions src/app/dev/DevToys.Api/Tool/GUI/Components/IUIDropDownButton.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
namespace DevToys.Api;

/// <summary>
/// A component that represents a drop down button where the user can click on a menu item.
/// </summary>
public interface IUIDropDownButton : IUIElement
{
/// <summary>
/// Gets the list of items displayed in the drop down menu.
/// </summary>
IUIDropDownMenuItem[]? MenuItems { get; }

/// <summary>
/// Gets the text to display in the drop down button.
/// </summary>
string? Text { get; }

/// <summary>
/// Gets the name of the font containing the icon.
/// </summary>
string? IconFontName { get; }

/// <summary>
/// Gets the glyph corresponding to the icon in the <see cref="IconFontName"/>.
/// </summary>
char IconGlyph { get; }

///<summary>
/// Raised when <see cref="MenuItems"/> is changed.
/// </summary>
event EventHandler? MenuItemsChanged;

/// <summary>
/// Raised when <see cref="Text"/> is changed.
/// </summary>
event EventHandler? TextChanged;

/// <summary>
/// Raised when <see cref="IconFontName"/> is changed.
/// </summary>
event EventHandler? IconFontNameChanged;

/// <summary>
/// Raised when <see cref="IconGlyph"/> is changed.
/// </summary>
event EventHandler? IconGlyphChanged;
}

[DebuggerDisplay($"Id = {{{nameof(Id)}}}, Text = {{{nameof(Text)}}}")]
internal sealed class UIDropDownButton : UIElement, IUIDropDownButton
{
private IUIDropDownMenuItem[]? _menuItems;
private string? _text;
private string? _iconFontName;
private char _iconGlyph;

internal UIDropDownButton(string? id)
: base(id)
{
}

public IUIDropDownMenuItem[]? MenuItems
{
get => _menuItems;
internal set => SetPropertyValue(ref _menuItems, value, MenuItemsChanged);
}

public string? Text
{
get => _text;
internal set => SetPropertyValue(ref _text, value, TextChanged);
}

public string? IconFontName
{
get => _iconFontName;
internal set
{
Guard.IsNotNullOrWhiteSpace(value);
SetPropertyValue(ref _iconFontName, value, IconFontNameChanged);
}
}

public char IconGlyph
{
get => _iconGlyph;
internal set => SetPropertyValue(ref _iconGlyph, value, IconGlyphChanged);
}

public event EventHandler? MenuItemsChanged;
public event EventHandler? TextChanged;
public event EventHandler? IconFontNameChanged;
public event EventHandler? IconGlyphChanged;
}

public static partial class GUI
{
/// <summary>
/// Create a component that represents a drop down button where the user can click on a menu item.
/// </summary>
public static IUIDropDownButton DropDownButton()
{
return DropDownButton(null);
}

/// <summary>
/// Create a component that represents a drop down button where the user can click on a menu item.
/// </summary>
/// <param name="id">An optional unique identifier for this UI element.</param>
public static IUIDropDownButton DropDownButton(string? id)
{
return new UIDropDownButton(id);
}

/// <summary>
/// Create a component that represents a drop down button where the user can click on a menu item.
/// </summary>
/// <param name="id">An optional unique identifier for this UI element.</param>
/// <param name="text">The text to display in the drop down button.</param>
public static IUIDropDownButton DropDownButton(string? id, string text)
{
return new UIDropDownButton(id).Text(text);
}

/// <summary>
/// Sets the <see cref="IUIDropDownButton.Text"/> of the drop down button.
/// </summary>
public static IUIDropDownButton Text(this IUIDropDownButton element, string? text)
{
((UIDropDownButton)element).Text = text;
return element;
}

/// <summary>
/// Sets the icon of the drop down button.
/// </summary>
public static IUIDropDownButton Icon(this IUIDropDownButton element, string fontName, char glyph)
{
var button = (UIDropDownButton)element;
button.IconFontName = fontName;
button.IconGlyph = glyph;
return button;
}

/// <summary>
/// Sets the <see cref="IUIDropDownButton.MenuItems"/> in the drop down button.
/// </summary>
public static IUIDropDownButton WithMenuItems(this IUIDropDownButton element, params IUIDropDownMenuItem[] menuItems)
{
((UIDropDownButton)element).MenuItems = menuItems;
return element;
}
}
165 changes: 165 additions & 0 deletions src/app/dev/DevToys.Api/Tool/GUI/Components/IUIDropDownMenuItem.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
namespace DevToys.Api;

/// <summary>
/// A component that represents a menu item, which reacts when clicking on it.
/// </summary>
public interface IUIDropDownMenuItem
{
/// <summary>
/// Gets whether this menu item should be enabled or disabled. Default is true.
/// </summary>
bool IsEnabled { get; }

/// <summary>
/// Gets the text to display in the menu item.
/// </summary>
string? Text { get; }

/// <summary>
/// Gets the name of the font containing the icon.
/// </summary>
string? IconFontName { get; }

/// <summary>
/// Gets the glyph corresponding to the icon in the <see cref="IconFontName"/>.
/// </summary>
char IconGlyph { get; }

/// <summary>
/// Gets the action to run when the user clicks the menu item.
/// </summary>
Func<ValueTask>? OnClickAction { get; }

/// <summary>
/// Raised when <see cref="IsEnabled"/> is changed.
/// </summary>
event EventHandler? IsEnabledChanged;

/// <summary>
/// Raised when <see cref="Text"/> is changed.
/// </summary>
event EventHandler? TextChanged;

/// <summary>
/// Raised when <see cref="IconFontName"/> is changed.
/// </summary>
event EventHandler? IconFontNameChanged;

/// <summary>
/// Raised when <see cref="IconGlyph"/> is changed.
/// </summary>
event EventHandler? IconGlyphChanged;
}

[DebuggerDisplay($"Text = {{{nameof(Text)}}}")]
internal sealed class UIDropDownMenuItem : ViewModelBase, IUIDropDownMenuItem
{
private bool _isEnabled = true;
private string? _text;
private string? _iconFontName;
private char _iconGlyph;

public bool IsEnabled
{
get => _isEnabled;
internal set
{
if (_isEnabled != value)
{
SetPropertyValue(ref _isEnabled, value, IsEnabledChanged);
}
}
}

public string? Text
{
get => _text;
internal set => SetPropertyValue(ref _text, value, TextChanged);
}

public string? IconFontName
{
get => _iconFontName;
internal set
{
Guard.IsNotNullOrWhiteSpace(value);
SetPropertyValue(ref _iconFontName, value, IconFontNameChanged);
}
}

public char IconGlyph
{
get => _iconGlyph;
internal set => SetPropertyValue(ref _iconGlyph, value, IconGlyphChanged);
}

public Func<ValueTask>? OnClickAction { get; internal set; }

public event EventHandler? IsEnabledChanged;
public event EventHandler? TextChanged;
public event EventHandler? IconFontNameChanged;
public event EventHandler? IconGlyphChanged;
}

public static partial class GUI
{
/// <summary>
/// Create a component that represents a menu item, which reacts when clicking on it.
/// </summary>
public static IUIDropDownMenuItem DropDownMenuItem()
{
return new UIDropDownMenuItem();
}

/// <summary>
/// Create a component that represents a menu item, which reacts when clicking on it.
/// </summary>
/// <param name="text">The text to display in the menu item.</param>
public static IUIDropDownMenuItem DropDownMenuItem(string text)
{
return DropDownMenuItem().Text(text);
}

/// <summary>
/// Sets the <see cref="IUIDropDownMenuItem.Text"/> of the menu item.
/// </summary>
public static IUIDropDownMenuItem Text(this IUIDropDownMenuItem element, string? text)
{
((UIDropDownMenuItem)element).Text = text;
return element;
}

/// <summary>
/// Sets the action to run when clicking on the menu item.
/// </summary>
public static IUIDropDownMenuItem OnClick(this IUIDropDownMenuItem element, Func<ValueTask>? actionOnClick)
{
((UIDropDownMenuItem)element).OnClickAction = actionOnClick;
return element;
}

/// <summary>
/// Sets the action to run when clicking on the menu item.
/// </summary>
public static IUIDropDownMenuItem OnClick(this IUIDropDownMenuItem element, Action? actionOnClick)
{
((UIDropDownMenuItem)element).OnClickAction
= () =>
{
actionOnClick?.Invoke();
return ValueTask.CompletedTask;
};
return element;
}

/// <summary>
/// Sets the icon of the menu item.
/// </summary>
public static IUIDropDownMenuItem Icon(this IUIDropDownMenuItem element, string fontName, char glyph)
{
var menuItem = (UIDropDownMenuItem)element;
menuItem.IconFontName = fontName;
menuItem.IconGlyph = glyph;
return menuItem;
}
}
25 changes: 1 addition & 24 deletions src/app/dev/DevToys.Api/Tool/GUI/Components/IUIElement.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ public interface IUIElement
}

[DebuggerDisplay($"Id = {{{nameof(Id)}}}, IsVisible = {{{nameof(IsVisible)}}}, IsEnabled = {{{nameof(IsEnabled)}}}")]
internal abstract class UIElement : IUIElement, INotifyPropertyChanged
internal abstract class UIElement : ViewModelBase, IUIElement
{
private bool _isVisible = true;
private bool _isEnabled = true;
Expand Down Expand Up @@ -100,29 +100,6 @@ public UIVerticalAlignment VerticalAlignment
public event EventHandler? HorizontalAlignmentChanged;

public event EventHandler? VerticalAlignmentChanged;

public event PropertyChangedEventHandler? PropertyChanged;

protected bool SetPropertyValue<T>(
ref T field,
T value,
EventHandler? propertyChangedEventHandler,
[CallerMemberName] string? propertyName = null)
{
if (!EqualityComparer<T>.Default.Equals(field, value))
{
field = value;
propertyChangedEventHandler?.Invoke(this, EventArgs.Empty);
OnPropertyChanged(propertyName);
return true;
}
return false;
}

protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new(propertyName));
}
}

public static partial class GUI
Expand Down
Loading