mirror of
https://github.com/ClassiCube/ClassiCube.git
synced 2025-01-23 09:34:35 -05:00
Core: Don't allow multiple lines of chat in classic mode.
This commit is contained in:
parent
c781af2d85
commit
6dad76e397
3 changed files with 185 additions and 167 deletions
|
@ -19,14 +19,22 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1.
|
||||
}
|
||||
|
||||
public override int MaxLines { get { return game.ClassicMode ? 1 : 3; } }
|
||||
public override int MaxCharsPerLine {
|
||||
get {
|
||||
bool allChars = game.ClassicMode || game.Server.SupportsPartialMessages;
|
||||
return allChars ? 64 : 62;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Init() {
|
||||
base.Init();
|
||||
bool supports = game.Server.SupportsPartialMessages;
|
||||
|
||||
if( buffer.Length > LineLength && !shownWarning && !supports ) {
|
||||
if( buffer.Length > MaxCharsPerLine && !shownWarning && !supports ) {
|
||||
game.Chat.Add( "&eNote: Each line will be sent as a separate packet.", MessageType.ClientStatus6 );
|
||||
shownWarning = true;
|
||||
} else if( buffer.Length <= LineLength && shownWarning ) {
|
||||
} else if( buffer.Length <= MaxCharsPerLine && shownWarning ) {
|
||||
game.Chat.Add( null, MessageType.ClientStatus6 );
|
||||
shownWarning = false;
|
||||
}
|
||||
|
@ -79,8 +87,8 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
|
||||
void SendNormal() {
|
||||
int packetsCount = 0;
|
||||
for( int i = 0; i < parts.Length; i++ ) {
|
||||
if( parts[i] == null ) break;
|
||||
for( int i = 0; i < lines.Length; i++ ) {
|
||||
if( lines[i] == null ) break;
|
||||
packetsCount++;
|
||||
}
|
||||
|
||||
|
@ -91,7 +99,7 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
}
|
||||
|
||||
void SendNormalText( int i, bool partial ) {
|
||||
string text = parts[i];
|
||||
string text = lines[i];
|
||||
char lastCol = GetLastColour( 0, i );
|
||||
if( !IDrawer2D.IsWhiteColour( lastCol ) )
|
||||
text = "&" + lastCol + text;
|
||||
|
@ -103,10 +111,10 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
|
||||
void UpKey( bool controlDown ) {
|
||||
if( controlDown ) {
|
||||
int pos = caretPos == -1 ? buffer.Length : caretPos;
|
||||
if( pos < LineLength ) return;
|
||||
int pos = caret == -1 ? buffer.Length : caret;
|
||||
if( pos < MaxCharsPerLine ) return;
|
||||
|
||||
caretPos = pos - LineLength;
|
||||
caret = pos - MaxCharsPerLine;
|
||||
UpdateCaret();
|
||||
return;
|
||||
}
|
||||
|
@ -119,15 +127,15 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
|
||||
buffer.Clear();
|
||||
buffer.Append( 0, game.Chat.InputLog[typingLogPos] );
|
||||
caretPos = -1;
|
||||
caret = -1;
|
||||
Recreate();
|
||||
}
|
||||
}
|
||||
|
||||
void DownKey( bool controlDown ) {
|
||||
if( controlDown ) {
|
||||
if( caretPos == -1 || caretPos >= (parts.Length - 1) * LineLength ) return;
|
||||
caretPos += LineLength;
|
||||
if( caret == -1 || caret >= (lines.Length - 1) * MaxCharsPerLine ) return;
|
||||
caret += MaxCharsPerLine;
|
||||
UpdateCaret();
|
||||
return;
|
||||
}
|
||||
|
@ -142,13 +150,13 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
} else {
|
||||
buffer.Append( 0, game.Chat.InputLog[typingLogPos] );
|
||||
}
|
||||
caretPos = -1;
|
||||
caret = -1;
|
||||
Recreate();
|
||||
}
|
||||
}
|
||||
|
||||
void TabKey() {
|
||||
int pos = caretPos == -1 ? buffer.Length - 1 : caretPos;
|
||||
int pos = caret == -1 ? buffer.Length - 1 : caret;
|
||||
int start = pos;
|
||||
char[] value = buffer.value;
|
||||
|
||||
|
@ -172,11 +180,11 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
}
|
||||
|
||||
if( matches.Count == 1 ) {
|
||||
if( caretPos == -1 ) pos++;
|
||||
if( caret == -1 ) pos++;
|
||||
int len = pos - start;
|
||||
for( int i = 0; i < len; i++ )
|
||||
buffer.DeleteAt( start );
|
||||
if( caretPos != -1 ) caretPos -= len;
|
||||
if( caret != -1 ) caret -= len;
|
||||
Append( matches[0] );
|
||||
} else if( matches.Count > 1 ) {
|
||||
StringBuffer sb = new StringBuffer( Utils.StringLength );
|
||||
|
|
|
@ -12,63 +12,67 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
public InputWidget( Game game, Font font ) : base( game ) {
|
||||
HorizontalAnchor = Anchor.LeftOrTop;
|
||||
VerticalAnchor = Anchor.BottomOrRight;
|
||||
buffer = new WrappableStringBuffer( Utils.StringLength * lines );
|
||||
|
||||
buffer = new WrappableStringBuffer( Utils.StringLength * MaxLines );
|
||||
lines = new string[MaxLines];
|
||||
lineSizes = new Size[MaxLines];
|
||||
|
||||
DrawTextArgs args = new DrawTextArgs( "_", font, true );
|
||||
caretTex = game.Drawer2D.MakeChatTextTexture( ref args, 0, 0 );
|
||||
caretTex.Width = (short)((caretTex.Width * 3) / 4);
|
||||
defaultCaretWidth = caretTex.Width;
|
||||
caretWidth = caretTex.Width;
|
||||
|
||||
args = new DrawTextArgs( "> ", font, true );
|
||||
Size defSize = game.Drawer2D.MeasureChatSize( ref args );
|
||||
defaultWidth = Width = defSize.Width;
|
||||
defaultHeight = Height = defSize.Height;
|
||||
Size size = game.Drawer2D.MeasureChatSize( ref args );
|
||||
prefixWidth = Width = size.Width;
|
||||
prefixHeight = Height = size.Height;
|
||||
this.font = font;
|
||||
}
|
||||
}
|
||||
|
||||
internal const int lines = 3;
|
||||
internal WrappableStringBuffer buffer;
|
||||
protected int caretPos = -1;
|
||||
internal WrappableStringBuffer buffer;
|
||||
protected int caret = -1;
|
||||
|
||||
Texture inputTex, caretTex, prefixTex;
|
||||
readonly Font font;
|
||||
int defaultCaretWidth, defaultWidth, defaultHeight;
|
||||
FastColour caretCol;
|
||||
int caretWidth, prefixWidth, prefixHeight;
|
||||
FastColour caretColour;
|
||||
static FastColour backColour = new FastColour( 0, 0, 0, 127 );
|
||||
|
||||
public override void Render( double delta ) {
|
||||
gfx.Texturing = false;
|
||||
int y = Y, x = X;
|
||||
|
||||
for( int i = 0; i < sizes.Length; i++ ) {
|
||||
if( i > 0 && sizes[i].Height == 0 ) break;
|
||||
bool caretAtEnd = caretTex.Y1 == y && (indexX == LineLength || caretPos == -1);
|
||||
int drawWidth = sizes[i].Width + (caretAtEnd ? caretTex.Width : 0);
|
||||
for( int i = 0; i < lineSizes.Length; i++ ) {
|
||||
if( i > 0 && lineSizes[i].Height == 0 ) break;
|
||||
bool caretAtEnd = caretTex.Y1 == y && (caretCol == MaxCharsPerLine || caret == -1);
|
||||
int drawWidth = lineSizes[i].Width + (caretAtEnd ? caretTex.Width : 0);
|
||||
// Cover whole window width to match original classic behaviour
|
||||
if( game.PureClassic )
|
||||
drawWidth = Math.Max( drawWidth, game.Width - X * 4 );
|
||||
|
||||
gfx.Draw2DQuad( x, y, drawWidth + 10, defaultHeight, backColour );
|
||||
y += sizes[i].Height;
|
||||
gfx.Draw2DQuad( x, y, drawWidth + 10, prefixHeight, backColour );
|
||||
y += lineSizes[i].Height;
|
||||
}
|
||||
gfx.Texturing = true;
|
||||
|
||||
inputTex.Render( gfx );
|
||||
caretTex.Render( gfx, caretCol );
|
||||
caretTex.Render( gfx, caretColour );
|
||||
}
|
||||
|
||||
internal string[] parts = new string[lines];
|
||||
int[] partLens = new int[lines];
|
||||
Size[] sizes = new Size[lines];
|
||||
int maxWidth = 0;
|
||||
int indexX, indexY;
|
||||
|
||||
internal int LineLength { get { return game.Server.SupportsPartialMessages ? 64 : 62; } }
|
||||
internal int TotalChars { get { return LineLength * lines; } }
|
||||
/// <summary> The maximum number of lines that may be entered. </summary>
|
||||
public abstract int MaxLines { get; }
|
||||
|
||||
/// <summary> The maximum number of characters that can fit on one line. </summary>
|
||||
public abstract int MaxCharsPerLine { get; }
|
||||
|
||||
protected string[] lines; // raw text of each line
|
||||
protected Size[] lineSizes; // size of each line in pixels
|
||||
int caretCol, caretRow; // coordinates of caret
|
||||
int maxWidth = 0; // maximum width of any line
|
||||
|
||||
public override void Init() {
|
||||
X = 5;
|
||||
buffer.WordWrap( game.Drawer2D, ref parts, ref partLens, LineLength, TotalChars );
|
||||
buffer.WordWrap( game.Drawer2D, lines, MaxCharsPerLine );
|
||||
|
||||
CalculateLineSizes();
|
||||
RemakeTexture();
|
||||
|
@ -77,57 +81,59 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
|
||||
/// <summary> Calculates the sizes of each line in the text buffer. </summary>
|
||||
public void CalculateLineSizes() {
|
||||
for( int y = 0; y < sizes.Length; y++ )
|
||||
sizes[y] = Size.Empty;
|
||||
sizes[0].Width = defaultWidth;
|
||||
maxWidth = defaultWidth;
|
||||
for( int y = 0; y < lineSizes.Length; y++ )
|
||||
lineSizes[y] = Size.Empty;
|
||||
lineSizes[0].Width = prefixWidth;
|
||||
maxWidth = prefixWidth;
|
||||
|
||||
DrawTextArgs args = new DrawTextArgs( null, font, true );
|
||||
for( int y = 0; y < lines; y++ ) {
|
||||
int offset = y == 0 ? defaultWidth : 0;
|
||||
args.Text = parts[y];
|
||||
sizes[y] += game.Drawer2D.MeasureChatSize( ref args );
|
||||
maxWidth = Math.Max( maxWidth, sizes[y].Width );
|
||||
for( int y = 0; y < MaxLines; y++ ) {
|
||||
args.Text = lines[y];
|
||||
lineSizes[y] += game.Drawer2D.MeasureChatSize( ref args );
|
||||
maxWidth = Math.Max( maxWidth, lineSizes[y].Width );
|
||||
}
|
||||
if( sizes[0].Height == 0 ) sizes[0].Height = defaultHeight;
|
||||
if( lineSizes[0].Height == 0 ) lineSizes[0].Height = prefixHeight;
|
||||
}
|
||||
|
||||
/// <summary> Calculates the location and size of the caret character </summary>
|
||||
public void UpdateCaret() {
|
||||
if( caretPos >= buffer.Length ) caretPos = -1;
|
||||
buffer.MakeCoords( caretPos, partLens, out indexX, out indexY );
|
||||
if( caret >= buffer.Length ) caret = -1;
|
||||
buffer.GetCoords( caret, lines, out caretCol, out caretRow );
|
||||
DrawTextArgs args = new DrawTextArgs( null, font, true );
|
||||
|
||||
if( indexX == LineLength ) {
|
||||
caretTex.X1 = 10 + sizes[indexY].Width;
|
||||
caretCol = FastColour.Yellow;
|
||||
caretTex.Width = (short)defaultCaretWidth;
|
||||
} else {
|
||||
args.Text = parts[indexY].Substring( 0, indexX );
|
||||
Size trimmedSize = game.Drawer2D.MeasureChatSize( ref args );
|
||||
if( indexY == 0 ) trimmedSize.Width += defaultWidth;
|
||||
caretTex.X1 = 10 + trimmedSize.Width;
|
||||
caretCol = FastColour.Scale( FastColour.White, 0.8f );
|
||||
|
||||
string line = parts[indexY];
|
||||
args.Text = indexX < line.Length ? new String( line[indexX], 1 ) : "";
|
||||
int caretWidth = indexX < line.Length ?
|
||||
game.Drawer2D.MeasureChatSize( ref args ).Width : defaultCaretWidth;
|
||||
caretTex.Width = (short)caretWidth;
|
||||
}
|
||||
caretTex.Y1 = sizes[0].Height * indexY + Y;
|
||||
|
||||
// Update the colour of the caret
|
||||
IDrawer2D drawer = game.Drawer2D;
|
||||
char code = GetLastColour( indexX, indexY );
|
||||
if( code != '\0' ) caretCol = drawer.Colours[code];
|
||||
|
||||
if( caretCol == MaxCharsPerLine ) {
|
||||
caretTex.X1 = 10 + lineSizes[caretRow].Width;
|
||||
caretColour = FastColour.Yellow;
|
||||
caretTex.Width = (short)caretWidth;
|
||||
} else {
|
||||
args.Text = lines[caretRow].Substring( 0, caretCol );
|
||||
Size trimmedSize = drawer.MeasureChatSize( ref args );
|
||||
if( caretRow == 0 ) trimmedSize.Width += prefixWidth;
|
||||
|
||||
caretTex.X1 = 10 + trimmedSize.Width;
|
||||
caretColour = FastColour.Scale( FastColour.White, 0.8f );
|
||||
|
||||
string line = lines[caretRow];
|
||||
if( caretCol < line.Length ) {
|
||||
args.Text = new String( line[caretCol], 1 );
|
||||
caretTex.Width = (short)drawer.MeasureChatSize( ref args ).Width;
|
||||
} else {
|
||||
caretTex.Width = (short)caretWidth;
|
||||
}
|
||||
}
|
||||
caretTex.Y1 = lineSizes[0].Height * caretRow + Y;
|
||||
|
||||
// Update the colour of the caret
|
||||
char code = GetLastColour( caretCol, caretRow );
|
||||
if( code != '\0' ) caretColour = drawer.Colours[code];
|
||||
}
|
||||
|
||||
/// <summary> Remakes the raw texture containg all the chat lines. </summary>
|
||||
public void RemakeTexture() {
|
||||
int totalHeight = 0;
|
||||
for( int i = 0; i < lines; i++ )
|
||||
totalHeight += sizes[i].Height;
|
||||
for( int i = 0; i < MaxLines; i++ )
|
||||
totalHeight += lineSizes[i].Height;
|
||||
Size size = new Size( maxWidth, totalHeight );
|
||||
|
||||
int realHeight = 0;
|
||||
|
@ -138,21 +144,21 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
DrawTextArgs args = new DrawTextArgs( "> ", font, true );
|
||||
drawer.DrawChatText( ref args, 0, 0 );
|
||||
|
||||
for( int i = 0; i < parts.Length; i++ ) {
|
||||
if( parts[i] == null ) break;
|
||||
args.Text = parts[i];
|
||||
for( int i = 0; i < lines.Length; i++ ) {
|
||||
if( lines[i] == null ) break;
|
||||
args.Text = lines[i];
|
||||
char lastCol = GetLastColour( 0, i );
|
||||
if( !IDrawer2D.IsWhiteColour( lastCol ) )
|
||||
args.Text = "&" + lastCol + args.Text;
|
||||
|
||||
int offset = i == 0 ? defaultWidth : 0;
|
||||
int offset = i == 0 ? prefixWidth : 0;
|
||||
drawer.DrawChatText( ref args, offset, realHeight );
|
||||
realHeight += sizes[i].Height;
|
||||
realHeight += lineSizes[i].Height;
|
||||
}
|
||||
inputTex = drawer.Make2DTexture( bmp, size, 10, 0 );
|
||||
}
|
||||
|
||||
Height = realHeight == 0 ? defaultHeight : realHeight;
|
||||
Height = realHeight == 0 ? prefixHeight : realHeight;
|
||||
Y = game.Height - Height - YOffset;
|
||||
inputTex.Y1 = Y;
|
||||
Width = size.Width;
|
||||
|
@ -162,10 +168,10 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
int x = indexX;
|
||||
IDrawer2D drawer = game.Drawer2D;
|
||||
for( int y = indexY; y >= 0; y-- ) {
|
||||
string part = parts[y];
|
||||
string part = lines[y];
|
||||
char code = drawer.LastColour( part, x );
|
||||
if( code != '\0' ) return code;
|
||||
if( y > 0 ) x = parts[y - 1].Length;
|
||||
if( y > 0 ) x = lines[y - 1].Length;
|
||||
}
|
||||
return '\0';
|
||||
}
|
||||
|
@ -190,7 +196,7 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
/// <summary> Invoked when the user presses enter. </summary>
|
||||
public virtual void EnterInput() {
|
||||
Clear();
|
||||
Height = defaultHeight;
|
||||
Height = prefixHeight;
|
||||
}
|
||||
|
||||
|
||||
|
@ -198,10 +204,10 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
/// <remarks> Deletes the native texture. </remarks>
|
||||
public void Clear() {
|
||||
buffer.Clear();
|
||||
for( int i = 0; i < parts.Length; i++ )
|
||||
parts[i] = null;
|
||||
for( int i = 0; i < lines.Length; i++ )
|
||||
lines[i] = null;
|
||||
|
||||
caretPos = -1;
|
||||
caret = -1;
|
||||
Dispose();
|
||||
}
|
||||
|
||||
|
@ -225,14 +231,15 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
}
|
||||
|
||||
bool AppendChar( char c ) {
|
||||
if( buffer.Length == TotalChars ) return false;
|
||||
int totalChars = MaxCharsPerLine * lines.Length;
|
||||
if( buffer.Length == totalChars ) return false;
|
||||
|
||||
if( caretPos == -1 ) {
|
||||
if( caret == -1 ) {
|
||||
buffer.InsertAt( buffer.Length, c );
|
||||
} else {
|
||||
buffer.InsertAt( caretPos, c );
|
||||
caretPos++;
|
||||
if( caretPos >= buffer.Length ) caretPos = -1;
|
||||
buffer.InsertAt( caret, c );
|
||||
caret++;
|
||||
if( caret >= buffer.Length ) caret = -1;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -276,37 +283,35 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
}
|
||||
|
||||
|
||||
#region Input handling
|
||||
#region Input handling
|
||||
|
||||
void BackspaceKey( bool controlDown ) {
|
||||
if( controlDown ) {
|
||||
if( caretPos == -1 ) caretPos = buffer.Length - 1;
|
||||
int len = buffer.GetBackLength( caretPos );
|
||||
if( caret == -1 ) caret = buffer.Length - 1;
|
||||
int len = buffer.GetBackLength( caret );
|
||||
if( len == 0 ) return;
|
||||
|
||||
caretPos -= len;
|
||||
if( caretPos < 0 ) caretPos = 0;
|
||||
caret -= len;
|
||||
if( caret < 0 ) caret = 0;
|
||||
for( int i = 0; i <= len; i++ )
|
||||
buffer.DeleteAt( caretPos );
|
||||
buffer.DeleteAt( caret );
|
||||
|
||||
if( caretPos >= buffer.Length ) caretPos = -1;
|
||||
if( caretPos == -1 && buffer.Length > 0 ) {
|
||||
if( caret >= buffer.Length ) caret = -1;
|
||||
if( caret == -1 && buffer.Length > 0 ) {
|
||||
buffer.value[buffer.Length] = ' ';
|
||||
} else if( caretPos >= 0 && buffer.value[caretPos] != ' ' ) {
|
||||
buffer.InsertAt( caretPos, ' ' );
|
||||
} else if( caret >= 0 && buffer.value[caret] != ' ' ) {
|
||||
buffer.InsertAt( caret, ' ' );
|
||||
}
|
||||
Recreate();
|
||||
} else if( !buffer.Empty && caretPos != 0 ) {
|
||||
int index = caretPos == -1 ? buffer.Length - 1 : caretPos;
|
||||
} else if( !buffer.Empty && caret != 0 ) {
|
||||
int index = caret == -1 ? buffer.Length - 1 : caret;
|
||||
if( CheckColour( index - 1 ) ) {
|
||||
DeleteChar(); // backspace XYZ%e to XYZ
|
||||
index -= 1;
|
||||
} else if( CheckColour( index - 2 ) ) {
|
||||
DeleteChar(); DeleteChar(); // backspace XYZ%eH to XYZ
|
||||
index -= 2;
|
||||
}
|
||||
|
||||
if( index > 0 ) DeleteChar();
|
||||
DeleteChar();
|
||||
Recreate();
|
||||
}
|
||||
}
|
||||
|
@ -318,68 +323,71 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
}
|
||||
|
||||
void DeleteChar() {
|
||||
if( caretPos == -1 ) {
|
||||
if( buffer.Length == 0 ) return;
|
||||
|
||||
if( caret == -1 ) {
|
||||
buffer.DeleteAt( buffer.Length - 1 );
|
||||
} else {
|
||||
caretPos--;
|
||||
buffer.DeleteAt( caretPos );
|
||||
caret--;
|
||||
buffer.DeleteAt( caret );
|
||||
}
|
||||
}
|
||||
|
||||
void DeleteKey() {
|
||||
if( !buffer.Empty && caretPos != -1 ) {
|
||||
buffer.DeleteAt( caretPos );
|
||||
if( caretPos >= buffer.Length ) caretPos = -1;
|
||||
if( !buffer.Empty && caret != -1 ) {
|
||||
buffer.DeleteAt( caret );
|
||||
if( caret >= buffer.Length ) caret = -1;
|
||||
Recreate();
|
||||
}
|
||||
}
|
||||
|
||||
void LeftKey( bool controlDown ) {
|
||||
if( controlDown ) {
|
||||
if( caretPos == -1 )
|
||||
caretPos = buffer.Length - 1;
|
||||
caretPos -= buffer.GetBackLength( caretPos );
|
||||
if( caret == -1 )
|
||||
caret = buffer.Length - 1;
|
||||
caret -= buffer.GetBackLength( caret );
|
||||
UpdateCaret();
|
||||
return;
|
||||
}
|
||||
|
||||
if( !buffer.Empty ) {
|
||||
if( caretPos == -1 ) caretPos = buffer.Length;
|
||||
caretPos--;
|
||||
if( caretPos < 0 ) caretPos = 0;
|
||||
if( caret == -1 ) caret = buffer.Length;
|
||||
caret--;
|
||||
if( caret < 0 ) caret = 0;
|
||||
UpdateCaret();
|
||||
}
|
||||
}
|
||||
|
||||
void RightKey( bool controlDown ) {
|
||||
if( controlDown ) {
|
||||
caretPos += buffer.GetForwardLength( caretPos );
|
||||
if( caretPos >= buffer.Length ) caretPos = -1;
|
||||
caret += buffer.GetForwardLength( caret );
|
||||
if( caret >= buffer.Length ) caret = -1;
|
||||
UpdateCaret();
|
||||
return;
|
||||
}
|
||||
|
||||
if( !buffer.Empty && caretPos != -1 ) {
|
||||
caretPos++;
|
||||
if( caretPos >= buffer.Length ) caretPos = -1;
|
||||
if( !buffer.Empty && caret != -1 ) {
|
||||
caret++;
|
||||
if( caret >= buffer.Length ) caret = -1;
|
||||
UpdateCaret();
|
||||
}
|
||||
}
|
||||
|
||||
void HomeKey() {
|
||||
if( buffer.Empty ) return;
|
||||
caretPos = 0;
|
||||
caret = 0;
|
||||
UpdateCaret();
|
||||
}
|
||||
|
||||
void EndKey() {
|
||||
caretPos = -1;
|
||||
caret = -1;
|
||||
UpdateCaret();
|
||||
}
|
||||
|
||||
static char[] trimChars = {'\r', '\n', '\v', '\f', ' ', '\t', '\0'};
|
||||
bool OtherKey( Key key ) {
|
||||
if( key == Key.V && buffer.Length < TotalChars ) {
|
||||
int totalChars = MaxCharsPerLine * lines.Length;
|
||||
if( key == Key.V && buffer.Length < totalChars ) {
|
||||
string text = null;
|
||||
try {
|
||||
text = game.window.ClipboardText.Trim( trimChars );
|
||||
|
@ -432,12 +440,12 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
mouseX -= inputTex.X1; mouseY -= inputTex.Y1;
|
||||
DrawTextArgs args = new DrawTextArgs( null, font, true );
|
||||
IDrawer2D drawer = game.Drawer2D;
|
||||
int offset = 0, elemHeight = defaultHeight;
|
||||
int offset = 0, elemHeight = prefixHeight;
|
||||
string oneChar = new String( 'A', 1 );
|
||||
|
||||
for( int y = 0; y < parts.Length; y++ ) {
|
||||
string line = parts[y];
|
||||
int xOffset = y == 0 ? defaultWidth : 0;
|
||||
for( int y = 0; y < lines.Length; y++ ) {
|
||||
string line = lines[y];
|
||||
int xOffset = y == 0 ? prefixWidth : 0;
|
||||
if( line == null ) continue;
|
||||
|
||||
for( int x = 0; x < line.Length; x++ ) {
|
||||
|
@ -450,13 +458,13 @@ namespace ClassicalSharp.Gui.Widgets {
|
|||
args.Text = oneChar;
|
||||
int elemWidth = drawer.MeasureChatSize( ref args ).Width;
|
||||
if( GuiElement.Contains( trimmedWidth, y * elemHeight, elemWidth, elemHeight, mouseX, mouseY ) ) {
|
||||
caretPos = offset + x;
|
||||
caret = offset + x;
|
||||
UpdateCaret(); return;
|
||||
}
|
||||
}
|
||||
offset += line.Length;
|
||||
}
|
||||
caretPos = -1;
|
||||
caret = -1;
|
||||
UpdateCaret();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,17 +3,16 @@ using System;
|
|||
|
||||
namespace ClassicalSharp {
|
||||
|
||||
public sealed class WrappableStringBuffer : StringBuffer {
|
||||
|
||||
char[] wrap;
|
||||
public unsafe sealed class WrappableStringBuffer : StringBuffer {
|
||||
|
||||
char[] wrap;
|
||||
public WrappableStringBuffer( int capacity ) : base( capacity ) {
|
||||
wrap = new char[capacity];
|
||||
}
|
||||
|
||||
public void WordWrap( IDrawer2D drawer, ref string[] lines, ref int[] lineLens,
|
||||
int lineSize, int totalChars ) {
|
||||
public void WordWrap( IDrawer2D drawer, string[] lines, int maxPerLine ) {
|
||||
int len = Length;
|
||||
int* lineLens = stackalloc int[lines.Length];
|
||||
for( int i = 0; i < lines.Length; i++ ) {
|
||||
lines[i] = null;
|
||||
lineLens[i] = 0;
|
||||
|
@ -23,31 +22,29 @@ namespace ClassicalSharp {
|
|||
char[] realText = value;
|
||||
MakeWrapCopy();
|
||||
|
||||
int linesCount = 0;
|
||||
for( int index = 0; index < totalChars; index += lineSize ) {
|
||||
if( value[index] == '\0' )
|
||||
break;
|
||||
int usedLines = 0, totalChars = maxPerLine * lines.Length;
|
||||
for( int index = 0; index < totalChars; index += maxPerLine ) {
|
||||
if( value[index] == '\0' ) break;
|
||||
|
||||
int lineEnd = index + (lineSize - 1), nextLine = lineEnd + 1;
|
||||
linesCount++;
|
||||
int lineEnd = index + (maxPerLine - 1), nextStart = lineEnd + 1;
|
||||
usedLines++;
|
||||
|
||||
// Do we need word wrapping?
|
||||
bool needWrap = !IsWrapper( value[lineEnd] )
|
||||
&& nextLine < totalChars && !IsWrapper( value[nextLine] );
|
||||
int wrappedLen = needWrap ? WrapLine( index, lineSize ) : lineSize;
|
||||
&& nextStart < totalChars && !IsWrapper( value[nextStart] );
|
||||
int wrappedLen = needWrap ? WrapLine( index, maxPerLine ) : maxPerLine;
|
||||
|
||||
// Calculate the maximum size of this line
|
||||
int lineLen = lineSize;
|
||||
int lineLen = maxPerLine;
|
||||
for( int i = lineEnd; i >= index; i-- ) {
|
||||
if( value[i] != '\0' ) break;
|
||||
lineLen--;
|
||||
}
|
||||
lineLens[index / lineSize] = Math.Min( lineLen, wrappedLen );
|
||||
lineLens[index / maxPerLine] = Math.Min( lineLen, wrappedLen );
|
||||
}
|
||||
|
||||
// Output the used lines
|
||||
OutputLines( drawer, ref lines, lineLens,
|
||||
linesCount, lineSize, totalChars );
|
||||
OutputLines( drawer, lines, lineLens, usedLines, maxPerLine );
|
||||
value = realText;
|
||||
}
|
||||
|
||||
|
@ -61,8 +58,8 @@ namespace ClassicalSharp {
|
|||
value = wrap;
|
||||
}
|
||||
|
||||
void OutputLines( IDrawer2D drawer, ref string[] lines, int[] lineLens,
|
||||
int linesCount, int lineSize, int totalChars ) {
|
||||
void OutputLines( IDrawer2D drawer, string[] lines, int* lineLens, int usedLines, int charsPerLine ) {
|
||||
int totalChars = charsPerLine * lines.Length;
|
||||
for( int i = 0; i < totalChars; i++ ) {
|
||||
if( value[i] == '\0' ) value[i] = ' ';
|
||||
}
|
||||
|
@ -72,8 +69,9 @@ namespace ClassicalSharp {
|
|||
value[i] = '&';
|
||||
}
|
||||
|
||||
for( int i = 0; i < Math.Max( 1, linesCount ); i++ )
|
||||
lines[i] = new String( value, i * lineSize, lineLens[i] );
|
||||
usedLines = Math.Max( 1, usedLines );
|
||||
for( int i = 0; i < usedLines; i++ )
|
||||
lines[i] = new String( value, i * charsPerLine, lineLens[i] );
|
||||
}
|
||||
|
||||
int WrapLine( int index, int lineSize ) {
|
||||
|
@ -96,22 +94,26 @@ namespace ClassicalSharp {
|
|||
|| c == '<' || c == '/' || c == '\\';
|
||||
}
|
||||
|
||||
public void MakeCoords( int index, int[] partLens, out int x, out int y ) {
|
||||
/// <summary> Calculates where the given raw index is located in the wrapped lines. </summary>
|
||||
public void GetCoords( int index, string[] lines, out int col, out int row ) {
|
||||
if( index == -1 ) index = Int32.MaxValue;
|
||||
int total = 0; x = -1; y = 0;
|
||||
int total = 0; col = -1; row = 0;
|
||||
|
||||
for( int yy = 0; yy < partLens.Length; yy++ ) {
|
||||
if( partLens[yy] == 0 ) break;
|
||||
for( int y = 0; y < lines.Length; y++ ) {
|
||||
int lineLength = LineLength( lines[y] );
|
||||
if( lineLength == 0 ) break;
|
||||
|
||||
y = yy;
|
||||
if( index < total + partLens[yy] ) {
|
||||
x = index - total; break;
|
||||
row = y;
|
||||
if( index < total + lineLength ) {
|
||||
col = index - total; break;
|
||||
}
|
||||
total += partLens[yy];
|
||||
total += lineLength;
|
||||
}
|
||||
if( x == -1 ) x = partLens[y];
|
||||
if( col == -1 ) col = LineLength( lines[row] );
|
||||
}
|
||||
|
||||
static int LineLength( string line ) { return line == null ? 0 : line.Length; }
|
||||
|
||||
public int GetBackLength( int index ) {
|
||||
if( index <= 0 ) return 0;
|
||||
int start = index;
|
||||
|
|
Loading…
Add table
Reference in a new issue