Skip to content

Commit a6eb9ea

Browse files
committed
Fixing double- and triple-click selection behavior (Peter Lewis)
Double clicking selects words, double-clicking and dragging does too. Triple-click for lines. http://code.google.com/p/arduino/issues/detail?id=824
1 parent b133faa commit a6eb9ea

File tree

1 file changed

+132
-73
lines changed

1 file changed

+132
-73
lines changed

app/src/processing/app/syntax/JEditTextArea.java

Lines changed: 132 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -834,6 +834,17 @@ public int getLineStopOffset(int line)
834834
return lineElement.getEndOffset();
835835
}
836836

837+
/**
838+
* Returns the end offset of the specified line, but not past the end of the text
839+
* @param line The line
840+
* @return The end offset of the specified line, safe to use for a selection, or -1 if the line is
841+
* invalid.
842+
*/
843+
public int getSafeLineStopOffset(int line)
844+
{
845+
return Math.min(getLineStopOffset(line),getDocumentLength());
846+
}
847+
837848
/**
838849
* Returns the length of the specified line.
839850
* @param line The line
@@ -1144,7 +1155,7 @@ public void select(int start, int end)
11441155
{
11451156
throw new IllegalArgumentException("Bounds out of"
11461157
+ " range: " + newStart + "," +
1147-
newEnd);
1158+
newEnd + " [" + getDocumentLength() + "]");
11481159
}
11491160

11501161
// If the new position is the same as the old, we don't
@@ -1201,6 +1212,86 @@ public void select(int start, int end)
12011212
// getLineOfOffset(end));
12021213
}
12031214
}
1215+
1216+
private boolean isWordCharacter( char ch, String noWordSep )
1217+
{
1218+
return Character.isLetterOrDigit(ch) || ch=='_' || noWordSep.indexOf(ch) != -1;
1219+
}
1220+
1221+
protected void setNewSelectionWord( int line, int offset )
1222+
{
1223+
if (getLineLength(line) == 0) {
1224+
newSelectionStart = getLineStartOffset(line);
1225+
newSelectionEnd = newSelectionStart;
1226+
return;
1227+
}
1228+
1229+
String noWordSep = (String)document.getProperty("noWordSep");
1230+
if(noWordSep == null)
1231+
noWordSep = "";
1232+
1233+
String lineText = getLineText(line);
1234+
1235+
int wordStart = 0;
1236+
int wordEnd = lineText.length();
1237+
1238+
char ch = lineText.charAt(Math.max(0,offset - 1));
1239+
1240+
// special case for whitespace (fry 0122, bug #348)
1241+
// this is really nasty.. turns out that double-clicking any non-letter
1242+
// or digit char gets lumped together.. sooo, this quickly gets messy,
1243+
// because really it needs to check whether the chars are of the same
1244+
// type.. so a double space or double - might be grouped together,
1245+
// but what about a +=1? do + and - get grouped but not the 1? blech,
1246+
// coming back to this later. it's not a difficult fix, just a
1247+
// time-consuming one to track down all the proper cases.
1248+
/*
1249+
if (ch == ' ') {
1250+
//System.out.println("yeehaa");
1251+
1252+
for(int i = offset - 1; i >= 0; i--) {
1253+
if (lineText.charAt(i) == ' ') {
1254+
wordStart = i;
1255+
} else {
1256+
break;
1257+
}
1258+
}
1259+
for(int i = offset; i < lineText.length(); i++) {
1260+
if (lineText.charAt(i) == ' ') {
1261+
wordEnd = i + 1;
1262+
} else {
1263+
break;
1264+
}
1265+
}
1266+
1267+
} else {
1268+
*/
1269+
1270+
// If the user clicked on a non-letter char,
1271+
// we select the surrounding non-letters
1272+
boolean selectNoLetter = !isWordCharacter(ch,noWordSep);
1273+
1274+
for(int i = offset - 1; i >= 0; i--) {
1275+
ch = lineText.charAt(i);
1276+
if (selectNoLetter ^ !isWordCharacter(ch,noWordSep)) {
1277+
wordStart = i + 1;
1278+
break;
1279+
}
1280+
}
1281+
1282+
for(int i = offset; i < lineText.length(); i++) {
1283+
ch = lineText.charAt(i);
1284+
if(selectNoLetter ^ !isWordCharacter(ch,noWordSep)) {
1285+
wordEnd = i;
1286+
break;
1287+
}
1288+
}
1289+
//}
1290+
int lineStart = getLineStartOffset(line);
1291+
1292+
newSelectionStart = lineStart + wordStart;
1293+
newSelectionEnd = lineStart + wordEnd;
1294+
}
12041295

12051296

