Hi,
I've made 3 minor enhancements to Scintilla which I hope you will
consider incorporating into the proper version.
1) Horizontal scrollbar on long lines: I've added some code to the
Paint() method so it works out the longest line on screen while it is
painting and changes the size of the scrollbar if necessary. This should
work on Windows and GTK, but is only tested on Windows.
2) Find is very slow if the codepage isn't UTF8: This is because
MovePositionOutsideChar() is very slow when it thinks the codepage might
have multi-byte chars, which is whenever the codepage isn't UTF8. I've
created a change so that the codepage is queried (via Windows) for the
maximum char width. If this is 1 then there is nothing to do (CR/LF is
done separately). This should compile on Windows and GTK, but only
Windows queries the codepage (GTK continues to assumes 2 bytes).
3) Rectangular pasting:
a) If the clipboard contains a single line and there is a rectangular
selection (possibly zero-width), then the clipboard line will be copied
onto each of the selected lines.
b) If there is a rectangular selection then pasting will be rectangular
whether the clipboard content was copied rectangular or not; but only if
the number of lines selected matches the number in the clipboard
(excepting case (a) above).
c) If the clipboard contains a rectangular copy, then pasting is not
allowed if there is a stream-selection.
The rectangular changes should compile and work on Windows and compile
with no effect on GTK.
If you have any queries, or would like something done differently feel
free to ask.
--
Snow (aka Ross Newell)
diff -r -u scintilla/src/Editor.cxx scin1.67/src/Editor.cxx
--- scintilla/src/Editor.cxx 2005-12-10 09:22:10.000000000 +0000
+++ scin1.67/src/Editor.cxx 2006-03-04 18:18:56.000000000 +0000
@@ -2817,6 +2817,9 @@
rcTextArea.left = vs.fixedColumnWidth;
rcTextArea.right -= vs.rightMarginWidth;
surfaceWindow->SetClip(rcTextArea);
+
+ int textAreaWidth = rcTextArea.right - rcTextArea.left - 1;
+ int dispScrollWidth = textAreaWidth;
// Loop on visible lines
//double durLayout = 0.0;
@@ -2861,6 +2864,9 @@
ll->selEnd = -1;
ll->containsCaret = false;
}
+
+ int lineLength =
ll->positions[ll->numCharsInLine];
+ dispScrollWidth = lineLength > dispScrollWidth ? lineLength :
dispScrollWidth;
GetHotSpotRange(ll->hsStart, ll->hsEnd);
@@ -3004,6 +3010,20 @@
//if (durPaint < 0.00000001)
// durPaint = 0.00000001;
+ // If we are scrolled too far right for this page,
+ // make the scrollbars bigger.
+ if (dispScrollWidth < xOffset + textAreaWidth) {
+ dispScrollWidth = xOffset + textAreaWidth;
+ }
+
+ // If the needed width is bigger increase it, if the needed width is
more than 50
+ // smaller and we have painted the whole screen decrease it.
+ if (dispScrollWidth > scrollWidth ||
+ (scrollWidth - dispScrollWidth > 50 && rcClient.Height() ==
rcArea.Height())) {
+ scrollWidth = dispScrollWidth;
+ SetScrollBars();
+ }
+
// Right column limit indicator
PRectangle rcBeyondEOF = rcClient;
rcBeyondEOF.left = vs.fixedColumnWidth;
diff -r -u scintilla/win32/ScintillaWin.cxx scin1.67/win32/ScintillaWin.cxx
--- scintilla/win32/ScintillaWin.cxx 2005-11-30 09:42:42.000000000 +0000
+++ scin1.67/win32/ScintillaWin.cxx 2006-03-04 18:24:12.000000000 +0000
@@ -1107,13 +1107,14 @@
if (!horizontalScrollBarVisible || (wrapState != eWrapNone))
horizEndPreferred = 0;
unsigned int pageWidth = rcText.Width();
- sci.fMask = SIF_PAGE | SIF_RANGE;
GetScrollInfo(SB_HORZ, &sci);
if ((sci.nMin != 0) ||
(sci.nMax != horizEndPreferred) ||
(sci.nPage != pageWidth) ||
- (sci.nPos != 0)) {
+ (sci.nPos != 0)) {
sci.fMask = SIF_PAGE | SIF_RANGE;
+ if (horizEndPreferred != 0)
+ sci.fMask |= SIF_DISABLENOSCROLL;
sci.nMin = 0;
sci.nMax = horizEndPreferred;
sci.nPage = pageWidth;
@@ -1124,6 +1125,12 @@
if (scrollWidth < static_cast<int>(pageWidth)) {
HorizontalScrollTo(0);
}
+ else if (horizEndPreferred != 0) {
+ // Sometime Windows won't display the horizontal
scrollbar
+ // This seems to persuade it most of the time.
+ ShowScrollBar(MainHWND(), SB_HORZ, FALSE);
+ ShowScrollBar(MainHWND(), SB_HORZ, TRUE);
+ }
}
return modified;
}
diff -r -u scintilla/gtk/PlatGTK.cxx scin1.67/gtk/PlatGTK.cxx
--- scintilla/gtk/PlatGTK.cxx 2005-08-04 16:36:40.000000000 +0100
+++ scin1.67/gtk/PlatGTK.cxx 2006-03-04 18:36:26.000000000 +0000
@@ -2516,7 +2516,7 @@
}
#endif
-int Platform::DBCSCharMaxLength() {
+int Platform::DBCSCharMaxLength(int codePage) {
return MB_CUR_MAX;
//return 2;
}
diff -r -u scintilla/include/Platform.h scin1.67/include/Platform.h
--- scintilla/include/Platform.h 2005-03-25 16:08:20.000000000 +0000
+++ scin1.67/include/Platform.h 2006-03-04 18:35:34.000000000 +0000
@@ -477,7 +477,7 @@
WindowID w, unsigned int msg, unsigned long wParam=0, void
*lParam=0);
static bool IsDBCSLeadByte(int codePage, char ch);
static int DBCSCharLength(int codePage, const char *s);
- static int DBCSCharMaxLength();
+ static int DBCSCharMaxLength(int codePage);
// These are utility functions not really tied to a platform
static int Minimum(int a, int b);
diff -r -u scintilla/src/Document.cxx scin1.67/src/Document.cxx
--- scintilla/src/Document.cxx 2005-12-12 10:43:04.000000000 +0000
+++ scin1.67/src/Document.cxx 2006-03-04 18:40:50.000000000 +0000
@@ -271,7 +271,7 @@
} else if (dbcsCodePage) {
char mbstr[maxBytesInDBCSCharacter+1];
int i;
- for (i=0; i<Platform::DBCSCharMaxLength(); i++) {
+ for (i=0; i<Platform::DBCSCharMaxLength(dbcsCodePage); i++) {
mbstr[i] = cb.CharAt(pos+i);
}
mbstr[i] = '\0';
@@ -315,14 +315,14 @@
pos--;
ch = static_cast<unsigned char>(cb.CharAt(pos));
}
- } else {
+ } else if (Platform::DBCSCharMaxLength(dbcsCodePage) != 1) {
// Anchor DBCS calculations at start of line because
start of line can
// not be a DBCS trail byte.
int posCheck = LineStart(LineFromPosition(pos));
while (posCheck < pos) {
char mbstr[maxBytesInDBCSCharacter+1];
int i;
- for(i=0;i<Platform::DBCSCharMaxLength();i++) {
+
for(i=0;i<Platform::DBCSCharMaxLength(dbcsCodePage);i++) {
mbstr[i] = cb.CharAt(posCheck+i);
}
mbstr[i] = '\0';
diff -r -u scintilla/win32/PlatWin.cxx scin1.67/win32/PlatWin.cxx
--- scintilla/win32/PlatWin.cxx 2005-12-10 21:08:14.000000000 +0000
+++ scin1.67/win32/PlatWin.cxx 2006-03-04 18:33:54.000000000 +0000
@@ -1953,8 +1953,21 @@
return (::IsDBCSLeadByteEx(codePage, s[0]) != 0) ? 2 : 1;
}
-int Platform::DBCSCharMaxLength() {
- return 2;
+int Platform::DBCSCharMaxLength(int codePage) {
+ static cachedCodePage;
+ static CPINFO cacheCPInfo;
+
+ if (codePage == 0) {
+ return 1;
+ }
+ if (cachedCodePage != codePage) {
+ if (!GetCPInfo(codePage, &cacheCPInfo)) {
+ return 2;
+ }
+ cachedCodePage = codePage;
+ }
+
+ return cacheCPInfo.MaxCharSize;
}
// These are utility functions not really tied to a platform
diff -r -u scin1.67/gtk/ScintillaGTK.cxx scintilla/gtk/ScintillaGTK.cxx
--- scin1.67/gtk/ScintillaGTK.cxx 2005-11-15 23:24:02.000000000 +0000
+++ scintilla/gtk/ScintillaGTK.cxx 2006-03-04 19:26:18.000000000 +0000
@@ -1484,7 +1484,7 @@
int selStart = SelectionStart();
if (selText.rectangular) {
- PasteRectangular(selStart, selText.s,
selText.len);
+ PasteRectangular(selStart, selText.s,
selText.len, 0);
} else {
pdoc->InsertString(currentPos, selText.s,
selText.len);
SetEmptySelection(currentPos + selText.len);
diff -r -u scin1.67/src/Editor.cxx scintilla/src/Editor.cxx
--- scin1.67/src/Editor.cxx 2005-12-10 09:22:10.000000000 +0000
+++ scintilla/src/Editor.cxx 2006-03-04 19:39:06.000000000 +0000
@@ -3401,38 +3401,84 @@
}
}
-void Editor::PasteRectangular(int pos, const char *ptr, int len) {
+void Editor::PasteRectangular(int pos, const char *ptr, int len, int
nrSelectedLines) {
if (pdoc->IsReadOnly() || SelectionContainsProtected()) {
return;
}
- currentPos = pos;
- int xInsert = XFromPosition(currentPos);
- int line = pdoc->LineFromPosition(currentPos);
+
+ // Count the nr of lines in the clipboard triming blank lines from
start
+ // and end.
+ while (len > 0 && IsEOLChar(ptr[len - 1]))
+ len--;
+ while (len > 0 && IsEOLChar(ptr[0])) {
+ ptr++;
+ len--;
+ }
bool prevCr = false;
- pdoc->BeginUndoAction();
+ int nrPastingLines = 1;
for (int i = 0; i < len; i++) {
- if (IsEOLChar(ptr[i])) {
- if ((ptr[i] == '\r') || (!prevCr))
- line++;
- if (line >= pdoc->LinesTotal()) {
- if (pdoc->eolMode != SC_EOL_LF)
- pdoc->InsertChar(pdoc->Length(), '\r');
- if (pdoc->eolMode != SC_EOL_CR)
- pdoc->InsertChar(pdoc->Length(), '\n');
+ if (IsEOLChar(ptr[i])) {
+ if (ptr[i] == '\r' || (!prevCr)) {
+ nrPastingLines++;
}
- // Pad the end of lines with spaces if required
+ prevCr = ptr[i] == '\r';
+ } else {
+ prevCr = false;
+ }
+ }
+
+ if (nrPastingLines != 1 && nrSelectedLines > 0 && nrPastingLines
!= nrSelectedLines) {
+ // Beep?
+ return;
+ }
+
+ // Only do this once we know we will proceed.
+ ClearSelection();
+
+ int xInsert = XFromPosition(currentPos);
+ int line = pdoc->LineFromPosition(currentPos);
+
+ pdoc->BeginUndoAction();
+
+ if (nrPastingLines == 1 && nrSelectedLines > 0) {
+ // Paste the (only) clipboard line onto each selected line.
+ for (int i = 0; i < nrSelectedLines; i++) {
+ // Pad the beginning of lines with spaces if required
currentPos = PositionFromLineX(line, xInsert);
- if ((XFromPosition(currentPos) < xInsert) && (i + 1 <
len)) {
- for (int i = 0; i < xInsert -
XFromPosition(currentPos); i++) {
- pdoc->InsertChar(currentPos, ' ');
- currentPos++;
+ for (int j = 0; j < xInsert -
XFromPosition(currentPos); j++) {
+ pdoc->InsertChar(currentPos, ' ');
+ currentPos++;
+ }
+ pdoc->InsertString(currentPos, ptr, len);
+ line++;
+ }
+ } else {
+ prevCr = false;
+ currentPos = pos;
+ for (int i = 0; i < len; i++) {
+ if (IsEOLChar(ptr[i])) {
+ if ((ptr[i] == '\r') || (!prevCr))
+ line++;
+ if (line >= pdoc->LinesTotal()) {
+ if (pdoc->eolMode != SC_EOL_LF)
+
pdoc->InsertChar(pdoc->Length(), '\r');
+ if (pdoc->eolMode != SC_EOL_CR)
+
pdoc->InsertChar(pdoc->Length(), '\n');
}
+ // Pad the beginning of lines with spaces if
required
+ currentPos = PositionFromLineX(line, xInsert);
+ if ((XFromPosition(currentPos) < xInsert) && (i
+ 1 < len)) {
+ for (int i = 0; i < xInsert -
XFromPosition(currentPos); i++) {
+ pdoc->InsertChar(currentPos, '
');
+ currentPos++;
+ }
+ }
+ prevCr = ptr[i] == '\r';
+ } else {
+ pdoc->InsertString(currentPos, ptr + i, 1);
+ currentPos++;
+ prevCr = false;
}
- prevCr = ptr[i] == '\r';
- } else {
- pdoc->InsertString(currentPos, ptr + i, 1);
- currentPos++;
- prevCr = false;
}
}
pdoc->EndUndoAction();
@@ -4923,7 +4969,7 @@
position = positionAfterDeletion;
if (rectangular) {
- PasteRectangular(position, value, istrlen(value));
+ PasteRectangular(position, value, istrlen(value), 0);
pdoc->EndUndoAction();
// Should try to select new rectangle but it may not be
a rectangle now so just select the drop position
SetEmptySelection(position);
diff -r -u scin1.67/src/Editor.h scintilla/src/Editor.h
--- scin1.67/src/Editor.h 2005-12-10 09:22:10.000000000 +0000
+++ scintilla/src/Editor.h 2006-03-04 18:52:28.000000000 +0000
@@ -414,7 +414,7 @@
void ClearAll();
void ClearDocumentStyle();
void Cut();
- void PasteRectangular(int pos, const char *ptr, int len);
+ void PasteRectangular(int pos, const char *ptr, int len, int
nrSelectedLines);
virtual void Copy() = 0;
virtual bool CanPaste();
virtual void Paste() = 0;
diff -r -u scin1.67/win32/ScintillaWin.cxx scintilla/win32/ScintillaWin.cxx
--- scin1.67/win32/ScintillaWin.cxx 2005-11-30 09:42:42.000000000 +0000
+++ scintilla/win32/ScintillaWin.cxx 2006-03-04 18:58:20.000000000 +0000
@@ -222,7 +222,7 @@
virtual bool GetScrollInfo(int nBar, LPSCROLLINFO lpsi);
void ChangeScrollPos(int barType, int pos);
- void InsertPasteText(const char *text, int len, int selStart, bool
isRectangular);
+ void InsertPasteText(const char *text, int len, int selStart, int
rectangularNrLines);
public:
// Public for benefit of Scintilla_DirectFunction
@@ -1237,10 +1237,11 @@
}
};
-void ScintillaWin::InsertPasteText(const char *text, int len, int selStart,
bool isRectangular) {
- if (isRectangular) {
- PasteRectangular(selStart, text, len);
+void ScintillaWin::InsertPasteText(const char *text, int len, int selStart,
int rectangularNrLines) {
+ if (rectangularNrLines != 0) {
+ PasteRectangular(selStart, text, len, rectangularNrLines);
} else {
+ ClearSelection();
if (convertPastes) {
// Convert line endings of the paste into our local
line-endings mode
char *convertedString =
Document::TransformLineEnds(&len, text, len, pdoc->eolMode);
@@ -1260,10 +1261,28 @@
if (!::OpenClipboard(MainHWND()))
return;
pdoc->BeginUndoAction();
- ClearSelection();
+
int selStart = SelectionStart();
- bool isRectangular = ::IsClipboardFormatAvailable(cfColumnSelect) != 0;
+ int selEnd = SelectionEnd();
+ int rectangularNrLines = 0;
+ // If there is a rectangular selection count the nr lines selected.
+ bool isRectangular = selType == selRectangle;
+ if (isRectangular) {
+ int firstLine = pdoc->LineFromPosition(selStart);
+ int lastLine = pdoc->LineFromPosition(selEnd);
+ rectangularNrLines = lastLine - firstLine + 1;
+ }
+ else if (::IsClipboardFormatAvailable(cfColumnSelect)) {
+ if (selStart != selEnd) {
+ return;
+ }
+ else {
+ isRectangular = true;
+ rectangularNrLines = -1;
+ }
+ }
+
// Always use CF_UNICODETEXT if available
GlobalMemory memUSelection(::GetClipboardData(CF_UNICODETEXT));
if (memUSelection) {
@@ -1294,7 +1313,7 @@
}
if (putf) {
- InsertPasteText(putf, len, selStart,
isRectangular);
+ InsertPasteText(putf, len, selStart,
rectangularNrLines);
delete []putf;
}
}
@@ -1329,11 +1348,11 @@
delete []uptr;
if (putf) {
- InsertPasteText(putf, mlen,
selStart, isRectangular);
+ InsertPasteText(putf, mlen,
selStart, rectangularNrLines);
delete []putf;
}
} else {
- InsertPasteText(ptr, len, selStart,
isRectangular);
+ InsertPasteText(ptr, len, selStart,
rectangularNrLines);
}
}
memSelection.Unlock();
_______________________________________________
Scintilla-interest mailing list
[email protected]
http://mailman.lyra.org/mailman/listinfo/scintilla-interest