| 1 | // This file is part of SmallBASIC | 
|---|
| 2 | // | 
|---|
| 3 | // Copyright(C) 2001-2020 Chris Warren-Smith. | 
|---|
| 4 | // | 
|---|
| 5 | // This program is distributed under the terms of the GPL v2.0 or later | 
|---|
| 6 | // Download the GNU Public License (GPL) from www.gnu.org | 
|---|
| 7 | // | 
|---|
| 8 |  | 
|---|
| 9 | #ifndef TEXTEDIT_H | 
|---|
| 10 | #define TEXTEDIT_H | 
|---|
| 11 |  | 
|---|
| 12 | #define STB_TEXTEDIT_CHARTYPE char | 
|---|
| 13 | #define STB_TEXTEDIT_UNDOCHARCOUNT 5000 | 
|---|
| 14 | #define MARGIN_CHARS 4 | 
|---|
| 15 | #define MAX_MARKERS 10 | 
|---|
| 16 |  | 
|---|
| 17 | #include <config.h> | 
|---|
| 18 | #include <stdlib.h> | 
|---|
| 19 | #include <string.h> | 
|---|
| 20 | #include <ctype.h> | 
|---|
| 21 | #include "lib/stb/stb_textedit.h" | 
|---|
| 22 | #include "ui/inputs.h" | 
|---|
| 23 | #include "ui/theme.h" | 
|---|
| 24 | #include "common/smbas.h" | 
|---|
| 25 | #include "common/keymap.h" | 
|---|
| 26 |  | 
|---|
| 27 | struct TextEditInput; | 
|---|
| 28 |  | 
|---|
| 29 | struct StackTraceNode { | 
|---|
| 30 | StackTraceNode(const char *keyword, int type, int line) | 
|---|
| 31 | : _keyword(keyword), _type(type), _line(line) {} | 
|---|
| 32 | virtual ~StackTraceNode() {} | 
|---|
| 33 | const char *_keyword; | 
|---|
| 34 | int _type; | 
|---|
| 35 | int _line; | 
|---|
| 36 | }; | 
|---|
| 37 |  | 
|---|
| 38 | typedef strlib::List<StackTraceNode *> StackTrace; | 
|---|
| 39 |  | 
|---|
| 40 | struct EditBuffer { | 
|---|
| 41 | char *_buffer; | 
|---|
| 42 | int _len; | 
|---|
| 43 | int _size; | 
|---|
| 44 | int _lines; | 
|---|
| 45 | TextEditInput *_in; | 
|---|
| 46 |  | 
|---|
| 47 | EditBuffer(TextEditInput *in, const char *text); | 
|---|
| 48 | virtual ~EditBuffer(); | 
|---|
| 49 |  | 
|---|
| 50 | void append(const char *text, int len) { insertChars(_len, text, len); } | 
|---|
| 51 | void append(const char *text) { insertChars(_len, text, strlen(text)); } | 
|---|
| 52 | void clear(); | 
|---|
| 53 | int  countNewlines(const char *text, int num); | 
|---|
| 54 | int  deleteChars(int pos, int num); | 
|---|
| 55 | char getChar(int pos); | 
|---|
| 56 | int  insertChars(int pos, const char *text, int num); | 
|---|
| 57 | int  lineCount(); | 
|---|
| 58 | void removeTrailingSpaces(STB_TexteditState *state); | 
|---|
| 59 | char *(int start, int end); | 
|---|
| 60 | }; | 
|---|
| 61 |  | 
|---|
| 62 | struct TextEditInput : public FormEditInput { | 
|---|
| 63 | TextEditInput(const char *text, int chW, int chH, int x, int y, int w, int h); | 
|---|
| 64 | virtual ~TextEditInput(); | 
|---|
| 65 |  | 
|---|
| 66 | void append(const char *text, int len) { _buf.append(text, len); } | 
|---|
| 67 | void completeWord(const char *word); | 
|---|
| 68 | const char *completeKeyword(int index); | 
|---|
| 69 | void draw(int x, int y, int w, int h, int chw); | 
|---|
| 70 | bool edit(int key, int screenWidth, int charWidth); | 
|---|
| 71 | bool find(const char *word, bool next); | 
|---|
| 72 | int  getCursorPos() const { return _state.cursor; } | 
|---|
| 73 | int  getCol() const { return _cursorCol; } | 
|---|
| 74 | int  getRow() const { return _cursorRow + 1; } | 
|---|
| 75 | int  () const { return _height / _charHeight; } | 
|---|
| 76 | int  getLines() { return _buf.lineCount(); } | 
|---|
| 77 | int  getMarginWidth() { return _marginWidth; } | 
|---|
| 78 | void getSelectionCounts(int *lines, int *chars); | 
|---|
| 79 | int  getSelectionRow(); | 
|---|
| 80 | int  getSelectionStart() { return _state.select_start; } | 
|---|
| 81 | int  getScroll() const { return _scroll; } | 
|---|
| 82 | const char *getText() const { return _buf._buffer; } | 
|---|
| 83 | char *getTextSelection(bool selectAll); | 
|---|
| 84 | int  getTextLength() const { return _buf._len; } | 
|---|
| 85 | int *getMarkers(); | 
|---|
| 86 | void gotoLine(const char *buffer); | 
|---|
| 87 | void reload(const char *text); | 
|---|
| 88 | bool save(const char *filePath); | 
|---|
| 89 | void setCursor(int pos); | 
|---|
| 90 | void setCursorPos(int pos); | 
|---|
| 91 | void setCursorRow(int row); | 
|---|
| 92 | void setLineNumbers() { _marginWidth = 1 + (_charWidth * MARGIN_CHARS); } | 
|---|
| 93 | void setText(const char *text) { _buf.clear(); _buf.append(text); } | 
|---|
| 94 | void setTheme(EditTheme *theme) { _theme = theme; } | 
|---|
| 95 | void clicked(int x, int y, bool pressed); | 
|---|
| 96 | void updateField(var_p_t form); | 
|---|
| 97 | bool updateUI(var_p_t form, var_p_t field); | 
|---|
| 98 | bool selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw); | 
|---|
| 99 | int  padding(bool) const { return 0; } | 
|---|
| 100 | void layout(StbTexteditRow *row, int start_i) const; | 
|---|
| 101 | int  charWidth(int k, int i) const; | 
|---|
| 102 | char *copy(bool cut); | 
|---|
| 103 | void paste(const char *text); | 
|---|
| 104 | void selectAll(); | 
|---|
| 105 | bool isDirty() { return _dirty && _state.undostate.undo_point > 0; } | 
|---|
| 106 | void setDirty(bool dirty) { _dirty = dirty; } | 
|---|
| 107 | void layout(int w, int h); | 
|---|
| 108 | const char *getNodeId(); | 
|---|
| 109 | char *getWordBeforeCursor(); | 
|---|
| 110 | bool replaceNext(const char *text, bool skip); | 
|---|
| 111 | int  getCompletions(StringList *list, int max); | 
|---|
| 112 | void selectNavigate(bool up); | 
|---|
| 113 | EditTheme *getTheme() { return _theme; } | 
|---|
| 114 |  | 
|---|
| 115 | protected: | 
|---|
| 116 | enum SyntaxState { | 
|---|
| 117 | kReset = 0, | 
|---|
| 118 | , | 
|---|
| 119 | kText, | 
|---|
| 120 | kCommand, | 
|---|
| 121 | kStatement, | 
|---|
| 122 | kDigit, | 
|---|
| 123 | }; | 
|---|
| 124 |  | 
|---|
| 125 | void dragPage(int y, bool &redraw); | 
|---|
| 126 | void drawText(int x, int y, const char *str, int length, SyntaxState &state); | 
|---|
| 127 | void calcMargin(); | 
|---|
| 128 | void changeCase(); | 
|---|
| 129 | void cycleTheme(); | 
|---|
| 130 | void drawLineNumber(int x, int y, int row, bool selected); | 
|---|
| 131 | void editDeleteLine(); | 
|---|
| 132 | void editEnter(); | 
|---|
| 133 | void editTab(); | 
|---|
| 134 | bool endStatement(const char *buf); | 
|---|
| 135 | void findMatchingBrace(); | 
|---|
| 136 | int  getCursorRow(); | 
|---|
| 137 | uint32_t getHash(const char *str, int offs, int &count); | 
|---|
| 138 | int  getIndent(char *spaces, int len, int pos); | 
|---|
| 139 | int  getLineChars(StbTexteditRow *row, int pos); | 
|---|
| 140 | char *getSelection(int *start, int *end); | 
|---|
| 141 | void gotoNextMarker(); | 
|---|
| 142 | void killWord(); | 
|---|
| 143 | void lineNavigate(bool lineDown); | 
|---|
| 144 | char *lineText(int pos); | 
|---|
| 145 | int  lineEnd(int pos) { return linePos(pos, true); } | 
|---|
| 146 | int  linePos(int pos, bool end, bool excludeBreak=true); | 
|---|
| 147 | int  lineStart(int pos) { return linePos(pos, false); } | 
|---|
| 148 | bool matchCommand(uint32_t hash); | 
|---|
| 149 | bool matchStatement(uint32_t hash); | 
|---|
| 150 | void pageNavigate(bool pageDown, bool shift); | 
|---|
| 151 | void removeTrailingSpaces(); | 
|---|
| 152 | void selectWord(); | 
|---|
| 153 | void setColor(SyntaxState &state); | 
|---|
| 154 | void toggleMarker(); | 
|---|
| 155 | void updateScroll(); | 
|---|
| 156 | int wordEnd(); | 
|---|
| 157 | int wordStart(); | 
|---|
| 158 |  | 
|---|
| 159 | EditBuffer _buf; | 
|---|
| 160 | STB_TexteditState _state; | 
|---|
| 161 | EditTheme *_theme; | 
|---|
| 162 | int _charWidth; | 
|---|
| 163 | int _charHeight; | 
|---|
| 164 | int _marginWidth; | 
|---|
| 165 | int _scroll; | 
|---|
| 166 | int _cursorCol; | 
|---|
| 167 | int _cursorRow; | 
|---|
| 168 | int _cursorLine; | 
|---|
| 169 | int _indentLevel; | 
|---|
| 170 | int _matchingBrace; | 
|---|
| 171 | int _ptY; | 
|---|
| 172 | int _pressTick; | 
|---|
| 173 | int _xmargin; | 
|---|
| 174 | int _ymargin; | 
|---|
| 175 | bool _bottom; | 
|---|
| 176 | bool _dirty; | 
|---|
| 177 | }; | 
|---|
| 178 |  | 
|---|
| 179 | struct TextEditHelpWidget : public TextEditInput { | 
|---|
| 180 | TextEditHelpWidget(TextEditInput *editor, int chW, int chH, bool overlay=true); | 
|---|
| 181 | virtual ~TextEditHelpWidget(); | 
|---|
| 182 |  | 
|---|
| 183 | enum HelpMode { | 
|---|
| 184 | kNone, | 
|---|
| 185 | kHelp, | 
|---|
| 186 | kHelpKeyword, | 
|---|
| 187 | kCompletion, | 
|---|
| 188 | kOutline, | 
|---|
| 189 | kSearch, | 
|---|
| 190 | kEnterReplace, | 
|---|
| 191 | kEnterReplaceWith, | 
|---|
| 192 | kReplace, | 
|---|
| 193 | kReplaceDone, | 
|---|
| 194 | kGotoLine, | 
|---|
| 195 | kMessage, | 
|---|
| 196 | kLineEdit, | 
|---|
| 197 | kStacktrace | 
|---|
| 198 | }; | 
|---|
| 199 |  | 
|---|
| 200 | void clicked(int x, int y, bool pressed); | 
|---|
| 201 | void createCompletionHelp(); | 
|---|
| 202 | void createGotoLine(); | 
|---|
| 203 | void createHelp(); | 
|---|
| 204 | void createLineEdit(const char *value); | 
|---|
| 205 | void createKeywordIndex(); | 
|---|
| 206 | void createMessage() { reset(kMessage); } | 
|---|
| 207 | void createOutline(); | 
|---|
| 208 | void createSearch(bool replace); | 
|---|
| 209 | void createStackTrace(const char *error, int line, StackTrace &trace); | 
|---|
| 210 | void draw(int x, int y, int w, int h, int chw); | 
|---|
| 211 | bool edit(int key, int screenWidth, int charWidth); | 
|---|
| 212 | void paste(const char *text); | 
|---|
| 213 | bool isDrawTop() { return true; } | 
|---|
| 214 | void reset(HelpMode mode); | 
|---|
| 215 | void cancelMode() { _mode = kNone; } | 
|---|
| 216 | bool closeOnEnter() const; | 
|---|
| 217 | bool searchMode() const { return _mode >= kSearch && _mode <= kReplaceDone; } | 
|---|
| 218 | void layout(int w, int h); | 
|---|
| 219 | bool lineEditMode() const { return _mode == kLineEdit; } | 
|---|
| 220 | bool messageMode() const { return _mode == kMessage; } | 
|---|
| 221 | bool replaceMode() const { return _mode == kReplace; } | 
|---|
| 222 | bool replaceModeWith() const { return _mode == kEnterReplaceWith; } | 
|---|
| 223 | bool replaceDoneMode() const { return _mode == kReplaceDone; } | 
|---|
| 224 | bool selected(MAPoint2d pt, int scrollX, int scrollY, bool &redraw); | 
|---|
| 225 | void (int cols, int rows); | 
|---|
| 226 | void (); | 
|---|
| 227 | void toggleKeyword(); | 
|---|
| 228 |  | 
|---|
| 229 | private: | 
|---|
| 230 | void completeLine(int pos); | 
|---|
| 231 | void completeWord(int pos); | 
|---|
| 232 | void createPackageIndex(); | 
|---|
| 233 |  | 
|---|
| 234 | HelpMode _mode; | 
|---|
| 235 | strlib::List<int *> _outline; | 
|---|
| 236 | TextEditInput *_editor; | 
|---|
| 237 | const char *_openPackage; | 
|---|
| 238 | int _openKeyword; | 
|---|
| 239 | enum Layout { | 
|---|
| 240 | kLine, | 
|---|
| 241 | , | 
|---|
| 242 | , | 
|---|
| 243 | } _layout; | 
|---|
| 244 | }; | 
|---|
| 245 |  | 
|---|
| 246 | #define STB_TEXTEDIT_STRING       EditBuffer | 
|---|
| 247 | #define STB_TEXTEDIT_K_LEFT       SB_KEY_LEFT | 
|---|
| 248 | #define STB_TEXTEDIT_K_RIGHT      SB_KEY_RIGHT | 
|---|
| 249 | #define STB_TEXTEDIT_K_UP         SB_KEY_UP | 
|---|
| 250 | #define STB_TEXTEDIT_K_DOWN       SB_KEY_DOWN | 
|---|
| 251 | #define STB_TEXTEDIT_K_LINESTART  SB_KEY_HOME | 
|---|
| 252 | #define STB_TEXTEDIT_K_LINEEND    SB_KEY_END | 
|---|
| 253 | #define STB_TEXTEDIT_K_DELETE     SB_KEY_DELETE | 
|---|
| 254 | #define STB_TEXTEDIT_K_BACKSPACE  SB_KEY_BACKSPACE | 
|---|
| 255 | #define STB_TEXTEDIT_K_TEXTSTART  SB_KEY_CTRL(SB_KEY_HOME) | 
|---|
| 256 | #define STB_TEXTEDIT_K_TEXTEND    SB_KEY_CTRL(SB_KEY_END) | 
|---|
| 257 | #define STB_TEXTEDIT_K_UNDO       SB_KEY_CTRL('z') | 
|---|
| 258 | #define STB_TEXTEDIT_K_REDO       SB_KEY_CTRL('y') | 
|---|
| 259 | #define STB_TEXTEDIT_K_INSERT     SB_KEY_INSERT | 
|---|
| 260 | #define STB_TEXTEDIT_K_WORDLEFT   SB_KEY_CTRL(SB_KEY_LEFT) | 
|---|
| 261 | #define STB_TEXTEDIT_K_WORDRIGHT  SB_KEY_CTRL(SB_KEY_RIGHT) | 
|---|
| 262 | #define STB_TEXTEDIT_K_PGUP       SB_KEY_PGUP | 
|---|
| 263 | #define STB_TEXTEDIT_K_PGDOWN     SB_KEY_PGDN | 
|---|
| 264 | #define STB_TEXTEDIT_NEWLINE      '\n' | 
|---|
| 265 | #define STB_TEXTEDIT_K_CONTROL    SB_KEY_CTRL(0) | 
|---|
| 266 | #define STB_TEXTEDIT_K_SHIFT      SB_KEY_SHIFT(0) | 
|---|
| 267 | #define STB_TEXTEDIT_GETWIDTH_NEWLINE 0.0f | 
|---|
| 268 | #define STB_TEXTEDIT_KEYTOTEXT(k) k | 
|---|
| 269 | #define STB_TEXTEDIT_STRINGLEN(o) o->_len | 
|---|
| 270 | #define STB_TEXTEDIT_GETCHAR(o,i) o->getChar(i) | 
|---|
| 271 | #define STB_TEXTEDIT_GETWIDTH(o,n,i)      o->_in->charWidth(n, i) | 
|---|
| 272 | #define STB_TEXTEDIT_LAYOUTROW(r,o,n)     o->_in->layout(r, n) | 
|---|
| 273 | #define STB_TEXTEDIT_DELETECHARS(o,i,n)   o->deleteChars(i, n) | 
|---|
| 274 | #define STB_TEXTEDIT_INSERTCHARS(o,i,c,n) o->insertChars(i, c, n) | 
|---|
| 275 |  | 
|---|
| 276 | #endif | 
|---|
| 277 |  | 
|---|
| 278 |  | 
|---|