12061297
/**
@@ -1684,6 +1775,14 @@ public void processKeyEvent(KeyEvent evt) {
16841775
protected int selectionEnd;
16851776
protected int selectionEndLine;
16861777
protected boolean biasLeft;
1778+
1779+
protected int newSelectionStart; // hack to get around lack of multiple returns in Java
1780+
protected int newSelectionEnd;
1781+
1782+
protected boolean selectWord;
1783+
protected boolean selectLine;
1784+
protected int selectionAncorStart;
1785+
protected int selectionAncorEnd;
16871786

16881787
protected int bracketPosition;
16891788
protected int bracketLine;
@@ -2021,9 +2120,26 @@ public void mouseDragged(MouseEvent evt)
20212120
{
20222121
if (popup != null && popup.isVisible()) return;
20232122

2024-
setSelectionRectangular((evt.getModifiers()
2025-
& InputEvent.CTRL_MASK) != 0);
2026-
select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
2123+
if ( !selectWord && !selectLine ) {
2124+
setSelectionRectangular((evt.getModifiers()
2125+
& InputEvent.CTRL_MASK) != 0);
2126+
select(getMarkPosition(),xyToOffset(evt.getX(),evt.getY()));
2127+
} else {
2128+
int line = yToLine(evt.getY());
2129+
if ( selectWord ) {
2130+
setNewSelectionWord( line, xToOffset(line,evt.getX()) );
2131+
} else {
2132+
newSelectionStart = getLineStartOffset(line);
2133+
newSelectionEnd = getSafeLineStopOffset(line);
2134+
}
2135+
if ( newSelectionStart < selectionAncorStart ) {
2136+
select(newSelectionStart,selectionAncorEnd);
2137+
} else if ( newSelectionEnd > selectionAncorEnd ) {
2138+
select(selectionAncorStart,newSelectionEnd);
2139+
} else {
2140+
select(newSelectionStart,newSelectionEnd);
2141+
}
2142+
}
20272143
}
20282144

20292145
final Cursor normalCursor = new Cursor(Cursor.DEFAULT_CURSOR);
@@ -2094,6 +2210,9 @@ public void mousePressed(MouseEvent evt)
20942210
int offset = xToOffset(line,evt.getX());
20952211
int dot = getLineStartOffset(line) + offset;
20962212

2213+
selectLine = false;
2214+
selectWord = false;
2215+
20972216
switch(evt.getClickCount()) {
20982217

20992218
case 1:
@@ -2159,74 +2278,11 @@ private void doDoubleClick(MouseEvent evt, int line,
21592278
bl.printStackTrace();
21602279
}
21612280

2162-
String noWordSep = (String)document.getProperty("noWordSep");
2163-
if(noWordSep == null)
2164-
noWordSep = "";
2165-
2166-
// Ok, it's not a bracket... select the word
2167-
String lineText = getLineText(line);
2168-
2169-
int wordStart = 0;
2170-
int wordEnd = lineText.length();
2171-
2172-
char ch = lineText.charAt(Math.max(0,offset - 1));
2173-
2174-
// special case for whitespace (fry 0122, bug #348)
2175-
// this is really nasty.. turns out that double-clicking any non-letter
2176-
// or digit char gets lumped together.. sooo, this quickly gets messy,
2177-
// because really it needs to check whether the chars are of the same
2178-
// type.. so a double space or double - might be grouped together,
2179-
// but what about a +=1? do + and - get grouped but not the 1? blech,
2180-
// coming back to this later. it's not a difficult fix, just a
2181-
// time-consuming one to track down all the proper cases.
2182-
/*
2183-
if (ch == ' ') {
2184-
//System.out.println("yeehaa");
2185-
2186-
for(int i = offset - 1; i >= 0; i--) {
2187-
if (lineText.charAt(i) == ' ') {
2188-
wordStart = i;
2189-
} else {
2190-
break;
2191-
}
2192-
}
2193-
for(int i = offset; i < lineText.length(); i++) {
2194-
if (lineText.charAt(i) == ' ') {
2195-
wordEnd = i + 1;
2196-
} else {
2197-
break;
2198-
}
2199-
}
2200-
2201-
} else {
2202-
*/
2203-
2204-
// If the user clicked on a non-letter char,
2205-
// we select the surrounding non-letters
2206-
boolean selectNoLetter = (!Character.isLetterOrDigit(ch)
2207-
&& noWordSep.indexOf(ch) == -1);
2208-
2209-
for(int i = offset - 1; i >= 0; i--) {
2210-
ch = lineText.charAt(i);
2211-
if (selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
2212-
noWordSep.indexOf(ch) == -1)) {
2213-
wordStart = i + 1;
2214-
break;
2215-
}
2216-
}
2217-
2218-
for(int i = offset; i < lineText.length(); i++) {
2219-
ch = lineText.charAt(i);
2220-
if(selectNoLetter ^ (!Character.isLetterOrDigit(ch) &&
2221-
noWordSep.indexOf(ch) == -1)) {
2222-
wordEnd = i;
2223-
break;
2224-
}
2225-
}
2226-
//}
2227-
2228-
int lineStart = getLineStartOffset(line);
2229-
select(lineStart + wordStart,lineStart + wordEnd);
2281+
setNewSelectionWord( line, offset );
2282+
select(newSelectionStart,newSelectionEnd);
2283+
selectWord = true;
2284+
selectionAncorStart = selectionStart;
2285+
selectionAncorEnd = selectionEnd;
22302286

22312287
/*
22322288
String lineText = getLineText(line);
@@ -2242,7 +2298,10 @@ private void doDoubleClick(MouseEvent evt, int line,
22422298
private void doTripleClick(MouseEvent evt, int line,
22432299
int offset, int dot)
22442300
{
2245-
select(getLineStartOffset(line),getLineStopOffset(line)-1);
2301+
selectLine = true;
2302+
select(getLineStartOffset(line),getSafeLineStopOffset(line));
2303+
selectionAncorStart = selectionStart;
2304+
selectionAncorEnd = selectionEnd;
22462305
}
22472306
}
22482307

0 commit comments

Comments
 (0)