From 92903490111e88d672bc230e8b6e3504b2feaf1c Mon Sep 17 00:00:00 2001 From: deathmarine Date: Tue, 26 Jul 2016 11:56:29 -0400 Subject: [PATCH] Addresses #53 Adds Ctrl+Wheel text zoom, and FontChooser to RightClick popup --- .gitignore | 1 + License.txt => license.txt | 0 Luyten.ico => luyten.ico | Bin pom.xml | 4 +- src/us/deathmarine/luyten/JFontChooser.java | 719 ++++++++++++++++++++ src/us/deathmarine/luyten/OpenFile.java | 53 +- 6 files changed, 773 insertions(+), 4 deletions(-) rename License.txt => license.txt (100%) rename Luyten.ico => luyten.ico (100%) create mode 100644 src/us/deathmarine/luyten/JFontChooser.java diff --git a/.gitignore b/.gitignore index 67a4b00..d565640 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,4 @@ /bin /target /lib +/resources diff --git a/License.txt b/license.txt similarity index 100% rename from License.txt rename to license.txt diff --git a/Luyten.ico b/luyten.ico similarity index 100% rename from Luyten.ico rename to luyten.ico diff --git a/pom.xml b/pom.xml index 36a4790..5bb5517 100644 --- a/pom.xml +++ b/pom.xml @@ -164,7 +164,7 @@ ${project.groupId}.${project.artifactId}.Luyten - Luyten.ico + luyten.ico 1.7.0 1.8.0 @@ -228,7 +228,7 @@ bundleid="${project.groupId}.${project.artifactId}" mainclass="${project.groupId}.${project.artifactId}.LuytenOsx" version="${project.version}" copyright="2015" - icon="${project.build.sourceDirectory}/resources/Luyten.icns" + icon="${project.build.sourceDirectory}/resources/luyten.icns" jvmversion="1.7+" screenmenu="true" antialiasedgraphics="true" highresolutioncapable="true" > diff --git a/src/us/deathmarine/luyten/JFontChooser.java b/src/us/deathmarine/luyten/JFontChooser.java new file mode 100644 index 0000000..3e5b262 --- /dev/null +++ b/src/us/deathmarine/luyten/JFontChooser.java @@ -0,0 +1,719 @@ +package us.deathmarine.luyten; + +import java.awt.BorderLayout; +import java.awt.Component; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Frame; +import java.awt.GraphicsEnvironment; +import java.awt.GridLayout; +import java.awt.event.ActionEvent; +import java.awt.event.FocusAdapter; +import java.awt.event.FocusEvent; +import java.awt.event.KeyAdapter; +import java.awt.event.KeyEvent; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import javax.swing.AbstractAction; +import javax.swing.Action; +import javax.swing.ActionMap; +import javax.swing.BorderFactory; +import javax.swing.BoxLayout; +import javax.swing.InputMap; +import javax.swing.JButton; +import javax.swing.JComponent; +import javax.swing.JDialog; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextField; +import javax.swing.KeyStroke; +import javax.swing.ListSelectionModel; +import javax.swing.SwingUtilities; +import javax.swing.border.Border; +import javax.swing.event.DocumentEvent; +import javax.swing.event.DocumentListener; +import javax.swing.event.ListSelectionEvent; +import javax.swing.event.ListSelectionListener; +import javax.swing.text.BadLocationException; +import javax.swing.text.Document; +import javax.swing.text.JTextComponent; +import javax.swing.text.Position; + +/** + * The JFontChooser class is a swing component for font selection. + * This class has JFileChooser like APIs. The following code pops + * up a font chooser dialog. + * + *
+ * JFontChooser fontChooser = new JFontChooser(); int result =
+ * fontChooser.showDialog(parent); if (result == JFontChooser.OK_OPTION) { Font
+ * font = fontChooser.getSelectedFont(); System.out.println("Selected Font : " +
+ * font); }
+ * 
+ * 
+ **/
+public class JFontChooser extends JComponent {
+	// class variables
+	/**
+	 * Return value from showDialog().
+	 * 
+	 * @see #showDialog
+	 **/
+	public static final int OK_OPTION = 0;
+	/**
+	 * Return value from showDialog().
+	 * 
+	 * @see #showDialog
+	 **/
+	public static final int CANCEL_OPTION = 1;
+	/**
+	 * Return value from showDialog().
+	 * 
+	 * @see #showDialog
+	 **/
+	public static final int ERROR_OPTION = -1;
+	private static final Font DEFAULT_SELECTED_FONT = new Font("Serif", Font.PLAIN, 12);
+	private static final Font DEFAULT_FONT = new Font("Dialog", Font.PLAIN, 10);
+	private static final int[] FONT_STYLE_CODES = { Font.PLAIN, Font.BOLD, Font.ITALIC, Font.BOLD | Font.ITALIC };
+	private static final String[] DEFAULT_FONT_SIZE_STRINGS = { "8", "9", "10", "11", "12", "14", "16", "18", "20",
+			"22", "24", "26", "28", "36", "48", "72", };
+
+	// instance variables
+	protected int dialogResultValue = ERROR_OPTION;
+
+	private String[] fontStyleNames = null;
+	private String[] fontFamilyNames = null;
+	private String[] fontSizeStrings = null;
+	private JTextField fontFamilyTextField = null;
+	private JTextField fontStyleTextField = null;
+	private JTextField fontSizeTextField = null;
+	private JList fontNameList = null;
+	private JList fontStyleList = null;
+	private JList fontSizeList = null;
+	private JPanel fontNamePanel = null;
+	private JPanel fontStylePanel = null;
+	private JPanel fontSizePanel = null;
+	private JPanel samplePanel = null;
+	private JTextField sampleText = null;
+
+	/**
+	 * Constructs a JFontChooser object.
+	 **/
+	public JFontChooser() {
+		this(DEFAULT_FONT_SIZE_STRINGS);
+	}
+
+	/**
+	 * Constructs a JFontChooser object using the given font size
+	 * array.
+	 * 
+	 * @param fontSizeStrings
+	 *            the array of font size string.
+	 **/
+	public JFontChooser(String[] fontSizeStrings) {
+		if (fontSizeStrings == null) {
+			fontSizeStrings = DEFAULT_FONT_SIZE_STRINGS;
+		}
+		this.fontSizeStrings = fontSizeStrings;
+
+		JPanel selectPanel = new JPanel();
+		selectPanel.setLayout(new BoxLayout(selectPanel, BoxLayout.X_AXIS));
+		selectPanel.add(getFontFamilyPanel());
+		selectPanel.add(getFontStylePanel());
+		selectPanel.add(getFontSizePanel());
+
+		JPanel contentsPanel = new JPanel();
+		contentsPanel.setLayout(new GridLayout(2, 1));
+		contentsPanel.add(selectPanel, BorderLayout.NORTH);
+		contentsPanel.add(getSamplePanel(), BorderLayout.CENTER);
+
+		this.setLayout(new BoxLayout(this, BoxLayout.X_AXIS));
+		this.add(contentsPanel);
+		this.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+		this.setSelectedFont(DEFAULT_SELECTED_FONT);
+	}
+
+	public JTextField getFontFamilyTextField() {
+		if (fontFamilyTextField == null) {
+			fontFamilyTextField = new JTextField();
+			fontFamilyTextField.addFocusListener(new TextFieldFocusHandlerForTextSelection(fontFamilyTextField));
+			fontFamilyTextField.addKeyListener(new TextFieldKeyHandlerForListSelectionUpDown(getFontFamilyList()));
+			fontFamilyTextField.getDocument()
+					.addDocumentListener(new ListSearchTextFieldDocumentHandler(getFontFamilyList()));
+			fontFamilyTextField.setFont(DEFAULT_FONT);
+
+		}
+		return fontFamilyTextField;
+	}
+
+	public JTextField getFontStyleTextField() {
+		if (fontStyleTextField == null) {
+			fontStyleTextField = new JTextField();
+			fontStyleTextField.addFocusListener(new TextFieldFocusHandlerForTextSelection(fontStyleTextField));
+			fontStyleTextField.addKeyListener(new TextFieldKeyHandlerForListSelectionUpDown(getFontStyleList()));
+			fontStyleTextField.getDocument()
+					.addDocumentListener(new ListSearchTextFieldDocumentHandler(getFontStyleList()));
+			fontStyleTextField.setFont(DEFAULT_FONT);
+		}
+		return fontStyleTextField;
+	}
+
+	public JTextField getFontSizeTextField() {
+		if (fontSizeTextField == null) {
+			fontSizeTextField = new JTextField();
+			fontSizeTextField.addFocusListener(new TextFieldFocusHandlerForTextSelection(fontSizeTextField));
+			fontSizeTextField.addKeyListener(new TextFieldKeyHandlerForListSelectionUpDown(getFontSizeList()));
+			fontSizeTextField.getDocument()
+					.addDocumentListener(new ListSearchTextFieldDocumentHandler(getFontSizeList()));
+			fontSizeTextField.setFont(DEFAULT_FONT);
+		}
+		return fontSizeTextField;
+	}
+
+	public JList getFontFamilyList() {
+		if (fontNameList == null) {
+			fontNameList = new JList(getFontFamilies());
+			fontNameList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+			fontNameList.addListSelectionListener(new ListSelectionHandler(getFontFamilyTextField()));
+			fontNameList.setSelectedIndex(0);
+			fontNameList.setFont(DEFAULT_FONT);
+			fontNameList.setFocusable(false);
+		}
+		return fontNameList;
+	}
+
+	public JList getFontStyleList() {
+		if (fontStyleList == null) {
+			fontStyleList = new JList(getFontStyleNames());
+			fontStyleList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+			fontStyleList.addListSelectionListener(new ListSelectionHandler(getFontStyleTextField()));
+			fontStyleList.setSelectedIndex(0);
+			fontStyleList.setFont(DEFAULT_FONT);
+			fontStyleList.setFocusable(false);
+		}
+		return fontStyleList;
+	}
+
+	public JList getFontSizeList() {
+		if (fontSizeList == null) {
+			fontSizeList = new JList(this.fontSizeStrings);
+			fontSizeList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+			fontSizeList.addListSelectionListener(new ListSelectionHandler(getFontSizeTextField()));
+			fontSizeList.setSelectedIndex(0);
+			fontSizeList.setFont(DEFAULT_FONT);
+			fontSizeList.setFocusable(false);
+		}
+		return fontSizeList;
+	}
+
+	/**
+	 * Get the family name of the selected font.
+	 * 
+	 * @return the font family of the selected font.
+	 *
+	 * @see #setSelectedFontFamily
+	 **/
+	public String getSelectedFontFamily() {
+		String fontName = (String) getFontFamilyList().getSelectedValue();
+		return fontName;
+	}
+
+	/**
+	 * Get the style of the selected font.
+	 * 
+	 * @return the style of the selected font. Font.PLAIN,
+	 *         Font.BOLD, Font.ITALIC,
+	 *         Font.BOLD|Font.ITALIC
+	 *
+	 * @see java.awt.Font#PLAIN
+	 * @see java.awt.Font#BOLD
+	 * @see java.awt.Font#ITALIC
+	 * @see #setSelectedFontStyle
+	 **/
+	public int getSelectedFontStyle() {
+		int index = getFontStyleList().getSelectedIndex();
+		return FONT_STYLE_CODES[index];
+	}
+
+	/**
+	 * Get the size of the selected font.
+	 * 
+	 * @return the size of the selected font
+	 *
+	 * @see #setSelectedFontSize
+	 **/
+	public int getSelectedFontSize() {
+		int fontSize = 1;
+		String fontSizeString = getFontSizeTextField().getText();
+		while (true) {
+			try {
+				fontSize = Integer.parseInt(fontSizeString);
+				break;
+			} catch (NumberFormatException e) {
+				fontSizeString = (String) getFontSizeList().getSelectedValue();
+				getFontSizeTextField().setText(fontSizeString);
+			}
+		}
+
+		return fontSize;
+	}
+
+	/**
+	 * Get the selected font.
+	 * 
+	 * @return the selected font
+	 *
+	 * @see #setSelectedFont
+	 * @see java.awt.Font
+	 **/
+	public Font getSelectedFont() {
+		Font font = new Font(getSelectedFontFamily(), getSelectedFontStyle(), getSelectedFontSize());
+		return font;
+	}
+
+	/**
+	 * Set the family name of the selected font.
+	 * 
+	 * @param name
+	 *            the family name of the selected font.
+	 *
+	 * @see getSelectedFontFamily
+	 **/
+	public void setSelectedFontFamily(String name) {
+		String[] names = getFontFamilies();
+		for (int i = 0; i < names.length; i++) {
+			if (names[i].toLowerCase().equals(name.toLowerCase())) {
+				getFontFamilyList().setSelectedIndex(i);
+				break;
+			}
+		}
+		updateSampleFont();
+	}
+
+	/**
+	 * Set the style of the selected font.
+	 * 
+	 * @param style
+	 *            the size of the selected font. Font.PLAIN,
+	 *            Font.BOLD, Font.ITALIC, or
+	 *            Font.BOLD|Font.ITALIC.
+	 *
+	 * @see java.awt.Font#PLAIN
+	 * @see java.awt.Font#BOLD
+	 * @see java.awt.Font#ITALIC
+	 * @see #getSelectedFontStyle
+	 **/
+	public void setSelectedFontStyle(int style) {
+		for (int i = 0; i < FONT_STYLE_CODES.length; i++) {
+			if (FONT_STYLE_CODES[i] == style) {
+				getFontStyleList().setSelectedIndex(i);
+				break;
+			}
+		}
+		updateSampleFont();
+	}
+
+	/**
+	 * Set the size of the selected font.
+	 * 
+	 * @param size
+	 *            the size of the selected font
+	 *
+	 * @see #getSelectedFontSize
+	 **/
+	public void setSelectedFontSize(int size) {
+		String sizeString = String.valueOf(size);
+		for (int i = 0; i < this.fontSizeStrings.length; i++) {
+			if (this.fontSizeStrings[i].equals(sizeString)) {
+				getFontSizeList().setSelectedIndex(i);
+				break;
+			}
+		}
+		getFontSizeTextField().setText(sizeString);
+		updateSampleFont();
+	}
+
+	/**
+	 * Set the selected font.
+	 * 
+	 * @param font
+	 *            the selected font
+	 *
+	 * @see #getSelectedFont
+	 * @see java.awt.Font
+	 **/
+	public void setSelectedFont(Font font) {
+		setSelectedFontFamily(font.getFamily());
+		setSelectedFontStyle(font.getStyle());
+		setSelectedFontSize(font.getSize());
+	}
+
+	public String getVersionString() {
+		return ("Version");
+	}
+
+	/**
+	 * Show font selection dialog.
+	 * 
+	 * @param parent
+	 *            Dialog's Parent component.
+	 * @return OK_OPTION, CANCEL_OPTION or ERROR_OPTION
+	 *
+	 * @see #OK_OPTION
+	 * @see #CANCEL_OPTION
+	 * @see #ERROR_OPTION
+	 **/
+	public int showDialog(Component parent) {
+		dialogResultValue = ERROR_OPTION;
+		JDialog dialog = createDialog(parent);
+		dialog.addWindowListener(new WindowAdapter() {
+			public void windowClosing(WindowEvent e) {
+				dialogResultValue = CANCEL_OPTION;
+			}
+		});
+
+		dialog.setVisible(true);
+		dialog.dispose();
+		dialog = null;
+
+		return dialogResultValue;
+	}
+
+	protected class ListSelectionHandler implements ListSelectionListener {
+		private JTextComponent textComponent;
+
+		ListSelectionHandler(JTextComponent textComponent) {
+			this.textComponent = textComponent;
+		}
+
+		public void valueChanged(ListSelectionEvent e) {
+			if (e.getValueIsAdjusting() == false) {
+				JList list = (JList) e.getSource();
+				String selectedValue = (String) list.getSelectedValue();
+
+				String oldValue = textComponent.getText();
+				textComponent.setText(selectedValue);
+				if (!oldValue.equalsIgnoreCase(selectedValue)) {
+					textComponent.selectAll();
+					textComponent.requestFocus();
+				}
+
+				updateSampleFont();
+			}
+		}
+	}
+
+	protected class TextFieldFocusHandlerForTextSelection extends FocusAdapter {
+		private JTextComponent textComponent;
+
+		public TextFieldFocusHandlerForTextSelection(JTextComponent textComponent) {
+			this.textComponent = textComponent;
+		}
+
+		public void focusGained(FocusEvent e) {
+			textComponent.selectAll();
+		}
+
+		public void focusLost(FocusEvent e) {
+			textComponent.select(0, 0);
+			updateSampleFont();
+		}
+	}
+
+	protected class TextFieldKeyHandlerForListSelectionUpDown extends KeyAdapter {
+		private JList targetList;
+
+		public TextFieldKeyHandlerForListSelectionUpDown(JList list) {
+			this.targetList = list;
+		}
+
+		public void keyPressed(KeyEvent e) {
+			int i = targetList.getSelectedIndex();
+			switch (e.getKeyCode()) {
+			case KeyEvent.VK_UP:
+				i = targetList.getSelectedIndex() - 1;
+				if (i < 0) {
+					i = 0;
+				}
+				targetList.setSelectedIndex(i);
+				break;
+			case KeyEvent.VK_DOWN:
+				int listSize = targetList.getModel().getSize();
+				i = targetList.getSelectedIndex() + 1;
+				if (i >= listSize) {
+					i = listSize - 1;
+				}
+				targetList.setSelectedIndex(i);
+				break;
+			default:
+				break;
+			}
+		}
+	}
+
+	protected class ListSearchTextFieldDocumentHandler implements DocumentListener {
+		JList targetList;
+
+		public ListSearchTextFieldDocumentHandler(JList targetList) {
+			this.targetList = targetList;
+		}
+
+		public void insertUpdate(DocumentEvent e) {
+			update(e);
+		}
+
+		public void removeUpdate(DocumentEvent e) {
+			update(e);
+		}
+
+		public void changedUpdate(DocumentEvent e) {
+			update(e);
+		}
+
+		private void update(DocumentEvent event) {
+			String newValue = "";
+			try {
+				Document doc = event.getDocument();
+				newValue = doc.getText(0, doc.getLength());
+			} catch (BadLocationException e) {
+				e.printStackTrace();
+			}
+
+			if (newValue.length() > 0) {
+				int index = targetList.getNextMatch(newValue, 0, Position.Bias.Forward);
+				if (index < 0) {
+					index = 0;
+				}
+				targetList.ensureIndexIsVisible(index);
+
+				String matchedName = targetList.getModel().getElementAt(index).toString();
+				if (newValue.equalsIgnoreCase(matchedName)) {
+					if (index != targetList.getSelectedIndex()) {
+						SwingUtilities.invokeLater(new ListSelector(index));
+					}
+				}
+			}
+		}
+
+		public class ListSelector implements Runnable {
+			private int index;
+
+			public ListSelector(int index) {
+				this.index = index;
+			}
+
+			public void run() {
+				targetList.setSelectedIndex(this.index);
+			}
+		}
+	}
+
+	protected class DialogOKAction extends AbstractAction {
+		protected static final String ACTION_NAME = "OK";
+		private JDialog dialog;
+
+		protected DialogOKAction(JDialog dialog) {
+			this.dialog = dialog;
+			putValue(Action.DEFAULT, ACTION_NAME);
+			putValue(Action.ACTION_COMMAND_KEY, ACTION_NAME);
+			putValue(Action.NAME, (ACTION_NAME));
+		}
+
+		public void actionPerformed(ActionEvent e) {
+			dialogResultValue = OK_OPTION;
+			dialog.setVisible(false);
+		}
+	}
+
+	protected class DialogCancelAction extends AbstractAction {
+		protected static final String ACTION_NAME = "Cancel";
+		private JDialog dialog;
+
+		protected DialogCancelAction(JDialog dialog) {
+			this.dialog = dialog;
+			putValue(Action.DEFAULT, ACTION_NAME);
+			putValue(Action.ACTION_COMMAND_KEY, ACTION_NAME);
+			putValue(Action.NAME, (ACTION_NAME));
+		}
+
+		public void actionPerformed(ActionEvent e) {
+			dialogResultValue = CANCEL_OPTION;
+			dialog.setVisible(false);
+		}
+	}
+
+	protected JDialog createDialog(Component parent) {
+		Frame frame = parent instanceof Frame ? (Frame) parent
+				: (Frame) SwingUtilities.getAncestorOfClass(Frame.class, parent);
+		JDialog dialog = new JDialog(frame, ("Select Font"), true);
+
+		Action okAction = new DialogOKAction(dialog);
+		Action cancelAction = new DialogCancelAction(dialog);
+
+		JButton okButton = new JButton(okAction);
+		okButton.setFont(DEFAULT_FONT);
+		JButton cancelButton = new JButton(cancelAction);
+		cancelButton.setFont(DEFAULT_FONT);
+
+		JPanel buttonsPanel = new JPanel();
+		buttonsPanel.setLayout(new GridLayout(2, 1));
+		buttonsPanel.add(okButton);
+		buttonsPanel.add(cancelButton);
+		buttonsPanel.setBorder(BorderFactory.createEmptyBorder(25, 0, 10, 10));
+
+		ActionMap actionMap = buttonsPanel.getActionMap();
+		actionMap.put(cancelAction.getValue(Action.DEFAULT), cancelAction);
+		actionMap.put(okAction.getValue(Action.DEFAULT), okAction);
+		InputMap inputMap = buttonsPanel.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
+		inputMap.put(KeyStroke.getKeyStroke("ESCAPE"), cancelAction.getValue(Action.DEFAULT));
+		inputMap.put(KeyStroke.getKeyStroke("ENTER"), okAction.getValue(Action.DEFAULT));
+
+		JPanel dialogEastPanel = new JPanel();
+		dialogEastPanel.setLayout(new BorderLayout());
+		dialogEastPanel.add(buttonsPanel, BorderLayout.NORTH);
+
+		dialog.getContentPane().add(this, BorderLayout.CENTER);
+		dialog.getContentPane().add(dialogEastPanel, BorderLayout.EAST);
+		dialog.pack();
+		dialog.setLocationRelativeTo(frame);
+		return dialog;
+	}
+
+	protected void updateSampleFont() {
+		Font font = getSelectedFont();
+		getSampleTextField().setFont(font);
+	}
+
+	protected JPanel getFontFamilyPanel() {
+		if (fontNamePanel == null) {
+			fontNamePanel = new JPanel();
+			fontNamePanel.setLayout(new BorderLayout());
+			fontNamePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+			fontNamePanel.setPreferredSize(new Dimension(180, 130));
+
+			JScrollPane scrollPane = new JScrollPane(getFontFamilyList());
+			scrollPane.getVerticalScrollBar().setFocusable(false);
+			scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+
+			JPanel p = new JPanel();
+			p.setLayout(new BorderLayout());
+			p.add(getFontFamilyTextField(), BorderLayout.NORTH);
+			p.add(scrollPane, BorderLayout.CENTER);
+
+			JLabel label = new JLabel(("Font Name"));
+			label.setHorizontalAlignment(JLabel.LEFT);
+			label.setHorizontalTextPosition(JLabel.LEFT);
+			label.setLabelFor(getFontFamilyTextField());
+			label.setDisplayedMnemonic('F');
+
+			fontNamePanel.add(label, BorderLayout.NORTH);
+			fontNamePanel.add(p, BorderLayout.CENTER);
+
+		}
+		return fontNamePanel;
+	}
+
+	protected JPanel getFontStylePanel() {
+		if (fontStylePanel == null) {
+			fontStylePanel = new JPanel();
+			fontStylePanel.setLayout(new BorderLayout());
+			fontStylePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+			fontStylePanel.setPreferredSize(new Dimension(140, 130));
+
+			JScrollPane scrollPane = new JScrollPane(getFontStyleList());
+			scrollPane.getVerticalScrollBar().setFocusable(false);
+			scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+
+			JPanel p = new JPanel();
+			p.setLayout(new BorderLayout());
+			p.add(getFontStyleTextField(), BorderLayout.NORTH);
+			p.add(scrollPane, BorderLayout.CENTER);
+
+			JLabel label = new JLabel(("Font Style"));
+			label.setHorizontalAlignment(JLabel.LEFT);
+			label.setHorizontalTextPosition(JLabel.LEFT);
+			label.setLabelFor(getFontStyleTextField());
+			label.setDisplayedMnemonic('Y');
+
+			fontStylePanel.add(label, BorderLayout.NORTH);
+			fontStylePanel.add(p, BorderLayout.CENTER);
+		}
+		return fontStylePanel;
+	}
+
+	protected JPanel getFontSizePanel() {
+		if (fontSizePanel == null) {
+			fontSizePanel = new JPanel();
+			fontSizePanel.setLayout(new BorderLayout());
+			fontSizePanel.setPreferredSize(new Dimension(70, 130));
+			fontSizePanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+
+			JScrollPane scrollPane = new JScrollPane(getFontSizeList());
+			scrollPane.getVerticalScrollBar().setFocusable(false);
+			scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
+
+			JPanel p = new JPanel();
+			p.setLayout(new BorderLayout());
+			p.add(getFontSizeTextField(), BorderLayout.NORTH);
+			p.add(scrollPane, BorderLayout.CENTER);
+
+			JLabel label = new JLabel(("Font Size"));
+			label.setHorizontalAlignment(JLabel.LEFT);
+			label.setHorizontalTextPosition(JLabel.LEFT);
+			label.setLabelFor(getFontSizeTextField());
+			label.setDisplayedMnemonic('S');
+
+			fontSizePanel.add(label, BorderLayout.NORTH);
+			fontSizePanel.add(p, BorderLayout.CENTER);
+		}
+		return fontSizePanel;
+	}
+
+	protected JPanel getSamplePanel() {
+		if (samplePanel == null) {
+			Border titledBorder = BorderFactory.createTitledBorder(BorderFactory.createEtchedBorder(), ("Sample"));
+			Border empty = BorderFactory.createEmptyBorder(5, 10, 10, 10);
+			Border border = BorderFactory.createCompoundBorder(titledBorder, empty);
+
+			samplePanel = new JPanel();
+			samplePanel.setLayout(new BorderLayout());
+			samplePanel.setBorder(border);
+
+			samplePanel.add(getSampleTextField(), BorderLayout.CENTER);
+		}
+		return samplePanel;
+	}
+
+	protected JTextField getSampleTextField() {
+		if (sampleText == null) {
+			Border lowered = BorderFactory.createLoweredBevelBorder();
+
+			sampleText = new JTextField(("AaBbYyZz"));
+			sampleText.setBorder(lowered);
+			sampleText.setPreferredSize(new Dimension(300, 100));
+		}
+		return sampleText;
+	}
+
+	protected String[] getFontFamilies() {
+		if (fontFamilyNames == null) {
+			GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
+			fontFamilyNames = env.getAvailableFontFamilyNames();
+		}
+		return fontFamilyNames;
+	}
+
+	protected String[] getFontStyleNames() {
+		if (fontStyleNames == null) {
+			int i = 0;
+			fontStyleNames = new String[4];
+			fontStyleNames[i++] = ("Plain");
+			fontStyleNames[i++] = ("Bold");
+			fontStyleNames[i++] = ("Italic");
+			fontStyleNames[i++] = ("BoldItalic");
+		}
+		return fontStyleNames;
+	}
+}
\ No newline at end of file
diff --git a/src/us/deathmarine/luyten/OpenFile.java b/src/us/deathmarine/luyten/OpenFile.java
index 7ba8c75..f817d07 100644
--- a/src/us/deathmarine/luyten/OpenFile.java
+++ b/src/us/deathmarine/luyten/OpenFile.java
@@ -1,22 +1,34 @@
 package us.deathmarine.luyten;
 
 import java.awt.Cursor;
