From aa9e1ff1dae4f57bc7cfd7144ceca54985598e4a Mon Sep 17 00:00:00 2001 From: Luiz Henrique Cassettari Date: Sun, 7 Jul 2024 19:50:26 -0300 Subject: [PATCH] Add `RibbonThemeBitmapUtils` to change theme for `BitmapSource` --- CHANGELOG.md | 3 + Directory.Build.props | 2 +- ricaun.Revit.UI.Example/Revit/App.cs | 2 +- ricaun.Revit.UI.Example/Revit/AppList.cs | 2 +- ricaun.Revit.UI.Example/Revit/AppResource.cs | 2 +- ricaun.Revit.UI.Example/Revit/AppStacked.cs | 2 +- ricaun.Revit.UI.Example/Revit/AppTheme.cs | 76 +++++++++++++++++++ ricaun.Revit.UI/RibbonItemDataExtension.cs | 5 ++ ricaun.Revit.UI/RibbonItemExtension.cs | 5 ++ .../Utils/RibbonThemeBitmapUtils.cs | 53 +++++++++++++ ricaun.Revit.UI/ricaun.Revit.UI.csproj | 1 + 11 files changed, 148 insertions(+), 5 deletions(-) create mode 100644 ricaun.Revit.UI.Example/Revit/AppTheme.cs create mode 100644 ricaun.Revit.UI/Utils/RibbonThemeBitmapUtils.cs diff --git a/CHANGELOG.md b/CHANGELOG.md index b575b9c..8f13c7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Change `GetRibbonItem` to `GetRibbonItem_Alternative` to fix null when panel is removed. - Update `SetImage` to work with `ComboBoxMember` - Add `CreateComboBoxMember` to create `ComboBoxMember`. +- Add `RibbonThemeBitmapUtils` to change theme for `BitmapSource`. ### Tests - Add `RibbonThemeUtilsTests` to test the theme change event. - Add `ComboBoxMember` tests for `Image`, `Group` and `Current`. +### Example +- Add `AppTheme` to test theme change features for `RibbonItem`. ## [0.6.2] / 2024-01-09 - 2024-02-05 ### Features diff --git a/Directory.Build.props b/Directory.Build.props index 48b0ee8..af8d48e 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,5 @@ - 0.6.3-beta.1 + 0.6.3-beta.2 \ No newline at end of file diff --git a/ricaun.Revit.UI.Example/Revit/App.cs b/ricaun.Revit.UI.Example/Revit/App.cs index 4cc45b2..51a6acf 100644 --- a/ricaun.Revit.UI.Example/Revit/App.cs +++ b/ricaun.Revit.UI.Example/Revit/App.cs @@ -13,7 +13,7 @@ namespace ricaun.Revit.UI.Example.Revit { - [AppLoader] + //[AppLoader] //[Obsolete] public class App : IExternalApplication { diff --git a/ricaun.Revit.UI.Example/Revit/AppList.cs b/ricaun.Revit.UI.Example/Revit/AppList.cs index c521c35..ed293ea 100644 --- a/ricaun.Revit.UI.Example/Revit/AppList.cs +++ b/ricaun.Revit.UI.Example/Revit/AppList.cs @@ -4,7 +4,7 @@ namespace ricaun.Revit.UI.Example.Revit { - [AppLoader] + //[AppLoader] public class AppList : IExternalApplication { private static RibbonPanel ribbonPanel; diff --git a/ricaun.Revit.UI.Example/Revit/AppResource.cs b/ricaun.Revit.UI.Example/Revit/AppResource.cs index fc0cad4..d2a42d7 100644 --- a/ricaun.Revit.UI.Example/Revit/AppResource.cs +++ b/ricaun.Revit.UI.Example/Revit/AppResource.cs @@ -2,7 +2,7 @@ namespace ricaun.Revit.UI.Example.Revit { - [AppLoader] + //[AppLoader] public class AppResource : IExternalApplication { private static RibbonPanel ribbonPanel; diff --git a/ricaun.Revit.UI.Example/Revit/AppStacked.cs b/ricaun.Revit.UI.Example/Revit/AppStacked.cs index 62bc30c..d72f1e5 100644 --- a/ricaun.Revit.UI.Example/Revit/AppStacked.cs +++ b/ricaun.Revit.UI.Example/Revit/AppStacked.cs @@ -7,7 +7,7 @@ namespace ricaun.Revit.UI.Example.Revit { - [AppLoader] + //[AppLoader] public class AppStacked : IExternalApplication { private static RibbonPanel ribbonPanel; diff --git a/ricaun.Revit.UI.Example/Revit/AppTheme.cs b/ricaun.Revit.UI.Example/Revit/AppTheme.cs new file mode 100644 index 0000000..2b91d99 --- /dev/null +++ b/ricaun.Revit.UI.Example/Revit/AppTheme.cs @@ -0,0 +1,76 @@ +using Autodesk.Revit.Attributes; +using Autodesk.Revit.DB; +using Autodesk.Revit.UI; +using ricaun.Revit.UI.Utils; + +namespace ricaun.Revit.UI.Example.Revit +{ + [AppLoader] + public class AppTheme : IExternalApplication + { + const string LIGHT = "https://github.com/ricaun-io/Autodesk.Icon.Example/releases/download/1.0.1-alpha/Box-Blue-Light.ico"; + const string DARK = "https://github.com/ricaun-io/Autodesk.Icon.Example/releases/download/1.0.1-alpha/Box-Blue-Dark.ico"; + + private RibbonPanel ribbonPanel; + public Result OnStartup(UIControlledApplication application) + { + ribbonPanel = application.CreatePanel("Theme"); + + ribbonPanel.CreatePushButton("Light") + .SetLargeImage(LIGHT); + ribbonPanel.CreatePushButton("Dark") + .SetLargeImage(DARK); + string stringNull = null; + ribbonPanel.CreatePushButton("Null") + .SetLargeImage(LIGHT) + .SetLargeImage(stringNull); + + ribbonPanel.FlowStackedItems( + ribbonPanel.CreatePushButton("1").SetLargeImage(LIGHT), + ribbonPanel.CreatePushButton("2").SetLargeImage(DARK), + ribbonPanel.CreatePushButton("3").SetLargeImage(LIGHT) + ); + + ribbonPanel.AddSeparator(); + + var pushButton = ribbonPanel.CreatePushButton("Theme") + .SetLargeImage(LIGHT); + + var textBox = ribbonPanel.CreateTextBox() + .SetPromptText("TextBox") + .SetLargeImage(LIGHT); + + var comboBox = ribbonPanel.CreateComboBox() + .SetLargeImage(LIGHT); + comboBox.CreateComboBoxMember("ComboBox") + .SetLargeImage(LIGHT); + + ribbonPanel.RowStackedItems(pushButton, textBox, comboBox); + + return Result.Succeeded; + } + + public Result OnShutdown(UIControlledApplication application) + { + ribbonPanel?.Remove(); + return Result.Succeeded; + } + + [Transaction(TransactionMode.Manual)] + public class CommandTheme : IExternalCommand, IExternalCommandAvailability + { + public Result Execute(ExternalCommandData commandData, ref string message, ElementSet elementSet) + { + UIApplication uiapp = commandData.Application; + + UIThemeManager.CurrentTheme = UIThemeManager.CurrentTheme == UITheme.Light ? UITheme.Dark : UITheme.Light; + return Result.Succeeded; + } + + public bool IsCommandAvailable(UIApplication applicationData, CategorySet selectedCategories) + { + return true; + } + } + } +} \ No newline at end of file diff --git a/ricaun.Revit.UI/RibbonItemDataExtension.cs b/ricaun.Revit.UI/RibbonItemDataExtension.cs index 645669b..f61e9bb 100644 --- a/ricaun.Revit.UI/RibbonItemDataExtension.cs +++ b/ricaun.Revit.UI/RibbonItemDataExtension.cs @@ -1,4 +1,5 @@ using Autodesk.Revit.UI; +using ricaun.Revit.UI.Utils; using System.Windows.Media; namespace ricaun.Revit.UI @@ -150,6 +151,8 @@ public static TRibbonItem SetLargeImage(this TRibbonItem ribbonItem /// public static TRibbonItem SetImage(this TRibbonItem ribbonItem, ImageSource image) where TRibbonItem : RibbonItemData { + image = image.GetThemeImageSource(RibbonThemeUtils.IsLight); + if (ribbonItem is ButtonData ribbonButton) ribbonButton.Image = image?.GetBitmapFrame(16, (frame) => { ribbonButton.Image = frame; }); @@ -174,6 +177,8 @@ public static TRibbonItem SetImage(this TRibbonItem ribbonItem, Ima /// public static TRibbonItem SetLargeImage(this TRibbonItem ribbonItem, ImageSource largeImage) where TRibbonItem : RibbonItemData { + largeImage = largeImage.GetThemeImageSource(RibbonThemeUtils.IsLight); + if (ribbonItem is ButtonData ribbonButton) { ribbonButton.LargeImage = largeImage?.GetBitmapFrame(32, (frame) => { ribbonButton.LargeImage = frame; }); diff --git a/ricaun.Revit.UI/RibbonItemExtension.cs b/ricaun.Revit.UI/RibbonItemExtension.cs index b56d3a0..d6e06a7 100644 --- a/ricaun.Revit.UI/RibbonItemExtension.cs +++ b/ricaun.Revit.UI/RibbonItemExtension.cs @@ -1,4 +1,5 @@ using Autodesk.Revit.UI; +using ricaun.Revit.UI.Utils; using System.Windows.Media; namespace ricaun.Revit.UI @@ -192,6 +193,8 @@ public static TRibbonItem SetLargeImage(this TRibbonItem ribbonItem /// public static TRibbonItem SetImage(this TRibbonItem ribbonItem, ImageSource image) where TRibbonItem : RibbonItem { + image = image.GetThemeImageSource(RibbonThemeUtils.IsLight); + if (ribbonItem is RibbonButton ribbonButton) ribbonButton.Image = image?.GetBitmapFrame(16, (frame) => { ribbonButton.Image = frame; }); @@ -217,6 +220,8 @@ public static TRibbonItem SetImage(this TRibbonItem ribbonItem, Ima /// When , or does not have LargeImage, the Image is changed instead. public static TRibbonItem SetLargeImage(this TRibbonItem ribbonItem, ImageSource largeImage) where TRibbonItem : RibbonItem { + largeImage = largeImage.GetThemeImageSource(RibbonThemeUtils.IsLight); + if (ribbonItem is RibbonButton ribbonButton) { ribbonButton.LargeImage = largeImage?.GetBitmapFrame(32, (frame) => { ribbonButton.LargeImage = frame; }); diff --git a/ricaun.Revit.UI/Utils/RibbonThemeBitmapUtils.cs b/ricaun.Revit.UI/Utils/RibbonThemeBitmapUtils.cs new file mode 100644 index 0000000..2e9389b --- /dev/null +++ b/ricaun.Revit.UI/Utils/RibbonThemeBitmapUtils.cs @@ -0,0 +1,53 @@ +using System.Windows.Media; +using System.Windows.Media.Imaging; + +namespace ricaun.Revit.UI.Utils +{ + internal static class RibbonThemeBitmapUtils + { + private const string NAME_DARK = "dark"; + private const string NAME_LIGHT = "light"; + + internal static TImageSource GetThemeImageSource(this TImageSource imageSource, bool isLight = true) where TImageSource : ImageSource + { + if (imageSource.GetSourceName().TryThemeImage(isLight, out string imageTheme)) + { + if (imageTheme.GetBitmapSource() is TImageSource themeImageSource) + return themeImageSource; + } + + return imageSource; + } + + internal static bool TryThemeImage(this string image, bool isLight, out string imageTheme) + { + imageTheme = string.Empty; + + if (string.IsNullOrEmpty(image)) + return false; + + var findThemeName = !isLight ? NAME_LIGHT : NAME_DARK; + var replaceThemeName = isLight ? NAME_LIGHT : NAME_DARK; + + if (image.IndexOf(findThemeName, System.StringComparison.InvariantCultureIgnoreCase) != -1) + { + imageTheme = image.Replace(findThemeName, replaceThemeName); + return true; + } + + return false; + } + internal static string GetSourceName(this ImageSource imageSource) + { + if (imageSource is TransformedBitmap transformedBitmap) + { + return transformedBitmap.Source.ToString().ToLowerInvariant(); + } + if (imageSource is BitmapFrame bitmapFrame) + { + return bitmapFrame.Decoder.ToString().ToLowerInvariant(); + } + return null; + } + } +} diff --git a/ricaun.Revit.UI/ricaun.Revit.UI.csproj b/ricaun.Revit.UI/ricaun.Revit.UI.csproj index db24b5d..c58283d 100644 --- a/ricaun.Revit.UI/ricaun.Revit.UI.csproj +++ b/ricaun.Revit.UI/ricaun.Revit.UI.csproj @@ -133,6 +133,7 @@ + \ No newline at end of file