mirror of
https://github.com/arduino/Arduino.git
synced 2025-02-20 14:54:31 +01:00
Merge branch 'keys' of https://github.com/matthijskooijman/Arduino into matthijskooijman-keys
This commit is contained in:
commit
2b4883f755
@ -38,6 +38,7 @@ import org.fife.ui.rtextarea.Gutter;
|
||||
import org.fife.ui.rtextarea.RTextScrollPane;
|
||||
import processing.app.debug.RunnerException;
|
||||
import processing.app.forms.PasswordAuthorizationDialog;
|
||||
import processing.app.helpers.Keys;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.helpers.PreferencesMapException;
|
||||
import processing.app.legacy.PApplet;
|
||||
@ -312,6 +313,12 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
// to fix ugliness.. normally macosx java 1.3 puts an
|
||||
// ugly white border around this object, so turn it off.
|
||||
splitPane.setBorder(null);
|
||||
// By default, the split pane binds Ctrl-Tab and Ctrl-Shift-Tab for changing
|
||||
// focus. Since we do not use that, but want to use these shortcuts for
|
||||
// switching tabs, remove the bindings from the split pane. This allows the
|
||||
// events to bubble up and be handled by the EditorHeader.
|
||||
Keys.killBinding(splitPane, Keys.ctrl(KeyEvent.VK_TAB));
|
||||
Keys.killBinding(splitPane, Keys.ctrlShift(KeyEvent.VK_TAB));
|
||||
|
||||
// the default size on windows is too small and kinda ugly
|
||||
int dividerSize = PreferencesData.getInteger("editor.divider.size");
|
||||
@ -1033,7 +1040,6 @@ public class Editor extends JFrame implements RunnerListener {
|
||||
textArea.setAntiAliasingEnabled(PreferencesData.getBoolean("editor.antialias"));
|
||||
textArea.setTabsEmulated(PreferencesData.getBoolean("editor.tabs.expand"));
|
||||
textArea.setTabSize(PreferencesData.getInteger("editor.tabs.size"));
|
||||
textArea.setEditorListener(new EditorListener(this));
|
||||
textArea.addHyperlinkListener(new HyperlinkListener() {
|
||||
@Override
|
||||
public void hyperlinkUpdate(HyperlinkEvent hyperlinkEvent) {
|
||||
|
@ -63,6 +63,7 @@ public class EditorConsole extends JScrollPane {
|
||||
consoleTextPane.setEditable(false);
|
||||
DefaultCaret caret = (DefaultCaret) consoleTextPane.getCaret();
|
||||
caret.setUpdatePolicy(DefaultCaret.NEVER_UPDATE);
|
||||
consoleTextPane.setFocusTraversalKeysEnabled(false);
|
||||
|
||||
Color backgroundColour = Theme.getColor("console.color");
|
||||
consoleTextPane.setBackground(backgroundColour);
|
||||
|
@ -22,7 +22,10 @@
|
||||
*/
|
||||
|
||||
package processing.app;
|
||||
|
||||
import processing.app.helpers.Keys;
|
||||
import processing.app.helpers.OSUtils;
|
||||
import processing.app.helpers.SimpleAction;
|
||||
import processing.app.tools.MenuScroller;
|
||||
import static processing.app.I18n.tr;
|
||||
|
||||
@ -72,12 +75,69 @@ public class EditorHeader extends JComponent {
|
||||
|
||||
static Image[][] pieces;
|
||||
|
||||
//
|
||||
|
||||
Image offscreen;
|
||||
int sizeW, sizeH;
|
||||
int imageW, imageH;
|
||||
|
||||
public class Actions {
|
||||
public final Action newTab = new SimpleAction(tr("New Tab"),
|
||||
Keys.ctrlShift(KeyEvent.VK_N),
|
||||
() -> editor.getSketch().handleNewCode());
|
||||
|
||||
public final Action renameTab = new SimpleAction(tr("Rename"),
|
||||
() -> editor.getSketch().handleRenameCode());
|
||||
|
||||
public final Action deleteTab = new SimpleAction(tr("Delete"), () -> {
|
||||
try {
|
||||
editor.getSketch().handleDeleteCode();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
});
|
||||
|
||||
public final Action prevTab = new SimpleAction(tr("Previous Tab"),
|
||||
Keys.ctrlAlt(KeyEvent.VK_LEFT),
|
||||
() -> editor.sketch.handlePrevCode());
|
||||
|
||||
public final Action nextTab = new SimpleAction(tr("Next Tab"),
|
||||
Keys.ctrlAlt(KeyEvent.VK_RIGHT),
|
||||
() -> editor.sketch.handleNextCode());
|
||||
|
||||
Actions() {
|
||||
// Explicitly bind keybindings for the actions with accelerators above
|
||||
// Normally, this happens automatically for any actions bound to menu
|
||||
// items, but only for menus attached to a window, not for popup menus.
|
||||
Keys.bind(EditorHeader.this, newTab);
|
||||
Keys.bind(EditorHeader.this, prevTab);
|
||||
Keys.bind(EditorHeader.this, nextTab);
|
||||
|
||||
// Add alternative keybindings to switch tabs
|
||||
Keys.bind(EditorHeader.this, prevTab, Keys.ctrlShift(KeyEvent.VK_TAB));
|
||||
Keys.bind(EditorHeader.this, nextTab, Keys.ctrl(KeyEvent.VK_TAB));
|
||||
}
|
||||
}
|
||||
public Actions actions = new Actions();
|
||||
|
||||
/**
|
||||
* Called whenever we, or any of our ancestors, is added to a container.
|
||||
*/
|
||||
public void addNotify() {
|
||||
super.addNotify();
|
||||
/*
|
||||
* Once we get added to a window, remove Ctrl-Tab and Ctrl-Shift-Tab from
|
||||
* the keys used for focus traversal (so our bindings for these keys will
|
||||
* work). All components inherit from the window eventually, so this should
|
||||
* work whenever the focus is inside our window. Some components (notably
|
||||
* JTextPane / JEditorPane) keep their own focus traversal keys, though, and
|
||||
* have to be treated individually (either the same as below, or by
|
||||
* disabling focus traversal entirely).
|
||||
*/
|
||||
Window window = SwingUtilities.getWindowAncestor(this);
|
||||
if (window != null) {
|
||||
Keys.killFocusTraversalBinding(window, Keys.ctrl(KeyEvent.VK_TAB));
|
||||
Keys.killFocusTraversalBinding(window, Keys.ctrlShift(KeyEvent.VK_TAB));
|
||||
}
|
||||
}
|
||||
|
||||
public EditorHeader(Editor eddie) {
|
||||
this.editor = eddie; // weird name for listener
|
||||
@ -236,7 +296,6 @@ public class EditorHeader extends JComponent {
|
||||
|
||||
|
||||
public void rebuildMenu() {
|
||||
//System.out.println("rebuilding");
|
||||
if (menu != null) {
|
||||
menu.removeAll();
|
||||
|
||||
@ -244,143 +303,34 @@ public class EditorHeader extends JComponent {
|
||||
menu = new JMenu();
|
||||
MenuScroller.setScrollerFor(menu);
|
||||
popup = menu.getPopupMenu();
|
||||
add(popup);
|
||||
popup.setLightWeightPopupEnabled(true);
|
||||
|
||||
/*
|
||||
popup.addPopupMenuListener(new PopupMenuListener() {
|
||||
public void popupMenuCanceled(PopupMenuEvent e) {
|
||||
// on redraw, the isVisible() will get checked.
|
||||
// actually, a repaint may be fired anyway, so this
|
||||
// may be redundant.
|
||||
repaint();
|
||||
}
|
||||
|
||||
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) { }
|
||||
public void popupMenuWillBecomeVisible(PopupMenuEvent e) { }
|
||||
});
|
||||
*/
|
||||
}
|
||||
JMenuItem item;
|
||||
|
||||
// maybe this shouldn't have a command key anyways..
|
||||
// since we're not trying to make this a full ide..
|
||||
//item = Editor.newJMenuItem("New", 'T');
|
||||
|
||||
/*
|
||||
item = Editor.newJMenuItem("Previous", KeyEvent.VK_PAGE_UP);
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.out.println("prev");
|
||||
}
|
||||
});
|
||||
if (editor.sketch != null) {
|
||||
item.setEnabled(editor.sketch.codeCount > 1);
|
||||
}
|
||||
menu.add(item);
|
||||
|
||||
item = Editor.newJMenuItem("Next", KeyEvent.VK_PAGE_DOWN);
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.out.println("ext");
|
||||
}
|
||||
});
|
||||
if (editor.sketch != null) {
|
||||
item.setEnabled(editor.sketch.codeCount > 1);
|
||||
}
|
||||
menu.add(item);
|
||||
|
||||
menu.add(new JMenuItem(actions.newTab));
|
||||
menu.add(new JMenuItem(actions.renameTab));
|
||||
menu.add(new JMenuItem(actions.deleteTab));
|
||||
menu.addSeparator();
|
||||
*/
|
||||
|
||||
//item = new JMenuItem("New Tab");
|
||||
item = Editor.newJMenuItemShift(tr("New Tab"), 'N');
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.getSketch().handleNewCode();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
item = new JMenuItem(tr("Rename"));
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.getSketch().handleRenameCode();
|
||||
/*
|
||||
// this is already being called by nameCode(), the second stage of rename
|
||||
if (editor.sketch.current == editor.sketch.code[0]) {
|
||||
editor.sketchbook.rebuildMenus();
|
||||
}
|
||||
*/
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
item = new JMenuItem(tr("Delete"));
|
||||
item.addActionListener(new ActionListener() {
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
try {
|
||||
editor.getSketch().handleDeleteCode();
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
menu.addSeparator();
|
||||
|
||||
// KeyEvent.VK_LEFT and VK_RIGHT will make Windows beep
|
||||
|
||||
item = new JMenuItem(tr("Previous Tab"));
|
||||
KeyStroke ctrlAltLeft = KeyStroke
|
||||
.getKeyStroke(KeyEvent.VK_LEFT, Editor.SHORTCUT_ALT_KEY_MASK);
|
||||
item.setAccelerator(ctrlAltLeft);
|
||||
item.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.handlePrevCode();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
|
||||
item = new JMenuItem(tr("Next Tab"));
|
||||
KeyStroke ctrlAltRight = KeyStroke
|
||||
.getKeyStroke(KeyEvent.VK_RIGHT, Editor.SHORTCUT_ALT_KEY_MASK);
|
||||
item.setAccelerator(ctrlAltRight);
|
||||
item.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.sketch.handleNextCode();
|
||||
}
|
||||
});
|
||||
menu.add(item);
|
||||
menu.add(new JMenuItem(actions.prevTab));
|
||||
menu.add(new JMenuItem(actions.nextTab));
|
||||
|
||||
Sketch sketch = editor.getSketch();
|
||||
if (sketch != null) {
|
||||
menu.addSeparator();
|
||||
|
||||
ActionListener jumpListener = new ActionListener() {
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
editor.getSketch().setCurrentCode(e.getActionCommand());
|
||||
}
|
||||
};
|
||||
int i = 0;
|
||||
for (SketchCode code : sketch.getCodes()) {
|
||||
final int index = i++;
|
||||
item = new JMenuItem(code.isExtension(sketch.getDefaultExtension()) ?
|
||||
code.getPrettyName() : code.getFileName());
|
||||
item.setActionCommand(code.getFileName());
|
||||
item.addActionListener(jumpListener);
|
||||
item.addActionListener((ActionEvent e) -> {
|
||||
editor.getSketch().setCurrentCode(index);
|
||||
});
|
||||
menu.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void deselectMenu() {
|
||||
repaint();
|
||||
}
|
||||
|
||||
|
||||
public Dimension getPreferredSize() {
|
||||
return getMinimumSize();
|
||||
}
|
||||
|
@ -1,79 +0,0 @@
|
||||
package processing.app;
|
||||
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.KeyListener;
|
||||
|
||||
import processing.app.syntax.SketchTextArea;
|
||||
|
||||
public class EditorListener implements KeyListener {
|
||||
|
||||
private Editor editor;
|
||||
|
||||
public EditorListener(Editor editor) {
|
||||
super();
|
||||
this.editor = editor;
|
||||
}
|
||||
|
||||
/** ctrl-alt on windows and linux, cmd-alt on mac os x */
|
||||
private static final int CTRL = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
|
||||
private static final int CTRL_ALT = InputEvent.ALT_MASK | CTRL;
|
||||
private static final int CTRL_SHIFT = InputEvent.SHIFT_MASK | CTRL;
|
||||
|
||||
public void keyTyped(KeyEvent event) {
|
||||
char c = event.getKeyChar();
|
||||
|
||||
if ((event.getModifiers() & KeyEvent.CTRL_MASK) != 0) {
|
||||
// The char is not control code when CTRL key pressed? It should be a shortcut.
|
||||
if (!Character.isISOControl(c)) {
|
||||
event.consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyPressed(KeyEvent event) {
|
||||
|
||||
SketchTextArea textarea = editor.getTextArea();
|
||||
|
||||
if (!textarea.isEditable()) return;
|
||||
|
||||
Sketch sketch = editor.getSketch();
|
||||
|
||||
int code = event.getKeyCode();
|
||||
|
||||
// Navigation..
|
||||
if ((event.getModifiers() & CTRL) == CTRL && code == KeyEvent.VK_TAB) {
|
||||
sketch.handleNextCode();
|
||||
}
|
||||
|
||||
// Navigation..
|
||||
// FIXME: not working on LINUX !!!
|
||||
if ((event.getModifiers() & CTRL_SHIFT) == CTRL_SHIFT && code == KeyEvent.VK_TAB) {
|
||||
sketch.handlePrevCode();
|
||||
}
|
||||
|
||||
// Navigation..
|
||||
if ((event.getModifiers() & CTRL_ALT) == CTRL_ALT) {
|
||||
if (code == KeyEvent.VK_LEFT) {
|
||||
sketch.handlePrevCode();
|
||||
} else if (code == KeyEvent.VK_RIGHT) {
|
||||
sketch.handleNextCode();
|
||||
}
|
||||
}
|
||||
|
||||
// if (event.isAltDown() && code == KeyEvent.VK_T) {
|
||||
// int line = textarea.getCaretLineNumber();
|
||||
// textarea.setActiveLineRange(line, line + 3);
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void keyReleased(KeyEvent e) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
}
|
233
app/src/processing/app/helpers/Keys.java
Normal file
233
app/src/processing/app/helpers/Keys.java
Normal file
@ -0,0 +1,233 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Copyright 2015 Matthijs Kooijman <matthijs@stdin.nl>
|
||||
*
|
||||
* Arduino is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*/
|
||||
|
||||
package processing.app.helpers;
|
||||
|
||||
import java.awt.AWTKeyStroke;
|
||||
import java.awt.Component;
|
||||
import java.awt.KeyboardFocusManager;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.InputEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.swing.Action;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
/**
|
||||
* This class contains some keybinding-related helper methods.
|
||||
*/
|
||||
public class Keys {
|
||||
|
||||
/**
|
||||
* Register a keybinding in the given components WHEN_IN_FOCUSED_WINDOW input
|
||||
* map, runing the given action when the action's accelerator key is pressed.
|
||||
*
|
||||
* Note that this is typically automatically handled when the action is
|
||||
* assigned to a JMenuItem, but it can still be needed for other actions, or
|
||||
* actions mapped to JMenuItems in a popup menu that is not added to any
|
||||
* window normally (and thus does not fire when the popup is closed).
|
||||
*
|
||||
* When the action is disabled, the keybinding is unregistered, and when it is
|
||||
* enabled, it is registered again.
|
||||
*/
|
||||
public static void bind(final JComponent component, final Action action) {
|
||||
bind(component, action,
|
||||
(KeyStroke) action.getValue(Action.ACCELERATOR_KEY));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a keybinding, running the given action when the given keystroke is
|
||||
* pressed when the given component is in the focused window.
|
||||
*
|
||||
* This is typically used to bind an additional keystroke to a menu item, in
|
||||
* addition to the primary accelerator key.
|
||||
*
|
||||
* When the action is disabled, the keybinding is unregistered, and when it is
|
||||
* enabled, it is registered again.
|
||||
*/
|
||||
public static void bind(final JComponent component, final Action action,
|
||||
KeyStroke keystroke) {
|
||||
bind(component, action, keystroke, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a keybinding to be handled in given condition, running the given
|
||||
* action when the given keystroke is pressed.
|
||||
*
|
||||
* When the action is disabled, the keybinding is unregistered, and when it is
|
||||
* enabled, it is registered again.
|
||||
*
|
||||
* @param component
|
||||
* The component to register the keybinding on.
|
||||
* @param action
|
||||
* The action to run when the keystroke is pressed
|
||||
* @param action
|
||||
* The keystroke to bind
|
||||
* @param condition
|
||||
* The condition under which to run the keystroke. Should be one of
|
||||
* JComponent.WHEN_FOCUSED,
|
||||
* JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT or
|
||||
* JComponent.WHEN_IN_FOCUSED_WINDOW.
|
||||
*/
|
||||
public static void bind(final JComponent component, final Action action,
|
||||
KeyStroke keystroke, int condition) {
|
||||
// The input map maps keystrokes to arbitrary objects (originally strings
|
||||
// that described the option, we just use the Action object itself).
|
||||
if (action.isEnabled())
|
||||
enableBind(component, action, keystroke, condition);
|
||||
|
||||
// The action map maps the arbitrary option to an Action to execute. These
|
||||
// be kept in the component even when the action is disabled.
|
||||
component.getActionMap().put(action, action);
|
||||
|
||||
// Enable and disable the binding when the action is enabled / disabled.
|
||||
action.addPropertyChangeListener((PropertyChangeEvent e) -> {
|
||||
if (e.getPropertyName().equals("enabled")) {
|
||||
if (e.getNewValue().equals(Boolean.TRUE))
|
||||
enableBind(component, action, keystroke, condition);
|
||||
else
|
||||
disableBind(component, action, keystroke, condition);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill an existing binding from the given condition. If the binding is
|
||||
* defined on the given component, it is removed, but if it is defined through
|
||||
* a parent inputmap (typically shared by multiple components, so best not
|
||||
* touched), this adds a dummy binding for this component, that will never
|
||||
* match an action in the component's action map, effectively disabling the
|
||||
* binding.
|
||||
*
|
||||
* This method is not intended to unbind a binding created by bind(), since
|
||||
* such a binding would get re-enabled when the action is re-enabled.
|
||||
*/
|
||||
public static void killBinding(final JComponent component,
|
||||
final KeyStroke keystroke, int condition) {
|
||||
InputMap map = component.getInputMap(condition);
|
||||
// First, try removing it
|
||||
map.remove(keystroke);
|
||||
// If the binding is defined in a parent map, defining it will not work, so
|
||||
// instead add an override that will never appear in the action map.
|
||||
if (map.get(keystroke) != null)
|
||||
map.put(keystroke, new Object());
|
||||
}
|
||||
|
||||
/**
|
||||
* Kill an existing binding like above, but from all three conditions
|
||||
* (WHEN_FOCUSED, WHEN_ANCESTOR_OF_FOCUSED_COMPONENT, WHEN_IN_FOCUSED_WINDOW).
|
||||
*/
|
||||
public static void killBinding(final JComponent component,
|
||||
final KeyStroke key) {
|
||||
killBinding(component, key, JComponent.WHEN_FOCUSED);
|
||||
killBinding(component, key, JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
killBinding(component, key, JComponent.WHEN_IN_FOCUSED_WINDOW);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a keystroke from the keys used to shift focus in or below the given
|
||||
* component. This modifies all sets of focus traversal keys on the given
|
||||
* component to remove the given keystroke. These sets are inherited down the
|
||||
* component hierarchy (until a component that has a custom set itself).
|
||||
*/
|
||||
public static void killFocusTraversalBinding(final Component component,
|
||||
final KeyStroke keystroke) {
|
||||
int[] sets = { KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,
|
||||
KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,
|
||||
KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS,
|
||||
KeyboardFocusManager.DOWN_CYCLE_TRAVERSAL_KEYS };
|
||||
for (int set : sets) {
|
||||
Set<AWTKeyStroke> keys = component.getFocusTraversalKeys(set);
|
||||
// keys is immutable, so create a new set to allow changes
|
||||
keys = new HashSet<>(keys);
|
||||
if (set == 0)
|
||||
keys.add(ctrlAlt('Z'));
|
||||
|
||||
// If the given keystroke was present in the set, replace it with the
|
||||
// updated set with the keystroke removed.
|
||||
if (keys.remove(keystroke))
|
||||
component.setFocusTraversalKeys(set, keys);
|
||||
}
|
||||
}
|
||||
|
||||
private static void enableBind(final JComponent component,
|
||||
final Action action, final KeyStroke keystroke,
|
||||
int condition) {
|
||||
component.getInputMap(condition).put(keystroke, action);
|
||||
}
|
||||
|
||||
private static void disableBind(final JComponent component,
|
||||
final Action action,
|
||||
final KeyStroke keystroke, int condition) {
|
||||
component.getInputMap(condition).put(keystroke, action);
|
||||
}
|
||||
|
||||
private static final int CTRL = Toolkit.getDefaultToolkit()
|
||||
.getMenuShortcutKeyMask();
|
||||
|
||||
/**
|
||||
* Creates a KeyCode for the "menu shortcut" + the key passed in. By default,
|
||||
* the menu shortcut is the ctrl key (hence the method name), but platforms
|
||||
* might use a different key (like the Apple key on OSX).
|
||||
*
|
||||
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
|
||||
* but this does not work for all characters, so is not recommended).
|
||||
*/
|
||||
public static KeyStroke ctrl(int keyCode) {
|
||||
return KeyStroke.getKeyStroke(keyCode, CTRL);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KeyCode for the "menu shortcut" + shift + the key passed in. By
|
||||
* default, the menu shortcut is the ctrl key (hence the method name), but
|
||||
* platforms might use a different key (like the Apple key on OSX).
|
||||
*
|
||||
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
|
||||
* but this does not work for all characters, so is not recommended).
|
||||
*/
|
||||
public static KeyStroke ctrlShift(int keyCode) {
|
||||
return KeyStroke.getKeyStroke(keyCode, CTRL | InputEvent.SHIFT_MASK);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a KeyCode for the "menu shortcut" + shift + the key passed in. By
|
||||
* default, the menu shortcut is the ctrl key (hence the method name), but
|
||||
* platforms might use a different key (like the Apple key on OSX).
|
||||
*
|
||||
* keyCode should be a KeyEvent.VK_* constant (it can also be a char constant,
|
||||
* but this does not work for all characters, so is not recommended).
|
||||
*/
|
||||
public static KeyStroke ctrlAlt(int keyCode) {
|
||||
return KeyStroke.getKeyStroke(keyCode, CTRL | InputEvent.ALT_MASK);
|
||||
}
|
||||
}
|
112
app/src/processing/app/helpers/SimpleAction.java
Normal file
112
app/src/processing/app/helpers/SimpleAction.java
Normal file
@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of Arduino.
|
||||
*
|
||||
* Copyright 2015 Matthijs Kooijman <matthijs@stdin.nl>
|
||||
*
|
||||
* Arduino is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program 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 program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*
|
||||
* As a special exception, you may use this file as part of a free software
|
||||
* library without restriction. Specifically, if other files instantiate
|
||||
* templates or use macros or inline functions from this file, or you compile
|
||||
* this file and link it with other files to produce an executable, this
|
||||
* file does not by itself cause the resulting executable to be covered by
|
||||
* the GNU General Public License. This exception does not however
|
||||
* invalidate any other reasons why the executable file might be covered by
|
||||
* the GNU General Public License.
|
||||
*/
|
||||
|
||||
package processing.app.helpers;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.KeyStroke;
|
||||
|
||||
/**
|
||||
* Class to easily define instances of the Swing Action interface.
|
||||
*
|
||||
* When using AbstractAction, you have to create a subclass that implements the
|
||||
* actionPerformed() method, and sets attributes in the constructor, which gets
|
||||
* verbose quickly. This class implements actionPerformed for you, and forwards
|
||||
* it to the ActionListener passed to the constructor (intended to be a lambda
|
||||
* expression). Additional Action attributes can be set by passing constructor
|
||||
* arguments.
|
||||
*
|
||||
* The name of this class refers to the fact that it's simple to create an
|
||||
* action using this class, but perhaps a better name can be found for it.
|
||||
*
|
||||
* @see javax.swing.Action
|
||||
*/
|
||||
public class SimpleAction extends AbstractAction {
|
||||
private ActionListener listener;
|
||||
|
||||
/**
|
||||
* Version of ActionListener that does not take an ActionEvent as an argument
|
||||
* This can be used when you do not care about the event itself, just that it
|
||||
* happened, typically for passing a argumentless lambda or method reference
|
||||
* to the SimpleAction constructor.
|
||||
*/
|
||||
public interface AnonymousActionListener {
|
||||
public void actionPerformed();
|
||||
}
|
||||
|
||||
public SimpleAction(String name, ActionListener listener) {
|
||||
this(name, null, null, listener);
|
||||
}
|
||||
|
||||
public SimpleAction(String name, AnonymousActionListener listener) {
|
||||
this(name, null, null, listener);
|
||||
}
|
||||
|
||||
public SimpleAction(String name, KeyStroke accelerator,
|
||||
ActionListener listener) {
|
||||
this(name, null, accelerator, listener);
|
||||
}
|
||||
|
||||
public SimpleAction(String name, KeyStroke accelerator,
|
||||
AnonymousActionListener listener) {
|
||||
this(name, null, accelerator, listener);
|
||||
}
|
||||
|
||||
public SimpleAction(String name, String description,
|
||||
ActionListener listener) {
|
||||
this(name, description, null, listener);
|
||||
}
|
||||
|
||||
public SimpleAction(String name, String description,
|
||||
AnonymousActionListener listener) {
|
||||
this(name, description, null, listener);
|
||||
}
|
||||
|
||||
public SimpleAction(String name, String description, KeyStroke accelerator,
|
||||
AnonymousActionListener listener) {
|
||||
this(name, description, accelerator,
|
||||
(ActionEvent) -> listener.actionPerformed());
|
||||
}
|
||||
|
||||
public SimpleAction(String name, String description, KeyStroke accelerator,
|
||||
ActionListener listener) {
|
||||
this.putValue(NAME, name);
|
||||
this.putValue(SHORT_DESCRIPTION, description);
|
||||
this.putValue(ACCELERATOR_KEY, accelerator);
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
listener.actionPerformed(e);
|
||||
}
|
||||
}
|
@ -38,10 +38,8 @@ import org.fife.ui.rtextarea.RTextAreaUI;
|
||||
import org.fife.ui.rtextarea.RUndoManager;
|
||||
import processing.app.Base;
|
||||
import processing.app.BaseNoGui;
|
||||
import processing.app.EditorListener;
|
||||
import processing.app.PreferencesData;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.event.EventListenerList;
|
||||
import javax.swing.event.HyperlinkEvent;
|
||||
import javax.swing.event.HyperlinkListener;
|
||||
@ -50,16 +48,13 @@ import javax.swing.text.Document;
|
||||
import javax.swing.text.Segment;
|
||||
import javax.swing.undo.UndoManager;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
@ -72,8 +67,6 @@ public class SketchTextArea extends RSyntaxTextArea {
|
||||
|
||||
private final static Logger LOG = Logger.getLogger(SketchTextArea.class.getName());
|
||||
|
||||
private EditorListener editorListener;
|
||||
|
||||
private PdeKeywords pdeKeywords;
|
||||
|
||||
public SketchTextArea(PdeKeywords pdeKeywords) throws IOException {
|
||||
@ -91,8 +84,6 @@ public class SketchTextArea extends RSyntaxTextArea {
|
||||
|
||||
setLinkGenerator(new DocLinkGenerator(pdeKeywords));
|
||||
|
||||
fixControlTab();
|
||||
|
||||
setSyntaxEditingStyle(SYNTAX_STYLE_CPLUSPLUS);
|
||||
}
|
||||
|
||||
@ -153,53 +144,10 @@ public class SketchTextArea extends RSyntaxTextArea {
|
||||
getSyntaxScheme().setStyle(tokenType, style);
|
||||
}
|
||||
|
||||
// Removing the default focus traversal keys
|
||||
// This is because the DefaultKeyboardFocusManager handles the keypress and consumes the event
|
||||
private void fixControlTab() {
|
||||
removeCTRLTabFromFocusTraversal();
|
||||
|
||||
removeCTRLSHIFTTabFromFocusTraversal();
|
||||
}
|
||||
|
||||
private void removeCTRLSHIFTTabFromFocusTraversal() {
|
||||
KeyStroke ctrlShiftTab = KeyStroke.getKeyStroke("ctrl shift TAB");
|
||||
Set<AWTKeyStroke> backwardKeys = new HashSet<>(this.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS));
|
||||
backwardKeys.remove(ctrlShiftTab);
|
||||
}
|
||||
|
||||
private void removeCTRLTabFromFocusTraversal() {
|
||||
KeyStroke ctrlTab = KeyStroke.getKeyStroke("ctrl TAB");
|
||||
Set<AWTKeyStroke> forwardKeys = new HashSet<>(this.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS));
|
||||
forwardKeys.remove(ctrlTab);
|
||||
this.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, forwardKeys);
|
||||
}
|
||||
|
||||
|
||||
public boolean isSelectionActive() {
|
||||
return this.getSelectedText() != null;
|
||||
}
|
||||
|
||||
public void processKeyEvent(KeyEvent evt) {
|
||||
|
||||
// this had to be added because the menu key events weren't making it up to the frame.
|
||||
|
||||
switch (evt.getID()) {
|
||||
case KeyEvent.KEY_TYPED:
|
||||
if (editorListener != null) editorListener.keyTyped(evt);
|
||||
break;
|
||||
case KeyEvent.KEY_PRESSED:
|
||||
if (editorListener != null) editorListener.keyPressed(evt);
|
||||
break;
|
||||
case KeyEvent.KEY_RELEASED:
|
||||
// inputHandler.keyReleased(evt);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!evt.isConsumed()) {
|
||||
super.processKeyEvent(evt);
|
||||
}
|
||||
}
|
||||
|
||||
public void switchDocument(Document document, UndoManager newUndo) {
|
||||
|
||||
// HACK: Dont discard changes on curret UndoManager.
|
||||
@ -233,11 +181,6 @@ public class SketchTextArea extends RSyntaxTextArea {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void setEditorListener(EditorListener editorListener) {
|
||||
this.editorListener = editorListener;
|
||||
}
|
||||
|
||||
private static class DocLinkGenerator implements LinkGenerator {
|
||||
|
||||
private final PdeKeywords pdeKeywords;
|
||||
|
@ -23,6 +23,15 @@ public class SketchTextAreaDefaultInputMap extends RSyntaxTextAreaDefaultInputMa
|
||||
|
||||
remove(KeyStroke.getKeyStroke(KeyEvent.VK_K, defaultModifier));
|
||||
|
||||
// Remove a troublesome binding for the / key. By default, RSyntaxTextArea
|
||||
// binds the / KEY_TYPED event to insert a / and optionally complete any XML
|
||||
// tags. However, since this also triggeres on ctrl-slash, this means that
|
||||
// in addition to toggling comments on ctrl-slash, it also inserts a slash.
|
||||
// Since we don't need the XML completion feature anyway, just unbind it
|
||||
// here. A future version of RSyntaxTextArea might fix this, see
|
||||
// https://github.com/bobbylight/RSyntaxTextArea/issues/157.
|
||||
remove(KeyStroke.getKeyStroke('/'));
|
||||
|
||||
if (PreferencesData.getBoolean("editor.advanced")) {
|
||||
put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, alt), RTextAreaEditorKit.rtaLineDownAction);
|
||||
put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, alt), RTextAreaEditorKit.rtaLineUpAction);
|
||||
|
Loading…
x
Reference in New Issue
Block a user