abstract sclass DynDialogWithUser > DynModule { L dialog = synchroList(); S input; transient JTextArea taDialog; transient JTextField tfInput; transient L onUserInput; sclass DialogItem { S author, line; long timestamp = now(); toString { ret "[" + localTimeWithSeconds(timestamp) + "] " + author + ": " + line; } } visualize { tfInput = dm_fieldTextField('input); onEnter(tfInput, rThread sendInput); ret centerAndSouthWithMargins( jSection("Dialog", taDialog = setDisabledTextColor(Color.black, makeUneditable(jLiveValueWordWrapTypeWriterTextArea_autoScroll( dm_calculatedLiveValue(S, func -> S { dialogToString() }))))), withLabel("Your input:", tfInput)); } void sendInput { S input = this.input; addLine('User, input); selectAll(tfInput); pcallFAll(onUserInput, input); } void onUserInput(VF1 r) { onUserInput = createOrAddToSyncList(onUserInput, r); } // API S dialogToString() { ret lines_rtrim(allToString(cloneList(dialog))); } void addLine(S author, S line) { dialog.add(nu(DialogItem.class, +author, +line)); change(); } }