Build 0.20.10.0
This commit is contained in:
@@ -174,9 +174,9 @@ namespace Barotrauma
|
||||
|
||||
Character.DisableControls = true;
|
||||
|
||||
if (PlayerInput.KeyHit(Keys.Tab))
|
||||
if (PlayerInput.KeyHit(Keys.Tab) && !textBox.IsIMEActive)
|
||||
{
|
||||
textBox.Text = AutoComplete(textBox.Text, increment: string.IsNullOrEmpty(currentAutoCompletedCommand) ? 0 : 1 );
|
||||
textBox.Text = AutoComplete(textBox.Text, increment: string.IsNullOrEmpty(currentAutoCompletedCommand) ? 0 : 1 );
|
||||
}
|
||||
|
||||
if (PlayerInput.KeyDown(Keys.LeftControl) || PlayerInput.KeyDown(Keys.RightControl))
|
||||
|
||||
@@ -1,72 +1,18 @@
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Input;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
|
||||
namespace EventInput
|
||||
{
|
||||
public class CharacterEventArgs : EventArgs
|
||||
public readonly record struct CharacterEventArgs(char Character, long Param)
|
||||
{
|
||||
private readonly char character;
|
||||
private readonly long lParam;
|
||||
|
||||
public CharacterEventArgs(char character, long lParam)
|
||||
{
|
||||
this.character = character;
|
||||
this.lParam = lParam;
|
||||
}
|
||||
|
||||
public char Character
|
||||
{
|
||||
get { return character; }
|
||||
}
|
||||
|
||||
public long Param
|
||||
{
|
||||
get { return lParam; }
|
||||
}
|
||||
|
||||
public long RepeatCount
|
||||
{
|
||||
get { return lParam & 0xffff; }
|
||||
}
|
||||
|
||||
public bool ExtendedKey
|
||||
{
|
||||
get { return (lParam & (1 << 24)) > 0; }
|
||||
}
|
||||
|
||||
public bool AltPressed
|
||||
{
|
||||
get { return (lParam & (1 << 29)) > 0; }
|
||||
}
|
||||
|
||||
public bool PreviousState
|
||||
{
|
||||
get { return (lParam & (1 << 30)) > 0; }
|
||||
}
|
||||
|
||||
public bool TransitionState
|
||||
{
|
||||
get { return (lParam & (1 << 31)) > 0; }
|
||||
}
|
||||
public long RepeatCount => Param & 0xffff;
|
||||
public bool ExtendedKey => (Param & (1 << 24)) > 0;
|
||||
public bool AltPressed => (Param & (1 << 29)) > 0;
|
||||
public bool PreviousState => (Param & (1 << 30)) > 0;
|
||||
public bool TransitionState => (Param & (1 << 31)) > 0;
|
||||
}
|
||||
|
||||
public class KeyEventArgs : EventArgs
|
||||
{
|
||||
private Keys keyCode;
|
||||
|
||||
public KeyEventArgs(Keys keyCode)
|
||||
{
|
||||
this.keyCode = keyCode;
|
||||
}
|
||||
|
||||
public Keys KeyCode
|
||||
{
|
||||
get { return keyCode; }
|
||||
}
|
||||
}
|
||||
public readonly record struct KeyEventArgs(Keys KeyCode, char Character);
|
||||
|
||||
public delegate void CharEnteredHandler(object sender, CharacterEventArgs e);
|
||||
public delegate void KeyEventHandler(object sender, KeyEventArgs e);
|
||||
@@ -89,14 +35,11 @@ namespace EventInput
|
||||
/// </summary>
|
||||
public static event KeyEventHandler KeyUp;
|
||||
|
||||
|
||||
#if !WINDOWS
|
||||
/// <summary>
|
||||
/// Raised when the user is editing text and IME is in progress.
|
||||
/// Windows build uses ImeSharp instead because SDL2's IME implementation is broken on Windows (https://github.com/libsdl-org/SDL/issues/2243)
|
||||
/// </summary>
|
||||
public static event EditingTextHandler EditingText;
|
||||
#endif
|
||||
|
||||
|
||||
static bool initialized;
|
||||
|
||||
@@ -110,11 +53,10 @@ namespace EventInput
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
window.TextInput += ReceiveInput;
|
||||
#if !WINDOWS
|
||||
window.KeyDown += ReceiveKeyDown;
|
||||
window.TextEditing += ReceiveTextEditing;
|
||||
#endif
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
@@ -122,15 +64,17 @@ namespace EventInput
|
||||
private static void ReceiveInput(object sender, TextInputEventArgs e)
|
||||
{
|
||||
OnCharEntered(e.Character);
|
||||
KeyDown?.Invoke(sender, new KeyEventArgs(e.Key));
|
||||
}
|
||||
|
||||
#if !WINDOWS
|
||||
private static void ReceiveKeyDown(object sender, TextInputEventArgs e)
|
||||
{
|
||||
KeyDown?.Invoke(sender, new KeyEventArgs(e.Key, e.Character));
|
||||
}
|
||||
|
||||
private static void ReceiveTextEditing(object sender, TextEditingEventArgs e)
|
||||
{
|
||||
EditingText?.Invoke(sender, e);
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void OnCharEntered(char character)
|
||||
{
|
||||
|
||||
@@ -10,11 +10,7 @@ namespace EventInput
|
||||
void ReceiveTextInput(string text);
|
||||
void ReceiveCommandInput(char command);
|
||||
void ReceiveSpecialInput(Keys key);
|
||||
|
||||
#if !WINDOWS
|
||||
/// Windows build uses ImeSharp instead because SDL2's IME implementation is broken on Windows (https://github.com/libsdl-org/SDL/issues/2243)
|
||||
void ReceiveEditingInput(string text, int start);
|
||||
#endif
|
||||
void ReceiveEditingInput(string text, int start, int length);
|
||||
|
||||
bool Selected { get; set; } //or Focused
|
||||
}
|
||||
@@ -26,59 +22,27 @@ namespace EventInput
|
||||
EventInput.Initialize(window);
|
||||
EventInput.CharEntered += EventInput_CharEntered;
|
||||
EventInput.KeyDown += EventInput_KeyDown;
|
||||
#if !WINDOWS
|
||||
EventInput.EditingText += EventInput_TextEditing;
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SDL by default starts in a state where it accepts IME inputs
|
||||
* this is bad because this blocks keybinds since the IME thinks
|
||||
* it's typing in a text box and not forwarding keybinds to the game.
|
||||
*/
|
||||
TextInput.StopTextInput();
|
||||
GameMain.ResetIMEWorkaround();
|
||||
}
|
||||
#if !WINDOWS
|
||||
|
||||
public void EventInput_TextEditing(object sender, TextEditingEventArgs e)
|
||||
{
|
||||
_subscriber?.ReceiveEditingInput(e.Text, e.Start);
|
||||
_subscriber?.ReceiveEditingInput(e.Text, e.Start, e.Length);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void EventInput_KeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
_subscriber?.ReceiveSpecialInput(e.KeyCode);
|
||||
if (char.IsControl(e.Character))
|
||||
{
|
||||
_subscriber?.ReceiveCommandInput(e.Character);
|
||||
}
|
||||
}
|
||||
|
||||
void EventInput_CharEntered(object sender, CharacterEventArgs e)
|
||||
{
|
||||
if (_subscriber == null)
|
||||
return;
|
||||
if (char.IsControl(e.Character))
|
||||
{
|
||||
_subscriber.ReceiveCommandInput(e.Character);
|
||||
// Doesn't work as expected. Not sure why this should be run in a separate thread.
|
||||
//#if WINDOWS
|
||||
// //ctrl-v
|
||||
// if (e.Character == 0x16) // 22
|
||||
// {
|
||||
// //XNA runs in Multiple Thread Apartment state, which cannot recieve clipboard
|
||||
// Thread thread = new Thread(PasteThread);
|
||||
// thread.SetApartmentState(ApartmentState.STA);
|
||||
// thread.Start();
|
||||
// thread.Join();
|
||||
// _subscriber.ReceiveTextInput(_pasteResult);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// _subscriber.ReceiveCommandInput(e.Character);
|
||||
// }
|
||||
//#else
|
||||
// _subscriber.ReceiveCommandInput(e.Character);
|
||||
//#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
_subscriber.ReceiveTextInput(e.Character);
|
||||
}
|
||||
_subscriber?.ReceiveTextInput(e.Character);
|
||||
}
|
||||
|
||||
IKeyboardSubscriber _subscriber;
|
||||
@@ -97,8 +61,9 @@ namespace EventInput
|
||||
|
||||
if (value is GUITextBox box)
|
||||
{
|
||||
TextInput.SetTextInputRect(box.Rect);
|
||||
TextInput.SetTextInputRect(box.MouseRect);
|
||||
TextInput.StartTextInput();
|
||||
TextInput.SetTextInputRect(box.MouseRect);
|
||||
}
|
||||
|
||||
_subscriber = value;
|
||||
|
||||
@@ -1261,10 +1261,6 @@ namespace Barotrauma
|
||||
UpdateMessages(deltaTime);
|
||||
UpdateSavingIndicator(deltaTime);
|
||||
}
|
||||
|
||||
#if WINDOWS
|
||||
GUITextBox.UpdateIME();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void UpdateGUIMessageBoxesOnly(float deltaTime)
|
||||
|
||||
@@ -111,10 +111,7 @@ namespace Barotrauma
|
||||
}
|
||||
public void ReceiveTextInput(string text) { }
|
||||
public void ReceiveCommandInput(char command) { }
|
||||
|
||||
#if !WINDOWS
|
||||
public void ReceiveEditingInput(string text, int start) { }
|
||||
#endif
|
||||
public void ReceiveEditingInput(string text, int start, int length) { }
|
||||
|
||||
public void ReceiveSpecialInput(Keys key)
|
||||
{
|
||||
@@ -125,9 +122,7 @@ namespace Barotrauma
|
||||
listBox.ReceiveSpecialInput(key);
|
||||
GUI.KeyboardDispatcher.Subscriber = this;
|
||||
break;
|
||||
case Keys.Enter:
|
||||
case Keys.Space:
|
||||
case Keys.Escape:
|
||||
default:
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1347,10 +1347,7 @@ namespace Barotrauma
|
||||
}
|
||||
public void ReceiveTextInput(string text) { }
|
||||
public void ReceiveCommandInput(char command) { }
|
||||
|
||||
#if !WINDOWS
|
||||
public void ReceiveEditingInput(string text, int start) { }
|
||||
#endif
|
||||
public void ReceiveEditingInput(string text, int start, int length) { }
|
||||
|
||||
public void ReceiveSpecialInput(Keys key)
|
||||
{
|
||||
@@ -1368,9 +1365,7 @@ namespace Barotrauma
|
||||
case Keys.Right:
|
||||
if (isHorizontal && AllowArrowKeyScroll) { SelectNext(playSelectSound: PlaySelectSound.Yes); }
|
||||
break;
|
||||
case Keys.Enter:
|
||||
case Keys.Space:
|
||||
case Keys.Escape:
|
||||
default:
|
||||
GUI.KeyboardDispatcher.Subscriber = null;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -223,24 +223,24 @@ namespace Barotrauma
|
||||
public ScalableFont GetFontForStr(string str) =>
|
||||
Prefabs.ActivePrefab.GetFontForCategory(TextManager.GetSpeciallyHandledCategories(str));
|
||||
|
||||
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth)
|
||||
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects spriteEffects, float layerDepth)
|
||||
{
|
||||
DrawString(sb, text.Value, position, color, rotation, origin, scale, se, layerDepth);
|
||||
DrawString(sb, text.Value, position, color, rotation, origin, scale, spriteEffects, layerDepth);
|
||||
}
|
||||
|
||||
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects se, float layerDepth)
|
||||
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects spriteEffects, float layerDepth)
|
||||
{
|
||||
GetFontForStr(text).DrawString(sb, text, position, color, rotation, origin, scale, se, layerDepth);
|
||||
GetFontForStr(text).DrawString(sb, text, position, color, rotation, origin, scale, spriteEffects, layerDepth);
|
||||
}
|
||||
|
||||
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, Alignment alignment = Alignment.TopLeft)
|
||||
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects spriteEffects, float layerDepth, Alignment alignment = Alignment.TopLeft)
|
||||
{
|
||||
DrawString(sb, text.Value, position, color, rotation, origin, scale, se, layerDepth, alignment);
|
||||
DrawString(sb, text.Value, position, color, rotation, origin, scale, spriteEffects, layerDepth, alignment);
|
||||
}
|
||||
|
||||
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, Alignment alignment = Alignment.TopLeft, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit)
|
||||
public void DrawString(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects spriteEffects, float layerDepth, Alignment alignment = Alignment.TopLeft, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit)
|
||||
{
|
||||
GetFontForStr(text).DrawString(sb, text, position, color, rotation, origin, scale, se, layerDepth, alignment, forceUpperCase);
|
||||
GetFontForStr(text).DrawString(sb, text, position, color, rotation, origin, scale, spriteEffects, layerDepth, alignment, forceUpperCase);
|
||||
}
|
||||
|
||||
public void DrawString(SpriteBatch sb, LocalizedString text, Vector2 position, Color color, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit, bool italics = false)
|
||||
@@ -253,9 +253,9 @@ namespace Barotrauma
|
||||
GetFontForStr(text).DrawString(sb, text, position, color, forceUpperCase, italics);
|
||||
}
|
||||
|
||||
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects se, float layerDepth, in ImmutableArray<RichTextData>? richTextData, int rtdOffset = 0, Alignment alignment = Alignment.TopLeft, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit)
|
||||
public void DrawStringWithColors(SpriteBatch sb, string text, Vector2 position, Color color, float rotation, Vector2 origin, float scale, SpriteEffects spriteEffects, float layerDepth, in ImmutableArray<RichTextData>? richTextData, int rtdOffset = 0, Alignment alignment = Alignment.TopLeft, ForceUpperCase forceUpperCase = Barotrauma.ForceUpperCase.Inherit)
|
||||
{
|
||||
GetFontForStr(text).DrawStringWithColors(sb, text, position, color, rotation, origin, scale, se, layerDepth, richTextData, rtdOffset, alignment, forceUpperCase);
|
||||
GetFontForStr(text).DrawStringWithColors(sb, text, position, color, rotation, origin, scale, spriteEffects, layerDepth, richTextData, rtdOffset, alignment, forceUpperCase);
|
||||
}
|
||||
|
||||
public Vector2 MeasureString(LocalizedString str, bool removeExtraSpacing = false)
|
||||
|
||||
@@ -256,6 +256,8 @@ namespace Barotrauma
|
||||
|
||||
private readonly IMEPreviewTextHandler imePreviewTextHandler;
|
||||
|
||||
public bool IsIMEActive => imePreviewTextHandler is { HasText: true };
|
||||
|
||||
public GUITextBox(RectTransform rectT, string text = "", Color? textColor = null, GUIFont font = null,
|
||||
Alignment textAlignment = Alignment.Left, bool wrap = false, string style = "", Color? color = null, bool createClearButton = false, bool createPenIcon = true)
|
||||
: base(style, rectT)
|
||||
@@ -574,6 +576,7 @@ namespace Barotrauma
|
||||
{
|
||||
CaretIndex = Math.Min(Text.Length, CaretIndex + input.Length);
|
||||
OnTextChanged?.Invoke(this, Text);
|
||||
imePreviewTextHandler?.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -602,10 +605,12 @@ namespace Barotrauma
|
||||
|
||||
public void ReceiveCommandInput(char command)
|
||||
{
|
||||
if (Text == null) Text = "";
|
||||
if (IsIMEActive) { return; }
|
||||
|
||||
if (Text == null) { Text = ""; }
|
||||
|
||||
// Prevent alt gr from triggering any of these as that combination is often needed for special characters
|
||||
if (PlayerInput.IsAltDown()) return;
|
||||
if (PlayerInput.IsAltDown()) { return; }
|
||||
|
||||
switch (command)
|
||||
{
|
||||
@@ -678,21 +683,22 @@ namespace Barotrauma
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if !WINDOWS
|
||||
public void ReceiveEditingInput(string text, int start)
|
||||
|
||||
public void ReceiveEditingInput(string text, int start, int length)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
if (start is 0) { imePreviewTextHandler.Reset(); }
|
||||
imePreviewTextHandler.Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
imePreviewTextHandler.UpdateText(text, start);
|
||||
imePreviewTextHandler.UpdateText(text, start, length);
|
||||
}
|
||||
#endif
|
||||
|
||||
public void ReceiveSpecialInput(Keys key)
|
||||
{
|
||||
if (IsIMEActive) { return; }
|
||||
|
||||
switch (key)
|
||||
{
|
||||
case Keys.Left:
|
||||
@@ -883,20 +889,7 @@ namespace Barotrauma
|
||||
|
||||
public void DrawIMEPreview(SpriteBatch spriteBatch)
|
||||
{
|
||||
if (!imePreviewTextHandler.HasText) { return; }
|
||||
|
||||
Vector2 imePosition = CaretScreenPos;
|
||||
int inflate = GUI.IntScale(3);
|
||||
|
||||
RectangleF rect = new RectangleF(imePosition, imePreviewTextHandler.TextSize);
|
||||
rect.Inflate(inflate, inflate);
|
||||
|
||||
RectangleF borderRect = rect;
|
||||
borderRect.Inflate(1, 1);
|
||||
|
||||
GUI.DrawFilledRectangle(spriteBatch, borderRect, Color.White, depth: 0.02f);
|
||||
GUI.DrawFilledRectangle(spriteBatch, rect, Color.Black, depth: 0.01f);
|
||||
Font.DrawString(spriteBatch, imePreviewTextHandler.PreviewText, imePosition, GUIStyle.Orange, 0.0f, Vector2.Zero, 1f, SpriteEffects.None, 0, alignment: textBlock.TextAlignment, forceUpperCase: textBlock.ForceUpperCase);
|
||||
imePreviewTextHandler.DrawIMEPreview(spriteBatch, CaretScreenPos, textBlock);
|
||||
}
|
||||
|
||||
private void CalculateSelection()
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
using ImeSharp;
|
||||
using Microsoft.Xna.Framework;
|
||||
using System;
|
||||
|
||||
namespace Barotrauma;
|
||||
|
||||
/// <summary>
|
||||
/// A class for handling Input Method Editor (used for inputting e.g. Chinese and Japanese text)
|
||||
/// </summary>
|
||||
public partial class GUITextBox : GUIComponent
|
||||
{
|
||||
private static bool initialized;
|
||||
|
||||
public static GUIFrame IMEWindow { get; set; }
|
||||
public static GUITextBlock IMETextBlock { get; set; }
|
||||
|
||||
public static void UpdateIME()
|
||||
{
|
||||
if (!initialized) { InitializeIME(); }
|
||||
if (GUI.KeyboardDispatcher.Subscriber is GUITextBox { Selected: true })
|
||||
{
|
||||
IMEWindow?.AddToGUIUpdateList(order: 10);
|
||||
}
|
||||
}
|
||||
|
||||
private static void InitializeIME()
|
||||
{
|
||||
InputMethod.Initialize(GameMain.Instance.Window.Hwnd, false);
|
||||
InputMethod.TextCompositionCallback = OnTextComposition;
|
||||
InputMethod.CommitTextCompositionCallback = OnCommitTextComposition;
|
||||
InputMethod.Enabled = true;
|
||||
IMEWindow = new GUIFrame(new RectTransform(new Point(GUI.IntScale(300), GUI.IntScale(300)), GUI.Canvas), "InnerFrame") { CanBeFocused = false, Visible = false };
|
||||
IMETextBlock = new GUITextBlock(new RectTransform(Vector2.One, IMEWindow.RectTransform), "") { CanBeFocused = false };
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
private static void OnTextComposition(IMEString compositionText, int cursorPosition, IMEString[] candidateList, int candidatePageStart, int candidatePageSize, int candidateSelection)
|
||||
{
|
||||
if (GUI.KeyboardDispatcher.Subscriber is not GUITextBox { Selected: true } textBox) { return; }
|
||||
IMEWindow.Visible = true;
|
||||
string text = compositionText.ToString().Insert(cursorPosition, "|");
|
||||
if (candidateList != null)
|
||||
{
|
||||
text += "\n";
|
||||
for (int i = 0; i < candidatePageSize; i++)
|
||||
{
|
||||
string candidateStr = $"\t{candidatePageStart + i + 1} {candidateList[i]}";
|
||||
if (candidateSelection == i)
|
||||
{
|
||||
candidateStr = $" ‖color:{XMLExtensions.ToStringHex(Color.White)}‖{candidateStr}‖end‖";
|
||||
}
|
||||
candidateStr += "\n";
|
||||
text += candidateStr;
|
||||
}
|
||||
}
|
||||
IMETextBlock.Text = RichString.Rich(text);
|
||||
|
||||
IMEWindow.RectTransform.NonScaledSize = new Point(
|
||||
Math.Max(IMEWindow.Rect.Width, (int)IMETextBlock.TextSize.X + GUI.IntScale(32)),
|
||||
(int)IMETextBlock.TextSize.Y);
|
||||
|
||||
Point windowPos = new Point(textBox.Rect.X, textBox.Rect.Bottom);
|
||||
if (windowPos.Y + IMEWindow.Rect.Height > GameMain.GraphicsHeight)
|
||||
{
|
||||
windowPos.Y = textBox.Rect.Y - IMEWindow.Rect.Height;
|
||||
}
|
||||
IMEWindow.RectTransform.ScreenSpaceOffset = windowPos;
|
||||
}
|
||||
|
||||
private static void OnCommitTextComposition(string text)
|
||||
{
|
||||
if (IMEWindow.Visible)
|
||||
{
|
||||
foreach (char c in text)
|
||||
{
|
||||
if (!char.IsControl(c))
|
||||
{
|
||||
GUI.KeyboardDispatcher.Subscriber?.ReceiveTextInput(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
IMEWindow.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,25 @@
|
||||
#nullable enable
|
||||
|
||||
using System.Collections.Immutable;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma
|
||||
{
|
||||
|
||||
public sealed class IMEPreviewTextHandler
|
||||
{
|
||||
public string PreviewText { get; private set; } = string.Empty;
|
||||
public Vector2 TextSize { get; private set; }
|
||||
public bool HasText => !string.IsNullOrEmpty(PreviewText);
|
||||
public bool HasText => !string.IsNullOrEmpty(previewText);
|
||||
|
||||
// This has to be settable because for some reason we update the font of GUITextBox in some places
|
||||
public GUIFont Font { get; set; }
|
||||
|
||||
private string previewText = string.Empty;
|
||||
private Vector2 textSize;
|
||||
|
||||
private bool isSectioned;
|
||||
private ImmutableArray<RichTextData>? richTextData;
|
||||
|
||||
public IMEPreviewTextHandler(GUIFont font)
|
||||
{
|
||||
Font = font;
|
||||
@@ -20,35 +27,64 @@ namespace Barotrauma
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
TextSize = Vector2.Zero;
|
||||
PreviewText = string.Empty;
|
||||
textSize = Vector2.Zero;
|
||||
previewText = string.Empty;
|
||||
richTextData = null;
|
||||
isSectioned = false;
|
||||
}
|
||||
|
||||
public void UpdateText(string text, int start)
|
||||
public void UpdateText(string text, int start, int length)
|
||||
{
|
||||
if (string.IsNullOrEmpty(text) && start is 0)
|
||||
isSectioned = start >= 0 && length > 0;
|
||||
richTextData = null;
|
||||
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
int totalLength = start + text.Length;
|
||||
string newText = PreviewText;
|
||||
if (newText.Length > totalLength)
|
||||
{
|
||||
newText = newText[..totalLength];
|
||||
}
|
||||
previewText = text;
|
||||
|
||||
if (totalLength > newText.Length)
|
||||
{
|
||||
// this is required for some reason on Windows
|
||||
// my guess is that the order which TextEditing events come thru is not guaranteed
|
||||
newText = newText.PadRight(totalLength);
|
||||
}
|
||||
textSize = Font.MeasureString(text);
|
||||
|
||||
newText = newText.Remove(start, text.Length).Insert(start, text);
|
||||
PreviewText = newText;
|
||||
TextSize = Font.MeasureString(PreviewText);
|
||||
if (!isSectioned) { return; }
|
||||
|
||||
string coloredText = ToolBox.ColorSectionOfString(text, start, length, GUIStyle.Orange);
|
||||
|
||||
RichString richString = RichString.Rich(coloredText);
|
||||
|
||||
previewText = richString.SanitizedValue;
|
||||
richTextData = richString.RichTextData;
|
||||
}
|
||||
|
||||
public void DrawIMEPreview(SpriteBatch spriteBatch, Vector2 position, GUITextBlock textBlock)
|
||||
{
|
||||
if (!HasText) { return; }
|
||||
|
||||
int inflate = GUI.IntScale(3);
|
||||
|
||||
RectangleF rect = new RectangleF(position, textSize);
|
||||
rect.Inflate(inflate, inflate);
|
||||
|
||||
RectangleF borderRect = rect;
|
||||
borderRect.Inflate(1, 1);
|
||||
|
||||
GUI.DrawFilledRectangle(spriteBatch, borderRect, Color.White, depth: 0.02f);
|
||||
GUI.DrawFilledRectangle(spriteBatch, rect, Color.Black, depth: 0.01f);
|
||||
|
||||
Font.DrawStringWithColors(spriteBatch,
|
||||
text: previewText,
|
||||
position: position,
|
||||
color: isSectioned ? GUIStyle.TextColorNormal : GUIStyle.Orange,
|
||||
rotation: 0.0f,
|
||||
origin: Vector2.Zero,
|
||||
scale: 1f,
|
||||
spriteEffects: SpriteEffects.None,
|
||||
layerDepth: 0,
|
||||
richTextData: richTextData,
|
||||
alignment: textBlock.TextAlignment,
|
||||
forceUpperCase: textBlock.ForceUpperCase);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -377,6 +377,7 @@ namespace Barotrauma
|
||||
Hyper.ComponentModel.HyperTypeDescriptionProvider.Add(typeof(Hull));
|
||||
|
||||
performanceCounterTimer = Stopwatch.StartNew();
|
||||
ResetIMEWorkaround();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1239,5 +1240,20 @@ namespace Barotrauma
|
||||
};
|
||||
msgBox.Buttons[1].OnClicked = msgBox.Close;
|
||||
}
|
||||
|
||||
/*
|
||||
* On some systems, IME input is enabled by default, and being able to set the game to a state
|
||||
* where it doesn't accept IME input on game launch seems very inconsistent.
|
||||
* This function quickly cycles through IME input states and is called from couple different places
|
||||
* to ensure that IME input is disabled properly when it's not needed.
|
||||
*/
|
||||
public static void ResetIMEWorkaround()
|
||||
{
|
||||
Rectangle rect = new Rectangle(0, 0, GraphicsWidth, GraphicsHeight);
|
||||
TextInput.SetTextInputRect(rect);
|
||||
TextInput.StartTextInput();
|
||||
TextInput.SetTextInputRect(rect);
|
||||
TextInput.StopTextInput();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -999,6 +999,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (MapEntityCategory category in Enum.GetValues(typeof(MapEntityCategory)))
|
||||
{
|
||||
if (category == MapEntityCategory.None) { continue; }
|
||||
entityCategoryButtons.Add(new GUIButton(new RectTransform(new Vector2(1.0f, 1.0f), entityMenuTop.RectTransform, scaleBasis: ScaleBasis.BothHeight),
|
||||
"", style: "CategoryButton." + category.ToString())
|
||||
{
|
||||
@@ -1085,6 +1086,7 @@ namespace Barotrauma
|
||||
|
||||
foreach (MapEntityCategory category in Enum.GetValues(typeof(MapEntityCategory)))
|
||||
{
|
||||
if (category == MapEntityCategory.None) { continue; }
|
||||
LocalizedString categoryName = TextManager.Get("MapEntityCategory." + category);
|
||||
maxTextWidth = (int)Math.Max(maxTextWidth, GUIStyle.SubHeadingFont.MeasureString(categoryName.Replace(" ", "\n")).X + GUI.IntScale(50));
|
||||
foreach (MapEntityPrefab ep in MapEntityPrefab.List)
|
||||
|
||||
@@ -863,22 +863,21 @@ namespace Barotrauma
|
||||
PlayDamageSound(damageType, damage, bodyPosition, 800.0f);
|
||||
}
|
||||
|
||||
private static readonly List<DamageSound> tempList = new List<DamageSound>();
|
||||
public static void PlayDamageSound(string damageType, float damage, Vector2 position, float range = 2000.0f, IEnumerable<Identifier> tags = null)
|
||||
{
|
||||
damage = MathHelper.Clamp(damage + Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f);
|
||||
tempList.Clear();
|
||||
foreach (var s in damageSounds)
|
||||
{
|
||||
if ((s.DamageRange == Vector2.Zero ||
|
||||
(damage >= s.DamageRange.X && damage <= s.DamageRange.Y)) &&
|
||||
s.DamageType == damageType &&
|
||||
(s.RequiredTag.IsEmpty || (tags == null ? s.RequiredTag.IsEmpty : tags.Contains(s.RequiredTag))))
|
||||
{
|
||||
tempList.Add(s);
|
||||
}
|
||||
}
|
||||
var damageSound = tempList.GetRandomUnsynced();
|
||||
//if the damage is too low for any sound, don't play anything
|
||||
if (damageSounds.All(d => damage < d.DamageRange.X)) { return; }
|
||||
|
||||
//allow the damage to differ by 10 from the configured damage range,
|
||||
//so the same amount of damage doesn't always play the same sound
|
||||
float randomizedDamage = MathHelper.Clamp(damage + Rand.Range(-10.0f, 10.0f), 0.0f, 100.0f);
|
||||
|
||||
var suitableSounds = damageSounds.Where(s =>
|
||||
s.DamageType == damageType &&
|
||||
(s.DamageRange == Vector2.Zero || (randomizedDamage >= s.DamageRange.X && randomizedDamage <= s.DamageRange.Y)) &&
|
||||
(s.RequiredTag.IsEmpty || (tags == null ? s.RequiredTag.IsEmpty : tags.Contains(s.RequiredTag))));
|
||||
|
||||
var damageSound = suitableSounds.GetRandomUnsynced();
|
||||
damageSound?.Sound?.Play(1.0f, range, position, muffle: !damageSound.IgnoreMuffling && ShouldMuffleSound(Character.Controlled, position, range, null));
|
||||
}
|
||||
|
||||
|
||||
@@ -512,5 +512,34 @@ namespace Barotrauma
|
||||
|
||||
return new Vector2(paddingX, paddingY);
|
||||
}
|
||||
|
||||
public static string ColorSectionOfString(string text, int start, int length, Color color)
|
||||
{
|
||||
int end = start + length;
|
||||
|
||||
if (start < 0 || length < 0 || end > text.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException($"Invalid start ({start}) or length ({length}) for text \"{text}\".");
|
||||
}
|
||||
|
||||
string stichedString = string.Empty;
|
||||
|
||||
if (start > 0)
|
||||
{
|
||||
stichedString += text[..start];
|
||||
}
|
||||
|
||||
// this is the highlighted part
|
||||
stichedString += ColorString(text[start..end], color);
|
||||
|
||||
if (end < text.Length)
|
||||
{
|
||||
stichedString += text[end..];
|
||||
}
|
||||
|
||||
return stichedString;
|
||||
|
||||
static string ColorString(string text, Color color) => $"‖color:{color.ToStringHex()}‖{text}‖end‖";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user