Skip to content

Instantly share code, notes, and snippets.

@krypt-lynx
Last active June 18, 2022 17:56
Show Gist options
  • Save krypt-lynx/5b34d7e29bc56ffe98179d02090e4f53 to your computer and use it in GitHub Desktop.
Save krypt-lynx/5b34d7e29bc56ffe98179d02090e4f53 to your computer and use it in GitHub Desktop.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VRage.Game.ModAPI.Ingame;
namespace Script
{
#region ingame script start
public enum WordWrapOptions
{
None = 0,
Overflow = 1,
SplitWords = 2,
NewLineExtra = 4,
Default = None
}
public interface IFontDataProvider
{
int Width(char ch);
int Width(string str, char lead = '\0');
int Height();
int LetterSpacing(char left, char right);
}
public class StringUtils
{
public StringUtils(IFontDataProvider dataProvider)
{
this.dataProvider = dataProvider;
}
IFontDataProvider dataProvider = null;
public List<string> Wrap(string str, int width, WordWrapOptions options = WordWrapOptions.Default)
{
int end;
return Wrap(str, x => width, 0, out end, options);
}
public List<string> Wrap(string str, Func<int, int> width, WordWrapOptions options = WordWrapOptions.Default)
{
int end;
return Wrap(str, width, 0, out end, options);
}
public List<string> Wrap(string str, Func<int, int> width, int start, out int end, WordWrapOptions options = WordWrapOptions.Default)
{
List<string> lines = new List<string>();
bool allowClipping = (options | WordWrapOptions.Overflow) == options;
bool splitWords = (options | WordWrapOptions.SplitWords) == options;
bool newLineExtra = (options | WordWrapOptions.NewLineExtra) == options;
StringBuilder line = new StringBuilder();
StringBuilder candidate = new StringBuilder();
int lWidth = width(lines.Count);
if (lWidth == -1)
{
end = start;
return lines;
}
int cWidth = 0;
char left = '\0';
char[] chars = str.ToCharArray();
int i = start;
int imax = chars.Length;
for (; i < imax; i++)
{
char ch = chars[i];
int delta = dataProvider.LetterSpacing(left, ch) + dataProvider.Width(ch);
if (ch == '\n')
{
// New line:
// Finishing text line
// If 'newLineExtra': Adding extra line if text line was not empty
line.Append(candidate);
lines.Add(line.ToString());
if (newLineExtra && line.Length > 0)
{
lines.Add("");
}
candidate.Clear();
cWidth = 0;
line.Clear();
lWidth = width(lines.Count);
if (lWidth == -1)
{
goto loop_break;
}
}
else if (ch == '\r')
{
// ignoting 'caret return' characters
}
else if (splitWords || !char.IsWhiteSpace(ch))
{
// building 'candidate' until there is space for it
// starting new line in case if 'candidate' becoming too long
// inserting is as in case if already at new line
if (cWidth + delta > lWidth)
{
if (lWidth < width(lines.Count))
{
lines.Add(line.ToString());
line.Clear();
lWidth = width(lines.Count);
if (lWidth == -1)
{
goto loop_break;
}
}
if (
(cWidth + delta > width(lines.Count)) &&
!(allowClipping && candidate.Length == 0)
)
{
if (candidate.Length == 0)
{
goto loop_break;
}
line.Append(candidate);
lines.Add(line.ToString());
line.Clear();
lWidth = width(lines.Count);
if (lWidth == -1)
{
goto loop_break;
}
candidate.Clear();
candidate.Append(ch);
cWidth = delta;
}
else
{
cWidth += delta;
candidate.Append(ch);
}
}
else
{
cWidth += delta;
candidate.Append(ch);
}
}
else
{
// insering candidate at current line
// adding whitespace if can, staring new line if can't
line.Append(candidate);
lWidth -= cWidth;
candidate.Clear();
cWidth = 0;
if (lWidth <= delta)
{
lines.Add(line.ToString());
line.Clear();
lWidth = width(lines.Count);
if (lWidth == -1)
{
goto loop_break;
}
}
else
{
lWidth -= delta;
line.Append(ch);
}
}
}
// appending tail
if (candidate.Length > 0)
{
line.Append(candidate);
}
if (line.Length > 0 || lines.Count == 0)
{
lines.Add(line.ToString());
}
loop_break:
end = i;
return lines;
}
}
class DebugFontDataProvider : IFontDataProvider
{
static string cRef =
"\n\n\n\n\n\n'|¦ˉ‘’‚\nј\n !I`ijl ¡¨¯´¸ÌÍÎÏìíîïĨĩĪīĮįİıĵĺļľłˆˇ˘˙˚˛˜˝ІЇії‹›∙\n" +
"(),.1:;[]ft{}·ţťŧț\n\"-rª­ºŀŕŗř\n*²³¹\n\\°“”„\nґ\n/ijтэє\nL_vx«»ĹĻĽĿŁГгзлхчҐ–" +
"•\n7?Jcz¢¿çćĉċčĴźżžЃЈЧавийнопсъьѓѕќ\n3FKTabdeghknopqsuy£µÝàáâãäåèéêëðñòóôõö" +
"øùúûüýþÿāăąďđēĕėęěĝğġģĥħĶķńņňʼnōŏőśŝşšŢŤŦũūŭůűųŶŷŸșȚЎЗКЛбдекруцяёђћўџ\n+<=>E" +
"^~¬±¶ÈÉÊË×÷ĒĔĖĘĚЄЏЕНЭ−\n#0245689CXZ¤¥ÇßĆĈĊČŹŻŽƒЁЌАБВДИЙПРСТУХЬ€\n$&GHPUVY§Ù" +
"ÚÛÜÞĀĜĞĠĢĤĦŨŪŬŮŰŲОФЦЪЯжы†‡\nABDNOQRSÀÁÂÃÄÅÐÑÒÓÔÕÖØĂĄĎĐŃŅŇŌŎŐŔŖŘŚŜŞŠȘЅЊЖф□\n" +
"љ\nю\n%IJЫ\n@©®мшњ\nMМШ\nmw¼ŵЮщ\n¾æœЉ\n½Щ\n™\nWÆŒŴ—…‰\n\n\n\n\n\n\n\n" +
"\n\n";
static string kRef =
"\nЖв?ж?\nъв>\nьв>\nҐ,?-?.?‚?„?…?–?—?š>œ>à>á>â>ã>ä>å>æ>ç>è>é>ê>ë>ð>ñ?ò>ó>ô>õ" +
">ö>ø>ù?ú?û?ü?ž?ā>ă>ą>ć>ĉ>č>ď>đ>ě>ē>ĕ>ę>ĝ>ğ>ń?ň?ō>ŏ>ŕ?ř?ś>ŝ>ş>ș>ũ?ū?ŭ?ů?ų?ŵ?" +
"ź?Ц>Ш>Ы?Ю?б>в?ж?н>";
static Dictionary<char, int> cW;
static Dictionary<char, Dictionary<char, int>> kP;
public DebugFontDataProvider()
{
cW = new Dictionary<char, int>();
int w = 0;
foreach (char c in cRef)
{
if (c == '\n')
w++;
else
cW[c] = w;
}
kP = new Dictionary<char, Dictionary<char, int>>();
Dictionary<char, int> cur = null;
for (var e = ((IList<char>)kRef.ToCharArray()).GetEnumerator(); e.MoveNext();)
{
char c1 = e.Current;
e.MoveNext();
char c2 = e.Current;
if (c1 == '\n')
kP[c2] = cur = new Dictionary<char, int>();
else
cur[c1] = c2 - 64;
}
}
public int Width(char ch)
{
int w;
cW.TryGetValue(ch, out w);
return w;
}
public int Width(string str, char lead = '\0')
{
char lc = lead;
int wd = 0, w;
foreach (var c in str)
{
cW.TryGetValue(c, out w);
wd += w + 1;
if (kP.ContainsKey(lc))
{
kP[lc].TryGetValue(c, out w);
wd += w;
}
lc = c;
}
return wd;
}
public int LetterSpacing(char left, char right)
{
if (kP.ContainsKey(left))
{
int w;
kP[left].TryGetValue(right, out w);
return w + 1;
}
return 1;
}
int SpacingOrZero(char left, char right)
{
if (left == '\0' || right == '\0')
{
return 0;
}
else
{
return LetterSpacing(left, right);
}
}
public int Height()
{
return 37;
}
}
class MonospacedFontDataProvider : IFontDataProvider
{
const int charWidth = 24;
const int lineHeight = 37;
const int letterSpacing = 1;
public int LetterSpacing(char left, char right)
{
return letterSpacing;
}
public int Width(char ch)
{
return charWidth;
}
public int Width(string str, char lead = '\0')
{
return (charWidth + letterSpacing) * str.Length;
}
public int Height()
{
return lineHeight;
}
}
#endregion // ingame script end
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment