X-Git-Url: https://ecere.com/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ecere%2Fsrc%2Fgui%2Fcontrols%2FEditBox.ec;h=05816d5b6ebcd42cf2bab5f93de5792217fd59be;hb=51a4bdfd9d7da90402bc341c0bc59a9ae6f7928f;hp=29f30744405c5c9418ac5475b45c4f58310d80e4;hpb=c5db0bbc5d77719e512a17be9de5156a1202efe6;p=sdk diff --git a/ecere/src/gui/controls/EditBox.ec b/ecere/src/gui/controls/EditBox.ec index 29f3074..05816d5 100644 --- a/ecere/src/gui/controls/EditBox.ec +++ b/ecere/src/gui/controls/EditBox.ec @@ -11,6 +11,16 @@ import "FindDialog" import "GoToDialog" import "Array" +char * strchrmax(const char * s, int c, int max) +{ + int i; + char ch; + for(i = 0; i < max && (ch = s[i]); i++) + if(ch == c) + return (char *)s + i; + return null; +} + public class SyntaxColorScheme { public: @@ -47,28 +57,48 @@ public: byte b = (string)[0]; \ int i; \ byte mask = 0x7F; \ - numBytes = 1; \ + numBytes = b ? 1 : 0; \ ch = 0; \ - if(b & 0x80 && b & 0x40) \ + if(b & 0x80) \ { \ - mask >>= 2; \ - numBytes++; \ - if(b & 0x20) \ + if(b & 0x40) \ { \ + mask >>= 2; \ numBytes++; \ - mask >>= 1; \ - if(b & 0x10) \ + if(b & 0x20) \ { \ numBytes++; \ mask >>= 1; \ + if(b & 0x10) \ + { \ + if(b & 0x08) { numBytes = 0; } \ + numBytes++; \ + mask >>= 1; \ + } \ } \ } \ + else \ + numBytes = 0; \ } \ for(i = 0; i 1 && (!(b & 0x80) || (b & 0x40))) \ + { \ + numBytes = 0; \ + ch = 0; \ + } \ + } \ + if(i < numBytes || \ + ch > 0x10FFFF || (ch >= 0xD800 && ch <= 0xDFFF) || \ + (ch < 0x80 && numBytes > 1) || \ + (ch < 0x800 && numBytes > 2) || \ + (ch < 0x10000 && numBytes > 3))\ + { \ + ch = 0; \ + numBytes = 0; \ } \ ch; \ }) @@ -79,12 +109,13 @@ class EditBoxBits bool noCaret:1, noSelect:1, tabKey:1, useTab:1, tabSel:1, allCaps:1, syntax:1, wrap:1; // Syntax States - bool inMultiLineComment:1, inPrep:1, escaped:1; + bool inMultiLineComment:1, inPrep:1, escaped:1, continuedSingleLineComment:1, wasInMultiLine:1, continuedString:1, continuedQuotes:1; bool recomputeSyntax:1; bool cursorFollowsView:1; - + // bool lineNumbers:1; + bool autoSize:1; }; /* TODO: @@ -105,15 +136,13 @@ private: static class ArrayImpl { - uint size; Class type; + uint size; byte * array; }; public class OldArray { - uint size; - ~OldArray() { int c; @@ -121,13 +150,13 @@ public class OldArray if(type.type == normalClass || type.type == noHeadClass) { for(c = 0; c actions { size = 8 }; public: int count; int curAction; void * data; int dontRecord; bool insideRedo; + bool recordAsOne; + bool firstEvent; dontRecord = 0; - + + ~UndoBuffer() + { + actions.Free(); + } + void Undo() { - dontRecord++; - if(curAction > 0) + bool continued = true; + while(curAction > 0 && continued) { - UndoAction action = actions._[--curAction]; + UndoAction action = actions[--curAction]; + dontRecord++; + #ifdef _DEBUG /*Print("Undoing: "); action.Print(data);*/ #endif action.Undo(data); + dontRecord--; + + continued = curAction > 0 && actions[curAction-1].continued; } - dontRecord--; } void Redo() { - dontRecord++; - insideRedo = true; - if(curAction < count) + bool continued = true; + while(curAction < count && continued) { - UndoAction action = actions._[curAction]; + UndoAction action = actions[curAction]; + continued = action.continued; + dontRecord++; + insideRedo = true; + curAction++; #ifdef _DEBUG /*Print("Redoing: "); action.Print(data);*/ #endif action.Redo(data); + + insideRedo = false; + dontRecord--; } - insideRedo = false; - dontRecord--; } void Record(UndoAction action) @@ -230,7 +271,7 @@ public: { int c; for(c = curAction; c < count; c++) - delete actions._[c]; + delete actions[c]; } count = curAction; @@ -242,7 +283,13 @@ public: /*Print("Recording: "); action.Print(data);*/ #endif - actions._[count++] = action; + if(recordAsOne) + { + if(!firstEvent && count > 0) + actions[count-1].continued = true; + firstEvent = false; + } + actions[count++] = action; curAction = count; if(actions.size > count + count / 2 && count + count / 2 >= 8) @@ -251,21 +298,33 @@ public: else delete action; } + + void Clear() + { + actions.Free(); + actions.size = 8; + count = 0; + curAction = 0; + firstEvent = true; + } }; static class AddCharAction : UndoAction { int y, x; unichar ch; - int addedSpaces, addedTabs; + int addedSpaces, addedTabs, xAdjustment; type = class(AddCharAction); void Undo(EditBox editBox) { - editBox.GoToPosition(null, (ch == '\n') ? (y + 1) : y, (ch == '\n') ? 0 : (x + 1)); + editBox.GoToPosition(null, (ch == '\n') ? (y + 1) : y, (ch == '\n') ? 0 : (x + 1) - xAdjustment); editBox.BackSpace(); if(addedTabs || addedSpaces) - editBox.DelCh(editBox.line, y, x - (addedSpaces + addedTabs), editBox.line, y, x, false); + { + editBox.DelCh(editBox.line, y, x - xAdjustment - (addedSpaces + addedTabs), editBox.line, y, x - xAdjustment, false); + editBox.GoToPosition(editBox.line, y, x); + } editBox.UpdateDirty(); } @@ -287,7 +346,7 @@ static class AddTextAction : UndoAction { int y1, x1, y2, x2; char * string; - int addedSpaces, addedTabs; + int addedSpaces, addedTabs, xAdjustment; type = class(AddTextAction); #ifdef _DEBUG @@ -330,14 +389,14 @@ static class DelTextAction : UndoAction { int y1, x1, y2, x2; char * string; - bool placeAfter; + bool placeAfter, noHighlight; int addedSpaces; type = class(DelTextAction); #ifdef _DEBUG void Print(EditBox editBox) { - PrintLn("DelText: y1 = ", y1, "x1 = ", x1, ", y2 = ", y2, ", x2 = ", x2, ", string = ", string, ", addedSpaces = ", addedSpaces, ", placeAfter = ", placeAfter); + PrintLn("DelText: y1 = ", y1, "x1 = ", x1, ", y2 = ", y2, ", x2 = ", x2, ", string = ", string, ", addedSpaces = ", addedSpaces, ", placeAfter = ", placeAfter); } #endif void Undo(EditBox editBox) @@ -348,8 +407,11 @@ static class DelTextAction : UndoAction if(!placeAfter) { editBox.GoToPosition(null, y1, x1); - editBox.selY = y2; - editBox.selX = x2; + if(!noHighlight) + { + editBox.selY = y2; + editBox.selX = x2; + } { int c; editBox.selLine = editBox.lines.first; for(c = 0; c < editBox.selY && editBox.selLine; c++, editBox.selLine = editBox.selLine.next); } //editBox.SetViewToCursor(true); @@ -357,10 +419,13 @@ static class DelTextAction : UndoAction editBox.DelCh(editBox.line, y1, x1 - addedSpaces, editBox.line, y1, x1, false); } else - { - editBox.selY = y1; - editBox.selX = x1; - { int c; editBox.selLine = editBox.lines.first; for(c = 0; c < editBox.selY && editBox.selLine; c++, editBox.selLine = editBox.selLine.next); } + { + if(!noHighlight) + { + editBox.selY = y1; + editBox.selX = x1; + } + { int c; editBox.selLine = editBox.lines.first; for(c = 0; c < editBox.selY && editBox.selLine; c++, editBox.selLine = editBox.selLine.next); } //editBox.SetViewToCursor(true); if(addedSpaces) @@ -396,14 +461,14 @@ static class ReplaceTextAction : UndoAction char * oldString; char * newString; bool placeAfter; - int addedSpaces, addedTabs; + int addedSpaces, addedTabs, xAdjustment; type = class(ReplaceTextAction); #ifdef _DEBUG void Print(EditBox editBox) { - PrintLn("ReplaceText: y1 = ", y1, "x1 = ", x1, ", y2 = ", y2, ", x2 = ", x2, ", y3 = ", y3, ", x3 = ", x3, ", oldString = ", oldString, ", newString = ", newString, ", addedSpaces = ", addedSpaces, ", addedTabs = ", addedTabs, ", placeAfter = ", placeAfter); + PrintLn("ReplaceText: y1 = ", y1, "x1 = ", x1, ", y2 = ", y2, ", x2 = ", x2, ", y3 = ", y3, ", x3 = ", x3, ", oldString = ", oldString, ", newString = ", newString, ", addedSpaces = ", addedSpaces, ", addedTabs = ", addedTabs, ", placeAfter = ", placeAfter); } #endif void Undo(EditBox editBox) @@ -462,7 +527,7 @@ static class ReplaceTextAction : UndoAction /* static class MoveTextAction : UndoAction { - int fy1, fx1, fy2, fx2; + int fy1, fx1, fy2, fx2; int ty, tx; type = class(MoveTextAction); @@ -485,7 +550,7 @@ public class EditLine : struct int length; EditBox editBox; public: - property char * text + property const char * text { set { @@ -511,7 +576,7 @@ private: { char * buffer; int newSize; - + // Adds '\0' byte count = count+1; @@ -573,7 +638,7 @@ public struct BufferLocation if(y > end.y) y -= end.y - start.y; // Location is the last touched line - else + else { if(x >= end.x) { @@ -605,7 +670,7 @@ public struct BufferLocation for(c = 0, line = start.line; c... (this.lines[10].text) property EditLine lastLine { get { return lines.last; } }; property EditLine line { get { return this.line; } }; // TODO: Add Set this.line = this.lines[10] - property char * contents + property const char * contents { - property_category "Data" + property_category $"Data" set { if(this) { + undoBuffer.Clear(); + + undoBuffer.dontRecord++; Deselect(); DelCh(this.lines.first, 0, 0, this.lines.last, this.lineCount-1, ((EditLine)(this.lines.last)).count, true); if(value) @@ -774,6 +835,7 @@ public: //SetViewToCursor(true); UpdateDirty(); Home(); + undoBuffer.dontRecord--; } } @@ -785,7 +847,7 @@ public: /* Can't implement this right now because of memory leak... Need string reference counting... if(style.multiLine) { - + EditLine line; int len = 0; @@ -818,7 +880,7 @@ public: char * buffer = null; if(style.multiLine) { - + EditLine line; int len = 0; @@ -834,7 +896,7 @@ public: len += lineLen; if(line.next) buffer[len++] = '\n'; } - buffer[len] = '\0'; + buffer[len] = '\0'; } return buffer; } @@ -850,7 +912,7 @@ public: return null; } - void SetLineText(char * text) + void SetLineText(const char * text) { if(this) { @@ -861,6 +923,7 @@ public: property Color selectionColor { set { selectionColor = value; } get { return selectionColor; } isset { return selectionColor ? true : false; } }; property Color selectionText { set { selectionText = value; } get { return selectionText; } isset { return selectionText ? true : false; } }; property SyntaxColorScheme syntaxColorScheme { set { delete colorScheme; colorScheme = value; incref colorScheme; } } + property bool recordUndoEvent { set { undoBuffer.recordAsOne = value; undoBuffer.firstEvent = true; } get { return undoBuffer.recordAsOne; } }; // selectionStart.line, selectionStart.column (With Set) // selection.line1, selection.line2, selection.column1, selection.column2 (Read only) @@ -876,7 +939,7 @@ private: int lineCount; // Font Space size Size space, large; - + // Position of Caret (Not necessarily displayed position) int x,y; int col; @@ -892,7 +955,7 @@ private: // ViewX is x offset in pixels, ViewY is y offset in lines int viewX, viewY; // viewLine is first displayed line - EditLine viewLine; + EditLine viewLine; // start and end of area to redraw int startY, endY; @@ -926,7 +989,7 @@ private: bool modified; - void (* FontExtent)(Display display, Font font, char * text, int len, int * width, int * height); + void (* FontExtent)(Display display, Font font, const char * text, int len, int * width, int * height, int prevGlyph, int * rPrevGlyph, int * overHang); Color backColor; bool rightButtonDown; @@ -934,16 +997,16 @@ private: int caretX, caretY; UndoBuffer undoBuffer { data = this }; int savedAction; - Color selectionColor, selectionText; + ColorAlpha selectionColor, selectionText; SyntaxColorScheme colorScheme { }; menu = Menu { }; // Edit Menu - Menu editMenu { menu, "Edit", e }; + Menu editMenu { menu, $"Edit", e }; MenuItem itemEditCut { - editMenu, "Cut\tCtrl+X", t, disabled = true; + editMenu, $"Cut\tCtrl+X", t, disabled = true; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -954,7 +1017,7 @@ private: }; MenuItem itemEditCopy { - editMenu, "Copy\tCtrl+C", c, disabled = true; + editMenu, $"Copy\tCtrl+C", c, disabled = true; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -964,8 +1027,8 @@ private: }; MenuItem itemEditPaste { - editMenu, "Paste\tCtrl+V", p; - + editMenu, $"Paste\tCtrl+V", p; + bool NotifySelect(MenuItem item, Modifiers mods) { if(!(style.readOnly)) @@ -975,7 +1038,7 @@ private: }; MenuItem itemEditDelete { - editMenu, "Delete\tDel", d, disabled = true; + editMenu, $"Delete\tDel", d, disabled = true; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -987,7 +1050,7 @@ private: MenuDivider { editMenu }; MenuItem itemEditSelectAll { - editMenu, "Select All\tCtrl+A", a; + editMenu, $"Select All\tCtrl+A", a; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -998,7 +1061,7 @@ private: MenuDivider { editMenu }; MenuItem itemEditUndo { - editMenu, "Undo\tCtrl+Z", u; + editMenu, $"Undo\tCtrl+Z", u; disabled = true; bool NotifySelect(MenuItem item, Modifiers mods) @@ -1009,7 +1072,7 @@ private: }; MenuItem itemEditRedo { - editMenu, "Redo\tCtrl+Y", o; + editMenu, $"Redo\tCtrl+Y", o; disabled = true; bool NotifySelect(MenuItem item, Modifiers mods) @@ -1021,7 +1084,7 @@ private: MenuDivider { editMenu }; MenuItem { - editMenu, "Find Previous\tShift-F3", e, shiftF3; + editMenu, $"Find Previous\tShift-F3", e, shiftF3; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -1034,7 +1097,7 @@ private: }; MenuItem { - editMenu, "Find Next\tF3", n, f3; + editMenu, $"Find Next\tF3", n, f3; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -1047,7 +1110,7 @@ private: }; MenuItem itemEditFind { - editMenu, "Find...\tCtrl+F", f, ctrlF; + editMenu, $"Find...\tCtrl+F", f, ctrlF; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -1074,13 +1137,13 @@ private: }; MenuItem { - editMenu, "Replace...\tCtrl+R", r, ctrlR; + editMenu, $"Replace...\tCtrl+R", r, ctrlR; bool NotifySelect(MenuItem item, Modifiers mods) { ReplaceDialog dialog { - master = master, + master = master, isModal = true, searchString = searchString, replaceString = replaceString, @@ -1093,7 +1156,7 @@ private: void NotifyDestroyed(Window window, DialogResult result) { ReplaceDialog dialog = (ReplaceDialog)window; - char * replace = dialog.replaceString; + const char * replace = dialog.replaceString; if(replace) strcpy(replaceString, replace); strcpy(searchString, dialog.searchString); @@ -1108,7 +1171,7 @@ private: MenuDivider { editMenu }; MenuItem { - editMenu, "Go To...\tCtrl+G", g, ctrlG; + editMenu, $"Go To...\tCtrl+G", g, ctrlG; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -1121,7 +1184,7 @@ private: MenuDivider { editMenu }; MenuItem itemEditInsertTab { - editMenu, "Insert Tabs", i, checkable = true; + editMenu, $"Insert Tabs", i, checkable = true; bool NotifySelect(MenuItem item, Modifiers mods) { @@ -1137,7 +1200,7 @@ private: EditBox() { static bool syntaxInit = false; - if(!syntaxInit) + if(!syntaxInit) { int g,c; syntaxInit = true; @@ -1159,9 +1222,9 @@ private: colorScheme.keywordColors = [ blue, blue ]; } - FontExtent = Display::FontExtent; + FontExtent = Display::FontExtent2; font = fontObject; - lines.offset = (uint)&((EditLine)0).prev; + lines.offset = (uint)(uintptr)&((EditLine)0).prev; style = EditBoxBits { hScroll = true }; @@ -1175,7 +1238,7 @@ private: maxLineSize = MAXINT; tabSize = 3; - + overwrite = false; mouseSelect = this.mouseMove = false; line = null; @@ -1184,7 +1247,7 @@ private: col = 0; y = -1; line = selLine = null; - viewX = 0; + viewX = 0; viewY = 0; maxLength = 0; maxLine = null; @@ -1215,7 +1278,7 @@ private: lines.Free(EditLine::Free); } - void FlushBuffer(Surface surface, EditLine line, int wc, int * renderStart, int * x, int y, int numSpaces, Box box) + void FlushBuffer(Surface surface, EditLine line, int wc, int * renderStart, int * x, int y, int * previousGlyph, int * oh, int numSpaces, bool drawSpaces, Box box) { int count = wc - *renderStart; if(count) @@ -1226,28 +1289,34 @@ private: if(!numSpaces) { + int coh; //FontExtent(display, font, line.buffer + *renderStart, count, &w, null); surface.TextFont(font); - surface.TextExtent(line.buffer + *renderStart, count, &w, null); - if(*x + w + XOFFSET > 0) - surface.WriteText(XOFFSET + *x,y, line.buffer + *renderStart, count); + surface.TextExtent2(line.buffer + *renderStart, count, &w, null, *previousGlyph, null, &coh); + + if(*x + w + coh + XOFFSET > 0) + { + surface.WriteText2(XOFFSET + *x,y, line.buffer + *renderStart, count, *previousGlyph, previousGlyph); + *oh = coh; + //surface.WriteText(XOFFSET + *x,y, line.buffer + *renderStart, count); + } *x += w; } else { w = numSpaces; // * space.w; - if(*x + w + XOFFSET > 0 && surface.GetTextOpacity()) - surface.Area(XOFFSET + *x - 1, y, XOFFSET + *x + w, y + space.h-1); + if(*x + w + XOFFSET > 0 && (drawSpaces)) + surface.Area(XOFFSET + *x /*- 1*/ + *oh, y, XOFFSET + *x + w, y + space.h-1); // WHATS UP WITH THIS... surface.Area(XOFFSET + *x, y, XOFFSET + *x + w, y + space.h-1); *x += w; - } + } } *renderStart = wc; } } - int CheckColors(EditLine line, int wc, bool selection, int selX, int editX, bool *selected, - Color selectionForeground, Color selectionBackground, Color textColor, Color *foreground, Color *background, bool *opacity, bool *overwrite) + bool CheckColors(EditLine line, int wc, bool selection, int selX, int editX, bool *selected, + Color selectionForeground, Color selectionBackground, Color textColor, Color *foreground, Color *background, bool *opacity, int *overwrite) { bool flush = false; @@ -1271,7 +1340,7 @@ private: if((style.stuckCaret && wc == line.count && !line.next) || (!mouseMove && line == this.line && wc == editX)) { - *overwrite = true; + *overwrite = 1; flush = true; } } @@ -1283,12 +1352,15 @@ private: if(style.syntax) { bool inMultiLineComment = reset ? false : style.inMultiLineComment; + bool wasInMultiLine = reset ? false : style.wasInMultiLine; bool inString = false; bool inQuotes = false; bool inPrep = reset ? false : style.inPrep; bool inSingleLineComment = false; bool escaped = reset ? false : style.escaped; - bool continuedSingleLineComment = false; + bool continuedSingleLineComment = reset ? false : style.continuedSingleLineComment; + bool continuedString = reset ? false : style.continuedString; + bool continuedQuotes = reset ? false : style.continuedQuotes; EditLine line = reset ? lines.first : firstLine; // int maxBackUp = 1000, c; @@ -1303,16 +1375,18 @@ private: if(!escaped) inPrep = false; inSingleLineComment = continuedSingleLineComment; escaped = false; - inString = false; - inQuotes = false; + inString = continuedString; + inQuotes = continuedQuotes; firstWord = true; for(c = 0; (ch = text[c]); c++) { bool wasEscaped = escaped; bool backLastWasStar = lastWasStar; + bool backWasInMultiLine = wasInMultiLine; escaped = false; lastWasStar = false; + wasInMultiLine = inMultiLineComment; if(ch == '/') { if(!inSingleLineComment && !inMultiLineComment && !inQuotes && !inString) @@ -1331,9 +1405,9 @@ private: } else if(ch == '*') { - if(!c || text[c-1] != '/') lastWasStar = true; + if(backWasInMultiLine) lastWasStar = true; } - else if(!inSingleLineComment && !inMultiLineComment && !inQuotes && ch == '\"') + else if(ch == '\"' && !inSingleLineComment && !inMultiLineComment && !inQuotes) { if(inString && !wasEscaped) { @@ -1344,7 +1418,7 @@ private: inString = true; } } - else if(!inSingleLineComment && !inMultiLineComment && !inString && ch == '\'') + else if(ch == '\'' && !inSingleLineComment && !inMultiLineComment && !inString) { if(inQuotes && !wasEscaped) inQuotes = false; @@ -1358,30 +1432,40 @@ private: if(!wasEscaped) escaped = true; } - else + else if(ch == '#' && !inQuotes && !inString && !inMultiLineComment && !inSingleLineComment) { - if(!inQuotes && !inString && !inMultiLineComment && !inSingleLineComment && ch == '#') + if(firstWord) { - if(firstWord) - { - inPrep = true; - } + inPrep = true; } } - firstWord = false; + else if(ch != ' ' && ch != '\t') + firstWord = false; + } + if(line.count && line.text[line.count - 1] == '\\') + { + continuedSingleLineComment = inSingleLineComment; + continuedString = inString; + continuedQuotes = inQuotes; + } + else + { + continuedSingleLineComment = false; + continuedString = false; + continuedQuotes = false; } } - - continuedSingleLineComment = false; - if(line.count && line.text[line.count - 1] == '\\') - continuedSingleLineComment = true; + style.continuedSingleLineComment = continuedSingleLineComment; + style.continuedString = continuedString; + style.continuedQuotes = continuedQuotes; style.inMultiLineComment = inMultiLineComment; + style.wasInMultiLine = wasInMultiLine; style.inPrep = inPrep; style.escaped = escaped; } } - + /*void OnDrawOverChildren(Surface surface) { if(style.lineNumbers) @@ -1399,18 +1483,37 @@ private: else surface.SetBackground(Color{230, 230, 230}); surface.textOpacity = true; - + sprintf(lineText,"%5u ", currentLineNumber % 100000); if(currentLineNumber > this.lineCount) surface.WriteText(0,i*space.h+1," ",6); else surface.WriteText(0,i*space.h+1,lineText,6); - + currentLineNumber++; } } }*/ + static inline int countTabsExtraSpaces(char * buffer, int tabSize, int start, int end) + { + // TODO: Handle tabs position properly with UTF-8 (and everywhere else) + int p = 0, i, extra = 0; + for(i = 0; i < end; i++) + { + if(buffer[i] == '\t') + { + int t = tabSize - (p % tabSize); + p += t; + if(i >= start) + extra += t-1; + } + else + p++; + } + return extra; + } + void OnRedraw(Surface surface) { EditLine line; @@ -1423,14 +1526,14 @@ private: Color textColor; Box box; int maxW = clientSize.w; - + Color foreground, background; bool opacity; // Overwrite Caret Stuff - bool overWrite = false; - int overWriteX, overWriteY; - byte overWriteCh; + int overWrite = 0; + int overWriteX = 0, overWriteY = 0; + char overWriteCh; // ****** SYNTAX STATES ****** bool inMultiLineComment = style.inMultiLineComment; @@ -1439,19 +1542,29 @@ private: bool inPrep = style.inPrep; bool inSingleLineComment = false; bool escaped = style.escaped; - bool continuedSingleLineComment = false; + bool continuedSingleLineComment = style.continuedSingleLineComment; + bool continuedString = style.continuedString; + bool continuedQuotes = style.continuedQuotes; + bool wasInMultiLine = style.wasInMultiLine; // ****** ************* ****** + // For drawing selection background + EditLine selStartLine = this.y < this.selY ? this.line : this.selLine; + EditLine selEndLine = this.y < this.selY ? this.selLine : this.line; + int selStartX = this.y < this.selY || (this.y == this.selY && this.x < this.selX) ? this.x : this.selX; + int selEndX = this.y > this.selY || (this.y == this.selY && this.x > this.selX) ? this.x : this.selX; + /////////////////////////////////// + if(!isEnabled) defaultTextColor = Color { 85, 85, 85 }; textColor = defaultTextColor; if( - Abs(selectionBackground.r - property::background.r) + - Abs(selectionBackground.g - property::background.g) + + Abs(selectionBackground.r - property::background.r) + + Abs(selectionBackground.g - property::background.g) + Abs(selectionBackground.b - property::background.b) < 92) { - selectionBackground = activeBorder; + selectionBackground = formColor; selectionForeground = selectionColor ? selectionColor : SELECTION_COLOR; } @@ -1463,7 +1576,7 @@ private: if(!isEnabled) { - surface.SetBackground(activeBorder); + surface.SetBackground(formColor); surface.Area(0,0,clientSize.w, clientSize.h); } @@ -1476,7 +1589,7 @@ private: selX = this.selX; } else - { + { editX = Min(this.x,this.line.count); selX = Min(this.selX,this.selLine.count); } @@ -1492,7 +1605,7 @@ private: */ surface.SetForeground(foreground); surface.SetBackground(background); - surface.TextOpacity(opacity); + surface.TextOpacity(false); surface.GetBox(box); @@ -1504,16 +1617,17 @@ private: int start = 0; Color newTextColor = textColor = defaultTextColor; bool lineComplete = false; - + int overHang = 0; // ****** SYNTAX HIGHLIGHTING ****** bool lastWasStar = false; + bool trailingSpace = false; bool firstWord = true; if(!escaped) inPrep = false; inSingleLineComment = continuedSingleLineComment; escaped = false; - inString = false; - inQuotes = false; + inString = continuedString; + inQuotes = continuedQuotes; // ********************************* /* === DEBUGGING TOOL FOR MAXLINE === @@ -1529,7 +1643,65 @@ private: surface.SetBackground(selected ? SELECTION_COLOR|0xFF000000 : BLACK|0xFF000000); } */ - + + // Draw Selection Background all at once here + if(selected || line == this.line || line == this.selLine) + { + int sx = XOFFSET + x, sy = y; + int tw, th; + int oh = 0; + char * buffer = line.buffer; + if(line != this.line && line != this.selLine) + { + if(style.freeCaret) + { + tw = clientSize.w - sx; + th = space.h; + } + else + { + surface.TextExtent2(buffer, line.count, &tw, &th, 0, null, &oh); + tw += countTabsExtraSpaces(buffer, tabSize, 0, line.count) * space.w; + } + } + else if(line == selStartLine) + { + int prevGlyph = 0; + int start = Min(line.count, selStartX); + int end = Min(line.count, selEndX); + surface.TextExtent2(buffer, start, &tw, &th, 0, &prevGlyph, null); + sx += tw; + sx += countTabsExtraSpaces(buffer, tabSize, 0, start) * space.w; + if(selStartX > start) sx += space.w * (selStartX - start); + if(style.freeCaret && line != selEndLine) + { + tw = clientSize.w - sx; + th = space.h; + } + else if(line != selEndLine) + { + surface.TextExtent2(buffer + start, line.count - start, &tw, &th, prevGlyph, null, &oh); + tw += countTabsExtraSpaces(buffer, tabSize, start, line.count) * space.w; + } + else + { + surface.TextExtent2(buffer + start, end - start, &tw, &th, prevGlyph, null, &oh); + tw += countTabsExtraSpaces(buffer, tabSize, start, end) * space.w; + end = Max(end, selStartX); + if(selEndX > end) { tw += space.w * (selEndX - end); th = space.h; } + } + } + else if(line == selEndLine) + { + int end = Min(line.count, selEndX); + surface.TextExtent2(buffer, end, &tw, &th, 0, null, &oh); + tw += countTabsExtraSpaces(buffer, tabSize, 0, end) * space.w; + if(selEndX - end) { tw += space.w * (selEndX - end); th = space.h; } + } + tw += oh; + surface.Area(sx, sy, sx + tw-1, sy + th-1); + } + if(line == this.selLine && line == this.line) { end = Max(line.count, this.x); @@ -1556,10 +1728,13 @@ private: y += space.h; lineComplete = false; } - + textColor = newTextColor; if(!selected) + { + foreground = textColor; surface.SetForeground(textColor); + } // Look at words for(; c 1 || !isReal) valid = false; break; + case 'l': case 'L': + gotL++; + if(gotL > 2 || (isReal && (gotL == 2 || gotF)) || (gotL == 2 && (s[i-1] != ch))) + valid = false; + break; + case 'u': case 'U': gotU++; if(gotU > 1 || isReal) valid = false; break; + case 'i': case 'I': case 'j': case 'J': gotI++; if(gotI > 1) valid = false; break; + default: valid = false; + } + } + + // Don't highlight numbers with too many decimal points + if(s[0] == '.' && isdigit(s[1])) + { + int newWordLen; + while(s[0] == '.' && isdigit(s[1])) + { + int newWordLen = s - word; + c += newWordLen - wordLen; + wordLen = newWordLen; + strtod(s, &s); + } + newWordLen = s - word; + c += newWordLen - wordLen; + wordLen = newWordLen; + } + else if(valid) + { + int newWordLen = s + i - word; + newTextColor = colorScheme.numberColor; + c += newWordLen - wordLen; + wordLen = newWordLen; + } + else if(dot && dot > word && dot < s) + newTextColor = colorScheme.numberColor; + } } else { @@ -1722,14 +1975,14 @@ private: if(firstWord) { inPrep = true; - newTextColor = colorScheme.preprocessorColor; + newTextColor = wordLen == 1 ? colorScheme.keywordColors[1] : colorScheme.preprocessorColor; } } - if(!inQuotes && !inString && !inMultiLineComment && !inSingleLineComment) + if(x < box.right && !inQuotes && !inString && !inMultiLineComment && !inSingleLineComment) { for(g = 0; g < ((inPrep && word[0] != '#') ? 2 : 1); g++) { - char ** keys = keyWords[g]; + const char ** keys = keyWords[g]; int * len = keyLen[g]; for(ccc = 0; keys[ccc]; ccc++) { @@ -1760,18 +2013,22 @@ private: inQuotes = backInQuotes; inPrep = backInPrep; inSingleLineComment = backInSingleLineComment; + wasInMultiLine = backWasInMultiLine; break; } else { textColor = newTextColor; if(!selected) + { + foreground = textColor; surface.SetForeground(textColor); + } } } } } - + // If we're not breaking, this can't be rendered as spacing anymore spacing = false; @@ -1781,7 +2038,8 @@ private: //if(!numSpaces) { int tw; - FontExtent(display, font, line.buffer + start, bufferLen + wordLen, &tw, null); + int oh; + FontExtent(display, font, line.buffer + start, bufferLen + wordLen, &tw, null, 0, null, &oh); w = tw; } /*else @@ -1790,9 +2048,13 @@ private: }*/ if(x + viewX + w > maxW) { - c -= wordLen; - lineComplete = true; - break; + // Avoid an endless loop until we fix wrapping + if(c - wordLen > start) + { + c -= wordLen; + lineComplete = true; + break; + } } } } @@ -1803,15 +2065,17 @@ private: { int renderStart = start; bool flush = false; + bool flagTrailingSpace = false; int numSpaces = 0; int wc; + int previousGlyph = 0; // Render checking if we need to split because of selection or to find where to draw insert caret for(wc = start; wc < start + bufferLen; wc++) { flush = CheckColors(line, wc, selection, selX, editX, &selected, selectionForeground, selectionBackground, textColor, &foreground, &background, &opacity, &overWrite); - if(overWrite == true) + if(overWrite == 1) { overWriteCh = (wc < line.count) ? line.buffer[wc] : ' '; if(overWriteCh == '\t') overWriteCh = ' '; @@ -1819,8 +2083,11 @@ private: if(flush) { - FlushBuffer(surface, line, wc, &renderStart, &x, y, numSpaces, box); - if(overWrite == true) + flagTrailingSpace = numSpaces && trailingSpace && style.syntax && start + bufferLen == line.count && line != this.line; + if(flagTrailingSpace) surface.SetBackground(red); + FlushBuffer(surface, line, wc, &renderStart, &x, y, &previousGlyph, &overHang, numSpaces, flagTrailingSpace, box); + if(flagTrailingSpace) surface.SetBackground(background); + if(overWrite == 1) { overWriteX = x; overWriteY = y; @@ -1828,8 +2095,6 @@ private: } numSpaces = 0; - surface.TextOpacity(opacity); - surface.SetBackground(background); surface.SetForeground(foreground); flush = false; @@ -1847,7 +2112,10 @@ private: } } } - FlushBuffer(surface, line, wc, &renderStart, &x, y, numSpaces, box); + flagTrailingSpace = numSpaces && trailingSpace && style.syntax && start + bufferLen == line.count && line != this.line; + if(flagTrailingSpace) surface.SetBackground(red); + FlushBuffer(surface, line, wc, &renderStart, &x, y, &previousGlyph, &overHang, numSpaces, flagTrailingSpace, box); + if(flagTrailingSpace) surface.SetBackground(background); start += bufferLen; } } @@ -1855,40 +2123,32 @@ private: if(CheckColors(line, c, selection, selX, editX, &selected, selectionForeground, selectionBackground, textColor, &foreground, &background, &opacity, &overWrite)) { - if(overWrite == true) + if(overWrite == 1) { overWriteX = x; overWriteY = y; overWriteCh = ' '; overWrite = 2; } - surface.TextOpacity(opacity); surface.SetBackground(background); surface.SetForeground(foreground); } - if(style.freeCaret && selected) + if(line.count && line.text[line.count - 1] == '\\') { - surface.SetBackground(selectionBackground); - surface.Area(x + XOFFSET - 1,y,clientSize.w-1,y+this.space.h-1); - // TEST: surface.Area(x + XOFFSET,y,clientSize.w-1,y+this.space.h-1); + continuedSingleLineComment = inSingleLineComment; + continuedString = inString; + continuedQuotes = inQuotes; } - - - /* - if(style.freeCaret && selected) + else { - surface.SetBackground(selectionBackground); - surface.Area(x + XOFFSET - 1,y,clientSize.w-1,y+this.space.h-1); + continuedSingleLineComment = false; + continuedString = false; + continuedQuotes = false; } - */ - - continuedSingleLineComment = false; - if(line.count && line.text[line.count - 1] == '\\') - continuedSingleLineComment = true; y+=this.space.h; - if(y > box.bottom) // >=clientSize.h) + if(y > box.bottom) // >=clientSize.h) break; } @@ -1912,12 +2172,12 @@ private: if(x > selX) { if(x > line.count) - width = Max(line.length + (x - line.count) * space.w, maxLength); + width = Max(line.length + (x - line.count) * space.w, maxLength + XOFFSET); } else { if(selX > selLine.count) - width = Max(selLine.length + (selX - selLine.count) * space.w, maxLength); + width = Max(selLine.length + (selX - selLine.count) * space.w, maxLength + XOFFSET); } } @@ -1930,8 +2190,6 @@ private: void ComputeLength(EditLine line) { int c; - int tabOccur = 0; - int tabWidth; int x = 0; for(c = 0; c < line.count; ) @@ -1966,7 +2224,10 @@ private: len = 1; } else - FontExtent(display, font, line.buffer + start, len, &w, null); + { + int oh; + FontExtent(display, font, line.buffer + start, len, &w, null, 0, null, &oh); + } } else { @@ -1974,13 +2235,15 @@ private: c++; } x += w; - } + } line.length = x; if(line.length > this.maxLength) { this.maxLine = line; this.maxLength = line.length; + + if(style.autoSize) AutoSize(); } } @@ -1999,13 +2262,15 @@ private: this.maxLine = line; } } + + if(style.autoSize) AutoSize(); } void SelDirty() { if(this.selY != this.y) DirtyAll(); - else if(this.selX != this.x) // commented out to erase caret: if(this.selX != this.x) + else if(this.selX != this.x) // commented out to erase caret: if(this.selX != this.x) DirtyLine(this.y); } @@ -2015,9 +2280,8 @@ private: int c, position = 0; unichar ch; int nb; - for(c = 0; c= 0; c--) @@ -2054,8 +2318,8 @@ private: } return hadComment; } - - int _DelCh(EditLine l1, int y1, int c1, EditLine l2, int y2, int c2, bool placeAfter, int * addedSpacesPtr) + + int _DelCh(EditLine l1, int y1, int c1, EditLine l2, int y2, int c2, bool placeAfter, bool highlight, int * addedSpacesPtr) { EditLine line = l1, next; char * buffer; @@ -2084,7 +2348,7 @@ private: { byte ch = buffer[c1]; if(UTF8_IS_FIRST(ch)) break; - c1--; + c1--; extras++; } oldCount2 = l2.count; @@ -2101,10 +2365,10 @@ private: { int len; char * string; - + len = GetText(null, l1, y1, start, l2, y2, c2, false, false); string = new char[len]; - action = DelTextAction { y1 = y1, x1 = start, y2 = y2, x2 = c2, string = string, placeAfter = placeAfter }; + action = DelTextAction { y1 = y1, x1 = start, y2 = y2, x2 = c2, string = string, placeAfter = placeAfter, noHighlight = !highlight }; GetText(string, l1, y1, start, l2, y2, c2, false, false); Record(action); } @@ -2129,14 +2393,16 @@ private: buffer = new char[line.size ? line.size : 1]; */ buffer = new char[line.size]; - if(!buffer) return; + // TODO: Better handling of these allocation failures + if(!buffer) return extras; CopyBytes(buffer,l2.buffer,oldCount1 + 1/*line.count + 1*//*line.size*/); } else buffer = l2.buffer; - if(!line.AdjustBuffer(newLineCount)) - return; + // TODO: Better handling of these allocation failures + if(!line.AdjustBuffer(newLineCount)) + return extras; #ifdef _DEBUG /*if(newLineCount > 4000 || newLineCount < 0) @@ -2188,7 +2454,7 @@ private: { this.lineCount--; delete line.buffer; - + if(line == this.viewLine) { if(this.viewLine.next) @@ -2197,7 +2463,7 @@ private: //this.viewY++; style.recomputeSyntax = true; } - else + else { this.viewLine = this.viewLine.prev; this.viewY--; @@ -2214,7 +2480,7 @@ private: this.x = this.line.count; //this.y++; } - else + else { this.line = this.line.prev; this.x = this.line.count; @@ -2231,7 +2497,7 @@ private: this.dropLine = this.dropLine.next; this.dropX = this.dropLine.count; } - else + else { this.dropLine = this.dropLine.prev; this.dropX = this.dropLine.count; @@ -2247,7 +2513,7 @@ private: this.selLine = this.selLine.next; this.selX = this.selLine.count; } - else + else { this.selLine = this.selLine.prev; this.selX = this.selLine.count; @@ -2276,28 +2542,28 @@ private: { if(this.selY < this.y) { - _DelCh(this.selLine, this.selY, this.selX, this.line, this.y, this.x, true, addedSpacesPtr); + _DelCh(this.selLine, this.selY, this.selX, this.line, this.y, this.x, true, true, addedSpacesPtr); this.x = this.selX; this.y = this.selY; this.line = this.selLine; } else if(this.selY > this.y) { - _DelCh(this.line, this.y, this.x, this.selLine, this.selY, this.selX, false, addedSpacesPtr); + _DelCh(this.line, this.y, this.x, this.selLine, this.selY, this.selX, false, true, addedSpacesPtr); this.selX = this.x; this.selY = this.y; this.selLine = this.line; } else if(this.selX < this.x) { - _DelCh(this.selLine, this.selY, this.selX, this.line, this.y, this.x, true, addedSpacesPtr); + _DelCh(this.selLine, this.selY, this.selX, this.line, this.y, this.x, true, true, addedSpacesPtr); this.x = this.selX; this.y = this.selY; this.line = this.selLine; } else { - _DelCh(this.line, this.y, this.x, this.selLine, this.selY, this.selX, false, addedSpacesPtr); + _DelCh(this.line, this.y, this.x, this.selLine, this.selY, this.selX, false, true, addedSpacesPtr); this.selX = this.x; this.selY = this.y; this.selLine = this.line; @@ -2308,12 +2574,12 @@ private: return false; } - bool AddToLine(char * stringLine, int count, bool LFComing, int * addedSpacesPtr, int * addedTabsPtr) + bool AddToLine(const char * stringLine, int count, bool LFComing, int * addedSpacesPtr, int * addedTabsPtr, int * xAdjustmentPtr) { bool hadComment = false; // Add the line here EditLine line = this.line; - + // The purpose of this is solely to lock a max number of characters if no HSCROLLING is present if(!style.hScroll && created) { @@ -2334,7 +2600,7 @@ private: { int w; int numBytes = 1; - char * string; + const char * string; if(c < Min(this.x, line.count)) string = line.buffer + c; else if(c < endX) @@ -2350,12 +2616,13 @@ private: } else { + int oh; numBytes = UTF8_NUM_BYTES(*string); - FontExtent(display, this.font, string, numBytes, &w, null); + FontExtent(display, this.font, string, numBytes, &w, null, 0, null, &oh); } x += w; - if(x >= clientSize.w) + if(x >= clientSize.w) { count = c - max; break; @@ -2368,7 +2635,8 @@ private: { int addedSpaces = 0; int addedTabs = 0; - + int xAdjustment = 0; + // Add blank spaces if EES_FREECARET if(this.x > line.count) { @@ -2394,6 +2662,8 @@ private: addedSpaces = wantedPosition - position; else { + xAdjustment = wantedPosition - position; + // Put a first tab addedTabs = 1; position += this.tabSize - (position % this.tabSize); @@ -2402,6 +2672,8 @@ private: position += (addedTabs-1) * this.tabSize; // Finish off with spaces addedSpaces = wantedPosition - position; + + xAdjustment -= addedSpaces + addedTabs; } } else @@ -2425,12 +2697,11 @@ private: { BufferLocation before = { this.line, this.y, this.x }, after = { this.line, this.y, this.x }; bool hasComment; - + memmove(line.buffer+this.x+count, line.buffer+this.x,line.count-this.x); CopyBytes(line.buffer + this.x + addedTabs + addedSpaces, stringLine, count); if(addedTabs) { - *addedTabsPtr = addedTabs; FillBytes(line.buffer+line.count,'\t',addedTabs); #ifdef _DEBUG if(addedTabs > 4000 || addedTabs < 0) @@ -2438,8 +2709,7 @@ private: #endif line.count += addedTabs; } - else if(addedTabs) - *addedTabsPtr = 0; + if(addedSpaces) { FillBytes(line.buffer+line.count,' ',addedSpaces); @@ -2448,10 +2718,11 @@ private: printf("Warning"); #endif line.count += addedSpaces; - if(addedSpacesPtr) *addedSpacesPtr = addedSpaces; - } - else if(addedSpacesPtr) - *addedSpacesPtr = 0; + } + + if(addedTabsPtr) *addedTabsPtr = addedTabs; + if(addedSpacesPtr) *addedSpacesPtr = addedSpaces; + if(xAdjustmentPtr) *xAdjustmentPtr = xAdjustment; #ifdef _DEBUG if(count > 4000 || count < 0) printf("Warning"); @@ -2467,7 +2738,7 @@ private: ComputeLength(line); ComputeColumn(); - after.x = this.x; + after.x = this.x; hasComment = HasCommentOrEscape(line); if(!undoBuffer.insideRedo) @@ -2508,7 +2779,7 @@ private: this.x = this.line.count; ComputeColumn(); if(deselect) - Deselect(); + _Deselect(); } } @@ -2525,16 +2796,15 @@ private: this.x = 0; this.col = 0; if(deselect) - Deselect(); + _Deselect(); } } // Returns true if it needs scrolling bool FindMouse(int px, int py, int * tx, int * ty, EditLine * tline, bool half) { - int w; int c; - int x, y; + int y; EditLine line; bool needHScroll = false; @@ -2599,7 +2869,7 @@ private: this.endY = clientSize.h-1; //ErrorLog("DirtyEnd %d\n", y); } - + void DirtyLine(int y) { if(y >= this.viewY) @@ -2678,7 +2948,7 @@ private: { if(line) { - if(mouseMove || (!overwrite && !style.noCaret)) + if(mouseMove || !style.noCaret) { int max = this.mouseMove ? this.dropX : this.x; int y = this.mouseMove ? this.dropY : this.y; @@ -2721,7 +2991,10 @@ private: len = 1; } else - FontExtent(display, this.font, line.buffer + start, len, &w, null); + { + int oh; + FontExtent(display, this.font, line.buffer + start, len, &w, null, 0, null, &oh); + } } else { @@ -2729,16 +3002,20 @@ private: c++; } x += w; - } + } } if(setCaret) caretX = x; caretY = y * this.space.h; - SetCaret(x + XOFFSET-2, y * space.h + YOFFSET, space.h); + if(!overwrite) + SetCaret(x + XOFFSET-2, y * space.h + YOFFSET, space.h); + else + SetCaret(0, 0, 0); } else SetCaret(0, 0, 0); + // TOFIX: Mismatch between NotifyCaretMove() and NotifyDropped() / GoToPosition() NotifyCaretMove(master, this, y + 1, x + 1); SelectionEnables(); @@ -2793,7 +3070,6 @@ private: while(true) { int start = c; - int numBytes = 1; int len = 1; int w; if(c < Min(max, line.count)) @@ -2823,20 +3099,23 @@ private: len = 1; } else - FontExtent(display, font, line.buffer + start, len, &w, null); + { + int oh; + FontExtent(display, font, line.buffer + start, len, &w, null, 0, null, &oh); + } } - else + else { if(style.freeCaret && c < max) w = space.w; - else + else { if(px) *px = x; return c; } c++; } - if(x + (((half && len == 1) ? (w / 2) : w)) >= position) + if(x + (((half && len == 1) ? (w / 2) : w)) >= position) { int lastW; while(len > 0) @@ -2848,7 +3127,10 @@ private: else a--; if(a > start) - FontExtent(display, font, line.buffer + start, a - start, &w, null); + { + int oh; + FontExtent(display, font, line.buffer + start, a - start, &w, null, 0, null, &oh); + } else w = 0; if(position > x + (half ? ((w + lastW) / 2) : lastW)) break; @@ -2871,7 +3153,7 @@ private: if(this.x < c) this.x = x; else - { + { c = AdjustXPosition(line, viewX + clientSize.w - 1, false, &x, MAXINT, c); if(this.x > c) this.x = c; @@ -2894,7 +3176,7 @@ private: { int c, numLines; EditLine oldLine = this.line; - + bool selecting = this.x != this.selX || this.y != this.selY; numLines = clientSize.h / this.space.h; @@ -2938,7 +3220,7 @@ private: } /* - bool SaveFile(char * fileName) + bool SaveFile(const char * fileName) { File f = eFile_Open(fileName, FO_WRITE); if(f) @@ -2987,6 +3269,13 @@ private: return true; } + void AutoSize() + { + int aw = maxLength + 12, ah = Max(lineCount, 1) * space.h + 2; + int nw = minClientSize.w, nh = minClientSize.h, xw = maxClientSize.w, xh = maxClientSize.h; + clientSize = { nw && aw < nw ? nw : xw && aw > xw ? xw : aw, nh && ah < nh ? nh : xh && ah > xh ? xh : ah }; + } + bool OnResizing(int *w, int *h) { if(!*h) @@ -3034,16 +3323,16 @@ private: PopupMenu popup; Menu contextMenu { }; - MenuItem { contextMenu, "Cut\tCtrl+X", t, NotifySelect = itemEditCut.NotifySelect, disabled = !selection || style.readOnly }; - MenuItem { contextMenu, "Copy\tCtrl+C", c, NotifySelect = itemEditCopy.NotifySelect, disabled = !selection }; - MenuItem { contextMenu, "Paste\tCtrl+V", p, NotifySelect = itemEditPaste.NotifySelect, disabled = style.readOnly }; - MenuItem { contextMenu, "Delete\tDel", d, NotifySelect = itemEditDelete.NotifySelect, disabled = !selection || style.readOnly }; + MenuItem { contextMenu, $"Cut\tCtrl+X", t, NotifySelect = itemEditCut.NotifySelect, disabled = !selection || style.readOnly }; + MenuItem { contextMenu, $"Copy\tCtrl+C", c, NotifySelect = itemEditCopy.NotifySelect, disabled = !selection }; + MenuItem { contextMenu, $"Paste\tCtrl+V", p, NotifySelect = itemEditPaste.NotifySelect, disabled = style.readOnly }; + MenuItem { contextMenu, $"Delete\tDel", d, NotifySelect = itemEditDelete.NotifySelect, disabled = !selection || style.readOnly }; MenuDivider { contextMenu }; - MenuItem { contextMenu, "Select All\tCtrl+A", a, NotifySelect = itemEditSelectAll.NotifySelect }; + MenuItem { contextMenu, $"Select All\tCtrl+A", a, NotifySelect = itemEditSelectAll.NotifySelect }; popup = PopupMenu { master = this, menu = contextMenu, /* - nonClient = true, interim = false, parent = parent, + nonClient = true, interim = false, parent = parent, position = { x + clientStart.x + parent.clientStart.x + position.x, y + cientStart.y + parent.sy + clientStart.y + position.y }; */ position = { x + clientStart.x + absPosition.x - guiApp.desktop.position.x, y + clientStart.y + absPosition.y - guiApp.desktop.position.y } @@ -3106,17 +3395,16 @@ private: this.y = y; this.line = line; DirtyLine(this.y); - this.selLine = this.line; - this.selX = this.x; - this.selY = this.y; - //Deselect(); + _Deselect(); } ComputeColumn(); } - + UpdateDirty(); UpdateCaretPosition(true); - return true; + // Return false because DataBoxes automatically set EditBox editor's clickThrough to true for MouseMove events + // ( for tool tips -- see 95ee4962c4c7bc3fe0a04aa6a4f98cacada40884) + return false; } bool OnLeftButtonUp(int x, int y, Modifiers mods) @@ -3125,9 +3413,9 @@ private: mouseSelect = false; wordSelect = false; - + x -= XOFFSET; - + ReleaseCapture(); if(!style.readOnly) { @@ -3168,12 +3456,16 @@ private: moveX = this.selX - this.x; } } + + recordUndoEvent = true; DelSel(null); this.dropX -= moveX; this.selX = this.x = this.dropX; this.selY = this.y = this.dropY; this.selLine = this.line = this.dropLine; AddS(text); + recordUndoEvent = false; + SetViewToCursor(true); delete text; Modified(); @@ -3205,7 +3497,7 @@ private: this.line = line; ComputeColumn(); DirtyLine(this.y); - Deselect(); + _Deselect(); UpdateDirty(); } } @@ -3223,7 +3515,9 @@ private: } } mouseMove = false; - return true; + // Return false because DataBoxes automatically set EditBox editor's clickThrough to true for MouseMove events + // ( for tool tips -- see 95ee4962c4c7bc3fe0a04aa6a4f98cacada40884) + return false; } bool OnMouseMove(int mx, int my, Modifiers mods) @@ -3232,10 +3526,10 @@ private: EditLine line; bool needScroll; - if(mods != -1 && mods.isSideEffect) - { - SetSelectCursor(); - return true; + if(mods != -1 && mods.isSideEffect) + { + SetSelectCursor(); + return true; } if(style.noSelect) return true; if(wordSelect) return true; @@ -3248,11 +3542,11 @@ private: { if(!needScroll) timer.Stop(); - else + else { if(needScroll) timer.Start(); - if(mods != -1 && + if(mods != -1 && ((style.hScroll) || (style.vScroll))) return true; } @@ -3321,7 +3615,7 @@ private: for(c = start; c= 0; y--) { - c = (y == this.y) ? (this.x-1) : line.count-1; + c = (y == this.y) ? (Min(this.x-1, line.count-1)) : line.count-1; // Slow down when going on lines... if(y != this.y) break; @@ -3450,9 +3746,10 @@ private: else break; } + //if(this.x != 0) { - DelCh(line,y,c+1,this.line,this.y,this.x, true); + _DelCh(line, y, c+1, this.line, this.y, this.x, true, false, null); this.x = this.selX = Min(c+1, line.count); this.y = this.selY = y; this.line = this.selLine = line; @@ -3483,55 +3780,52 @@ private: SetViewToCursor(true); Modified(); } - // Delete word - else if(key.ctrl) - { - if(this.x < this.line.count) - { - int i; - int length; - //Can't delete right away as that would change the line.count - for(i = this.x; i < this.line.count; i++) - { - if(!IS_ALUNDER(this.line.buffer[i])) - break; - DelCh(this.line, this.y, this.x, this.line, this.y, this.x+1, false); - i--; - } - - for(; i < this.line.count; i++) - { - //Delete trailing whitespace - if(IS_ALUNDER(this.line.buffer[i])) - break; - DelCh(this.line, this.y, this.x, this.line, this.y, this.x+1, false); - i--; - } - SetViewToCursor(true); - Modified(); - } - else if(this.line.next) - { - DelCh(this.line, this.y, this.x, this.line.next, this.y+1, 0, false); - SetViewToCursor(true); - Modified(); - } - } - else + else { - if(!(style.freeCaret)) + EditLine line1 = this.line, line2 = this.line; + int x1, y1 = this.y, x2, y2 = this.y; + if(!style.freeCaret) { this.selX = this.x = Min(this.x, this.line.count); ComputeColumn(); } - if(this.x < this.line.count) + x1 = this.x; + + if(x1 < line1.count) { - DelCh(this.line, this.y, this.x, this.line, this.y, this.x+1, false); + // Delete word + if(key.ctrl) + { + int i; + char * buffer = line1.buffer; + for(i = x1; i < line1.count; i++) + { + if(!IS_ALUNDER(buffer[i])) + break; + } + + for(; i < line1.count; i++) + { + // Delete trailing whitespace + if(IS_ALUNDER(buffer[i])) + break; + } + x2 = i; + } + else + x2 = x1 + 1; } - else if(this.line.next) + else { - DelCh(this.line, this.y, this.x, this.line.next, this.y+1, 0, false); + // Avoid creating trailing spaces if there is no content on next line + line2 = line1.next; + y2++; + if(line2 && !line2.count) + x1 = line1.count; + x2 = 0; } + if(line2) + _DelCh(line1, y1, x1, line2, y2, x2, false, false, null); SetViewToCursor(true); Modified(); } @@ -3548,6 +3842,8 @@ private: bool stuffAfter = false; char * addString; int len = 0; + /*bool resetX = false; + int backX;*/ if(style.stuckCaret) GoToEnd(true); if(style.readOnly) break; @@ -3562,19 +3858,31 @@ private: else break; } + + // Prevent adding trailing spaces if at the head of a line + /*if(c && c == this.x && c < this.line.count && this.x == this.selX && this.y == this.selY) + { + position = 0; + backX = this.x; + this.x = 0; + this.selX = 0; + resetX = true; + }*/ + if(!line.count) position = x; if(this.x < this.line.count) stuffAfter = true; - + //If last character is a { indent one tab - if(this.line.buffer[this.x - 1] == '{') + c = Min(x, line.count); + if(c > 0 && line.buffer[c - 1] == '{') { //Except if the next non space character is a } bool indent = false; int i; - for(i = this.x; i < this.line.size; i++) + for(i = c; i <= this.line.count; i++) // indent will be set to true on nul terminating char if(this.line.buffer[i] != ' ' && this.line.buffer[i] != '\t') { if(this.line.buffer[i] != '}') @@ -3606,9 +3914,27 @@ private: } addString[len] = '\0'; } + recordUndoEvent = true; if(AddS(addString)) { - if(!stuffAfter && style.freeCaret) + EditLine prevLine = this.line.prev; + if(prevLine) + { + // Nuke spaces if that is all that is left on previous line + int i; + char * buffer = prevLine.buffer; + for(i = 0; i < prevLine.count; i++) + if(buffer[i] != ' ' && buffer[i] != '\t') + break; + if(i == prevLine.count) + DelCh(prevLine, this.y - 1, 0, prevLine, this.y - 1, prevLine.count, false); + } + /*if(resetX) + { + this.x = this.selX = backX; + ComputeColumn(); + } + else */if(!stuffAfter && style.freeCaret) { this.x = this.selX = position; ComputeColumn(); @@ -3617,6 +3943,7 @@ private: SetViewToCursor(true); Modified(); } + recordUndoEvent = false; delete addString; return false; } @@ -3637,8 +3964,8 @@ private: bool foundAlpha = false; bool found = false; int y = this.y; - EditLine line, lastLine; - int lastC, lastY; + EditLine line, lastLine = null; + int lastC = 0, lastY = 0; for(line = this.line; (line && !found); line = line.prev, y--) { @@ -3676,14 +4003,14 @@ private: break; } } - while(--c) + while(--c >= 0) { byte ch = line.buffer[c]; if(UTF8_IS_FIRST(ch)) break; - } + } } - // No next word found, + // No next word found, if(!found && ( this.x > 0 || (!line.count && this.x))) { foundAlpha = true; @@ -3709,12 +4036,12 @@ private: { if(x <= line.count) { - byte * buffer = line.buffer; + byte * buffer = (byte *)line.buffer; while(--x) { byte ch = buffer[x]; if(UTF8_IS_FIRST(ch)) break; - } + } } else x--; @@ -3730,7 +4057,7 @@ private: } ComputeColumn(); } - if(!shift) Deselect(); + if(!shift) _Deselect(); SetViewToCursor(true); //break; return false; @@ -3759,18 +4086,18 @@ private: { bool foundAlpha = false; bool found = false; - EditLine line, lastLine; + EditLine line = null, lastLine = null; int y = this.y; - int lastC, lastY, lastNumBytes; - + int lastC = 0, lastY = 0, lastNumBytes = 0; + for(line = this.line; (line && !found); line = line.next, y++) { int start = (line == this.line) ? this.x : 0; int c; int numBytes; - for(c = start; c < line.count; c += numBytes) + unichar ch; + for(c = start; c < line.count && (ch = UTF8_GET_CHAR(line.buffer + c, numBytes)); c += numBytes) { - unichar ch = UTF8_GET_CHAR(line.buffer + c, numBytes); if(IS_ALUNDER(ch)) { foundAlpha = true; @@ -3794,7 +4121,7 @@ private: lastY = y; break; } - } + } if(found) { DirtyLine(this.y); @@ -3817,9 +4144,9 @@ private: int start = (line == this.line) ? this.x : 0; int c; int numBytes; - for(c = start; c < line.count; c += numBytes) + unichar ch; + for(c = start; c < line.count && (ch = UTF8_GET_CHAR(line.buffer + c, numBytes)); c += numBytes) { - unichar ch = UTF8_GET_CHAR(line.buffer + c, numBytes); if(!IS_ALUNDER(ch)) foundAlpha = true; else if(foundAlpha) @@ -3834,7 +4161,7 @@ private: break; } } - // No next word found, + // No next word found, if(!found && (c != this.x || line != this.line)) { found = true; @@ -3855,12 +4182,12 @@ private: { if(x < line.count) { - byte * buffer = line.buffer; + byte * buffer = (byte *)line.buffer; while(++x) { byte ch = buffer[x]; if(UTF8_IS_FIRST(ch)) break; - } + } } else x++; @@ -3880,7 +4207,7 @@ private: } } } - if(!shift) Deselect(); + if(!shift) _Deselect(); SetViewToCursor(true); // break; return false; @@ -3895,7 +4222,7 @@ private: else { if(style.stuckCaret) break; - + if(!shift) SelDirty(); DirtyLine(this.y); @@ -3908,9 +4235,9 @@ private: this.y--; this.x = AdjustXPosition(line, caretX, true, null, MAXINT, 0); } - + DirtyLine(this.y); - if(!shift) Deselect(); + if(!shift) _Deselect(); ComputeColumn(); SetViewToCursor(false); @@ -3961,7 +4288,7 @@ private: len = (nextSpace - (text + textPos)); else len = line.count - textPos; - + if(textPos < line.count) { display.FontExtent(font, text + textPos, len, &w, null); @@ -3996,7 +4323,7 @@ private: } DirtyLine(this.y); - if(!shift) Deselect(); + if(!shift) _Deselect(); ComputeColumn(); SetViewToCursor(false); return false; @@ -4014,7 +4341,7 @@ private: this.x = line.count; DirtyLine(this.y); - if(!shift) Deselect(); + if(!shift) _Deselect(); ComputeColumn(); SetViewToCursor(false); return false; @@ -4024,13 +4351,13 @@ private: } while(textPos < line.count); DirtyLine(this.y); - if(!shift) Deselect(); + if(!shift) _Deselect(); ComputeColumn(); SetViewToCursor(false); return false; } */ - + // PREVIOUS CODE /* if(this.line.prev) @@ -4043,7 +4370,7 @@ private: DirtyLine(this.y); this.x = x; - if(!shift) Deselect(); + if(!shift) _Deselect(); ComputeColumn(); @@ -4066,15 +4393,17 @@ private: { if(style.stuckCaret) break; { + /* int th = space.h; int textPos = 0; int sx = 0, sy = this.y * this.space.h; int maxW = clientSize.w - sx; char * text = line.buffer; + */ if(!shift) SelDirty(); DirtyLine(this.y); - + if(style.wrap) { /* @@ -4091,12 +4420,11 @@ private: this.x = AdjustXPosition(line, caretX, true, null, MAXINT, 0); } - if(!shift) Deselect(); + DirtyLine(this.y); + if(!shift) _Deselect(); ComputeColumn(); - if(this.selX != this.x || this.selY != this.y) - DirtyLine(this.y); SetViewToCursor(false); - + /* while(!textPos || (style.freeCaret || textPos 0 && !UTF8_IS_FIRST(text[--this.x])); - + len = this.x - startPos; display.FontExtent(font, text + startPos, len, &x, null); } - - if(!shift) Deselect(); + + if(!shift) _Deselect(); ComputeColumn(); SetViewToCursor(false); @@ -4165,12 +4493,12 @@ private: this.x = line.count; DirtyLine(this.y); - if(!shift) Deselect(); + if(!shift) _Deselect(); ComputeColumn(); SetViewToCursor(false); return false; - } + } else if(textPos >= line.count && line.next) { startPos = 0; @@ -4195,7 +4523,7 @@ private: this.x = Min(this.x, line.count); //int x = AdjustXPosition(this.line, this.line.next, true, null, MAXINT, 0); this.y++; - if(!shift) Deselect(); + if(!shift) _Deselect(); ComputeColumn(); if(this.selX != this.x || this.selY != this.y) @@ -4214,7 +4542,7 @@ private: DirtyLine(this.y); this.y++; this.x = x; - if(!shift) Deselect(); + if(!shift) _Deselect(); ComputeColumn(); if(this.selX != this.x || this.selY != this.y) @@ -4229,6 +4557,7 @@ private: case home: { if(style.stuckCaret) break; + if(!style.multiLine && key.ctrl) break; if(!(style.freeCaret)) this.selX = Min(this.selX, this.selLine.count); @@ -4251,22 +4580,22 @@ private: for(c=0; line.buffer[c]; c++) if(line.buffer[c] != ' ' && line.buffer[c] != '\t') break; - if(c != 0 || this.x) + if(overwrite || (shift && (c != 0 || this.x))) DirtyLine(this.y); - if(this.x != c) + if(this.x != c) this.x = c; else this.x = 0; } else { - /*if(this.x != 0) - DirtyLine(this.y);*/ + if(overwrite || (shift && this.x != 0)) + DirtyLine(this.y); this.x = 0; } ComputeColumn(); } - if(!shift) Deselect(); + if(!shift) _Deselect(); SetViewToCursor(true); //break; return false; @@ -4274,7 +4603,8 @@ private: case end: { if(style.stuckCaret) break; - if(!(style.freeCaret)) + if(!style.multiLine && key.ctrl) break; + if(!style.freeCaret) this.selX = Min(this.selX, this.selLine.count); if(!shift) SelDirty(); @@ -4285,10 +4615,11 @@ private: else if(this.x != this.line.count) { this.x = this.line.count; - //DirtyLine(this.y); + if(overwrite || shift) + DirtyLine(this.y); ComputeColumn(); } - if(!shift) Deselect(); + if(!shift) _Deselect(); SetViewToCursor(true); //break; return false; @@ -4351,7 +4682,7 @@ private: Record(action); } memmove(line.buffer,line.buffer+lastC,line.size-lastC); - if(!line.AdjustBuffer(line.count-lastC)) + if(!line.AdjustBuffer(line.count-lastC)) break; line.count-=lastC; DirtyLine(y); @@ -4374,7 +4705,7 @@ private: { BufferLocation before = { line, y, 0 }, after = { line, y, 1 }; - if(!line.AdjustBuffer(line.count+1)) + if(!line.AdjustBuffer(line.count+1)) break; NotifyCharsAdded(master, this, &before, &after, this.pasteOperation); @@ -4396,7 +4727,7 @@ private: BufferLocation before = { line, y, 0 }, after = { line, y, this.tabSize }; NotifyCharsAdded(master, this, &before, &after, this.pasteOperation); - if(!line.AdjustBuffer(line.count+this.tabSize)) + if(!line.AdjustBuffer(line.count+this.tabSize)) break; { @@ -4418,6 +4749,7 @@ private: if(line == lastLine) break; } } + ComputeLength(maxLine); } else { @@ -4437,7 +4769,7 @@ private: ComputeColumn(); } // Insert spaces - start = this.x; + start = Min(this.x, this.selX); for(c=start; ((c == start) || ((c) % this.tabSize)); c++) { addString[len++] = ' '; @@ -4453,76 +4785,85 @@ private: } break; case pageDown: - if(key.ctrl) + if(style.multiLine) { - if(!(style.hScroll) || hasHorzScroll) break; - if(this.viewX < this.maxLength) + if(key.ctrl) { - //this.viewX+=this.space.w*this.tabSize; - //DirtyAll(); - SetScrollPosition((this.viewX + this.space.w*this.tabSize), this.viewY * this.space.h); + if(!(style.hScroll) || hasHorzScroll) break; + if(this.viewX < this.maxLength) + { + //this.viewX+=this.space.w*this.tabSize; + //DirtyAll(); + SetScrollPosition((this.viewX + this.space.w*this.tabSize), this.viewY * this.space.h); + } } + else + { + PageDown(); + DirtyAll(); + if(!shift) _Deselect(); + SetCursorToViewX(); + SetCursorToViewY(); + } + return false; } - else - { - PageDown(); - DirtyAll(); - if(!shift) Deselect(); - SetCursorToViewX(); - SetCursorToViewY(); - } - return false; - // break; + break; case pageUp: - if(key.ctrl) + if(style.multiLine) { - if(!(style.hScroll) || hasHorzScroll) break; - if(this.viewX > 0) + if(key.ctrl) { - //this.viewX-=this.space.w*this.tabSize; - //this.viewX = Max(this.viewX,0); - //DirtyAll(); - SetScrollPosition((this.viewX-this.space.w*this.tabSize), this.viewY * this.space.h); - // SetCursorToView(); + if(!(style.hScroll) || hasHorzScroll) break; + if(this.viewX > 0) + { + //this.viewX-=this.space.w*this.tabSize; + //this.viewX = Max(this.viewX,0); + //DirtyAll(); + SetScrollPosition((this.viewX-this.space.w*this.tabSize), this.viewY * this.space.h); + // SetCursorToView(); + } } + else + { + PageUp(); + DirtyAll(); + if(!shift) _Deselect(); + SetCursorToViewX(); + SetCursorToViewY(); + } + return false; } - else - { - PageUp(); - DirtyAll(); - if(!shift) Deselect(); - SetCursorToViewX(); - SetCursorToViewY(); - } - // break; - return false; + break; case insert: if(key.ctrl) { Copy(); return false; } - else if(key.shift) - { - if(!(style.readOnly)) - Paste(); - return false; - } - else + else if(!style.readOnly) { - this.overwrite ^= 1; - UpdateCaretPosition(true); - if(this.overwrite) - SetCaret(0,0,0); - DirtyLine(this.y); - UpdateDirty(); - NotifyOvrToggle(master, this, this.overwrite); + if(key.shift) + { + if(!(style.readOnly)) + Paste(); + return false; + } + else + { + this.overwrite ^= 1; + UpdateCaretPosition(true); + if(this.overwrite) + SetCaret(0,0,0); + DirtyLine(this.y); + UpdateDirty(); + NotifyOvrToggle(master, this, this.overwrite); + } } break; - case hotKey: + case hotKey: break; default: - + switch(key) { case ctrlA: @@ -4533,7 +4874,7 @@ private: //Save current view position int tempX = this.viewX; int tempY = this.viewY; - + this.selX = 0; this.selY = 0; this.selLine = this.lines.first; @@ -4543,10 +4884,10 @@ private: ComputeColumn(); DirtyAll(); SetViewToCursor(true); - + //Restore previous view position SetScrollPosition(tempX, tempY * this.space.h); - + UpdateDirty(); SetSelectCursor(); SelectionEnables(); @@ -4589,14 +4930,14 @@ private: { //Only indent back if you are exactly at one tab. { - bool whitespace = true; + //bool whitespace = true; int i; char * newline; int putsize; - - int indentwidth; + + int indentwidth = 0; EditLine line = this.line; - + //Only remove one tab if there is nothing else on the line. for(i = 0; i < this.line.count; i++) { @@ -4606,13 +4947,13 @@ private: return false; } } - + //Find opening { i = 1; while(i && line) { int pos; - + indentwidth = 0; for(pos = line.count - 1; pos >= 0; pos--) { @@ -4631,35 +4972,36 @@ private: } line = line.prev; } - + //Place the } to get an undo: PutCh(ch); - + this.x = this.line.count; this.selX = 0; - + if(!style.useTab) putsize = indentwidth; else putsize = indentwidth / this.tabSize + indentwidth % this.tabSize; - + newline = new char[putsize+2]; newline[putsize] = '}'; newline[putsize+1] = '\0'; - + i = 0; if(style.useTab) for(; i < indentwidth / this.tabSize; i++) newline[i] = '\t'; for(;i < putsize; i++) newline[i] = ' '; - + AddS(newline); - + delete newline; } return false; - } else if(!key.ctrl && !key.alt && ch != 128 && ch >= 32) + } + else if(!key.ctrl && !key.alt && ch != 128 && ch >= 32) { PutCh(ch); return false; @@ -4706,7 +5048,7 @@ private: for(; position > this.viewY && this.viewLine.next; this.viewLine = this.viewLine.next, this.viewY++); FigureStartSyntaxStates(oldViewLine, false); } - + if(action != setRange) { if(!this.mouseMove && style.cursorFollowsView && !SelSize()) SetCursorToViewY(); @@ -4722,8 +5064,8 @@ private: int numLines = clientSize.h / this.space.h; int y; if(Abs(this.viewY - oldViewY) < numLines) - - + + if(this.viewY > oldViewY) { for(y = oldViewY; y clientSize.h + this.space.h)) && !(style.vScroll)) { // Make sure it fits, but we need a default line is this.font is too big for window if(this.space.h * (this.lineCount+1) > clientSize.h && this.line) @@ -4841,7 +5183,7 @@ private: length = this.line.count - endX; } } - if(!line.AdjustBuffer(length)) + if(!line.AdjustBuffer(length)) return false; if(this.line) { @@ -4864,14 +5206,14 @@ private: this.line = line; this.x = 0; this.col = 0; - - ComputeLength(this.line); + line.count = length; #ifdef _DEBUG if(length > 4000 || length < 0) printf("Warning"); #endif - line.count = length; + ComputeLength(this.line); + DirtyEnd(this.y); this.y++; this.lineCount++; @@ -4888,9 +5230,10 @@ private: char string[5]; int count = UTF32toUTF8Len(&ch, 1, string, 5); DelSel(&addedSpaces); - result = AddToLine(string, count, false, addedSpaces ? null : &addedSpaces, &addedTabs); + result = AddToLine(string, count, false, addedSpaces ? null : &addedSpaces, &addedTabs, &xAdjustment); if(addedSpacesPtr) *addedSpacesPtr = addedSpaces; if(addedTabsPtr) *addedTabsPtr = addedTabs; + if(xAdjustmentPtr) *xAdjustmentPtr = xAdjustment; } this.selX = this.x; this.selY = this.y; @@ -4906,6 +5249,7 @@ private: } if(addCharAction) { + addCharAction.x -= addedTabs * (tabSize-1); addCharAction.addedSpaces = addedSpaces; addCharAction.addedTabs = addedTabs; } @@ -4921,7 +5265,7 @@ public: bool AddCh(unichar ch) { - return _AddCh(ch, null, null); + return _AddCh(ch, null, null, null); } void Modified() @@ -4934,7 +5278,7 @@ public: void Delete(EditLine line1, int y1, int x1, EditLine line2, int y2, int x2) { Deselect(); - DelCh(line1, y1, x1, line2, y2, x2, false); + _DelCh(line1, y1, x1, line2, y2, x2, false, false, null); SetViewToCursor(true); UpdateDirty(); Modified(); @@ -4945,6 +5289,11 @@ public: undoBuffer.Undo(); itemEditUndo.disabled = undoBuffer.curAction == 0; itemEditRedo.disabled = undoBuffer.curAction == undoBuffer.count; + + UpdateDirty(); + SetSelectCursor(); + SelectionEnables(); + if(savedAction == undoBuffer.curAction) { modifiedDocument = false; @@ -4958,6 +5307,11 @@ public: undoBuffer.Redo(); itemEditUndo.disabled = undoBuffer.curAction == 0; itemEditRedo.disabled = undoBuffer.curAction == undoBuffer.count; + + UpdateDirty(); + SetSelectCursor(); + SelectionEnables(); + if(savedAction == undoBuffer.curAction) { modifiedDocument = false; @@ -5010,20 +5364,20 @@ public: } // BASIC OUTPUT - bool AddS(char * string) + bool AddS(const char * string) { if(this) { bool ret = true; - char * line; + const char * line; int c, count; - int addedSpaces = 0, addedTabs = 0; + int addedSpaces = 0, addedTabs = 0, xAdjustment = 0; AddTextAction action = null; ReplaceTextAction replaceAction = null; this.pasteOperation = true; - if(style.stuckCaret /*|EES_READONLY)*/ ) + if(style.stuckCaret /*|EES_READONLY)*/ ) GoToEnd(true); if(!undoBuffer.dontRecord) @@ -5032,7 +5386,7 @@ public: if(!style.multiLine) { int i; - char ch; + char ch; for(i = 0; (ch = placeString[i]); i++) if(ch == '\n') { @@ -5041,7 +5395,7 @@ public: break; } } - + if(selX != x || selY != y) { char * newString; @@ -5074,7 +5428,7 @@ public: action = AddTextAction { y1 = y, x1 = Min(this.line.count, x), string = placeString }; else action = AddTextAction { y1 = y, x1 = x, string = placeString }; - + Record(action); } else @@ -5090,7 +5444,7 @@ public: { if(string[c] == '\n' || string[c] == '\r') { - if(!AddToLine(line,count, true, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs)) + if(!AddToLine(line, count, true, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs, xAdjustment ? null : &xAdjustment)) { ret = false; break; @@ -5099,6 +5453,7 @@ public: { if(!AddCh('\n')) { + count = 0; ret = false; break; } @@ -5107,7 +5462,7 @@ public: count = 0; line = string+c+1; /* - if(string[c] == '\r' && *line == '\n') + if(string[c] == '\r' && *line == '\n') { line++; c++; @@ -5123,8 +5478,8 @@ public: // FindMaxLine(); // Add the line here - if(count) - if(!AddToLine(line,count,false, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs)) + if(ret && count) + if(!AddToLine(line,count,false, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs, xAdjustment ? null : &xAdjustment)) { ret = false; } @@ -5137,6 +5492,7 @@ public: action.x2 = x; action.addedSpaces = addedSpaces; action.addedTabs = addedTabs; + action.xAdjustment = xAdjustment; } else if(replaceAction) { @@ -5144,6 +5500,7 @@ public: replaceAction.x3 = x; replaceAction.addedSpaces = addedSpaces; replaceAction.addedTabs = addedTabs; + replaceAction.xAdjustment = xAdjustment; } UpdateCaretPosition(true); @@ -5171,18 +5528,18 @@ public: void PutCh(unichar ch) { bool result; - - if((ch >= 32 /*&& ch <=126*/) || ch == '\n') + + if((ch >= 32 /*&& ch <=126*/) || ch == '\n' || ch == '\t') //if((ch >= 32) || ch == '\n') { - int addedSpaces = 0, addedTabs = 0; + int addedSpaces = 0, addedTabs = 0, xAdjustment = 0; ReplaceTextAction replaceAction = null; AddCharAction addCharAction = null; if(style.allCaps) ch = (ch < 128) ? toupper(ch) : ch; // TODO: UNICODE TO UPPER - if(this.x < this.line.count && this.overwrite) + if(this.overwrite && selX == x && selY == y && this.x < this.line.count) { char buffer[5]; char * newString; @@ -5239,18 +5596,20 @@ public: } } undoBuffer.dontRecord++; - result = _AddCh(ch, &addedSpaces, &addedTabs); + result = _AddCh(ch, &addedSpaces, &addedTabs, &xAdjustment); if(replaceAction) { replaceAction.x3 = x; replaceAction.y3 = y; replaceAction.addedSpaces = addedSpaces; replaceAction.addedTabs = addedTabs; - } + replaceAction.addedTabs = xAdjustment; + } if(addCharAction) { addCharAction.addedSpaces = addedSpaces; addCharAction.addedTabs = addedTabs; + addCharAction.xAdjustment = xAdjustment; } undoBuffer.dontRecord--; if(ch == '\n') @@ -5260,7 +5619,7 @@ public: } } - void PutS(char * string) + void PutS(const char * string) { if(this) { @@ -5270,23 +5629,25 @@ public: } } - void Printf(char * format, ...) + void Printf(const char * format, ...) { if(this) { char temp[MAX_F_STRING]; va_list args; va_start(args, format); - vsprintf(temp, format, args); + vsnprintf(temp, sizeof(temp), format, args); + temp[sizeof(temp)-1] = 0; va_end(args); PutS(temp); } } - void SetContents(char * format, ...) + void SetContents(const char * format, ...) { if(this) { + undoBuffer.dontRecord++; Deselect(); DelCh(this.lines.first, 0, 0, this.lines.last, this.lineCount-1, ((EditLine)(this.lines.last)).count, true); if(format) @@ -5294,13 +5655,15 @@ public: char temp[MAX_F_STRING]; va_list args; va_start(args, format); - vsprintf(temp, format, args); + vsnprintf(temp, sizeof(temp), format, args); + temp[sizeof(temp)-1] = 0; va_end(args); AddS(temp); } UpdateDirty(); Home(); + undoBuffer.dontRecord--; } } @@ -5310,7 +5673,10 @@ public: { if(x > 0) { - x -= 1 + DelCh(line, y, x-1, line, y, x, true); + if(x > line.count) + x--; + else + x -= 1 + _DelCh(line, y, x-1, line, y, x, true, false, null); Modified(); } else if(this.line.prev) @@ -5319,7 +5685,7 @@ public: int x = line.count; int y = this.y; - DelCh(line, this.y-1, x, this.line, this.y, this.x, true); + _DelCh(line, this.y-1, x, this.line, this.y, this.x, true, false, null); this.line = line; this.y = y-1; this.x = x; @@ -5380,7 +5746,7 @@ public: DirtyLine(c); this.y = c; this.line = line; - Deselect(); + _Deselect(); SetViewToCursor(true); return true; } @@ -5388,6 +5754,7 @@ public: return false; } + // NOTE: Mismatch with NotifyCaretMove() for x/y + 1 bool GoToPosition(EditLine line, int y, int x) { /* @@ -5413,7 +5780,7 @@ public: this.y = y; this.line = line; ComputeColumn(); - Deselect(); + _Deselect(); SetViewToCursor(true); return true; } @@ -5425,8 +5792,7 @@ public: { if(created) { - int w; - int c, numLines; + int numLines; EditLine line; int x; int checkX, checkY; @@ -5438,7 +5804,7 @@ public: FixScrollArea(); selected = selX != this.x || selY != y; - + viewX = this.viewX; viewY = this.viewY; @@ -5486,7 +5852,7 @@ public: } } - if(!dontScroll) + if(!dontScroll) { if(style.vScroll) { @@ -5509,13 +5875,13 @@ public: for(;dropLine && dropLine.prev && dropY >= numLines;) { dropLine = dropLine.prev; - dropY--; + dropY--; } else for(;this.line && this.line.prev && this.y >= numLines;) { this.line = this.line.prev; - y--; + y--; } } @@ -5589,7 +5955,7 @@ public: } else { - EditLine oldLine = this.line; + //EditLine oldLine = this.line; bool lastOne = false; EditLine oldViewLine = this.viewLine; bool figureSyntax = false; @@ -5625,7 +5991,7 @@ public: { int c, numLines; EditLine line; - + if(this.y == 0) return; numLines = clientSize.h / this.space.h; @@ -5637,8 +6003,6 @@ public: } else { - EditLine oldLine = this.line; - for(c=0, line = this.line.prev; line && c