Jump to content
LaunchBox Community Forums

Recommended Posts

Posted

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:

image.thumb.png.bec4d1bc7815a86a06a67289d3705882.png

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):

image.thumb.png.64d89f781fe0486f4c3876a511d49950.png

(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):

image.thumb.png.f4b45bee71d5b76fcaf613e2e426af82.png

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?

Posted (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 by stigzler
  • Game On 1
Posted (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 by stigzler

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...