+import java.awt.Font;
 import java.awt.Panel;
+import java.awt.PopupMenu;
 import java.awt.Rectangle;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
 import java.awt.event.AdjustmentEvent;
 import java.awt.event.AdjustmentListener;
 import java.awt.event.InputEvent;
 import java.awt.event.MouseEvent;
 import java.awt.event.MouseMotionAdapter;
+import java.awt.event.MouseWheelEvent;
+import java.awt.event.MouseWheelListener;
 import java.io.StringWriter;
+import java.lang.reflect.Field;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeMap;
 import java.util.concurrent.ConcurrentHashMap;
+
+import javax.swing.JDialog;
 import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
 import javax.swing.JScrollBar;
+import javax.swing.JScrollPane;
 import javax.swing.ScrollPaneConstants;
 import javax.swing.SwingUtilities;
 import javax.swing.event.HyperlinkEvent;
@@ -26,6 +38,7 @@ import org.fife.ui.rsyntaxtextarea.RSyntaxTextArea;
 import org.fife.ui.rsyntaxtextarea.SyntaxConstants;
 import org.fife.ui.rsyntaxtextarea.Theme;
 import org.fife.ui.rtextarea.RTextScrollPane;
+
 import com.strobel.assembler.metadata.MetadataSystem;
 import com.strobel.assembler.metadata.TypeDefinition;
 import com.strobel.decompiler.DecompilationOptions;
