!7 module MarkImage > DynImageSurface { File file; transient JTable table; start { ownResource(onClipboardFile_monitorRegularly(3.0, vf loadFile)); } void loadFile(final File f) enter { if (!isImageFile(f)) ret; setModuleName("Mark Image - " + f2s(f)); setField(file := f); setImage(loadImage2(file)); showMarkings(); } visualize { table = sexyTable(); JComponent i = super.visualize(); loadFile(file); ret withCenteredButtons(jvsplit(i, jSection("Marked things", table)), imageSelectionDepend(imageSurface, jbutton("Mark selection...", rThread markSelection)), tableDependentButton(table, "Delete item", rThread { saveImageFileMarkings(file, removeAndReturnCollection(loadMarkings(), selectedTableRow(table))); showMarkings(); }), jHelpIcon("Copy an image file (must be a file on disk) to the clipboard to mark it here")); } void markSelection enter { Rect r = getSelection(); if (r == null) ret; inputText("Enter description for selected area", voidfunc(S name) { LPair markings = loadMarkings(); setAdd(markings, pair(r, name)); print("New markings:"); pnlIndent(markings); saveImageFileMarkings(file, markings); showMarkings(); }); } LPair loadMarkings() { ret unnull(loadImageFileMarkings(file)); } void showMarkings { LPair markings = loadMarkings(); dataToTable(table, map(markings, p -> litorderedmap("Rect" := str(p.a), "Description" := p.b))); overlaySelectionsOnImageSurface(imageSurface, pairsA(loadMarkings())); } }