Skip to content

Commit 789b861

Browse files
authored
Make blinking Placeholder's Nucleus and ForeColor customizable in both CaretStates (#167)
* Make blinking Placeholder's Nucleus and ForeColor customizable in both CaretStates * Renaming of Placeholder-related variables + refactor (#167) - Rename Placholder's "ForeColor" to "Color". - Use property initializer GlyphInfo.Foreground. - Restore "readonly field" instead of property getter for LaTeXSettings.Dummy. - Use the name parts "Resting" and "Active" in the placeholder setting names (instead of "Hiding" and "FullShow" which are related to the caret but do not fit a blinking placeholder). - Use variable name "placeholder" instead of "ph". * Add unit tests for customizable placeholder (#167) * Disable parallelization of customizable placeholder unit tests Also: verify more in LaTeXSettings_Placeholder_IsNewInstance. * Add unit test AllCustomizablePlaceholderPropertiesAreResetOnCaretVisible (#167) Also: in the MockTests class, verify that AttributedGlyphRun sets the GlyphInfo.Foreground to null (default color). * Unit test CustomizedPlaceholderBlinks: test complete cycle * Fix failing unit test CaretTimerResetsOnKeyPress * Use Assert.All instead of Assert.True(enumerable.All(pred)) * Revert "Fix failing unit test CaretTimerResetsOnKeyPress" This reverts commit 9925952. * Replace Assert.NotEqual + replace hardcoded strings by constants * Refactoring and cleaning (of customizable placeholder tests and more) * Placeholder tests: use Assert.NotSame and async Task
1 parent 43b209b commit 789b861

File tree

7 files changed

+131
-25
lines changed

7 files changed

+131
-25
lines changed

CSharpMath.CoreTests/MockTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,17 @@ public void TestGlyphBoundsWithoutM() {
1212
var font = new TestFont(10);
1313
var provider = TestGlyphBoundsProvider.Instance;
1414
var glyphRun = new AttributedGlyphRun<TestFont, TGlyph>(hello, hello, font);
15+
Assert.All(glyphRun.GlyphInfos, glyphInfo => Assert.Null(glyphInfo.Foreground));
1516
var width = provider.GetTypographicWidth(font, glyphRun);
1617
Approximately.Equal(width, 25, 0.01);
1718
}
18-
1919
[Fact]
2020
public void TestGlyphBoundsWithM() {
2121
string america = "America";
2222
var font = new TestFont(10);
2323
var provider = TestGlyphBoundsProvider.Instance;
2424
var glyphRun = new AttributedGlyphRun<TestFont, TGlyph>(america, america, font);
25+
Assert.All(glyphRun.GlyphInfos, glyphInfo => Assert.Null(glyphInfo.Foreground));
2526
var width = provider.GetTypographicWidth(font, glyphRun);
2627
Approximately.Equal(width, 40, 0.01);
2728
}

CSharpMath.Editor.Tests/CaretTests.cs

Lines changed: 110 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using System;
2-
using System.Collections.Generic;
32
using System.Threading.Tasks;
3+
using CSharpMath.Atom;
44
using CSharpMath.CoreTests.FrontEnd;
55
using Xunit;
66

@@ -32,18 +32,18 @@ public async Task Test() {
3232
var outer = Assert.IsType<Atom.Atoms.Placeholder>(Assert.Single(keyboard.MathList));
3333
var inner = Assert.IsType<Atom.Atoms.Placeholder>(Assert.Single(outer.Superscript));
3434
Assert.Equal(MathKeyboardCaretState.ShownThroughPlaceholder, keyboard.CaretState);
35-
Assert.Equal("\u25A1", outer.Nucleus);
36-
Assert.Equal("\u25A0", inner.Nucleus);
35+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, outer.Nucleus);
36+
Assert.Equal(DefaultPlaceholderSettings.ActiveNucleus, inner.Nucleus);
3737

3838
await Task.Delay((int)MathKeyboard<TestFont, char>.DefaultBlinkMilliseconds + CaretBlinks.MillisecondBuffer);
3939
Assert.Equal(MathKeyboardCaretState.TemporarilyHidden, keyboard.CaretState);
40-
Assert.Equal("\u25A1", outer.Nucleus);
41-
Assert.Equal("\u25A1", inner.Nucleus);
40+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, outer.Nucleus);
41+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, inner.Nucleus);
4242

