sclass JPaintTool is Swingable { transient gettable BufferedImage image; transient ImageSurface imageSurface; transient settable Dimension defaultImageSize = sixteenToNine_p(480); settable File autoPersistFile; bool autoPersistInstalled; volatile bool dirty; double autoPersistInterval = 10.0; ReliableSingleThread rstPersist = new(r _persist); transient JPanel buttons; transient ImageSurfaceScribbleTool scribbler; //transient JColorChooser colorChooser; void init { imageSurface if null = makeImageSurface(); if (image == null) { setImage(makeNewImage()); if (autoPersistFile != null) { pcall { var img = loadImage2(autoPersistFile); if (img != null) setImage(img); else set dirty; } if (!autoPersistInstalled) { set autoPersistInstalled; awtEvery(imageSurface, autoPersistInterval, rstPersist); bindToComponent(imageSurface, null, rstPersist); } } } } BufferedImage makeNewImage() { ret main newImage(defaultImageSize); } visualize { init(); ret northAndCenterWithMargin(buttons = jcenteredline(flattenToList( jbutton("New image", rThread newImage), /*colorChooser = onChange( -> scribbler.setColor(colorChooser.getColor()), jColorChooser(scribbler.getColor())),* map colorSelectButton(colors()) )), jscroll_center_borderless(imageSurface)); } void setImage(BufferedImage image) { this.image = image; imageSurface.setImage(image); } swappable ImageSurface makeImageSurface() { var is = pixelatedImageSurface(); //is.setAutoZoomToDisplay(true); //is.specialPurposed = true; is.zoomable(false); is.removeAllTools(); scribbler = new ImageSurfaceScribbleTool(is); scribbler.onPainted(-> { set dirty; }); ret is; } void _persist { if (autoPersistFile != null && dirty) { dirty = false; savePNGVerbose(autoPersistFile, image); } } void newImage { setImage(makeNewImage()); set dirty; } JButton colorSelectButton(Color color) { ret toolTip("Select color to draw with", jImageButton(newImage(16, color), -> scribbler.setColor(color))); } L colors() { ret colorPaletteByBits(1); // 8 primary colors } } }