package com.kreative.paint.palette; import java.awt.*; import java.awt.event.*; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import javax.swing.*; import javax.swing.event.*; import com.kreative.paint.PaintContext; import com.kreative.paint.PaintContextListener; import com.kreative.paint.document.draw.PaintSettings; import com.kreative.paint.material.MaterialList; import com.kreative.paint.material.MaterialManager; import com.kreative.paint.material.fontlist.FontList; import com.kreative.paint.util.SwingUtils; public class FontPanel extends PaintContextPanel { private static final long serialVersionUID = 1L; private static final int[] menusizes = new int[] { 9, 10, 12, 14, 18, 24, 36, 48, 56, 64, 72 }; private static final int[] sizes = new int[]{ 7, 8, 9, 10, 11, 12, 13, 14, 16, 18, 20, 22, 24, 28, 32, 36, 40, 44, 48, 56, 64, 72, 80, 88, 96, 120, 144 }; private static final String[] styleNames = new String[]{ PaletteUtilities.messages.getString("fonts.plain"), PaletteUtilities.messages.getString("fonts.bold"), PaletteUtilities.messages.getString("fonts.italic"), PaletteUtilities.messages.getString("fonts.bolditalic") }; private static final int[] styles = new int[]{ Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD|Font.ITALIC }; private String allFontsName; private SortedMap<String,Font> allFonts; private SortedMap<String,FontList> fontLists; private DefaultListModel collectionList; private JList collectionView; private DefaultListModel fontList; private JList fontView; private DefaultListModel styleList; private JList styleView; private DefaultListModel sizeList; private JList sizeView; private SpinnerModel sizeSpin; private JSpinner sizeSpinView; private JPopupMenu fpop; private JPopupMenu spop; private boolean eventexec = false; public FontPanel(PaintContext pc, MaterialManager mm) { super(pc, CHANGED_FONT); allFontsName = PaletteUtilities.messages.getString("fonts.all"); allFonts = mm.fontLoader().getFonts(); String[] allFontNames = allFonts.keySet().toArray(new String[allFonts.size()]); FontList allFontsList = new FontList(allFontsName, allFontNames); fontLists = new TreeMap<String,FontList>(); fontLists.put(allFontsName, allFontsList); MaterialList<FontList> fl = mm.fontLoader().getFontLists(); for (int j = 0; j < fl.size(); j++) { String listName = fl.getName(j); FontList oldList = fl.getValue(j); FontList newList = new FontList(listName); for (int i = 0, n = oldList.size(); i < n; i++) { Integer fontId = oldList.getId(i); String fontName = oldList.getName(i); if (allFonts.containsKey(fontName)) { newList.add(fontId, fontName); } } if (!newList.isEmpty()) { fontLists.put(listName, newList); } } collectionList = new DefaultListModel(); for (String coll : fontLists.keySet()) collectionList.addElement(coll); collectionView = new JList(collectionList); collectionView.setSelectedValue(allFontsName, true); JScrollPane collectionPane = new JScrollPane(collectionView, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); fontList = new DefaultListModel(); for (String font : allFonts.keySet()) fontList.addElement(font); fontView = new JList(fontList); JScrollPane fontPane = new JScrollPane(fontView, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); styleList = new DefaultListModel(); for (String style : styleNames) styleList.addElement(style); styleView = new JList(styleList); styleView.setCellRenderer(new DefaultListCellRenderer() { private static final long serialVersionUID = 1L; public Component getListCellRendererComponent(JList list, Object value, int index, boolean sel, boolean focus) { JLabel l = (JLabel)super.getListCellRendererComponent(list, value, index, sel, focus); l.setFont(l.getFont().deriveFont(styles[index])); return l; } }); JScrollPane stylePane = new JScrollPane(styleView, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); sizeList = new DefaultListModel(); for (int size : sizes) sizeList.addElement(size); sizeView = new JList(sizeList); JScrollPane sizePane = new JScrollPane(sizeView, JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); sizeSpin = new SpinnerNumberModel(12, 1, 32767, 1); sizeSpinView = new JSpinner(sizeSpin); SwingUtils.shrink(sizeSpinView); collectionView.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!eventexec) { eventexec = true; fontList.removeAllElements(); FontList coll = fontLists.get(collectionView.getSelectedValue().toString()); for (String font : coll.uniqueNamesToArray()) fontList.addElement(font); if (FontPanel.this.pc != null) { Font f = FontPanel.this.pc.getFont(); fontView.setSelectedValue(f.getFamily(), true); int style = f.getStyle(); for (int i=0; i<styleNames.length && i<styles.length; i++) { if (styles[i] == style) styleView.setSelectedValue(styleNames[i], true); } sizeView.setSelectedValue(f.getSize(), true); } eventexec = false; } } }); fontView.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!eventexec) { eventexec = true; if (FontPanel.this.pc != null) { String fn = fontView.getSelectedValue().toString(); int st = styles[styleView.getSelectedIndex()]; int sz = ((Number)sizeView.getSelectedValue()).intValue(); Font font = allFonts.containsKey(fn) ? allFonts.get(fn).deriveFont(st, (float)sz) : new Font(fn, st, sz); FontPanel.this.pc.setFont(font); } eventexec = false; } } }); styleView.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!eventexec) { eventexec = true; if (FontPanel.this.pc != null) { String fn = fontView.getSelectedValue().toString(); int st = styles[styleView.getSelectedIndex()]; int sz = ((Number)sizeView.getSelectedValue()).intValue(); Font font = allFonts.containsKey(fn) ? allFonts.get(fn).deriveFont(st, (float)sz) : new Font(fn, st, sz); FontPanel.this.pc.setFont(font); } eventexec = false; } } }); sizeView.addListSelectionListener(new ListSelectionListener() { public void valueChanged(ListSelectionEvent e) { if (!eventexec) { eventexec = true; if (FontPanel.this.pc != null) { String fn = fontView.getSelectedValue().toString(); int st = styles[styleView.getSelectedIndex()]; int sz = ((Number)sizeView.getSelectedValue()).intValue(); Font font = allFonts.containsKey(fn) ? allFonts.get(fn).deriveFont(st, (float)sz) : new Font(fn, st, sz); FontPanel.this.pc.setFont(font); sizeSpin.setValue(sz); } eventexec = false; } } }); sizeSpinView.addChangeListener(new ChangeListener() { public void stateChanged(ChangeEvent e) { if (!eventexec) { eventexec = true; if (FontPanel.this.pc != null) { String fn = fontView.getSelectedValue().toString(); int st = styles[styleView.getSelectedIndex()]; int sz = ((Number)sizeSpin.getValue()).intValue(); Font font = allFonts.containsKey(fn) ? allFonts.get(fn).deriveFont(st, (float)sz) : new Font(fn, st, sz); FontPanel.this.pc.setFont(font); sizeView.clearSelection(); sizeView.setSelectedValue(sz, true); } eventexec = false; } } }); JPanel fontPanel = new JPanel(new GridLayout(1,3)); fontPanel.add(collectionPane); fontPanel.add(fontPane); fontPanel.add(stylePane); JPanel sizePanel = new JPanel(new BorderLayout()); sizePanel.add(sizePane, BorderLayout.CENTER); sizePanel.add(sizeSpinView, BorderLayout.SOUTH); setLayout(new BorderLayout()); add(fontPanel, BorderLayout.CENTER); add(sizePanel, BorderLayout.EAST); fpop = new FontPopup(); spop = new SizePopup(); update(); } public void update() { if (!eventexec) { eventexec = true; if (pc != null) { Font f = pc.getFont(); if (!fontList.contains(f.getFamily())) { collectionView.setSelectedValue(allFontsName, true); fontList.removeAllElements(); for (String font : allFonts.keySet()) fontList.addElement(font); } fontView.setSelectedValue(f.getFamily(), true); int style = f.getStyle(); for (int i=0; i<styleNames.length && i<styles.length; i++) { if (styles[i] == style) styleView.setSelectedValue(styleNames[i], true); } sizeView.clearSelection(); sizeView.setSelectedValue(f.getSize(), true); sizeSpin.setValue(f.getSize()); } eventexec = false; } } public JPopupMenu getFontPopup() { return fpop; } public JPopupMenu getSizePopup() { return spop; } private static final String[] ALPHABET_LETTERS = new String[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "#" }; private class FontPopup extends JPopupMenu implements PaintContextListener { private static final long serialVersionUID = 1L; public FontPopup() { add(new ShowFontsMenuItem(this)); addSeparator(); String sel = FontPanel.this.pc.getFont().getFamily(); for (Map.Entry<String,FontList> c : fontLists.entrySet()) { if (c.getKey().equals(allFontsName)) { // All Fonts is handled specially because Java is terrible at handling long menus. JMenu m = new JMenu(c.getKey()); JMenu[] sm = new JMenu[ALPHABET_LETTERS.length]; for (int i = 0; i < ALPHABET_LETTERS.length; i++) { sm[i] = new JMenu(ALPHABET_LETTERS[i]); m.add(sm[i]); } for (final String fontName : c.getValue().uniqueNamesToArray()) { JMenuItem mi = new JCheckBoxMenuItem(fontName); mi.setSelected(fontName.equals(sel)); mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Font pf = FontPanel.this.pc.getFont(); int st = pf.getStyle(); int sz = pf.getSize(); Font font = allFonts.containsKey(fontName) ? allFonts.get(fontName).deriveFont(st, (float)sz) : new Font(fontName, st, sz); FontPanel.this.pc.setFont(font); } }); boolean found = false; for (int i = 0; i < ALPHABET_LETTERS.length; i++) { if (fontName.toLowerCase().startsWith(ALPHABET_LETTERS[i].toLowerCase())) { sm[i].add(mi); found = true; break; } } if (!found) sm[ALPHABET_LETTERS.length-1].add(mi); } add(m); } else { JMenu m = new JMenu(c.getKey()); for (final String fontName : c.getValue().uniqueNamesToArray()) { JMenuItem mi = new JCheckBoxMenuItem(fontName); mi.setSelected(fontName.equals(sel)); mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Font pf = FontPanel.this.pc.getFont(); int st = pf.getStyle(); int sz = pf.getSize(); Font font = allFonts.containsKey(fontName) ? allFonts.get(fontName).deriveFont(st, (float)sz) : new Font(fontName, st, sz); FontPanel.this.pc.setFont(font); } }); m.add(mi); } add(m); } } FontPanel.this.pc.addPaintContextListener(FontPopup.this); } public void editingChanged(PaintContext src, boolean editingStroke, boolean editingBkgnd) {} public void paintSettingsChanged(PaintContext src, PaintSettings ps, int delta) { if ((delta & PaintContext.CHANGED_FONT) != 0) { setChecked(FontPopup.this, ps.textFont.getFamily()); } } private void setChecked(MenuElement mi, String sel) { if (mi instanceof JMenuItem) { ((JMenuItem)mi).setSelected(((JMenuItem)mi).getText().equals(sel)); } for (MenuElement smi : mi.getSubElements()) { setChecked(smi, sel); } } } private class SizePopup extends JPopupMenu implements PaintContextListener { private static final long serialVersionUID = 1L; public SizePopup() { add(new ShowFontsMenuItem(this)); addSeparator(); int selst = FontPanel.this.pc.getFont().getStyle(); int selsz = FontPanel.this.pc.getFont().getSize(); for (int i = 0; i < styles.length; i++) { JMenuItem mi = new JCheckBoxMenuItem(styleNames[i]); mi.setSelected(styles[i] == selst); mi.setFont(mi.getFont().deriveFont(styles[i])); final int st = styles[i]; mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { FontPanel.this.pc.setFont(FontPanel.this.pc.getFont().deriveFont(st)); } }); add(mi); } addSeparator(); for (int size : menusizes) { JMenuItem mi = new JCheckBoxMenuItem(Integer.toString(size)); mi.setSelected(size == selsz); final float sz = (float)size; mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { FontPanel.this.pc.setFont(FontPanel.this.pc.getFont().deriveFont(sz)); } }); add(mi); } JMenuItem mi = new JMenuItem(PaletteUtilities.messages.getString("fonts.other")); mi.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Font f = FontPanel.this.pc.getFont(); String nz = JOptionPane.showInputDialog(PaletteUtilities.messages.getString("fonts.other.prompt"), Integer.toString(f.getSize())); if (nz != null) { try { int sz = Integer.parseInt(nz); FontPanel.this.pc.setFont(f.deriveFont((float)sz)); } catch (NumberFormatException nfe) {} } } }); add(mi); FontPanel.this.pc.addPaintContextListener(SizePopup.this); } public void editingChanged(PaintContext src, boolean editingStroke, boolean editingBkgnd) {} public void paintSettingsChanged(PaintContext src, PaintSettings ps, int delta) { if ((delta & PaintContext.CHANGED_FONT) != 0) { setChecked(this, ps.textFont.getStyle(), ps.textFont.getSize()); } } private void setChecked(MenuElement mi, int selst, int selsz) { String selstst = ""; for (int i = 0; i < styles.length; i++) { if (styles[i] == selst) selstst = styleNames[i]; } String selszst = Integer.toString(selsz); setChecked(mi, selstst, selszst); } private void setChecked(MenuElement mi, String selst, String selsz) { if (mi instanceof JMenuItem) { ((JMenuItem)mi).setSelected(((JMenuItem)mi).getText().equals(selst) || ((JMenuItem)mi).getText().equals(selsz)); } for (MenuElement smi : mi.getSubElements()) { setChecked(smi, selst, selsz); } } } private class ShowFontsMenuItem extends JMenuItem { private static final long serialVersionUID = 1L; public ShowFontsMenuItem(final JPopupMenu parent) { super(PaletteUtilities.messages.getString("fonts.show")); addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { Container c = FontPanel.this.getParent(); while (true) { if (c == null) { return; } else if (c instanceof Window) { Point p = MouseInfo.getPointerInfo().getLocation(); c.setLocation(p.x-64, p.y-8); c.setVisible(true); return; } else { c = c.getParent(); } } } }); } } }