4343
await Task.Delay((int)MathKeyboard<TestFont, char>.DefaultBlinkMilliseconds + CaretBlinks.MillisecondBuffer);
4444
Assert.Equal(MathKeyboardCaretState.ShownThroughPlaceholder, keyboard.CaretState);
45-
Assert.Equal("\u25A1", outer.Nucleus);
46-
Assert.Equal("\u25A0", inner.Nucleus);
45+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, outer.Nucleus);
46+
Assert.Equal(DefaultPlaceholderSettings.ActiveNucleus, inner.Nucleus);
4747
}
4848
}
4949
public class CaretMovesWithPlaceholder {
@@ -58,20 +58,20 @@ public async Task Test() {
5858
var outer = Assert.IsType<Atom.Atoms.Placeholder>(Assert.Single(keyboard.MathList));
5959
var inner = Assert.IsType<Atom.Atoms.Placeholder>(Assert.Single(outer.Subscript));
6060
Assert.Equal(MathKeyboardCaretState.ShownThroughPlaceholder, keyboard.CaretState);
61-
Assert.Equal("\u25A1", outer.Nucleus);
62-
Assert.Equal("\u25A0", inner.Nucleus);
61+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, outer.Nucleus);
62+
Assert.Equal(DefaultPlaceholderSettings.ActiveNucleus, inner.Nucleus);
6363

6464
await Task.Delay((int)MathKeyboard<TestFont, char>.DefaultBlinkMilliseconds + CaretBlinks.MillisecondBuffer);
6565
Assert.Equal(MathKeyboardCaretState.TemporarilyHidden, keyboard.CaretState);
6666
keyboard.KeyPress(MathKeyboardInput.Left);
6767
Assert.Equal(MathKeyboardCaretState.ShownThroughPlaceholder, keyboard.CaretState);
68-
Assert.Equal("\u25A0", outer.Nucleus);
69-
Assert.Equal("\u25A1", inner.Nucleus);
68+
Assert.Equal(DefaultPlaceholderSettings.ActiveNucleus, outer.Nucleus);
69+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, inner.Nucleus);
7070

