25 #region Obsolete Members
35 [Obsolete(
"TextBoxWidget.JustOpened is deprecated.",
true)]
38 [Obsolete(
"TextBoxWidget.MoveNextFlag is deprecated.",
true)]
57 if (value.StartsWith(
'[')
58 && value.EndsWith(
']')) {
59 string[] xp = value.Substring(1, value.Length - 2).Split(
':');
80 public string Title {
get;
set; }
88 if (value.StartsWith(
'[')
89 && value.EndsWith(
']')) {
90 string[] xp = value.Substring(1, value.Length - 2).Split(
':');
108 [Obsolete($
"TextBoxWidget.m_caretPosition is deprecated, use {nameof(TextBoxWidget)}.{nameof(Caret)} instead.",
true)]
119 [Obsolete($
"TextBoxWidget.CaretPosition is deprecated, use {nameof(TextBoxWidget)}.{nameof(Caret)} instead.",
true)]
122 set =>
Caret = value;
133 [Obsolete($
"TextBoxWidget.m_hasFocus is deprecated, use {nameof(TextBoxWidget)}.{nameof(HasFocus)} instead.",
true)]
144 [Obsolete($
"TextBoxWidget.m_size is deprecated, use {nameof(TextBoxWidget)}.{nameof(Size)} property instead.",
true)]
157 [Obsolete($
"TextBoxWidget.m_focusStartTime is deprecated, use {nameof(TextBoxWidget)}.{nameof(FocusStartTime)} instead.",
true)]
179 caret += selectionLength;
180 selectionLength = -selectionLength;
182 return Text.Substring(caret, selectionLength);
219 string text = value ==
null ? string.Empty :
231 string text = value ==
null ? string.Empty :
395 if (originValue && !value) {
398 if (!originValue && value) {
416 string left = str[..splitPosition];
417 string right = str[splitPosition..];
418 return [left, right];
453 public void EnterCharacter(
char value,
int position = -1,
bool moveCaret =
true) {
468 OverwriteCharacter();
474 void OverwriteCharacter() {
475 if (position is -1) {
481 str =
new string(
' ', distanceToNextIndent);
484 str = value.ToString();
489 Text =
Text.Remove(position, str.Length);
493 void InsertCharacter() {
497 if (position is -1) {
503 str =
new string(
' ', distanceToNextIndent);
506 str = value.ToString();
530 caret += selectionLength;
531 selectionLength = -selectionLength;
533 Text =
Text.Remove(caret, selectionLength);
535 Caret = Math.Clamp(caret, 0,
Text.Length);
556 foreach (
char character
in value.ReplaceLineEndings(
"\n")) {
571 public static string[]
CharacterKindsMap = [
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789"];
605 public void BackSpace(
char? character =
null,
int count = 1,
bool moveCaret =
true) {
610 string map = character.HasValue ?
CharacterKindsMap.FirstOrDefault(x => x.Contains(character.Value), character.ToString()) :
null;
612 for (i =
Caret; i > 0 && count != 0; i--) {
614 && !map.Contains(
Text[i - 1])) {
650 public void Delete(
char? character =
null,
int count = 1) {
655 string map = character.HasValue ?
CharacterKindsMap.FirstOrDefault(x => x.Contains(character.Value), character.ToString()) :
null;
656 for (; count != 0 &&
Caret <
Text.Length; count--) {
668 InputMethod.TextCompositionCallback += (text, pos) => {
675 FocusedTextBox.CompositionText = text;
676 FocusedTextBox.CompositionTextCaret = pos;
679 InputMethod.TextInputCallback += character => {
683 FocusedTextBox.CompositionText =
null;
712 FocusedTextBox.Caret = 0;
741 case (< (
char)32 or > (
char)126) and <= (char)128: {
808 if (
Input.Click.HasValue) {
815#elif ANDROID || BROWSER
829 Caret = CalculateClickedCharacterIndex(
846 if (
Input.Scroll.HasValue
847 &&
Input.MousePosition.HasValue
849 float scroll = Input.Scroll.Value.X * Input.Scroll.Value.Z / 92;
852 if (
Input.Drag.HasValue) {
861 Caret = CalculateClickedCharacterIndex(
879 int caret2 = CalculateClickedCharacterIndex(
890 if (Math.Abs(caret2 -
Caret) > 1) {
897 && !
Input.Drag.HasValue) {
984 && lastChar !=
'\n') {
996 List<TextBoxWidget> textBoxes = FindTextBoxWidgets(rootWidget);
997 int thisIndex = textBoxes.IndexOf(
this);
1027 List<TextBoxWidget> textBoxes =
new(16);
1030 textBoxes.Add(textBoxWidget);
1035 List<TextBoxWidget> result = FindTextBoxWidgets(containerWidget);
1036 if (result.Count is not 0) {
1037 textBoxes.AddRange(result);
1043 static int CalculateClickedCharacterIndex(
BitmapFont font,
1049 float scale = fontScale * font.
Scale;
1051 float currentPosition = 0f;
1052 float currentHeight = widgetActualSize.Y / 2f - font.LineHeight * scale / 2;
1054 while (currentHeight + font.
LineHeight * scale + spacing.
Y < clickPosition.
Y) {
1055 i = text.IndexOf(
'\n', i) + 1;
1059 currentHeight += font.LineHeight * scale + spacing.
Y;
1061 for (; i < text.Length; i++) {
1062 char letter = text[i];
1063 if (letter ==
'\n') {
1066 if (letter ==
'\u200b') {
1070 float kerning = i + 1 < text.Length ? font.
GetKerning(letter, text[i + 1]) : 0f;
1071 if (currentPosition + (glyph.
Width - kerning + spacing.
X) / 2 > clickPosition.
X) {
1074 currentPosition += (glyph.Width - kerning + spacing.
X) * scale;
1183 throw new InvalidOperationException($
"{nameof(MaximumLength)} 必须大于或等于 0.");
1186 if (
Text.Length > value) {
1201 throw new InvalidOperationException($
"{nameof(MaximumLength)} 必须大于或等于 0.");
1204 if (
Text.Sum(x => x ==
'\n' ? 1 : 0) > value) {
1272 const double tolerance = 0.01;
1274 if (scrollRange < 0) {
1277 float newValue = Math.Clamp(
m_scroll, 0, scrollRange);
1278 if (Math.Abs(newValue -
m_scroll) > tolerance) {
1439 #region Input Method Api
1479 get => InputMethod.Enabled;
1480 set => InputMethod.Enabled = value;
1501 InputMethod.CandidateList.Select(x => x.ToString()).ToArray();
1516 InputMethod.CandidateSelection;
1531 InputMethod.CandidatePageSize;
1570#pragma warning disable CS0067
1571 public event Action<TextBoxWidget>
Enter;
1582#pragma warning restore CS0067
1637 string candidate = $
"{i + 1} {CandidatesList[i]}";
1641 int characterIndex = 0;
1642 while (characterIndex < candidate.Length) {
1645 glyph =
Font.GetGlyph(candidate[characterIndex]);
1648 glyph =
Font.FallbackGlyph;
1659 candidate = candidate[..characterIndex];
1684 Display.ScissorRectangle = rect;
1691 catch (Exception e) {
1703 int selectionStart = caretIndex;
1705 selectionStart += selectionLength;
1706 selectionLength = -selectionLength;
1709 textToDraw =
new string(
'*', textToDraw.Length);
1713 Vector2 currentDrawPosition = (0, ActualSize.Y / 2);
1714 List<TextDrawItem> drawItems =
new(3);
1717 string[] lines = textToDraw.Split(
'\n');
1719 foreach (
string line
in lines) {
1720 if (selectionLength != 0
1721 && selectionStart < charIndex + line.Length
1722 && selectionStart + selectionLength > charIndex) {
1723 int lineStart = charIndex;
1724 int selectionStartInLine = Math.Max(selectionStart - lineStart, 0);
1725 int selectionEndInLine = Math.Min(selectionStart + selectionLength - lineStart, line.Length);
1726 int actualSelectionLength = selectionEndInLine - selectionStartInLine;
1731 selectionStartInLine,
1732 actualSelectionLength,
1741 if (charIndex <= caretIndex
1742 && charIndex + line.Length >= caretIndex) {
1743 string[] split =
SplitStringAt(line, caretIndex - charIndex);
1773 if (split.Length > 1) {
1801 charIndex += line.Length + 1;
1804 drawItem.
Draw(ref currentDrawPosition);
1807 flatBatch.TransformTriangles(scrollTransform);
1808 fontBatch.TransformTriangles(scrollTransform);
1809 underlineFlatBatch.TransformLines(scrollTransform);
1826 base.MeasureOverride(parentAvailableSize);
1846 fontBatch.QueueText(
1847 fullText.Substring(start, length),
1855 position.X += size.
X;
1868 fontBatch.QueueText(
1877 underlineFlatBatch.QueueLine(
1883 position.X += size.
X;
1890 string compositionText,
1891 int compositionTextCaret,
1897 Vector2 offset = font.MeasureText(compositionText, 0, compositionTextCaret, fontScale, fontSpacing) *
Vector2.
UnitX;
1898 flatBatch.QueueQuad(position + offset + (0, -height / 2), position + offset + (width, height / 2), 0, color);
1904 int relativeCaretPosition,
1905 int selectionLength,
1924 flatBatch.QueueQuad(position + (offset, -height / 2), position + (offset + length, height / 2), 0, color);
1931 position.Y += font.GlyphHeight * font.Scale * fontScale + fontSpacing.Y;
void TransformLines(Matrix matrix, int start=0, int end=-1)
void TransformTriangles(Matrix matrix, int start=0, int end=-1)
void TransformTriangles(Matrix matrix, int start=0, int end=-1)
static readonly BlendState NonPremultiplied
static Rectangle ScissorRectangle
void QueueQuad(Vector2 corner1, Vector2 corner2, float depth, Color color)
void QueueRectangle(Vector2 corner1, Vector2 corner2, float depth, Color color)
void QueueText(string text, Vector2 position, float depth, Color color, TextAnchor anchor=TextAnchor.Default)
FlatBatch2D FlatBatch(int layer=0, DepthStencilState depthStencilState=null, RasterizerState rasterizerState=null, BlendState blendState=null)
void Flush(bool clearAfterFlush=true, int maxLayer=int.MaxValue)
FontBatch2D FontBatch(BitmapFont font=null, int layer=0, DepthStencilState depthStencilState=null, RasterizerState rasterizerState=null, BlendState blendState=null, SamplerState samplerState=null)
static SamplerState PointClamp
static SamplerState LinearClamp
static void Error(object message)
static string ClipboardString
static object Get(Type type, string name)
static string GetContentWidgets(string name, string prop)
static string Get(string className, int key)
获取在当前语言类名键对应的字符串
override void Draw(ref Vector2 position)
override void Draw(ref Vector2 position)
override void Draw(ref Vector2 position)
override void Draw(ref Vector2 position)
int m_relativeCaretPosition
override void Draw(ref Vector2 position)
override void Run(TextBoxWidget widget)
void Draw(ref Vector2 position)
void Run(TextBoxWidget widget)
static int CandidatesSelection
Action< TextBoxWidget > TextChanged
Action< TextBoxWidget > Enter
static string[] SplitStringAt(string str, int splitPosition)
void LimitScrollValue()
限制 Scroll 属性的值。
virtual void Draw_(DrawContext dc)
static void CloseInputMethod()
override void UpdateCeases()
Action< TextBoxWidget > Escape
static TextBoxWidget FocusedTextBox
Action< TextBoxWidget > FocusLost
void BackSpace(char? character=null, int count=1, bool moveCaret=true)
Vector2 CandidateListOffset
static string[] CharacterKindsMap
static string[] CandidatesList
static bool ShowCandidatesWindow
Action< TextBoxWidget > OnFocus
static bool InputMethodEnabled
static void ShowInputMethod()
Color CandidateSelectionColor
float CandidateWindowLength
override void MeasureOverride(Vector2 parentAvailableSize)
void EnterText(string value)
static int CandidatesPageSize
bool DragStartedInsideTextBox
void EnterCharacter(char value, int position=-1, bool moveCaret=true)
Queue< UpdateTask > TasksQueue
每帧执行一次的任务队列。
override void Overdraw(DrawContext dc)
void EnterText(string value, int index)
bool SwitchTextBoxWhenTabbed
Color CandidateWindowColor
override void Draw(DrawContext dc)
static void SetCursorPosition(TextBoxWidget widget)
void ChangeTextNoEvent(string value)
Vector2? LastDragPosition
void Delete(char? character=null, int count=1)
readonly PrimitivesRenderer2D PrimitivesRenderer2D
static Matrix CreateTranslation(float x, float y, float z)
static readonly Vector2 Zero
static readonly Vector2 UnitY
static Vector2 Transform(Vector2 v, Matrix m)
static readonly Vector2 UnitX