Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

220
LINES

< > BotCompany Repo | #1034387 // JPaintTool - it's totally like MS Paint

JavaX fragment (include) [tags: use-pretranspiled]

Libraryless. Click here for Pure Java version (20367L/129K).

1  
sclass JPaintTool > MetaWithChangeListeners is Swingable, AutoCloseable {
2  
  settableWithVar File autoPersistFile;
3  
  settableWithVar double autoPersistInterval = 10.0;
4  
  settableWithVar Color brushColor = Color.black;
5  
  settableWithVar bool drawingAllowed = true;
6  
  settable Color bgColor = Color.lightGray; // background color around image surface
7  
  
8  
  event imageChanged(BufferedImage image);
9  
  
10  
  transient settableWithChange volatile bool dirty;
11  
  transient gettable BufferedImage image;
12  
  transient gettable ImageSurface imageSurface;
13  
  transient bool autoPersistInstalled;
14  
  transient ReliableSingleThread rstPersist = new(r _persist);
15  
  transient JPanel buttons;
16  
  
17  
  // tools
18  
  transient new ImageSurfaceScribbleTool scribbler;
19  
  transient new ImageSurfaceDragger dragger;
20  
  transient new ImageSurfaceSelector selector;
21  
  
22  
  transient JComboBox<WidthAndHeight> cbImageSize;
23  
  //transient settableWithVar S status;
24  
  transient new ButtonGroup colorButtonGroup;
25  
  transient new ButtonGroup toolSelectButtonGroup;
26  
  
27  
  transient simplyCached void init() {
28  
    imageSurface = makeImageSurface();
29  
    
30  
    imageSurface.onUserModifiedImage(image -> {
31  
      print("userModifiedImage");
32  
      setImage(image);
33  
      fireImageChanged();
34  
    });
35  
    
36  
    cbImageSize = jTypedComboBox(imageSizes());
37  
    main onChange(cbImageSize, l1 setImageSize);
38  
39  
    printVars("JPaintTool.init", +image, +autoPersistFile);
40  
    if (image == null) {
41  
      setImage(makeNewImage());
42  
      
43  
      if (autoPersistFile != null) {
44  
        pcall {
45  
          var img = loadImage2(autoPersistFile);
46  
          if (img != null) {
47  
            setImage(img);
48  
            print("Image loaded");
49  
          }
50  
        }
51  
                      
52  
        if (!autoPersistInstalled) {
53  
          set autoPersistInstalled;
54  
          awtEvery(imageSurface, autoPersistInterval, rstPersist);
55  
          bindToComponent(imageSurface, null, rstPersist);
56  
        }
57  
      }
58  
    }
59  
    
60  
    varDrawingAllowed().onChangeAndNow(b -> scribbler.enabled(print(scribblerEnabled := b)));
61  
  }
62  
  
63  
  BufferedImage makeNewImage() {
64  
    ret main newImage(defaultImageSize());
65  
  }
66  
  
67  
  WidthAndHeight defaultImageSize() { ret getSelected(cbImageSize); }
68  
  
69  
  cachedVisualize {
70  
    init();
71  
    var filePathLabel = new JFilePathLabel(autoPersistFile).nameOnly();
72  
    varAutoPersistFile().onChange(file -> filePathLabel.setFile(file));
73  
    
74  
    var filePathLabelVis = filePathLabel.visualize();
75  
    componentPopupMenuItem(filePathLabel.button.visualize(),
76  
      "Save image now", r { set dirty; rstPersist!; });
77  
    
78  
    ret withTopMargin(northCenterAndSouthWithMargin(
79  
      // north buttons
80  
      
81  
      buttons = jcenteredline(flattenToList(
82  
        jbutton("New image", rThread newImage),
83  
        withLabel("Size:", cbImageSize),
84  
        map colorSelectButton(colors()),
85  
        swing(-> new JImageSwitch(#1103077, #1103078, varDrawingAllowed())
86  
          .setToolTips(
87  
            "Drawing allowed (click to change)",
88  
            "Drawing not allowed (click to change)")),
89  
      )),
90  
      
91  
      // image surface
92  
      
93  
      centerAndEastWithMargin(
94  
        jscroll_borderless(setBackground(bgColor, jFullCenter(imageSurface))),
95  
        //jscroll_center_borderless(imageSurface),
96  
        vstackWithSpacing(
97  
          makeToolSelectors()
98  
        )
99  
      ),
100  
      
101  
      // south controls
102  
      centerAndEast(
103  
        withLeftMargin(bottomLeftControls()),
104  
        autoPersistFile == null ? jpanel()
105  
          : withSideMargin(withLabel("Image:", filePathLabelVis))
106  
      )
107  
    ));
108  
  }
109  
  
110  
  void setImage(BufferedImage image) {
111  
    this.image = image;
112  
    imageSurface.setImage(image);
113  
    imageChanged(image);
114  
  }
115  
116  
  transient swappable ImageSurface makeImageSurface() {  
117  
    var is = pixelatedImageSurface();
118  
    //is.setAutoZoomToDisplay(true);
119  
    is.specialPurposed = true;
120  
    is.allowPaste(true);
121  
    is.zoomable(false);
122  
    is.removeAllTools();
123  
    //scribbler.onScribbleDone(scribble -> printStruct(scribble));
124  
    scribbler.onPainted(l0 fireImageChanged);
125  
    varBrushColor().onChangeAndNow(color -> scribbler.setColor(color));
126  
    is.setTool(scribbler);
127  
    
128  
    ret is;
129  
  }
130  
  
131  
  void fireImageChanged {
132  
    set dirty;
133  
    imageChanged(getImage());
134  
  }
135  
  
136  
  void _persist {
137  
    if (autoPersistFile != null && dirty) {
138  
      dirty = false;
139  
      savePNGVerbose(autoPersistFile, image);
140  
    }
141  
  }
142  
  
143  
  // doesn't allow drawing immediately
144  
  void loadImageProtected(File file) {
145  
    loadImage(file);
146  
    drawingAllowed(false);
147  
  }
148  
149  
  // Note: also auto-persists to that file
150  
  void loadImage(File file) {  
151  
    close(); // persist
152  
    var img = loadImage2(file);
153  
    autoPersistFile(file);
154  
    setImage(img);
155  
  }
156  
  
157  
  void newImage() ctex {
158  
    close(); // persist
159  
    //if (dirty && !swingConfirm(imageSurface, "Discard image")) ret;
160  
    
161  
    var file = createAutoPersistFile();
162  
    print("Created auto persist file: " + f2s(file));
163  
    autoPersistFile(file);
164  
    setImage(makeNewImage());
165  
    drawingAllowed(true);
166  
    dirty = false;
167  
  }
168  
  
169  
  // swap to make a new file every time user clicks "New image"
170  
  swappable File createAutoPersistFile() { ret autoPersistFile(); }
171  
  
172  
  JToggleButton colorSelectButton(Color color) {
173  
    var btn = jImageToggleButton(main newImage(16, color),
174  
      "Select color to draw with", -> setBrushColor(color),
175  
      eq(brushColor(), color));
176  
    ret addToButtonGroup(colorButtonGroup, btn);
177  
  }
178  
  
179  
  L<Color> colors() {
180  
    ret colorPaletteByBits(1); // 8 primary colors
181  
  }
182  
  
183  
  L<WidthAndHeight> imageSizes() {
184  
    ret mapLL sixteenToNine_p(
185  
      240, 360, 480, 720
186  
    );
187  
  }
188  
  
189  
  void setImageSize(WidthAndHeight size) {
190  
    if (!sameSize(getImage(), size))
191  
      newImage();
192  
  }
193  
  
194  
  close {
195  
    rstPersist.triggerAndWait();
196  
  }
197  
  
198  
  transient swappable JComponent bottomLeftControls() { ret jpanel(); }
199  
  
200  
  void selectTool(ImageSurfaceMouseHandler tool) {
201  
    imageSurface.setTool(tool);
202  
  }
203  
  
204  
  JToggleButton toolSelectButton(ImageSurfaceMouseHandler tool,
205  
    S imageID, S toolTip) {
206  
    ret addToButtonGroup(toolSelectButtonGroup, jImageToggleButton(imageID, toolTip,
207  
      -> selectTool(tool),
208  
      imageSurface.hasTool(tool));
209  
  }
210  
  
211  
  L<JComponent> makeToolSelectors() {
212  
    ret ll(
213  
      instaToolTip(-> "Draw on image with left mouse button"
214  
        + stringIf(!drawingAllowed, " (click lock icon to start)"),
215  
        toolSelectButton(scribbler, #1103080, null)),
216  
      toolSelectButton(dragger, #1103079, "Scroll image with left mouse button"),
217  
      toolSelectButton(selector, #1103081, "Select rectangular area with left mouse button")
218  
    );
219  
  }
220  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, ekrmjmnbrukm, mowyntqkapby, mqqgnosmbjvj

No comments. add comment

Snippet ID: #1034387
Snippet name: JPaintTool - it's totally like MS Paint
Eternal ID of this version: #1034387/93
Text MD5: eac7f071cb23abd7156eef8cefb9b1f7
Transpilation MD5: 3625af800b2dd13d063bee8619419ebc
Author: stefan
Category: javax / gui
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2022-03-20 18:34:40
Source code size: 6769 bytes / 220 lines
Pitched / IR pitched: No / No
Views / Downloads: 346 / 1008
Version history: 92 change(s)
Referenced in: [show references]