7171
Assert.Equal(MathKeyboardCaretState.ShownThroughPlaceholder, keyboard.CaretState);
7272
keyboard.KeyPress(MathKeyboardInput.Right);
73-
Assert.Equal("\u25A1", outer.Nucleus);
74-
Assert.Equal("\u25A0", inner.Nucleus);
73+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, outer.Nucleus);
74+
Assert.Equal(DefaultPlaceholderSettings.ActiveNucleus, inner.Nucleus);
7575
}
7676
}
7777
public class CaretStaysHidden {
@@ -176,4 +176,101 @@ public async Task Test() {
176176
Assert.Equal(MathKeyboardCaretState.Shown, keyboard.CaretState);
177177
}
178178
}
179+
public class DefaultPlaceholderSettings {
180+
public const string ActiveNucleus = "■";
181+
public const string RestingNucleus = "□";
182+
public static readonly System.Drawing.Color? ActiveColor = null;
183+
public static readonly System.Drawing.Color? RestingColor = null;
184+
}
185+
[CollectionDefinition(nameof(NonParallelPlaceholderTests), DisableParallelization = true)]
186+
public class NonParallelPlaceholderTests { }
187+
[Collection(nameof(NonParallelPlaceholderTests))]
188+
public class DefaultPlaceholder {
189+
[Fact]
190+
public void LaTeXSettingsPlaceholderIsNewInstance() {
191+
Assert.NotSame(LaTeXSettings.Placeholder, LaTeXSettings.Placeholder);
192+
// Double check, also verify that its contents are 'fresh':
193+
LaTeXSettings.Placeholder.Nucleus = "x";
194+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, LaTeXSettings.Placeholder.Nucleus);
195+
LaTeXSettings.Placeholder.Color = System.Drawing.Color.Green;
196+
Assert.Equal(DefaultPlaceholderSettings.RestingColor, LaTeXSettings.Placeholder.Color);
197+
}
198+
[Fact]
199+
public void DefaultPlaceholderAppearance() {
200+
Assert.Null(LaTeXSettings.PlaceholderActiveColor);
201+
Assert.Null(LaTeXSettings.PlaceholderRestingColor);
202+
Assert.Equal(DefaultPlaceholderSettings.ActiveNucleus, LaTeXSettings.PlaceholderActiveNucleus);
203+
Assert.Equal(DefaultPlaceholderSettings.RestingNucleus, LaTeXSettings.PlaceholderRestingNucleus);
204+
Assert.Equal(LaTeXSettings.PlaceholderRestingNucleus, LaTeXSettings.Placeholder.Nucleus);
205+
Assert.Equal(LaTeXSettings.PlaceholderRestingColor, LaTeXSettings.Placeholder.Color);
206+
}
207+
}
208+
[Collection(nameof(NonParallelPlaceholderTests))]
209+
public class CustomizablePlaceholder : IDisposable {
210+
public CustomizablePlaceholder() {
211+
LaTeXSettings.PlaceholderActiveNucleus = "😀";
212+
LaTeXSettings.PlaceholderRestingNucleus = "😐";
213+
LaTeXSettings.PlaceholderActiveColor = System.Drawing.Color.Green;
214+
LaTeXSettings.PlaceholderRestingColor = System.Drawing.Color.Blue;
215+
}
216+
public void Dispose() {
217+
LaTeXSettings.PlaceholderActiveNucleus = DefaultPlaceholderSettings.ActiveNucleus;
218+
LaTeXSettings.PlaceholderRestingNucleus = DefaultPlaceholderSettings.RestingNucleus;
219+
LaTeXSettings.PlaceholderActiveColor = DefaultPlaceholderSettings.ActiveColor;
220+
LaTeXSettings.PlaceholderRestingColor = DefaultPlaceholderSettings.RestingColor;
221+
}
222+
[Fact]
223+
public async Task CustomizedPlaceholderBlinks() {
224+
var keyboard = new MathKeyboard<TestFont, char>(TestTypesettingContexts.Instance, new TestFont()) {
225+
CaretState = MathKeyboardCaretState.Shown
226+
};
227+
Assert.Equal(MathKeyboardCaretState.Shown, keyboard.CaretState);
228+
229+
keyboard.KeyPress(MathKeyboardInput.Subscript);
230+
var outer = Assert.IsType<Atom.Atoms.Placeholder>(Assert.Single(keyboard.MathList));
231+
var inner = Assert.IsType<Atom.Atoms.Placeholder>(Assert.Single(outer.Subscript));
232+
Assert.Equal(MathKeyboardCaretState.ShownThroughPlaceholder, keyboard.CaretState);
233+
Assert.Equal("😐", outer.Nucleus);
234+
Assert.Equal(System.Drawing.Color.Blue, outer.Color);
235+
Assert.Equal("😀", inner.Nucleus);
236+
Assert.Equal(System.Drawing.Color.Green, inner.Color);
237+
238+
await Task.Delay((int)MathKeyboard<TestFont, char>.DefaultBlinkMilliseconds + CaretBlinks.MillisecondBuffer);
239+
Assert.Equal(MathKeyboardCaretState.TemporarilyHidden, keyboard.CaretState);
240+
Assert.Equal("😐", outer.Nucleus);
241+
Assert.Equal(System.Drawing.Color.Blue, outer.Color);
242+
Assert.Equal("😐", inner.Nucleus);
243+
Assert.Equal(System.Drawing.Color.Blue, inner.Color);
244+
245+
await Task.Delay((int)MathKeyboard<TestFont, char>.DefaultBlinkMilliseconds + CaretBlinks.MillisecondBuffer);
246+
Assert.Equal(MathKeyboardCaretState.ShownThroughPlaceholder, keyboard.CaretState);
247+
Assert.Equal("😐", outer.Nucleus);
248+
Assert.Equal(System.Drawing.Color.Blue, outer.Color);
249+
Assert.Equal("😀", inner.Nucleus);
250+
Assert.Equal(System.Drawing.Color.Green, inner.Color);
251+
}
252+
[Fact]
253+
public void AllCustomizablePlaceholderPropertiesAreResetOnCaretVisible() {
254+
var keyboard = new MathKeyboard<TestFont, char>(TestTypesettingContexts.Instance, new TestFont()) {
255+
CaretState = MathKeyboardCaretState.Shown
256+
};
257+
Assert.Equal(MathKeyboardCaretState.Shown, keyboard.CaretState);
258+
keyboard.KeyPress(MathKeyboardInput.Subscript);
259+
var outer = Assert.IsType<Atom.Atoms.Placeholder>(Assert.Single(keyboard.MathList));
260+
var inner = Assert.IsType<Atom.Atoms.Placeholder>(Assert.Single(outer.Subscript));
261+
Assert.Equal(MathKeyboardCaretState.ShownThroughPlaceholder, keyboard.CaretState);
262+
263+
keyboard.InsertionIndex = MathListIndex.Level0Index(keyboard.MathList.Count);
264+
Assert.Equal(MathKeyboardCaretState.Shown, keyboard.CaretState);
265+
Assert.Equal(LaTeXSettings.PlaceholderRestingNucleus, outer.Nucleus);
266+
Assert.Equal(LaTeXSettings.PlaceholderRestingColor, outer.Color);
267+
Assert.Equal(LaTeXSettings.PlaceholderRestingNucleus, inner.Nucleus);
268+
Assert.Equal(LaTeXSettings.PlaceholderRestingColor, inner.Color);
269+
}
270+
[Fact]
271+
public void CustomizedPlaceholderGetter() {
272+
Assert.Equal("😐", LaTeXSettings.Placeholder.Nucleus);
273+
Assert.Equal(System.Drawing.Color.Blue, LaTeXSettings.Placeholder.Color);
274+
}
275+
}
179276
}

