mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
TextComponents: triple-click-and-drag now extends selection by whole lines
triple-click-and-drag does not work in theme editor because drag is enabled, anyway a triple-click now selects the whole line before dragging starts
This commit is contained in:
@@ -15,7 +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-click-and-drag now extends selection by whole words.
|
||||
- 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,14 +19,18 @@ 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;
|
||||
@@ -52,8 +56,9 @@ public class FlatCaret
|
||||
private boolean wasTemporaryLost;
|
||||
private boolean isMousePressed;
|
||||
private boolean isWordSelection;
|
||||
private int beginInitialWord;
|
||||
private int endInitialWord;
|
||||
private boolean isLineSelection;
|
||||
private int dragSelectionStart;
|
||||
private int dragSelectionEnd;
|
||||
|
||||
public FlatCaret( String selectAllOnFocusPolicy, boolean selectAllOnMouseClick ) {
|
||||
this.selectAllOnFocusPolicy = selectAllOnFocusPolicy;
|
||||
@@ -153,11 +158,34 @@ public class FlatCaret
|
||||
isMousePressed = true;
|
||||
super.mousePressed( e );
|
||||
|
||||
JTextComponent c = getComponent();
|
||||
|
||||
// left double-click starts word selection
|
||||
isWordSelection = e.getClickCount() == 2 && SwingUtilities.isLeftMouseButton( e ) && !e.isConsumed();
|
||||
if( isWordSelection ) {
|
||||
beginInitialWord = getMark();
|
||||
endInitialWord = getDot();
|
||||
|
||||
// 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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -165,33 +193,29 @@ public class FlatCaret
|
||||
public void mouseReleased( MouseEvent e ) {
|
||||
isMousePressed = false;
|
||||
isWordSelection = false;
|
||||
isLineSelection = false;
|
||||
super.mouseReleased( e );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseDragged( MouseEvent e ) {
|
||||
if( isWordSelection && !e.isConsumed() && SwingUtilities.isLeftMouseButton( e ) ) {
|
||||
// fix Swing's double-click-and-drag behavior so that dragging after
|
||||
// a double-click extends selection by whole words
|
||||
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 {
|
||||
int mark;
|
||||
int dot;
|
||||
if( pos > endInitialWord ) {
|
||||
mark = beginInitialWord;
|
||||
dot = Utilities.getWordEnd( c, pos );
|
||||
} else if( pos < beginInitialWord ) {
|
||||
mark = endInitialWord;
|
||||
dot = Utilities.getWordStart( c, pos );
|
||||
} else {
|
||||
mark = beginInitialWord;
|
||||
dot = endInitialWord;
|
||||
}
|
||||
select( mark, dot );
|
||||
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 );
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
@@ -138,14 +146,15 @@ public class FlatTextComponentsTest
|
||||
JComboBox<String> comboBox6 = new JComboBox<>();
|
||||
JSpinner spinner5 = new JSpinner();
|
||||
JLabel label5 = new JLabel();
|
||||
JTextField textField4 = new JTextField();
|
||||
textField = new JTextField();
|
||||
dragEnabledCheckBox = new JCheckBox();
|
||||
JLabel label6 = new JLabel();
|
||||
JScrollPane scrollPane2 = new JScrollPane();
|
||||
JTextArea textArea2 = new JTextArea();
|
||||
textArea = new JTextArea();
|
||||
JScrollPane scrollPane4 = new JScrollPane();
|
||||
JTextPane textPane4 = new JTextPane();
|
||||
textPane = new JTextPane();
|
||||
JScrollPane scrollPane6 = new JScrollPane();
|
||||
JEditorPane editorPane5 = new JEditorPane();
|
||||
editorPane = new JEditorPane();
|
||||
JPopupMenu popupMenu1 = new JPopupMenu();
|
||||
JMenuItem cutMenuItem = new JMenuItem();
|
||||
JMenuItem copyMenuItem = new JMenuItem();
|
||||
@@ -535,10 +544,16 @@ public class FlatTextComponentsTest
|
||||
label5.setName("label5");
|
||||
add(label5, "cell 0 16");
|
||||
|
||||
//---- textField4 ----
|
||||
textField4.setText("123 456 789 abc def");
|
||||
textField4.setName("textField4");
|
||||
add(textField4, "cell 1 16 2 1,growx");
|
||||
//---- 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>");
|
||||
@@ -549,10 +564,10 @@ public class FlatTextComponentsTest
|
||||
{
|
||||
scrollPane2.setName("scrollPane2");
|
||||
|
||||
//---- textArea2 ----
|
||||
textArea2.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");
|
||||
textArea2.setName("textArea2");
|
||||
scrollPane2.setViewportView(textArea2);
|
||||
//---- 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");
|
||||
|
||||
@@ -560,10 +575,10 @@ public class FlatTextComponentsTest
|
||||
{
|
||||
scrollPane4.setName("scrollPane4");
|
||||
|
||||
//---- textPane4 ----
|
||||
textPane4.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");
|
||||
textPane4.setName("textPane4");
|
||||
scrollPane4.setViewportView(textPane4);
|
||||
//---- 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");
|
||||
|
||||
@@ -571,10 +586,10 @@ public class FlatTextComponentsTest
|
||||
{
|
||||
scrollPane6.setName("scrollPane6");
|
||||
|
||||
//---- editorPane5 ----
|
||||
editorPane5.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");
|
||||
editorPane5.setName("editorPane5");
|
||||
scrollPane6.setViewportView(editorPane5);
|
||||
//---- 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");
|
||||
|
||||
@@ -612,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 -----------------------------------------------------------
|
||||
|
||||
@@ -423,11 +423,24 @@ new FormModel {
|
||||
"value": "cell 0 16"
|
||||
} )
|
||||
add( new FormComponent( "javax.swing.JTextField" ) {
|
||||
name: "textField4"
|
||||
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>"
|
||||
@@ -437,8 +450,11 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane2"
|
||||
add( new FormComponent( "javax.swing.JTextArea" ) {
|
||||
name: "textArea2"
|
||||
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"
|
||||
@@ -446,8 +462,11 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane4"
|
||||
add( new FormComponent( "javax.swing.JTextPane" ) {
|
||||
name: "textPane4"
|
||||
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"
|
||||
@@ -455,8 +474,11 @@ new FormModel {
|
||||
add( new FormContainer( "javax.swing.JScrollPane", new FormLayoutManager( class javax.swing.JScrollPane ) ) {
|
||||
name: "scrollPane6"
|
||||
add( new FormComponent( "javax.swing.JEditorPane" ) {
|
||||
name: "editorPane5"
|
||||
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"
|
||||
|
||||
@@ -18,12 +18,16 @@ 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;
|
||||
@@ -70,59 +74,83 @@ class FlatRSyntaxTextAreaUI
|
||||
extends ConfigurableCaret
|
||||
{
|
||||
private boolean isWordSelection;
|
||||
private int beginInitialWord;
|
||||
private int endInitialWord;
|
||||
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();
|
||||
if( isWordSelection ) {
|
||||
beginInitialWord = getMark();
|
||||
endInitialWord = getDot();
|
||||
|
||||
// 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 && !e.isConsumed() && SwingUtilities.isLeftMouseButton( e ) ) {
|
||||
// fix Swing's double-click-and-drag behavior so that dragging after
|
||||
// a double-click extends selection by whole words
|
||||
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 {
|
||||
int mark;
|
||||
int dot;
|
||||
if( pos > endInitialWord ) {
|
||||
mark = beginInitialWord;
|
||||
dot = Utilities.getWordEnd( c, pos );
|
||||
} else if( pos < beginInitialWord ) {
|
||||
mark = endInitialWord;
|
||||
dot = Utilities.getWordStart( c, pos );
|
||||
} else {
|
||||
mark = beginInitialWord;
|
||||
dot = endInitialWord;
|
||||
}
|
||||
if( mark != getMark() )
|
||||
setDot( mark );
|
||||
if( dot != getDot() )
|
||||
moveDot( dot );
|
||||
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