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 | |