diff --git a/CodenameOne/src/com/codename1/ui/TextArea.java b/CodenameOne/src/com/codename1/ui/TextArea.java index cb7f447db40..bebfe7ec53b 100644 --- a/CodenameOne/src/com/codename1/ui/TextArea.java +++ b/CodenameOne/src/com/codename1/ui/TextArea.java @@ -151,6 +151,9 @@ public class TextArea extends Component implements ActionSource, TextHolder { private final EventDispatcher listeners = new EventDispatcher(); private ActionListener doneListener; private int valign = defaultValign; + /// True once setVerticalAlignment() has been called, so the multi-line TOP + /// default in getVerticalAlignment() no longer overrides an explicit choice. + private boolean verticalAlignmentSet; private int linesToScroll = 1; //private int modifierFlag = 0x00000; /// Unsupported characters is a string that contains characters that cause issues @@ -1380,6 +1383,15 @@ void paintHint(Graphics g) { if (Display.getInstance().isNativeEditorVisible(this) && Display.impl.nativeEditorPaintsHint()) { return; } + // For multi-row text areas, keep the hint vertically aligned with where + // the text will actually be rendered/edited so it doesn't sit in the + // middle while the cursor is on the first line (issue #5345). Single-line + // fields and one-row growable fields (e.g. a chat input) keep their + // existing (centered) hint behavior since there is no meaningful gap. + Label hint = getHintLabelImpl(); + if (hint != null && !isSingleLineTextArea() && getActualRows() > 1) { + hint.setVerticalAlignment(getVerticalAlignment()); + } super.paintHint(g); } @@ -1852,11 +1864,16 @@ boolean shouldShowHint() { return "".equals(getText()); } - /// Returns the vertical alignment of the text field. + /// Returns the vertical alignment of the text field, one of: CENTER, TOP, BOTTOM /// - /// For multi-line text areas, this alignment is applied only while there is extra - /// vertical space in the component. If the text content uses all available height - /// (or overflows), the rendering naturally starts from the top. + /// Multi-line text areas default to #TOP, regardless of the theme default + /// (`textCmpVAlignInt`, which is meant for single-line fields). Single-line fields + /// keep the theme default. A value passed to #setVerticalAlignment(int) is always + /// honored as-is, so an explicit #CENTER / #BOTTOM still works (e.g. for display + /// text). For editable multi-line areas the #TOP default also keeps the lightweight + /// rendering aligned with the native editor, which top-aligns its content on every + /// current platform, so the text, cursor and hint don't jump when editing starts + /// and ends (issue #5345). /// /// #### Returns /// @@ -1870,6 +1887,9 @@ boolean shouldShowHint() { /// /// - #BOTTOM public int getVerticalAlignment() { + if (!verticalAlignmentSet && !isSingleLineTextArea()) { + return TOP; + } return valign; } @@ -1879,6 +1899,11 @@ public int getVerticalAlignment() { /// vertical space in the component. If there is no extra room, alignment becomes /// effectively top-aligned because content already fills the available area. /// + /// Setting a value here overrides the multi-line #TOP default described in + /// #getVerticalAlignment(): the value you pass is honored even for an editable + /// multi-line area (which may then visibly shift when its native editor, which + /// top-aligns, takes over). + /// /// #### Parameters /// /// - `valign`: alignment value @@ -1895,6 +1920,7 @@ public void setVerticalAlignment(int valign) { throw new IllegalArgumentException("Alignment can't be set to " + valign); } this.valign = valign; + this.verticalAlignmentSet = true; } /// {@inheritDoc} diff --git a/maven/core-unittests/src/test/java/com/codename1/ui/TextAreaTest.java b/maven/core-unittests/src/test/java/com/codename1/ui/TextAreaTest.java index c792db02b5e..8ff225ffb6a 100644 --- a/maven/core-unittests/src/test/java/com/codename1/ui/TextAreaTest.java +++ b/maven/core-unittests/src/test/java/com/codename1/ui/TextAreaTest.java @@ -412,6 +412,63 @@ void testVerticalAlignmentRejectsInvalidValues() { assertThrows(IllegalArgumentException.class, () -> textArea.setVerticalAlignment(Component.BASELINE)); } + @FormTest + void testMultilineDefaultsToTop() { + // Regression test for #5345: with a CENTER theme default a multi-line text + // area reports TOP by default (the theme default is meant for single-line + // fields). For an editable area this matches the top-aligning native editor, + // so the text doesn't jump when editing starts and ends. + int previous = TextArea.getDefaultValign(); + TextArea.setDefaultValign(Component.CENTER); + try { + TextArea editable = new TextArea("text text", 3, 20); + editable.setEditable(true); + assertEquals(Component.TOP, editable.getVerticalAlignment()); + + TextArea nonEditable = new TextArea("text text", 3, 20); + nonEditable.setEditable(false); + assertEquals(Component.TOP, nonEditable.getVerticalAlignment()); + } finally { + TextArea.setDefaultValign(previous); + } + } + + @FormTest + void testExplicitVerticalAlignmentOverridesMultilineDefault() { + // An explicit setVerticalAlignment() is honored even for a multi-line area, + // so display text can still be centered/bottom-aligned. + int previous = TextArea.getDefaultValign(); + TextArea.setDefaultValign(Component.CENTER); + try { + TextArea textArea = new TextArea("text text", 3, 20); + textArea.setEditable(false); + + textArea.setVerticalAlignment(Component.CENTER); + assertEquals(Component.CENTER, textArea.getVerticalAlignment()); + + textArea.setVerticalAlignment(Component.BOTTOM); + assertEquals(Component.BOTTOM, textArea.getVerticalAlignment()); + } finally { + TextArea.setDefaultValign(previous); + } + } + + @FormTest + void testSingleLineKeepsThemeVerticalAlignment() { + // Single-line fields keep the theme default (they center vertically in their + // native editor). + int previous = TextArea.getDefaultValign(); + TextArea.setDefaultValign(Component.CENTER); + try { + TextArea textArea = new TextArea("text", 1, 20); + textArea.setSingleLineTextArea(true); + textArea.setEditable(true); + assertEquals(Component.CENTER, textArea.getVerticalAlignment()); + } finally { + TextArea.setDefaultValign(previous); + } + } + @FormTest void testVerticalAlignmentScreenshotStates() { Form form = new Form("TextArea VAlign", BoxLayout.y()); diff --git a/scripts/ios/screenshots-metal/ButtonTheme_dark.png b/scripts/ios/screenshots-metal/ButtonTheme_dark.png index b646ddd393f..600162abb87 100644 Binary files a/scripts/ios/screenshots-metal/ButtonTheme_dark.png and b/scripts/ios/screenshots-metal/ButtonTheme_dark.png differ diff --git a/scripts/ios/screenshots-metal/ButtonTheme_light.png b/scripts/ios/screenshots-metal/ButtonTheme_light.png index 80d74fe9295..d76293afd97 100644 Binary files a/scripts/ios/screenshots-metal/ButtonTheme_light.png and b/scripts/ios/screenshots-metal/ButtonTheme_light.png differ diff --git a/scripts/ios/screenshots-metal/ChatView_dark.png b/scripts/ios/screenshots-metal/ChatView_dark.png index 1cb9d2baddc..6884086cb93 100644 Binary files a/scripts/ios/screenshots-metal/ChatView_dark.png and b/scripts/ios/screenshots-metal/ChatView_dark.png differ diff --git a/scripts/ios/screenshots-metal/ChatView_light.png b/scripts/ios/screenshots-metal/ChatView_light.png index 0690a5893dd..ab128a749db 100644 Binary files a/scripts/ios/screenshots-metal/ChatView_light.png and b/scripts/ios/screenshots-metal/ChatView_light.png differ diff --git a/scripts/ios/screenshots-metal/DialogTheme_dark.png b/scripts/ios/screenshots-metal/DialogTheme_dark.png index 835c0f2402e..b57cedfe387 100644 Binary files a/scripts/ios/screenshots-metal/DialogTheme_dark.png and b/scripts/ios/screenshots-metal/DialogTheme_dark.png differ diff --git a/scripts/ios/screenshots-metal/DialogTheme_light.png b/scripts/ios/screenshots-metal/DialogTheme_light.png index 280ab7bf595..c5e3dc51d2e 100644 Binary files a/scripts/ios/screenshots-metal/DialogTheme_light.png and b/scripts/ios/screenshots-metal/DialogTheme_light.png differ diff --git a/scripts/ios/screenshots-metal/ShowcaseTheme_dark.png b/scripts/ios/screenshots-metal/ShowcaseTheme_dark.png index e805dfe44f5..310a8bf35e2 100644 Binary files a/scripts/ios/screenshots-metal/ShowcaseTheme_dark.png and b/scripts/ios/screenshots-metal/ShowcaseTheme_dark.png differ diff --git a/scripts/ios/screenshots-metal/ShowcaseTheme_light.png b/scripts/ios/screenshots-metal/ShowcaseTheme_light.png index c5430c8636b..63ce808d03f 100644 Binary files a/scripts/ios/screenshots-metal/ShowcaseTheme_light.png and b/scripts/ios/screenshots-metal/ShowcaseTheme_light.png differ diff --git a/scripts/ios/screenshots-metal/SpanLabelTheme_dark.png b/scripts/ios/screenshots-metal/SpanLabelTheme_dark.png index 99985d536dd..2d960adc96e 100644 Binary files a/scripts/ios/screenshots-metal/SpanLabelTheme_dark.png and b/scripts/ios/screenshots-metal/SpanLabelTheme_dark.png differ diff --git a/scripts/ios/screenshots-metal/SpanLabelTheme_light.png b/scripts/ios/screenshots-metal/SpanLabelTheme_light.png index 091a5367a1b..626947f7ce6 100644 Binary files a/scripts/ios/screenshots-metal/SpanLabelTheme_light.png and b/scripts/ios/screenshots-metal/SpanLabelTheme_light.png differ diff --git a/scripts/ios/screenshots-metal/SwitchTheme_dark.png b/scripts/ios/screenshots-metal/SwitchTheme_dark.png index 3d820b73367..828a18614cb 100644 Binary files a/scripts/ios/screenshots-metal/SwitchTheme_dark.png and b/scripts/ios/screenshots-metal/SwitchTheme_dark.png differ diff --git a/scripts/ios/screenshots-metal/SwitchTheme_light.png b/scripts/ios/screenshots-metal/SwitchTheme_light.png index e00e5fe1b8d..359a785b45e 100644 Binary files a/scripts/ios/screenshots-metal/SwitchTheme_light.png and b/scripts/ios/screenshots-metal/SwitchTheme_light.png differ diff --git a/scripts/ios/screenshots-metal/TextFieldTheme_dark.png b/scripts/ios/screenshots-metal/TextFieldTheme_dark.png index 0c14e60e781..114b7ee451a 100644 Binary files a/scripts/ios/screenshots-metal/TextFieldTheme_dark.png and b/scripts/ios/screenshots-metal/TextFieldTheme_dark.png differ diff --git a/scripts/ios/screenshots-metal/TextFieldTheme_light.png b/scripts/ios/screenshots-metal/TextFieldTheme_light.png index f44d1ef922f..4869333a3fb 100644 Binary files a/scripts/ios/screenshots-metal/TextFieldTheme_light.png and b/scripts/ios/screenshots-metal/TextFieldTheme_light.png differ diff --git a/scripts/ios/screenshots-tv/ChatView_dark.png b/scripts/ios/screenshots-tv/ChatView_dark.png index e70972aca46..3b22faf7638 100644 Binary files a/scripts/ios/screenshots-tv/ChatView_dark.png and b/scripts/ios/screenshots-tv/ChatView_dark.png differ diff --git a/scripts/ios/screenshots-tv/ChatView_light.png b/scripts/ios/screenshots-tv/ChatView_light.png index ae911471dcf..3c05a94c201 100644 Binary files a/scripts/ios/screenshots-tv/ChatView_light.png and b/scripts/ios/screenshots-tv/ChatView_light.png differ diff --git a/scripts/ios/screenshots-tv/SpanLabelTheme_dark.png b/scripts/ios/screenshots-tv/SpanLabelTheme_dark.png index 693767a15a6..d1cac6b3ebd 100644 Binary files a/scripts/ios/screenshots-tv/SpanLabelTheme_dark.png and b/scripts/ios/screenshots-tv/SpanLabelTheme_dark.png differ diff --git a/scripts/ios/screenshots-tv/SpanLabelTheme_light.png b/scripts/ios/screenshots-tv/SpanLabelTheme_light.png index 01bc95b2665..ae9dcf4d98e 100644 Binary files a/scripts/ios/screenshots-tv/SpanLabelTheme_light.png and b/scripts/ios/screenshots-tv/SpanLabelTheme_light.png differ diff --git a/scripts/ios/screenshots-watch/AppReviewDialog.png b/scripts/ios/screenshots-watch/AppReviewDialog.png index 56f1722a026..c76dbc11168 100644 Binary files a/scripts/ios/screenshots-watch/AppReviewDialog.png and b/scripts/ios/screenshots-watch/AppReviewDialog.png differ diff --git a/scripts/ios/screenshots-watch/ChatView_dark.png b/scripts/ios/screenshots-watch/ChatView_dark.png index 7bbfc086784..a3af62a3d73 100644 Binary files a/scripts/ios/screenshots-watch/ChatView_dark.png and b/scripts/ios/screenshots-watch/ChatView_dark.png differ diff --git a/scripts/ios/screenshots-watch/ChatView_light.png b/scripts/ios/screenshots-watch/ChatView_light.png index fc7a375f899..8b9196c731b 100644 Binary files a/scripts/ios/screenshots-watch/ChatView_light.png and b/scripts/ios/screenshots-watch/ChatView_light.png differ diff --git a/scripts/ios/screenshots-watch/DialogTheme_dark.png b/scripts/ios/screenshots-watch/DialogTheme_dark.png index 5db50b26cb3..819b5e3f97f 100644 Binary files a/scripts/ios/screenshots-watch/DialogTheme_dark.png and b/scripts/ios/screenshots-watch/DialogTheme_dark.png differ diff --git a/scripts/ios/screenshots-watch/DialogTheme_light.png b/scripts/ios/screenshots-watch/DialogTheme_light.png index ae1e2b880a0..5cbf9961af1 100644 Binary files a/scripts/ios/screenshots-watch/DialogTheme_light.png and b/scripts/ios/screenshots-watch/DialogTheme_light.png differ diff --git a/scripts/ios/screenshots-watch/SpanLabelTheme_dark.png b/scripts/ios/screenshots-watch/SpanLabelTheme_dark.png index 6f86b1db910..4f386fd984d 100644 Binary files a/scripts/ios/screenshots-watch/SpanLabelTheme_dark.png and b/scripts/ios/screenshots-watch/SpanLabelTheme_dark.png differ diff --git a/scripts/ios/screenshots-watch/SpanLabelTheme_light.png b/scripts/ios/screenshots-watch/SpanLabelTheme_light.png index aedbeb9567b..f03c335cbdf 100644 Binary files a/scripts/ios/screenshots-watch/SpanLabelTheme_light.png and b/scripts/ios/screenshots-watch/SpanLabelTheme_light.png differ diff --git a/scripts/ios/screenshots/ButtonTheme_dark.png b/scripts/ios/screenshots/ButtonTheme_dark.png index 22abe6a5cad..f4b45ddd207 100644 Binary files a/scripts/ios/screenshots/ButtonTheme_dark.png and b/scripts/ios/screenshots/ButtonTheme_dark.png differ diff --git a/scripts/ios/screenshots/ButtonTheme_light.png b/scripts/ios/screenshots/ButtonTheme_light.png index 34ba65441f0..b2af4cf699e 100644 Binary files a/scripts/ios/screenshots/ButtonTheme_light.png and b/scripts/ios/screenshots/ButtonTheme_light.png differ diff --git a/scripts/ios/screenshots/ChatView_dark.png b/scripts/ios/screenshots/ChatView_dark.png index c42defb9db0..e77eed2fc16 100644 Binary files a/scripts/ios/screenshots/ChatView_dark.png and b/scripts/ios/screenshots/ChatView_dark.png differ diff --git a/scripts/ios/screenshots/ChatView_light.png b/scripts/ios/screenshots/ChatView_light.png index bf5f4091cf1..962d3ebfd95 100644 Binary files a/scripts/ios/screenshots/ChatView_light.png and b/scripts/ios/screenshots/ChatView_light.png differ diff --git a/scripts/ios/screenshots/DialogTheme_dark.png b/scripts/ios/screenshots/DialogTheme_dark.png index a8d53816c46..22ebcb93584 100644 Binary files a/scripts/ios/screenshots/DialogTheme_dark.png and b/scripts/ios/screenshots/DialogTheme_dark.png differ diff --git a/scripts/ios/screenshots/DialogTheme_light.png b/scripts/ios/screenshots/DialogTheme_light.png index 389e29308f5..9189b96d37c 100644 Binary files a/scripts/ios/screenshots/DialogTheme_light.png and b/scripts/ios/screenshots/DialogTheme_light.png differ diff --git a/scripts/ios/screenshots/ShowcaseTheme_dark.png b/scripts/ios/screenshots/ShowcaseTheme_dark.png index 09281c80300..6d2c8bbf119 100644 Binary files a/scripts/ios/screenshots/ShowcaseTheme_dark.png and b/scripts/ios/screenshots/ShowcaseTheme_dark.png differ diff --git a/scripts/ios/screenshots/ShowcaseTheme_light.png b/scripts/ios/screenshots/ShowcaseTheme_light.png index 966a77e69e9..b4fd4fffe84 100644 Binary files a/scripts/ios/screenshots/ShowcaseTheme_light.png and b/scripts/ios/screenshots/ShowcaseTheme_light.png differ diff --git a/scripts/ios/screenshots/SpanLabelTheme_dark.png b/scripts/ios/screenshots/SpanLabelTheme_dark.png index 5ab62a71887..3b666c3d8f5 100644 Binary files a/scripts/ios/screenshots/SpanLabelTheme_dark.png and b/scripts/ios/screenshots/SpanLabelTheme_dark.png differ diff --git a/scripts/ios/screenshots/SpanLabelTheme_light.png b/scripts/ios/screenshots/SpanLabelTheme_light.png index 97c978d9bde..bf43fa4bd97 100644 Binary files a/scripts/ios/screenshots/SpanLabelTheme_light.png and b/scripts/ios/screenshots/SpanLabelTheme_light.png differ diff --git a/scripts/ios/screenshots/TextFieldTheme_dark.png b/scripts/ios/screenshots/TextFieldTheme_dark.png index 80433128839..f33c6783efb 100644 Binary files a/scripts/ios/screenshots/TextFieldTheme_dark.png and b/scripts/ios/screenshots/TextFieldTheme_dark.png differ diff --git a/scripts/ios/screenshots/TextFieldTheme_light.png b/scripts/ios/screenshots/TextFieldTheme_light.png index dd5ac799a9b..413858627dc 100644 Binary files a/scripts/ios/screenshots/TextFieldTheme_light.png and b/scripts/ios/screenshots/TextFieldTheme_light.png differ diff --git a/scripts/mac-native/screenshots/ButtonTheme_dark.png b/scripts/mac-native/screenshots/ButtonTheme_dark.png index 3a354ee38fc..dbc63706d35 100644 Binary files a/scripts/mac-native/screenshots/ButtonTheme_dark.png and b/scripts/mac-native/screenshots/ButtonTheme_dark.png differ diff --git a/scripts/mac-native/screenshots/ButtonTheme_light.png b/scripts/mac-native/screenshots/ButtonTheme_light.png index 6e00a451d33..6fefbbd33bf 100644 Binary files a/scripts/mac-native/screenshots/ButtonTheme_light.png and b/scripts/mac-native/screenshots/ButtonTheme_light.png differ diff --git a/scripts/mac-native/screenshots/ChatView_dark.png b/scripts/mac-native/screenshots/ChatView_dark.png index e1c5158fa09..d8f8087780f 100644 Binary files a/scripts/mac-native/screenshots/ChatView_dark.png and b/scripts/mac-native/screenshots/ChatView_dark.png differ diff --git a/scripts/mac-native/screenshots/ChatView_light.png b/scripts/mac-native/screenshots/ChatView_light.png index 0a5d63f9216..ff77481a6cf 100644 Binary files a/scripts/mac-native/screenshots/ChatView_light.png and b/scripts/mac-native/screenshots/ChatView_light.png differ diff --git a/scripts/mac-native/screenshots/DialogTheme_dark.png b/scripts/mac-native/screenshots/DialogTheme_dark.png index 965fa0328ac..e011cdc82e1 100644 Binary files a/scripts/mac-native/screenshots/DialogTheme_dark.png and b/scripts/mac-native/screenshots/DialogTheme_dark.png differ diff --git a/scripts/mac-native/screenshots/DialogTheme_light.png b/scripts/mac-native/screenshots/DialogTheme_light.png index 1a345a40a3d..82019da5eef 100644 Binary files a/scripts/mac-native/screenshots/DialogTheme_light.png and b/scripts/mac-native/screenshots/DialogTheme_light.png differ diff --git a/scripts/mac-native/screenshots/ShowcaseTheme_dark.png b/scripts/mac-native/screenshots/ShowcaseTheme_dark.png index 2070ee2d690..fa1ef0c2279 100644 Binary files a/scripts/mac-native/screenshots/ShowcaseTheme_dark.png and b/scripts/mac-native/screenshots/ShowcaseTheme_dark.png differ diff --git a/scripts/mac-native/screenshots/ShowcaseTheme_light.png b/scripts/mac-native/screenshots/ShowcaseTheme_light.png index aa1ba963b7a..494a27d43cc 100644 Binary files a/scripts/mac-native/screenshots/ShowcaseTheme_light.png and b/scripts/mac-native/screenshots/ShowcaseTheme_light.png differ diff --git a/scripts/mac-native/screenshots/SpanLabelTheme_dark.png b/scripts/mac-native/screenshots/SpanLabelTheme_dark.png index d2ada61da38..f94abc98635 100644 Binary files a/scripts/mac-native/screenshots/SpanLabelTheme_dark.png and b/scripts/mac-native/screenshots/SpanLabelTheme_dark.png differ diff --git a/scripts/mac-native/screenshots/SpanLabelTheme_light.png b/scripts/mac-native/screenshots/SpanLabelTheme_light.png index d45fa510f9a..14aa6128371 100644 Binary files a/scripts/mac-native/screenshots/SpanLabelTheme_light.png and b/scripts/mac-native/screenshots/SpanLabelTheme_light.png differ diff --git a/scripts/mac-native/screenshots/SwitchTheme_dark.png b/scripts/mac-native/screenshots/SwitchTheme_dark.png index d7e372be197..a3475035564 100644 Binary files a/scripts/mac-native/screenshots/SwitchTheme_dark.png and b/scripts/mac-native/screenshots/SwitchTheme_dark.png differ diff --git a/scripts/mac-native/screenshots/SwitchTheme_light.png b/scripts/mac-native/screenshots/SwitchTheme_light.png index db7b5a83f56..340b291a580 100644 Binary files a/scripts/mac-native/screenshots/SwitchTheme_light.png and b/scripts/mac-native/screenshots/SwitchTheme_light.png differ diff --git a/scripts/mac-native/screenshots/TextFieldTheme_dark.png b/scripts/mac-native/screenshots/TextFieldTheme_dark.png index 72efc8de5b3..caff020630c 100644 Binary files a/scripts/mac-native/screenshots/TextFieldTheme_dark.png and b/scripts/mac-native/screenshots/TextFieldTheme_dark.png differ diff --git a/scripts/mac-native/screenshots/TextFieldTheme_light.png b/scripts/mac-native/screenshots/TextFieldTheme_light.png index 5845aa3e24b..8a13205dcd0 100644 Binary files a/scripts/mac-native/screenshots/TextFieldTheme_light.png and b/scripts/mac-native/screenshots/TextFieldTheme_light.png differ