// TODO: call fullyConfigured in normal constructor // (so we don't end up erroneously making EMPTY G22ShapeCollectorPanel's) sclass G22ShapeCollectorPanel > MetaWithChangeListeners is Swingable { settable G22Utils g22utils; settable bool qoiAlways; settableWithVar S imageSourceDesc = "Left screen half"; AnalyzedImage completedImage; // seconds per gradient color cycle settable double gradientCycleTime = 2.0; settable int maxDrift = 100; new MouseInComponentMonitor mouseMonitor; PicturesByMD5 pics; new JMaxSpeedAnimation anim; JCheckBox cbOn = jcheckbox("On", true); //JCheckBox cbFreezeOnHover = jcheckbox("Freeze on hover", true); JCheckBox cbAnimateGradients = jcheckbox("Animate gradients", false); JSpinner colorsSpinner = jListSpinner(itemPlus(2, dropFirst(firstNCubes(16)))); JSpinner blurSpinner = jSpinner(0, 0, 99); JLabel lblStats = rightAlignedLabel(); JSlider driftSlider; JCheckBox cbAntiDrift = jcheckbox("Antidrift", true); class AnalyzedImage extends G22DataWrangler { G22DataWrangler wrangler() { this; } simplyCached byte[] qoiData() { ret g22utils.timeFunction("QOI compress", -> toQOI(inputImage())); } simplyCached S qoiMD5() { ret md5(qoiData()); } S saveImage() { pics.put(qoiMD5(), qoiData()); ret qoiMD5(); } } void init { if (pics != null) ret; pics = g22utils.picturesByMD5(); driftSlider = jSlider(-maxDrift, maxDrift, 0); componentPopupMenuItem(driftSlider, "Reset", r { driftSlider.setValue(0) }); //looselyBindLiveValueToCheckBox(g22utils.liveProjectVar("Freeze on hover"), cbFreezeOnHover); looselyBindLiveValueToCheckBox(g22utils.liveProjectVar("Animate gradients"), cbAnimateGradients); looselyBindLiveValueToSpinner(g22utils.liveProjectVar("colors"), colorsSpinner); looselyBindLiveValueToSpinner(g22utils.liveProjectVar("blur"), blurSpinner); looselyBindLiveValueToSlider(g22utils.liveProjectVar("brightnessDrift"), driftSlider); looselyBindLiveValueToCheckBox(g22utils.liveProjectVar("Antidrift"), cbAntiDrift); } swappable BufferedImage nextInputImage() { ret shootLeftScreenHalf(); } selfType imageSource(IF0 imageSource, S imageSourceDesc default str(imageSource)) { nextInputImage = imageSource; imageSourceDesc = imageSourceDesc; this; } bool running() { ret isChecked(cbOn) /*&& !(isChecked(cbFreezeOnHover) && mouseMonitor!)*/; } BufferedImage nextFrame() { if (!running()) { sleepSeconds(0.1); null; } var inputImage = nextInputImage(); new AnalyzedImage ai; var wrangler = ai.wrangler(); wrangler.timings(g22utils.functionTimings()); wrangler.inputImage(inputImage); wrangler.colors(intFromSpinner(colorsSpinner)); wrangler.blur(intFromSpinner(blurSpinner)); // drift is between -1 and 1 var drift = (float) (intFromSlider(driftSlider)/100.0); if (isChecked(cbAnimateGradients)) drift = (float) transformFromZeroToOne(-1, 1, frac(sysSeconds()/gradientCycleTime)); wrangler.drift(drift); wrangler.antiDrift(isChecked(cbAntiDrift) || isChecked(cbAnimateGradients) ? -drift : 0); wrangler.stepUntilStage(wrangler.regionsStage); g22utils.setTransientProjectVar("Last wrangler", wrangler); L qoiInfo = !qoiAlways ? null : ll( "QOI: " + str_toK(l(ai.qoiData())), "Hash: " + takeFirst(3, ai.qoiMD5()), "Saved: " + yesNo_short(pics.has(ai.qoiMD5()))); setText(lblStats, commaCombine( anim.fps(), nRegions(wrangler.regions), qoiInfo, nImages(pics.imageCount()) + " saved", n2(countConcepts(g22utils.concepts(), G22PointOfInterest), "POI") ); completedImage = ai; g22utils.setTransientProjectVar("Last analyzed image", ai); ret toBufferedImage(wrangler.posterizedImage); } swappable JComponent watchingUI() { ret liveValueLabel(varImageSourceDesc()); } cachedVisualize { init(); anim.renderFrame(l0 nextFrame); mouseMonitor.init(anim.imageSurface()); // UI main layout ret northAndCenterWithMargins( northAndCenterWithMargin( jcenteredline(withLabel("Watching:", watchingUI())), jCenteredSection(" Visual Controls ", jHigherScrollPane_borderless_center(withSideMargin( jcenteredline( cbOn, //cbFreezeOnHover, jCenteredSection("Colors", colorsSpinner), jCenteredSection("Blur", blurSpinner), cbAnimateGradients, jCenteredSection("Drift", driftSlider), cbAntiDrift, ) )))), centerAndSouthWithMargin( jCenteredSection(" What I See ", anim), centerAndEastWithMargin(lblStats, jThreadedButton("Save image", -> { completedImage?.saveImage(); }))) ); } ImageSurface imageSurface() { ret anim.imageSurface(); } static G22ShapeCollectorPanel fullyConfigured(G22Utils g22utils, G22ShapeCollectorPanel collector default new) { ret (G22ShapeCollectorPanel) g22utils.leftArrowWithVars([[ collector g22utils < g22utils collector visualize is <- collector imageSurface hoveringOverRegion <- new Var is addOverlay < G2Drawable g -> { region <- hoveringOverRegion get if notNull region { //zoomGraphics g (is zoomY) (is zoomY) for outline in g22_allBorderTraces_autoDiagonals region { for p in outline { p <- scalePt p (is zoomY) (is zoomY) //drawPixel g p < Color green fillRect g (Color green) (p x) (p y) (iceil < is zoomX) (iceil < is zoomY) } } } } collector anim, displayNewImage <- IVF1 image -> { pt <- is mousePosition if isNull pt { hoveringOverRegion clear } else { ai <- collector completedImage regionMaker <- ai wrangler, regionMaker hoveringOverRegion set < regionMaker getRegion < regionMaker regionAt pt // TODO: doesn't work like this // if not < collector running { is repaint } } //toolTip is hoveringOverRegion collector anim, displayNewImage_base image } is imageSurfaceOnLeftClick < IVF1 pt -> { region <- hoveringOverRegion get if isNull region { ret } ai <- collector completedImage md5 <- ai saveImage poi <- new G22PointOfInterest poi imageMD5 <- md5 poi pt <- pt poi bnpSettings <- ai wrangler, bnpSettings poi source <- spaceCombine "Clicked" (byUser) "on" ( ymdWithSlashes) registerConcept (concepts) poi } collector ]], +collector); } }