mirror of
https://github.com/bloxstraplabs/bloxstrap.git
synced 2025-04-23 02:51:26 -07:00
* add custom bootstrappers * add avalonedit to licenses page * add gif support * add stretch & stretchdirection to images * dont create a bitmapimage for gifs * remove maxheight and maxwidth sets * remove comment * add isenabled * add more textblock properties * add markdowntextblocks * update how transform elements are stored * overhaul textbox content * dont set fontsize if not set * fix warnings * add foreground property to control * add background property to textblock * count descendants and increase element cap * add auto complete * dont display completion window if there is no data * sort schema elements and types * make ! close the completion window * add end tag auto complete * fix pos being wrong * dont treat comments as elements * add imagebrushes * follow same conventions as brushes * fix exception messages * fix them again * update schema * fix crash * now it works * wrong attribute name * add solidcolorbrush * move converters into a separate file * add lineargradientbrushes * unify handlers * update schema * add fake BloxstrapCustomBootstrapper * stop adding an extra end character * add property element auto-complete * add title attribute to custombloxstrapbootstrapper * add shapes * add string translation support * use default wpf size instead of 100x100 * update min height of window * fix verticalalignment not working * uncap height and width * add effects * move transformation handler inside frameworkelement * fix title bar effect & transformation removal * add more frameworkelement properties * add layout transform * add font properties to control * improve window border stuff * make sure file contents are in CRLF * add cornerradius to progress bar * add progressring * Update wpfui * update schema * update function names * add children check to content * make sure only one content is defined * add fontfamily * update schema * only allow file uris for images * disable backdrop * move text setter to textblock handler from base * split up creator into multiple files * turn version into a constant * add grids * cleanup converters * add IgnoreTitleBarInset * add Version to schema * reveal custom bootstrapper stuff on selection * increase listbox height * only set statustext binding in textblock * update ui * rename ZIndex to Panel.ZIndex * add stackpanel * add border * fix being unable to apply transforms on grids * rearrange and add new editor button * use snackbars for saving * add close confirmation message * use viewmodel variable * remove pointless onpropertychanged call * add version string format * start editor window in the centre * update licenses page also resized the about window so everything could fit nicely * fix border not inheriting frameworkelement * add WindowCornerPreference * add the import dialog * add an export theme button * update version number * localise CustomDialog exceptions * localise custom theme editor * localise custom theme add dialog * localise frontend * localise appearance menu page * change customtheme error strings namespace * change icons on appearance page * update button margin on appearance page
152 lines
5.9 KiB
C#
152 lines
5.9 KiB
C#
using System.Windows;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Bloxstrap.UI.Elements.Bootstrapper
|
|
{
|
|
public partial class CustomDialog
|
|
{
|
|
const int Version = 1;
|
|
|
|
private class DummyFrameworkElement : FrameworkElement { }
|
|
|
|
private const int MaxElements = 100;
|
|
|
|
private bool _initialised = false;
|
|
|
|
// prevent users from creating elements with the same name multiple times
|
|
private List<string> UsedNames { get; } = new List<string>();
|
|
|
|
private string ThemeDir { get; set; } = "";
|
|
|
|
delegate object HandleXmlElementDelegate(CustomDialog dialog, XElement xmlElement);
|
|
|
|
private static Dictionary<string, HandleXmlElementDelegate> _elementHandlerMap = new Dictionary<string, HandleXmlElementDelegate>()
|
|
{
|
|
["BloxstrapCustomBootstrapper"] = HandleXmlElement_BloxstrapCustomBootstrapper_Fake,
|
|
["TitleBar"] = HandleXmlElement_TitleBar,
|
|
["Button"] = HandleXmlElement_Button,
|
|
["ProgressBar"] = HandleXmlElement_ProgressBar,
|
|
["ProgressRing"] = HandleXmlElement_ProgressRing,
|
|
["TextBlock"] = HandleXmlElement_TextBlock,
|
|
["MarkdownTextBlock"] = HandleXmlElement_MarkdownTextBlock,
|
|
["Image"] = HandleXmlElement_Image,
|
|
["Grid"] = HandleXmlElement_Grid,
|
|
["StackPanel"] = HandleXmlElement_StackPanel,
|
|
["Border"] = HandleXmlElement_Border,
|
|
|
|
["SolidColorBrush"] = HandleXmlElement_SolidColorBrush,
|
|
["ImageBrush"] = HandleXmlElement_ImageBrush,
|
|
["LinearGradientBrush"] = HandleXmlElement_LinearGradientBrush,
|
|
|
|
["GradientStop"] = HandleXmlElement_GradientStop,
|
|
|
|
["ScaleTransform"] = HandleXmlElement_ScaleTransform,
|
|
["SkewTransform"] = HandleXmlElement_SkewTransform,
|
|
["RotateTransform"] = HandleXmlElement_RotateTransform,
|
|
["TranslateTransform"] = HandleXmlElement_TranslateTransform,
|
|
|
|
["BlurEffect"] = HandleXmlElement_BlurEffect,
|
|
["DropShadowEffect"] = HandleXmlElement_DropShadowEffect,
|
|
|
|
["Ellipse"] = HandleXmlElement_Ellipse,
|
|
["Line"] = HandleXmlElement_Line,
|
|
["Rectangle"] = HandleXmlElement_Rectangle,
|
|
|
|
["RowDefinition"] = HandleXmlElement_RowDefinition,
|
|
["ColumnDefinition"] = HandleXmlElement_ColumnDefinition
|
|
};
|
|
|
|
private static T HandleXml<T>(CustomDialog dialog, XElement xmlElement) where T : class
|
|
{
|
|
if (!_elementHandlerMap.ContainsKey(xmlElement.Name.ToString()))
|
|
throw new CustomThemeException("CustomTheme.Errors.UnknownElement", xmlElement.Name);
|
|
|
|
var element = _elementHandlerMap[xmlElement.Name.ToString()](dialog, xmlElement);
|
|
if (element is not T)
|
|
throw new CustomThemeException("CustomTheme.Errors.ElementInvalidChild", xmlElement.Parent!.Name, xmlElement.Name);
|
|
|
|
return (T)element;
|
|
}
|
|
|
|
private static void AddXml(CustomDialog dialog, XElement xmlElement)
|
|
{
|
|
if (xmlElement.Name.ToString().StartsWith($"{xmlElement.Parent!.Name}."))
|
|
return; // not an xml element
|
|
|
|
var uiElement = HandleXml<UIElement>(dialog, xmlElement);
|
|
if (uiElement is not DummyFrameworkElement)
|
|
dialog.ElementGrid.Children.Add(uiElement);
|
|
}
|
|
|
|
private static void AssertThemeVersion(string? versionStr)
|
|
{
|
|
if (string.IsNullOrEmpty(versionStr))
|
|
throw new CustomThemeException("CustomTheme.Errors.VersionNotSet", "BloxstrapCustomBootstrapper");
|
|
|
|
if (!uint.TryParse(versionStr, out uint version))
|
|
throw new CustomThemeException("CustomTheme.Errors.VersionNotNumber", "BloxstrapCustomBootstrapper");
|
|
|
|
switch (version)
|
|
{
|
|
case Version:
|
|
break;
|
|
case 0: // Themes made between Oct 19, 2024 to Mar 11, 2025 (on the feature/custom-bootstrappers branch)
|
|
throw new CustomThemeException("CustomTheme.Errors.VersionNotSupported", "BloxstrapCustomBootstrapper", version);
|
|
default:
|
|
throw new CustomThemeException("CustomTheme.Errors.VersionNotRecognised", "BloxstrapCustomBootstrapper", version);
|
|
}
|
|
}
|
|
|
|
private void HandleXmlBase(XElement xml)
|
|
{
|
|
if (_initialised)
|
|
throw new CustomThemeException("CustomTheme.Errors.DialogAlreadyInitialised");
|
|
|
|
if (xml.Name != "BloxstrapCustomBootstrapper")
|
|
throw new CustomThemeException("CustomTheme.Errors.InvalidRoot", "BloxstrapCustomBootstrapper");
|
|
|
|
AssertThemeVersion(xml.Attribute("Version")?.Value);
|
|
|
|
if (xml.Descendants().Count() > MaxElements)
|
|
throw new CustomThemeException("CustomTheme.Errors.TooManyElements", MaxElements, xml.Descendants().Count());
|
|
|
|
_initialised = true;
|
|
|
|
// handle root
|
|
HandleXmlElement_BloxstrapCustomBootstrapper(this, xml);
|
|
|
|
// handle everything else
|
|
foreach (var child in xml.Elements())
|
|
AddXml(this, child);
|
|
}
|
|
|
|
#region Public APIs
|
|
public void ApplyCustomTheme(string name, string contents)
|
|
{
|
|
ThemeDir = System.IO.Path.Combine(Paths.CustomThemes, name);
|
|
|
|
XElement xml;
|
|
|
|
try
|
|
{
|
|
using (MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(contents)))
|
|
xml = XElement.Load(ms);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
throw new CustomThemeException(ex, "CustomTheme.Errors.XMLParseFailed", ex.Message);
|
|
}
|
|
|
|
HandleXmlBase(xml);
|
|
}
|
|
|
|
public void ApplyCustomTheme(string name)
|
|
{
|
|
string path = System.IO.Path.Combine(Paths.CustomThemes, name, "Theme.xml");
|
|
|
|
ApplyCustomTheme(name, File.ReadAllText(path));
|
|
}
|
|
#endregion
|
|
}
|
|
}
|