diff --git a/ClassicalSharp/2D/GuiElement.cs b/ClassicalSharp/2D/GuiElement.cs index 9a8a7ce25..d99ffbdc2 100644 --- a/ClassicalSharp/2D/GuiElement.cs +++ b/ClassicalSharp/2D/GuiElement.cs @@ -59,16 +59,7 @@ namespace ClassicalSharp.Gui { return (axisSize - elemSize) / 2 + offset; } - protected bool IsValidInputChar( char c ) { - if( c >= ' ' && c <= '~' ) return true; // ascii - - bool isCP437 = Utils.ControlCharReplacements.IndexOf( c ) >= 0 || - Utils.ExtendedCharReplacements.IndexOf( c ) >= 0; - bool supportsCP437 = game.Server.SupportsFullCP437; - return supportsCP437 && isCP437; - } - - protected static bool Contains( int recX, int recY, int width, int height, int x, int y ) { + public static bool Contains( int recX, int recY, int width, int height, int x, int y ) { return x >= recX && y >= recY && x < recX + width && y < recY + height; } } diff --git a/ClassicalSharp/2D/Screens/ChatScreen.cs b/ClassicalSharp/2D/Screens/ChatScreen.cs index 30a4da6ad..05f2ba583 100644 --- a/ClassicalSharp/2D/Screens/ChatScreen.cs +++ b/ClassicalSharp/2D/Screens/ChatScreen.cs @@ -19,7 +19,7 @@ namespace ClassicalSharp.Gui.Screens { HudScreen hud; int chatLines; ChatTextWidget announcement; - TextInputWidget textInput; + InputWidget textInput; TextGroupWidget status, bottomRight, normalChat, clientStatus; bool suppressNextPress = true; int chatIndex; @@ -50,7 +50,7 @@ namespace ClassicalSharp.Gui.Screens { } void ConstructWidgets() { - textInput = new TextInputWidget( game, chatFont ); + textInput = new InputWidget( game, chatFont ); textInput.YOffset = 5; altText = new AltTextInputWidget( game, chatFont, textInput ); altText.Init(); @@ -420,7 +420,7 @@ namespace ClassicalSharp.Gui.Screens { game.Gui.ShowWarning( warning ); } else if( game.ClickableChat ) { for( int i = 0; i < text.Length; i++ ) { - if( !IsValidInputChar( text[i] ) ) { + if( !Utils.IsValidInputChar( text[i], game ) ) { game.Chat.Add( "&eChatline contained characters that can't be sent on this server." ); return true; } diff --git a/ClassicalSharp/2D/Widgets/Chat/AltTextInputWidget.cs b/ClassicalSharp/2D/Widgets/Chat/AltTextInputWidget.cs index b3b76ba5f..195547053 100644 --- a/ClassicalSharp/2D/Widgets/Chat/AltTextInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/AltTextInputWidget.cs @@ -9,7 +9,7 @@ using Android.Graphics; namespace ClassicalSharp.Gui.Widgets { public sealed partial class AltTextInputWidget : Widget { - public AltTextInputWidget( Game game, Font font, TextInputWidget parent ) : base( game ) { + public AltTextInputWidget( Game game, Font font, InputWidget parent ) : base( game ) { HorizontalAnchor = Anchor.LeftOrTop; VerticalAnchor = Anchor.BottomOrRight; this.font = font; @@ -25,7 +25,7 @@ namespace ClassicalSharp.Gui.Widgets { public Texture texture; readonly Font font; - TextInputWidget parent; + InputWidget parent; Size elementSize; public void SetActive( bool active ) { diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs b/ClassicalSharp/2D/Widgets/Chat/InputWidget.cs similarity index 86% rename from ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs rename to ClassicalSharp/2D/Widgets/Chat/InputWidget.cs index 1ad6e0541..ba6e9278a 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.cs +++ b/ClassicalSharp/2D/Widgets/Chat/InputWidget.cs @@ -1,15 +1,16 @@ // ClassicalSharp copyright 2014-2016 UnknownShadow200 | Licensed under MIT using System; using System.Drawing; +using OpenTK.Input; #if ANDROID using Android.Graphics; #endif namespace ClassicalSharp.Gui.Widgets { - public sealed partial class TextInputWidget : Widget { + public sealed class InputWidget : Widget { - const int lines = 3; - public TextInputWidget( Game game, Font font ) : base( game ) { + internal const int lines = 3; + public InputWidget( Game game, Font font ) : base( game ) { HorizontalAnchor = Anchor.LeftOrTop; VerticalAnchor = Anchor.BottomOrRight; typingLogPos = game.Chat.InputLog.Count; // Index of newest entry + 1. @@ -26,13 +27,16 @@ namespace ClassicalSharp.Gui.Widgets { defaultHeight = Height = defSize.Height; this.font = font; + inputHandler = new InputWidgetHandler( game, this ); } - Texture inputTex, caretTex, prefixTex; - int caretPos = -1, typingLogPos = 0; - int defaultCaretWidth, defaultWidth, defaultHeight; + InputWidgetHandler inputHandler; + internal Texture inputTex, caretTex, prefixTex; + internal int caretPos = -1, typingLogPos = 0; + internal int defaultCaretWidth, defaultWidth, defaultHeight; internal WrappableStringBuffer buffer; - readonly Font font; + internal readonly Font font; + internal string originalText; FastColour caretCol; static FastColour backColour = new FastColour( 0, 0, 0, 127 ); @@ -57,15 +61,15 @@ namespace ClassicalSharp.Gui.Widgets { caretTex.Render( gfx, caretCol ); } - string[] parts = new string[lines]; + internal string[] parts = new string[lines]; int[] partLens = new int[lines]; Size[] sizes = new Size[lines]; int maxWidth = 0; int indexX, indexY; bool shownWarning; - int LineLength { get { return game.Server.SupportsPartialMessages ? 64 : 62; } } - int TotalChars { get { return LineLength * lines; } } + internal int LineLength { get { return game.Server.SupportsPartialMessages ? 64 : 62; } } + internal int TotalChars { get { return LineLength * lines; } } public override void Init() { X = 5; @@ -98,7 +102,7 @@ namespace ClassicalSharp.Gui.Widgets { CalculateCaretData(); } - void CalculateCaretData() { + internal void CalculateCaretData() { if( caretPos >= buffer.Length ) caretPos = -1; buffer.MakeCoords( caretPos, partLens, out indexX, out indexY ); DrawTextArgs args = new DrawTextArgs( null, font, true ); @@ -285,5 +289,25 @@ namespace ClassicalSharp.Gui.Widgets { } Recreate(); } + + + public override bool HandlesKeyPress( char key ) { + if( game.HideGui ) return true; + + if( Utils.IsValidInputChar( key, game ) ) { + AppendChar( key ); + return true; + } + return false; + } + + public override bool HandlesKeyDown( Key key ) { + if( game.HideGui ) return key < Key.F1 || key > Key.F35; + return inputHandler.HandlesKeyDown( key ); + } + + public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) { + return inputHandler.HandlesMouseClick( mouseX, mouseY, button ); + } } } \ No newline at end of file diff --git a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs b/ClassicalSharp/2D/Widgets/Chat/InputWidgetHandler.cs similarity index 58% rename from ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs rename to ClassicalSharp/2D/Widgets/Chat/InputWidgetHandler.cs index 2bdf5dc96..b5ea208c9 100644 --- a/ClassicalSharp/2D/Widgets/Chat/TextInputWidget.Handlers.cs +++ b/ClassicalSharp/2D/Widgets/Chat/InputWidgetHandler.cs @@ -6,21 +6,17 @@ using ClassicalSharp.Entities; using OpenTK.Input; namespace ClassicalSharp.Gui.Widgets { - public sealed partial class TextInputWidget : Widget { + public sealed class InputWidgetHandler { - public override bool HandlesKeyPress( char key ) { - if( game.HideGui ) return true; - - if( IsValidInputChar( key ) ) { - AppendChar( key ); - return true; - } - return false; + Game game; + InputWidget w; + + public InputWidgetHandler( Game game, InputWidget w ) { + this.game = game; + this.w = w; } - public override bool HandlesKeyDown( Key key ) { - if( game.HideGui ) - return key < Key.F1 || key > Key.F35; + public bool HandlesKeyDown( Key key ) { bool clipboardDown = OpenTK.Configuration.RunningOnMacOS ? (game.IsKeyDown( Key.WinLeft ) || game.IsKeyDown( Key.WinRight )) : (game.IsKeyDown( Key.ControlLeft ) || game.IsKeyDown( Key.ControlRight )); @@ -40,9 +36,9 @@ namespace ClassicalSharp.Gui.Widgets { } void TabKey() { - int pos = caretPos == -1 ? buffer.Length - 1 : caretPos; + int pos = w.caretPos == -1 ? w.buffer.Length - 1 : w.caretPos; int start = pos; - char[] value = buffer.value; + char[] value = w.buffer.value; while( start >= 0 && IsNameChar( value[start] ) ) start--; @@ -64,12 +60,12 @@ namespace ClassicalSharp.Gui.Widgets { } if( matches.Count == 1 ) { - if( caretPos == -1 ) pos++; + if( w.caretPos == -1 ) pos++; int len = pos - start; for( int i = 0; i < len; i++ ) - buffer.DeleteAt( start ); - if( caretPos != -1 ) caretPos -= len; - AppendText( matches[0] ); + w.buffer.DeleteAt( start ); + if( w.caretPos != -1 ) w.caretPos -= len; + w.AppendText( matches[0] ); } else if( matches.Count > 1 ) { StringBuffer sb = new StringBuffer( Utils.StringLength ); int index = 0; @@ -94,149 +90,148 @@ namespace ClassicalSharp.Gui.Widgets { void BackspaceKey( bool controlDown ) { if( controlDown ) { - if( caretPos == -1 ) caretPos = buffer.Length - 1; - int len = buffer.GetBackLength( caretPos ); + if( w.caretPos == -1 ) w.caretPos = w.buffer.Length - 1; + int len = w.buffer.GetBackLength( w.caretPos ); if( len == 0 ) return; - caretPos -= len; - if( caretPos < 0 ) caretPos = 0; + w.caretPos -= len; + if( w.caretPos < 0 ) w.caretPos = 0; for( int i = 0; i <= len; i++ ) - buffer.DeleteAt( caretPos ); + w.buffer.DeleteAt( w.caretPos ); - if( caretPos >= buffer.Length ) caretPos = -1; - if( caretPos == -1 && buffer.Length > 0 ) { - buffer.value[buffer.Length] = ' '; - } else if( caretPos >= 0 && buffer.value[caretPos] != ' ' ) { - buffer.InsertAt( caretPos, ' ' ); + if( w.caretPos >= w.buffer.Length ) w.caretPos = -1; + if( w.caretPos == -1 && w.buffer.Length > 0 ) { + w.buffer.value[w.buffer.Length] = ' '; + } else if( w.caretPos >= 0 && w.buffer.value[w.caretPos] != ' ' ) { + w.buffer.InsertAt( w.caretPos, ' ' ); } - Recreate(); - } else if( !buffer.Empty && caretPos != 0 ) { - int index = caretPos == -1 ? buffer.Length - 1 : caretPos; + w.Recreate(); + } else if( !w.buffer.Empty && w.caretPos != 0 ) { + int index = w.caretPos == -1 ? w.buffer.Length - 1 : w.caretPos; if( CheckColour( index - 1 ) ) { DeleteChar(); // backspace XYZ%e to XYZ } else if( CheckColour( index - 2 ) ) { DeleteChar(); DeleteChar(); // backspace XYZ%eH to XYZ } DeleteChar(); - Recreate(); + w.Recreate(); } } bool CheckColour( int index ) { if( index < 0 ) return false; - char code = buffer.value[index], col = buffer.value[index + 1]; + char code = w.buffer.value[index], col = w.buffer.value[index + 1]; return (code == '%' || code == '&') && game.Drawer2D.ValidColour( col ); } void DeleteChar() { - if( caretPos == -1 ) { - buffer.DeleteAt( buffer.Length - 1 ); + if( w.caretPos == -1 ) { + w.buffer.DeleteAt( w.buffer.Length - 1 ); } else { - caretPos--; - buffer.DeleteAt( caretPos ); + w.caretPos--; + w.buffer.DeleteAt( w.caretPos ); } } void DeleteKey() { - if( !buffer.Empty && caretPos != -1 ) { - buffer.DeleteAt( caretPos ); - if( caretPos >= buffer.Length ) caretPos = -1; - Recreate(); + if( !w.buffer.Empty && w.caretPos != -1 ) { + w.buffer.DeleteAt( w.caretPos ); + if( w.caretPos >= w.buffer.Length ) w.caretPos = -1; + w.Recreate(); } } void LeftKey( bool controlDown ) { if( controlDown ) { - if( caretPos == -1 ) - caretPos = buffer.Length - 1; - caretPos -= buffer.GetBackLength( caretPos ); - CalculateCaretData(); + if( w.caretPos == -1 ) + w.caretPos = w.buffer.Length - 1; + w.caretPos -= w.buffer.GetBackLength( w.caretPos ); + w.CalculateCaretData(); return; } - if( !buffer.Empty ) { - if( caretPos == -1 ) caretPos = buffer.Length; - caretPos--; - if( caretPos < 0 ) caretPos = 0; - CalculateCaretData(); + if( !w.buffer.Empty ) { + if( w.caretPos == -1 ) w.caretPos = w.buffer.Length; + w.caretPos--; + if( w.caretPos < 0 ) w.caretPos = 0; + w.CalculateCaretData(); } } void RightKey( bool controlDown ) { if( controlDown ) { - caretPos += buffer.GetForwardLength( caretPos ); - if( caretPos >= buffer.Length ) caretPos = -1; - CalculateCaretData(); + w.caretPos += w.buffer.GetForwardLength( w.caretPos ); + if( w.caretPos >= w.buffer.Length ) w.caretPos = -1; + w.CalculateCaretData(); return; } - if( !buffer.Empty && caretPos != -1 ) { - caretPos++; - if( caretPos >= buffer.Length ) caretPos = -1; - CalculateCaretData(); + if( !w.buffer.Empty && w.caretPos != -1 ) { + w.caretPos++; + if( w.caretPos >= w.buffer.Length ) w.caretPos = -1; + w.CalculateCaretData(); } } - - string originalText; + void UpKey( bool controlDown ) { if( controlDown ) { - int pos = caretPos == -1 ? buffer.Length : caretPos; - if( pos < LineLength ) return; + int pos = w.caretPos == -1 ? w.buffer.Length : w.caretPos; + if( pos < w.LineLength ) return; - caretPos = pos - LineLength; - CalculateCaretData(); + w.caretPos = pos - w.LineLength; + w.CalculateCaretData(); return; } - if( typingLogPos == game.Chat.InputLog.Count ) - originalText = buffer.ToString(); + if( w.typingLogPos == game.Chat.InputLog.Count ) + w.originalText = w.buffer.ToString(); if( game.Chat.InputLog.Count > 0 ) { - typingLogPos--; - if( typingLogPos < 0 ) typingLogPos = 0; - buffer.Clear(); - buffer.Append( 0, game.Chat.InputLog[typingLogPos] ); - caretPos = -1; - Recreate(); + w.typingLogPos--; + if( w.typingLogPos < 0 ) w.typingLogPos = 0; + w.buffer.Clear(); + w.buffer.Append( 0, game.Chat.InputLog[w.typingLogPos] ); + w.caretPos = -1; + w.Recreate(); } } void DownKey( bool controlDown ) { if( controlDown ) { - if( caretPos == -1 || caretPos >= (lines - 1) * LineLength ) return; - caretPos += LineLength; - CalculateCaretData(); + if( w.caretPos == -1 || w.caretPos >= (w.parts.Length - 1) * w.LineLength ) return; + w.caretPos += w.LineLength; + w.CalculateCaretData(); return; } if( game.Chat.InputLog.Count > 0 ) { - typingLogPos++; - buffer.Clear(); - if( typingLogPos >= game.Chat.InputLog.Count ) { - typingLogPos = game.Chat.InputLog.Count; - if( originalText != null ) - buffer.Append( 0, originalText ); + w.typingLogPos++; + w.buffer.Clear(); + if( w.typingLogPos >= game.Chat.InputLog.Count ) { + w.typingLogPos = game.Chat.InputLog.Count; + if( w.originalText != null ) + w.buffer.Append( 0, w.originalText ); } else { - buffer.Append( 0, game.Chat.InputLog[typingLogPos] ); + w.buffer.Append( 0, game.Chat.InputLog[w.typingLogPos] ); } - caretPos = -1; - Recreate(); + w.caretPos = -1; + w.Recreate(); } } void HomeKey() { - if( buffer.Empty ) return; - caretPos = 0; - CalculateCaretData(); + if( w.buffer.Empty ) return; + w.caretPos = 0; + w.CalculateCaretData(); } void EndKey() { - caretPos = -1; - CalculateCaretData(); + w.caretPos = -1; + w.CalculateCaretData(); } static char[] trimChars = {'\r', '\n', '\v', '\f', ' ', '\t', '\0'}; bool OtherKey( Key key ) { - if( key == Key.V && buffer.Length < TotalChars ) { + if( key == Key.V && w.buffer.Length < w.TotalChars ) { string text = null; try { text = game.window.ClipboardText.Trim( trimChars ); @@ -251,18 +246,18 @@ namespace ClassicalSharp.Gui.Widgets { game.Chat.Add( null, MessageType.ClientStatus4 ); for( int i = 0; i < text.Length; i++ ) { - if( IsValidInputChar( text[i] ) ) continue; + if( Utils.IsValidInputChar( text[i], game ) ) continue; const string warning = "&eClipboard contained some characters that can't be sent."; game.Chat.Add( warning, MessageType.ClientStatus4 ); text = RemoveInvalidChars( text ); break; } - AppendText( text ); + w.AppendText( text ); return true; } else if( key == Key.C ) { - if( buffer.Empty ) return true; + if( w.buffer.Empty ) return true; try { - game.window.ClipboardText = buffer.ToString(); + game.window.ClipboardText = w.buffer.ToString(); } catch( Exception ex ) { ErrorHandler.LogError( "Copy to clipboard", ex ); const string warning = "&cError while trying to copy to clipboard."; @@ -278,28 +273,28 @@ namespace ClassicalSharp.Gui.Widgets { int length = 0; for( int i = 0; i < input.Length; i++ ) { char c = input[i]; - if( !IsValidInputChar( c ) ) continue; + if( !Utils.IsValidInputChar( c, game ) ) continue; chars[length++] = c; } return new String( chars, 0, length ); } - public override bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) { + public bool HandlesMouseClick( int mouseX, int mouseY, MouseButton button ) { if( button == MouseButton.Left ) SetCaretToCursor( mouseX, mouseY ); return true; } unsafe void SetCaretToCursor( int mouseX, int mouseY ) { - mouseX -= inputTex.X1; mouseY -= inputTex.Y1; - DrawTextArgs args = new DrawTextArgs( null, font, true ); + mouseX -= w.inputTex.X1; mouseY -= w.inputTex.Y1; + DrawTextArgs args = new DrawTextArgs( null, w.font, true ); IDrawer2D drawer = game.Drawer2D; - int offset = 0, elemHeight = defaultHeight; + int offset = 0, elemHeight = w.defaultHeight; string oneChar = new String( 'A', 1 ); - for( int y = 0; y < lines; y++ ) { - string line = parts[y]; - int xOffset = y == 0 ? defaultWidth : 0; + for( int y = 0; y < w.parts.Length; y++ ) { + string line = w.parts[y]; + int xOffset = y == 0 ? w.defaultWidth : 0; if( line == null ) continue; for( int x = 0; x < line.Length; x++ ) { @@ -311,15 +306,15 @@ namespace ClassicalSharp.Gui.Widgets { args.Text = oneChar; int elemWidth = drawer.MeasureChatSize( ref args ).Width; - if( Contains( trimmedWidth, y * elemHeight, elemWidth, elemHeight, mouseX, mouseY ) ) { - caretPos = offset + x; - CalculateCaretData(); return; + if( GuiElement.Contains( trimmedWidth, y * elemHeight, elemWidth, elemHeight, mouseX, mouseY ) ) { + w.caretPos = offset + x; + w.CalculateCaretData(); return; } } offset += line.Length; } - caretPos = -1; - CalculateCaretData(); + w.caretPos = -1; + w.CalculateCaretData(); } } } \ No newline at end of file diff --git a/ClassicalSharp/Utils/Utils.cs b/ClassicalSharp/Utils/Utils.cs index fc865ad2d..45a8b9623 100644 --- a/ClassicalSharp/Utils/Utils.cs +++ b/ClassicalSharp/Utils/Utils.cs @@ -168,7 +168,7 @@ namespace ClassicalSharp { int http = value.IndexOf( "http://", index ); int https = value.IndexOf( "https://", index ); return http == index || https == index; - } + } /// Conversion for code page 437 characters from index 0 to 31 to unicode. public const string ControlCharReplacements = "\0☺☻♥♦♣♠•◘○◙♂♀♪♫☼►◄↕‼¶§▬↨↑↓→←∟↔▲▼"; @@ -182,7 +182,7 @@ namespace ClassicalSharp { fixed( char* ptr = value ) { for( int i = 0; i < value.Length; i++ ) { char c = ptr[i]; - if( c < 'A' || c > 'Z' ) continue; + if( c < 'A' || c > 'Z' ) continue; c += ' '; ptr[i] = c; } } @@ -193,7 +193,7 @@ namespace ClassicalSharp { public static bool TryParseDecimal( string s, out float result ) { result = 0; float temp; - const NumberStyles style = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite + const NumberStyles style = NumberStyles.AllowLeadingWhite | NumberStyles.AllowTrailingWhite | NumberStyles.AllowLeadingSign | NumberStyles.AllowDecimalPoint; if( !Single.TryParse( s, style, NumberFormatInfo.InvariantInfo, out temp ) ) return false; @@ -201,5 +201,15 @@ namespace ClassicalSharp { result = temp; return true; } + + + public static bool IsValidInputChar( char c, Game game ) { + if( c >= ' ' && c <= '~' ) return true; // ascii + + bool isCP437 = Utils.ControlCharReplacements.IndexOf( c ) >= 0 || + Utils.ExtendedCharReplacements.IndexOf( c ) >= 0; + bool supportsCP437 = game.Server.SupportsFullCP437; + return supportsCP437 && isCP437; + } } } \ No newline at end of file