diff --git a/Cmdline/Main.cs b/Cmdline/Main.cs index 3b54d1feea..78fe0887e3 100644 --- a/Cmdline/Main.cs +++ b/Cmdline/Main.cs @@ -177,7 +177,7 @@ private static int RunSimpleAction(Options cmdline, CommonOptions options, strin return Gui(manager, (GuiOptions)options, args); case "consoleui": - return ConsoleUi(manager, options, args); + return ConsoleUi(manager, (ConsoleUIOptions)options, args); case "prompt": return new Prompt().RunCommand(manager, cmdline.options); @@ -277,11 +277,13 @@ private static int Gui(GameInstanceManager manager, GuiOptions options, string[] return Exit.OK; } - private static int ConsoleUi(GameInstanceManager manager, CommonOptions opts, string[] args) + private static int ConsoleUi(GameInstanceManager manager, ConsoleUIOptions opts, string[] args) { // Debug/verbose output just messes up the screen LogManager.GetRepository().Threshold = Level.Warn; - return CKAN.ConsoleUI.ConsoleUI.Main_(args, manager, opts.Debug); + return CKAN.ConsoleUI.ConsoleUI.Main_(args, manager, + opts.Theme ?? Environment.GetEnvironmentVariable("CKAN_CONSOLEUI_THEME") ?? "default", + opts.Debug); } private static int Version(IUser user) diff --git a/Cmdline/Options.cs b/Cmdline/Options.cs index 821d018c71..0e88b1a902 100644 --- a/Cmdline/Options.cs +++ b/Cmdline/Options.cs @@ -477,7 +477,11 @@ internal class GuiOptions : InstanceSpecificOptions public bool ShowConsole { get; set; } } - internal class ConsoleUIOptions : InstanceSpecificOptions { } + internal class ConsoleUIOptions : InstanceSpecificOptions + { + [Option("theme", HelpText = "Name of color scheme to use, falls back to environment variable CKAN_CONSOLEUI_THEME")] + public string Theme { get; set; } + } internal class UpdateOptions : InstanceSpecificOptions { diff --git a/ConsoleUI/AuthTokenAddDialog.cs b/ConsoleUI/AuthTokenAddDialog.cs index c6f7e54c85..03d109dd6c 100644 --- a/ConsoleUI/AuthTokenAddDialog.cs +++ b/ConsoleUI/AuthTokenAddDialog.cs @@ -28,8 +28,8 @@ public AuthTokenAddDialog() : base() AddObject(new ConsoleLabel( l + 2, t + 2, l + 2 + labelW, () => "Host:", - () => ConsoleTheme.Current.PopupBg, - () => ConsoleTheme.Current.PopupFg + th => th.PopupBg, + th => th.PopupFg )); hostEntry = new ConsoleField( @@ -42,8 +42,8 @@ public AuthTokenAddDialog() : base() AddObject(new ConsoleLabel( l + 2, t + 4, l + 2 + labelW, () => "Token:", - () => ConsoleTheme.Current.PopupBg, - () => ConsoleTheme.Current.PopupFg + th => th.PopupBg, + th => th.PopupFg )); tokenEntry = new ConsoleField( @@ -54,10 +54,10 @@ public AuthTokenAddDialog() : base() AddObject(tokenEntry); AddTip("Esc", "Cancel"); - AddBinding(Keys.Escape, (object sender) => false); + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => false); AddTip("Enter", "Accept", validKey); - AddBinding(Keys.Enter, (object sender) => { + AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { if (validKey()) { ServiceLocator.Container.Resolve().SetAuthToken(hostEntry.Value, tokenEntry.Value); return false; diff --git a/ConsoleUI/AuthTokenListScreen.cs b/ConsoleUI/AuthTokenListScreen.cs index 3d1a4e3154..d3747252a8 100644 --- a/ConsoleUI/AuthTokenListScreen.cs +++ b/ConsoleUI/AuthTokenListScreen.cs @@ -56,23 +56,23 @@ public AuthTokenScreen() : base() 3, -1, -1, () => "NOTE: These values are private! Do not share screenshots of this screen!", null, - () => ConsoleTheme.Current.AlertFrameFg + th => th.AlertFrameFg )); AddTip("Esc", "Back"); - AddBinding(Keys.Escape, (object sender) => false); + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => false); tokenList.AddTip("A", "Add"); - tokenList.AddBinding(Keys.A, (object sender) => { + tokenList.AddBinding(Keys.A, (object sender, ConsoleTheme theme) => { AuthTokenAddDialog ad = new AuthTokenAddDialog(); - ad.Run(); - DrawBackground(); + ad.Run(theme); + DrawBackground(theme); tokenList.SetData(new List(ServiceLocator.Container.Resolve().GetAuthTokenHosts())); return true; }); tokenList.AddTip("R", "Remove", () => tokenList.Selection != null); - tokenList.AddBinding(Keys.R, (object sender) => { + tokenList.AddBinding(Keys.R, (object sender, ConsoleTheme theme) => { if (tokenList.Selection != null) { ServiceLocator.Container.Resolve().SetAuthToken(tokenList.Selection, null); tokenList.SetData(new List(ServiceLocator.Container.Resolve().GetAuthTokenHosts())); @@ -97,9 +97,9 @@ protected override string CenterHeader() return "Authentication Tokens"; } - private bool openGitHubURL() + private bool openGitHubURL(ConsoleTheme theme) { - ModInfoScreen.LaunchURL(githubTokenURL); + ModInfoScreen.LaunchURL(theme, githubTokenURL); return true; } diff --git a/ConsoleUI/CompatibleVersionDialog.cs b/ConsoleUI/CompatibleVersionDialog.cs index 80fd96355a..f878748de0 100644 --- a/ConsoleUI/CompatibleVersionDialog.cs +++ b/ConsoleUI/CompatibleVersionDialog.cs @@ -40,7 +40,7 @@ public CompatibleVersionDialog(IGame game) : base() ); AddObject(choices); choices.AddTip("Enter", "Select version"); - choices.AddBinding(Keys.Enter, (object sender) => { + choices.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { choice = choices.Selection; return false; }); @@ -52,7 +52,7 @@ public CompatibleVersionDialog(IGame game) : base() }; AddObject(manualEntry); manualEntry.AddTip("Enter", "Accept value", () => GameVersion.TryParse(manualEntry.Value, out choice)); - manualEntry.AddBinding(Keys.Enter, (object sender) => { + manualEntry.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { if (GameVersion.TryParse(manualEntry.Value, out choice)) { // Good value, done running return false; @@ -63,7 +63,7 @@ public CompatibleVersionDialog(IGame game) : base() }); AddTip("Esc", "Cancel"); - AddBinding(Keys.Escape, (object sender) => { + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => { choice = null; return false; }); @@ -75,12 +75,13 @@ public CompatibleVersionDialog(IGame game) : base() /// Display the dialog and handle its interaction /// /// Function to control the dialog, default is normal user interaction + /// The visual theme to use to draw the dialog /// /// Row user selected /// - public new GameVersion Run(Action process = null) + public new GameVersion Run(ConsoleTheme theme, Action process = null) { - base.Run(process); + base.Run(theme, process); return choice; } diff --git a/ConsoleUI/ConsoleCKAN.cs b/ConsoleUI/ConsoleCKAN.cs index 5422ef6395..0e34799f13 100644 --- a/ConsoleUI/ConsoleCKAN.cs +++ b/ConsoleUI/ConsoleCKAN.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using CKAN.ConsoleUI.Toolkit; namespace CKAN.ConsoleUI { @@ -13,34 +14,43 @@ public class ConsoleCKAN { /// Starts with a splash screen, then instance selection if no default, /// then list of mods. /// - public ConsoleCKAN(GameInstanceManager mgr, bool debug) + public ConsoleCKAN(GameInstanceManager mgr, string themeName, bool debug) { - // GameInstanceManager only uses its IUser object to construct game instance objects, - // which only use it to inform the user about the creation of the CKAN/ folder. - // These aren't really intended to be displayed, so the manager - // can keep a NullUser reference forever. - GameInstanceManager manager = mgr ?? new GameInstanceManager(new NullUser()); + if (ConsoleTheme.Themes.TryGetValue(themeName, out ConsoleTheme theme)) + { + // GameInstanceManager only uses its IUser object to construct game instance objects, + // which only use it to inform the user about the creation of the CKAN/ folder. + // These aren't really intended to be displayed, so the manager + // can keep a NullUser reference forever. + GameInstanceManager manager = mgr ?? new GameInstanceManager(new NullUser()); - // The splash screen returns true when it's safe to run the rest of the app. - // This can be blocked by a lock file, for example. - if (new SplashScreen(manager).Run()) { + // The splash screen returns true when it's safe to run the rest of the app. + // This can be blocked by a lock file, for example. + if (new SplashScreen(manager).Run(theme)) { - if (manager.CurrentInstance == null) { - if (manager.Instances.Count == 0) { - // No instances, add one - new GameInstanceAddScreen(manager).Run(); - // Set instance to current if they added one - manager.GetPreferredInstance(); - } else { - // Multiple instances, no default, pick one - new GameInstanceListScreen(manager).Run(); + if (manager.CurrentInstance == null) { + if (manager.Instances.Count == 0) { + // No instances, add one + new GameInstanceAddScreen(manager).Run(theme); + // Set instance to current if they added one + manager.GetPreferredInstance(); + } else { + // Multiple instances, no default, pick one + new GameInstanceListScreen(manager).Run(theme); + } + } + if (manager.CurrentInstance != null) { + new ModListScreen(manager, debug).Run(theme); } - } - if (manager.CurrentInstance != null) { - new ModListScreen(manager, debug).Run(); - } - new ExitScreen().Run(); + new ExitScreen().Run(theme); + } + } + else + { + Console.WriteLine("No such theme: {0}", themeName); + Console.WriteLine("Available themes: {0}", string.Join(", ", + ConsoleTheme.Themes.Keys.OrderBy(th => th))); } } diff --git a/ConsoleUI/DependencyScreen.cs b/ConsoleUI/DependencyScreen.cs index be89dec54b..02e10451f4 100644 --- a/ConsoleUI/DependencyScreen.cs +++ b/ConsoleUI/DependencyScreen.cs @@ -64,13 +64,13 @@ public DependencyScreen(GameInstanceManager mgr, ChangePlan cp, HashSet 1, 0, ListSortDirection.Descending ); dependencyList.AddTip("+", "Toggle"); - dependencyList.AddBinding(Keys.Plus, (object sender) => { + dependencyList.AddBinding(Keys.Plus, (object sender, ConsoleTheme theme) => { ChangePlan.toggleContains(accepted, dependencyList.Selection.module); return true; }); dependencyList.AddTip("Ctrl+A", "Select all"); - dependencyList.AddBinding(Keys.CtrlA, (object sender) => { + dependencyList.AddBinding(Keys.CtrlA, (object sender, ConsoleTheme theme) => { foreach (var kvp in dependencies) { if (!accepted.Contains(kvp.Key)) { ChangePlan.toggleContains(accepted, kvp.Key); @@ -80,15 +80,15 @@ public DependencyScreen(GameInstanceManager mgr, ChangePlan cp, HashSet }); dependencyList.AddTip("Ctrl+D", "Deselect all", () => accepted.Count > 0); - dependencyList.AddBinding(Keys.CtrlD, (object sender) => { + dependencyList.AddBinding(Keys.CtrlD, (object sender, ConsoleTheme theme) => { accepted.Clear(); return true; }); dependencyList.AddTip("Enter", "Details"); - dependencyList.AddBinding(Keys.Enter, (object sender) => { + dependencyList.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { if (dependencyList.Selection != null) { - LaunchSubScreen(new ModInfoScreen( + LaunchSubScreen(theme, new ModInfoScreen( manager, plan, dependencyList.Selection.module, debug @@ -100,7 +100,7 @@ public DependencyScreen(GameInstanceManager mgr, ChangePlan cp, HashSet AddObject(dependencyList); AddTip("Esc", "Cancel"); - AddBinding(Keys.Escape, (object sender) => { + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => { // Add everything to rejected foreach (var kvp in dependencies) { rejected.Add(kvp.Key.identifier); @@ -109,7 +109,7 @@ public DependencyScreen(GameInstanceManager mgr, ChangePlan cp, HashSet }); AddTip("F9", "Accept"); - AddBinding(Keys.F9, (object sender) => { + AddBinding(Keys.F9, (object sender, ConsoleTheme theme) => { foreach (CkanModule mod in accepted) { plan.Install.Add(mod); } diff --git a/ConsoleUI/DownloadImportDialog.cs b/ConsoleUI/DownloadImportDialog.cs index e05ea3c6b7..1d3ab99f49 100644 --- a/ConsoleUI/DownloadImportDialog.cs +++ b/ConsoleUI/DownloadImportDialog.cs @@ -14,10 +14,11 @@ public static class DownloadImportDialog { /// /// Let the user choose some zip files, then import them to the mod cache. /// + /// The visual theme to use to draw the dialog /// Game instance to import into /// Cache object to import into /// Change plan object for marking things to be installed - public static void ImportDownloads(GameInstance gameInst, NetModuleCache cache, ChangePlan cp) + public static void ImportDownloads(ConsoleTheme theme, GameInstance gameInst, NetModuleCache cache, ChangePlan cp) { ConsoleFileMultiSelectDialog cfmsd = new ConsoleFileMultiSelectDialog( "Import Downloads", @@ -25,12 +26,12 @@ public static void ImportDownloads(GameInstance gameInst, NetModuleCache cache, "*.zip", "Import" ); - HashSet files = cfmsd.Run(); + HashSet files = cfmsd.Run(theme); if (files.Count > 0) { ProgressScreen ps = new ProgressScreen("Importing Downloads", "Calculating..."); ModuleInstaller inst = ModuleInstaller.GetInstance(gameInst, cache, ps); - ps.Run(() => inst.ImportFiles(files, ps, + ps.Run(theme, (ConsoleTheme th) => inst.ImportFiles(files, ps, (CkanModule mod) => cp.Install.Add(mod), RegistryManager.Instance(gameInst).registry)); // Don't let the installer re-use old screen references inst.User = null; diff --git a/ConsoleUI/ExitScreen.cs b/ConsoleUI/ExitScreen.cs index 314c6be004..77c8b88732 100644 --- a/ConsoleUI/ExitScreen.cs +++ b/ConsoleUI/ExitScreen.cs @@ -18,9 +18,9 @@ public ExitScreen() { } /// Show the screen. /// Luckily we don't have any interaction to do. /// - public void Run() + public void Run(ConsoleTheme theme) { - Draw(); + Draw(theme); // Try to return the terminal to normal Console.SetCursorPosition(0, Console.WindowHeight - 2); @@ -32,18 +32,76 @@ public void Run() /// Draw a cool retro exit screen like Id used to do. /// This is a composite of the exit screens of ULTIMATE DOOM and DOOM II. /// - private void Draw() + private void Draw(ConsoleTheme theme) { Console.CursorVisible = false; - Console.BackgroundColor = outerBg; + if (theme.ExitOuterBg.HasValue) + { + Console.BackgroundColor = theme.ExitOuterBg.Value; + } + else + { + Console.ResetColor(); + } Console.Clear(); + FancyLinePiece ckanPiece = new FancyLinePiece("CKAN", theme.ExitInnerBg, theme.ExitHighlightFg); + + FancyLinePiece[][] lines = new FancyLinePiece[][] { + new FancyLinePiece[] { + ckanPiece, + new FancyLinePiece(", the Comprehensive Kerbal Archive Network", theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + new FancyLinePiece( + new string(Symbols.horizLine, Console.WindowWidth - 2 -2 * horizMargin), + theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + new FancyLinePiece("YOU ARE USING ", theme.ExitInnerBg, theme.ExitNormalFg), + new FancyLinePiece($"CKAN {Meta.GetVersion()}", theme.ExitInnerBg, theme.ExitHighlightFg), + new FancyLinePiece(".", theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + }, new FancyLinePiece[] { + new FancyLinePiece("Thanks for downloading ", theme.ExitInnerBg, theme.ExitNormalFg), + ckanPiece, + new FancyLinePiece(". We hope you have as", theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + new FancyLinePiece("much fun using it as we had (and have) making it.", theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + }, new FancyLinePiece[] { + new FancyLinePiece("If you have paid for ", theme.ExitInnerBg, theme.ExitNormalFg), + ckanPiece, + new FancyLinePiece(", try to get your money back,", theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + new FancyLinePiece("because you can download ", theme.ExitInnerBg, theme.ExitNormalFg), + ckanPiece, + new FancyLinePiece(" for free from", theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/releases/latest", theme.ExitInnerBg, theme.ExitLinkFg) + }, new FancyLinePiece[] { + }, new FancyLinePiece[] { + new FancyLinePiece("If you have any problems using ", theme.ExitInnerBg, theme.ExitNormalFg), + ckanPiece, + new FancyLinePiece(", please send us an issue at", theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/issues", theme.ExitInnerBg, theme.ExitLinkFg) + }, new FancyLinePiece[] { + }, new FancyLinePiece[] { + ckanPiece, + new FancyLinePiece(" WAS CREATED BY THE ", theme.ExitInnerBg, theme.ExitNormalFg), + ckanPiece, + new FancyLinePiece(" AUTHORS:", theme.ExitInnerBg, theme.ExitNormalFg) + }, new FancyLinePiece[] { + new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/graphs/contributors", theme.ExitInnerBg, theme.ExitLinkFg) + }, new FancyLinePiece[] { + } + }; + for (int i = 0; i < lines.Length; ++i) { - drawLine(i, lines[i]); + drawLine(theme, i, lines[i]); } } - private void drawLine(int y, FancyLinePiece[] pieces) + private void drawLine(ConsoleTheme theme, int y, FancyLinePiece[] pieces) { // First we need to know how long the text is for centering int textLen = 0; @@ -62,7 +120,7 @@ private void drawLine(int y, FancyLinePiece[] pieces) // Left padding Console.SetCursorPosition(horizMargin, y); - Console.BackgroundColor = innerBg; + Console.BackgroundColor = theme.ExitInnerBg; Console.Write(new string(' ', leftPad)); foreach (FancyLinePiece p in pieces) { p.Draw(); @@ -71,62 +129,6 @@ private void drawLine(int y, FancyLinePiece[] pieces) } private const int horizMargin = 6; - private static ConsoleColor outerBg = ConsoleColor.Black; - private static ConsoleColor innerBg = ConsoleColor.DarkRed; - private static ConsoleColor mainFg = ConsoleColor.Yellow; - private static ConsoleColor hiliteFg = ConsoleColor.White; - private static ConsoleColor linkFg = ConsoleColor.Cyan; - - private static FancyLinePiece ckanPiece = new FancyLinePiece("CKAN", innerBg, hiliteFg); - - private static FancyLinePiece[][] lines = new FancyLinePiece[][] { - new FancyLinePiece[] { - ckanPiece, - new FancyLinePiece(", the Comprehensive Kerbal Archive Network", innerBg, mainFg) - }, new FancyLinePiece[] { - new FancyLinePiece( - new string(Symbols.horizLine, Console.WindowWidth - 2 -2 * horizMargin), - innerBg, mainFg) - }, new FancyLinePiece[] { - new FancyLinePiece("YOU ARE USING ", innerBg, mainFg), - new FancyLinePiece($"CKAN {Meta.GetVersion()}", innerBg, hiliteFg), - new FancyLinePiece(".", innerBg, mainFg) - }, new FancyLinePiece[] { - }, new FancyLinePiece[] { - new FancyLinePiece("Thanks for downloading ", innerBg, mainFg), - ckanPiece, - new FancyLinePiece(". We hope you have as", innerBg, mainFg) - }, new FancyLinePiece[] { - new FancyLinePiece("much fun using it as we had (and have) making it.", innerBg, mainFg) - }, new FancyLinePiece[] { - }, new FancyLinePiece[] { - new FancyLinePiece("If you have paid for ", innerBg, mainFg), - ckanPiece, - new FancyLinePiece(", try to get your money back,", innerBg, mainFg) - }, new FancyLinePiece[] { - new FancyLinePiece("because you can download ", innerBg, mainFg), - ckanPiece, - new FancyLinePiece(" for free from", innerBg, mainFg) - }, new FancyLinePiece[] { - new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/releases/latest", innerBg, linkFg) - }, new FancyLinePiece[] { - }, new FancyLinePiece[] { - new FancyLinePiece("If you have any problems using ", innerBg, mainFg), - ckanPiece, - new FancyLinePiece(", please send us an issue at", innerBg, mainFg) - }, new FancyLinePiece[] { - new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/issues", innerBg, linkFg) - }, new FancyLinePiece[] { - }, new FancyLinePiece[] { - ckanPiece, - new FancyLinePiece(" WAS CREATED BY THE ", innerBg, mainFg), - ckanPiece, - new FancyLinePiece(" AUTHORS:", innerBg, mainFg) - }, new FancyLinePiece[] { - new FancyLinePiece("https://github.com/KSP-CKAN/CKAN/graphs/contributors", innerBg, linkFg) - }, new FancyLinePiece[] { - } - }; } /// diff --git a/ConsoleUI/GameInstanceAddScreen.cs b/ConsoleUI/GameInstanceAddScreen.cs index a43048f768..290bf620c4 100644 --- a/ConsoleUI/GameInstanceAddScreen.cs +++ b/ConsoleUI/GameInstanceAddScreen.cs @@ -18,7 +18,7 @@ public GameInstanceAddScreen(GameInstanceManager mgr) : base(mgr) AddObject(new ConsoleLabel( labelWidth, pathRow + 1, -1, () => $"Example: {examplePath}", - null, () => ConsoleTheme.Current.DimLabelFg + null, th => th.DimLabelFg )); } diff --git a/ConsoleUI/GameInstanceEditScreen.cs b/ConsoleUI/GameInstanceEditScreen.cs index fdeb00cd88..4ac8a6ff07 100644 --- a/ConsoleUI/GameInstanceEditScreen.cs +++ b/ConsoleUI/GameInstanceEditScreen.cs @@ -47,7 +47,7 @@ public GameInstanceEditScreen(GameInstanceManager mgr, GameInstance k) 1, repoFrameTop, -1, compatFrameBottom, compatFrameTop, () => $"Mod List Sources", () => $"Additional Compatible Versions", - () => ConsoleTheme.Current.LabelFg + th => th.LabelFg )); repoList = new ConsoleListBox( @@ -72,13 +72,13 @@ public GameInstanceEditScreen(GameInstanceManager mgr, GameInstance k) ); AddObject(repoList); repoList.AddTip("A", "Add"); - repoList.AddBinding(Keys.A, (object sender) => { - LaunchSubScreen(new RepoAddScreen(ksp.game, repoEditList)); + repoList.AddBinding(Keys.A, (object sender, ConsoleTheme theme) => { + LaunchSubScreen(theme, new RepoAddScreen(ksp.game, repoEditList)); repoList.SetData(new List(repoEditList.Values)); return true; }); repoList.AddTip("R", "Remove"); - repoList.AddBinding(Keys.R, (object sender) => { + repoList.AddBinding(Keys.R, (object sender, ConsoleTheme theme) => { int oldPrio = repoList.Selection.priority; repoEditList.Remove(repoList.Selection.name); // Reshuffle the priorities to fill @@ -91,13 +91,13 @@ public GameInstanceEditScreen(GameInstanceManager mgr, GameInstance k) return true; }); repoList.AddTip("E", "Edit"); - repoList.AddBinding(Keys.E, (object sender) => { - LaunchSubScreen(new RepoEditScreen(ksp.game, repoEditList, repoList.Selection)); + repoList.AddBinding(Keys.E, (object sender, ConsoleTheme theme) => { + LaunchSubScreen(theme, new RepoEditScreen(ksp.game, repoEditList, repoList.Selection)); repoList.SetData(new List(repoEditList.Values)); return true; }); repoList.AddTip("-", "Up"); - repoList.AddBinding(Keys.Minus, (object sender) => { + repoList.AddBinding(Keys.Minus, (object sender, ConsoleTheme theme) => { if (repoList.Selection.priority > 0) { Repository prev = SortedDictFind(repoEditList, r => r.priority == repoList.Selection.priority - 1); @@ -110,7 +110,7 @@ public GameInstanceEditScreen(GameInstanceManager mgr, GameInstance k) return true; }); repoList.AddTip("+", "Down"); - repoList.AddBinding(Keys.Plus, (object sender) => { + repoList.AddBinding(Keys.Plus, (object sender, ConsoleTheme theme) => { Repository next = SortedDictFind(repoEditList, r => r.priority == repoList.Selection.priority + 1); if (next != null) { @@ -137,10 +137,10 @@ public GameInstanceEditScreen(GameInstanceManager mgr, GameInstance k) AddObject(compatList); compatList.AddTip("A", "Add"); - compatList.AddBinding(Keys.A, (object sender) => { + compatList.AddBinding(Keys.A, (object sender, ConsoleTheme theme) => { CompatibleVersionDialog vd = new CompatibleVersionDialog(ksp.game); - GameVersion newVersion = vd.Run(); - DrawBackground(); + GameVersion newVersion = vd.Run(theme); + DrawBackground(theme); if (newVersion != null && !compatEditList.Contains(newVersion)) { compatEditList.Add(newVersion); compatList.SetData(compatEditList); @@ -148,7 +148,7 @@ public GameInstanceEditScreen(GameInstanceManager mgr, GameInstance k) return true; }); compatList.AddTip("R", "Remove", () => compatList.Selection != null); - compatList.AddBinding(Keys.R, (object sender) => { + compatList.AddBinding(Keys.R, (object sender, ConsoleTheme theme) => { compatEditList.Remove(compatList.Selection); compatList.SetData(compatEditList); return true; diff --git a/ConsoleUI/GameInstanceListScreen.cs b/ConsoleUI/GameInstanceListScreen.cs index 3a4c27e254..d72d20fd74 100644 --- a/ConsoleUI/GameInstanceListScreen.cs +++ b/ConsoleUI/GameInstanceListScreen.cs @@ -58,22 +58,22 @@ public GameInstanceListScreen(GameInstanceManager mgr, bool first = false) if (first) { AddTip("Ctrl+Q", "Quit"); - AddBinding(Keys.AltX, (object sender) => false); - AddBinding(Keys.CtrlQ, (object sender) => false); + AddBinding(Keys.AltX, (object sender, ConsoleTheme theme) => false); + AddBinding(Keys.CtrlQ, (object sender, ConsoleTheme theme) => false); } else { AddTip("Esc", "Quit"); - AddBinding(Keys.Escape, (object sender) => false); + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => false); } AddTip("Enter", "Select"); - AddBinding(Keys.Enter, (object sender) => { + AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { ConsoleMessageDialog d = new ConsoleMessageDialog( $"Loading instance {instanceList.Selection.Name}...", new List() ); - if (TryGetInstance(instanceList.Selection, () => { d.Run(() => {}); })) { + if (TryGetInstance(theme, instanceList.Selection, (ConsoleTheme th) => { d.Run(th, (ConsoleTheme thm) => {}); })) { try { manager.SetCurrentInstance(instanceList.Selection.Name); } catch (Exception ex) { @@ -88,34 +88,34 @@ public GameInstanceListScreen(GameInstanceManager mgr, bool first = false) }); instanceList.AddTip("A", "Add"); - instanceList.AddBinding(Keys.A, (object sender) => { - LaunchSubScreen(new GameInstanceAddScreen(manager)); + instanceList.AddBinding(Keys.A, (object sender, ConsoleTheme theme) => { + LaunchSubScreen(theme, new GameInstanceAddScreen(manager)); instanceList.SetData(manager.Instances.Values); return true; }); instanceList.AddTip("R", "Remove"); - instanceList.AddBinding(Keys.R, (object sender) => { + instanceList.AddBinding(Keys.R, (object sender, ConsoleTheme theme) => { manager.RemoveInstance(instanceList.Selection.Name); instanceList.SetData(manager.Instances.Values); return true; }); instanceList.AddTip("E", "Edit"); - instanceList.AddBinding(Keys.E, (object sender) => { + instanceList.AddBinding(Keys.E, (object sender, ConsoleTheme theme) => { ConsoleMessageDialog d = new ConsoleMessageDialog( $"Loading instance {instanceList.Selection.Name}...", new List() ); - TryGetInstance(instanceList.Selection, () => { d.Run(() => {}); }); + TryGetInstance(theme, instanceList.Selection, (ConsoleTheme th) => { d.Run(theme, (ConsoleTheme thm) => {}); }); // Still launch the screen even if the load fails, // because you need to be able to fix the name/path. - LaunchSubScreen(new GameInstanceEditScreen(manager, instanceList.Selection)); + LaunchSubScreen(theme, new GameInstanceEditScreen(manager, instanceList.Selection)); return true; }); instanceList.AddTip("D", "Default"); - instanceList.AddBinding(Keys.D, (object sender) => { + instanceList.AddBinding(Keys.D, (object sender, ConsoleTheme theme) => { string name = instanceList.Selection.Name; if (name == manager.AutoStartInstance) { manager.ClearAutoStart(); @@ -127,7 +127,7 @@ public GameInstanceListScreen(GameInstanceManager mgr, bool first = false) $"Error loading {k.path}:\n{k.Message}", new List() {"OK"} ); - errd.Run(); + errd.Run(theme); } } return true; @@ -164,12 +164,13 @@ protected override string MenuTip() /// /// Try to load the registry of an instance /// + /// The visual theme to use to draw the dialog /// Game instance /// Function that shows a loading message /// /// True if successfully loaded, false if it's locked or the registry was corrupted, etc. /// - public static bool TryGetInstance(GameInstance ksp, Action render) + public static bool TryGetInstance(ConsoleTheme theme, GameInstance ksp, Action render) { bool retry; do { @@ -177,7 +178,7 @@ public static bool TryGetInstance(GameInstance ksp, Action render) retry = false; // Show loading message - render(); + render(theme); // Try to get the lock; this will throw if another instance is in there RegistryManager.Instance(ksp); @@ -190,7 +191,7 @@ public static bool TryGetInstance(GameInstance ksp, Action render) + "Do you want to delete this lock file to force access?", new List() {"Cancel", "Force"} ); - if (md.Run() == 1) { + if (md.Run(theme) == 1) { // Delete it File.Delete(k.lockfilePath); retry = true; @@ -205,7 +206,7 @@ public static bool TryGetInstance(GameInstance ksp, Action render) $"Error loading {ksp.GameDir()}:\n{k.Message}", new List() {"OK"} ); - errd.Run(); + errd.Run(theme); return false; } catch (Exception e) { @@ -214,7 +215,7 @@ public static bool TryGetInstance(GameInstance ksp, Action render) $"Error loading {Path.Combine(ksp.CkanDir(), "registry.json")}:\n{e.Message}", new List() {"OK"} ); - errd.Run(); + errd.Run(theme); return false; } diff --git a/ConsoleUI/GameInstanceScreen.cs b/ConsoleUI/GameInstanceScreen.cs index 5a7d857a84..6be65334f7 100644 --- a/ConsoleUI/GameInstanceScreen.cs +++ b/ConsoleUI/GameInstanceScreen.cs @@ -19,7 +19,7 @@ protected GameInstanceScreen(GameInstanceManager mgr, string initName = "", stri manager = mgr; AddTip("F2", "Accept"); - AddBinding(Keys.F2, (object sender) => { + AddBinding(Keys.F2, (object sender, ConsoleTheme theme) => { if (Valid()) { Save(); // Close screen @@ -31,7 +31,7 @@ protected GameInstanceScreen(GameInstanceManager mgr, string initName = "", stri }); AddTip("Esc", "Cancel"); - AddBinding(Keys.Escape, (object sender) => { + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => { // Discard changes return false; }); @@ -98,14 +98,19 @@ protected bool pathValid() // Handle default path dragged-and-dropped onto Mac's Terminal path.Value = path.Value.Replace("Kerbal\\ Space\\ Program", "Kerbal Space Program"); } - if (!GameInstanceManager.IsGameInstanceDir(new DirectoryInfo(path.Value))) { - // Complain about non-KSP path - RaiseError("Path does not correspond to a game folder!"); - SetFocus(path); - return false; - } else { - return true; + try + { + // DirectoryInfo's constructor throws exceptions for invalid characters, empty strings, etc. + if (GameInstanceManager.IsGameInstanceDir(new DirectoryInfo(path.Value))) { + return true; + } + } catch { + // Pretend DirectoryInfo constructed an instance that made IsGameInstanceDir return false } + // Complain about non-KSP path + RaiseError("Path does not correspond to a game folder!"); + SetFocus(path); + return false; } /// diff --git a/ConsoleUI/InstallScreen.cs b/ConsoleUI/InstallScreen.cs index 5119cd083d..2a1a835f5f 100644 --- a/ConsoleUI/InstallScreen.cs +++ b/ConsoleUI/InstallScreen.cs @@ -30,15 +30,16 @@ public InstallScreen(GameInstanceManager mgr, ChangePlan cp, bool dbg) /// /// Run the screen /// + /// The visual theme to use to draw the dialog /// Framework parameter not used by this object - public override void Run(Action process = null) + public override void Run(ConsoleTheme theme, Action process = null) { HashSet rejected = new HashSet(); - DrawBackground(); + DrawBackground(theme); using (TransactionScope trans = CkanTransaction.CreateTransactionScope()) { bool retry = false; do { - Draw(); + Draw(theme); try { // Reset this so we stop unless an exception sets it to true retry = false; @@ -49,7 +50,7 @@ public override void Run(Action process = null) // Track previously rejected optional dependencies and don't prompt for them again. DependencyScreen ds = new DependencyScreen(manager, plan, rejected, debug); if (ds.HaveOptions()) { - LaunchSubScreen(ds); + LaunchSubScreen(theme, ds); } } @@ -106,9 +107,9 @@ public override void Run(Action process = null) } catch (DownloadThrottledKraken ex) { if (RaiseYesNoDialog($"{ex.ToString()}\n\nEdit authentication tokens now?")) { if (ex.infoUrl != null) { - ModInfoScreen.LaunchURL(ex.infoUrl); + ModInfoScreen.LaunchURL(theme, ex.infoUrl); } - LaunchSubScreen(new AuthTokenScreen()); + LaunchSubScreen(theme, new AuthTokenScreen()); } } catch (MissingCertificateKraken ex) { RaiseError(ex.ToString()); @@ -122,8 +123,8 @@ public override void Run(Action process = null) ex.modules, (CkanModule mod) => mod.ToString() ); - CkanModule chosen = ch.Run(); - DrawBackground(); + CkanModule chosen = ch.Run(theme); + DrawBackground(theme); if (chosen != null) { // Use chosen to continue installing plan.Install.Add(chosen); diff --git a/ConsoleUI/ModInfoScreen.cs b/ConsoleUI/ModInfoScreen.cs index 27be0e4050..4fc1736da8 100644 --- a/ConsoleUI/ModInfoScreen.cs +++ b/ConsoleUI/ModInfoScreen.cs @@ -34,7 +34,7 @@ public ModInfoScreen(GameInstanceManager mgr, ChangePlan cp, CkanModule m, bool 1, 1, -1, () => mod.name == mod.identifier ? mod.name : $"{mod.name} ({mod.identifier})", null, - () => ConsoleTheme.Current.ActiveFrameFg + th => th.ActiveFrameFg )); AddObject(new ConsoleLabel( 1, 2, -1, @@ -44,14 +44,14 @@ public ModInfoScreen(GameInstanceManager mgr, ChangePlan cp, CkanModule m, bool AddObject(new ConsoleFrame( 1, 3, midL, 7, () => "", - () => ConsoleTheme.Current.NormalFrameFg, + th => th.NormalFrameFg, false )); AddObject(new ConsoleLabel( 3, 4, 11, () => "License:", null, - () => ConsoleTheme.Current.DimLabelFg + th => th.DimLabelFg )); AddObject(new ConsoleLabel( 13, 4, midL - 2, @@ -62,7 +62,7 @@ public ModInfoScreen(GameInstanceManager mgr, ChangePlan cp, CkanModule m, bool 3, 5, 12, () => "Download:", null, - () => ConsoleTheme.Current.DimLabelFg + th => th.DimLabelFg )); AddObject(new ConsoleLabel( 13, 5, midL - 2, @@ -79,14 +79,14 @@ public ModInfoScreen(GameInstanceManager mgr, ChangePlan cp, CkanModule m, bool AddObject(new ConsoleFrame( 1, Math.Max(depsBot, versBot) + 1, -1, -1, () => "Description", - () => ConsoleTheme.Current.NormalFrameFg, + th => th.NormalFrameFg, false )); ConsoleTextBox tb = new ConsoleTextBox( 3, Math.Max(depsBot, versBot) + 2, -3, -2, false, TextAlign.Left, - () => ConsoleTheme.Current.MainBg, - () => ConsoleTheme.Current.LabelFg + th => th.MainBg, + th => th.LabelFg ); tb.AddLine(mod.@abstract); if (!string.IsNullOrEmpty(mod.description) @@ -101,15 +101,15 @@ public ModInfoScreen(GameInstanceManager mgr, ChangePlan cp, CkanModule m, bool tb.AddScrollBindings(this); AddTip("Esc", "Back"); - AddBinding(Keys.Escape, (object sender) => false); + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => false); AddTip("Ctrl+D", "Download", () => !manager.Cache.IsMaybeCachedZip(mod) && !mod.IsDLC ); - AddBinding(Keys.CtrlD, (object sender) => { + AddBinding(Keys.CtrlD, (object sender, ConsoleTheme theme) => { if (!mod.IsDLC) { - Download(); + Download(theme); } return true; }); @@ -121,49 +121,49 @@ public ModInfoScreen(GameInstanceManager mgr, ChangePlan cp, CkanModule m, bool opts.Add(new ConsoleMenuOption( "Home page", "", "Open the home page URL in a browser", true, - () => LaunchURL(mod.resources.homepage) + th => LaunchURL(th, mod.resources.homepage) )); } if (mod.resources.repository != null) { opts.Add(new ConsoleMenuOption( "Repository", "", "Open the repository URL in a browser", true, - () => LaunchURL(mod.resources.repository) + th => LaunchURL(th, mod.resources.repository) )); } if (mod.resources.bugtracker != null) { opts.Add(new ConsoleMenuOption( "Bugtracker", "", "Open the bug tracker URL in a browser", true, - () => LaunchURL(mod.resources.bugtracker) + th => LaunchURL(th, mod.resources.bugtracker) )); } if (mod.resources.spacedock != null) { opts.Add(new ConsoleMenuOption( "SpaceDock", "", "Open the SpaceDock URL in a browser", true, - () => LaunchURL(mod.resources.spacedock) + th => LaunchURL(th, mod.resources.spacedock) )); } if (mod.resources.curse != null) { opts.Add(new ConsoleMenuOption( "Curse", "", "Open the Curse URL in a browser", true, - () => LaunchURL(mod.resources.curse) + th => LaunchURL(th, mod.resources.curse) )); } if (mod.resources.store != null) { opts.Add(new ConsoleMenuOption( "Store", "", "Open the Store URL in a browser", true, - () => LaunchURL(mod.resources.store) + th => LaunchURL(th, mod.resources.store) )); } if (mod.resources.steamstore != null) { opts.Add(new ConsoleMenuOption( "Steam Store", "", "Open the Steam Store URL in a browser", true, - () => LaunchURL(mod.resources.steamstore) + th => LaunchURL(th, mod.resources.steamstore) )); } if (debug) { @@ -205,7 +205,7 @@ protected override string MenuTip() return "Links"; } - private bool ViewMetadata() + private bool ViewMetadata(ConsoleTheme theme) { ConsoleMessageDialog md = new ConsoleMessageDialog( $"\"{mod.identifier}\": {registry.GetAvailableMetadata(mod.identifier)}", @@ -213,19 +213,20 @@ private bool ViewMetadata() () => $"{mod.name} Metadata", TextAlign.Left ); - md.Run(); - DrawBackground(); + md.Run(theme); + DrawBackground(theme); return true; } /// /// Launch a URL in the system browser. /// + /// The visual theme to use to draw the dialog /// URL to launch /// /// True. /// - public static bool LaunchURL(Uri u) + public static bool LaunchURL(ConsoleTheme theme, Uri u) { // I'm getting error output on Linux, because this runs xdg-open which // calls chromium-browser which prints a bunch of stuff about plugins that @@ -235,7 +236,7 @@ public static bool LaunchURL(Uri u) // So instead we display a popup dialog for the garbage to print all over, // then wait 1.5 seconds and refresh the screen when it closes. ConsoleMessageDialog d = new ConsoleMessageDialog("Launching...", new List()); - d.Run(() => { + d.Run(theme, (ConsoleTheme th) => { Utilities.ProcessStartURL(u.ToString()); System.Threading.Thread.Sleep(1500); }); @@ -256,7 +257,7 @@ private int addDependencies(int top = 8) AddObject(new ConsoleFrame( 1, top, midL, top + h - 1, () => "Dependencies", - () => ConsoleTheme.Current.NormalFrameFg, + th => th.NormalFrameFg, false )); if (numDeps > 0) { @@ -264,13 +265,13 @@ private int addDependencies(int top = 8) 3, top + 1, 3 + lblW - 1, () => $"Required ({numDeps}):", null, - () => ConsoleTheme.Current.DimLabelFg + th => th.DimLabelFg )); ConsoleTextBox tb = new ConsoleTextBox( 3 + lblW, top + 1, midL - 2, top + 1 + numDeps - 1, false, TextAlign.Left, - () => ConsoleTheme.Current.MainBg, - () => ConsoleTheme.Current.LabelFg + th => th.MainBg, + th => th.LabelFg ); AddObject(tb); foreach (RelationshipDescriptor rd in mod.depends) { @@ -287,13 +288,13 @@ private int addDependencies(int top = 8) 3, top + 1 + numDeps, 3 + lblW - 1, () => $"Conflicts ({numConfs}):", null, - () => ConsoleTheme.Current.DimLabelFg + th => th.DimLabelFg )); ConsoleTextBox tb = new ConsoleTextBox( 3 + lblW, top + 1 + numDeps, midL - 2, top + h - 2, false, TextAlign.Left, - () => ConsoleTheme.Current.MainBg, - () => ConsoleTheme.Current.LabelFg + th => th.MainBg, + th => th.LabelFg ); AddObject(tb); // FUTURE: Find mods that conflict with this one @@ -354,7 +355,7 @@ private int addVersionDisplay() addVersionBox( boxLeft, boxTop, boxRight, boxTop + boxH - 1, () => $"Replaced by {mr.ReplaceWith.identifier}", - () => ConsoleTheme.Current.AlertFrameFg, + th => th.AlertFrameFg, false, new List() {mr.ReplaceWith} ); @@ -363,7 +364,7 @@ private int addVersionDisplay() addVersionBox( boxLeft, boxTop, boxRight, boxTop + boxH - 1, () => $"Installed {instTime?.ToString("d") ?? "manually"}", - () => ConsoleTheme.Current.ActiveFrameFg, + th => th.ActiveFrameFg, true, new List() {inst} ); @@ -374,7 +375,7 @@ private int addVersionDisplay() addVersionBox( boxLeft, boxTop, boxRight, boxTop + boxH - 1, () => $"Latest/Installed {instTime?.ToString("d") ?? "manually"}", - () => ConsoleTheme.Current.ActiveFrameFg, + th => th.ActiveFrameFg, true, new List() {inst} ); @@ -388,7 +389,7 @@ private int addVersionDisplay() addVersionBox( boxLeft, boxTop, boxRight, boxTop + boxH - 1, () => "Latest Version", - () => ConsoleTheme.Current.AlertFrameFg, + th => th.AlertFrameFg, false, new List() {latest} ); @@ -397,7 +398,7 @@ private int addVersionDisplay() addVersionBox( boxLeft, boxTop, boxRight, boxTop + boxH - 1, () => $"Installed {instTime?.ToString("d") ?? "manually"}", - () => ConsoleTheme.Current.ActiveFrameFg, + th => th.ActiveFrameFg, true, new List() {inst} ); @@ -409,7 +410,7 @@ private int addVersionDisplay() addVersionBox( boxLeft, boxTop, boxRight, boxTop + boxH - 1, () => "Latest Version", - () => ConsoleTheme.Current.NormalFrameFg, + th => th.NormalFrameFg, false, new List() {latest} ); @@ -422,7 +423,7 @@ private int addVersionDisplay() addVersionBox( boxLeft, boxTop, boxRight, boxTop + boxH - 1, () => "Other Versions", - () => ConsoleTheme.Current.NormalFrameFg, + th => th.NormalFrameFg, false, others ); @@ -438,7 +439,7 @@ private int addVersionDisplay() addVersionBox( boxLeft, boxTop, boxRight, boxTop + boxH - 1, () => $"UNAVAILABLE/Installed {instTime?.ToString("d") ?? "manually"}", - () => ConsoleTheme.Current.AlertFrameFg, + th => th.AlertFrameFg, true, new List() {mod} ); @@ -449,7 +450,7 @@ private int addVersionDisplay() return boxTop - 1; } - private void addVersionBox(int l, int t, int r, int b, Func title, Func color, bool doubleLine, List releases) + private void addVersionBox(int l, int t, int r, int b, Func title, Func color, bool doubleLine, List releases) { AddObject(new ConsoleFrame( l, t, r, b, @@ -475,7 +476,7 @@ private void addVersionBox(int l, int t, int r, int b, Func title, Func< l + 2, t + 2, r - 2, () => "Compatible with:", null, - () => ConsoleTheme.Current.DimLabelFg + th => th.DimLabelFg )); AddObject(new ConsoleLabel( l + 4, t + 3, r - 2, @@ -535,14 +536,15 @@ private string HostedOn() return mod.download?.Host ?? ""; } - private void Download() + private void Download(ConsoleTheme theme) { ProgressScreen ps = new ProgressScreen($"Downloading {mod.identifier}"); NetAsyncModulesDownloader dl = new NetAsyncModulesDownloader(ps, manager.Cache); ModuleInstaller inst = ModuleInstaller.GetInstance(manager.CurrentInstance, manager.Cache, ps); LaunchSubScreen( + theme, ps, - () => { + (ConsoleTheme th) => { try { dl.DownloadModules(new List {mod}); if (!manager.Cache.IsMaybeCachedZip(mod)) { diff --git a/ConsoleUI/ModListHelpDialog.cs b/ConsoleUI/ModListHelpDialog.cs index fee27901ea..ade60c16b0 100644 --- a/ConsoleUI/ModListHelpDialog.cs +++ b/ConsoleUI/ModListHelpDialog.cs @@ -23,8 +23,8 @@ public ModListHelpDialog() : base() GetLeft() + 2, GetTop() + 2, Console.WindowWidth / 2 - 1, GetBottom() - 4, false, TextAlign.Center, - () => ConsoleTheme.Current.PopupBg, - () => ConsoleTheme.Current.PopupFg + th => th.PopupBg, + th => th.PopupFg ); AddObject(symbolTb); symbolTb.AddLine("Status Symbols"); @@ -46,8 +46,8 @@ public ModListHelpDialog() : base() Console.WindowWidth / 2 + 1, GetTop() + 3, GetRight() - 2, GetBottom() - 4, false, TextAlign.Center, - () => ConsoleTheme.Current.PopupBg, - () => ConsoleTheme.Current.PopupFg + th => th.PopupBg, + th => th.PopupFg ); AddObject(searchTb); searchTb.AddLine("Special Searches"); diff --git a/ConsoleUI/ModListScreen.cs b/ConsoleUI/ModListScreen.cs index 0ecf732292..96c11a0de8 100644 --- a/ConsoleUI/ModListScreen.cs +++ b/ConsoleUI/ModListScreen.cs @@ -123,33 +123,33 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) AddObject(searchBox); AddObject(moduleList); - AddBinding(Keys.CtrlQ, (object sender) => false); - AddBinding(Keys.AltX, (object sender) => false); - AddBinding(Keys.F1, (object sender) => Help()); - AddBinding(Keys.AltH, (object sender) => Help()); - AddBinding(Keys.F5, (object sender) => UpdateRegistry()); - AddBinding(Keys.CtrlR, (object sender) => UpdateRegistry()); - AddBinding(Keys.CtrlU, (object sender) => UpgradeAll()); + AddBinding(Keys.CtrlQ, (object sender, ConsoleTheme theme) => false); + AddBinding(Keys.AltX, (object sender, ConsoleTheme theme) => false); + AddBinding(Keys.F1, (object sender, ConsoleTheme theme) => Help(theme)); + AddBinding(Keys.AltH, (object sender, ConsoleTheme theme) => Help(theme)); + AddBinding(Keys.F5, (object sender, ConsoleTheme theme) => UpdateRegistry(theme)); + AddBinding(Keys.CtrlR, (object sender, ConsoleTheme theme) => UpdateRegistry(theme)); + AddBinding(Keys.CtrlU, (object sender, ConsoleTheme theme) => UpgradeAll(theme)); // Now a bunch of convenience shortcuts so you don't get stuck in the search box - searchBox.AddBinding(Keys.PageUp, (object sender) => { + searchBox.AddBinding(Keys.PageUp, (object sender, ConsoleTheme theme) => { SetFocus(moduleList); return true; }); - searchBox.AddBinding(Keys.PageDown, (object sender) => { + searchBox.AddBinding(Keys.PageDown, (object sender, ConsoleTheme theme) => { SetFocus(moduleList); return true; }); - searchBox.AddBinding(Keys.Enter, (object sender) => { + searchBox.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { SetFocus(moduleList); return true; }); - moduleList.AddBinding(Keys.CtrlF, (object sender) => { + moduleList.AddBinding(Keys.CtrlF, (object sender, ConsoleTheme theme) => { SetFocus(searchBox); return true; }); - moduleList.AddBinding(Keys.Escape, (object sender) => { + moduleList.AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => { searchBox.Clear(); return true; }); @@ -157,9 +157,9 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) moduleList.AddTip("Enter", "Details", () => moduleList.Selection != null ); - moduleList.AddBinding(Keys.Enter, (object sender) => { + moduleList.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { if (moduleList.Selection != null) { - LaunchSubScreen(new ModInfoScreen(manager, plan, moduleList.Selection, debug)); + LaunchSubScreen(theme, new ModInfoScreen(manager, plan, moduleList.Selection, debug)); } return true; }); @@ -178,7 +178,7 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) () => moduleList.Selection != null && registry.GetReplacement(moduleList.Selection.identifier, manager.CurrentInstance.VersionCriteria()) != null ); - moduleList.AddBinding(Keys.Plus, (object sender) => { + moduleList.AddBinding(Keys.Plus, (object sender, ConsoleTheme theme) => { if (moduleList.Selection != null && !moduleList.Selection.IsDLC) { if (!registry.IsInstalled(moduleList.Selection.identifier, false)) { plan.ToggleInstall(moduleList.Selection); @@ -197,7 +197,7 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) && registry.IsInstalled(moduleList.Selection.identifier, false) && !registry.IsAutodetected(moduleList.Selection.identifier) ); - moduleList.AddBinding(Keys.Minus, (object sender) => { + moduleList.AddBinding(Keys.Minus, (object sender, ConsoleTheme theme) => { if (moduleList.Selection != null && !moduleList.Selection.IsDLC && registry.IsInstalled(moduleList.Selection.identifier, false) && !registry.IsAutodetected(moduleList.Selection.identifier)) { @@ -214,7 +214,7 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) () => moduleList.Selection != null && !moduleList.Selection.IsDLC && (registry.InstalledModule(moduleList.Selection.identifier)?.AutoInstalled ?? false) ); - moduleList.AddBinding(Keys.F8, (object sender) => { + moduleList.AddBinding(Keys.F8, (object sender, ConsoleTheme theme) => { InstalledModule im = registry.InstalledModule(moduleList.Selection.identifier); if (im != null && !moduleList.Selection.IsDLC) { im.AutoInstalled = !im.AutoInstalled; @@ -224,8 +224,8 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) }); AddTip("F9", "Apply changes", plan.NonEmpty); - AddBinding(Keys.F9, (object sender) => { - ApplyChanges(); + AddBinding(Keys.F9, (object sender, ConsoleTheme theme) => { + ApplyChanges(theme); return true; }); @@ -234,7 +234,7 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) 1, -1, searchWidth, () => $"{CkanModule.FmtSize(totalInstalledDownloadSize())} installed", null, - () => ConsoleTheme.Current.DimLabelFg + th => th.DimLabelFg )); AddObject(new ConsoleLabel( @@ -246,14 +246,14 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) : $"Updated at least {days} days ago"; }, null, - () => { + (ConsoleTheme th) => { int daysSince = daysSinceUpdated(registryFilePath()); if (daysSince < daysTillStale) { - return ConsoleTheme.Current.RegistryUpToDate; + return th.RegistryUpToDate; } else if (daysSince < daystillVeryStale) { - return ConsoleTheme.Current.RegistryStale; + return th.RegistryStale; } else { - return ConsoleTheme.Current.RegistryVeryStale; + return th.RegistryVeryStale; } } )); @@ -292,7 +292,7 @@ public ModListScreen(GameInstanceManager mgr, bool dbg) null, new ConsoleMenuOption("Quit", "Ctrl+Q", "Exit to DOS", - true, () => false) + true, (ConsoleTheme th) => false) }; if (debug) { opts.Add(null); @@ -325,25 +325,25 @@ protected override string CenterHeader() ? "F1" : "F1, Alt+H"; - private bool ImportDownloads() + private bool ImportDownloads(ConsoleTheme theme) { - DownloadImportDialog.ImportDownloads(manager.CurrentInstance, manager.Cache, plan); + DownloadImportDialog.ImportDownloads(theme, manager.CurrentInstance, manager.Cache, plan); RefreshList(); return true; } - private bool CaptureKey() + private bool CaptureKey(ConsoleTheme theme) { ConsoleKeyInfo k = default(ConsoleKeyInfo); ConsoleMessageDialog keyprompt = new ConsoleMessageDialog("Press a key", new List()); - keyprompt.Run(() => { + keyprompt.Run(theme, (ConsoleTheme th) => { k = Console.ReadKey(true); }); ConsoleMessageDialog output = new ConsoleMessageDialog( $"Key: {k.Key,18}\nKeyChar: 0x{(int)k.KeyChar:x2}\nModifiers: {k.Modifiers,12}", new List {"OK"} ); - output.Run(); + output.Run(theme); return true; } @@ -357,7 +357,7 @@ private bool HasAnyUpgradeable() return false; } - private bool UpgradeAll() + private bool UpgradeAll(ConsoleTheme theme) { foreach (string identifier in registry.Installed(true).Select(kvp => kvp.Key)) { if (registry.HasUpdate(identifier, manager.CurrentInstance.VersionCriteria())) { @@ -367,7 +367,7 @@ private bool UpgradeAll() return true; } - private bool ViewSuggestions() + private bool ViewSuggestions(ConsoleTheme theme) { ChangePlan reinstall = new ChangePlan(); foreach (InstalledModule im in registry.InstalledModules) { @@ -383,7 +383,7 @@ private bool ViewSuggestions() try { DependencyScreen ds = new DependencyScreen(manager, reinstall, new HashSet(), debug); if (ds.HaveOptions()) { - LaunchSubScreen(ds); + LaunchSubScreen(theme, ds); bool needRefresh = false; // Copy the right ones into our real plan foreach (CkanModule mod in reinstall.Install) { @@ -414,10 +414,10 @@ private int daysSinceUpdated(string filename) return (DateTime.Now - File.GetLastWriteTime(filename)).Days; } - private bool UpdateRegistry() + private bool UpdateRegistry(ConsoleTheme theme) { ProgressScreen ps = new ProgressScreen("Updating Registry", "Checking for updates"); - LaunchSubScreen(ps, () => { + LaunchSubScreen(theme, ps, (ConsoleTheme th) => { HashSet availBefore = new HashSet( Array.ConvertAll( registry.CompatibleModules( @@ -473,10 +473,10 @@ private bool ScanForMods() return true; } - private bool SelectInstall() + private bool SelectInstall(ConsoleTheme theme) { GameInstance prevInst = manager.CurrentInstance; - LaunchSubScreen(new GameInstanceListScreen(manager)); + LaunchSubScreen(theme, new GameInstanceListScreen(manager)); // Abort if same instance as before if (!prevInst.Equals(manager.CurrentInstance)) { plan.Reset(); @@ -486,9 +486,9 @@ private bool SelectInstall() return true; } - private bool EditAuthTokens() + private bool EditAuthTokens(ConsoleTheme theme) { - LaunchSubScreen(new AuthTokenScreen()); + LaunchSubScreen(theme, new AuthTokenScreen()); return true; } @@ -518,7 +518,7 @@ private List GetAllMods(bool force = false) return allMods; } - private bool ExportInstalled() + private bool ExportInstalled(ConsoleTheme theme) { try { // Save the mod list as "depends" without the installed versions. @@ -535,17 +535,17 @@ private bool ExportInstalled() return true; } - private bool Help() + private bool Help(ConsoleTheme theme) { ModListHelpDialog hd = new ModListHelpDialog(); - hd.Run(); - DrawBackground(); + hd.Run(theme); + DrawBackground(theme); return true; } - private bool ApplyChanges() + private bool ApplyChanges(ConsoleTheme theme) { - LaunchSubScreen(new InstallScreen(manager, plan, debug)); + LaunchSubScreen(theme, new InstallScreen(manager, plan, debug)); RefreshList(); return true; } diff --git a/ConsoleUI/Program.cs b/ConsoleUI/Program.cs index b602a10de4..c584a9459e 100644 --- a/ConsoleUI/Program.cs +++ b/ConsoleUI/Program.cs @@ -16,7 +16,7 @@ public static class ConsoleUI [STAThread] public static void Main(string[] args) { - Main_(args, null); + Main_(args, null, null); } /// @@ -25,15 +25,16 @@ public static void Main(string[] args) /// /// Command line arguments /// Game instance manager object potentially initialized by command line flags + /// 'default' to use default theme, 'dark' to use dark theme /// True if debug options should be available, false otherwise /// /// Process exit status /// - public static int Main_(string[] args, GameInstanceManager manager, bool debug = false) + public static int Main_(string[] args, GameInstanceManager manager, string themeName, bool debug = false) { Logging.Initialize(); - new ConsoleCKAN(manager, debug); + new ConsoleCKAN(manager, themeName, debug); // Tell RegistryManager not to throw Dispose-related exceptions at exit RegistryManager.DisposeAll(); diff --git a/ConsoleUI/ProgressScreen.cs b/ConsoleUI/ProgressScreen.cs index 124ffed654..593975e716 100644 --- a/ConsoleUI/ProgressScreen.cs +++ b/ConsoleUI/ProgressScreen.cs @@ -23,7 +23,8 @@ public ProgressScreen(string descrip, string initMsg = "") 1, 2, -1, -1, 8, () => "Progress", () => "Messages", - () => ConsoleTheme.Current.NormalFrameFg + // Cheating because our IUser handler needs a theme context + th => { yesNoTheme = th; return th.NormalFrameFg; } )); progress = new ConsoleProgressBar( 3, 5, -3, @@ -78,11 +79,11 @@ public override bool RaiseYesNoDialog(string question) TextAlign.Center, -Console.WindowHeight / 2 ); - d.AddBinding(Keys.Y, (object sender) => { + d.AddBinding(Keys.Y, (object sender, ConsoleTheme theme) => { d.PressButton(0); return false; }); - d.AddBinding(Keys.N, (object sender) => { + d.AddBinding(Keys.N, (object sender, ConsoleTheme theme) => { d.PressButton(1); return false; }); @@ -91,9 +92,9 @@ public override bool RaiseYesNoDialog(string question) d.AddTip("Cursor keys", "Scroll messages"); messages.AddScrollBindings(d, true); - bool val = d.Run() == 0; - DrawBackground(); - Draw(); + bool val = d.Run(yesNoTheme) == 0; + DrawBackground(yesNoTheme); + Draw(yesNoTheme); return val; } @@ -121,6 +122,8 @@ protected override void Progress(string message, int percent) private ConsoleProgressBar progress; private ConsoleTextBox messages; + private ConsoleTheme yesNoTheme; + private string topMessage = ""; private string taskDescription = ""; private double percent = 0; diff --git a/ConsoleUI/RepoScreen.cs b/ConsoleUI/RepoScreen.cs index 72f86e327d..0317516d5e 100644 --- a/ConsoleUI/RepoScreen.cs +++ b/ConsoleUI/RepoScreen.cs @@ -35,7 +35,7 @@ protected RepoScreen(IGame game, SortedDictionary reps, stri AddObject(url); AddTip("F2", "Accept"); - AddBinding(Keys.F2, (object sender) => { + AddBinding(Keys.F2, (object sender, ConsoleTheme theme) => { if (Valid()) { Save(); return false; @@ -45,7 +45,7 @@ protected RepoScreen(IGame game, SortedDictionary reps, stri }); AddTip("Esc", "Cancel"); - AddBinding(Keys.Escape, (object sender) => { + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => { return false; }); @@ -57,7 +57,7 @@ protected RepoScreen(IGame game, SortedDictionary reps, stri Repository repo = r; opts.Add(new ConsoleMenuOption( repo.name, "", $"Import values from default mod list source {repo.name}", - true, () => { + true, (ConsoleTheme theme) => { name.Value = repo.name; name.Position = name.Value.Length; url.Value = repo.uri.ToString(); diff --git a/ConsoleUI/SplashScreen.cs b/ConsoleUI/SplashScreen.cs index f43a3d2982..a912cf65ee 100644 --- a/ConsoleUI/SplashScreen.cs +++ b/ConsoleUI/SplashScreen.cs @@ -21,18 +21,19 @@ public SplashScreen(GameInstanceManager mgr) /// /// Show the splash screen and wait for a key press. /// - public bool Run() + /// The visual theme to use to draw the dialog + public bool Run(ConsoleTheme theme) { // If there's a default instance, try to get the lock for it. GameInstance ksp = manager.CurrentInstance ?? manager.GetPreferredInstance(); - if (ksp != null && !GameInstanceListScreen.TryGetInstance(ksp, () => Draw(false))) { + if (ksp != null && !GameInstanceListScreen.TryGetInstance(theme, ksp, (ConsoleTheme th) => Draw(th, false))) { Console.ResetColor(); Console.Clear(); Console.CursorVisible = true; return false; } // Draw screen with press any key - Draw(true); + Draw(theme, true); // Wait for a key Console.ReadKey(true); return true; @@ -41,14 +42,22 @@ public bool Run() /// /// Draw a cool retro splash screen like IBM used to do. /// + /// The visual theme to use to draw the dialog /// If true, ask user to press any key, otherwise say loading - private void Draw(bool pressAny = false) + private void Draw(ConsoleTheme theme, bool pressAny = false) { Console.CursorVisible = false; - Console.ResetColor(); + if (theme.SplashBg.HasValue) + { + Console.BackgroundColor = theme.SplashBg.Value; + } + else + { + Console.ResetColor(); + } Console.Clear(); - Console.ForegroundColor = ConsoleColor.Blue; + Console.ForegroundColor = theme.SplashAccentFg; string block = $"{Symbols.lowerHalfBlock}"; @@ -63,7 +72,7 @@ private void Draw(bool pressAny = false) drawCentered(10, "Comprehensive Kerbal Archive Network"); - Console.ForegroundColor = ConsoleColor.Gray; + Console.ForegroundColor = theme.SplashNormalFg; string horiz = $"{Symbols.horizLineDouble}"; drawCentered(12, $"{Symbols.upperLeftCornerDouble}##################################################{Symbols.upperRightCornerDouble}".Replace("#", horiz)); diff --git a/ConsoleUI/Toolkit/ConsoleButton.cs b/ConsoleUI/Toolkit/ConsoleButton.cs index b9085a94f0..98aea54123 100644 --- a/ConsoleUI/Toolkit/ConsoleButton.cs +++ b/ConsoleUI/Toolkit/ConsoleButton.cs @@ -26,29 +26,33 @@ public ConsoleButton(int l, int t, int r, string cap, Action onClick) /// /// Draw the button /// + /// The visual theme to use to draw the dialog /// True if button has the focus, false otherwise - public override void Draw(bool focused) + public override void Draw(ConsoleTheme theme, bool focused) { int w = GetRight() - GetLeft() + 1; // Main button text Console.SetCursorPosition(GetLeft(), GetTop()); - Console.BackgroundColor = ConsoleTheme.Current.PopupButtonBg; + Console.BackgroundColor = theme.PopupButtonBg; if (focused) { - Console.ForegroundColor = ConsoleTheme.Current.PopupButtonSelectedFg; + Console.ForegroundColor = theme.PopupButtonSelectedFg; } else { - Console.ForegroundColor = ConsoleTheme.Current.PopupButtonFg; + Console.ForegroundColor = theme.PopupButtonFg; } Console.Write(ScreenObject.PadCenter(caption, w)); // Right shadow - Console.BackgroundColor = ConsoleTheme.Current.PopupBg; - Console.ForegroundColor = ConsoleTheme.Current.PopupButtonShadow; - Console.Write(Symbols.lowerHalfBlock); + if (theme.PopupButtonShadow.HasValue) + { + Console.BackgroundColor = theme.PopupBg; + Console.ForegroundColor = theme.PopupButtonShadow.Value; + Console.Write(Symbols.lowerHalfBlock); - // Bottom shadow - Console.SetCursorPosition(GetLeft() + 1, GetTop() + 1); - Console.Write(shadowStrip); + // Bottom shadow + Console.SetCursorPosition(GetLeft() + 1, GetTop() + 1); + Console.Write(shadowStrip); + } } /// diff --git a/ConsoleUI/Toolkit/ConsoleChoiceDialog.cs b/ConsoleUI/Toolkit/ConsoleChoiceDialog.cs index ba9e16ea77..cafd0c12d2 100644 --- a/ConsoleUI/Toolkit/ConsoleChoiceDialog.cs +++ b/ConsoleUI/Toolkit/ConsoleChoiceDialog.cs @@ -38,8 +38,8 @@ public ConsoleChoiceDialog(string m, string hdr, List c, Func ConsoleTheme.Current.PopupBg, - () => ConsoleTheme.Current.PopupFg + th => th.PopupBg, + th => th.PopupFg ); AddObject(tb); tb.AddLine(m); @@ -60,12 +60,12 @@ public ConsoleChoiceDialog(string m, string hdr, List c, Func { + choices.AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => { return false; }); choices.AddTip("Esc", "Cancel"); - choices.AddBinding(Keys.Escape, (object sender) => { + choices.AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => { cancelled = true; return false; }); @@ -76,13 +76,14 @@ public ConsoleChoiceDialog(string m, string hdr, List c, Func /// Display the dialog and handle its interaction /// + /// The visual theme to use to draw the dialog /// Function to control the dialog, default is normal user interaction /// /// Row user selected /// - public new ChoiceT Run(Action process = null) + public new ChoiceT Run(ConsoleTheme theme, Action process = null) { - base.Run(process); + base.Run(theme, process); return cancelled ? default(ChoiceT) : choices.Selection; } diff --git a/ConsoleUI/Toolkit/ConsoleDialog.cs b/ConsoleUI/Toolkit/ConsoleDialog.cs index 7935bb05a7..3a73809040 100644 --- a/ConsoleUI/Toolkit/ConsoleDialog.cs +++ b/ConsoleUI/Toolkit/ConsoleDialog.cs @@ -23,30 +23,34 @@ protected ConsoleDialog() /// /// Draw a drop shadow to the right and bottom of a given box /// + /// The visual theme to use to draw the dialog /// Left edge of box casting the shadow /// Top edge of box casting the shadow /// Right edge of box casting the shadow /// Bottom edge of box casting the shadow - public static void DrawShadow(int l, int t, int r, int b) + public static void DrawShadow(ConsoleTheme theme, int l, int t, int r, int b) { int w = r - l + 1; - Console.BackgroundColor = ConsoleTheme.Current.PopupShadow; - if (r < Console.WindowWidth - 2) { - // Right shadow - for (int y = t + 1; y <= b; ++y) { - if (y >= 0 && y < Console.WindowHeight - 1) { - Console.SetCursorPosition(r + 1, y); - Console.Write(" "); + if (theme.PopupShadow.HasValue) + { + Console.BackgroundColor = theme.PopupShadow.Value; + if (r < Console.WindowWidth - 2) { + // Right shadow + for (int y = t + 1; y <= b; ++y) { + if (y >= 0 && y < Console.WindowHeight - 1) { + Console.SetCursorPosition(r + 1, y); + Console.Write(" "); + } } } - } - // Bottom shadow - if (l + w + 2 > Console.WindowWidth) { - w = Console.WindowWidth - l - 2; - } - if (b < Console.WindowHeight - 1) { - Console.SetCursorPosition(l + 2, b + 1); - Console.Write("".PadRight(w)); + // Bottom shadow + if (l + w + 2 > Console.WindowWidth) { + w = Console.WindowWidth - l - 2; + } + if (b < Console.WindowHeight - 1) { + Console.SetCursorPosition(l + 2, b + 1); + Console.Write("".PadRight(w)); + } } } @@ -92,13 +96,13 @@ protected void SetDimensions(int l, int t, int r, int b) /// /// Draw the outline of the dialog and clear the footer /// - protected override void DrawBackground() + protected override void DrawBackground(ConsoleTheme theme) { int w = GetRight() - GetLeft() + 1; string fullHorizLineDouble = new string(Symbols.horizLineDouble, w - 2); string midSpace = new string(' ', w - 2); - Console.BackgroundColor = ConsoleTheme.Current.PopupBg; - Console.ForegroundColor = ConsoleTheme.Current.PopupOutlineFg; + Console.BackgroundColor = theme.PopupBg; + Console.ForegroundColor = theme.PopupOutlineFg; for (int y = GetTop(); y <= GetBottom(); ++y) { if (y < 0 || y >= Console.WindowHeight) { continue; @@ -123,7 +127,7 @@ protected override void DrawBackground() Console.Write(Symbols.vertLineDouble + midSpace + Symbols.vertLineDouble); } } - DrawShadow(GetLeft(), GetTop(), GetRight(), GetBottom()); + DrawShadow(theme, GetLeft(), GetTop(), GetRight(), GetBottom()); } private bool validX(int x) diff --git a/ConsoleUI/Toolkit/ConsoleDoubleFrame.cs b/ConsoleUI/Toolkit/ConsoleDoubleFrame.cs index 67e9367e4f..d27a35db54 100644 --- a/ConsoleUI/Toolkit/ConsoleDoubleFrame.cs +++ b/ConsoleUI/Toolkit/ConsoleDoubleFrame.cs @@ -22,7 +22,7 @@ public class ConsoleDoubleFrame : ScreenObject { /// If true, draw a double line border, else single line public ConsoleDoubleFrame(int l, int t, int r, int b, int midY, Func topTitle, Func midTitle, - Func borderColor, bool dblBorder = false) + Func borderColor, bool dblBorder = false) : base(l, t, r, b) { getTopTitle = topTitle; @@ -35,14 +35,15 @@ public ConsoleDoubleFrame(int l, int t, int r, int b, int midY, /// /// Draw a frame /// + /// The visual theme to use to draw the dialog /// Framework parameter not relevant to this control - public override void Draw(bool focused) + public override void Draw(ConsoleTheme theme, bool focused) { int l = GetLeft(), t = GetTop(), r = GetRight(), b = GetBottom(); int w = r - l + 1; - Console.BackgroundColor = ConsoleTheme.Current.MainBg; - Console.ForegroundColor = getColor(); + Console.BackgroundColor = theme.MainBg; + Console.ForegroundColor = getColor(theme); Console.SetCursorPosition(l, t); Console.Write(doubleBorder ? Symbols.upperLeftCornerDouble : Symbols.upperLeftCorner); writeTitleRow(getTopTitle(), w); @@ -92,7 +93,7 @@ private void writeTitleRow(string title, int w) private Func getTopTitle; private Func getMidTitle; - private Func getColor; + private Func getColor; private bool doubleBorder; private int middleRow; } diff --git a/ConsoleUI/Toolkit/ConsoleField.cs b/ConsoleUI/Toolkit/ConsoleField.cs index d1d2263584..33d1ce8263 100644 --- a/ConsoleUI/Toolkit/ConsoleField.cs +++ b/ConsoleUI/Toolkit/ConsoleField.cs @@ -67,8 +67,9 @@ public void Clear() /// /// Draw the field /// + /// The visual theme to use to draw the dialog /// If true, draw with focus, else without focus - public override void Draw(bool focused) + public override void Draw(ConsoleTheme theme, bool focused) { int w = GetRight() - GetLeft() + 1; @@ -83,15 +84,15 @@ public override void Draw(bool focused) } Console.SetCursorPosition(GetLeft(), GetTop()); - Console.BackgroundColor = ConsoleTheme.Current.FieldBg; + Console.BackgroundColor = theme.FieldBg; if (string.IsNullOrEmpty(Value)) { - Console.ForegroundColor = ConsoleTheme.Current.FieldGhostFg; + Console.ForegroundColor = theme.FieldGhostFg; Console.Write(GhostText().PadRight(w)); } else { if (focused) { - Console.ForegroundColor = ConsoleTheme.Current.FieldFocusedFg; + Console.ForegroundColor = theme.FieldFocusedFg; } else { - Console.ForegroundColor = ConsoleTheme.Current.FieldBlurredFg; + Console.ForegroundColor = theme.FieldBlurredFg; } Console.Write(FormatExactWidth(Value.Substring(leftPos), w)); } diff --git a/ConsoleUI/Toolkit/ConsoleFileMultiSelectDialog.cs b/ConsoleUI/Toolkit/ConsoleFileMultiSelectDialog.cs index 73b8b3f007..255334fdea 100644 --- a/ConsoleUI/Toolkit/ConsoleFileMultiSelectDialog.cs +++ b/ConsoleUI/Toolkit/ConsoleFileMultiSelectDialog.cs @@ -35,8 +35,8 @@ public ConsoleFileMultiSelectDialog(string title, string startPath, string filPa AddObject(new ConsoleLabel( left + 2, top + 2, left + 2 + labelW - 1, () => $"Directory:", - () => ConsoleTheme.Current.PopupBg, - () => ConsoleTheme.Current.PopupFg + th => th.PopupBg, + th => th.PopupFg )); pathField = new ConsoleField( @@ -49,8 +49,8 @@ public ConsoleFileMultiSelectDialog(string title, string startPath, string filPa AddObject(new ConsoleLabel( left + 2, bottom - 1, right - 2, () => $"{chosenFiles.Count} selected, {CkanModule.FmtSize(totalChosenSize())}", - () => ConsoleTheme.Current.PopupBg, - () => ConsoleTheme.Current.PopupFg + th => th.PopupBg, + th => th.PopupFg )); // ListBox showing zip files in current dir @@ -90,25 +90,25 @@ public ConsoleFileMultiSelectDialog(string title, string startPath, string filPa AddObject(fileList); AddTip("Esc", "Cancel"); - AddBinding(Keys.Escape, (object sender) => { + AddBinding(Keys.Escape, (object sender, ConsoleTheme theme) => { chosenFiles.Clear(); return false; }); AddTip("F10", "Sort"); - AddBinding(Keys.F10, (object sender) => { - fileList.SortMenu().Run(right - 2, top + 2); - DrawBackground(); + AddBinding(Keys.F10, (object sender, ConsoleTheme theme) => { + fileList.SortMenu().Run(theme, right - 2, top + 2); + DrawBackground(theme); return true; }); AddTip("Enter", "Change directory", () => fileList.Selection != null && isDir(fileList.Selection)); AddTip("Enter", "Select", () => fileList.Selection != null && !isDir(fileList.Selection)); - AddBinding(Keys.Enter, (object sender) => selectRow()); - AddBinding(Keys.Space, (object sender) => selectRow()); + AddBinding(Keys.Enter, (object sender, ConsoleTheme theme) => selectRow()); + AddBinding(Keys.Space, (object sender, ConsoleTheme theme) => selectRow()); AddTip("Ctrl+A", "Select all"); - AddBinding(Keys.CtrlA, (object sender) => { + AddBinding(Keys.CtrlA, (object sender, ConsoleTheme theme) => { foreach (FileSystemInfo fi in contents) { if (!isDir(fi)) { FileInfo file = fi as FileInfo; @@ -121,7 +121,7 @@ public ConsoleFileMultiSelectDialog(string title, string startPath, string filPa }); AddTip("Ctrl+D", "Deselect all", () => chosenFiles.Count > 0); - AddBinding(Keys.CtrlD, (object sender) => { + AddBinding(Keys.CtrlD, (object sender, ConsoleTheme theme) => { if (chosenFiles.Count > 0) { chosenFiles.Clear(); } @@ -129,7 +129,7 @@ public ConsoleFileMultiSelectDialog(string title, string startPath, string filPa }); AddTip("F9", "Import", () => chosenFiles.Count > 0); - AddBinding(Keys.F9, (object sender) => { + AddBinding(Keys.F9, (object sender, ConsoleTheme theme) => { return false; }); } @@ -170,13 +170,14 @@ private void pathFieldChanged(ConsoleField sender, string newValue) /// /// Display the dialog and handle its interaction /// + /// The visual theme to use to draw the dialog /// Function to control the dialog, default is normal user interaction /// /// Files user selected /// - public new HashSet Run(Action process = null) + public new HashSet Run(ConsoleTheme theme, Action process = null) { - base.Run(process); + base.Run(theme, process); return chosenFiles; } diff --git a/ConsoleUI/Toolkit/ConsoleFrame.cs b/ConsoleUI/Toolkit/ConsoleFrame.cs index 27c9e0abe0..1d9bc859b1 100644 --- a/ConsoleUI/Toolkit/ConsoleFrame.cs +++ b/ConsoleUI/Toolkit/ConsoleFrame.cs @@ -18,7 +18,7 @@ public class ConsoleFrame : ScreenObject { /// Function returning foreground color for border /// If true, draw a double line border, else single line public ConsoleFrame(int l, int t, int r, int b, Func title, - Func borderColor, bool dblBorder = false) + Func borderColor, bool dblBorder = false) : base(l, t, r, b) { getTitle = title; @@ -29,15 +29,16 @@ public ConsoleFrame(int l, int t, int r, int b, Func title, /// /// Draw a frame /// + /// The visual theme to use to draw the dialog /// Framework parameter not relevant to this control - public override void Draw(bool focused) + public override void Draw(ConsoleTheme theme, bool focused) { int l = GetLeft(), t = GetTop(), r = GetRight(), b = GetBottom(); int w = r - l + 1; string title = getTitle(); - Console.BackgroundColor = ConsoleTheme.Current.MainBg; - Console.ForegroundColor = getColor(); + Console.BackgroundColor = theme.MainBg; + Console.ForegroundColor = getColor(theme); Console.SetCursorPosition(l, t); Console.Write(doubleBorder ? Symbols.upperLeftCornerDouble : Symbols.upperLeftCorner); if (title.Length > 0) { @@ -75,7 +76,7 @@ public override void Draw(bool focused) public override bool Focusable() { return false; } private Func getTitle; - private Func getColor; + private Func getColor; private bool doubleBorder; } diff --git a/ConsoleUI/Toolkit/ConsoleLabel.cs b/ConsoleUI/Toolkit/ConsoleLabel.cs index 90895c7a21..a59f8678a0 100644 --- a/ConsoleUI/Toolkit/ConsoleLabel.cs +++ b/ConsoleUI/Toolkit/ConsoleLabel.cs @@ -16,7 +16,7 @@ public class ConsoleLabel : ScreenObject { /// Function returning the text to show in the label /// Function returning the background color for the label /// Function returning the foreground color for the label - public ConsoleLabel(int l, int t, int r, Func lf, Func bgFunc = null, Func fgFunc = null) + public ConsoleLabel(int l, int t, int r, Func lf, Func bgFunc = null, Func fgFunc = null) : base(l, t, r, t) { labelFunc = lf; @@ -27,20 +27,21 @@ public ConsoleLabel(int l, int t, int r, Func lf, Func bgF /// /// Draw the labelFunc /// + /// The visual theme to use to draw the dialog /// Framework parameter not relevant to this object - public override void Draw(bool focused) + public override void Draw(ConsoleTheme theme, bool focused) { int w = GetRight() - GetLeft() + 1; Console.SetCursorPosition(GetLeft(), GetTop()); if (getBgColor == null) { - Console.BackgroundColor = ConsoleTheme.Current.LabelBg; + Console.BackgroundColor = theme.LabelBg; } else { - Console.BackgroundColor = getBgColor(); + Console.BackgroundColor = getBgColor(theme); } if (getFgColor == null) { - Console.ForegroundColor = ConsoleTheme.Current.LabelFg; + Console.ForegroundColor = theme.LabelFg; } else { - Console.ForegroundColor = getFgColor(); + Console.ForegroundColor = getFgColor(theme); } try { Console.Write(FormatExactWidth(labelFunc(), w)); @@ -55,8 +56,8 @@ public override void Draw(bool focused) public override bool Focusable() { return false; } private Func labelFunc; - private Func getBgColor; - private Func getFgColor; + private Func getBgColor; + private Func getFgColor; } } diff --git a/ConsoleUI/Toolkit/ConsoleListBox.cs b/ConsoleUI/Toolkit/ConsoleListBox.cs index b75bf4e06f..f7e29eccef 100644 --- a/ConsoleUI/Toolkit/ConsoleListBox.cs +++ b/ConsoleUI/Toolkit/ConsoleListBox.cs @@ -100,8 +100,9 @@ public RowT Selection { /// /// Draw the list box /// + /// The visual theme to use to draw the dialog /// Framework parameter not relevant to this object - public override void Draw(bool focused) + public override void Draw(ConsoleTheme theme, bool focused) { int l = GetLeft(), r = GetRight(), t = GetTop(), b = GetBottom(), h = b - t + 1; @@ -140,8 +141,8 @@ public override void Draw(bool focused) for (int y = 0, index = topRow - 1; y < h; ++y, ++index) { Console.SetCursorPosition(l, t + y); if (y == 0) { - Console.BackgroundColor = ConsoleTheme.Current.ListBoxHeaderBg; - Console.ForegroundColor = ConsoleTheme.Current.ListBoxHeaderFg; + Console.BackgroundColor = theme.ListBoxHeaderBg; + Console.ForegroundColor = theme.ListBoxHeaderFg; Console.Write(" "); for (int i = 0; i < columns.Count; ++i) { ConsoleListBoxColumn col = columns[i]; @@ -159,11 +160,11 @@ public override void Draw(bool focused) } } else if (index >= 0 && index < sortedFilteredData.Count) { if (topRow + y - 1 == selectedRow) { - Console.BackgroundColor = ConsoleTheme.Current.ListBoxSelectedBg; - Console.ForegroundColor = ConsoleTheme.Current.ListBoxSelectedFg; + Console.BackgroundColor = theme.ListBoxSelectedBg; + Console.ForegroundColor = theme.ListBoxSelectedFg; } else { - Console.BackgroundColor = ConsoleTheme.Current.ListBoxUnselectedBg; - Console.ForegroundColor = ConsoleTheme.Current.ListBoxUnselectedFg; + Console.BackgroundColor = theme.ListBoxUnselectedBg; + Console.ForegroundColor = theme.ListBoxUnselectedFg; } Console.Write(" "); for (int i = 0; i < columns.Count; ++i) { @@ -181,8 +182,8 @@ public override void Draw(bool focused) } } } else { - Console.BackgroundColor = ConsoleTheme.Current.ListBoxUnselectedBg; - Console.ForegroundColor = ConsoleTheme.Current.ListBoxUnselectedFg; + Console.BackgroundColor = theme.ListBoxUnselectedBg; + Console.ForegroundColor = theme.ListBoxUnselectedFg; } try { if (y == 0) { @@ -197,6 +198,7 @@ public override void Draw(bool focused) // Now draw the scrollbar if (needScrollbar) { DrawScrollbar( + theme, r, t + scrollTop, b, sortedFilteredData.Count > 0 ? t + 1 + scrollTop + (h - 2 - scrollTop) * selectedRow / sortedFilteredData.Count @@ -295,14 +297,14 @@ public ConsolePopupMenu SortMenu() "Ascending", "", "Sort the list in ascending order", true, - () => { SortDirection = ListSortDirection.Ascending; return true; }, + (ConsoleTheme theme) => { SortDirection = ListSortDirection.Ascending; return true; }, () => { return sortDir == ListSortDirection.Ascending; } ), new ConsoleMenuOption( "Descending", "", "Sort the list in descending order", true, - () => { SortDirection = ListSortDirection.Descending; return true;}, + (ConsoleTheme theme) => { SortDirection = ListSortDirection.Descending; return true;}, () => { return sortDir == ListSortDirection.Descending; } ), null @@ -319,7 +321,7 @@ public ConsolePopupMenu SortMenu() ? $"Sort the list by column #{i+1}" : $"Sort the list by the {columns[i].Header} column", true, - () => { SortColumnIndex = newIndex; return true; }, + (ConsoleTheme theme) => { SortColumnIndex = newIndex; return true; }, () => { return sortColIndex == newIndex; } )); } diff --git a/ConsoleUI/Toolkit/ConsoleMessageDialog.cs b/ConsoleUI/Toolkit/ConsoleMessageDialog.cs index 1fe8c6b7dd..ca8848b0ec 100644 --- a/ConsoleUI/Toolkit/ConsoleMessageDialog.cs +++ b/ConsoleUI/Toolkit/ConsoleMessageDialog.cs @@ -66,8 +66,8 @@ public ConsoleMessageDialog(string m, List btns, Func hdr = null GetLeft() + 2, GetTop() + 2, GetRight() - 2, GetBottom() - 2 - (btns.Count > 0 ? 2 : 0), false, ta, - () => ConsoleTheme.Current.PopupBg, - () => ConsoleTheme.Current.PopupFg + th => th.PopupBg, + th => th.PopupFg ); AddObject(tb); tb.AddLine(m); @@ -95,13 +95,14 @@ public ConsoleMessageDialog(string m, List btns, Func hdr = null /// /// Show the dialog and handle its interaction /// + /// The visual theme to use to draw the dialog /// Function to control the dialog, default is normal user interaction /// /// Index of button the user pressed /// - public new int Run(Action process = null) + public new int Run(ConsoleTheme theme, Action process = null) { - base.Run(process); + base.Run(theme, process); return selectedButton; } diff --git a/ConsoleUI/Toolkit/ConsolePopupMenu.cs b/ConsoleUI/Toolkit/ConsolePopupMenu.cs index 8e5a49b203..6992071280 100644 --- a/ConsoleUI/Toolkit/ConsolePopupMenu.cs +++ b/ConsoleUI/Toolkit/ConsolePopupMenu.cs @@ -35,17 +35,18 @@ public ConsolePopupMenu(List opts) /// /// Display the menu and handle its interactions /// + /// The visual theme to use to draw the dialog /// X coordinate of right edge of menu /// Y coordinate of top edge of menu /// /// Return value of menu option selected by user /// - public bool Run(int right, int top) + public bool Run(ConsoleTheme theme, int right, int top) { bool val = true; bool done = false; do { - Draw(right, top); + Draw(theme, right, top); ConsoleKeyInfo k = Console.ReadKey(true); switch (k.Key) { case ConsoleKey.UpArrow: @@ -63,10 +64,11 @@ public bool Run(int right, int top) done = true; } if (options[selectedOption].OnExec != null) { - val = options[selectedOption].OnExec(); + val = options[selectedOption].OnExec(theme); } if (options[selectedOption].SubMenu != null) { options[selectedOption].SubMenu.Run( + theme, right - 2, top + selectedOption + 2 ); @@ -81,7 +83,7 @@ public bool Run(int right, int top) return val; } - private void Draw(int right, int top) + private void Draw(ConsoleTheme theme, int right, int top) { if (options.Count > 0) { right = Formatting.ConvertCoord(right, Console.WindowWidth); @@ -92,8 +94,8 @@ private void Draw(int right, int top) // Horizontal lines before and after the options int h = options.Count + 2; - Console.BackgroundColor = ConsoleTheme.Current.MenuBg; - Console.ForegroundColor = ConsoleTheme.Current.MenuFg; + Console.BackgroundColor = theme.MenuBg; + Console.ForegroundColor = theme.MenuFg; string fullHorizLine = new string(Symbols.horizLine, longestLength + 2); for (int index = -1, y = top; y < top + h; ++index, ++y) { Console.SetCursorPosition(right - w + 1, y); @@ -114,19 +116,19 @@ private void Draw(int right, int top) // Draw menu option Console.Write(Symbols.vertLine); if (!opt.Enabled) { - Console.ForegroundColor = ConsoleTheme.Current.MenuDisabledFg; + Console.ForegroundColor = theme.MenuDisabledFg; } if (index == selectedOption) { // Draw highlighted menu option - Console.BackgroundColor = ConsoleTheme.Current.MenuSelectedBg; + Console.BackgroundColor = theme.MenuSelectedBg; Console.Write(" " + AnnotatedCaption(opt) + " "); - Console.BackgroundColor = ConsoleTheme.Current.MenuBg; + Console.BackgroundColor = theme.MenuBg; } else { // Draw normal menu option Console.Write(" " + AnnotatedCaption(opt) + " "); } if (!opt.Enabled) { - Console.ForegroundColor = ConsoleTheme.Current.MenuFg; + Console.ForegroundColor = theme.MenuFg; } Console.Write(Symbols.vertLine); } @@ -134,17 +136,17 @@ private void Draw(int right, int top) // Right padding Console.Write(" "); } - ConsoleDialog.DrawShadow(right - w + 1, top, right, top + h - 1); - DrawFooter(); + ConsoleDialog.DrawShadow(theme, right - w + 1, top, right, top + h - 1); + DrawFooter(theme); Console.SetCursorPosition(right - longestLength - 3, top + selectedOption + 1); Console.CursorVisible = true; } } - private void DrawFooter() + private void DrawFooter(ConsoleTheme theme) { - Console.BackgroundColor = ConsoleTheme.Current.FooterBg; - Console.ForegroundColor = ConsoleTheme.Current.FooterDescriptionFg; + Console.BackgroundColor = theme.FooterBg; + Console.ForegroundColor = theme.FooterDescriptionFg; Console.SetCursorPosition(0, Console.WindowHeight - 1); Console.Write(" "); // Windows cmd.exe auto-scrolls the whole window if you draw a @@ -191,7 +193,7 @@ public class ConsoleMenuOption { /// Submenu to open for this option /// true if this option should be drawn normally and allowed for selection, false to draw it grayed out and not allow selection public ConsoleMenuOption(string cap, string key, string tt, bool close, - Func exec = null, Func radio = null, ConsolePopupMenu submenu = null, + Func exec = null, Func radio = null, ConsolePopupMenu submenu = null, bool enabled = true) { Caption = cap; @@ -223,7 +225,7 @@ public ConsoleMenuOption(string cap, string key, string tt, bool close, /// /// Function to call if the user chooses this option /// - public readonly Func OnExec; + public readonly Func OnExec; /// /// If set, this option is a radio button, and this function returns its value /// diff --git a/ConsoleUI/Toolkit/ConsoleProgressBar.cs b/ConsoleUI/Toolkit/ConsoleProgressBar.cs index e8f7e1fcfa..77f93b35a5 100644 --- a/ConsoleUI/Toolkit/ConsoleProgressBar.cs +++ b/ConsoleUI/Toolkit/ConsoleProgressBar.cs @@ -25,8 +25,9 @@ public ConsoleProgressBar(int l, int t, int r, Func cf, Func pf) /// /// Draw the progress bar /// + /// The visual theme to use to draw the dialog /// Framework parameter not relevant to this object - public override void Draw(bool focused) + public override void Draw(ConsoleTheme theme, bool focused) { int l = GetLeft(), t = GetTop(); int w = GetRight() - l + 1; @@ -46,14 +47,14 @@ public override void Draw(bool focused) // Draw the highlighted part if (highlightWidth > 0) { - Console.BackgroundColor = ConsoleTheme.Current.ProgressBarHighlightBg; - Console.ForegroundColor = ConsoleTheme.Current.ProgressBarHighlightFg; + Console.BackgroundColor = theme.ProgressBarHighlightBg; + Console.ForegroundColor = theme.ProgressBarHighlightFg; Console.Write(caption.Substring(0, highlightWidth)); } // Draw the non highlighted part - Console.BackgroundColor = ConsoleTheme.Current.ProgressBarBg; - Console.ForegroundColor = ConsoleTheme.Current.ProgressBarFg; + Console.BackgroundColor = theme.ProgressBarBg; + Console.ForegroundColor = theme.ProgressBarFg; Console.Write(caption.Substring(highlightWidth)); } diff --git a/ConsoleUI/Toolkit/ConsoleScreen.cs b/ConsoleUI/Toolkit/ConsoleScreen.cs index 98f224385f..856d0cf0d4 100644 --- a/ConsoleUI/Toolkit/ConsoleScreen.cs +++ b/ConsoleUI/Toolkit/ConsoleScreen.cs @@ -18,14 +18,14 @@ protected ConsoleScreen() "F10", MenuTip(), () => mainMenu != null ); - AddBinding(Keys.F10, (object sender) => { + AddBinding(Keys.F10, (object sender, ConsoleTheme theme) => { bool val = true; if (mainMenu != null) { - DrawSelectedHamburger(); + DrawSelectedHamburger(theme); - val = mainMenu.Run(Console.WindowWidth - 1, 1); + val = mainMenu.Run(theme, Console.WindowWidth - 1, 1); - DrawBackground(); + DrawBackground(theme); } return val; }); @@ -34,13 +34,14 @@ protected ConsoleScreen() /// /// Launch a screen and then clean up after it so we can continue using this screen. /// + /// The visual theme to use to draw the dialog /// Subscreen to launch /// Function to drive the screen, default is normal interaction - protected void LaunchSubScreen(ConsoleScreen cs, Action newProc = null) + protected void LaunchSubScreen(ConsoleTheme theme, ConsoleScreen cs, Action newProc = null) { - cs.Run(newProc); - DrawBackground(); - Draw(); + cs.Run(theme, newProc); + DrawBackground(theme); + Draw(theme); } /// @@ -95,18 +96,18 @@ public virtual bool RaiseYesNoDialog(string question) string.Join("", messagePieces) + question, new List() {"Yes", "No"} ); - d.AddBinding(Keys.Y, (object sender) => { + d.AddBinding(Keys.Y, (object sender, ConsoleTheme theme) => { d.PressButton(0); return false; }); - d.AddBinding(Keys.N, (object sender) => { + d.AddBinding(Keys.N, (object sender, ConsoleTheme theme) => { d.PressButton(1); return false; }); messagePieces.Clear(); - bool val = d.Run() == 0; - DrawBackground(); - Draw(); + bool val = d.Run(userTheme) == 0; + DrawBackground(userTheme); + Draw(userTheme); return val; } @@ -127,9 +128,9 @@ public int RaiseSelectionDialog(string message, params object[] args) new List(Array.ConvertAll(args, p => p.ToString())) ); messagePieces.Clear(); - int val = d.Run(); - DrawBackground(); - Draw(); + int val = d.Run(userTheme); + DrawBackground(userTheme); + Draw(userTheme); return val; } @@ -146,9 +147,9 @@ public void RaiseError(string message, params object[] args) new List() {"OK"} ); messagePieces.Clear(); - d.Run(); - DrawBackground(); - Draw(); + d.Run(userTheme); + DrawBackground(userTheme); + Draw(userTheme); } /// @@ -160,7 +161,7 @@ public void RaiseError(string message, params object[] args) public void RaiseMessage(string message, params object[] args) { Message(message, args); - Draw(); + Draw(userTheme); } /// @@ -197,7 +198,7 @@ protected virtual void Message(string message, params object[] args) public void RaiseProgress(string message, int percent) { Progress(message, percent); - Draw(); + Draw(userTheme); } /// @@ -209,25 +210,28 @@ protected virtual void Progress(string message, int percent) { } #endregion IUser - private void DrawSelectedHamburger() + private void DrawSelectedHamburger(ConsoleTheme theme) { Console.SetCursorPosition(Console.WindowWidth - 3, 0); - Console.BackgroundColor = ConsoleTheme.Current.MenuSelectedBg; - Console.ForegroundColor = ConsoleTheme.Current.MenuFg; + Console.BackgroundColor = theme.MenuSelectedBg; + Console.ForegroundColor = theme.MenuFg; Console.Write(hamburger); } /// /// Set the whole screen to dark blue and draw the top header bar /// - protected override void DrawBackground() + protected override void DrawBackground(ConsoleTheme theme) { - Console.BackgroundColor = ConsoleTheme.Current.MainBg; + // Cheat because our IUser handlers need a theme + userTheme = theme; + + Console.BackgroundColor = theme.MainBg; Console.Clear(); Console.SetCursorPosition(0, 0); - Console.BackgroundColor = ConsoleTheme.Current.HeaderBg; - Console.ForegroundColor = ConsoleTheme.Current.HeaderFg; + Console.BackgroundColor = theme.HeaderBg; + Console.ForegroundColor = theme.HeaderFg; Console.Write(LeftCenterRight( " " + LeftHeader(), CenterHeader(), @@ -262,6 +266,7 @@ private static string LeftCenterRight(string left, string center, string right, return left.PadRight(leftSideWidth) + center + right.PadLeft(rightSideWidth); } + private ConsoleTheme userTheme; private static readonly string hamburger = $" {Symbols.hamburger} "; } diff --git a/ConsoleUI/Toolkit/ConsoleTextBox.cs b/ConsoleUI/Toolkit/ConsoleTextBox.cs index 1cef248a97..273f14eeb4 100644 --- a/ConsoleUI/Toolkit/ConsoleTextBox.cs +++ b/ConsoleUI/Toolkit/ConsoleTextBox.cs @@ -23,8 +23,8 @@ public ConsoleTextBox( int l, int t, int r, int b, bool autoScroll = true, TextAlign ta = TextAlign.Left, - Func bgFunc = null, - Func fgFunc = null) + Func bgFunc = null, + Func fgFunc = null) : base(l, t, r, b) { scrollToBottom = autoScroll; @@ -95,8 +95,9 @@ public void ScrollDown(int? howFar = null) /// /// Draw the text box /// + /// The visual theme to use to draw the dialog /// Framework parameter not relevant to this object - public override void Draw(bool focused) + public override void Draw(ConsoleTheme theme, bool focused) { int l = GetLeft(); int h = GetBottom() - GetTop() + 1; @@ -105,14 +106,14 @@ public override void Draw(bool focused) int w = GetRight() - l + 1 + (lines.Count > h ? -1 : 0); if (getBgColor != null) { - Console.BackgroundColor = getBgColor(); + Console.BackgroundColor = getBgColor(theme); } else { - Console.BackgroundColor = ConsoleTheme.Current.TextBoxBg; + Console.BackgroundColor = theme.TextBoxBg; } if (getFgColor != null) { - Console.ForegroundColor = getFgColor(); + Console.ForegroundColor = getFgColor(theme); } else { - Console.ForegroundColor = ConsoleTheme.Current.TextBoxFg; + Console.ForegroundColor = theme.TextBoxFg; } for (int y = GetTop(); y <= GetBottom(); ++y, ++index) { Console.SetCursorPosition(l, y); @@ -136,6 +137,7 @@ public override void Draw(bool focused) // Scrollbar if (lines.Count > h) { DrawScrollbar( + theme, GetRight(), GetTop(), GetBottom(), GetTop() + 1 + (h - 3) * topLine / (lines.Count - h) ); @@ -150,58 +152,58 @@ public override void Draw(bool focused) public void AddScrollBindings(ScreenContainer cont, bool drawMore = false) { if (drawMore) { - cont.AddBinding(Keys.Home, (object sender) => { + cont.AddBinding(Keys.Home, (object sender, ConsoleTheme theme) => { ScrollToTop(); - Draw(false); + Draw(theme, false); return true; }); - cont.AddBinding(Keys.End, (object sender) => { + cont.AddBinding(Keys.End, (object sender, ConsoleTheme theme) => { ScrollToBottom(); - Draw(false); + Draw(theme, false); return true; }); - cont.AddBinding(Keys.PageUp, (object sender) => { + cont.AddBinding(Keys.PageUp, (object sender, ConsoleTheme theme) => { ScrollUp(); - Draw(false); + Draw(theme, false); return true; }); - cont.AddBinding(Keys.PageDown, (object sender) => { + cont.AddBinding(Keys.PageDown, (object sender, ConsoleTheme theme) => { ScrollDown(); - Draw(false); + Draw(theme, false); return true; }); - cont.AddBinding(Keys.UpArrow, (object sender) => { + cont.AddBinding(Keys.UpArrow, (object sender, ConsoleTheme theme) => { ScrollUp(1); - Draw(false); + Draw(theme, false); return true; }); - cont.AddBinding(Keys.DownArrow, (object sender) => { + cont.AddBinding(Keys.DownArrow, (object sender, ConsoleTheme theme) => { ScrollDown(1); - Draw(false); + Draw(theme, false); return true; }); } else { - cont.AddBinding(Keys.Home, (object sender) => { + cont.AddBinding(Keys.Home, (object sender, ConsoleTheme theme) => { ScrollToTop(); return true; }); - cont.AddBinding(Keys.End, (object sender) => { + cont.AddBinding(Keys.End, (object sender, ConsoleTheme theme) => { ScrollToBottom(); return true; }); - cont.AddBinding(Keys.PageUp, (object sender) => { + cont.AddBinding(Keys.PageUp, (object sender, ConsoleTheme theme) => { ScrollUp(); return true; }); - cont.AddBinding(Keys.PageDown, (object sender) => { + cont.AddBinding(Keys.PageDown, (object sender, ConsoleTheme theme) => { ScrollDown(); return true; }); - cont.AddBinding(Keys.UpArrow, (object sender) => { + cont.AddBinding(Keys.UpArrow, (object sender, ConsoleTheme theme) => { ScrollUp(1); return true; }); - cont.AddBinding(Keys.DownArrow, (object sender) => { + cont.AddBinding(Keys.DownArrow, (object sender, ConsoleTheme theme) => { ScrollDown(1); return true; }); @@ -217,8 +219,8 @@ public void AddScrollBindings(ScreenContainer cont, bool drawMore = false) private int topLine; private TextAlign align; private SynchronizedCollection lines = new SynchronizedCollection(); - private Func getBgColor; - private Func getFgColor; + private Func getBgColor; + private Func getFgColor; } /// diff --git a/ConsoleUI/Toolkit/ConsoleTheme.cs b/ConsoleUI/Toolkit/ConsoleTheme.cs index fe00926c71..986327eef9 100644 --- a/ConsoleUI/Toolkit/ConsoleTheme.cs +++ b/ConsoleUI/Toolkit/ConsoleTheme.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace CKAN.ConsoleUI.Toolkit { @@ -9,210 +10,365 @@ namespace CKAN.ConsoleUI.Toolkit { /// public class ConsoleTheme { + /// + /// Background color for splash screen, null for transparent + /// + public ConsoleColor? SplashBg; + + /// + /// Foreground color for splash screen + /// + public ConsoleColor SplashNormalFg; + + /// + /// Foreground color for logo on splash screen + /// + public ConsoleColor SplashAccentFg; + + /// + /// Background color for exit screen + /// + public ConsoleColor? ExitOuterBg; + + /// + /// Background color for info pane of exit screen + /// + public ConsoleColor ExitInnerBg; + + /// + /// Foreground color for normal text on exit screen + /// + public ConsoleColor ExitNormalFg; + + /// + /// Foreground color for highlighted text on exit screen + /// + public ConsoleColor ExitHighlightFg; + + /// + /// Foreground color for links on exit screen + /// + public ConsoleColor ExitLinkFg; + /// /// Background color for normal screen /// - public readonly ConsoleColor MainBg = ConsoleColor.DarkBlue; + public ConsoleColor MainBg; /// /// Background for top header row /// - public readonly ConsoleColor HeaderBg = ConsoleColor.Gray; + public ConsoleColor HeaderBg; /// /// Foreground for top header row /// - public readonly ConsoleColor HeaderFg = ConsoleColor.Black; + public ConsoleColor HeaderFg; /// /// Background for bottom footer row /// - public readonly ConsoleColor FooterBg = ConsoleColor.Gray; + public ConsoleColor FooterBg; /// /// Foreground for vertical separator bars between footer sections /// - public readonly ConsoleColor FooterSeparatorFg = ConsoleColor.DarkGray; + public ConsoleColor FooterSeparatorFg; /// /// Foreground for names of keys in footer /// - public readonly ConsoleColor FooterKeyFg = ConsoleColor.DarkRed; + public ConsoleColor FooterKeyFg; /// /// Foreground for descriptions of key functions in footer /// - public readonly ConsoleColor FooterDescriptionFg = ConsoleColor.Black; + public ConsoleColor FooterDescriptionFg; /// /// Default background for labels /// - public readonly ConsoleColor LabelBg = ConsoleColor.DarkBlue; + public ConsoleColor LabelBg; /// /// Default foreground for labels /// - public readonly ConsoleColor LabelFg = ConsoleColor.Gray; + public ConsoleColor LabelFg; /// /// Foreground for de-emphasized labels /// - public readonly ConsoleColor DimLabelFg = ConsoleColor.DarkCyan; + public ConsoleColor DimLabelFg; /// /// Background for text editing field /// - public readonly ConsoleColor FieldBg = ConsoleColor.Black; + public ConsoleColor FieldBg; /// /// Foreground for ghost text displayed in empty text editing field /// - public readonly ConsoleColor FieldGhostFg = ConsoleColor.DarkGray; + public ConsoleColor FieldGhostFg; /// /// Foreground for text in text editing field with focus /// - public readonly ConsoleColor FieldFocusedFg = ConsoleColor.Cyan; + public ConsoleColor FieldFocusedFg; /// /// Foreground for text in text editing field without focus /// - public readonly ConsoleColor FieldBlurredFg = ConsoleColor.DarkCyan; + public ConsoleColor FieldBlurredFg; /// /// Background for list box header row /// - public readonly ConsoleColor ListBoxHeaderBg = ConsoleColor.Gray; + public ConsoleColor ListBoxHeaderBg; /// /// Foreground for list box header row /// - public readonly ConsoleColor ListBoxHeaderFg = ConsoleColor.Black; + public ConsoleColor ListBoxHeaderFg; /// /// Background for list box data row when not selected /// - public readonly ConsoleColor ListBoxUnselectedBg = ConsoleColor.DarkCyan; + public ConsoleColor ListBoxUnselectedBg; /// /// Foreground for list box data row when not selected /// - public readonly ConsoleColor ListBoxUnselectedFg = ConsoleColor.Black; + public ConsoleColor ListBoxUnselectedFg; /// /// Background for list box selected row /// - public readonly ConsoleColor ListBoxSelectedBg = ConsoleColor.DarkGreen; + public ConsoleColor ListBoxSelectedBg; /// /// Foreground for list box selected row /// - public readonly ConsoleColor ListBoxSelectedFg = ConsoleColor.White; + public ConsoleColor ListBoxSelectedFg; /// /// Background for scroll bars /// - public readonly ConsoleColor ScrollBarBg = ConsoleColor.DarkBlue; + public ConsoleColor ScrollBarBg; /// /// Foreground for scroll bars /// - public readonly ConsoleColor ScrollBarFg = ConsoleColor.DarkCyan; + public ConsoleColor ScrollBarFg; /// /// Background for popup menus /// - public readonly ConsoleColor MenuBg = ConsoleColor.Gray; + public ConsoleColor MenuBg; /// /// Foreground for popup menus /// - public readonly ConsoleColor MenuFg = ConsoleColor.Black; + public ConsoleColor MenuFg; /// /// Foreground for disabled popup menu options /// - public readonly ConsoleColor MenuDisabledFg = ConsoleColor.DarkGray; + public ConsoleColor MenuDisabledFg; /// /// Background for selected menu option /// - public readonly ConsoleColor MenuSelectedBg = ConsoleColor.DarkGreen; + public ConsoleColor MenuSelectedBg; /// /// Foreground for text indicating registry was updated recently /// - public readonly ConsoleColor RegistryUpToDate = ConsoleColor.DarkGray; + public ConsoleColor RegistryUpToDate; /// /// Foreground for text indicating registry was updated a while ago /// - public readonly ConsoleColor RegistryStale = ConsoleColor.Yellow; + public ConsoleColor RegistryStale; /// /// Foreground for text indicating registry was updated dangerously long ago /// - public readonly ConsoleColor RegistryVeryStale = ConsoleColor.Red; + public ConsoleColor RegistryVeryStale; /// /// Background for popup dialogs /// - public readonly ConsoleColor PopupBg = ConsoleColor.Gray; + public ConsoleColor PopupBg; /// /// Foreground for popup dialog text /// - public readonly ConsoleColor PopupFg = ConsoleColor.Black; + public ConsoleColor PopupFg; /// /// Foreground for popup dialog outlines /// - public readonly ConsoleColor PopupOutlineFg = ConsoleColor.White; + public ConsoleColor PopupOutlineFg; /// /// Color for shadow drawn to bottom and right of popup dialogs /// - public readonly ConsoleColor PopupShadow = ConsoleColor.Black; + public ConsoleColor? PopupShadow; /// /// Background for buttons /// - public readonly ConsoleColor PopupButtonBg = ConsoleColor.DarkGreen; + public ConsoleColor PopupButtonBg; /// /// Foreground for buttons without focus /// - public readonly ConsoleColor PopupButtonFg = ConsoleColor.Black; + public ConsoleColor PopupButtonFg; /// /// Foreground for buttons with focus /// - public readonly ConsoleColor PopupButtonSelectedFg = ConsoleColor.Cyan; + public ConsoleColor PopupButtonSelectedFg; /// /// Color for shadow drawn to bottom and right of buttons /// - public readonly ConsoleColor PopupButtonShadow = ConsoleColor.Black; + public ConsoleColor? PopupButtonShadow; /// /// Default background for multi line text box /// - public readonly ConsoleColor TextBoxBg = ConsoleColor.DarkCyan; + public ConsoleColor TextBoxBg; /// /// Default foreground for multi line text box /// - public readonly ConsoleColor TextBoxFg = ConsoleColor.Yellow; + public ConsoleColor TextBoxFg; /// /// Background for non-completed part of progress bars /// - public readonly ConsoleColor ProgressBarBg = ConsoleColor.DarkCyan; + public ConsoleColor ProgressBarBg; /// /// Foreground for non-completed part of progress bars /// - public readonly ConsoleColor ProgressBarFg = ConsoleColor.Black; + public ConsoleColor ProgressBarFg; /// /// Background for completed part of progress bars /// - public readonly ConsoleColor ProgressBarHighlightBg = ConsoleColor.DarkGreen; + public ConsoleColor ProgressBarHighlightBg; /// /// Foreground for completed part of progress bars /// - public readonly ConsoleColor ProgressBarHighlightFg = ConsoleColor.Yellow; + public ConsoleColor ProgressBarHighlightFg; /// /// Foreground for normal box frames /// - public readonly ConsoleColor NormalFrameFg = ConsoleColor.Gray; + public ConsoleColor NormalFrameFg; /// /// Foreground for active/highlighted box frames /// - public readonly ConsoleColor ActiveFrameFg = ConsoleColor.White; + public ConsoleColor ActiveFrameFg; /// /// Foreground for important/abnormal box frames /// - public readonly ConsoleColor AlertFrameFg = ConsoleColor.Yellow; - - /// - /// Singleton instance for current theme. - /// Default values are as per above. - /// - public static ConsoleTheme Current = new ConsoleTheme(); - - private ConsoleTheme() { } + public ConsoleColor AlertFrameFg; + + /// + /// Available themes + /// + public static readonly Dictionary Themes = new Dictionary() { + { + "default", + new ConsoleTheme() { + SplashBg = null, + SplashNormalFg = ConsoleColor.Gray, + SplashAccentFg = ConsoleColor.Blue, + ExitOuterBg = ConsoleColor.Black, + ExitInnerBg = ConsoleColor.DarkRed, + ExitNormalFg = ConsoleColor.Yellow, + ExitHighlightFg = ConsoleColor.White, + ExitLinkFg = ConsoleColor.Cyan, + MainBg = ConsoleColor.DarkBlue, + HeaderBg = ConsoleColor.Gray, + HeaderFg = ConsoleColor.Black, + FooterBg = ConsoleColor.Gray, + FooterSeparatorFg = ConsoleColor.DarkGray, + FooterKeyFg = ConsoleColor.DarkRed, + FooterDescriptionFg = ConsoleColor.Black, + LabelBg = ConsoleColor.DarkBlue, + LabelFg = ConsoleColor.Gray, + DimLabelFg = ConsoleColor.DarkCyan, + FieldBg = ConsoleColor.Black, + FieldGhostFg = ConsoleColor.DarkGray, + FieldFocusedFg = ConsoleColor.Cyan, + FieldBlurredFg = ConsoleColor.DarkCyan, + ListBoxHeaderBg = ConsoleColor.Gray, + ListBoxHeaderFg = ConsoleColor.Black, + ListBoxUnselectedBg = ConsoleColor.DarkCyan, + ListBoxUnselectedFg = ConsoleColor.Black, + ListBoxSelectedBg = ConsoleColor.DarkGreen, + ListBoxSelectedFg = ConsoleColor.White, + ScrollBarBg = ConsoleColor.DarkBlue, + ScrollBarFg = ConsoleColor.DarkCyan, + MenuBg = ConsoleColor.Gray, + MenuFg = ConsoleColor.Black, + MenuDisabledFg = ConsoleColor.DarkGray, + MenuSelectedBg = ConsoleColor.DarkGreen, + RegistryUpToDate = ConsoleColor.DarkGray, + RegistryStale = ConsoleColor.Yellow, + RegistryVeryStale = ConsoleColor.Red, + PopupBg = ConsoleColor.Gray, + PopupFg = ConsoleColor.Black, + PopupOutlineFg = ConsoleColor.White, + PopupShadow = ConsoleColor.Black, + PopupButtonBg = ConsoleColor.DarkGreen, + PopupButtonFg = ConsoleColor.Black, + PopupButtonSelectedFg = ConsoleColor.Cyan, + PopupButtonShadow = ConsoleColor.Black, + TextBoxBg = ConsoleColor.DarkCyan, + TextBoxFg = ConsoleColor.Yellow, + ProgressBarBg = ConsoleColor.DarkCyan, + ProgressBarFg = ConsoleColor.Black, + ProgressBarHighlightBg = ConsoleColor.DarkGreen, + ProgressBarHighlightFg = ConsoleColor.Yellow, + NormalFrameFg = ConsoleColor.Gray, + ActiveFrameFg = ConsoleColor.White, + AlertFrameFg = ConsoleColor.Yellow, + } + }, { + "dark", + new ConsoleTheme() { + SplashBg = ConsoleColor.Black, + SplashNormalFg = ConsoleColor.DarkGreen, + SplashAccentFg = ConsoleColor.Green, + ExitOuterBg = null, + ExitInnerBg = ConsoleColor.Black, + ExitNormalFg = ConsoleColor.DarkGreen, + ExitHighlightFg = ConsoleColor.Green, + ExitLinkFg = ConsoleColor.Green, + MainBg = ConsoleColor.Black, + HeaderBg = ConsoleColor.DarkGreen, + HeaderFg = ConsoleColor.Black, + FooterBg = ConsoleColor.DarkGreen, + FooterSeparatorFg = ConsoleColor.Black, + FooterKeyFg = ConsoleColor.Green, + FooterDescriptionFg = ConsoleColor.Black, + LabelBg = ConsoleColor.Black, + LabelFg = ConsoleColor.DarkGreen, + DimLabelFg = ConsoleColor.DarkGreen, + FieldBg = ConsoleColor.Black, + FieldGhostFg = ConsoleColor.DarkGreen, + FieldFocusedFg = ConsoleColor.Green, + FieldBlurredFg = ConsoleColor.DarkGreen, + ListBoxHeaderBg = ConsoleColor.DarkGreen, + ListBoxHeaderFg = ConsoleColor.Black, + ListBoxUnselectedBg = ConsoleColor.Black, + ListBoxUnselectedFg = ConsoleColor.DarkGreen, + ListBoxSelectedBg = ConsoleColor.Black, + ListBoxSelectedFg = ConsoleColor.Green, + ScrollBarBg = ConsoleColor.Black, + ScrollBarFg = ConsoleColor.DarkGreen, + MenuBg = ConsoleColor.DarkGreen, + MenuFg = ConsoleColor.Black, + MenuDisabledFg = ConsoleColor.Black, + MenuSelectedBg = ConsoleColor.Green, + RegistryUpToDate = ConsoleColor.DarkGreen, + RegistryStale = ConsoleColor.Green, + RegistryVeryStale = ConsoleColor.Green, + PopupBg = ConsoleColor.Black, + PopupFg = ConsoleColor.Green, + PopupOutlineFg = ConsoleColor.Green, + PopupShadow = null, + PopupButtonBg = ConsoleColor.DarkGreen, + PopupButtonFg = ConsoleColor.Black, + PopupButtonSelectedFg = ConsoleColor.Green, + PopupButtonShadow = null, + TextBoxBg = ConsoleColor.Black, + TextBoxFg = ConsoleColor.DarkGreen, + ProgressBarBg = ConsoleColor.Black, + ProgressBarFg = ConsoleColor.DarkGreen, + ProgressBarHighlightBg = ConsoleColor.DarkGreen, + ProgressBarHighlightFg = ConsoleColor.Black, + NormalFrameFg = ConsoleColor.DarkGreen, + ActiveFrameFg = ConsoleColor.Green, + AlertFrameFg = ConsoleColor.Green, + } + } + }; } } diff --git a/ConsoleUI/Toolkit/ScreenContainer.cs b/ConsoleUI/Toolkit/ScreenContainer.cs index d7773ca41d..a15c7de74f 100644 --- a/ConsoleUI/Toolkit/ScreenContainer.cs +++ b/ConsoleUI/Toolkit/ScreenContainer.cs @@ -14,9 +14,9 @@ public abstract class ScreenContainer { /// protected ScreenContainer() { - AddBinding(Keys.CtrlL, (object sender) => { + AddBinding(Keys.CtrlL, (object sender, ConsoleTheme theme) => { // Just redraw everything and keep running - DrawBackground(); + DrawBackground(theme); return true; }); } @@ -24,10 +24,11 @@ protected ScreenContainer() /// /// Draw the contained screen objects and manage their interaction /// + /// The visual theme to use to draw the dialog /// Logic to drive the screen, default is normal user interaction - public virtual void Run(Action process = null) + public virtual void Run(ConsoleTheme theme, Action process = null) { - DrawBackground(); + DrawBackground(theme); if (process == null) { // This should be a simple default parameter, but C# has trouble @@ -36,11 +37,11 @@ public virtual void Run(Action process = null) } else { // Other classes can't call Draw directly, so do it for them once. // Would be nice to make this cleaner somehow. - Draw(); + Draw(theme); } // Run the actual logic for the container - process(); + process(theme); ClearBackground(); } @@ -58,7 +59,7 @@ protected void AddObject(ScreenObject so) /// /// Delegate type for key bindings /// - public delegate bool KeyAction(object sender); + public delegate bool KeyAction(object sender, ConsoleTheme theme); /// /// Bind an action to a key @@ -93,7 +94,7 @@ public void AddTip(string key, string descrip, Func displayIf = null) /// Called once at the beginning and then again later if we need to reset the display. /// NOT called every tick, to reduce flickering. /// - protected virtual void DrawBackground() { } + protected virtual void DrawBackground(ConsoleTheme theme) { } /// /// Reset the display, called when closing it. @@ -104,15 +105,15 @@ protected virtual void ClearBackground() { } /// Draw all the contained ScreenObjects. /// Also places the cursor where it should be. /// - protected void Draw() + protected void Draw(ConsoleTheme theme) { lock (screenLock) { Console.CursorVisible = false; - DrawFooter(); + DrawFooter(theme); for (int i = 0; i < objects.Count; ++i) { - objects[i].Draw(i == focusIndex); + objects[i].Draw(theme, i == focusIndex); } if (objects.Count > 0 @@ -134,19 +135,19 @@ protected void Draw() /// then the bindings of the focused ScreenObject. /// Stops when 'done' is true. /// - protected void Interact() + protected void Interact(ConsoleTheme theme) { focusIndex = -1; Blur(null, true); do { - Draw(); + Draw(theme); ConsoleKeyInfo k = Console.ReadKey(true); if (bindings.ContainsKey(k)) { - done = !bindings[k](this); + done = !bindings[k](this, theme); } else if (objects.Count > 0) { if (objects[focusIndex].Bindings.ContainsKey(k)) { - done = !objects[focusIndex].Bindings[k](this); + done = !objects[focusIndex].Bindings[k](this, theme); } else { objects[focusIndex].OnKeyPress(k); } @@ -183,10 +184,10 @@ protected void SetFocus(ScreenObject so) } } - private void DrawFooter() + private void DrawFooter(ConsoleTheme theme) { Console.SetCursorPosition(0, Console.WindowHeight - 1); - Console.BackgroundColor = ConsoleTheme.Current.FooterBg; + Console.BackgroundColor = theme.FooterBg; Console.Write(" "); var tipLists = new List>() { tips }; if (objects.Count > 0) { @@ -203,12 +204,12 @@ private void DrawFooter() if (first) { first = false; } else { - Console.ForegroundColor = ConsoleTheme.Current.FooterSeparatorFg; + Console.ForegroundColor = theme.FooterSeparatorFg; Console.Write(tipSeparator); } - Console.ForegroundColor = ConsoleTheme.Current.FooterKeyFg; + Console.ForegroundColor = theme.FooterKeyFg; Console.Write(tipList[i].Key); - Console.ForegroundColor = ConsoleTheme.Current.FooterDescriptionFg; + Console.ForegroundColor = theme.FooterDescriptionFg; string remainder; if (tipList[i].Key == tipList[i].Description.Substring(0, 1)) { remainder = tipList[i].Description.Substring(1); @@ -246,7 +247,7 @@ private void Blur(ScreenObject source, bool forward) } while (!objects[focusIndex].Focusable()); } } - + private bool done = false; private List objects = new List(); diff --git a/ConsoleUI/Toolkit/ScreenObject.cs b/ConsoleUI/Toolkit/ScreenObject.cs index 8174f848e2..b466b53f42 100644 --- a/ConsoleUI/Toolkit/ScreenObject.cs +++ b/ConsoleUI/Toolkit/ScreenObject.cs @@ -106,14 +106,15 @@ public void AddTip(string key, string descrip, Func displayIf = null) /// /// Draw a scrollbar for scrollable screen objects /// + /// The visual theme to use to draw the dialog /// X coordinate of scrollbar /// Y coordinate of top of scrollbar /// Y coordinate of bottom of scrollbar /// Y coordinate of the box indicating how scrolled the bar is - protected void DrawScrollbar(int r, int t, int b, int dragRow) + protected void DrawScrollbar(ConsoleTheme theme, int r, int t, int b, int dragRow) { - Console.BackgroundColor = ConsoleTheme.Current.ScrollBarBg; - Console.ForegroundColor = ConsoleTheme.Current.ScrollBarFg; + Console.BackgroundColor = theme.ScrollBarBg; + Console.ForegroundColor = theme.ScrollBarFg; for (int y = t; y <= b; ++y) { Console.SetCursorPosition(r, y); if (y <= t) { @@ -148,8 +149,9 @@ protected void DrawScrollbar(int r, int t, int b, int dragRow) /// /// Draw the UI element /// + /// The visual theme to use to draw the dialog /// If true, draw with focus, else draw without focused - public abstract void Draw(bool focused); + public abstract void Draw(ConsoleTheme theme, bool focused); /// /// Return whether the UI element can accept focus diff --git a/Netkan/Validators/VrefValidator.cs b/Netkan/Validators/VrefValidator.cs index edc5dcd9c5..2efb42718c 100644 --- a/Netkan/Validators/VrefValidator.cs +++ b/Netkan/Validators/VrefValidator.cs @@ -43,7 +43,7 @@ public void Validate(Metadata metadata) var avc = _moduleService.GetInternalAvc(mod, file, "."); hasVersionFile = (avc != null); } - catch (BadMetadataKraken k) + catch (BadMetadataKraken) { // This means the install stanzas don't match any files. // That's not our problem; someone else will report it.