-
-
Notifications
You must be signed in to change notification settings - Fork 25
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
#256 interim work on font creator tool
- Loading branch information
Showing
20 changed files
with
1,300 additions
and
11 deletions.
There are no files selected for viewing
193 changes: 193 additions & 0 deletions
193
...c/main/java/com/thecoderscorner/menu/editorui/controller/CreateFontUtilityController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,193 @@ | ||
package com.thecoderscorner.menu.editorui.controller; | ||
|
||
import com.thecoderscorner.menu.editorui.dialog.SelectUnicodeRangesDialog; | ||
import com.thecoderscorner.menu.editorui.generator.core.VariableNameGenerator; | ||
import com.thecoderscorner.menu.editorui.generator.font.AwtLoadedFont; | ||
import com.thecoderscorner.menu.editorui.generator.font.LoadedFont; | ||
import com.thecoderscorner.menu.editorui.generator.font.NoLoadedFont; | ||
import com.thecoderscorner.menu.editorui.generator.font.UnicodeBlockMapping; | ||
import com.thecoderscorner.menu.editorui.uimodel.CurrentProjectEditorUI; | ||
import javafx.collections.FXCollections; | ||
import javafx.event.ActionEvent; | ||
import javafx.geometry.Insets; | ||
import javafx.scene.control.Button; | ||
import javafx.scene.control.Label; | ||
import javafx.scene.control.Menu; | ||
import javafx.scene.control.MenuItem; | ||
import javafx.scene.control.TextField; | ||
import javafx.scene.control.*; | ||
import javafx.scene.image.Image; | ||
import javafx.scene.image.ImageView; | ||
import javafx.scene.image.WritableImage; | ||
import javafx.scene.layout.GridPane; | ||
import javafx.scene.paint.Color; | ||
import javafx.stage.Stage; | ||
|
||
import javax.swing.*; | ||
import java.awt.*; | ||
import java.nio.file.Path; | ||
import java.util.*; | ||
import java.util.List; | ||
|
||
import static com.thecoderscorner.menu.editorui.generator.font.AwtLoadedFont.*; | ||
|
||
public class CreateFontUtilityController { | ||
public TextField fontFileField; | ||
public Button onHelp; | ||
public Button onToggleSelected; | ||
public Button onGenerateAdafruit; | ||
public Button onGenerateTcUnicode; | ||
public Label approxSizeField; | ||
public Spinner<Integer> pixelSizeSpinner; | ||
public ComboBox<FontStyle> fontStyleCombo; | ||
public TextField outputStructNameField; | ||
public GridPane fontRenderArea; | ||
public Menu loadedFontsMenu; | ||
private CurrentProjectEditorUI editorUI; | ||
private String homeDirectory; | ||
private Path currentDir; | ||
private LoadedFont loadedFont = NO_LOADED_FONT; | ||
private Set<UnicodeBlockMapping> blockMappings = Set.of(); | ||
private Map<UnicodeBlockMapping,List<ToggleButton>> controlsByBlock = new HashMap<>(); | ||
private Map<Integer, Boolean> currentlySelected = new HashMap<>(); | ||
|
||
public void initialise(CurrentProjectEditorUI editorUI, String homeDirectory) { | ||
this.editorUI = editorUI; | ||
this.homeDirectory = homeDirectory; | ||
var fileName = editorUI.getCurrentProject().getFileName(); | ||
currentDir = (fileName.equals("New")) ? Path.of(homeDirectory) : Path.of(fileName).getParent(); | ||
blockMappings = Set.of(UnicodeBlockMapping.BASIC_LATIN, UnicodeBlockMapping.LATIN1_SUPPLEMENT); | ||
|
||
pixelSizeSpinner.setValueFactory(new SpinnerValueFactory.IntegerSpinnerValueFactory(1, 255, 12)); | ||
pixelSizeSpinner.getValueFactory().valueProperty().addListener((observable, oldValue, newValue) -> { | ||
changeNameField(); | ||
recalcFont(); | ||
}); | ||
|
||
this.fontStyleCombo.setItems(FXCollections.observableArrayList(FontStyle.values())); | ||
this.fontStyleCombo.getSelectionModel().select(0); | ||
|
||
SwingUtilities.invokeLater(() -> { | ||
var ge = GraphicsEnvironment.getLocalGraphicsEnvironment(); | ||
for(var f : ge.getAllFonts()) { | ||
MenuItem item = new MenuItem(f.getName() + " " + f.getFamily()); | ||
item.setOnAction(event -> { | ||
fontFileField.setText("OS " + f.getName() + " " + f.getFamily()); | ||
loadedFont = new AwtLoadedFont(f, fontStyleCombo.getValue(), pixelSizeSpinner.getValue(), blockMappings); | ||
}); | ||
loadedFontsMenu.getItems().add(item); | ||
} | ||
}); | ||
} | ||
|
||
public void onChooseFont(ActionEvent actionEvent) { | ||
var fileChoice = editorUI.findFileNameFromUser(Optional.of(currentDir), true, "Fonts|*.ttf"); | ||
fileChoice.ifPresent(file -> { | ||
fontFileField.setText(file); | ||
changeNameField(); | ||
loadedFont = new AwtLoadedFont(file, fontStyleCombo.getValue(), pixelSizeSpinner.getValue(), blockMappings); | ||
recalcFont(); | ||
}); | ||
} | ||
|
||
private void recalcFont() { | ||
fontRenderArea.getChildren().clear(); | ||
controlsByBlock.clear(); | ||
loadedFont.deriveFont(fontStyleCombo.getValue(), pixelSizeSpinner.getValue()); | ||
int gridRow = 0; | ||
for(var blockRange : UnicodeBlockMapping.values()) { | ||
if(!blockMappings.contains(blockRange)) continue; | ||
|
||
fontRenderArea.add(new Label(blockRange.toString()), 0, gridRow, 5, 1); | ||
CheckBox selAllCheck = new CheckBox("Select/Clear All"); | ||
selAllCheck.setOnAction(event -> { | ||
var allItems = controlsByBlock.get(blockRange); | ||
if(allItems != null && !allItems.isEmpty()) { | ||
for(var item : allItems) { | ||
item.setSelected(selAllCheck.isSelected()); | ||
} | ||
for(int i=blockRange.getStartingCode(); i<=blockRange.getEndingCode();i++) { | ||
currentlySelected.put(i, selAllCheck.isSelected()); | ||
} | ||
} | ||
}); | ||
fontRenderArea.add(selAllCheck, 6, gridRow, 3, 1); | ||
|
||
gridRow++; | ||
|
||
var allButtons = new ArrayList<ToggleButton>(); | ||
int gridCol = 0; | ||
for(int i=blockRange.getStartingCode(); i<blockRange.getEndingCode();i++) { | ||
var maybeGlyph = loadedFont.getConvertedGlyph(i); | ||
if (maybeGlyph.isPresent()) { | ||
var glyph = maybeGlyph.get(); | ||
Image img = fromGlyphToImg(glyph); | ||
var toggleButton = new ToggleButton("U" + glyph.code()); | ||
toggleButton.setGraphic(new ImageView(img)); | ||
toggleButton.setContentDisplay(ContentDisplay.TOP); | ||
var selected = currentlySelected.get(glyph.code()); | ||
toggleButton.setSelected(selected != null && selected); | ||
toggleButton.setOnAction(event -> currentlySelected.put(glyph.code(), toggleButton.isSelected())); | ||
fontRenderArea.add(toggleButton, gridCol, gridRow); | ||
allButtons.add(toggleButton); | ||
GridPane.setMargin(toggleButton, new Insets(4)); | ||
gridCol++; | ||
if(gridCol > 9) { | ||
gridCol = 0; | ||
gridRow++; | ||
} | ||
} | ||
} | ||
gridRow++; | ||
controlsByBlock.put(blockRange, allButtons); | ||
} | ||
} | ||
|
||
private Image fromGlyphToImg(ConvertedFontGlyph glyph) { | ||
WritableImage img = new WritableImage(glyph.calculatedWidth() + 1, glyph.belowBaseline() + glyph.toBaseLine() + 1); | ||
var writer = img.getPixelWriter(); | ||
int bitOffset = 0; | ||
for(int y=glyph.fontDims().startY();y<glyph.fontDims().lastY(); y++) { | ||
for(int x=glyph.fontDims().startX();x<glyph.fontDims().lastX(); x++) { | ||
int byteOffset = bitOffset / 8; | ||
if(byteOffset >= glyph.data().length) break; | ||
int d = glyph.data()[byteOffset]; | ||
boolean on = (d & (1<<(bitOffset % 8))) != 0; | ||
if(on) { | ||
writer.setColor(x, y, Color.WHITE); | ||
} | ||
bitOffset++; | ||
} | ||
} | ||
return img; | ||
} | ||
|
||
public void onFontStyleChanged(ActionEvent actionEvent) { | ||
changeNameField(); | ||
recalcFont(); | ||
} | ||
|
||
private void changeNameField() { | ||
var file = Path.of(fontFileField.getText()).getFileName().toString(); | ||
file = file.replace(".ttf", ""); | ||
var outputName = file + " " + pixelSizeSpinner.getValue() + "pt " + fontStyleCombo.getValue(); | ||
outputStructNameField.setText(VariableNameGenerator.makeNameFromVariable(outputName)); | ||
} | ||
|
||
public void onChooseUnicodeRanges(ActionEvent actionEvent) { | ||
if(loadedFont instanceof NoLoadedFont) { | ||
Alert alert = new Alert(Alert.AlertType.ERROR, "Please select a font before choosing unicode ranges"); | ||
alert.setTitle("No font Selected"); | ||
alert.setHeaderText("No Font Selected"); | ||
alert.showAndWait(); | ||
} else { | ||
Stage mainStage = (Stage) outputStructNameField.getScene().getWindow(); | ||
var dlg = new SelectUnicodeRangesDialog(mainStage, loadedFont, blockMappings); | ||
dlg.getBlockMappings().ifPresent(unicodeBlockMappings -> { | ||
blockMappings = unicodeBlockMappings; | ||
recalcFont(); | ||
}); | ||
|
||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
87 changes: 87 additions & 0 deletions
87
...main/java/com/thecoderscorner/menu/editorui/controller/SelectUnicodeRangesController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package com.thecoderscorner.menu.editorui.controller; | ||
|
||
import com.thecoderscorner.menu.editorui.generator.font.LoadedFont; | ||
import com.thecoderscorner.menu.editorui.generator.font.UnicodeBlockMapping; | ||
import javafx.beans.property.BooleanProperty; | ||
import javafx.beans.property.SimpleBooleanProperty; | ||
import javafx.collections.FXCollections; | ||
import javafx.event.ActionEvent; | ||
import javafx.scene.control.Button; | ||
import javafx.scene.control.ListView; | ||
import javafx.scene.control.TextField; | ||
import javafx.scene.control.cell.CheckBoxListCell; | ||
import javafx.stage.Stage; | ||
|
||
import java.util.Arrays; | ||
import java.util.Optional; | ||
import java.util.Set; | ||
import java.util.stream.Collectors; | ||
|
||
import static com.thecoderscorner.menu.editorui.generator.font.AwtLoadedFont.NO_LOADED_FONT; | ||
|
||
public class SelectUnicodeRangesController { | ||
public TextField unicodeSearchField; | ||
public ListView<UnicodeBlockWithSelection> unicodeRangeList; | ||
public Button selectRangeButton; | ||
|
||
private LoadedFont loadedFont = NO_LOADED_FONT; | ||
private Optional<Set<UnicodeBlockMapping>> result = Optional.empty(); | ||
|
||
public void initialise(LoadedFont loadedFont, Set<UnicodeBlockMapping> currentEnabledMappings) { | ||
var blocksForList = Arrays.stream(UnicodeBlockMapping.values()) | ||
.map(bm -> new UnicodeBlockWithSelection(bm, currentEnabledMappings.contains(bm))) | ||
.toList(); | ||
unicodeRangeList.setItems(FXCollections.observableArrayList(blocksForList)); | ||
|
||
unicodeRangeList.setCellFactory(CheckBoxListCell.forListView(UnicodeBlockWithSelection::selectedProperty)); | ||
} | ||
|
||
public Optional<Set<UnicodeBlockMapping>> getBlockMappings() { | ||
return result; | ||
} | ||
|
||
public void onCancel(ActionEvent actionEvent) { | ||
result = Optional.empty(); | ||
((Stage)unicodeSearchField.getScene().getWindow()).close(); | ||
} | ||
|
||
public void onSelectRanges(ActionEvent actionEvent) { | ||
result = Optional.of(unicodeRangeList.getItems().stream() | ||
.filter(UnicodeBlockWithSelection::isSelected) | ||
.map(UnicodeBlockWithSelection::getBlockMapping) | ||
.collect(Collectors.toSet()) | ||
); | ||
((Stage)unicodeSearchField.getScene().getWindow()).close(); | ||
} | ||
|
||
public static class UnicodeBlockWithSelection { | ||
private final UnicodeBlockMapping blockMapping; | ||
private final BooleanProperty selected = new SimpleBooleanProperty(); | ||
|
||
public UnicodeBlockWithSelection(UnicodeBlockMapping blockMapping, boolean selected) { | ||
this.blockMapping = blockMapping; | ||
this.selected.set(selected); | ||
} | ||
|
||
public UnicodeBlockMapping getBlockMapping() { | ||
return blockMapping; | ||
} | ||
|
||
public boolean isSelected() { | ||
return selected.get(); | ||
} | ||
|
||
public void setSelected(boolean sel) { | ||
selected.set(sel); | ||
} | ||
|
||
public BooleanProperty selectedProperty() { | ||
return selected; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return blockMapping.toString(); | ||
} | ||
} | ||
} |
21 changes: 21 additions & 0 deletions
21
...rator/src/main/java/com/thecoderscorner/menu/editorui/dialog/CreateFontUtilityDialog.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package com.thecoderscorner.menu.editorui.dialog; | ||
|
||
import com.thecoderscorner.menu.editorui.controller.CreateFontUtilityController; | ||
import com.thecoderscorner.menu.editorui.uimodel.CurrentProjectEditorUI; | ||
import javafx.stage.Stage; | ||
|
||
public class CreateFontUtilityDialog extends BaseDialogSupport<CreateFontUtilityController> { | ||
private final String homeDirectory; | ||
private CurrentProjectEditorUI editorUI; | ||
|
||
public CreateFontUtilityDialog(Stage mainStage, CurrentProjectEditorUI editorUI, String homeDirectory) { | ||
this.editorUI = editorUI; | ||
this.homeDirectory = homeDirectory; | ||
tryAndCreateDialog(mainStage, "/ui/createFontPanel.fxml", "Create Font Utility", true); | ||
} | ||
|
||
@Override | ||
protected void initialiseController(CreateFontUtilityController controller) throws Exception { | ||
controller.initialise(editorUI, homeDirectory); | ||
} | ||
} |
33 changes: 33 additions & 0 deletions
33
...tor/src/main/java/com/thecoderscorner/menu/editorui/dialog/SelectUnicodeRangesDialog.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package com.thecoderscorner.menu.editorui.dialog; | ||
|
||
import com.thecoderscorner.menu.domain.state.MenuTree; | ||
import com.thecoderscorner.menu.editorui.controller.EditMenuInMenuItemController; | ||
import com.thecoderscorner.menu.editorui.controller.SelectUnicodeRangesController; | ||
import com.thecoderscorner.menu.editorui.generator.font.LoadedFont; | ||
import com.thecoderscorner.menu.editorui.generator.font.UnicodeBlockMapping; | ||
import com.thecoderscorner.menu.editorui.generator.parameters.MenuInMenuDefinition; | ||
import javafx.stage.Stage; | ||
|
||
import java.util.Optional; | ||
import java.util.Set; | ||
|
||
public class SelectUnicodeRangesDialog extends BaseDialogSupport<SelectUnicodeRangesController> { | ||
|
||
private final LoadedFont loadedFont; | ||
private Set<UnicodeBlockMapping> selectedRegions; | ||
|
||
public SelectUnicodeRangesDialog(Stage stage, LoadedFont loadedFont, Set<UnicodeBlockMapping> selectedRegions) { | ||
this.loadedFont = loadedFont; | ||
this.selectedRegions = selectedRegions; | ||
tryAndCreateDialog(stage, "/ui/selectUnicodeRanges.fxml", "Select Unicode Regions", true); | ||
} | ||
|
||
@Override | ||
protected void initialiseController(SelectUnicodeRangesController controller) throws Exception { | ||
controller.initialise(loadedFont, selectedRegions); | ||
} | ||
|
||
public Optional<Set<UnicodeBlockMapping>> getBlockMappings() { | ||
return controller.getBlockMappings(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.