mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-10 22:17:13 -06:00
Merge PR #401: Text components: double/triple-click-and-drag selection improvements
This commit is contained in:
@@ -15,6 +15,8 @@ FlatLaf Change Log
|
||||
- TextField, FormattedTextField and PasswordField: Support leading and trailing
|
||||
icons (set client property `JTextField.leadingIcon` or
|
||||
`JTextField.trailingIcon` to an `Icon`). (PR #378; issue #368)
|
||||
- TextComponents: Double/triple-click-and-drag now extends selection by whole
|
||||
words/lines.
|
||||
- Theming improvements: Reworks core themes to make it easier to create new
|
||||
themes (e.g. reduced explicit colors by using color functions). **Note**:
|
||||
There are minor incompatible changes in FlatLaf properties files. (PR #390)
|
||||
|
||||
@@ -19,17 +19,26 @@ package com.formdev.flatlaf.ui;
|
||||
import static com.formdev.flatlaf.FlatClientProperties.*;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.JFormattedTextField;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.UIResource;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.DefaultCaret;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import javax.swing.text.Document;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.Utilities;
|
||||
|
||||
/**
|
||||
* Caret that can select all text on focus gained.
|
||||
* Also fixes Swing's double-click-and-drag behavior so that dragging after
|
||||
* a double-click extends selection by whole words.
|
||||
*
|
||||
* @author Karl Tauber
|
||||
*/
|
||||
@@ -37,12 +46,19 @@ public class FlatCaret
|
||||
extends DefaultCaret
|
||||
implements UIResource
|
||||
{
|
||||
private static final String KEY_CARET_INFO = "FlatLaf.internal.caretInfo";
|
||||
|
||||
private final String selectAllOnFocusPolicy;
|
||||
private final boolean selectAllOnMouseClick;
|
||||
|
||||
private boolean inInstall;
|
||||
private boolean wasFocused;
|
||||
private boolean wasTemporaryLost;
|
||||
private boolean isMousePressed;
|
||||
private boolean isWordSelection;
|
||||
private boolean isLineSelection;
|
||||
private int dragSelectionStart;
|
||||
private int dragSelectionEnd;
|
||||
|
||||
public FlatCaret( String selectAllOnFocusPolicy, boolean selectAllOnMouseClick ) {
|
||||
this.selectAllOnFocusPolicy = selectAllOnFocusPolicy;
|
||||
@@ -51,16 +67,60 @@ public class FlatCaret
|
||||
|
||||
@Override
|
||||
public void install( JTextComponent c ) {
|
||||
super.install( c );
|
||||
// get caret info if switched theme
|
||||
long[] ci = (long[]) c.getClientProperty( KEY_CARET_INFO );
|
||||
if( ci != null ) {
|
||||
c.putClientProperty( KEY_CARET_INFO, null );
|
||||
|
||||
// the dot and mark are lost when switching LaF
|
||||
// --> move dot to end of text so that all text may be selected when it gains focus
|
||||
Document doc = c.getDocument();
|
||||
if( doc != null && getDot() == 0 && getMark() == 0 ) {
|
||||
int length = doc.getLength();
|
||||
if( length > 0 )
|
||||
setDot( length );
|
||||
// if caret info is too old assume that switched from FlatLaf
|
||||
// to another Laf and back to FlatLaf
|
||||
if( System.currentTimeMillis() - 500 > ci[3] )
|
||||
ci = null;
|
||||
}
|
||||
if( ci != null ) {
|
||||
// when switching theme, it is necessary to set blink rate before
|
||||
// invoking super.install() otherwise the caret does not blink
|
||||
setBlinkRate( (int) ci[2] );
|
||||
}
|
||||
|
||||
inInstall = true;
|
||||
try {
|
||||
super.install( c );
|
||||
} finally {
|
||||
inInstall = false;
|
||||
}
|
||||
|
||||
if( ci != null ) {
|
||||
// restore selection
|
||||
select( (int) ci[1], (int) ci[0] );
|
||||
|
||||
// if text component is focused, then caret and selection are visible,
|
||||
// but when switching theme, the component does not yet have
|
||||
// an highlighter and the selection is not painted
|
||||
// --> make selection temporary invisible later, then the caret
|
||||
// adds selection highlights to the text component highlighter
|
||||
if( isSelectionVisible() ) {
|
||||
EventQueue.invokeLater( () -> {
|
||||
if( isSelectionVisible() ) {
|
||||
setSelectionVisible( false );
|
||||
setSelectionVisible( true );
|
||||
}
|
||||
} );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deinstall( JTextComponent c ) {
|
||||
// remember dot and mark (the selection) when switching theme
|
||||
c.putClientProperty( KEY_CARET_INFO, new long[] {
|
||||
getDot(),
|
||||
getMark(),
|
||||
getBlinkRate(),
|
||||
System.currentTimeMillis(),
|
||||
} );
|
||||
|
||||
super.deinstall( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -79,7 +139,7 @@ public class FlatCaret
|
||||
|
||||
@Override
|
||||
public void focusGained( FocusEvent e ) {
|
||||
if( !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
||||
if( !inInstall && !wasTemporaryLost && (!isMousePressed || selectAllOnMouseClick) )
|
||||
selectAllOnFocusGained();
|
||||
wasTemporaryLost = false;
|
||||
wasFocused = true;
|
||||
@@ -97,14 +157,72 @@ public class FlatCaret
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
isMousePressed = true;
|
||||
super.mousePressed( e );
|
||||
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// left double-click starts word selection
|
||||
isWordSelection = e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) && !e.isConsumed();
|
||||
|
||||
// left triple-click starts line selection
|
||||
isLineSelection = e.getClickCount() == 3 && SwingUtilities.isLeftMouseButton( e ) && (!e.isConsumed() || c.getDragEnabled());
|
||||
|
||||
// select line
|
||||
// (this is also done in DefaultCaret.mouseClicked(), but this event is
|
||||
// sent when the mouse is released, which is too late for triple-click-and-drag)
|
||||
if( isLineSelection ) {
|
||||
ActionMap actionMap = c.getActionMap();
|
||||
Action selectLineAction = (actionMap != null)
|
||||
? actionMap.get( DefaultEditorKit.selectLineAction )
|
||||
: null;
|
||||
if( selectLineAction != null ) {
|
||||
selectLineAction.actionPerformed( new ActionEvent( c,
|
||||
ActionEvent.ACTION_PERFORMED, null, e.getWhen(), e.getModifiers() ) );
|
||||
}
|
||||
}
|
||||
|
||||
// remember selection where word/line selection starts to keep it always selected while dragging
|
||||
if( isWordSelection || isLineSelection ) {
|
||||
int mark = getMark();
|
||||
int dot = getDot();
|
||||
dragSelectionStart = Math.min( dot, mark );
|
||||
dragSelectionEnd = Math.max( dot, mark );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
isMousePressed = false;
|
||||
isWordSelection = false;
|
||||
isLineSelection = false;
|
||||
super.mouseReleased( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( (isWordSelection || isLineSelection) &&
|
||||
!e.isConsumed() && SwingUtilities.isLeftMouseButton( e ) )
|
||||
{
|
||||
// fix Swing's double/triple-click-and-drag behavior so that dragging after
|
||||
// a double/triple-click extends selection by whole words/lines
|
||||
JTextComponent c = getComponent();
|
||||
int pos = c.viewToModel( e.getPoint() );
|
||||
if( pos < 0 )
|
||||
return;
|
||||
|
||||
try {
|
||||
if( pos > dragSelectionEnd )
|
||||
select( dragSelectionStart, isWordSelection ? Utilities.getWordEnd( c, pos ) : Utilities.getRowEnd( c, pos ) );
|
||||
else if( pos < dragSelectionStart )
|
||||
select( dragSelectionEnd, isWordSelection ? Utilities.getWordStart( c, pos ) : Utilities.getRowStart( c, pos ) );
|
||||
else
|
||||
select( dragSelectionStart, dragSelectionEnd );
|
||||
} catch( BadLocationException ex ) {
|
||||
UIManager.getLookAndFeel().provideErrorFeedback( c );
|
||||
}
|
||||
} else
|
||||
super.mouseDragged( e );
|
||||
}
|
||||
|
||||
protected void selectAllOnFocusGained() {
|
||||
JTextComponent c = getComponent();
|
||||
Document doc = c.getDocument();
|
||||
@@ -135,15 +253,20 @@ public class FlatCaret
|
||||
// select all
|
||||
if( c instanceof JFormattedTextField ) {
|
||||
EventQueue.invokeLater( () -> {
|
||||
setDot( 0 );
|
||||
moveDot( doc.getLength() );
|
||||
select( 0, doc.getLength() );
|
||||
} );
|
||||
} else {
|
||||
setDot( 0 );
|
||||
moveDot( doc.getLength() );
|
||||
select( 0, doc.getLength() );
|
||||
}
|
||||
}
|
||||
|
||||
private void select( int mark, int dot ) {
|
||||
if( mark != getMark() )
|
||||
setDot( mark );
|
||||
if( dot != getDot() )
|
||||
moveDot( dot );
|
||||
}
|
||||
|
||||
/** @since 1.4 */
|
||||
public void scrollCaretToVisible() {
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
@@ -30,6 +30,7 @@ import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicEditorPaneUI;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
@@ -147,6 +148,11 @@ public class FlatEditorPaneUI
|
||||
focusListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( null, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
// invoke updateBackground() before super.propertyChange()
|
||||
|
||||
@@ -29,6 +29,7 @@ import javax.swing.JTextArea;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTextAreaUI;
|
||||
import javax.swing.text.Caret;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
@@ -136,6 +137,11 @@ public class FlatTextAreaUI
|
||||
focusListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( null, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
// invoke updateBackground() before super.propertyChange()
|
||||
|
||||
@@ -29,6 +29,7 @@ import javax.swing.JEditorPane;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTextPaneUI;
|
||||
import javax.swing.text.Caret;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
@@ -144,6 +145,11 @@ public class FlatTextPaneUI
|
||||
focusListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
return new FlatCaret( null, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void propertyChange( PropertyChangeEvent e ) {
|
||||
// invoke updateBackground() before super.propertyChange()
|
||||
|
||||
@@ -386,6 +386,12 @@ public class FlatComponents2Test
|
||||
tree.putClientProperty( FlatClientProperties.TREE_PAINT_SELECTION, paintSelection );
|
||||
}
|
||||
|
||||
private void treeEditableChanged() {
|
||||
boolean editable = treeEditableCheckBox.isSelected();
|
||||
for( JTree tree : allTrees )
|
||||
tree.setEditable( editable );
|
||||
}
|
||||
|
||||
private void treeMouseClicked( MouseEvent e ) {
|
||||
JTree tree = (JTree) e.getSource();
|
||||
int x = e.getX();
|
||||
@@ -475,6 +481,7 @@ public class FlatComponents2Test
|
||||
treeRendererComboBox = new JComboBox<>();
|
||||
treeWideSelectionCheckBox = new JCheckBox();
|
||||
treePaintSelectionCheckBox = new JCheckBox();
|
||||
treeEditableCheckBox = new JCheckBox();
|
||||
JPanel tableOptionsPanel = new JPanel();
|
||||
JLabel autoResizeModeLabel = new JLabel();
|
||||
autoResizeModeField = new JComboBox<>();
|
||||
@@ -754,10 +761,11 @@ public class FlatComponents2Test
|
||||
treeOptionsPanel.setLayout(new MigLayout(
|
||||
"hidemode 3",
|
||||
// columns
|
||||
"[fill]",
|
||||
"[left]",
|
||||
// rows
|
||||
"[]" +
|
||||
"[]0" +
|
||||
"[]0" +
|
||||
"[]"));
|
||||
|
||||
//---- treeRendererLabel ----
|
||||
@@ -786,6 +794,11 @@ public class FlatComponents2Test
|
||||
treePaintSelectionCheckBox.setSelected(true);
|
||||
treePaintSelectionCheckBox.addActionListener(e -> treePaintSelectionChanged());
|
||||
treeOptionsPanel.add(treePaintSelectionCheckBox, "cell 0 2");
|
||||
|
||||
//---- treeEditableCheckBox ----
|
||||
treeEditableCheckBox.setText("editable");
|
||||
treeEditableCheckBox.addActionListener(e -> treeEditableChanged());
|
||||
treeOptionsPanel.add(treeEditableCheckBox, "cell 0 3");
|
||||
}
|
||||
add(treeOptionsPanel, "cell 2 4");
|
||||
|
||||
@@ -905,6 +918,7 @@ public class FlatComponents2Test
|
||||
private JComboBox<String> treeRendererComboBox;
|
||||
private JCheckBox treeWideSelectionCheckBox;
|
||||
private JCheckBox treePaintSelectionCheckBox;
|
||||
private JCheckBox treeEditableCheckBox;
|
||||
private JComboBox<String> autoResizeModeField;
|
||||
private JComboBox<String> sortIconPositionComboBox;
|
||||
private JCheckBox showHorizontalLinesCheckBox;
|
||||
|
||||
@@ -317,8 +317,8 @@ new FormModel {
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "hidemode 3"
|
||||
"$columnConstraints": "[fill]"
|
||||
"$rowConstraints": "[][]0[]"
|
||||
"$columnConstraints": "[left]"
|
||||
"$rowConstraints": "[][]0[]0[]"
|
||||
} ) {
|
||||
name: "treeOptionsPanel"
|
||||
"border": new javax.swing.border.TitledBorder( "JTree Control" )
|
||||
@@ -367,6 +367,16 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 2"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "treeEditableCheckBox"
|
||||
"text": "editable"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "treeEditableChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 3"
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 2 4"
|
||||
} )
|
||||
|
||||
@@ -81,6 +81,14 @@ public class FlatTextComponentsTest
|
||||
}
|
||||
}
|
||||
|
||||
private void dragEnabledChanged() {
|
||||
boolean dragEnabled = dragEnabledCheckBox.isSelected();
|
||||
textField.setDragEnabled( dragEnabled );
|
||||
textArea.setDragEnabled( dragEnabled );
|
||||
textPane.setDragEnabled( dragEnabled );
|
||||
editorPane.setDragEnabled( dragEnabled );
|
||||
}
|
||||
|
||||
private void initComponents() {
|
||||
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
|
||||
JLabel textFieldLabel = new JLabel();
|
||||
@@ -137,6 +145,16 @@ public class FlatTextComponentsTest
|
||||
JLabel label4 = new JLabel();
|
||||
JComboBox<String> comboBox6 = new JComboBox<>();
|
||||
JSpinner spinner5 = new JSpinner();
|
||||
JLabel label5 = new JLabel();
|
||||
textField = new JTextField();
|
||||
dragEnabledCheckBox = new JCheckBox();
|
||||
JLabel label6 = new JLabel();
|
||||
JScrollPane scrollPane2 = new JScrollPane();
|
||||
textArea = new JTextArea();
|
||||
JScrollPane scrollPane4 = new JScrollPane();
|
||||
textPane = new JTextPane();
|
||||
JScrollPane scrollPane6 = new JScrollPane();
|
||||
editorPane = new JEditorPane();
|
||||
JPopupMenu popupMenu1 = new JPopupMenu();
|
||||
JMenuItem cutMenuItem = new JMenuItem();
|
||||
JMenuItem copyMenuItem = new JMenuItem();
|
||||
@@ -168,7 +186,9 @@ public class FlatTextComponentsTest
|
||||
"[::14]" +
|
||||
"[::14]" +
|
||||
"[]" +
|
||||
"[]"));
|
||||
"[]para" +
|
||||
"[]" +
|
||||
"[90,fill]"));
|
||||
|
||||
//---- textFieldLabel ----
|
||||
textFieldLabel.setText("JTextField:");
|
||||
@@ -519,6 +539,60 @@ public class FlatTextComponentsTest
|
||||
spinner5.setName("spinner5");
|
||||
add(spinner5, "cell 1 15,growx,hmax 14");
|
||||
|
||||
//---- label5 ----
|
||||
label5.setText("Double-click-and-drag:");
|
||||
label5.setName("label5");
|
||||
add(label5, "cell 0 16");
|
||||
|
||||
//---- textField ----
|
||||
textField.setText("123 456 789 abc def");
|
||||
textField.setName("textField");
|
||||
add(textField, "cell 1 16 2 1,growx");
|
||||
|
||||
//---- dragEnabledCheckBox ----
|
||||
dragEnabledCheckBox.setText("Drag enabled");
|
||||
dragEnabledCheckBox.setName("dragEnabledCheckBox");
|
||||
dragEnabledCheckBox.addActionListener(e -> dragEnabledChanged());
|
||||
add(dragEnabledCheckBox, "cell 3 16 2 1,alignx left,growx 0");
|
||||
|
||||
//---- label6 ----
|
||||
label6.setText("<html>JTextArea<br>JTextPane<br>JEditorPane</html>");
|
||||
label6.setName("label6");
|
||||
add(label6, "cell 0 17,align right top,grow 0 0");
|
||||
|
||||
//======== scrollPane2 ========
|
||||
{
|
||||
scrollPane2.setName("scrollPane2");
|
||||
|
||||
//---- textArea ----
|
||||
textArea.setText("1 123 456 789 abc def\n2 123 456 789 abc def\n3 123 456 789 abc def\n4 123 456 789 abc def\n5 123 456 789 abc def\n6 123 456 789 abc def\n7 123 456 789 abc def\n8 123 456 789 abc def");
|
||||
textArea.setName("textArea");
|
||||
scrollPane2.setViewportView(textArea);
|
||||
}
|
||||
add(scrollPane2, "cell 1 17 4 1,growx");
|
||||
|
||||
//======== scrollPane4 ========
|
||||
{
|
||||
scrollPane4.setName("scrollPane4");
|
||||
|
||||
//---- textPane ----
|
||||
textPane.setText("1 123 456 789 abc def\n2 123 456 789 abc def\n3 123 456 789 abc def\n4 123 456 789 abc def\n5 123 456 789 abc def\n6 123 456 789 abc def\n7 123 456 789 abc def\n8 123 456 789 abc def");
|
||||
textPane.setName("textPane");
|
||||
scrollPane4.setViewportView(textPane);
|
||||
}
|
||||
add(scrollPane4, "cell 1 17 4 1,growx");
|
||||
|
||||
//======== scrollPane6 ========
|
||||
{
|
||||
scrollPane6.setName("scrollPane6");
|
||||
|
||||
//---- editorPane ----
|
||||
editorPane.setText("1 123 456 789 abc def\n2 123 456 789 abc def\n3 123 456 789 abc def\n4 123 456 789 abc def\n5 123 456 789 abc def\n6 123 456 789 abc def\n7 123 456 789 abc def\n8 123 456 789 abc def");
|
||||
editorPane.setName("editorPane");
|
||||
scrollPane6.setViewportView(editorPane);
|
||||
}
|
||||
add(scrollPane6, "cell 1 17 4 1,growx");
|
||||
|
||||
//======== popupMenu1 ========
|
||||
{
|
||||
popupMenu1.setName("popupMenu1");
|
||||
@@ -553,6 +627,11 @@ public class FlatTextComponentsTest
|
||||
private JSpinner bottomPaddingField;
|
||||
private JCheckBox leadingIconCheckBox;
|
||||
private JCheckBox trailingIconCheckBox;
|
||||
private JTextField textField;
|
||||
private JCheckBox dragEnabledCheckBox;
|
||||
private JTextArea textArea;
|
||||
private JTextPane textPane;
|
||||
private JEditorPane editorPane;
|
||||
// JFormDesigner - End of variables declaration //GEN-END:variables
|
||||
|
||||
//---- TestIcon -----------------------------------------------------------
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
JFDML JFormDesigner: "7.0.4.0.360" Java: "16" encoding: "UTF-8"
|
||||
JFDML JFormDesigner: "7.0.4.0.360" Java: "17" encoding: "UTF-8"
|
||||
|
||||
new FormModel {
|
||||
contentType: "form/swing"
|
||||
@@ -10,7 +10,7 @@ new FormModel {
|
||||
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
|
||||
"$layoutConstraints": "ltr,insets dialog,hidemode 3"
|
||||
"$columnConstraints": "[][][::100][100,fill][fill]"
|
||||
"$rowConstraints": "[][][][50,fill][50,fill][50,fill][][]para[40][40][][][::14][::14][][]"
|
||||
"$rowConstraints": "[][][][50,fill][50,fill][50,fill][][]para[40][40][][][::14][::14][][]para[][90,fill]"
|
||||
} ) {
|
||||
name: "this"
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
@@ -416,9 +416,76 @@ new FormModel {
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 15,growx,hmax 14"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label5"
|
||||
"text": "Double-click-and-drag:"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 16"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||
name: "textField"
|
||||
"text": "123 456 789 abc def"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 16 2 1,growx"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||
name: "dragEnabledCheckBox"
|
||||
"text": "Drag enabled"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "dragEnabledChanged", false ) )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 3 16 2 1,alignx left,growx 0"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JLabel" ) {
|
||||
name: "label6"
|
||||
"text": "<html>JTextArea<br>JTextPane<br>JEditorPane</html>"
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 0 17,align right top,grow 0 0"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane2"
|
||||
add( new FormComponent( "javax.swing.JTextArea" ) {
|
||||
name: "textArea"
|
||||
"text": "1 123 456 789 abc def\n2 123 456 789 abc def\n3 123 456 789 abc def\n4 123 456 789 abc def\n5 123 456 789 abc def\n6 123 456 789 abc def\n7 123 456 789 abc def\n8 123 456 789 abc def"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 17 4 1,growx"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane4"
|
||||
add( new FormComponent( "javax.swing.JTextPane" ) {
|
||||
name: "textPane"
|
||||
"text": "1 123 456 789 abc def\n2 123 456 789 abc def\n3 123 456 789 abc def\n4 123 456 789 abc def\n5 123 456 789 abc def\n6 123 456 789 abc def\n7 123 456 789 abc def\n8 123 456 789 abc def"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 17 4 1,growx"
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane6"
|
||||
add( new FormComponent( "javax.swing.JEditorPane" ) {
|
||||
name: "editorPane"
|
||||
"text": "1 123 456 789 abc def\n2 123 456 789 abc def\n3 123 456 789 abc def\n4 123 456 789 abc def\n5 123 456 789 abc def\n6 123 456 789 abc def\n7 123 456 789 abc def\n8 123 456 789 abc def"
|
||||
auxiliary() {
|
||||
"JavaCodeGenerator.variableLocal": false
|
||||
}
|
||||
} )
|
||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||
"value": "cell 1 17 4 1,growx"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 0 )
|
||||
"size": new java.awt.Dimension( 530, 660 )
|
||||
"size": new java.awt.Dimension( 640, 725 )
|
||||
} )
|
||||
add( new FormContainer( "javax.swing.JPopupMenu", new FormLayoutManager( class javax.swing.JPopupMenu ) ) {
|
||||
name: "popupMenu1"
|
||||
@@ -435,7 +502,7 @@ new FormModel {
|
||||
"text": "Paste"
|
||||
} )
|
||||
}, new FormLayoutConstraints( null ) {
|
||||
"location": new java.awt.Point( 0, 705 )
|
||||
"location": new java.awt.Point( 0, 745 )
|
||||
"size": new java.awt.Dimension( 91, 87 )
|
||||
} )
|
||||
}
|
||||
|
||||
@@ -18,9 +18,20 @@ package com.formdev.flatlaf.themeeditor;
|
||||
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.MouseEvent;
|
||||
import javax.swing.Action;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.text.BadLocationException;
|
||||
import javax.swing.text.Caret;
|
||||
import javax.swing.text.DefaultEditorKit;
|
||||
import javax.swing.text.JTextComponent;
|
||||
import javax.swing.text.Utilities;
|
||||
import org.fife.ui.rsyntaxtextarea.RSyntaxTextAreaUI;
|
||||
import org.fife.ui.rtextarea.ConfigurableCaret;
|
||||
|
||||
/**
|
||||
* @author Karl Tauber
|
||||
@@ -32,6 +43,13 @@ class FlatRSyntaxTextAreaUI
|
||||
super( rSyntaxTextArea );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Caret createCaret() {
|
||||
Caret caret = new FlatConfigurableCaret();
|
||||
caret.setBlinkRate( 500 );
|
||||
return caret;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void paintCurrentLineHighlight( Graphics g, Rectangle visibleRect ) {
|
||||
if( !textArea.getHighlightCurrentLine() )
|
||||
@@ -49,4 +67,90 @@ class FlatRSyntaxTextAreaUI
|
||||
super.paintCurrentLineHighlight( g, visibleRect );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class FlatConfigurableCaret ----------------------------------------
|
||||
|
||||
private static class FlatConfigurableCaret
|
||||
extends ConfigurableCaret
|
||||
{
|
||||
private boolean isWordSelection;
|
||||
private boolean isLineSelection;
|
||||
private int dragSelectionStart;
|
||||
private int dragSelectionEnd;
|
||||
|
||||
@Override
|
||||
public void mousePressed( MouseEvent e ) {
|
||||
super.mousePressed( e );
|
||||
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// left double-click starts word selection
|
||||
isWordSelection = e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) && !e.isConsumed();
|
||||
|
||||
// left triple-click starts line selection
|
||||
isLineSelection = e.getClickCount() == 3 && SwingUtilities.isLeftMouseButton( e ) && (!e.isConsumed() || c.getDragEnabled());
|
||||
|
||||
// select line
|
||||
// (this is also done in DefaultCaret.mouseClicked(), but this event is
|
||||
// sent when the mouse is released, which is too late for triple-click-and-drag)
|
||||
if( isLineSelection ) {
|
||||
ActionMap actionMap = c.getActionMap();
|
||||
Action selectLineAction = (actionMap != null)
|
||||
? actionMap.get( DefaultEditorKit.selectLineAction )
|
||||
: null;
|
||||
if( selectLineAction != null ) {
|
||||
selectLineAction.actionPerformed( new ActionEvent( c,
|
||||
ActionEvent.ACTION_PERFORMED, null, e.getWhen(), e.getModifiers() ) );
|
||||
}
|
||||
}
|
||||
|
||||
// remember selection where word/line selection starts to keep it always selected while dragging
|
||||
if( isWordSelection || isLineSelection ) {
|
||||
int mark = getMark();
|
||||
int dot = getDot();
|
||||
dragSelectionStart = Math.min( dot, mark );
|
||||
dragSelectionEnd = Math.max( dot, mark );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
isWordSelection = false;
|
||||
isLineSelection = false;
|
||||
super.mouseReleased( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( (isWordSelection || isLineSelection) &&
|
||||
!e.isConsumed() && SwingUtilities.isLeftMouseButton( e ) )
|
||||
{
|
||||
// fix Swing's double/triple-click-and-drag behavior so that dragging after
|
||||
// a double/triple-click extends selection by whole words/lines
|
||||
JTextComponent c = getComponent();
|
||||
int pos = c.viewToModel( e.getPoint() );
|
||||
if( pos < 0 )
|
||||
return;
|
||||
|
||||
try {
|
||||
if( pos > dragSelectionEnd )
|
||||
select( dragSelectionStart, isWordSelection ? Utilities.getWordEnd( c, pos ) : Utilities.getRowEnd( c, pos ) );
|
||||
else if( pos < dragSelectionStart )
|
||||
select( dragSelectionEnd, isWordSelection ? Utilities.getWordStart( c, pos ) : Utilities.getRowStart( c, pos ) );
|
||||
else
|
||||
select( dragSelectionStart, dragSelectionEnd );
|
||||
} catch( BadLocationException ex ) {
|
||||
UIManager.getLookAndFeel().provideErrorFeedback( c );
|
||||
}
|
||||
} else
|
||||
super.mouseDragged( e );
|
||||
}
|
||||
|
||||
private void select( int mark, int dot ) {
|
||||
if( mark != getMark() )
|
||||
setDot( mark );
|
||||
if( dot != getDot() )
|
||||
moveDot( dot );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user