mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-01-23 17:43:08 -05:00
fix urls more
This commit is contained in:
parent
fe595a62c9
commit
29c81f5a5e
2 changed files with 69 additions and 92 deletions
|
@ -427,10 +427,9 @@ namespace ClassicalSharp.Gui.Screens {
|
||||||
bool HandlesChatClick(int mouseX, int mouseY) {
|
bool HandlesChatClick(int mouseX, int mouseY) {
|
||||||
string text = normalChat.GetSelected(mouseX, mouseY);
|
string text = normalChat.GetSelected(mouseX, mouseY);
|
||||||
if (text == null) return false;
|
if (text == null) return false;
|
||||||
string url = Utils.StripColours(text);
|
|
||||||
|
|
||||||
if (Utils.IsUrlPrefix(url, 0)) {
|
if (Utils.IsUrlPrefix(text, 0)) {
|
||||||
Overlay overlay = new UrlWarningOverlay(game, url);
|
Overlay overlay = new UrlWarningOverlay(game, text);
|
||||||
game.Gui.ShowOverlay(overlay, false);
|
game.Gui.ShowOverlay(overlay, false);
|
||||||
} else if (game.ClickableChat) {
|
} else if (game.ClickableChat) {
|
||||||
input.Append(text);
|
input.Append(text);
|
||||||
|
|
|
@ -24,6 +24,7 @@ namespace ClassicalSharp.Gui.Widgets {
|
||||||
internal string[] lines;
|
internal string[] lines;
|
||||||
int ElementsCount, defaultHeight;
|
int ElementsCount, defaultHeight;
|
||||||
readonly Font font, underlineFont;
|
readonly Font font, underlineFont;
|
||||||
|
const int prefixLen = 7; // "http://".Length
|
||||||
|
|
||||||
public override void Init() {
|
public override void Init() {
|
||||||
Textures = new Texture[ElementsCount];
|
Textures = new Texture[ElementsCount];
|
||||||
|
@ -143,23 +144,26 @@ namespace ClassicalSharp.Gui.Widgets {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe string GetUrl(int index, int mouseX) {
|
unsafe string GetUrl(int index, int mX) {
|
||||||
Texture tex = Textures[index]; mouseX -= tex.X1;
|
Texture tex = Textures[index]; mX -= tex.X1;
|
||||||
DrawTextArgs args = default(DrawTextArgs);
|
DrawTextArgs args = default(DrawTextArgs);
|
||||||
string text = lines[index];
|
string text = lines[index];
|
||||||
|
if (game.ClassicMode) return null;
|
||||||
|
|
||||||
char* chars = stackalloc char[lines.Length * 96];
|
char* chars = stackalloc char[lines.Length * 96];
|
||||||
Portion* portions = stackalloc Portion[(96 / 7) * 2];
|
Portion* portions = stackalloc Portion[(96 / prefixLen) * 2];
|
||||||
int portionsCount = Reduce(chars, index, portions);
|
int portionsCount = Reduce(chars, index, portions);
|
||||||
|
|
||||||
for (int i = 0, x = 0; i < portionsCount; i++) {
|
for (int i = 0, x = 0; i < portionsCount; i++) {
|
||||||
Portion bit = portions[i];
|
Portion bit = portions[i];
|
||||||
args.Text = text.Substring(bit.Beg, bit.Len);
|
args.Text = text.Substring(bit.LineBeg, bit.LineLen);
|
||||||
args.Font = (bit.ReducedLen & 0x8000) == 0 ? font : underlineFont;
|
args.Font = (bit.Len & 0x8000) == 0 ? font : underlineFont;
|
||||||
|
|
||||||
int width = game.Drawer2D.MeasureSize(ref args).Width;
|
int width = game.Drawer2D.MeasureSize(ref args).Width;
|
||||||
if (args.Font != font && mouseX >= x && mouseX < x + width) {
|
if (args.Font != font && mX >= x && mX < x + width) {
|
||||||
return new string(chars, bit.ReducedBeg, bit.ReducedLen & 0x7FFF);
|
string url = new string(chars, bit.Beg, bit.Len & 0x7FFF);
|
||||||
|
// replace multiline bits
|
||||||
|
return Utils.StripColours(url).Replace("> ", "");
|
||||||
}
|
}
|
||||||
x += width;
|
x += width;
|
||||||
}
|
}
|
||||||
|
@ -202,16 +206,16 @@ namespace ClassicalSharp.Gui.Widgets {
|
||||||
|
|
||||||
unsafe Texture DrawAdvanced(ref DrawTextArgs args, int index, string text) {
|
unsafe Texture DrawAdvanced(ref DrawTextArgs args, int index, string text) {
|
||||||
char* chars = stackalloc char[lines.Length * 96];
|
char* chars = stackalloc char[lines.Length * 96];
|
||||||
Portion* portions = stackalloc Portion[(96 / 7) * 2];
|
Portion* portions = stackalloc Portion[(96 / prefixLen) * 2];
|
||||||
int portionsCount = Reduce(chars, index, portions);
|
int portionsCount = Reduce(chars, index, portions);
|
||||||
|
|
||||||
Size total = Size.Empty;
|
Size total = Size.Empty;
|
||||||
Size* partSizes = stackalloc Size[portionsCount];
|
Size* partSizes = stackalloc Size[portionsCount];
|
||||||
|
|
||||||
for (int i = 0; i < portionsCount; i++) {
|
for (int i = 0; i < portionsCount; i++) {
|
||||||
Portion bit = portions[i];
|
Portion bit = portions[i];
|
||||||
args.Text = text.Substring(bit.Beg, bit.Len);
|
args.Text = text.Substring(bit.LineBeg, bit.LineLen);
|
||||||
args.Font = (bit.ReducedLen & 0x8000) == 0 ? font : underlineFont;
|
args.Font = (bit.Len & 0x8000) == 0 ? font : underlineFont;
|
||||||
|
|
||||||
partSizes[i] = game.Drawer2D.MeasureSize(ref args);
|
partSizes[i] = game.Drawer2D.MeasureSize(ref args);
|
||||||
total.Height = Math.Max(partSizes[i].Height, total.Height);
|
total.Height = Math.Max(partSizes[i].Height, total.Height);
|
||||||
|
@ -226,8 +230,8 @@ namespace ClassicalSharp.Gui.Widgets {
|
||||||
|
|
||||||
for (int i = 0; i < portionsCount; i++) {
|
for (int i = 0; i < portionsCount; i++) {
|
||||||
Portion bit = portions[i];
|
Portion bit = portions[i];
|
||||||
args.Text = text.Substring(bit.Beg, bit.Len);
|
args.Text = text.Substring(bit.LineBeg, bit.LineLen);
|
||||||
args.Font = (bit.ReducedLen & 0x8000) == 0 ? font : underlineFont;
|
args.Font = (bit.Len & 0x8000) == 0 ? font : underlineFont;
|
||||||
|
|
||||||
drawer.DrawText(ref args, x, 0);
|
drawer.DrawText(ref args, x, 0);
|
||||||
x += partSizes[i].Width;
|
x += partSizes[i].Width;
|
||||||
|
@ -238,13 +242,17 @@ namespace ClassicalSharp.Gui.Widgets {
|
||||||
|
|
||||||
unsafe static int NextUrl(char* chars, int i, int len) {
|
unsafe static int NextUrl(char* chars, int i, int len) {
|
||||||
for (; i < len; i++) {
|
for (; i < len; i++) {
|
||||||
if (chars[i] != 'h') continue;
|
if (!(chars[i] == 'h' || chars[i] == '&')) continue;
|
||||||
int left = len - i;
|
int left = len - i;
|
||||||
if (left < 7) return -1; // "http://".Length
|
if (left < prefixLen) return -1; // "http://".Length
|
||||||
|
|
||||||
|
// colour codes at start of URL
|
||||||
int start = i;
|
int start = i;
|
||||||
|
while (left >= 2 && chars[i] == '&') { left -= 2; i += 2; }
|
||||||
|
if (left < prefixLen) continue;
|
||||||
|
|
||||||
// Starts with "http" ?
|
// Starts with "http" ?
|
||||||
if (chars[i + 1] != 't' || chars[i + 2] != 't' || chars[i + 3] != 'p') continue;
|
if (chars[i] != 'h' || chars[i + 1] != 't' || chars[i + 2] != 't' || chars[i + 3] != 'p') continue;
|
||||||
left -= 4; i += 4;
|
left -= 4; i += 4;
|
||||||
|
|
||||||
// And then with "s://" or "://" ?
|
// And then with "s://" or "://" ?
|
||||||
|
@ -254,104 +262,74 @@ namespace ClassicalSharp.Gui.Widgets {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe static int ReduceLine(char* chars, ushort* mappings,
|
unsafe static void Output(Portion bit, int lineBeg, int lineEnd, ref Portion* portions) {
|
||||||
int count, int offset, string line) {
|
if (bit.Beg >= lineEnd || bit.Len == 0) return;
|
||||||
bool lineStart = true;
|
bit.LineBeg = bit.Beg;
|
||||||
for (int i = 0, last = line.Length - 1; i < line.Length;) {
|
bit.LineLen = bit.Len & 0x7FFF;
|
||||||
char cur = line[i];
|
|
||||||
|
|
||||||
// Trim colour codes and "> " line continues
|
|
||||||
if (cur == '&' && i < last && IDrawer2D.ValidColCode(line[i + 1])) {
|
|
||||||
i += 2; continue;
|
|
||||||
}
|
|
||||||
if (cur == '>' && i < last && lineStart && line[i + 1] == ' ') {
|
|
||||||
lineStart = false; i += 2; continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
lineStart = false;
|
|
||||||
chars[count] = cur;
|
|
||||||
mappings[count] = (ushort)(offset + i);
|
|
||||||
i++; count++;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe static void Output(Portion bit, ushort* mappings, int count,
|
|
||||||
int target, string[] lines, ref Portion* portions) {
|
|
||||||
int lineBeg = 0, lineLen = 0, lineEnd = 0, total = 0;
|
|
||||||
for (int i = 0; i < lines.Length; i++) {
|
|
||||||
string line = lines[i];
|
|
||||||
if (line == null) continue;
|
|
||||||
|
|
||||||
if (i == target) {
|
|
||||||
lineBeg = total;
|
|
||||||
lineLen = line.Length;
|
|
||||||
lineEnd = lineBeg + lineLen;
|
|
||||||
}
|
|
||||||
total += line.Length;
|
|
||||||
}
|
|
||||||
|
|
||||||
bit.Beg = mappings[bit.ReducedBeg];
|
// Adjust this portion to be within this line
|
||||||
if (bit.Beg >= lineEnd || bit.ReducedLen == 0) return;
|
|
||||||
|
|
||||||
// Map back this reduced portion to original lines
|
|
||||||
int end = bit.ReducedBeg + (bit.ReducedLen & 0x7FFF);
|
|
||||||
end = end < count ? mappings[end] : total;
|
|
||||||
bit.Len = end - bit.Beg;
|
|
||||||
|
|
||||||
// Adjust this reduced portion to lie inside line we care about
|
|
||||||
if (bit.Beg >= lineBeg) {
|
if (bit.Beg >= lineBeg) {
|
||||||
} else if (bit.Beg + bit.Len > lineBeg) {
|
} else if (bit.Beg + bit.LineLen > lineBeg) {
|
||||||
// Clamp start of portion to lie in this line
|
// Adjust start of portion to be within this line
|
||||||
int underBy = lineBeg - bit.Beg;
|
int underBy = lineBeg - bit.Beg;
|
||||||
bit.Beg += underBy; bit.Len -= underBy;
|
bit.LineBeg += underBy; bit.LineLen -= underBy;
|
||||||
} else {
|
} else { return; }
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clamp length of portion to lie in this line
|
// Limit length of portion to be within this line
|
||||||
int overBy = (bit.Beg + bit.Len) - lineEnd;
|
int overBy = (bit.LineBeg + bit.LineLen) - lineEnd;
|
||||||
if (overBy > 0) bit.Len -= overBy;
|
if (overBy > 0) bit.LineLen -= overBy;
|
||||||
|
|
||||||
bit.Beg -= lineBeg;
|
bit.LineBeg -= lineBeg;
|
||||||
if (bit.Len == 0) return;
|
if (bit.LineLen == 0) return;
|
||||||
|
|
||||||
*portions = bit; portions++;
|
*portions = bit; portions++;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct Portion { public int ReducedBeg, ReducedLen, Beg, Len; }
|
struct Portion { public int Beg, Len, LineBeg, LineLen; }
|
||||||
unsafe int Reduce(char* chars, int target, Portion* portions) {
|
unsafe int Reduce(char* chars, int target, Portion* portions) {
|
||||||
ushort* mappings = stackalloc ushort[lines.Length * 96];
|
|
||||||
Portion* start = portions;
|
Portion* start = portions;
|
||||||
int count = 0;
|
int total = 0;
|
||||||
|
int[] begs = new int[lines.Length];
|
||||||
|
int[] ends = new int[lines.Length];
|
||||||
|
|
||||||
for (int i = 0, offset = 0; i < lines.Length; i++) {
|
for (int i = 0; i < lines.Length; i++) {
|
||||||
string line = lines[i];
|
string line = lines[i];
|
||||||
if (line == null) continue;
|
begs[i] = -1; ends[i] = -1;
|
||||||
|
if (line == null) continue;
|
||||||
|
|
||||||
count = ReduceLine(chars, mappings, count, offset, line);
|
begs[i] = total;
|
||||||
offset += line.Length;
|
for (int j = 0; j < line.Length; j++) { chars[total + j] = line[j]; }
|
||||||
|
total += line.Length; ends[i] = total;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now find http:// and https:// urls
|
// Now find http:// and https:// urls
|
||||||
int urlEnd = 0;
|
int urlEnd = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int nextUrlStart = NextUrl(chars, urlEnd, count);
|
int nextUrlStart = NextUrl(chars, urlEnd, total);
|
||||||
if (nextUrlStart == -1) nextUrlStart = count;
|
if (nextUrlStart == -1) nextUrlStart = total;
|
||||||
|
|
||||||
// add normal portion between urls
|
// add normal portion between urls
|
||||||
Portion bit = default(Portion); bit.ReducedBeg = urlEnd;
|
Portion bit = default(Portion); bit.Beg = urlEnd;
|
||||||
bit.ReducedLen = nextUrlStart - urlEnd;
|
bit.Len = nextUrlStart - urlEnd;
|
||||||
Output(bit, mappings, count, target, lines, ref portions);
|
Output(bit, begs[target], ends[target], ref portions);
|
||||||
|
if (nextUrlStart == total) break;
|
||||||
|
|
||||||
if (nextUrlStart == count) break;
|
|
||||||
// work out how long this url is
|
// work out how long this url is
|
||||||
urlEnd = nextUrlStart;
|
urlEnd = nextUrlStart;
|
||||||
for (; urlEnd < count && chars[urlEnd] != ' '; urlEnd++) { }
|
for (; urlEnd < total && chars[urlEnd] != ' '; urlEnd++) {
|
||||||
|
if (chars[urlEnd] != '>') { urlEnd++; continue; }
|
||||||
|
int left = total - urlEnd;
|
||||||
|
|
||||||
|
// Skip "> "
|
||||||
|
while (left >= 2 && chars[urlEnd + 1] == '&') { left -= 2; urlEnd += 2; }
|
||||||
|
if (left > 0 && chars[urlEnd + 1] == ' ') urlEnd++;
|
||||||
|
}
|
||||||
|
|
||||||
// add this url portion
|
// add this url portion
|
||||||
bit = default(Portion); bit.ReducedBeg = nextUrlStart;
|
bit = default(Portion);
|
||||||
bit.ReducedLen = (urlEnd - nextUrlStart) | 0x8000;
|
bit.Beg = nextUrlStart;
|
||||||
Output(bit, mappings, count, target, lines, ref portions);
|
bit.Len = (urlEnd - nextUrlStart) | 0x8000;
|
||||||
|
Output(bit, begs[target], ends[target], ref portions);
|
||||||
}
|
}
|
||||||
return (int)(portions - start);
|
return (int)(portions - start);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue