Skip to content

Refactor legacy text input stack to ui::InputField and unify font handling APIs#3173

Draft
halx99 wants to merge 88 commits into
devfrom
input-field
Draft

Refactor legacy text input stack to ui::InputField and unify font handling APIs#3173
halx99 wants to merge 88 commits into
devfrom
input-field

Conversation

@halx99
Copy link
Copy Markdown
Collaborator

@halx99 halx99 commented May 19, 2026

Describe your changes

  • Replace legacy TextFieldTTF usage/removal and shift text input flows toward ui::InputField/IME-based behavior.
  • Add unified Label::create(text, fontName, fontSize) API with automatic font-type detection (BMFont/TTF/system font).
  • Add Label::setFontInfo(fontName, fontSize) to centralize runtime font switching.
  • Clean up Label internals by removing cached _lengthOfString state and deriving count from UTF-32 text (getCharCount()), reducing stale-length risks.
  • Introduce/rename clearer label query APIs (getLineCount(), getCharCount()) while keeping backward-compatible deprecated wrappers.
  • Harden UTF-8 handling paths in label/text operations (avoid accepting invalid UTF-8 silently).
  • Update desktop/input related plumbing and scene/UI compatibility touchpoints associated with the migration.
  • Apply broad cleanup/modernization in tests and headers (e.g., #pragma once, include path corrections, minor code hygiene).
  • Integrate iOS System Copy/Paste Menu for InputField Editing

Issue ticket number and link

Checklist before requesting a review

For each PR

  • Add Copyright if it missed:
    - "Copyright (c) 2019-present Axmol Engine contributors (see AUTHORS.md)."

  • I have performed a self-review of my code.

    Optional:

    • I have checked readme and add important infos to this PR.
    • I have added/adapted some tests too.

For core/new feature PR

  • I have checked readme and add important infos to this PR.
  • I have added thorough tests.

Axmol 3.x ------------------------------------------------------------

For each 3.x PR

  • Check the '#include "axmol.h"' and replace it with the needed headers.

@halx99 halx99 added this to the 3.0.0 milestone May 19, 2026
@halx99 halx99 linked an issue May 19, 2026 that may be closed by this pull request
@halx99 halx99 changed the title Input field Implement #3168 May 19, 2026
@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 19, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 211c215351

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread axmol/ui/UIWidget.cpp Outdated
Comment thread extensions/scripting/lua-bindings/auto/axlua_ui_auto.cpp Outdated
@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 20, 2026

/clang-format

@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 20, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: d2aff1905b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread extensions/sceneio/src/sceneio/WidgetReader/WidgetReader.cpp Outdated
Comment thread axmol/ui/UIButton.cpp Outdated
Comment thread axmol/ui/UIWidget.cpp Outdated
Comment thread axmol/ui/InputField.cpp Outdated
@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 24, 2026

@codex Again, provide merge title and change detail list about this PR via https://patch-diff.githubusercontent.com/raw/axmolengine/axmol/pull/3173.diff

@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 24, 2026

/clang-format

@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 24, 2026

@codex review

@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 24, 2026

@gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the UI and text input systems, replacing legacy TextField components with a new InputField widget and introducing a cross-platform clipboard API. It also updates the layout system by replacing ignoreContentAdaptWithSize with setAutoSize and renames various UI headers for consistency. Feedback highlights critical logic inversions in the setAutoSize implementation for several widgets (Button, ImageView, Slider, and LoadingBar) when Scale9 is enabled, which hinders manual sizing. Further improvements are suggested for Android clipboard robustness, touch position tracking in InputField, and optimizing the O(N^2) performance of the text layout measurement logic.

Comment thread axmol/ui/Button.cpp
Comment thread axmol/ui/ImageView.cpp Outdated
Comment thread axmol/ui/Slider.cpp Outdated
Comment thread axmol/ui/LoadingBar.cpp Outdated
Comment thread axmol/platform/android/java/src/dev/axmol/lib/AxmolEngine.java
Comment thread axmol/ui/InputField.cpp
Comment thread axmol/ui/InputField.cpp Outdated
@gemini-code-assist
Copy link
Copy Markdown

Hello halx99, thank you for reaching out. Regarding your question about the ui::InputField implementation, it is designed to be a more modern, IME-friendly replacement for the legacy TextFieldTTF.

Key improvements include:

  1. IME Integration: It utilizes the new InputDelegate and InputDispatcher architecture, which provides better support for platform-native IME features (like pre-edit text updates) compared to the legacy IMEDelegate.
  2. Cursor & Selection: It includes built-in cursor management and selection handling, which were significant pain points in the legacy implementation.
  3. Font Flexibility: The unified Label::create(text, fontName, fontSize) API allows for easier font handling across different types (BMFont, TTF, System).
  4. Performance: By deriving character counts from UTF-32 text (getCharCount()) and removing stale state like _lengthOfString, it reduces synchronization risks and improves performance.

If you are looking to migrate from TextFieldTTF or TextField, I recommend focusing on the InputField factory methods and the event-based listener system (addEventListener) to handle input changes, as this is the intended pattern for the new stack. Let me know if you have specific architectural questions or need help with a particular use case!

halx99 and others added 4 commits May 24, 2026 17:49
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 24, 2026

@gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request performs a major refactoring of the UI and input systems, replacing the deprecated TextFieldTTF and TextFieldEx widgets with a new InputField component that supports multiline text, cursors, and selections. The refactor includes a widespread renaming of UI classes and core methods (e.g., setAutoSize, getRenderNode) to improve API consistency, renames the IME system to a more general Input system, and introduces a cross-platform clipboard API. Review feedback identifies a high-severity risk of null pointer exceptions in the Android clipboard implementation and suggests adopting safer string access patterns in the InputField logic.

Comment thread axmol/platform/android/java/src/dev/axmol/lib/AxmolEngine.java
Comment thread axmol/ui/InputField.cpp Outdated
@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 24, 2026

/clang-format

@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 24, 2026

/clang-format

@halx99
Copy link
Copy Markdown
Collaborator Author

halx99 commented May 24, 2026

/gemini review

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request overhauls the text input and UI widget systems by introducing a modern InputField component to replace the deprecated TextFieldTTF and TextFieldEx. The new InputField supports multiline text, cursor control, selection, and native clipboard integration. Additionally, the Widget base class and its derivatives have been refactored to use a standardized setAutoSize and initRenderNode API, and the IME system has been renamed to InputDelegate. Reviewer feedback highlights significant efficiency and correctness concerns regarding character-by-character text measurement and the lack of word-level wrapping in multiline mode. Other actionable suggestions include syncing measurement labels with rendering effects, adjusting long-press trigger timing on mobile platforms, and correcting a typo in Label.cpp.

Comment thread axmol/ui/InputField.cpp
{
size_t nextByteOffset = _charByteOffsets[currentCharIdx + 1];
std::string_view charView(_inputText.data() + charByteOffset, nextByteOffset - charByteOffset);
charWidth = measureText(charView).width;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Measuring text character-by-character in a loop is extremely inefficient (O(N) heavy label updates) and typographically incorrect. It ignores kerning and ligatures, which will result in inaccurate cursor positioning for many fonts and languages. A better approach would be to measure the entire string and extract glyph positions from the FontAtlas or use Label's internal layout data if it can be exposed.

Comment thread axmol/2d/Label.cpp

void Label::setFontInfo(std::string_view fontName, float fontSize)
{
auto prevLableType = _currentLabelType;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

Typo in variable name: prevLableType should be prevLabelType.

    auto prevLabelType = _currentLabelType;

Comment thread axmol/ui/InputField.cpp
// Lazy initialize instance-specific measure label
if (!_measureLabel)
{
_measureLabel = Label::create(""sv, _fontName, _fontSize);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The _measureLabel is initialized with the font name and size, but it is never updated if the _renderLabel is subsequently modified with effects like outline or shadow. This will cause character width measurements to be incorrect, leading to cursor misalignment. Consider implementing a mechanism to sync the measure label's configuration with the render label.

Comment thread axmol/ui/InputField.cpp
}

// If the Label exposes internal padding or baseline offsets, apply them here.
// Example (pseudo): textBottomYInLabel += _renderLabel->getInternalPaddingBottom();
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This pseudo-code comment should be removed or implemented if it was intended to handle internal padding.

Comment thread axmol/ui/InputField.cpp
Vec2 localPoint = this->convertToNodeSpace(worldPoint);
moveCursorTo(localPoint, _selectionTouchMoved);

if (_continuousTouchPending && _continuousTouchElapsedTime >= _continuousTouchDelayTime)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The continuous touch (long press) logic only triggers the menu when the touch ends. Standard mobile behavior for text fields is to show the loupe or edit menu while the user is still holding the finger down. Consider moving the trigger logic to updateLayout or a timer callback.

Comment thread axmol/ui/InputField.cpp
if (_multilineEnabled && currentCharIdx > currentLine.startCharIndex)
{
// If adding this character exceeds available width, commit current line before tracking it
if (currentLine.charXOffsets.back() + charWidth > availableWidth)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The current multiline wrapping logic implements character-level wrapping, which breaks words in the middle. Most UI text inputs expect word-level wrapping. Consider implementing a word-wrap algorithm that looks for whitespace when a line exceeds the available width.

@halx99 halx99 marked this pull request as draft May 25, 2026 23:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

breaking changes enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unify Input control: ui::TextField, TextFieldTTF, ui::TextFieldEx

2 participants