/* * Open Source Physics software is free software as described near the bottom of this code file. * * For additional information and documentation on Open Source Physics please see: * <http://www.opensourcephysics.org/> */ package org.opensourcephysics.tools; import java.awt.Component; import java.awt.Container; import java.awt.Font; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.lang.reflect.Method; import java.util.Collection; import java.util.HashMap; import java.util.Map; import javax.swing.Icon; import javax.swing.JButton; import javax.swing.JMenu; import javax.swing.JMenuItem; import javax.swing.JTextField; import javax.swing.UIManager; import javax.swing.border.Border; import javax.swing.border.TitledBorder; import javax.swing.event.SwingPropertyChangeSupport; import org.opensourcephysics.display.ResizableIcon; /** * A class for setting relative font sizes by level. * * @author dobrown * @version 1.0 */ public class FontSizer { /** Base font for text fields */ public static final Font TEXT_FONT = new JTextField().getFont(); /** Base font for buttons */ public static final Font BUTTON_FONT = new JButton().getFont(); /** Base font for menu accelerators */ public static final Font ACCELERATOR_FONT = (Font)UIManager.get("MenuItem.acceleratorFont"); //$NON-NLS-1$ /** Icons for checkbox, radio button and arrow menu items */ public static final ResizableIcon CHECKBOXMENUITEM_ICON; public static final ResizableIcon RADIOBUTTONMENUITEM_ICON; public static final ResizableIcon CHECKBOX_ICON; public static final ResizableIcon RADIOBUTTON_ICON; public static final ResizableIcon ARROW_ICON; /** maximum font level */ public static final int MAX_LEVEL = 20; // static fields static Object levelObj = new FontSizer(); static PropertyChangeSupport support = new SwingPropertyChangeSupport(levelObj); static int level, integerFactor; static double levelFactor = 1.25; // size ratio per level static double factor; static Map<Font, Font> fontMap = new HashMap<Font, Font>(); static { Icon baseIcon = (Icon)UIManager.get("CheckBoxMenuItem.checkIcon"); //$NON-NLS-1$ CHECKBOXMENUITEM_ICON = new ResizableIcon(baseIcon); UIManager.put("CheckBoxMenuItem.checkIcon", CHECKBOXMENUITEM_ICON); //$NON-NLS-1$ baseIcon = (Icon)UIManager.get("CheckBox.icon"); //$NON-NLS-1$ CHECKBOX_ICON = new ResizableIcon(baseIcon); UIManager.put("CheckBox.icon", CHECKBOX_ICON); //$NON-NLS-1$ baseIcon = (Icon)UIManager.get("RadioButtonMenuItem.checkIcon"); //$NON-NLS-1$ RADIOBUTTONMENUITEM_ICON = new ResizableIcon(baseIcon); UIManager.put("RadioButtonMenuItem.checkIcon", RADIOBUTTONMENUITEM_ICON); //$NON-NLS-1$ baseIcon = (Icon)UIManager.get("RadioButton.icon"); //$NON-NLS-1$ RADIOBUTTON_ICON = new ResizableIcon(baseIcon); UIManager.put("RadioButton.icon", RADIOBUTTON_ICON); //$NON-NLS-1$ baseIcon = (Icon)UIManager.get("Menu.arrowIcon"); //$NON-NLS-1$ ARROW_ICON = new ResizableIcon(baseIcon); UIManager.put("Menu.arrowIcon", ARROW_ICON); //$NON-NLS-1$ } /** * Private constructor to prevent instantiation. */ private FontSizer() { /** empty block */ } /** * Sets the font level and informs all listeners. * * @param n a non-negative integer level */ public static void setLevel(int n) { n = Math.min(n, MAX_LEVEL); level = Math.max(n, 0); factor = getFactor(level); integerFactor = getIntegerFactor(level); CHECKBOXMENUITEM_ICON.resize(integerFactor); CHECKBOX_ICON.resize(integerFactor); ARROW_ICON.resize(integerFactor); RADIOBUTTONMENUITEM_ICON.resize(integerFactor); RADIOBUTTON_ICON.resize(integerFactor); Font font = getResizedFont(TEXT_FONT, level); UIManager.put("OptionPane.messageFont", font); //$NON-NLS-1$ UIManager.put("TextField.font", font); //$NON-NLS-1$ UIManager.put("ToolTip.font", font); //$NON-NLS-1$ UIManager.put("TabbedPane.font", font); //$NON-NLS-1$ font = getResizedFont(ACCELERATOR_FONT, level); UIManager.put("MenuItem.acceleratorFont", font); //$NON-NLS-1$ font= getResizedFont(BUTTON_FONT, level); UIManager.put("OptionPane.buttonFont", font); //$NON-NLS-1$ support.firePropertyChange("level", null, new Integer(level)); //$NON-NLS-1$ } /** * Gets the current font level. * * @return the level */ public static int getLevel() { return level; } /** * Increments the font level. */ public static void levelUp() { setLevel(level+1); } /** * Decrements the font level. */ public static void levelDown() { setLevel(level-1); } /** * Gets the current factor. * * @return the factor */ public static double getFactor() { return factor; } /** * Gets the current integer factor. * * @return the integer factor */ public static int getIntegerFactor() { return integerFactor; } /** * Sets the fonts of an object to a specified level. * * @param obj the object * @param level the level */ public static void setFonts(Object obj, int level) { if (obj instanceof Object[]) { for (Object next: ((Object[])obj)) { setFonts(next, level); } return; } if (obj instanceof Collection) { for (Object next: ((Collection<?>)obj)) { setFonts(next, level); } return; } double factor = getFactor(level); if(obj instanceof Container) { setFontFactor((Container) obj, factor); } else if(obj instanceof TitledBorder) { setFontFactor((TitledBorder) obj, factor); } else if(obj instanceof Component) { setFontFactor((Component) obj, factor); } } /** * Resizes a font to a specified level. * * @param font the font * @param level the level * @return the resized font */ public static Font getResizedFont(Font font, int level) { return getResizedFont(font, getFactor(level)); } /** * Resizes a font by a specified factor. * * @param font the font * @param factor the factor * @return the resized font */ public static Font getResizedFont(Font font, double factor) { if(font==null) { return null; } // get base font for this font Font base = fontMap.get(font); if(base==null) { base = font; fontMap.put(font, base); } // derive new font from base float size = (float) (base.getSize()*factor); font = base.deriveFont(size); fontMap.put(font, base); return font; } /** * Gets the factor corresponding to a specified level. * * @param level the level * @return the factor */ public static double getFactor(int level) { // get font size factor (= levelFactor^level) double factor = 1.0; for(int i = 0; i<level; i++) { factor *= levelFactor; } return factor; } /** * Gets the integer factor corresponding to a specified level. * * @param level the level * @return the integer factor */ public static int getIntegerFactor(int level) { return Math.round(Math.round(getFactor(level))); } /** * Adds a PropertyChangeListener. * * @param property the name of the property (only "level" accepted) * @param listener the object requesting property change notification */ public static void addPropertyChangeListener(String property, PropertyChangeListener listener) { if(property.equals("level")) { //$NON-NLS-1$ support.addPropertyChangeListener(property, listener); } } /** * Removes a PropertyChangeListener. * * @param property the name of the property (only "level" accepted) * @param listener the listener requesting removal */ public static void removePropertyChangeListener(String property, PropertyChangeListener listener) { support.removePropertyChangeListener(property, listener); } //_______________________________ private methods ____________________________ /** * Increases a container's normal font sizes by the specified factor. * * @param c a container * @param factor the factor */ private static void setFontFactor(Container c, double factor) { // get resized container font Font font = getResizedFont(c.getFont(), factor); // Added by Paco. This must be here because JComponent inherits from Container if (c instanceof javax.swing.JComponent) { Border border = ((javax.swing.JComponent) c).getBorder(); if(border instanceof TitledBorder) { setFontFactor((TitledBorder) border, factor); } } // End of added by Paco if (c instanceof JMenu) { setMenuFont((JMenu) c, font); } else { c.setFont(font); // iterate through child components for(int i = 0; i<c.getComponentCount(); i++) { Component co = c.getComponent(i); if((co instanceof Container)) { setFontFactor((Container) co, factor); } else { setFontFactor(co, factor); } } } // added by Doug Brown June 2015 to resize icons along with fonts if (c instanceof JButton) { JButton button = (JButton)c; for (int i=0; i<5; i++) { Icon icon = i==0? button.getIcon(): i==2? button.getSelectedIcon(): i==3? button.getRolloverIcon(): i==4? button.getRolloverSelectedIcon(): button.getDisabledIcon(); if (icon!=null && icon instanceof ResizableIcon) { ((ResizableIcon)icon).resize(getIntegerFactor()); } } } else if (c instanceof JMenu) { JMenu menu = (JMenu)c; Icon icon = menu.getIcon(); if (icon!=null && icon instanceof ResizableIcon) { ((ResizableIcon)icon).resize(getIntegerFactor()); } for (int i=0; i< menu.getItemCount(); i++) { JMenuItem item = menu.getItem(i); if (item!=null) { setFontFactor(item, factor); } } } else try { Method m = c.getClass().getMethod("getIcon", (Class<?>[])null); //$NON-NLS-1$ Icon icon = (Icon)m.invoke(c, (Object[])null); if (icon!=null && icon instanceof ResizableIcon) { ((ResizableIcon)icon).resize(getIntegerFactor()); } } catch (Exception e) { } // end of code added by Doug c.repaint(); } /** * Increases a component's normal font sizes by the specified factor. * * @param c a component * @param factor the factor */ private static void setFontFactor(Component c, double factor) { // get resized component font Font font = getResizedFont(c.getFont(), factor); c.setFont(font); // Added by Paco if (c instanceof javax.swing.JComponent) { Border border = ((javax.swing.JComponent) c).getBorder(); if(border instanceof TitledBorder) { setFontFactor((TitledBorder) border, factor); } } // End of added by Paco } /** * Increases a titled border's normal font size by the specified factor. * * @param b a titled border * @param factor the factor */ private static void setFontFactor(TitledBorder b, double factor) { // get resized border font Font font = b.getTitleFont(); if (font==null) { font = UIManager.getFont("TitledBorder.font"); //$NON-NLS-1$ } font = getResizedFont(font, factor); b.setTitleFont(font); } /** * Sets the menu font. * * @param m a menu * @param font the font */ private static void setMenuFont(JMenu m, Font font) { m.setFont(font); for(int i = 0; i<m.getMenuComponentCount(); i++) { m.getMenuComponent(i).setFont(font); if(m.getMenuComponent(i) instanceof JMenu) { setMenuFont((JMenu) m.getMenuComponent(i), font); } } } } /* * Open Source Physics software is free software; you can redistribute * it and/or modify it under the terms of the GNU General Public License (GPL) as * published by the Free Software Foundation; either version 2 of the License, * or(at your option) any later version. * Code that uses any portion of the code in the org.opensourcephysics package * or any subpackage (subdirectory) of this package must must also be be released * under the GNU GPL license. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston MA 02111-1307 USA * or view the license online at http://www.gnu.org/copyleft/gpl.html * * Copyright (c) 2007 The Open Source Physics project * http://www.opensourcephysics.org */