CSharpMath.Editor/MathKeyboard.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,9 @@ static void ResetPlaceholders(MathList mathList) {
4444
ResetPlaceholders(mathAtom.Superscript);
4545
ResetPlaceholders(mathAtom.Subscript);
4646
switch (mathAtom) {
47-
case Atoms.Placeholder _:
48-
mathAtom.Nucleus = "\u25A1";
47+
case Atoms.Placeholder placeholder:
48+
placeholder.Color = LaTeXSettings.PlaceholderRestingColor;
49+
placeholder.Nucleus = LaTeXSettings.PlaceholderRestingNucleus;
4950
break;
5051
case IMathListContainer container:
5152
foreach (var list in container.InnerLists)
@@ -62,10 +63,10 @@ public MathKeyboardCaretState CaretState {
6263
blinkTimer.Start();
6364
if (value != MathKeyboardCaretState.Hidden &&
6465
MathList.AtomAt(_insertionIndex) is Atoms.Placeholder placeholder)
65-
(placeholder.Nucleus, _caretState) =
66+
(placeholder.Nucleus, placeholder.Color, _caretState) =
6667
value == MathKeyboardCaretState.TemporarilyHidden
67-
? ("\u25A1", MathKeyboardCaretState.TemporarilyHidden)
68-
: ("\u25A0", MathKeyboardCaretState.ShownThroughPlaceholder);
68+
? (LaTeXSettings.PlaceholderRestingNucleus, LaTeXSettings.PlaceholderRestingColor, MathKeyboardCaretState.TemporarilyHidden)
69+
: (LaTeXSettings.PlaceholderActiveNucleus, LaTeXSettings.PlaceholderActiveColor, MathKeyboardCaretState.ShownThroughPlaceholder);
6970
else _caretState = value;
7071
RecreateDisplayFromMathList();
7172
RedrawRequested?.Invoke(this, EventArgs.Empty);

CSharpMath/Atom/Atoms/Placeholder.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
1+
using System.Drawing;
12
namespace CSharpMath.Atom.Atoms {
23
/// <summary>A placeholder for future input</summary>
34
public sealed class Placeholder : MathAtom {
4-
public Placeholder(string nucleus) : base(nucleus) { }
5+
public Color? Color { get; set; }
6+
public Placeholder(string nucleus, Color? color) : base(nucleus) => Color = color;
57
public override bool ScriptsAllowed => true;
68
public new Placeholder Clone(bool finalize) => (Placeholder)base.Clone(finalize);
7-
protected override MathAtom CloneInside(bool finalize) => new Placeholder(Nucleus);
9+
protected override MathAtom CloneInside(bool finalize) => new Placeholder(Nucleus, Color);
810
}
911
}

CSharpMath/Atom/LaTeXSettings.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -320,7 +320,11 @@ public static class LaTeXSettings {
320320
};
321321
public static MathAtom Times => new BinaryOperator("×");
322322
public static MathAtom Divide => new BinaryOperator("÷");
323-
public static MathAtom Placeholder => new Placeholder("\u25A1");
323+
public static Color? PlaceholderRestingColor { get; set; }
324+
public static Color? PlaceholderActiveColor { get; set; }
325+
public static string PlaceholderActiveNucleus { get; set; } = "\u25A0";
326+
public static string PlaceholderRestingNucleus { get; set; } = "\u25A1";
327+
public static Placeholder Placeholder => new Placeholder(PlaceholderRestingNucleus, PlaceholderRestingColor);
324328
public static MathList PlaceholderList => new MathList { Placeholder };
325329

326330
public static AliasBiDictionary<string, FontStyle> FontStyles { get; } =

CSharpMath/Display/AttributedGlyphRun.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using System.Collections.Generic;
2+
using System.Drawing;
23
using System.Linq;
34
using System.Text;
45

@@ -7,9 +8,9 @@ namespace CSharpMath.Display {
78
/// over the whole string. We use KernedGlyph objects instead of Glyphs to
89
/// allow us to set kern on a per-glyph basis.</summary>
910
public class AttributedGlyphRun<TFont, TGlyph> where TFont : FrontEnd.IFont<TGlyph> {
10-
public AttributedGlyphRun(string text, IEnumerable<TGlyph> glyphs, TFont font, bool isPlaceHolder = false) {
11+
public AttributedGlyphRun(string text, IEnumerable<TGlyph> glyphs, TFont font, bool isPlaceHolder = false, Color? color = null) {
1112
Text = new StringBuilder(text);
12-
GlyphInfos = glyphs.Select(g => new GlyphInfo<TGlyph>(g)).ToList();
13+
GlyphInfos = glyphs.Select(g => new GlyphInfo<TGlyph>(g) { Foreground = color }).ToList();
1314
Font = font;
1415
Placeholder = isPlaceHolder;
1516
}

CSharpMath/Display/Typesetter.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -337,7 +337,7 @@ private void CreateDisplayAtoms(List<MathAtom> preprocessedAtoms) {
337337
var nucleusText = atom.Nucleus;
338338
var glyphs = _context.GlyphFinder.FindGlyphs(_font, nucleusText);
339339
var current = new AttributedGlyphRun<TFont, TGlyph>(
340-
nucleusText, glyphs, _font, atom is Placeholder);
340+
nucleusText, glyphs, _font, atom is Placeholder, (atom as Placeholder)?.Color);
341341
_currentLine.AppendGlyphRun(current);
342342
if (_currentLineIndexRange.Location == Range.UndefinedInt)
343343
_currentLineIndexRange = atom.IndexRange;

0 commit comments

Comments
 (0)