convert from tilepane to gridpane to resolve mnemonic words layout issue
What changed, and why it matters
This commit is a purely cosmetic UI change in the Sparrow Wallet desktop app. It swaps the JavaFX layout component used to display BIP39 mnemonic word fields from a TilePane to a GridPane so the 12 or 24 seed words line up in a tidy grid. There is no change to how seed words are generated, stored, validated, or protected, and no security-relevant behavior is introduced or fixed.
No security action required; treat as a normal UI/layout fix.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch refactors MnemonicKeystoreDisplayPane and MnemonicKeystorePane to replace TilePane with GridPane for rendering mnemonic word entry/display fields. It removes TilePane/Orientation imports, changes the wordsPane field type to GridPane, and explicitly places each WordEntry at a calculated (col, row) instead of relying on TilePane’s flow layout. The number of columns is fixed at 3 and rows are derived from numWords/3. No cryptographic, validation, persistence, or input-handling logic is modified.
Changed components
src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreDisplayPane.javasrc/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.javaInspect captured patch +20 / −16
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreDisplayPane.java b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreDisplayPane.java
index 9b59fc0..9d1ba4e 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreDisplayPane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystoreDisplayPane.java
@@ -6,10 +6,9 @@ import com.sparrowwallet.drongo.wallet.WalletModel;
import javafx.beans.property.SimpleListProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
-import javafx.geometry.Orientation;
import javafx.scene.Node;
+import javafx.scene.layout.GridPane;
import javafx.scene.layout.StackPane;
-import javafx.scene.layout.TilePane;
import javafx.scene.layout.VBox;
import java.util.ArrayList;
@@ -32,11 +31,9 @@ public class MnemonicKeystoreDisplayPane extends MnemonicKeystorePane {
VBox vBox = new VBox();
vBox.setSpacing(10);
- wordsPane = new TilePane();
- wordsPane.setPrefRows(Math.ceilDiv(numWords, 3));
+ wordsPane = new GridPane();
wordsPane.setHgap(10);
wordsPane.setVgap(10);
- wordsPane.setOrientation(Orientation.VERTICAL);
List<String> words = new ArrayList<>();
for(int i = 0; i < numWords; i++) {
@@ -53,7 +50,14 @@ public class MnemonicKeystoreDisplayPane extends MnemonicKeystorePane {
wordEntries.get(i).setNextEntry(wordEntries.get(i + 1));
wordEntries.get(i).setNextField(wordEntries.get(i + 1).getEditor());
}
- wordsPane.getChildren().addAll(wordEntries);
+
+ int numCols = 3;
+ int numRows = Math.ceilDiv(numWords, numCols);
+ for(int i = 0; i < wordEntries.size(); i++) {
+ int col = i / numRows;
+ int row = i % numRows;
+ wordsPane.add(wordEntries.get(i), col, row);
+ }
vBox.getChildren().add(wordsPane);
diff --git a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.java b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.java
index 3697dcf..752257a 100644
--- a/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.java
+++ b/src/main/java/com/sparrowwallet/sparrow/control/MnemonicKeystorePane.java
@@ -15,20 +15,15 @@ import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ListChangeListener;
import javafx.collections.ObservableList;
-import javafx.concurrent.ScheduledService;
-import javafx.concurrent.Task;
import javafx.geometry.Insets;
-import javafx.geometry.Orientation;
import javafx.geometry.Pos;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.input.Clipboard;
import javafx.scene.layout.*;
import javafx.util.Callback;
-import javafx.util.Duration;
import org.controlsfx.control.textfield.AutoCompletionBinding;
import org.controlsfx.control.textfield.TextFields;
-import org.controlsfx.glyphfont.Glyph;
import org.controlsfx.validation.ValidationResult;
import org.controlsfx.validation.ValidationSupport;
import org.controlsfx.validation.Validator;
@@ -44,7 +39,7 @@ public class MnemonicKeystorePane extends TitledDescriptionPane {
private static final Logger log = LoggerFactory.getLogger(MnemonicKeystorePane.class);
protected SplitMenuButton enterMnemonicButton;
- protected TilePane wordsPane;
+ protected GridPane wordsPane;
protected Label validLabel;
protected Label invalidLabel;
@@ -167,11 +162,9 @@ public class MnemonicKeystorePane extends TitledDescriptionPane {
VBox vBox = new VBox();
vBox.setSpacing(10);
- wordsPane = new TilePane();
- wordsPane.setPrefRows(Math.ceilDiv(numWords, 3));
+ wordsPane = new GridPane();
wordsPane.setHgap(10);
wordsPane.setVgap(10);
- wordsPane.setOrientation(Orientation.VERTICAL);
List<String> words = new ArrayList<>();
for(int i = 0; i < numWords; i++) {
@@ -188,7 +181,14 @@ public class MnemonicKeystorePane extends TitledDescriptionPane {
wordEntries.get(i).setNextEntry(wordEntries.get(i + 1));
wordEntries.get(i).setNextField(wordEntries.get(i + 1).getEditor());
}
- wordsPane.getChildren().addAll(wordEntries);
+
+ int numCols = 3;
+ int numRows = Math.ceilDiv(numWords, numCols);
+ for(int i = 0; i < wordEntries.size(); i++) {
+ int col = i / numRows;
+ int row = i % numRows;
+ wordsPane.add(wordEntries.get(i), col, row);
+ }
vBox.getChildren().add(wordsPane);
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.