Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
362 views
in Technique[技术] by (71.8m points)

c# - How to display text with subscripts or superscripts in the Title Bar?

I would like to be able to show subscripted text in the Title Bar of a Windows Form or WPF Window. The reason for this is simple. Our project team has written a molecule editor:

enter image description here

Instead of just displaying its name, 'ACME', we would like to show something like:

ACME - Editing C6H12Cl

where the text is subscripted (and possibly superscripted) and whether the control is shown in a Windows Forms or WPF host.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The original question was asking how to insert a RichTextBox in a Form's Caption, to show a chemical formula.
It could be done, of course: you could take a look at DwmExtendFrameIntoClientArea and the Docs here: Custom Window Frame Using DWM and a number of SO questions.

But it's kind of overshooting, here. There's a simpler alternative: make use of the existing Unicode SubScript symbols (it's an Unicode category) to reproduce the formulas.

These are the base SubScript and SuperScript Unicode CodePoints of the Hindu-Arabic numerals:

char[] subScriptNumbers = {
    'u2080', 'u2081', 'u2082', 'u2083', 'u2084',
    'u2085', 'u2086', 'u2087', 'u2088', 'u2089'
};
char[] superScriptNumbers = {
    'u2070', 'u00B9', 'u00B2', 'u00B3', 'u2074',
    'u2075', 'u2076', 'u2077', 'u2078', 'u2079'
};

As hinted in comments, the simple formula: C6H12Cl can be transformed to C?H??Cl, mapping the numbers to the corresponding Unicode values in the SubScript range. For example:

this.Text = string.Concat("C6H12Cl".Select(c => char.IsDigit(c) ? subScriptNumbers[c-48] : c));

Or, since the SubScript CodePoints are sequential (the SuperScript ones are not):

const int subScriptBase = 0x2080;
string chem = "C6H12Cl";
// Or this.Title, in WPF
this.Text = chem.Aggregate(new StringBuilder(), (sb, c) => 
    sb.Append(char.IsDigit(c) ? (char)(subScriptBase + c - 48) : c)).ToString();

Since it appears that there's someone interested, I propose a slightly more complex parser (which uses the same logic), to produce different kinds of formulas:

The class shown here can convert sequences of SubScript/SuperScript numerals or letters, using a simple notation (similar to the notation of the Markup used by Wikipedia):

SuperScript: [+:symbols]          A[+:12]    => A12  
SubScript:   [-:symbols]          A[-:12]    => A??
Fraction:    [f:symbols/symbols]  A·[f:x/12] => A·????

For example:

string formula = "N[+:(x+2)] · H[+:3] · γLog[-:e] + δ· [f:n11/x]";
// Or this.Text, in WinForms
this.Title = UniSubSup.Parse(formula);

will print:

N???2?·H3·γLog? + δ·?11??

Note1:
When a markup contains spaces, it's skipped: hence [+:(x+2)] is parsed, while [+:(x + 2)] is not (in case these brackets should be ignored).

Note2:
I did not include all the letters because not all fonts support all the CodePoints in the SubScript and SuperScript categories. The Subscript n (u2099), which is relatively common (e.g., Logn), is not available in most of font types (since sub/super Scripting is generated by different means).
Some (very few) Fonts do have these glyphs. WebSites like fileformat.info can provide this information.

public class UniSubSup
{
    const char joiner =       'u200D';
    const char nonJoiner =    'u200C';
    const char fraction =     'u2044';
    const char solidusShort = 'u0337';
    const char solidusLong =  'u0338';

    protected internal static Dictionary<string, Func<string, string>> actions =
        new Dictionary<string, Func<string, string>>()
        {
            ["-"] = (s) => sub(s),
            ["+"] = (s) => sup(s),
            ["f"] = (s) => fract(s),
        };

    internal static string sub(string s) => 
        s.Aggregate(new StringBuilder(), (sb, c) => sb.Append(subScripts[c])).ToString();

    internal static string sup(string s) => 
        s.Aggregate(new StringBuilder(), (sb, c) => sb.Append(superScripts[c])).ToString();

    internal static string fract(string str)
    {
        var sb = new StringBuilder();
        var parts = str.Split('/');
        parts[0].Aggregate(sb, (s, c) => sb.Append(superScripts[c]));
        sb.Append(fraction);
        parts[1].Aggregate(sb, (s, c) => sb.Append(subScripts[c]));
        return sb.ToString();
    }

    static RegexOptions options = RegexOptions.Singleline | RegexOptions.Compiled;

    public static string Parse(string input)
    {
        string pattern = @"[(D{1}):(S/?S*?)]";
        var matches = Regex.Matches(input, pattern, options);
        var result = new StringBuilder(input);
        foreach (Match m in matches) 
            result = result.Replace(m.Value, actions[m.Groups[1].Value](m.Groups[2].Value));
        }
        return result.ToString();
    }

    internal static Dictionary<char, char> superScripts = new Dictionary<char, char>()
    {
        ['0'] = 'u2070', ['1'] = 'u00B9', ['2'] = 'u00B2', ['3'] = 'u00B3',
        ['4'] = 'u2074', ['5'] = 'u2075', ['6'] = 'u2076', ['7'] = 'u2077',
        ['8'] = 'u2078', ['9'] = 'u2079',
        ['+'] = 'u207A', ['-'] = 'u207B', ['='] = 'u207C',
        ['('] = 'u207D', [')'] = 'u207E',
        ['e'] = 'u1D49', ['n'] = 'u207F', ['x'] = 'u02E3' 
    };

    internal static Dictionary<char, char> subScripts = new Dictionary<char, char>()
    {
        ['0'] = 'u2080', ['1'] = 'u2081', ['2'] = 'u2082', ['3'] = 'u2083',
        ['4'] = 'u2084', ['5'] = 'u2085', ['6'] = 'u2086', ['7'] = 'u2087',
        ['8'] = 'u2088', ['9'] = 'u2089',
        ['+'] = 'u208A', ['-'] = 'u208B', ['='] = 'u208C',
        ['('] = 'u208D', [')'] = 'u208E', ['/'] = 'u2044',
        ['e'] = 'u2091', ['n'] = 'u2099', ['x'] = 'u2093'
    };
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...