@@ -67,7 +80,7 @@ public class OpenFile implements SyntaxConstants {
 	private DecompilationOptions decompilationOptions;
 	private TypeDefinition type;
 
-	public OpenFile(String name, String path, Theme theme, MainWindow mainWindow) {
+	public OpenFile(String name, String path, Theme theme, final MainWindow mainWindow) {
 		this.name = name;
 		this.path = path;
 		this.mainWindow = mainWindow;
@@ -128,8 +141,27 @@ public class OpenFile implements SyntaxConstants {
 		else
 			textArea.setSyntaxEditingStyle(SYNTAX_STYLE_PROPERTIES_FILE);
 		scrollPane = new RTextScrollPane(textArea, true);
+		
 		scrollPane.setIconRowHeaderEnabled(true);
 		textArea.setText("");
+		
+		//Edit RTextArea's PopupMenu
+		JPopupMenu pop = textArea.getPopupMenu();
+		pop.addSeparator();
+		JMenuItem item = new JMenuItem("Font");
+		item.addActionListener(new ActionListener() {
+			@Override
+			public void actionPerformed(ActionEvent e) {
+				JFontChooser fontChooser = new JFontChooser();
+				fontChooser.setSelectedFont(textArea.getFont());
+				int result = fontChooser.showDialog(mainWindow);
+				if (result == JFontChooser.OK_OPTION)
+					textArea.setFont(fontChooser.getSelectedFont()); 
+			}
+		});
+		pop.add(item);
+		textArea.setPopupMenu(pop);
+		
 		theme.apply(textArea);
 
 		scrollPane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
@@ -178,7 +210,24 @@ public class OpenFile implements SyntaxConstants {
 				return null;
 			}
 		});
-
+		
+		//Add Ctrl+Wheel Zoom for Text Size
+		scrollPane.addMouseWheelListener(new MouseWheelListener(){
+			@Override
+			public void mouseWheelMoved(MouseWheelEvent e) {
+				if ((e.getModifiersEx() & InputEvent.CTRL_DOWN_MASK) != 0){
+					Font font = textArea.getFont();
+					int size = font.getSize();
+					if(e.getWheelRotation() > 0){ //Down
+						textArea.setFont(new Font(font.getName(), font.getStyle(), ++size));
+					}else{
+						textArea.setFont(new Font(font.getName(), font.getStyle(), --size >= 2 ? --size : 2));					
+					}
+				}
+				e.consume();
+			}
+		});
+		
 		textArea.addMouseMotionListener(new MouseMotionAdapter() {
 			private boolean isLinkLabelPrev = false;
 			private String prevLinkText = null;