From fc4e8c7e56e517bcb6ae64a04762154bd3bd8120 Mon Sep 17 00:00:00 2001 From: UnknownShadow200 Date: Sat, 24 Oct 2015 12:33:37 +1100 Subject: [PATCH] Rope now uses its actual bounding box for collision detection, add clipboard support to new launcher, add clearing input support to new launcher. General cleanup of new launcher too. --- ClassicalSharp/Entities/Entity.cs | 4 +- ClassicalSharp/Entities/LocalPlayer.cs | 2 +- ClassicalSharp/Rendering/MapEnvRenderer.cs | 44 +++++--- Launcher2/Gui/Screens/ClassiCubeScreen.cs | 54 +++------ .../Gui/Screens/ClassiCubeServersScreen.cs | 78 ++++++------- Launcher2/Gui/Screens/DirectConnectScreen.cs | 24 ++-- Launcher2/Gui/Screens/LauncherInputScreen.cs | 75 +++++++++---- Launcher2/Gui/Screens/LauncherScreen.cs | 23 +++- Launcher2/Gui/Screens/ResourcesScreen.cs | 28 ++--- .../TableWidget/LauncherTableWidget.Input.cs | 1 - .../Gui/TableWidget/LauncherTableWidget.cs | 2 + Launcher2/Gui/Widgets/LauncherInputWidget.cs | 103 ++++++++++++++++++ ...erTextWidget.cs => LauncherLabelWidget.cs} | 5 +- .../Gui/Widgets/LauncherTextInputWidget.cs | 55 ---------- Launcher2/Launcher2.csproj | 4 +- Launcher2/LauncherWindow.cs | 2 +- 16 files changed, 284 insertions(+), 220 deletions(-) create mode 100644 Launcher2/Gui/Widgets/LauncherInputWidget.cs rename Launcher2/Gui/Widgets/{LauncherTextWidget.cs => LauncherLabelWidget.cs} (75%) delete mode 100644 Launcher2/Gui/Widgets/LauncherTextInputWidget.cs diff --git a/ClassicalSharp/Entities/Entity.cs b/ClassicalSharp/Entities/Entity.cs index 11621bcfa..034621525 100644 --- a/ClassicalSharp/Entities/Entity.cs +++ b/ClassicalSharp/Entities/Entity.cs @@ -66,8 +66,8 @@ namespace ClassicalSharp { byte block = game.Map.GetBlock( x, y, z ); if( condition( block ) ) { float blockHeight = info.Height[block]; - Vector3 min = new Vector3( x, y, z ); - Vector3 max = new Vector3( x + 1, y + blockHeight, z + 1 ); + Vector3 min = new Vector3( x, y, z ) + info.MinBB[block]; + Vector3 max = new Vector3( x, y, z ) + info.MaxBB[block]; BoundingBox blockBB = new BoundingBox( min, max ); if( blockBB.Intersects( bounds ) ) return true; } diff --git a/ClassicalSharp/Entities/LocalPlayer.cs b/ClassicalSharp/Entities/LocalPlayer.cs index d5c0ec48a..87a025881 100644 --- a/ClassicalSharp/Entities/LocalPlayer.cs +++ b/ClassicalSharp/Entities/LocalPlayer.cs @@ -165,7 +165,7 @@ namespace ClassicalSharp { } else if( TouchesAnyRope() && !flying && !noClip ) { Move( xMoving, zMoving, 0.02f * 1.7f, ropeDrag, ropeGrav, 1 ); } else { - float factor = !flying && onGround ? 0.1f : 0.02f; + float factor = !(flying || noClip) && onGround ? 0.1f : 0.02f; float gravity = useLiquidGravity ? liquidGrav : normalGrav; Move( xMoving, zMoving, factor * horMul, normalDrag, gravity, yMul ); diff --git a/ClassicalSharp/Rendering/MapEnvRenderer.cs b/ClassicalSharp/Rendering/MapEnvRenderer.cs index c5a13850f..2bf6831e7 100644 --- a/ClassicalSharp/Rendering/MapEnvRenderer.cs +++ b/ClassicalSharp/Rendering/MapEnvRenderer.cs @@ -20,7 +20,7 @@ namespace ClassicalSharp { int sidesVb = -1, edgesVb = -1; int edgeTexId, sideTexId; - int sidesVertices, edgesVertices, + int sidesVertices, edgesVertices, edgesBaseVertices, edgesVerVertices; bool legacy; @@ -48,16 +48,18 @@ namespace ClassicalSharp { graphics.BindTexture( sideTexId ); graphics.BeginVbBatch( VertexFormat.Pos3fTex2fCol4b ); graphics.BindVb( sidesVb ); - graphics.DrawIndexedVb_TrisT2fC4b( sidesVertices * 6 / 4, 0 ); + graphics.DrawIndexedVb_TrisT2fC4b( sidesVertices * 6 / 4, 0 ); graphics.AlphaBlending = true; graphics.BindTexture( edgeTexId ); graphics.BindVb( edgesVb ); + // Do not draw water when we cannot see it. // Fixes some 'depth bleeding through' issues with 16 bit depth buffers on large maps. Vector3 eyePos = game.LocalPlayer.EyePosition; - if( game.Camera.GetCameraPos( eyePos ).Y >= 0 ) { - graphics.DrawIndexedVb_TrisT2fC4b( edgesVertices * 6 / 4, 0 ); + float yVisible = Math.Min( 0, map.GroundHeight ); + if( game.Camera.GetCameraPos( eyePos ).Y >= yVisible ) { + graphics.DrawIndexedVb_TrisT2fC4b( edgesVertices * 6 / 4, 0 ); } else { graphics.DrawIndexedVb_TrisT2fC4b( edgesVerVertices * 6 / 4, edgesBaseVertices * 6 / 4 ); } @@ -127,8 +129,8 @@ namespace ClassicalSharp { sidesVertices += Utils.CountVertices( rec.Width, rec.Height, axisSize ); // YPlanes outside } sidesVertices += Utils.CountVertices( map.Width, map.Length, axisSize ); // YPlane beneath map - sidesVertices += 2 * Utils.CountVertices( map.Width, groundLevel, axisSize ); // ZPlanes - sidesVertices += 2 * Utils.CountVertices( map.Length, groundLevel, axisSize ); // XPlanes + sidesVertices += 2 * Utils.CountVertices( map.Width, Math.Abs( groundLevel ), axisSize ); // ZPlanes + sidesVertices += 2 * Utils.CountVertices( map.Length, Math.Abs( groundLevel ), axisSize ); // XPlanes VertexPos3fTex2fCol4b* vertices = stackalloc VertexPos3fTex2fCol4b[sidesVertices]; IntPtr ptr = (IntPtr)vertices; @@ -136,11 +138,17 @@ namespace ClassicalSharp { foreach( Rectangle rec in rects ) { DrawY( rec.X, rec.Y, rec.X + rec.Width, rec.Y + rec.Height, groundLevel, axisSize, col, ref vertices ); } + // Work properly for when ground level is below 0 + int y1 = 0, y2 = groundLevel; + if( groundLevel < 0 ) { + y1 = groundLevel; + y2 = 0; + } DrawY( 0, 0, map.Width, map.Length, 0, axisSize, col, ref vertices ); - DrawZ( 0, 0, map.Width, 0, groundLevel, axisSize, col, ref vertices ); - DrawZ( map.Length, 0, map.Width, 0, groundLevel, axisSize, col, ref vertices ); - DrawX( 0, 0, map.Length, 0, groundLevel, axisSize, col, ref vertices ); - DrawX( map.Width, 0, map.Length, 0, groundLevel, axisSize, col, ref vertices ); + DrawZ( 0, 0, map.Width, y1, y2, axisSize, col, ref vertices ); + DrawZ( map.Length, 0, map.Width, y1, y2, axisSize, col, ref vertices ); + DrawX( 0, 0, map.Length, y1, y2, axisSize, col, ref vertices ); + DrawX( map.Width, 0, map.Length, y1, y2, axisSize, col, ref vertices ); sidesVb = graphics.CreateVb( ptr, VertexFormat.Pos3fTex2fCol4b, sidesVertices ); } @@ -150,8 +158,10 @@ namespace ClassicalSharp { edgesVertices += Utils.CountVertices( rec.Width, rec.Height, axisSize ); // YPlanes outside } edgesBaseVertices = edgesVertices; - edgesVertices += 2 * Utils.CountVertices( map.Width, 2, axisSize ); // ZPlanes - edgesVertices += 2 * Utils.CountVertices( map.Length, 2, axisSize ); // XPlanes + if( waterLevel >= 0 ) { + edgesVertices += 2 * Utils.CountVertices( map.Width, 2, axisSize ); // ZPlanes + edgesVertices += 2 * Utils.CountVertices( map.Length, 2, axisSize ); // XPlanes + } edgesVerVertices = edgesVertices - edgesBaseVertices; VertexPos3fTex2fCol4b* vertices = stackalloc VertexPos3fTex2fCol4b[edgesVertices]; IntPtr ptr = (IntPtr)vertices; @@ -160,10 +170,12 @@ namespace ClassicalSharp { foreach( Rectangle rec in rects ) { DrawY( rec.X, rec.Y, rec.X + rec.Width, rec.Y + rec.Height, waterLevel, axisSize, game.Map.Sunlight, ref vertices ); } - DrawZ( 0, 0, map.Width, waterLevel - 2, waterLevel, axisSize, col, ref vertices ); - DrawZ( map.Length, 0, map.Width, waterLevel - 2, waterLevel, axisSize, col, ref vertices ); - DrawX( 0, 0, map.Length, waterLevel - 2, waterLevel, axisSize, col, ref vertices ); - DrawX( map.Width, 0, map.Length, waterLevel - 2, waterLevel, axisSize, col, ref vertices ); + if( waterLevel >= 0 ) { + DrawZ( 0, 0, map.Width, waterLevel - 2, waterLevel, axisSize, col, ref vertices ); + DrawZ( map.Length, 0, map.Width, waterLevel - 2, waterLevel, axisSize, col, ref vertices ); + DrawX( 0, 0, map.Length, waterLevel - 2, waterLevel, axisSize, col, ref vertices ); + DrawX( map.Width, 0, map.Length, waterLevel - 2, waterLevel, axisSize, col, ref vertices ); + } edgesVb = graphics.CreateVb( ptr, VertexFormat.Pos3fTex2fCol4b, edgesVertices ); } diff --git a/Launcher2/Gui/Screens/ClassiCubeScreen.cs b/Launcher2/Gui/Screens/ClassiCubeScreen.cs index e70fc0e51..7543dcf31 100644 --- a/Launcher2/Gui/Screens/ClassiCubeScreen.cs +++ b/Launcher2/Gui/Screens/ClassiCubeScreen.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; using System.Drawing; using System.IO; using System.Net; using ClassicalSharp; -using OpenTK; -using OpenTK.Input; namespace Launcher2 { @@ -87,19 +84,22 @@ namespace Launcher2 { void Draw() { widgetIndex = 0; - MakeTextAt( "Username", -180, -100 ); - MakeTextAt( "Password", -180, -50 ); + MakeTextAt( "Username", titleFont, -180, -100 ); + MakeTextAt( "Password", titleFont, -180, -50 ); - MakeTextInputAt( false, Get( widgetIndex ), 30, -100 ); - MakeTextInputAt( true, Get( widgetIndex ), 30, -50 ); + MakeInput( Get(), 300, Anchor.Centre, false, 30, -100, 32 ); + MakeInput( Get(), 300, Anchor.Centre, true, 30, -50, 32 ); - MakeButtonAt( "Sign in", 90, 35, -75, 0, StartClient ); - MakeButtonAt( "Back", 80, 35, 140, 0, (x, y) => game.SetScreen( new MainScreen( game ) ) ); - string text = widgets[6] == null ? "" : ((LauncherTextWidget)widgets[6]).Text; - MakeTextAt( text, 0, 50 ); + MakeButtonAt( "Sign in", 90, 35, titleFont, Anchor.Centre, + -75, 0, StartClient ); + MakeButtonAt( "Back", 80, 35, titleFont, Anchor.Centre, + 140, 0, (x, y) => game.SetScreen( new MainScreen( game ) ) ); + string text = widgets[6] == null ? "" : ((LauncherLabelWidget)widgets[6]).Text; + MakeTextAt( text, inputFont, 0, 50 ); if( HasServers && !signingIn ) - MakeButtonAt( "Servers", 90, 35, 35, 0, ShowServers ); + MakeButtonAt( "Servers", 90, 35, titleFont, Anchor.Centre, + 35, 0, ShowServers ); } string lastStatus; @@ -107,38 +107,18 @@ namespace Launcher2 { lastStatus = text; using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - LauncherTextWidget widget = (LauncherTextWidget)widgets[6]; + LauncherLabelWidget widget = (LauncherLabelWidget)widgets[6]; - drawer.Clear( LauncherWindow.clearColour, widget.X, widget.Y, + drawer.Clear( game.clearColour, widget.X, widget.Y, widget.Width, widget.Height ); widget.DrawAt( drawer, text, inputFont, Anchor.Centre, Anchor.Centre, 0, 50 ); Dirty = true; } } - void MakeTextAt( string text, int x, int y ) { - LauncherTextWidget widget = new LauncherTextWidget( game, text ); - widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y ); - widgets[widgetIndex++] = widget; - } - - void MakeTextInputAt( bool password, string text, int x, int y ) { - LauncherTextInputWidget widget = new LauncherTextInputWidget( game ); - widget.OnClick = InputClick; - widget.Password = password; - - widget.DrawAt( drawer, text, inputFont, Anchor.Centre, Anchor.Centre, 300, 30, x, y ); - widgets[widgetIndex++] = widget; - } - - void MakeButtonAt( string text, int width, int height, - int x, int y, Action onClick ) { - LauncherButtonWidget widget = new LauncherButtonWidget( game ); - widget.Text = text; - widget.OnClick = onClick; - - widget.Active = false; - widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, width, height, x, y ); + void MakeTextAt( string text, Font font, int x, int y ) { + LauncherLabelWidget widget = new LauncherLabelWidget( game, text ); + widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.Centre, x, y ); widgets[widgetIndex++] = widget; } diff --git a/Launcher2/Gui/Screens/ClassiCubeServersScreen.cs b/Launcher2/Gui/Screens/ClassiCubeServersScreen.cs index 963c9775b..4b75b7079 100644 --- a/Launcher2/Gui/Screens/ClassiCubeServersScreen.cs +++ b/Launcher2/Gui/Screens/ClassiCubeServersScreen.cs @@ -1,7 +1,5 @@ using System; -using System.Collections.Generic; using System.Drawing; -using System.Net; using ClassicalSharp; using OpenTK.Input; @@ -13,8 +11,8 @@ namespace Launcher2 { public ClassiCubeServersScreen( LauncherWindow game ) : base( game ) { titleFont = new Font( "Arial", 16, FontStyle.Bold ); inputFont = new Font( "Arial", 13, FontStyle.Regular ); - enterIndex = 4; - widgets = new LauncherWidget[7]; + enterIndex = 4; + widgets = new LauncherWidget[7]; } public override void Tick() { @@ -23,13 +21,13 @@ namespace Launcher2 { protected override void MouseMove( object sender, MouseMoveEventArgs e ) { base.MouseMove( sender, e ); if( selectedWidget != null && selectedWidget == widgets[tableIndex] ) { - LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + LauncherTableWidget table = (LauncherTableWidget)widgets[tableIndex]; table.MouseMove( e.XDelta, e.YDelta ); } } void MouseButtonUp( object sender, MouseButtonEventArgs e ) { - LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + LauncherTableWidget table = (LauncherTableWidget)widgets[tableIndex]; table.DraggingWidth = false; } @@ -39,24 +37,24 @@ namespace Launcher2 { void FilterList() { if( lastInput == widgets[1] ) { - LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + LauncherTableWidget table = (LauncherTableWidget)widgets[tableIndex]; table.FilterEntries( lastInput.Text ); ClampIndex(); Resize(); } } - public override void Init() { + public override void Init() { base.Init(); game.Window.Mouse.WheelChanged += MouseWheelChanged; game.Window.Mouse.ButtonUp += MouseButtonUp; - Resize(); + Resize(); } public override void Resize() { using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - drawer.Clear( LauncherWindow.clearColour ); + drawer.Clear( game.clearColour ); Draw(); } Dirty = true; @@ -64,53 +62,27 @@ namespace Launcher2 { void Draw() { widgetIndex = 0; - int lastIndex = GetLastInputIndex(); MakeTextAt( titleFont, "Search", -200, 10 ); - MakeTextInputAt( Get( widgetIndex ), 270, -25, 5 ); + MakeInput( Get(), 270, Anchor.LeftOrTop, false, -25, 5, 32 ); MakeTextAt( inputFont, "../play/", -210, 55 ); - MakeTextInputAt( Get( 3 ), 320, -20, 50 ); + MakeInput( Get(), 320, Anchor.LeftOrTop, false, -20, 50, 32 ); + ((LauncherInputWidget)widgets[3]).ClipboardFilter = HashFilter; - MakeButtonAt( "Connect", 100, 30, 180, 5, ConnectToServer ); - MakeButtonAt( "Back", 70, 30, 195, 50, - (x, y) => game.SetScreen( new MainScreen( game ) ) ); + MakeButtonAt( "Connect", 100, 30, titleFont, Anchor.LeftOrTop, + 180, 5, ConnectToServer ); + MakeButtonAt( "Back", 70, 30, titleFont, Anchor.LeftOrTop, + 195, 50, (x, y) => game.SetScreen( new MainScreen( game ) ) ); MakeTableWidget(); - - if( lastIndex >= 0 ) - lastInput = widgets[lastIndex] as LauncherTextInputWidget; - } - - int GetLastInputIndex() { - return lastInput == null ? -1 : - Array.IndexOf( widgets, lastInput ); } void MakeTextAt( Font font, string text, int x, int y ) { - LauncherTextWidget widget = new LauncherTextWidget( game, text ); + LauncherLabelWidget widget = new LauncherLabelWidget( game, text ); widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.LeftOrTop, x, y ); widgets[widgetIndex++] = widget; } - void MakeTextInputAt( string text, int width, int x, int y ) { - LauncherTextInputWidget widget = new LauncherTextInputWidget( game ); - widget.OnClick = InputClick; - - widget.DrawAt( drawer, text, inputFont, Anchor.Centre, Anchor.LeftOrTop, width, 30, x, y ); - widgets[widgetIndex++] = widget; - } - - void MakeButtonAt( string text, int width, int height, - int x, int y, Action onClick ) { - LauncherButtonWidget widget = new LauncherButtonWidget( game ); - widget.Text = text; - widget.OnClick = onClick; - - widget.Active = false; - widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.LeftOrTop, width, height, x, y ); - widgets[widgetIndex++] = widget; - } - void MakeTableWidget() { if( widgets[tableIndex] != null ) { LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; @@ -141,20 +113,34 @@ namespace Launcher2 { } void MouseWheelChanged( object sender, MouseWheelEventArgs e ) { - LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + LauncherTableWidget table = (LauncherTableWidget)widgets[tableIndex]; table.CurrentIndex -= e.Delta; ClampIndex(); Resize(); } void ClampIndex() { - LauncherTableWidget table = widgets[tableIndex] as LauncherTableWidget; + LauncherTableWidget table = (LauncherTableWidget)widgets[tableIndex]; if( table.CurrentIndex >= table.Count ) table.CurrentIndex = table.Count - 1; if( table.CurrentIndex < 0 ) table.CurrentIndex = 0; } + string HashFilter( string input ) { + // Server url look like http://www.classicube.net/server/play/aaaaa/ + + // Trim off the last / if it exists + if( input[input.Length - 1] == '/' ) + input = input.Substring( 0, input.Length - 1 ); + + // Trim the parts before the hash + int lastIndex = input.LastIndexOf( '/' ); + if( lastIndex >= 0 ) + input = input.Substring( lastIndex + 1 ); + return input; + } + public override void Dispose() { base.Dispose(); game.Window.Mouse.WheelChanged -= MouseWheelChanged; diff --git a/Launcher2/Gui/Screens/DirectConnectScreen.cs b/Launcher2/Gui/Screens/DirectConnectScreen.cs index 77f2fd67d..8162d517c 100644 --- a/Launcher2/Gui/Screens/DirectConnectScreen.cs +++ b/Launcher2/Gui/Screens/DirectConnectScreen.cs @@ -3,8 +3,6 @@ using System.Drawing; using System.IO; using System.Net; using ClassicalSharp; -using OpenTK; -using OpenTK.Input; namespace Launcher2 { @@ -12,7 +10,7 @@ namespace Launcher2 { public DirectConnectScreen( LauncherWindow game ) : base( game ) { titleFont = new Font( "Arial", 15, FontStyle.Bold ); - inputFont = new Font( "Arial", 15, FontStyle.Regular ); + inputFont = new Font( "Arial", 14, FontStyle.Regular ); enterIndex = 6; widgets = new LauncherWidget[9]; } @@ -69,9 +67,9 @@ namespace Launcher2 { MakeTextAt( "Address", -180, -50 ); MakeTextAt( "Mppass", -180, 0 ); - MakeTextInputAt( Get( widgetIndex ), 30, -100 ); - MakeTextInputAt( Get( widgetIndex ), 30, -50 ); - MakeTextInputAt( Get( widgetIndex ), 30, 0 ); + MakeInput( Get(), 300, Anchor.Centre, false, 30, -100, 32 ); + MakeInput( Get(), 300, Anchor.Centre, false, 30, -50, 64 ); + MakeInput( Get(), 300, Anchor.Centre, false, 30, 0, 32 ); MakeButtonAt( "Connect", 110, 35, -65, 50, StartClient ); MakeButtonAt( "Back", 80, 35, 140, 50, (x, y) => game.SetScreen( new MainScreen( game ) ) ); @@ -81,8 +79,8 @@ namespace Launcher2 { void SetStatus( string text ) { using( drawer ) { drawer.SetBitmap( game.Framebuffer ); - LauncherTextWidget widget = (LauncherTextWidget)widgets[8]; - drawer.Clear( LauncherWindow.clearColour, widget.X, widget.Y, + LauncherLabelWidget widget = (LauncherLabelWidget)widgets[8]; + drawer.Clear( game.clearColour, widget.X, widget.Y, widget.Width, widget.Height ); widget.DrawAt( drawer, text, inputFont, Anchor.Centre, Anchor.Centre, 0, 100 ); Dirty = true; @@ -90,19 +88,11 @@ namespace Launcher2 { } void MakeTextAt( string text, int x, int y ) { - LauncherTextWidget widget = new LauncherTextWidget( game, text ); + LauncherLabelWidget widget = new LauncherLabelWidget( game, text ); widget.DrawAt( drawer, text, titleFont, Anchor.Centre, Anchor.Centre, x, y ); widgets[widgetIndex++] = widget; } - void MakeTextInputAt( string text, int x, int y ) { - LauncherTextInputWidget widget = new LauncherTextInputWidget( game ); - widget.OnClick = InputClick; - - widget.DrawAt( drawer, text, inputFont, Anchor.Centre, Anchor.Centre, 300, 30, x, y ); - widgets[widgetIndex++] = widget; - } - void MakeButtonAt( string text, int width, int height, int x, int y, Action onClick ) { LauncherButtonWidget widget = new LauncherButtonWidget( game ); diff --git a/Launcher2/Gui/Screens/LauncherInputScreen.cs b/Launcher2/Gui/Screens/LauncherInputScreen.cs index 95e3d1099..01c8a7124 100644 --- a/Launcher2/Gui/Screens/LauncherInputScreen.cs +++ b/Launcher2/Gui/Screens/LauncherInputScreen.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; using System.Drawing; -using System.IO; -using System.Net; -using ClassicalSharp; using OpenTK; using OpenTK.Input; +using ClassicalSharp; namespace Launcher2 { @@ -28,18 +25,31 @@ namespace Launcher2 { protected void KeyDown( object sender, KeyboardKeyEventArgs e ) { if( lastInput != null && e.Key == Key.BackSpace ) { - using( drawer ) { - drawer.SetBitmap( game.Framebuffer ); - lastInput.RemoveChar( inputFont ); - Dirty = true; + if( lastInput.RemoveChar() ) { + RedrawLastInput(); + OnRemovedChar(); } - OnRemovedChar(); } else if( e.Key == Key.Enter && enterIndex >= 0 ) { LauncherWidget widget = widgets[enterIndex]; if( widget.OnClick != null ) widget.OnClick( 0, 0 ); } else if( e.Key == Key.Tab ) { HandleTab(); + } else if( lastInput != null && e.Key == Key.C && ControlDown ) { + lastInput.CopyToClipboard(); + } else if( lastInput != null && e.Key == Key.V && ControlDown ) { + if( lastInput.CopyFromClipboard() ) + RedrawLastInput(); + } else if( lastInput != null && e.Key == Key.Escape ) { + if( lastInput.ClearText() ) + RedrawLastInput(); + } + } + + bool ControlDown { + get { + KeyboardDevice keyboard = game.Window.Keyboard; + return keyboard[Key.ControlLeft] || keyboard[Key.ControlRight]; } } @@ -49,27 +59,36 @@ namespace Launcher2 { } protected void KeyPress( object sender, KeyPressEventArgs e ) { - if( lastInput != null ) { - using( drawer ) { - drawer.SetBitmap( game.Framebuffer ); - lastInput.AddChar( e.KeyChar, inputFont ); - Dirty = true; - } + if( lastInput != null && lastInput.AppendChar( e.KeyChar ) ) { + RedrawLastInput(); OnAddedChar(); } } + protected void RedrawLastInput() { + using( drawer ) { + drawer.SetBitmap( game.Framebuffer ); + if( lastInput.Width > lastInput.ButtonWidth ) + drawer.Clear( game.clearColour, lastInput.X, lastInput.Y, + lastInput.Width + 1, lastInput.Height + 1 ); + lastInput.Redraw( drawer, lastInput.Text, inputFont ); + Dirty = true; + } + } + protected virtual void OnAddedChar() { } protected virtual void OnRemovedChar() { } + protected string Get() { return Get( widgetIndex ); } + protected string Get( int index ) { LauncherWidget widget = widgets[index]; - return widget == null ? "" : ((widget as LauncherTextInputWidget)).Text; + return widget == null ? "" : ((widget as LauncherInputWidget)).Text; } protected void Set( int index, string text ) { - (widgets[index] as LauncherTextInputWidget) + (widgets[index] as LauncherInputWidget) .Redraw( drawer, text, inputFont ); } @@ -91,9 +110,9 @@ namespace Launcher2 { } } - protected LauncherTextInputWidget lastInput; + protected LauncherInputWidget lastInput; protected void InputClick( int mouseX, int mouseY ) { - LauncherTextInputWidget input = selectedWidget as LauncherTextInputWidget; + LauncherInputWidget input = (LauncherInputWidget)selectedWidget; using( drawer ) { drawer.SetBitmap( game.Framebuffer ); if( lastInput != null ) { @@ -108,6 +127,24 @@ namespace Launcher2 { Dirty = true; } + protected void MakeInput( string text, int width, Anchor verAnchor, bool password, + int x, int y, int maxChars ) { + if( widgets[widgetIndex] != null ) { + LauncherInputWidget input = (LauncherInputWidget)widgets[widgetIndex]; + input.DrawAt( drawer, text, inputFont, Anchor.Centre, verAnchor, width, 30, x, y ); + widgetIndex++; + return; + } + + LauncherInputWidget widget = new LauncherInputWidget( game ); + widget.OnClick = InputClick; + widget.Password = password; + widget.MaximumTextLength = maxChars; + + widget.DrawAt( drawer, text, inputFont, Anchor.Centre, verAnchor, width, 30, x, y ); + widgets[widgetIndex++] = widget; + } + public override void Dispose() { game.Window.Mouse.Move -= MouseMove; game.Window.Mouse.ButtonDown -= MouseButtonDown; diff --git a/Launcher2/Gui/Screens/LauncherScreen.cs b/Launcher2/Gui/Screens/LauncherScreen.cs index 49eba2e3b..4156f5dee 100644 --- a/Launcher2/Gui/Screens/LauncherScreen.cs +++ b/Launcher2/Gui/Screens/LauncherScreen.cs @@ -84,7 +84,7 @@ namespace Launcher2 { for( int i = 0; i < widgets.Length * 2; i++ ) { index = (index + 1) % widgets.Length; - if( widgets[index] is LauncherTextInputWidget + if( widgets[index] is LauncherInputWidget || widgets[index] is LauncherButtonWidget ) { LauncherWidget widget = widgets[index]; moveArgs.X = widget.X + widget.Width / 2; @@ -101,11 +101,30 @@ namespace Launcher2 { game.Window.DesktopCursorPos = p; lastClicked = widget; - if( widgets[index] is LauncherTextInputWidget ) + if( widgets[index] is LauncherInputWidget ) MouseButtonDown( null, pressArgs ); break; } } } + + protected void MakeButtonAt( string text, int width, int height, Font font, + Anchor verAnchor, int x, int y, Action onClick ) { + if( widgets[widgetIndex] != null ) { + LauncherButtonWidget input = (LauncherButtonWidget)widgets[widgetIndex]; + input.Active = false; + input.DrawAt( drawer, text, font, Anchor.Centre, verAnchor, width, height, x, y ); + widgetIndex++; + return; + } + + LauncherButtonWidget widget = new LauncherButtonWidget( game ); + widget.Text = text; + widget.OnClick = onClick; + + widget.Active = false; + widget.DrawAt( drawer, text, font, Anchor.Centre, verAnchor, width, height, x, y ); + widgets[widgetIndex++] = widget; + } } } diff --git a/Launcher2/Gui/Screens/ResourcesScreen.cs b/Launcher2/Gui/Screens/ResourcesScreen.cs index 57ef587f5..0de43e3e0 100644 --- a/Launcher2/Gui/Screens/ResourcesScreen.cs +++ b/Launcher2/Gui/Screens/ResourcesScreen.cs @@ -86,25 +86,26 @@ namespace Launcher2 { string text = widgets[0] == null ? String.Format( format, ResourceFetcher.EstimateDownloadSize().ToString( "F2" ) ) - : (widgets[0] as LauncherTextWidget).Text; + : (widgets[0] as LauncherLabelWidget).Text; MakeTextAt( statusFont, text, 0, 5 ); if( fetcher == null ) { MakeTextAt( infoFont, mainText, 0, -30 ); - MakeButtonAt( "Yes", 60, 30, -50, 40, DownloadResources ); + MakeButtonAt( "Yes", 60, 30, textFont, Anchor.Centre, + -50, 40, DownloadResources ); - MakeButtonAt( "No", 60, 30, 50, 40, - (x, y) => game.SetScreen( new MainScreen( game ) ) ); + MakeButtonAt( "No", 60, 30, textFont, Anchor.Centre, + 50, 40, (x, y) => game.SetScreen( new MainScreen( game ) ) ); } else { - MakeButtonAt( "Dismiss", 120, 30, 0, 40, - (x, y) => game.SetScreen( new MainScreen( game ) ) ); + MakeButtonAt( "Dismiss", 120, 30, textFont, Anchor.Centre, + 0, 40, (x, y) => game.SetScreen( new MainScreen( game ) ) ); widgets[2] = null; widgets[3] = null; } } void SetStatus( string text ) { - LauncherTextWidget widget = widgets[0] as LauncherTextWidget; + LauncherLabelWidget widget = widgets[0] as LauncherLabelWidget; using( drawer ) { drawer.SetBitmap( game.Framebuffer ); drawer.Clear( backCol, widget.X, widget.Y, widget.Width, widget.Height ); @@ -113,19 +114,8 @@ namespace Launcher2 { } } - void MakeButtonAt( string text, int width, - int height, int x, int y, Action onClick ) { - LauncherButtonWidget widget = new LauncherButtonWidget( game ); - widget.Text = text; - widget.OnClick = onClick; - - widget.Active = false; - widget.DrawAt( drawer, text, textFont, Anchor.Centre, Anchor.Centre, width, height, x, y ); - widgets[widgetIndex++] = widget; - } - void MakeTextAt( Font font, string text, int x, int y ) { - LauncherTextWidget widget = new LauncherTextWidget( game, text ); + LauncherLabelWidget widget = new LauncherLabelWidget( game, text ); widget.DrawAt( drawer, text, font, Anchor.Centre, Anchor.Centre, x, y ); widgets[widgetIndex++] = widget; } diff --git a/Launcher2/Gui/TableWidget/LauncherTableWidget.Input.cs b/Launcher2/Gui/TableWidget/LauncherTableWidget.Input.cs index a4a3e7837..c7a5373ba 100644 --- a/Launcher2/Gui/TableWidget/LauncherTableWidget.Input.cs +++ b/Launcher2/Gui/TableWidget/LauncherTableWidget.Input.cs @@ -58,7 +58,6 @@ namespace Launcher2 { } } - void ScrollbarClick( int mouseY ) { mouseY -= Y; float scale = (Window.Height - 10) / (float)Count; diff --git a/Launcher2/Gui/TableWidget/LauncherTableWidget.cs b/Launcher2/Gui/TableWidget/LauncherTableWidget.cs index 876d13acb..fa49a073e 100644 --- a/Launcher2/Gui/TableWidget/LauncherTableWidget.cs +++ b/Launcher2/Gui/TableWidget/LauncherTableWidget.cs @@ -33,6 +33,8 @@ namespace Launcher2 { Count = entries.Length; } + /// Filters the table such that only rows with server names + /// that contain the input (case insensitive) are shown. public void FilterEntries( string filter ) { Count = 0; int index = 0; diff --git a/Launcher2/Gui/Widgets/LauncherInputWidget.cs b/Launcher2/Gui/Widgets/LauncherInputWidget.cs new file mode 100644 index 000000000..15319e033 --- /dev/null +++ b/Launcher2/Gui/Widgets/LauncherInputWidget.cs @@ -0,0 +1,103 @@ +using System; +using System.Drawing; +using System.Windows.Forms; +using ClassicalSharp; + +namespace Launcher2 { + + /// Widget that represents text can have modified by the user. + public sealed class LauncherInputWidget : LauncherWidget { + + public int ButtonWidth, ButtonHeight; + public string Text; + + /// Whether the input widget currently is focused through a mouse click or tab. + public bool Active; + + /// Whether all characters should be rendered as *. + public bool Password; + + /// Maximum number of characters that the 'Text' field can contain. + public int MaximumTextLength = 32; + + /// Filter applied to text received from the clipboard. Can be null. + public Func ClipboardFilter; + + public LauncherInputWidget( LauncherWindow window ) : base( window ) { + } + + public void DrawAt( IDrawer2D drawer, string text, Font font, + Anchor horAnchor, Anchor verAnchor, int width, int height, int x, int y ) { + ButtonWidth = width; ButtonHeight = height; + Width = width; Height = height; + CalculateOffset( x, y, horAnchor, verAnchor ); + Redraw( drawer, text, font ); + } + + public void Redraw( IDrawer2D drawer, string text, Font font ) { + Text = text; + if( Password ) + text = new String( '*', text.Length ); + DrawTextArgs args = new DrawTextArgs( text, font, true ); + Size size = drawer.MeasureSize( ref args ); + Width = Math.Max( ButtonWidth, size.Width + 7 ); + + FastColour col = Active ? FastColour.White : new FastColour( 160, 160, 160 ); + drawer.DrawRectBounds( col, 2, X, Y, Width, Height ); + drawer.DrawRect( FastColour.Black, X + 2, Y + 2, Width - 4, Height - 4 ); + + args.SkipPartsCheck = true; + drawer.DrawText( ref args, X + 7, Y + 2 ); + } + + /// Appends a character to the end of the currently entered text. + /// true if a redraw is necessary, false otherwise. + public bool AppendChar( char c ) { + if( c >= ' ' && c <= '~' && Text.Length < MaximumTextLength ) { + Text += c; + return true; + } + return false; + } + + /// Removes the last character in the currently entered text. + /// true if a redraw is necessary, false otherwise. + public bool RemoveChar() { + if( Text.Length == 0 ) return false; + + Text = Text.Substring( 0, Text.Length - 1 ); + return true; + } + + /// Resets the currently entered text to an empty string + /// true if a redraw is necessary, false otherwise. + public bool ClearText() { + if( Text.Length == 0 ) return false; + + Text = ""; + return true; + } + + /// Copies the contents of the currently entered text to the system clipboard. + public void CopyToClipboard() { + if( !String.IsNullOrEmpty( Text ) ) + Clipboard.SetText( Text ); + } + + /// Sets the currently entered text to the contents of the system clipboard. + /// true if a redraw is necessary, false otherwise. + public bool CopyFromClipboard() { + string text = Clipboard.GetText(); + if( String.IsNullOrEmpty( text ) + || Text.Length >= MaximumTextLength ) return false; + + if( ClipboardFilter != null ) + text = ClipboardFilter( text ); + if( Text.Length + text.Length > MaximumTextLength ) { + text = text.Substring( 0, MaximumTextLength - Text.Length ); + } + Text += text; + return true; + } + } +} diff --git a/Launcher2/Gui/Widgets/LauncherTextWidget.cs b/Launcher2/Gui/Widgets/LauncherLabelWidget.cs similarity index 75% rename from Launcher2/Gui/Widgets/LauncherTextWidget.cs rename to Launcher2/Gui/Widgets/LauncherLabelWidget.cs index 7fb51fb58..c756eef20 100644 --- a/Launcher2/Gui/Widgets/LauncherTextWidget.cs +++ b/Launcher2/Gui/Widgets/LauncherLabelWidget.cs @@ -4,11 +4,12 @@ using ClassicalSharp; namespace Launcher2 { - public sealed class LauncherTextWidget : LauncherWidget { + /// Widget that represents text that cannot be modified by the user. + public sealed class LauncherLabelWidget : LauncherWidget { public string Text; - public LauncherTextWidget( LauncherWindow window, string text ) : base( window ) { + public LauncherLabelWidget( LauncherWindow window, string text ) : base( window ) { Text = text; } diff --git a/Launcher2/Gui/Widgets/LauncherTextInputWidget.cs b/Launcher2/Gui/Widgets/LauncherTextInputWidget.cs deleted file mode 100644 index c923f425a..000000000 --- a/Launcher2/Gui/Widgets/LauncherTextInputWidget.cs +++ /dev/null @@ -1,55 +0,0 @@ -using System; -using System.Drawing; -using ClassicalSharp; - -namespace Launcher2 { - - public sealed class LauncherTextInputWidget : LauncherWidget { - - public int ButtonWidth, ButtonHeight; - public string Text; - public bool Active; - public bool Password; - - public LauncherTextInputWidget( LauncherWindow window ) : base( window ) { - } - - public void DrawAt( IDrawer2D drawer, string text, Font font, - Anchor horAnchor, Anchor verAnchor, int width, int height, int x, int y ) { - ButtonWidth = width; ButtonHeight = height; - Width = width; Height = height; - CalculateOffset( x, y, horAnchor, verAnchor ); - Redraw( drawer, text, font ); - } - - public void Redraw( IDrawer2D drawer, string text, Font font ) { - Text = text; - if( Password ) - text = new String( '*', text.Length ); - DrawTextArgs args = new DrawTextArgs( text, font, true ); - Size size = drawer.MeasureSize( ref args ); - Width = Math.Max( ButtonWidth, size.Width + 7 ); - - FastColour col = Active ? FastColour.White : new FastColour( 160, 160, 160 ); - drawer.DrawRectBounds( col, 2, X, Y, Width, Height ); - drawer.DrawRect( FastColour.Black, X + 2, Y + 2, Width - 4, Height - 4 ); - - args.SkipPartsCheck = true; - drawer.DrawText( ref args, X + 7, Y + 2 ); - } - - public void AddChar( char c, Font font ) { - if( c >= ' ' && c <= '~' ) { - Text += c; - Redraw( Window.Drawer, Text, font ); - } - } - - public void RemoveChar( Font font ) { - if( Text.Length == 0 ) return; - - Text = Text.Substring( 0, Text.Length - 1 ); - Redraw( Window.Drawer, Text, font ); - } - } -} diff --git a/Launcher2/Launcher2.csproj b/Launcher2/Launcher2.csproj index a8ceaae6f..6a3657868 100644 --- a/Launcher2/Launcher2.csproj +++ b/Launcher2/Launcher2.csproj @@ -62,8 +62,8 @@ - - + + diff --git a/Launcher2/LauncherWindow.cs b/Launcher2/LauncherWindow.cs index 4a7de3c8a..ea0cb3456 100644 --- a/Launcher2/LauncherWindow.cs +++ b/Launcher2/LauncherWindow.cs @@ -103,7 +103,7 @@ namespace Launcher2 { platformDrawer.Draw( Window.WindowInfo, Framebuffer ); } - internal static FastColour clearColour = new FastColour( 30, 30, 30 ); + internal FastColour clearColour = new FastColour( 30, 30, 30 ); public void MakeBackground() { if( Framebuffer != null ) Framebuffer.Dispose();