X-Git-Url: http://ecere.com/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=ecere%2Fsrc%2Fgui%2Fcontrols%2FEditBox.ec;h=a811a1bdc05864feff9850fc3e23bf979ccd1449;hb=b9b18a98221c71e28bd2b2f028a37750ea8538c5;hp=694e6fcd2ebe0b26e55906e2759644cccde5d073;hpb=0921371923ff8d4b822ddb0f0eca4740ed98119c;p=sdk diff --git a/ecere/src/gui/controls/EditBox.ec b/ecere/src/gui/controls/EditBox.ec index 694e6fc..a811a1b 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: @@ -179,6 +189,8 @@ public class UndoAction : struct { public: subclass(UndoAction) type; + bool continued; + virtual void Undo(void * data) { type.Undo(this, data); } virtual void Redo(void * data) { type.Redo(this, data); } #ifdef _DEBUG @@ -200,6 +212,8 @@ public: void * data; int dontRecord; bool insideRedo; + bool recordAsOne; + bool firstEvent; dontRecord = 0; @@ -210,35 +224,43 @@ public: void Undo() { - dontRecord++; - if(curAction > 0) + bool continued = true; + while(curAction > 0 && continued) { 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]; + 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) @@ -261,6 +283,12 @@ public: /*Print("Recording: "); action.Print(data);*/ #endif + if(recordAsOne) + { + if(!firstEvent && count > 0) + actions[count-1].continued = true; + firstEvent = false; + } actions[count++] = action; curAction = count; @@ -276,15 +304,18 @@ 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(); } @@ -306,7 +337,7 @@ static class AddTextAction : UndoAction { int y1, x1, y2, x2; char * string; - int addedSpaces, addedTabs; + int addedSpaces, addedTabs, xAdjustment; type = class(AddTextAction); #ifdef _DEBUG @@ -349,7 +380,7 @@ static class DelTextAction : UndoAction { int y1, x1, y2, x2; char * string; - bool placeAfter; + bool placeAfter, noHighlight; int addedSpaces; type = class(DelTextAction); @@ -367,8 +398,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); @@ -377,8 +411,11 @@ static class DelTextAction : UndoAction } else { - editBox.selY = y1; - editBox.selX = x1; + 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); @@ -415,7 +452,7 @@ static class ReplaceTextAction : UndoAction char * oldString; char * newString; bool placeAfter; - int addedSpaces, addedTabs; + int addedSpaces, addedTabs, xAdjustment; type = class(ReplaceTextAction); @@ -504,7 +541,7 @@ public class EditLine : struct int length; EditBox editBox; public: - property char * text + property const char * text { set { @@ -634,7 +671,7 @@ public struct BufferLocation public enum EditBoxFindResult { notFound, found, wrapped }; -static char * keyWords1[] = +static const char * keyWords1[] = { // C "return","break","continue","default","switch","case","if","else","for","while", "do","long","short", @@ -645,6 +682,7 @@ static char * keyWords1[] = "__declspec", "goto", "inline", "__inline__", "_inline", "__inline", "__typeof","__extension__", "asm", "__asm", "_asm", "volatile", "#cpu", "__stdcall__", + "__restrict__", "__restrict", "restrict", // eC "class", "private", "public", @@ -671,12 +709,14 @@ static char * keyWords1[] = null }; -static char * keyWords2[] = +static const char * keyWords2[] = { - "defined", "warning", null + "defined", "warning", + "include", "pragma", "elif", "ifdef", "ifndef", "endif", "undef", "line", + null }; -static char ** keyWords[] = { keyWords1, keyWords2 }; +static const char ** keyWords[] = { keyWords1, keyWords2 }; #define NUM_KEYWORD_GROUPS (sizeof(keyWords) / sizeof(char **)) //static int * keyLen[NUM_KEYWORD_GROUPS]; static int keyLen[NUM_KEYWORD_GROUPS][sizeof(keyWords1)]; @@ -769,7 +809,7 @@ public: property EditLine firstLine { get { return lines.first; } }; // Change these to a List... (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" set @@ -861,7 +901,7 @@ public: return null; } - void SetLineText(char * text) + void SetLineText(const char * text) { if(this) { @@ -872,6 +912,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) @@ -937,7 +978,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; @@ -1104,7 +1145,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); @@ -1170,9 +1211,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 }; @@ -1226,7 +1267,7 @@ private: lines.Free(EditLine::Free); } - void FlushBuffer(Surface surface, EditLine line, int wc, int * renderStart, int * x, int y, int numSpaces, bool drawSpaces, 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) @@ -1237,18 +1278,24 @@ 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 && (drawSpaces || 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; } @@ -1257,8 +1304,8 @@ private: } } - 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; @@ -1282,7 +1329,7 @@ private: if((style.stuckCaret && wc == line.count && !line.next) || (!mouseMove && line == this.line && wc == editX)) { - *overwrite = true; + *overwrite = 1; flush = true; } } @@ -1437,6 +1484,25 @@ private: } }*/ + 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; @@ -1454,9 +1520,9 @@ private: 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; @@ -1471,6 +1537,13 @@ private: 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; @@ -1521,7 +1594,7 @@ private: */ surface.SetForeground(foreground); surface.SetBackground(background); - surface.TextOpacity(opacity); + surface.TextOpacity(false); surface.GetBox(box); @@ -1533,7 +1606,7 @@ private: int start = 0; Color newTextColor = textColor = defaultTextColor; bool lineComplete = false; - + int overHang = 0; // ****** SYNTAX HIGHLIGHTING ****** bool lastWasStar = false; @@ -1560,6 +1633,64 @@ private: } */ + // 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); @@ -1749,25 +1880,29 @@ private: if(!wasEscaped) escaped = true; } - else if(!inQuotes && !inString && !inMultiLineComment && !inSingleLineComment && (isdigit(word[0]) || (word[0] == '.' && isdigit(word[1])))) + else if(x < box.right && !inQuotes && !inString && !inMultiLineComment && !inSingleLineComment && (isdigit(word[0]) || (word[0] == '.' && isdigit(word[1])))) { - char * dot = strchr(word, '.'); - bool isHex = (word[0] == '0' && (word[1] == 'x' || word[1] == 'X')); - char * exponent; - bool isReal; + char * dot = word[wordLen] == '.' ? word + wordLen : (word[0] == '.' && (word == line.buffer || word[-1] == '-' || isspace(word[-1])) ? word : null); + bool isReal = dot != null; char * s = null; - if(isHex) - { - exponent = strchr(word, 'p'); - if(!exponent) exponent = strchr(word, 'P'); - } + if(dot) + isReal = true; else { - exponent = strchr(word, 'e'); - if(!exponent) exponent = strchr(word, 'E'); + char * exponent; + bool isHex = (word[0] == '0' && (word[1] == 'x' || word[1] == 'X')); + if(isHex) + { + exponent = strchrmax(word, 'p', wordLen); + if(!exponent) exponent = strchrmax(word, 'P', wordLen); + } + else + { + exponent = strchrmax(word, 'e', wordLen); + if(!exponent) exponent = strchrmax(word, 'E', wordLen); + } + isReal = exponent != null; } - if(dot && dot > word + wordLen) dot = null; - isReal = dot || exponent; if(isReal) strtod(word, &s); // strtod() seems to break on hex floats (e.g. 0x23e3p12, 0x1.fp3) else @@ -1787,7 +1922,7 @@ private: case 'f': case 'F': gotF++; if(gotF > 1 || !isReal) valid = false; break; case 'l': case 'L': gotL++; - if(gotL > 2 || isReal || (gotL == 2 && (s[i-1] != ch))) + 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; @@ -1829,14 +1964,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++) { @@ -1892,7 +2027,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 @@ -1921,13 +2057,14 @@ private: 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 = ' '; @@ -1937,8 +2074,9 @@ private: { flagTrailingSpace = numSpaces && trailingSpace && style.syntax && start + bufferLen == line.count && line != this.line; if(flagTrailingSpace) surface.SetBackground(red); - FlushBuffer(surface, line, wc, &renderStart, &x, y, numSpaces, flagTrailingSpace, box); - if(overWrite == true) + FlushBuffer(surface, line, wc, &renderStart, &x, y, &previousGlyph, &overHang, numSpaces, flagTrailingSpace, box); + if(flagTrailingSpace) surface.SetBackground(background); + if(overWrite == 1) { overWriteX = x; overWriteY = y; @@ -1946,8 +2084,6 @@ private: } numSpaces = 0; - surface.TextOpacity(opacity); - surface.SetBackground(background); surface.SetForeground(foreground); flush = false; @@ -1967,7 +2103,8 @@ private: } flagTrailingSpace = numSpaces && trailingSpace && style.syntax && start + bufferLen == line.count && line != this.line; if(flagTrailingSpace) surface.SetBackground(red); - FlushBuffer(surface, line, wc, &renderStart, &x, y, numSpaces, flagTrailingSpace, box); + FlushBuffer(surface, line, wc, &renderStart, &x, y, &previousGlyph, &overHang, numSpaces, flagTrailingSpace, box); + if(flagTrailingSpace) surface.SetBackground(background); start += bufferLen; } } @@ -1975,33 +2112,17 @@ 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) - { - 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); - } - - - /* - if(style.freeCaret && selected) - { - surface.SetBackground(selectionBackground); - surface.Area(x + XOFFSET - 1,y,clientSize.w-1,y+this.space.h-1); - } - */ if(line.count && line.text[line.count - 1] == '\\') { continuedSingleLineComment = inSingleLineComment; @@ -2058,8 +2179,6 @@ private: void ComputeLength(EditLine line) { int c; - int tabOccur = 0; - int tabWidth; int x = 0; for(c = 0; c < line.count; ) @@ -2094,7 +2213,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 { @@ -2159,9 +2281,9 @@ private: this.col = position; } - int DelCh(EditLine l1, int y1, int c1, EditLine l2, int y2, int c2, bool placeAfter) + void DelCh(EditLine l1, int y1, int c1, EditLine l2, int y2, int c2, bool placeAfter) { - return _DelCh(l1, y1, c1, l2, y2, c2, placeAfter, null); + _DelCh(l1, y1, c1, l2, y2, c2, placeAfter, true, null); } bool HasCommentOrEscape(EditLine line) @@ -2186,7 +2308,7 @@ 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; @@ -2235,7 +2357,7 @@ private: 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); } @@ -2260,14 +2382,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; + // TODO: Better handling of these allocation failures if(!line.AdjustBuffer(newLineCount)) - return; + return extras; #ifdef _DEBUG /*if(newLineCount > 4000 || newLineCount < 0) @@ -2407,28 +2531,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; @@ -2439,7 +2563,7 @@ 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 @@ -2465,7 +2589,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) @@ -2481,8 +2605,9 @@ 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; @@ -2499,6 +2624,7 @@ private: { int addedSpaces = 0; int addedTabs = 0; + int xAdjustment = 0; // Add blank spaces if EES_FREECARET if(this.x > line.count) @@ -2525,6 +2651,8 @@ private: addedSpaces = wantedPosition - position; else { + xAdjustment = wantedPosition - position; + // Put a first tab addedTabs = 1; position += this.tabSize - (position % this.tabSize); @@ -2533,6 +2661,8 @@ private: position += (addedTabs-1) * this.tabSize; // Finish off with spaces addedSpaces = wantedPosition - position; + + xAdjustment -= addedSpaces + addedTabs; } } else @@ -2561,7 +2691,6 @@ private: 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) @@ -2569,8 +2698,7 @@ private: #endif line.count += addedTabs; } - else if(addedTabs) - *addedTabsPtr = 0; + if(addedSpaces) { FillBytes(line.buffer+line.count,' ',addedSpaces); @@ -2579,10 +2707,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"); @@ -2663,9 +2792,8 @@ private: // 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; @@ -2809,7 +2937,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; @@ -2852,7 +2980,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 { @@ -2865,11 +2996,15 @@ private: 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(); @@ -2924,7 +3059,6 @@ private: while(true) { int start = c; - int numBytes = 1; int len = 1; int w; if(c < Min(max, line.count)) @@ -2954,7 +3088,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 { @@ -2979,7 +3116,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; @@ -3069,7 +3209,7 @@ private: } /* - bool SaveFile(char * fileName) + bool SaveFile(const char * fileName) { File f = eFile_Open(fileName, FO_WRITE); if(f) @@ -3305,12 +3445,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(); @@ -3495,8 +3639,9 @@ private: { if(FontExtent) { - FontExtent(display, font, " ", 1, (int *)&space.w, (int *)&space.h); - FontExtent(display, font, "W", 1, (int *)&large.w, (int *)&large.h); + int oh; + FontExtent(display, font, " ", 1, (int *)&space.w, (int *)&space.h, 0, null, &oh); + FontExtent(display, font, "W", 1, (int *)&large.w, (int *)&large.h, 0, null, &oh); space.w = Max(space.w, 1); large.w = Max(large.w, 1); @@ -3521,7 +3666,7 @@ private: bool OnLoadGraphics() { - FontExtent = Display::FontExtent; + FontExtent = Display::FontExtent2; font = fontObject; ComputeFont(); // UpdateCaretPosition(true); @@ -3560,10 +3705,10 @@ private: int y; bool done = false; EditLine line = this.line; - int c; + int c = 0; for(y = this.y; y>= 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; @@ -3590,9 +3735,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; @@ -3623,51 +3769,52 @@ private: SetViewToCursor(true); Modified(); } - // Delete word - else if(key.ctrl) - { - if(this.x < this.line.count) - { - int i; - int length; - for(i = this.x; i < this.line.count; i++) - { - if(!IS_ALUNDER(this.line.buffer[i])) - break; - } - - 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, i, false); - 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 { - 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(); } @@ -3684,6 +3831,8 @@ private: bool stuffAfter = false; char * addString; int len = 0; + /*bool resetX = false; + int backX;*/ if(style.stuckCaret) GoToEnd(true); if(style.readOnly) break; @@ -3698,6 +3847,17 @@ 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; @@ -3705,12 +3865,13 @@ private: 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] != '}') @@ -3742,9 +3903,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(); @@ -3753,6 +3932,7 @@ private: SetViewToCursor(true); Modified(); } + recordUndoEvent = false; delete addString; return false; } @@ -3773,8 +3953,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--) { @@ -3812,7 +3992,7 @@ private: break; } } - while(--c) + while(--c >= 0) { byte ch = line.buffer[c]; if(UTF8_IS_FIRST(ch)) break; @@ -3845,7 +4025,7 @@ private: { if(x <= line.count) { - byte * buffer = line.buffer; + byte * buffer = (byte *)line.buffer; while(--x) { byte ch = buffer[x]; @@ -3895,9 +4075,9 @@ 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++) { @@ -3991,7 +4171,7 @@ private: { if(x < line.count) { - byte * buffer = line.buffer; + byte * buffer = (byte *)line.buffer; while(++x) { byte ch = buffer[x]; @@ -4202,11 +4382,13 @@ 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); @@ -4387,7 +4569,7 @@ private: for(c=0; line.buffer[c]; c++) if(line.buffer[c] != ' ' && line.buffer[c] != '\t') break; - if(shift && (c != 0 || this.x)) + if(overwrite || (shift && (c != 0 || this.x))) DirtyLine(this.y); if(this.x != c) this.x = c; @@ -4396,7 +4578,7 @@ private: } else { - if(shift && this.x != 0) + if(overwrite || (shift && this.x != 0)) DirtyLine(this.y); this.x = 0; } @@ -4422,7 +4604,7 @@ private: else if(this.x != this.line.count) { this.x = this.line.count; - if(shift) + if(overwrite || shift) DirtyLine(this.y); ComputeColumn(); } @@ -4647,21 +4829,24 @@ private: Copy(); return false; } - else if(key.shift) + else if(!style.readOnly) { - 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); + 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: @@ -4734,12 +4919,12 @@ 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. @@ -4893,14 +5078,14 @@ private: UpdateDirty(); } - bool _AddCh(unichar ch, int * addedSpacesPtr, int * addedTabsPtr) + bool _AddCh(unichar ch, int * addedSpacesPtr, int * addedTabsPtr, int * xAdjustmentPtr) { EditLine line; - int length, endX; + int length, endX = 0; bool result; ReplaceTextAction replaceAction = null; AddCharAction addCharAction = null; - int addedSpaces = 0, addedTabs = 0; + int addedSpaces = 0, addedTabs = 0, xAdjustment = 0; if(ch == '\r') return true; if(style.stuckCaret /*|EES_READONLY)*/ ) @@ -5034,9 +5219,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; @@ -5068,7 +5254,7 @@ public: bool AddCh(unichar ch) { - return _AddCh(ch, null, null); + return _AddCh(ch, null, null, null); } void Modified() @@ -5081,7 +5267,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(); @@ -5092,6 +5278,11 @@ public: undoBuffer.Undo(); itemEditUndo.disabled = undoBuffer.curAction == 0; itemEditRedo.disabled = undoBuffer.curAction == undoBuffer.count; + + UpdateDirty(); + SetSelectCursor(); + SelectionEnables(); + if(savedAction == undoBuffer.curAction) { modifiedDocument = false; @@ -5105,6 +5296,11 @@ public: undoBuffer.Redo(); itemEditUndo.disabled = undoBuffer.curAction == 0; itemEditRedo.disabled = undoBuffer.curAction == undoBuffer.count; + + UpdateDirty(); + SetSelectCursor(); + SelectionEnables(); + if(savedAction == undoBuffer.curAction) { modifiedDocument = false; @@ -5157,14 +5353,14 @@ 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; @@ -5237,7 +5433,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; @@ -5272,7 +5468,7 @@ public: // Add the line here if(ret && count) - if(!AddToLine(line,count,false, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs)) + if(!AddToLine(line,count,false, addedSpaces ? null : &addedSpaces, addedTabs ? null : &addedTabs, xAdjustment ? null : &xAdjustment)) { ret = false; } @@ -5285,6 +5481,7 @@ public: action.x2 = x; action.addedSpaces = addedSpaces; action.addedTabs = addedTabs; + action.xAdjustment = xAdjustment; } else if(replaceAction) { @@ -5292,6 +5489,7 @@ public: replaceAction.x3 = x; replaceAction.addedSpaces = addedSpaces; replaceAction.addedTabs = addedTabs; + replaceAction.xAdjustment = xAdjustment; } UpdateCaretPosition(true); @@ -5320,10 +5518,10 @@ public: { 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; @@ -5387,19 +5585,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.x -= addedTabs * (tabSize-1); addCharAction.addedSpaces = addedSpaces; addCharAction.addedTabs = addedTabs; + addCharAction.xAdjustment = xAdjustment; } undoBuffer.dontRecord--; if(ch == '\n') @@ -5409,7 +5608,7 @@ public: } } - void PutS(char * string) + void PutS(const char * string) { if(this) { @@ -5419,7 +5618,7 @@ public: } } - void Printf(char * format, ...) + void Printf(const char * format, ...) { if(this) { @@ -5433,7 +5632,7 @@ public: } } - void SetContents(char * format, ...) + void SetContents(const char * format, ...) { if(this) { @@ -5463,7 +5662,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) @@ -5472,7 +5674,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; @@ -5541,6 +5743,7 @@ public: return false; } + // NOTE: Mismatch with NotifyCaretMove() for x/y + 1 bool GoToPosition(EditLine line, int y, int x) { /* @@ -5578,8 +5781,7 @@ public: { if(created) { - int w; - int c, numLines; + int numLines; EditLine line; int x; int checkX, checkY; @@ -5742,7 +5944,7 @@ public: } else { - EditLine oldLine = this.line; + //EditLine oldLine = this.line; bool lastOne = false; EditLine oldViewLine = this.viewLine; bool figureSyntax = false; @@ -5790,8 +5992,6 @@ public: } else { - EditLine oldLine = this.line; - for(c=0, line = this.line.prev; line && c=-1; c--) - { - if(c == -1 || !isspace(line.buffer[c])) - { - c++; - line.buffer[c] = '\0'; - line.count -= (line.count - c); - break; - } - } - } - f.Write(line.buffer, line.count,1); + f.Write(line.buffer, line.count, 1); if(line.next) { if(cr) f.Putc('\r'); @@ -6170,7 +6356,7 @@ public: itemEditRedo.disabled = undoBuffer.curAction == undoBuffer.count; } - EditBoxFindResult Find(char * text, bool matchWord, bool matchCase, bool isSearchDown) + EditBoxFindResult Find(const char * text, bool matchWord, bool matchCase, bool isSearchDown) { EditLine line; int num; @@ -6228,7 +6414,7 @@ public: return notFound; } - EditBoxFindResult FindInSelection(char * text, bool matchWord, bool matchCase, EditLine l2, int y2, int x2) + EditBoxFindResult FindInSelection(const char * text, bool matchWord, bool matchCase, EditLine l2, int y2, int x2) { EditLine line; int y; @@ -6463,7 +6649,7 @@ public: return result; } - bool Puts(char * string) + bool Puts(const char * string) { EditBox editBox = this.editBox; BufferLocation start { editBox.line, editBox.y, editBox.x }; @@ -6493,7 +6679,7 @@ public: { utf8Bytes[numBytes++] = ch; utf8Bytes[numBytes] = 0; - if(UTF8Validate(utf8Bytes)) + if(UTF8Validate((char *)utf8Bytes)) { editBox.AddCh(UTF8_GET_CHAR(utf8Bytes, numBytes)); numBytes = 0; @@ -6543,7 +6729,7 @@ public: start.AdjustDelete(pos, end); sel.AdjustDelete(pos, end); - editBox.DelCh(pos.line, pos.y, pos.x, end.line, end.y, end.x, true); + editBox._DelCh(pos.line, pos.y, pos.x, end.line, end.y, end.x, true, false, null); } } };