Skip to content

Commit 4e70c01

Browse files
committed
#586 clean up bitmap editor dialogs and functionality
1 parent baed086 commit 4e70c01

6 files changed

Lines changed: 162 additions & 69 deletions

File tree

.idea/compiler.xml

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

font-bmp-editor/src/main/java/com/thecoderscorner/bmped/gfxui/CreateFontUtilityController.java

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -232,32 +232,49 @@ public void onOnlineHelp(ActionEvent ignored) {
232232

233233
private boolean shouldOverwrite() {
234234
if(!dirty) return true;
235-
if(editorUI.questionYesNo("%font.create.changed.title", "%font.create.changed.content")) {
235+
if(editorUI.questionYesNo("Font has changed", "The font has changed, proceeding will lose the changes?")) {
236236
dirty = false;
237237
return true;
238238
} else return false;
239239
}
240240

241241
private void previewNativeFont(UnicodeBlockMapping mapping, List<FontGlyphDataControl> glyphs) {
242-
int totalWidth = Math.max(1, glyphs.stream().filter(FontGlyphDataControl::isSelected)
243-
.map(d -> d.getData().getPixelWidth()).reduce(0, Integer::sum));
244-
int maxHeight = glyphs.stream().map(d -> d.getData().getPixelHeight()).max(Integer::compareTo).orElse(1);
245-
NativeBmpBitPacker packer = new NativeBmpBitPacker(320, maxHeight * ((totalWidth / 320) + 1), false);
242+
int totalWidth = 0;
243+
int maxHeight = 1;
244+
int yAdvance = embeddedFont.getYAdvance();
245+
int currentX = 0;
246+
int numLines = 1;
247+
248+
for (var g : glyphs) {
249+
if (!g.isSelected()) continue;
250+
var glyph = g.glyph;
251+
int gWidth = glyph.calculatedWidth();
252+
if (currentX + gWidth > 640) {
253+
currentX = 0;
254+
numLines++;
255+
}
256+
currentX += gWidth;
257+
maxHeight = Math.max(maxHeight, glyph.data().getPixelHeight());
258+
}
259+
260+
int packerHeight = (numLines + 1) * yAdvance;
261+
NativeBmpBitPacker packer = new NativeBmpBitPacker(320, packerHeight, false);
246262
SimpleImagePane e = new SimpleImagePane(packer, NativePixelFormat.MONO_BITMAP, false, BitmapImportPopup.EMPTY_PALETTE, List.of());
247-
e.getDrawingGrid().setTextCursor(0,0);
263+
e.getDrawingGrid().setTextCursor(0, 0);
248264
e.getDrawingGrid().setFont(embeddedFont);
249265
e.getDrawingGrid().setCurrentColor(1);
250-
for(var g : glyphs) {
251-
if(!g.isSelected()) continue;
266+
for (var g : glyphs) {
267+
if (!g.isSelected()) continue;
252268
e.getDrawingGrid().printChar(g.glyph.code());
253269
}
254270

255271
var popup = new Popup();
256272
var vbox = new VBox(4);
257-
vbox.setStyle("-fx-background-color: #1f1a1a;-fx-border-style: solid;-fx-border-color: black;-fx-border-width: 2;-fx-background-insets: 6;-fx-padding: 10;-fx-font-size: " + GlobalSettings.defaultFontSize());
273+
vbox.getStyleClass().add("popup-content");
274+
vbox.setStyle("-fx-background-color: -fx-control-inner-background; -fx-border-style: solid; -fx-border-color: -fx-box-border; -fx-border-width: 1; -fx-padding: 10; -fx-font-size: " + GlobalSettings.defaultFontSize());
258275

259276
e.setPrefWidth(640);
260-
e.setPrefHeight(maxHeight * 2);
277+
e.setPrefHeight(packerHeight + 40); // extra space for the label at the top of SimpleImagePane
261278

262279
var title = new Label("Glyphs in %s range %d-%d".formatted(mapping.name(), mapping.getStartingCode(), mapping.getEndingCode()));
263280
var closeBtn = new Button("Close");
@@ -328,7 +345,8 @@ private void imgViewMouseClick(MouseEvent mouseEvent) {
328345

329346
var box = new VBox(4);
330347
box.setFillWidth(true);
331-
box.setStyle("-fx-font-size: " + GlobalSettings.defaultFontSize());
348+
box.getStyleClass().add("popup-content");
349+
box.setStyle("-fx-background-color: -fx-control-inner-background; -fx-border-style: solid; -fx-border-color: -fx-box-border; -fx-border-width: 1; -fx-padding: 6; -fx-font-size: " + GlobalSettings.defaultFontSize());
332350
var editButton = new Button("Edit Glyph U" + glyph.code());
333351
editButton.setMaxWidth(99999);
334352
editButton.setOnAction(_ -> {
@@ -352,12 +370,9 @@ private void imgViewMouseClick(MouseEvent mouseEvent) {
352370
var closeButton = new Button("Close");
353371
closeButton.setMaxWidth(99999);
354372
closeButton.setOnAction(_ -> popup.hide());
355-
box.setStyle("-fx-background-color: #1f1a1a;-fx-border-style: solid;-fx-border-color: black;-fx-border-width: 2;-fx-background-insets: 6;-fx-padding: 10;-fx-font-size: " + GlobalSettings.defaultFontSize());
356373
box.getChildren().addAll(selectButton, editButton, closeButton);
357374
popup.getContent().add(box);
358-
popup.show(pane.getScene().getWindow());
359-
popup.setX(mouseEvent.getScreenX());
360-
popup.setY(mouseEvent.getScreenY());
375+
popup.show(pane.getScene().getWindow(), mouseEvent.getScreenX(), mouseEvent.getScreenY());
361376
}
362377
}
363378
}

font-bmp-editor/src/main/java/com/thecoderscorner/bmped/gfxui/imgedit/ImageDrawingGrid.java

Lines changed: 69 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
*/
1818
public class ImageDrawingGrid extends Canvas {
1919
public enum DrawingMode { NONE, DOT, LINE, OUTLINE_RECT, FILLED_RECT, OUTLINE_CIRCLE, FLOOD_FILL, SELECTION }
20-
private final BmpDataManager bitmap;
21-
private final PortablePalette palette;
20+
private BmpDataManager bitmap;
21+
private PortablePalette palette;
2222
private final boolean editMode;
2323
private BiConsumer<Integer, Integer> positionConsumer;
2424
private DrawingMode mode = DrawingMode.NONE;
@@ -45,16 +45,23 @@ public ImageDrawingGrid(BmpDataManager bitmap, PortablePalette palette, boolean
4545
xStart = (int) (event.getX() / fitWidth * bitmap.getPixelWidth());
4646
yStart = (int) (event.getY() / fitHeight * bitmap.getPixelHeight());
4747
mode = currentShape == DrawingMode.FLOOD_FILL ? DrawingMode.FLOOD_FILL : DrawingMode.DOT;
48+
if(currentShape == DrawingMode.DOT) {
49+
recordChange();
50+
bitmap.setDataAt(xStart, yStart, colorIndex);
51+
onPaintSurface(getGraphicsContext2D());
52+
}
4853
});
4954

5055
setOnMouseDragged(event -> {
5156
mode = currentShape;
5257

5358
xNow = (int) (event.getX() / fitWidth * bitmap.getPixelWidth());
5459
yNow = (int) (event.getY() / fitHeight * bitmap.getPixelHeight());
55-
if (xNow > bitmap.getPixelWidth() || yNow > bitmap.getPixelHeight()) return;
60+
if (xNow >= bitmap.getPixelWidth() || yNow >= bitmap.getPixelHeight() || xNow < 0 || yNow < 0) return;
5661
if(mode == DrawingMode.SELECTION) {
5762
imageSelection = new OrderedRect(xStart, yStart, xNow, yNow);
63+
} else if(mode == DrawingMode.DOT) {
64+
bitmap.setDataAt(xNow, yNow, colorIndex);
5865
}
5966

6067
onPaintSurface(getGraphicsContext2D());
@@ -71,11 +78,9 @@ public ImageDrawingGrid(BmpDataManager bitmap, PortablePalette palette, boolean
7178
setOnMouseReleased(event -> {
7279
int xEnd = (int) (event.getX() / fitWidth * bitmap.getPixelWidth());
7380
int yEnd = (int) (event.getY() / fitHeight * bitmap.getPixelHeight());
74-
if (xEnd >= bitmap.getPixelWidth() || yEnd >= bitmap.getPixelHeight()) return;
81+
if (xEnd >= bitmap.getPixelWidth() || yEnd >= bitmap.getPixelHeight() || xEnd < 0 || yEnd < 0) return;
7582
if(mode == DrawingMode.DOT) {
76-
recordChange();
7783
bitmap.setDataAt(xEnd, yEnd, colorIndex);
78-
onPaintSurface(getGraphicsContext2D());
7984
} else if(mode == DrawingMode.FILLED_RECT) {
8085
recordChange();
8186
filledRectangle(bitmap, xStart, yStart, xEnd, yEnd);
@@ -111,24 +116,28 @@ public void floodFill(int x, int y, int startingCol) {
111116
floodFill(x + 1, y, startingCol);
112117
}
113118

119+
public void drawBoxOutline(BmpDataManager bitmapToDraw, int xStart, int yStart, int xEnd, int yEnd) {
120+
drawLine(bitmapToDraw, xStart, yStart, xEnd, yStart);
121+
drawLine(bitmapToDraw, xEnd, yStart, xEnd, yEnd);
122+
drawLine(bitmapToDraw, xStart, yEnd, xEnd, yEnd);
123+
drawLine(bitmapToDraw, xStart, yStart, xStart, yEnd);
124+
}
125+
114126
public void drawBoxOutline(int xEnd, int yEnd) {
115-
drawLine(xStart, yStart, xEnd, yStart);
116-
drawLine(xEnd, yStart, xEnd, yEnd);
117-
drawLine(xStart, yEnd, xEnd, yEnd);
118-
drawLine(xStart, yStart, xStart, yEnd);
127+
drawBoxOutline(bitmap, xStart, yStart, xEnd, yEnd);
119128
}
120129

121-
public void drawCircle(int x0, int y0, int r) {
130+
public void drawCircle(BmpDataManager bitmapToDraw, int x0, int y0, int r) {
122131
int f = 1 - r;
123132
int ddF_x = 1;
124133
int ddF_y = -2 * r;
125134
int x = 0;
126135
int y = r;
127136

128-
bitmap.setDataAt(x0, y0 + r, colorIndex);
129-
bitmap.setDataAt(x0, y0 - r, colorIndex);
130-
bitmap.setDataAt(x0 + r, y0, colorIndex);
131-
bitmap.setDataAt(x0 - r, y0, colorIndex);
137+
bitmapToDraw.setDataAt(x0, y0 + r, colorIndex);
138+
bitmapToDraw.setDataAt(x0, y0 - r, colorIndex);
139+
bitmapToDraw.setDataAt(x0 + r, y0, colorIndex);
140+
bitmapToDraw.setDataAt(x0 - r, y0, colorIndex);
132141

133142
while (x < y) {
134143
if (f >= 0) {
@@ -140,17 +149,21 @@ public void drawCircle(int x0, int y0, int r) {
140149
ddF_x += 2;
141150
f += ddF_x;
142151

143-
bitmap.setDataAt(x0 + x, y0 + y, colorIndex);
144-
bitmap.setDataAt(x0 - x, y0 + y, colorIndex);
145-
bitmap.setDataAt(x0 + x, y0 - y, colorIndex);
146-
bitmap.setDataAt(x0 - x, y0 - y, colorIndex);
147-
bitmap.setDataAt(x0 + y, y0 + x, colorIndex);
148-
bitmap.setDataAt(x0 - y, y0 + x, colorIndex);
149-
bitmap.setDataAt(x0 + y, y0 - x, colorIndex);
150-
bitmap.setDataAt(x0 - y, y0 - x, colorIndex);
152+
bitmapToDraw.setDataAt(x0 + x, y0 + y, colorIndex);
153+
bitmapToDraw.setDataAt(x0 - x, y0 + y, colorIndex);
154+
bitmapToDraw.setDataAt(x0 + x, y0 - y, colorIndex);
155+
bitmapToDraw.setDataAt(x0 - x, y0 - y, colorIndex);
156+
bitmapToDraw.setDataAt(x0 + y, y0 + x, colorIndex);
157+
bitmapToDraw.setDataAt(x0 - y, y0 + x, colorIndex);
158+
bitmapToDraw.setDataAt(x0 + y, y0 - x, colorIndex);
159+
bitmapToDraw.setDataAt(x0 - y, y0 - x, colorIndex);
151160
}
152161
}
153162

163+
public void drawCircle(int x0, int y0, int r) {
164+
drawCircle(bitmap, x0, y0, r);
165+
}
166+
154167
private void recordChange() {
155168
dirty = true;
156169
changed = true;
@@ -181,7 +194,7 @@ public void filledRectangle(BmpDataManager bitmap, int xStart, int yStart, int x
181194
}
182195
}
183196

184-
public void drawLine(int x0, int y0, int x1, int y1) {
197+
public void drawLine(BmpDataManager bitmapToDraw, int x0, int y0, int x1, int y1) {
185198
// roughly copied from Adafruit_GFX, Thanks!
186199
boolean steep = Math.abs(y1 - y0) > Math.abs(x1 - x0);
187200
if (steep) {
@@ -219,9 +232,9 @@ public void drawLine(int x0, int y0, int x1, int y1) {
219232

220233
for (; x0 <= x1; x0++) {
221234
if (steep) {
222-
bitmap.setDataAt(y0, x0, colorIndex);
235+
bitmapToDraw.setDataAt(y0, x0, colorIndex);
223236
} else {
224-
bitmap.setDataAt(x0, y0, colorIndex);
237+
bitmapToDraw.setDataAt(x0, y0, colorIndex);
225238
}
226239
err -= dy;
227240
if (err < 0) {
@@ -231,6 +244,10 @@ public void drawLine(int x0, int y0, int x1, int y1) {
231244
}
232245
}
233246

247+
public void drawLine(int x0, int y0, int x1, int y1) {
248+
drawLine(bitmap, x0, y0, x1, y1);
249+
}
250+
234251
public void setCurrentColor(int paletteIdx) {
235252
colorIndex = paletteIdx;
236253
}
@@ -267,16 +284,26 @@ public void onPaintSurface(GraphicsContext gc) {
267284

268285
if(!editMode) return;
269286

270-
gc.setStroke(Color.BLUE);
271-
gc.setLineWidth(3);
272-
gc.setLineDashes(10, 3);
273-
274-
double wid = ((xNow - xStart) + 1) * perSquareX;
275-
double hei = ((yNow - yStart) + 1) * perSquareY;
276-
if(mode == DrawingMode.FILLED_RECT || mode == DrawingMode.OUTLINE_RECT || mode == DrawingMode.OUTLINE_CIRCLE) {
277-
gc.strokeRect(xStart * perSquareX, yStart * perSquareY, wid, hei);
278-
} else if(mode == DrawingMode.LINE) {
279-
gc.strokeLine(xStart * perSquareX, yStart * perSquareY, xNow * perSquareX, yNow * perSquareY);
287+
if(mode == DrawingMode.FILLED_RECT || mode == DrawingMode.OUTLINE_RECT || mode == DrawingMode.OUTLINE_CIRCLE || mode == DrawingMode.LINE) {
288+
gc.setFill(ControlColor.asFxColor(palette.getColorAt(colorIndex)));
289+
var tempBmp = bitmap.createNew(bitmap.getPixelWidth(), bitmap.getPixelHeight());
290+
if(mode == DrawingMode.LINE) {
291+
drawLine(tempBmp, xStart, yStart, xNow, yNow);
292+
} else if(mode == DrawingMode.FILLED_RECT) {
293+
filledRectangle(tempBmp, xStart, yStart, xNow, yNow);
294+
} else if(mode == DrawingMode.OUTLINE_RECT) {
295+
drawBoxOutline(tempBmp, xStart, yStart, xNow, yNow);
296+
} else if(mode == DrawingMode.OUTLINE_CIRCLE) {
297+
int halfX = (xNow - xStart) / 2;
298+
drawCircle(tempBmp, xStart + halfX, yStart + halfX, halfX);
299+
}
300+
for (int y = 0; y < tempBmp.getPixelHeight(); y++) {
301+
for (int x = 0; x < tempBmp.getPixelWidth(); x++) {
302+
if(tempBmp.getDataAt(x, y) != 0) {
303+
gc.fillRect(x * perSquareX, y * perSquareY, perSquareX + 0.6, perSquareY + 0.6);
304+
}
305+
}
306+
}
280307
} else if(currentShape == DrawingMode.SELECTION && imageSelection != null) {
281308
gc.setStroke(Color.GREENYELLOW);
282309
gc.setLineWidth(4);
@@ -353,12 +380,17 @@ public void setFont(EmbeddedFont font) {
353380
this.embeddedFont = font;
354381
}
355382

383+
public void setBitmap(BmpDataManager bitmap, PortablePalette palette) {
384+
this.bitmap = bitmap;
385+
this.palette = palette;
386+
}
387+
356388
public void printChar(int code) {
357389
if(embeddedFont == null) return;
358390
var g = embeddedFont.getGlyph(code);
359391
if(g == null) return;
360392

361-
if(cursorX + g.calculatedWidth() > 320) {
393+
if(cursorX + g.calculatedWidth() > bitmap.getPixelWidth()) {
362394
cursorX = 0;
363395
cursorY += embeddedFont.getYAdvance();
364396
}

font-bmp-editor/src/main/java/com/thecoderscorner/bmped/gfxui/imgedit/SimpleImageEditor.java

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public boolean presentUI(BmpEditorUI editorUI) {
8989
var closeButton = new Button("Close");
9090
closeButton.setOnAction(_ -> {
9191
if(editingMode == EditingMode.BITMAP_EDITOR && canvas.isDirty()) {
92-
if(editorUI.questionYesNo("Image not saved?", "The image has been changed, do you want to save?")) {
92+
if(shouldBackupImage(editorUI)) {
9393
saveContents();
9494
}
9595
}
@@ -147,7 +147,7 @@ else if(ke.getCode().getCode() >= KeyCode.DIGIT0.getCode() && ke.getCode().getCo
147147
stage.setTitle("Bitmap Editor %s %d x %d".formatted(shortFmtText(format), bitmap.getPixelWidth(), bitmap.getPixelHeight()));
148148
stage.setOnCloseRequest(_ -> {
149149
if(editingMode == EditingMode.BITMAP_EDITOR && canvas.isDirty()) {
150-
if(editorUI.questionYesNo("Save Image?", "The image is dirty do you want to save?")) {
150+
if(shouldBackupImage(editorUI)) {
151151
saveContents();
152152
}
153153
}
@@ -156,6 +156,13 @@ else if(ke.getCode().getCode() >= KeyCode.DIGIT0.getCode() && ke.getCode().getCo
156156
return canvas.isChanged();
157157
}
158158

159+
private static boolean shouldBackupImage(BmpEditorUI editorUI) {
160+
return editorUI.questionYesNo(
161+
"Keep backup of edited image?",
162+
"Embedded images are saved as headers and can't be reloaded, " +
163+
"would you like to save a PNG copy?");
164+
}
165+
159166
private void changeShape(ImageDrawingGrid.DrawingMode drawingMode) {
160167
for(int i=0;i<modeComboBox.getItems().size(); i++) {
161168
if (modeComboBox.getItems().get(i).mode() == drawingMode) {

0 commit comments

Comments
 (0)