stigzler Posted 1 hour ago Posted 1 hour ago I have a couple of custom badges (rommStarSynced.png and installingFromRomm.png) in a custom badge set ("Solid In Color) for a plugin I'm designing: I manually set the badge set in BigBoxSettings.xml: <?xml version="1.0" encoding="utf-8"?> <LaunchBox> <BigBoxSettings> <BadgePack>Solid In Color</BadgePack> The class that should show the rommStarSynced badge: namespace RommStar.Core.Badges { internal class RommSyncedBadge : IGameBadge { public string Name => "Synced with Romm"; public string UniqueId => "rommStarSynced"; public Image DefaultIcon => Properties.Resources.romm40pxOutlined; public int Index { get; set; } = 0; public bool GetAppliesToGame(IGame game) { // IGame default state for Installed is null, Romm Import process will set to either true or false // so we can use this to determine if the game has been processed by Romm and if has - // show romm icon in badge array. return game.GetAllCustomFields().Any(cf => cf.Name == "Romm_RomIds"); } } } I thought this was how you were meant to line things up. However, the badge in question does not show in BigBox (despite the conditional in `GetAppliesToGame` should be returning true): (on an aside, if i set a breakpoint on `GetAppliesToGame` in BigBox debug, it doesn't brake there) It does, however, show in Launchbox (the purple badge at the end): In fact, in launchbox it doesn't require a copy to be in the badge folder. I'm guessing it just gets it via `DefaultIcon` in `InstallingBadge : IGameBadge` Any ideas? Quote
JoeViking245 Posted 1 hour ago Posted 1 hour ago Big Box will not show Custom badges like they do in LaunchBox. You need to modify the BB them file(s) to specifically show the specific badge(s). Quote
stigzler Posted 1 hour ago Author Posted 1 hour ago (edited) OK - with the help of @JoeViking245, figured you need to edit your theme's GameDetailsView.xaml in your BigBox theme. You need to add entries as per below: <Border Background="#40131313" CornerRadius="4"> <Border.Style> <Style TargetType="Border"> <Setter Property="Visibility" Value="Visible"/> <Setter Property="Margin" Value="{Binding Converter={StaticResource ScaleConverter}, ConverterParameter='0,0,20,0'}"/> <Style.Triggers> <MultiDataTrigger> <MultiDataTrigger.Conditions> <Condition Binding="{Binding ElementName=SavedGame, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=SaveStates, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=Documents, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=Achievements, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=MAMEHighScores, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=MultipleDiscs, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=MultipleVersions, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=NotInstalled, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=Installed, Path=HasBadge}" Value="False"/> <Condition Binding="{Binding ElementName=RommStarSynced, Path=HasBadge}" Value="False"/> </MultiDataTrigger.Conditions> <Setter Property="Visibility" Value="Collapsed"/> </MultiDataTrigger> </Style.Triggers> </Style> </Border.Style> <StackPanel Margin="{Binding Converter={StaticResource ScaleConverter}, ConverterParameter='10,10'}" Orientation="Horizontal" Opacity="0.6"> <coverFlow:FlowBadge x:Name="SavedGame" DataContext="{Binding SelectedGame}" BadgeName="HasSavedGame" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="SaveStates" DataContext="{Binding SelectedGame}" BadgeName="HasSaveStates" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="Documents" DataContext="{Binding SelectedGame}" BadgeName="Documents" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="Achievements" DataContext="{Binding SelectedGame}" BadgeName="Achievements" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="MAMEHighScores" DataContext="{Binding SelectedGame}" BadgeName="MAME High Scores" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="MultipleDiscs" DataContext="{Binding SelectedGame}" BadgeName="Multiple Discs" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="MultipleVersions" DataContext="{Binding SelectedGame}" BadgeName="Multiple Versions" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="NotInstalled" DataContext="{Binding SelectedGame}" BadgeName="Not Installed" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="Installed" DataContext="{Binding SelectedGame}" BadgeName="Installed" Style="{StaticResource FlowBadgeVisibilityStyle}"/> <coverFlow:FlowBadge x:Name="RommStarSynced" DataContext="{Binding SelectedGame}" BadgeName="rommStarSynced" Style="{StaticResource FlowBadgeVisibilityStyle}"/> </StackPanel> </Border> Note the "RommStarSynced" entries at the end of <MultiDataTrigger.Conditions> and the <coverFlow:FlowBadge> entries. Note: use the UniqueId property in your IGameBadge class as the BadgeName. If I figure out how to do this programatically at runtime, I will post an update. Note 2: I don't think you actually need a copy of the icon in the Badges folder. I think it's getting this image from DefaultIcon in the IGameBadge class Edited 1 hour ago by stigzler 1 Quote
stigzler Posted 4 minutes ago Author Posted 4 minutes ago (edited) OK - adding badges programmatically proved to be a hideous PITA. However, you can get your plugin/app to update the relevant theme xaml with he code below. It just inserts the lines you need. You will need to provide it with the theme name. I have tested it on "Default" and it works OK. It's mainly a harmless script as it just adds those lines if 2 lines matching the above format exist. Note: This approach doesn't seem to work with other themes as they appear to have a largely different format to the stock Default bb theme. The black art/idiosyncrasies of BB themes is a bit beyond me tbh, but the code may still provide guidance. using System; using System.IO; using System.Text; using Unbroken.LaunchBox.Plugins; namespace RommStar.Core.Helpers { public static class BigBoxRommStarIconsInjector { private const string TargetConditionFind = "<Condition Binding=\"{Binding ElementName=SaveStates, Path=HasBadge}\" Value=\"False\"/>"; private const string TargetConditionInsert = "<Condition Binding=\"{Binding ElementName=RommStarSynced, Path=HasBadge}\" Value=\"False\"/>"; private const string TargetBadgeFind = "<coverFlow:FlowBadge x:Name=\"SaveStates\" DataContext=\"{Binding SelectedGame}\" BadgeName=\"HasSaveStates\" Style=\"{StaticResource FlowBadgeVisibilityStyle}\"/>"; private const string TargetBadgeInsert = "<coverFlow:FlowBadge x:Name=\"RommStarSynced\" DataContext=\"{Binding SelectedGame}\" BadgeName=\"rommStarSynced\" Style=\"{StaticResource FlowBadgeVisibilityStyle}\"/>"; /// <summary> /// Automatically patches the active theme's GameDetailsView.xaml to include the RommStarSynced badge and condition. /// Call this once when your plugin initializes. /// </summary> public static void PatchThemeXaml(string themeName) { if (string.IsNullOrEmpty(themeName)) return; try { // 1. Locate the active Big Box theme directory via PluginHelper or standard LaunchBox paths string themePath = GetActiveThemeGameDetailsPath(themeName); if (string.IsNullOrEmpty(themePath) || !File.Exists(themePath)) { // Fallback: search common themes directory if active theme path resolution varies return; } string content = File.ReadAllText(themePath, Encoding.UTF8); bool modified = false; // 2. Check and inject the MultiDataTrigger condition if missing if (content.Contains(TargetConditionFind) && !content.Contains(TargetConditionInsert)) { // Insert right after the SaveStates condition line string replacementBlock = TargetConditionFind + Environment.NewLine + " " + TargetConditionInsert; content = content.Replace(TargetConditionFind, replacementBlock); modified = true; } // 3. Check and inject the FlowBadge element if missing if (content.Contains(TargetBadgeFind) && !content.Contains(TargetBadgeInsert)) { // Insert right after the SaveStates badge line string replacementBlock = TargetBadgeFind + Environment.NewLine + " " + TargetBadgeInsert; content = content.Replace(TargetBadgeFind, replacementBlock); modified = true; } // 4. Save back to disk only if changes were made if (modified) { File.WriteAllText(themePath, content, Encoding.UTF8); } } catch (Exception ex) { System.Diagnostics.Debug.WriteLine($"[RommStar] Failed to patch GameDetailsView.xaml: {ex.Message}"); } } private static string GetActiveThemeGameDetailsPath(string themeName) { try { // LaunchBox exposes the core installation directory or theme paths through PluginHelper/StateManager string appDir = Path.GetDirectoryName(typeof(PluginHelper).Assembly.Location); if (string.IsNullOrEmpty(appDir)) return null; string viewsDir = Path.Combine(Constants.LaunchboxRootDir, $"Themes\\{themeName}"); if (!Directory.Exists(viewsDir)) return null; // Search recursively for GameDetailsView.xaml across installed themes var matches = Directory.GetFiles(viewsDir, "Views/GameDetailsView.xaml", SearchOption.AllDirectories); foreach (var match in matches) { // Check if it's currently in use or return the first valid match (or target the user's active theme) // If you want to be precise, you can check which theme folder is currently set in BigBox settings, // or patch all installed themes so it works regardless of what theme the user switches to. return match; } } catch { } return null; } } } You'll obs need to make some changes to suit your own code (e.g. replacing references to Constants class etc). Edited 2 minutes ago by stigzler Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.