Skip to content

Commit

Permalink
Font Viewer: split view for simple glyphs.
Browse files Browse the repository at this point in the history
  • Loading branch information
rillig committed Oct 11, 2017
1 parent ef04160 commit e0574c2
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ public final String toString() {

abstract JComponent render();

boolean renderInScrollPane() {
return true;
}

@Override
public AbstractNode getChildAt(int index) {
throw new UnsupportedOperationException();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.google.typography.font.tools.fontviewer;

class AppState {
static int glyphRendererHeight = 200;
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private static List<AbstractNode> createTableNodes(Font font) {
Collections.sort(tableNodes, new Comparator<AbstractNode>() {
@Override
public int compare(AbstractNode o1, AbstractNode o2) {
return o1.getNodeName().compareTo(o2.getNodeName());
return o1.getNodeName().compareToIgnoreCase(o2.getNodeName());
}
});
return tableNodes;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
import com.google.typography.font.sfntly.Font;
import com.google.typography.font.sfntly.FontFactory;

import java.awt.Container;
import java.awt.Dimension;
import java.io.FileInputStream;

Expand All @@ -27,12 +26,13 @@
public class FontViewer {

private final JFrame frame;
private final JScrollPane mainScrollPane;
private final JScrollPane contentScrollPane;
private JSplitPane framePane;

FontViewer(Font font) {
JScrollPane fontPane = createFontTree(font);
this.mainScrollPane = createMainPane();
this.frame = createFrame(fontPane, this.mainScrollPane);
this.contentScrollPane = createContentPane();
this.frame = createFrame(fontPane, this.contentScrollPane);
}

private JScrollPane createFontTree(Font font) {
Expand All @@ -51,7 +51,7 @@ public void valueChanged(TreeSelectionEvent e) {
return fontPane;
}

private static JScrollPane createMainPane() {
private static JScrollPane createContentPane() {
JScrollPane pane = new JScrollPane();
pane.add(new JTextArea());
pane.setPreferredSize(new Dimension(500, 500));
Expand All @@ -61,9 +61,8 @@ private static JScrollPane createMainPane() {
private JFrame createFrame(JScrollPane fontPane, JScrollPane mainPane) {
JFrame frame = new JFrame("Font Viewer");
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
Container content = frame.getContentPane();
JSplitPane pane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, fontPane, mainPane);
content.add(pane);
this.framePane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, fontPane, mainPane);
frame.getContentPane().add(this.framePane);
frame.pack();
frame.setLocationRelativeTo(null);
return frame;
Expand All @@ -72,9 +71,14 @@ private JFrame createFrame(JScrollPane fontPane, JScrollPane mainPane) {
private void render(AbstractNode node) {
JComponent mainComponent = node.render();
mainComponent.setBorder(new EmptyBorder(3, 3, 3, 3));
this.mainScrollPane.setViewportView(mainComponent);
this.mainScrollPane.revalidate();
this.mainScrollPane.repaint();
if (node.renderInScrollPane()) {
this.contentScrollPane.setViewportView(mainComponent);
this.contentScrollPane.revalidate();
this.contentScrollPane.repaint();
this.framePane.setRightComponent(this.contentScrollPane);
} else {
this.framePane.setRightComponent(mainComponent);
}
}

public static void main(String[] args) throws Exception {
Expand Down
97 changes: 63 additions & 34 deletions java/src/com/google/typography/font/tools/fontviewer/GlyphNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
import com.google.typography.font.sfntly.table.truetype.Glyph;
import com.google.typography.font.sfntly.table.truetype.SimpleGlyph;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.RenderingHints;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.JTextArea;

public class GlyphNode extends AbstractNode {
Expand All @@ -23,70 +28,94 @@ public GlyphNode(int glyphId, Glyph glyph) {

@Override
protected String getNodeName() {
return String.valueOf(glyphId);
return String.valueOf(this.glyphId);
}

@Override
JComponent render() {
if (glyph instanceof SimpleGlyph) {
if (this.glyph instanceof SimpleGlyph) {
GlyphRenderer renderer = new GlyphRenderer();
JTextArea text = new JTextArea(glyph.toString());
JPanel panel = new JPanel();
panel.setLayout(new BorderLayout());
panel.add(renderer, BorderLayout.NORTH);
panel.add(text, BorderLayout.CENTER);
return panel;
JComponent text = new JScrollPane(new JTextArea(this.glyph.toString()));
text.setPreferredSize(new Dimension(500, 200));
final JSplitPane pane = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, renderer, text);
pane.addPropertyChangeListener(
JSplitPane.DIVIDER_LOCATION_PROPERTY,
new PropertyChangeListener() {
@Override
public void propertyChange(PropertyChangeEvent evt) {
AppState.glyphRendererHeight = (Integer) evt.getNewValue() - pane.getInsets().top;
}
});
pane.setPreferredSize(new Dimension(500, 500));
return pane;
} else {
return new JTextArea(glyph.toString());
return new JTextArea(this.glyph.toString());
}
}

@Override
boolean renderInScrollPane() {
return !(this.glyph instanceof SimpleGlyph);
}

private class GlyphRenderer extends JComponent {

private static final int MARGIN = 10;
private static final int SIZE = 100;

private final int minX = GlyphNode.this.glyph.xMin();
private final int minY = GlyphNode.this.glyph.yMin();
private final int maxX = GlyphNode.this.glyph.xMax();
private final int maxY = GlyphNode.this.glyph.yMax();

private double scale;

private void updateScale() {
int size = Math.min(this.getWidth(), this.getHeight()) - MARGIN - MARGIN;
this.scale = (double) size / Math.max(this.maxX - this.minX, this.maxY - this.minY);
}

@Override
public Dimension getPreferredSize() {
return new Dimension(MARGIN + SIZE + MARGIN, MARGIN + SIZE + MARGIN);
return new Dimension(500, AppState.glyphRendererHeight);
}

@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);

int minX = glyph.xMin(), minY = glyph.yMin();
int maxX = glyph.xMax(), maxY = glyph.yMax();
((Graphics2D) g).setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);

double scale = (double) SIZE / Math.max(maxX - minX, maxY - minY);
updateScale();

SimpleGlyph glyph = (SimpleGlyph) GlyphNode.this.glyph;
int firstScreenX = 0, firstScreenY = 0;
int lastScreenX = 0, lastScreenY = 0;
for (int c = 0, cmax = glyph.numberOfContours(); c < cmax; c++) {
Polygon polygon = new Polygon();
for (int p = 0, pmax = glyph.numberOfPoints(c); p < pmax; p++) {
int x = glyph.xCoordinate(c, p);
int y = glyph.yCoordinate(c, p);
polygon.addPoint(screenX(x), screenY(y));
}
g.setColor(Color.BLUE);
g.drawPolygon(polygon);

for (int p = 0, pmax = glyph.numberOfPoints(c); p < pmax; p++) {
int x = glyph.xCoordinate(c, p);
int y = glyph.yCoordinate(c, p);
boolean on = glyph.onCurve(c, p);
int screenX = MARGIN + (int) (scale * (x - minX));
int screenY = MARGIN + SIZE - (int) (scale * (y - minY));
g.setColor(on ? Color.BLACK : Color.GREEN);
g.drawOval(screenX - 2, screenY - 2, 4, 4);
if (p != 0) {
g.setColor(Color.BLUE);
g.drawLine(lastScreenX, lastScreenY, screenX, screenY);
} else {
firstScreenX = screenX;
firstScreenY = screenY;
}
if (p == pmax - 1) {
g.setColor(Color.BLUE);
g.drawLine(screenX, screenY, firstScreenX, firstScreenY);
}
lastScreenX = screenX;
lastScreenY = screenY;
g.drawOval(screenX(x) - 2, screenY(y) - 2, 4, 4);
}
}
}

private int screenX(int x) {
return MARGIN + (int) Math.round(this.scale * (x - this.minX));
}

private int screenY(int y) {
return MARGIN + (int) Math.round(this.scale * (this.maxY - y));
}
}
}

0 comments on commit e0574c2

Please sign in to comment.