!7 sclass Entry { S item, reasoning, feedback = ""; sS _fieldOrder = "reasoning item feedback"; } cmodule ListWithFeedback > DynObjectTable { S description, code, computerNotes, humanNotes, metaData, globalIDSaved; start { defaultAction = voidfunc(Entry e) { inputText("Feedback for: " + e.item, e.feedback, feedback -> { e.feedback = feedback; change(); }); }; } visual northCenterAndSouthWithMargins( northAndCenterWithMargin( centerAndEastWithMargin( dm_textFieldWithLabel description(), jThreadedButton("Save data", rEnter saveData)), jMinHeight(70, jhsplit(0.75, dm_textAreaWithTitle code(), dm_textAreaWithTitle computerNotes()))), withTitle("The List", super), centerAndEastWithMargin( jMinHeight(70, dm_textAreaWithTitle humanNotes()), jSouth(jbutton("All good", r-thread { setField(humanNotes := "all good"); })))); // API void saveData { File dir = ai_listsWithFeedbackDir(); setField(metaData := "Made on computer " + computerID() + " on " + localDateWithSeconds()); S globalID = aGlobalID(); S struct = javaTokWordWrap(dm_freshModuleStruct()); setField(globalIDSaved := globalID); infoBox("Saved: " + renderFileInfo(saveTextFile(newFile(dir, globalID + ".struct"), struct))); } // takes a list of strings or pairs (item + reasoning) void importItems(L l) { setData(map(l, o -> { o = quickImport(o); if (o cast Pair) ret nu Entry(item := o.a, reasoning := o.b); if (o cast WithReasoning) ret nu Entry(item := str(o!), reasoning := o.reasoning); ret nu Entry(item := str(o)); })); } }