#region ================== Namespaces using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; #endregion namespace CodeImp.DoomBuilder.Actions { public class HintsManager { #region ================== Public constants public const string GENERAL = "general"; public const string MULTISELECTION = "multiselection"; #endregion #region ================== Constants private const string HINTS_RESOURCE = "Hints.cfg"; private const string CLASS_MARKER = "class"; private const string GROUP_MARKER = "group"; private const string DEFAULT_HINT = "{\\rtf1 Press {\\b F1} to show help for current editing mode}"; #endregion #region ================== Variables private readonly Dictionary> hints; //> #endregion #region ================== Constructor public HintsManager() { hints = new Dictionary>(StringComparer.Ordinal); } #endregion #region ================== Hints //Hints.cfg is dev-only stuff so bare minimum of boilerplate is present //(e.g. create your Hints.cfg exactly the way it's done in the main project). internal void LoadHints(Assembly asm) { // Find a resource named Hints.cfg string[] resnames = asm.GetManifestResourceNames(); string asmname = asm.GetName().Name.ToLowerInvariant() + "_"; foreach(string rn in resnames) { // Found one? if(rn.EndsWith(HINTS_RESOURCE, StringComparison.OrdinalIgnoreCase)) { string classname = string.Empty; string groupname = string.Empty; List lines = new List(2); // Get a stream from the resource Stream data = asm.GetManifestResourceStream(rn); if(data == null) return; using(StreamReader reader = new StreamReader(data, Encoding.ASCII)) { while(!reader.EndOfStream) lines.Add(reader.ReadLine()); } Dictionary> group = new Dictionary>(StringComparer.Ordinal); foreach(string s in lines) { string line = s.Trim(); if(string.IsNullOrEmpty(line) || line.StartsWith("//")) continue; //class declaration? if(line.StartsWith(CLASS_MARKER)) { if(!string.IsNullOrEmpty(classname)) { hints.Add(asmname + classname, ProcessHints(group)); } classname = line.Substring(6, line.Length - 6); groupname = string.Empty; group.Clear(); continue; } //group declaration? if(line.StartsWith(GROUP_MARKER)) { groupname = line.Substring(6, line.Length - 6); group.Add(groupname, new List()); continue; } //regular lines line = line.Replace("\"", string.Empty).Replace("", "{\\b ").Replace("", "}").Replace("
", "\\par "); //replace action names with keys int start = line.IndexOf(""); while(start != -1) { int end = line.IndexOf(""); string key = line.Substring(start + 3, end - start - 3); line = line.Substring(0, start) + "{\\b " + Action.GetShortcutKeyDesc(key) + "}" + line.Substring(end + 4, line.Length - end - 4); start = line.IndexOf(""); } group[groupname].Add(line); } //add the last class hints.Add(asmname + classname, ProcessHints(group)); return; } } } private static Dictionary ProcessHints(Dictionary> hintsgroup) { var result = new Dictionary(StringComparer.Ordinal); foreach(KeyValuePair> group in hintsgroup) { result.Add(group.Key, "{\\rtf1" + string.Join("\\par\\par ", group.Value.ToArray()) + "}"); } return result; } public void ShowHints(Type type, string groupname) { string fullname = type.Assembly.GetName().Name.ToLowerInvariant() + "_" + type.Name; if(!hints.ContainsKey(fullname) || !hints[fullname].ContainsKey(groupname)) { General.Interface.ShowHints(DEFAULT_HINT); #if DEBUG Console.WriteLine("WARNING: Unable to get hints for class \"" + fullname + "\", group \"" + groupname + "\""); #endif return; } General.Interface.ShowHints(hints[fullname][groupname]); } #endregion #region ================== Utility public static string GetRtfString(string text) { text = text.Replace("", "{\\b ").Replace("", "}").Replace("
", "\\par\\par "); return "{\\rtf1" + text + "}"; } #endregion } }