sclass JChatConvo extends SingleComponentPanel { JLabel label; L posts = synchroList(); // params = contents, right, contents, right, ... *(O... params) { for (int i = 0; i+1 < l(params); i += 2) addPost(strUnnull(params[i]), isTrue(params[i+1])); // TODO: update only once setComponent(withMargin(label = jTopLabel())); onResize(label, r update); } srecord Post(S html, bool right) {} selfType addPost(S html, bool right) { swing { posts.add(new Post(html, right)); updateAndScrollDown(); } this; } void clearPosts { posts.clear(); update(); } void usePostsList(L posts) { this.posts = assertNotNull(posts); updateAndScrollDown(); } void update swing { if (label == null) ret; setText(label, hhtml(htmlForJLabel_chatConvo_table( cloneMap(posts, p -> pair(p.html, p.right)), label.getWidth()))); } void updateAndScrollDown { update(); scrollDown(); } void scrollDown { scrollAllTheWayDown(JChatConvo.this); } L posts() { ret cloneList(posts); } }