Skip to content

Commit 764d2e7

Browse files
committed
#446 New bitmap support, palette editing.
1 parent 1066dac commit 764d2e7

File tree

8 files changed

+169
-28
lines changed

8 files changed

+169
-28
lines changed

tcMenuGenerator/src/main/java/com/thecoderscorner/menu/editorui/gfxui/CreateBitmapWidgetController.java

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,10 @@ public class CreateBitmapWidgetController {
3737
public Button pasteImgButton;
3838
public CheckBox clipboardCheckBox;
3939
public TextField variableField;
40-
public Button addImgButton;
40+
public Button newImgButton;
4141
public Button createWidgetButton;
4242
public Button createBitmapButton;
43+
public Button loadImageButton;
4344
public GridPane imageGridPane;
4445

4546
private CurrentProjectEditorUI editorUI;
@@ -130,7 +131,7 @@ private void putImageIntoAvailableSlot(Image image) {
130131
if (loadedImages.size() >= 8) return;
131132

132133
BitmapImportPopup popup = new BitmapImportPopup(image);
133-
popup.showConfigSetup((Stage) addImgButton.getScene().getWindow(), this::importImage);
134+
popup.showConfigSetup((Stage) newImgButton.getScene().getWindow(), this::importImage);
134135
}
135136
private void importImage(BitmapImportPopup popup) {
136137
var img = createBitmap(popup);
@@ -140,7 +141,10 @@ private void importImage(BitmapImportPopup popup) {
140141
}
141142

142143
private void refreshButtonStates() {
143-
addImgButton.setDisable(loadedImages.size() == 8);
144+
boolean tooManyImages = loadedImages.size() == 8;
145+
newImgButton.setDisable(tooManyImages);
146+
loadImageButton.setDisable(tooManyImages);
147+
pasteImgButton.setDisable(tooManyImages);
144148
var variableEmpty = variableField.getText().isEmpty();
145149
createWidgetButton.setDisable(loadedImages.isEmpty() || variableEmpty);
146150
createBitmapButton.setDisable(loadedImages.isEmpty() || variableEmpty);
@@ -153,8 +157,12 @@ public void onClose(ActionEvent ignoredActionEvent) {
153157
public void onOnlineHelp(ActionEvent ignoredActionEvent) {
154158
SafeNavigator.safeNavigateTo(AppInformationPanel.CREATE_USE_BITMAP_PAGE);
155159
}
160+
public void onNewImage(ActionEvent ignoredActionEvent) {
161+
var popup = new BitmapImportPopup();
162+
popup.showNewBitmap((Stage) newImgButton.getScene().getWindow(), this::importImage);
163+
}
156164

157-
public void onAddImage(ActionEvent ignoredActionEvent) {
165+
public void onLoadImage(ActionEvent ignoredActionEvent) {
158166
var maybeFile = editorUI.findFileNameFromUser(getInitialDir(), true, "*");
159167
if(maybeFile.isPresent()) {
160168
try(var is = new BufferedInputStream(new FileInputStream(maybeFile.get()))) {

tcMenuGenerator/src/main/java/com/thecoderscorner/menu/editorui/gfxui/imgedit/ImageDrawingGrid.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
import javafx.scene.canvas.GraphicsContext;
88
import javafx.scene.paint.Color;
99

10+
import java.util.function.BiConsumer;
11+
1012
public class ImageDrawingGrid extends Canvas {
1113
public enum DrawingMode { NONE, DOT, LINE, OUTLINE_RECT, FILLED_RECT }
1214
private final BmpDataManager bitmap;
1315
private final PortablePalette palette;
1416
private final boolean editMode;
17+
private BiConsumer<Integer, Integer> positionConsumer;
1518
private DrawingMode mode = DrawingMode.NONE;
1619
private DrawingMode currentShape = DrawingMode.LINE;
1720
private int colorIndex = 0;
@@ -42,6 +45,12 @@ public ImageDrawingGrid(BmpDataManager bitmap, PortablePalette palette, boolean
4245
onPaintSurface(getGraphicsContext2D());
4346
});
4447

48+
setOnMouseMoved(event -> {
49+
int xEnd = (int) (event.getX() / fitWidth * bitmap.getPixelWidth());
50+
int yEnd = (int) (event.getY() / fitHeight * bitmap.getPixelHeight());
51+
if(positionConsumer != null) positionConsumer.accept(xEnd, yEnd);
52+
});
53+
4554
setOnMouseReleased(event -> {
4655
int xEnd = (int) (event.getX() / fitWidth * bitmap.getPixelWidth());
4756
int yEnd = (int) (event.getY() / fitHeight * bitmap.getPixelHeight());
@@ -208,4 +217,8 @@ protected void onPaintSurface(GraphicsContext gc) {
208217
public boolean isModified() {
209218
return dirty;
210219
}
220+
221+
public void onPositionUpdate(BiConsumer<Integer, Integer> consumer) {
222+
positionConsumer = consumer;
223+
}
211224
}

tcMenuGenerator/src/main/java/com/thecoderscorner/menu/editorui/gfxui/imgedit/SimpleImageEditor.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.thecoderscorner.menu.editorui.gfxui.imgedit;
22

33
import com.thecoderscorner.menu.domain.util.PortablePalette;
4+
import com.thecoderscorner.menu.editorui.dialog.BaseDialogSupport;
45
import com.thecoderscorner.menu.editorui.gfxui.pixmgr.BmpDataManager;
56
import com.thecoderscorner.menu.editorui.gfxui.pixmgr.NativePixelFormat;
67
import com.thecoderscorner.menu.editorui.gfxui.pixmgr.UIColorPaletteControl;
@@ -42,7 +43,7 @@ public boolean presentUI(CurrentProjectEditorUI editorUI) {
4243

4344
HBox hbox = new HBox(4);
4445
hbox.setAlignment(Pos.CENTER_LEFT);
45-
hbox.getChildren().add(new Label("Toolbar"));
46+
hbox.getChildren().add(new Label("Function"));
4647
pane.setTop(hbox);
4748
ImageDrawingGrid canvas = new ImageDrawingGrid(bitmap, palette, true);
4849
var modeComboBox = new ComboBox<>(FXCollections.observableArrayList(
@@ -51,6 +52,8 @@ public boolean presentUI(CurrentProjectEditorUI editorUI) {
5152
modeComboBox.getSelectionModel().select(0);
5253
modeComboBox.setOnAction(_ -> canvas.setCurrentShape(modeComboBox.getValue()));
5354
hbox.getChildren().add(modeComboBox);
55+
56+
hbox.getChildren().add(new Label("Palette"));
5457
UIColorPaletteControl paletteControl = new UIColorPaletteControl();
5558
hbox.getChildren().add(paletteControl.swatchControl(palette, canvas::setCurrentColor));
5659

@@ -66,7 +69,9 @@ public boolean presentUI(CurrentProjectEditorUI editorUI) {
6669
}
6770
});
6871
hbox.getChildren().add(saveButton);
69-
72+
var xyLabel = new Label("");
73+
canvas.onPositionUpdate((x, y) -> xyLabel.setText(STR."X=\{x}, Y=\{y}"));
74+
hbox.getChildren().add(xyLabel);
7075

7176
canvas.widthProperty().bind(pane.widthProperty());
7277
canvas.heightProperty().bind(pane.heightProperty().multiply(0.9));
@@ -75,11 +80,16 @@ public boolean presentUI(CurrentProjectEditorUI editorUI) {
7580
pane.heightProperty().addListener((_) -> canvas.onPaintSurface(canvas.getGraphicsContext2D()));
7681

7782
pane.setCenter(canvas);
83+
pane.getStyleClass().add("background");
7884

7985
Scene scene = new Scene(pane);
8086
Stage stage = new Stage();
87+
stage.setMaximized(true);
88+
stage.setWidth(800);
89+
stage.setWidth(600);
8190
stage.setScene(scene);
8291
stage.setTitle(STR."Bitmap Editor \{shortFmtText(format)} \{bitmap.getPixelWidth()} x \{bitmap.getPixelHeight()}");
92+
BaseDialogSupport.getJMetro().setScene(scene);
8393
stage.showAndWait();
8494
return canvas.isModified();
8595
}

tcMenuGenerator/src/main/java/com/thecoderscorner/menu/editorui/gfxui/pixmgr/BitmapImportPopup.java

Lines changed: 77 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,22 +5,22 @@
55
import com.thecoderscorner.menu.domain.util.PortablePalette;
66
import javafx.collections.FXCollections;
77
import javafx.scene.control.*;
8-
import javafx.scene.image.Image;
9-
import javafx.scene.image.ImageView;
8+
import javafx.scene.image.*;
109
import javafx.scene.layout.ColumnConstraints;
1110
import javafx.scene.layout.GridPane;
1211
import javafx.scene.layout.Priority;
1312
import javafx.scene.layout.RowConstraints;
1413
import javafx.stage.Popup;
1514
import javafx.stage.Stage;
1615

16+
import java.util.Arrays;
1717
import java.util.function.Consumer;
1818

1919
public class BitmapImportPopup {
2020
public static final PortablePalette EMPTY_PALETTE = new PortablePalette(
2121
new PortableColor[] { PortableColor.BLACK, PortableColor.WHITE}, PortablePalette.PaletteMode.ONE_BPP
2222
);
23-
private final Image loadedImage;
23+
private Image loadedImage;
2424
private PortablePalette palette = EMPTY_PALETTE;
2525
private int tolerance;
2626
private boolean applyAlpha;
@@ -30,6 +30,10 @@ public BitmapImportPopup(Image loadedImage) {
3030
this.loadedImage = loadedImage;
3131
}
3232

33+
public BitmapImportPopup() {
34+
this.loadedImage = null;
35+
}
36+
3337
private RowConstraints priorityRowConstraint(Priority priority) {
3438
var c = new RowConstraints();
3539
c.setVgrow(priority);
@@ -42,6 +46,59 @@ private ColumnConstraints priorityColConstraint(Priority priority) {
4246
return c;
4347
}
4448

49+
public void showNewBitmap(Stage where, Consumer<BitmapImportPopup> importContinuation) {
50+
var popup = new Popup();
51+
var grid = new GridPane();
52+
grid.setVgap(4);
53+
grid.setHgap(4);
54+
grid.getColumnConstraints().add(priorityColConstraint(Priority.NEVER));
55+
grid.getColumnConstraints().add(priorityColConstraint(Priority.SOMETIMES));
56+
for(int i=0; i<10; i++) {
57+
grid.getRowConstraints().add(priorityRowConstraint(Priority.NEVER));
58+
}
59+
60+
int row = 0;
61+
62+
grid.add(new Label("Width Pixels"), 0, row);
63+
Spinner<Integer> widthSpinner = new Spinner<>(1, 256, 32);
64+
grid.add(widthSpinner, 1, row++);
65+
grid.add(new Label("Height Pixels"), 0, row);
66+
Spinner<Integer> heightSpinner = new Spinner<>(1, 256, 32);
67+
grid.add(heightSpinner, 1, row++);
68+
69+
grid.add(new Label("Palette Mode"), 0, row);
70+
var pixelFormatCombo = new ComboBox<NativePixelFormat>();
71+
pixelFormatCombo.setItems(FXCollections.observableArrayList(NativePixelFormat.values()));
72+
pixelFormatCombo.getSelectionModel().select(0);
73+
grid.add(pixelFormatCombo, 1, row++);
74+
75+
Button createButton = createButtonBar("Create", grid, row, popup);
76+
77+
createButton.setOnAction(event -> {
78+
tolerance = 0;
79+
applyAlpha = false;
80+
pixelFormat = pixelFormatCombo.getValue();
81+
palette = new UIColorPaletteControl().createPaletteFor(pixelFormatCombo.getValue());
82+
loadedImage = generateImage(widthSpinner.getValue(), heightSpinner.getValue(), palette.getColorAt(0));
83+
importContinuation.accept(this);
84+
popup.hide();
85+
});
86+
87+
popup.getContent().add(grid);
88+
popup.show(where);
89+
}
90+
91+
private Image generateImage(Integer width, Integer height, PortableColor color) {
92+
WritableImage img = new WritableImage(width, height);
93+
PixelWriter pw = img.getPixelWriter();
94+
95+
int[] pixels = new int[width * height];
96+
Arrays.fill(pixels, color.asArgb());
97+
98+
pw.setPixels(0, 0, width, height, PixelFormat.getIntArgbInstance(), pixels, 0, width);
99+
return img ;
100+
}
101+
45102
public void showConfigSetup(Stage where, Consumer<BitmapImportPopup> importContinuation) {
46103
var popup = new Popup();
47104
var grid = new GridPane();
@@ -56,8 +113,9 @@ public void showConfigSetup(Stage where, Consumer<BitmapImportPopup> importConti
56113
int row = 0;
57114
UIColorPaletteControl paletteControl = new UIColorPaletteControl();
58115
grid.add(new Label("Settings for Image Import"), 0, row++);
59-
grid.add(new ImageView(loadedImage), 0, row, 1, 8);
60-
116+
if(loadedImage != null) {
117+
grid.add(new ImageView(loadedImage), 0, row, 1, 8);
118+
}
61119
grid.add(new Label("Output Format"), 1, row++);
62120
var pixelFormatCombo = new ComboBox<NativePixelFormat>();
63121
pixelFormatCombo.setItems(FXCollections.observableArrayList(NativePixelFormat.values()));
@@ -89,15 +147,7 @@ public void showConfigSetup(Stage where, Consumer<BitmapImportPopup> importConti
89147
paletteControl.initializePaletteEntries(palette, 350);
90148
grid.add(paletteControl.getControl(), 1, row++);
91149

92-
ButtonBar buttonBar = new ButtonBar();
93-
Button importButton = new Button("Import");
94-
importButton.setDefaultButton(true);
95-
buttonBar.getButtons().add(importButton);
96-
Button cancelButton = new Button("Cancel");
97-
cancelButton.setCancelButton(true);
98-
buttonBar.getButtons().add(cancelButton);
99-
grid.add(buttonBar, 0, row, 2, 1);
100-
grid.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());
150+
Button importButton = createButtonBar("Import", grid, row, popup);
101151

102152
popup.getContent().add(grid);
103153
popup.show(where);
@@ -110,7 +160,20 @@ public void showConfigSetup(Stage where, Consumer<BitmapImportPopup> importConti
110160
popup.hide();
111161
});
112162

163+
}
164+
165+
private static Button createButtonBar(String actionTxt, GridPane grid, int row, Popup popup) {
166+
ButtonBar buttonBar = new ButtonBar();
167+
Button importButton = new Button(actionTxt);
168+
importButton.setDefaultButton(true);
169+
buttonBar.getButtons().add(importButton);
170+
Button cancelButton = new Button("Cancel");
171+
cancelButton.setCancelButton(true);
172+
buttonBar.getButtons().add(cancelButton);
173+
grid.add(buttonBar, 0, row, 2, 1);
174+
grid.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());
113175
cancelButton.setOnAction(event -> popup.hide());
176+
return importButton;
114177
}
115178

116179
public Image getImage() {

tcMenuGenerator/src/main/java/com/thecoderscorner/menu/editorui/gfxui/pixmgr/UIColorPaletteControl.java

Lines changed: 47 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,22 @@
11
package com.thecoderscorner.menu.editorui.gfxui.pixmgr;
22

33
import com.thecoderscorner.embedcontrol.core.controlmgr.color.ControlColor;
4+
import com.thecoderscorner.embedcontrol.core.service.GlobalSettings;
45
import com.thecoderscorner.menu.domain.state.PortableColor;
56
import com.thecoderscorner.menu.domain.util.PortablePalette;
7+
import javafx.geometry.Insets;
68
import javafx.scene.Node;
9+
import javafx.scene.control.Button;
710
import javafx.scene.control.ColorPicker;
811
import javafx.scene.control.Label;
912
import javafx.scene.control.ScrollPane;
1013
import javafx.scene.image.Image;
14+
import javafx.scene.layout.Background;
1115
import javafx.scene.layout.HBox;
1216
import javafx.scene.layout.VBox;
1317
import javafx.scene.paint.Color;
1418
import javafx.scene.shape.Rectangle;
19+
import javafx.stage.Popup;
1520

1621
import java.util.ArrayList;
1722
import java.util.Arrays;
@@ -34,6 +39,7 @@ public Node getControl() {
3439

3540
public void initializePaletteEntries(PortablePalette palette, int maxSize) {
3641
paletteEntries = new VBox();
42+
pickers.clear();
3743
scrollArea.setContent(paletteEntries);
3844
scrollArea.setMaxHeight(maxSize);
3945
scrollArea.setVbarPolicy(ScrollPane.ScrollBarPolicy.ALWAYS);
@@ -60,11 +66,7 @@ public void initializePaletteEntries(PortablePalette palette, int maxSize) {
6066
public Node swatchControl(PortablePalette pal, Consumer<Integer> colorConsumer) {
6167
HBox hBox = new HBox(2);
6268
var listOfSwatches = new ArrayList<Rectangle>();
63-
for(var col : pal.getColorArray()) {
64-
var r = new Rectangle(20, 20, ControlColor.asFxColor(col));
65-
listOfSwatches.add(r);
66-
hBox.getChildren().add(r);
67-
}
69+
populateColorsIntoBox(pal, listOfSwatches, hBox);
6870
hBox.setOnMouseClicked(event -> {
6971
var swatch = event.getTarget();
7072
if(swatch instanceof Rectangle newSel) {
@@ -76,13 +78,52 @@ public Node swatchControl(PortablePalette pal, Consumer<Integer> colorConsumer)
7678
}
7779
var swatchIndex = hBox.getChildren().indexOf(event.getTarget());
7880
if(swatchIndex != -1 && swatchIndex < pal.getNumColors()) {
79-
colorConsumer.accept(swatchIndex);
81+
if(event.getClickCount() > 1) {
82+
showPopup(pal, hBox, () -> populateColorsIntoBox(pal, listOfSwatches, hBox));
83+
} else {
84+
colorConsumer.accept(swatchIndex);
85+
}
8086
}
8187
});
8288
return hBox;
8389
}
8490

91+
private static void populateColorsIntoBox(PortablePalette pal, ArrayList<Rectangle> listOfSwatches, HBox hBox) {
92+
hBox.getChildren().clear();
93+
listOfSwatches.clear();
94+
for(var col : pal.getColorArray()) {
95+
var r = new Rectangle(20, 20, ControlColor.asFxColor(col));
96+
listOfSwatches.add(r);
97+
hBox.getChildren().add(r);
98+
}
99+
}
100+
101+
private void showPopup(PortablePalette pal, HBox hBox, Runnable onClose) {
102+
var popup = new Popup();
103+
initializePaletteEntries(pal, 999);
104+
105+
var close = new Button("Apply");
106+
close.setOnAction(_ -> {
107+
popup.hide();
108+
onClose.run();
109+
});
110+
var vbox = new VBox(4);
111+
vbox.getChildren().add(paletteEntries);
112+
vbox.getChildren().add(close);
113+
vbox.setOpacity(1);
114+
vbox.setBackground(Background.fill(Color.BLACK));
115+
vbox.setOpaqueInsets(new Insets(10));
116+
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());
117+
118+
popup.getContent().add(vbox);
119+
popup.show(hBox.getScene().getWindow());
120+
}
121+
85122
public PortablePalette paletteFromImage(Image img, NativePixelFormat fmt, double tolerance) {
123+
// when null return the default
124+
if(img == null) return createPaletteFor(fmt);
125+
126+
// otherwise get the palette based on the colors in the image and the tolerance.
86127
var width = (int) img.getWidth();
87128
var height = (int) img.getHeight();
88129
var pixelReader = img.getPixelReader();

tcMenuGenerator/src/main/resources/i18n/TcMenuUIText.properties

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,8 @@ eeprom.type.bsp.stm=Use battery backed RAM on an STM32 board with BSP driver
423423
eeprom.type.mem.offs=Memory offset
424424
eeprom.type.page.size=Page Size
425425
bitmap.create.title=Native bitmap and title widget creation tool
426-
bitmap.add.image=Add Image
426+
bitmap.add.image=New Image
427+
bitmap.load.image=Load Image
427428
bitmap.remove.image=Remove Image
428429
bitmap.create.widget=Create Widget
429430
bitmap.create.bitmap=Create Bitmaps

0 commit comments

Comments
 (0)