1
2 /*************************************************************************
3 * Copyright (C) 2007-2015 Ruben Pollan Bella <meskio@sindominio.net> *
4 * *
5 * This file is part of TuDu. *
6 * *
7 * TuDu is free software; you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation; version 3 of the License. *
10 * *
11 * TuDu is distributed in the hope that it will be useful, *
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
14 * GNU General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.*
18 *************************************************************************/
19
20 #include "text.h"
21
22 #define cursor_x (cursor_col % cols)
23 #define rows_in_line(line) ((line->length() / cols) + 1)
24
operator =(const wstring & str)25 Text& Text::operator=(const wstring& str)
26 {
27 unsigned int i = 0, size;
28
29 /* build a list with each line of the text in an entry */
30 text.clear();
31 while (i < str.length())
32 {
33 for (size = 0; (i+size < str.length()) &&
34 ('\n' != str[i+size]); ++size);
35 text.push_back(str.substr(i, size));
36 i += size+1;
37 }
38 if (text.empty()) /* if is empty it makes a sigfault at edit */
39 text.push_back(L"");
40
41 /* set up the cursor */
42 cursor_col = 0; cursor_y = INT_MIN;
43 cursor_line = text.begin();
44 offset = text.begin();
45
46 return *this;
47 }
48
operator !=(const wstring & str)49 bool Text::operator!=(const wstring& str)
50 {
51 return (str != getStr());
52 }
53
print(Window & win)54 void Text::print(Window& win)
55 {
56 lines = win._lines();
57 cols = win._cols();
58 wstring str = _getStr(offset, lines);
59
60 win._erase();
61 win._addstr(0,0,str);
62 win._refresh();
63 }
64
edit(Window & win)65 void Text::edit(Window& win)
66 {
67 bool resized = false;
68
69 /* calculate the cursor_y */
70 cursor_y = 0;
71 for (list<wstring>::iterator i = offset; i != cursor_line; ++i)
72 cursor_y += rows_in_line(i);
73 cursor_y += cursor_col / cols;
74
75 lines = win._lines();
76 cols = win._cols();
77 win._move(cursor_y, cursor_x);
78 curs_set(1);
79 win._refresh();
80
81 /* editor loop */
82 wint_t key = '\e';
83 bool isKeyCode = (win._getch(key) == KEY_CODE_YES);
84 while ('\e' != key) {
85 if (isKeyCode)
86 {
87 switch (key)
88 {
89 case KEY_RESIZE:
90 resized = true;
91 break;
92 case KEY_LEFT: left();
93 break;
94 case KEY_RIGHT: right();
95 break;
96 case KEY_DOWN: down();
97 break;
98 case KEY_UP: up();
99 break;
100 case KEY_HOME: home();
101 break;
102 case KEY_END: end();
103 break;
104 case KEY_NPAGE: next_page();
105 break;
106 case KEY_PPAGE: prev_page();
107 break;
108 case KEY_BACKSPACE: backspace();
109 break;
110 case KEY_DC: supr();
111 break;
112 case KEY_ENTER: new_line();
113 break;
114 }
115 }
116 else
117 {
118 switch (key)
119 {
120 case '\n': new_line();
121 break;
122 case '\t': tab();
123 break;
124 default:
125 cursor_line->insert(cursor_col,1,key);
126 ++cursor_col;
127 if (0 == cursor_x) ++cursor_y;
128 break;
129 }
130 }
131
132 /* print the text, place cursor, ... */
133 wstring str = _getStr(offset, lines);
134 win._erase();
135 win._addstr(0,0,str);
136 win._move(cursor_y, cursor_x);
137 win._refresh();
138 isKeyCode = (win._getch(key) == KEY_CODE_YES);
139 }
140 curs_set(0);
141 print(win);
142 cursor_y = INT_MIN;
143
144 if (resized) ungetch(KEY_RESIZE);
145 return;
146 }
147
getStr()148 wstring Text::getStr()
149 {
150 wstring s = L"";
151
152 for (list<wstring>::iterator i = text.begin(); i != text.end(); ++i)
153 {
154 s += *i;
155 s += L'\n';
156 }
157 return s;
158 }
159
_getStr(list<wstring>::iterator begin,int length)160 wstring Text::_getStr(list<wstring>::iterator begin, int length)
161 {
162 int rows = 0;
163 wstring s = L"";
164 list<wstring>::iterator i = begin;
165
166 if (text.end() == begin) return s;
167 for (;i != text.end(); ++i)
168 {
169 if (length)
170 {
171 int rows_line = rows_in_line(i);
172 if (rows+rows_line > length)
173 {
174 for (int row = 0; row < length-rows; ++row)
175 {
176 s += i->substr(row*cols, cols);
177 }
178 s += '\n';
179 break;
180 }
181 rows += rows_line;
182 }
183 s += *i;
184 s += '\n';
185 if ((length) && (rows == length)) break;
186 }
187 s.erase(s.length()-1); /* del the last '\n' */
188 return s;
189 }
190
scroll_up(Window & win)191 void Text::scroll_up(Window& win)
192 {
193 lines = win._lines();
194 cols = win._cols();
195 _scroll_up();
196 print(win);
197 }
198
scroll_down(Window & win)199 void Text::scroll_down(Window& win)
200 {
201 lines = win._lines();
202 cols = win._cols();
203 _scroll_down();
204 print(win);
205 }
206
_scroll_up()207 bool Text::_scroll_up()
208 {
209 if (text.begin() != offset)
210 {
211 --offset;
212
213 /* update cursor_y if is editing */
214 if (cursor_y != INT_MIN)
215 {
216 cursor_y += rows_in_line(offset);
217 while (cursor_y >= lines)
218 {
219 cursor_y -= rows_in_line(cursor_line);
220 --cursor_line;
221 if ((int)cursor_line->length() < cursor_col)
222 cursor_col = cursor_line->length();
223 }
224 }
225 /* if is not in edit mode scroll also the cursor */
226 else
227 {
228 --cursor_line;
229 if ((int)cursor_line->length() < cursor_col)
230 cursor_col = cursor_line->length();
231 }
232 return true;
233 }
234 else
235 return false;
236 }
237
_scroll_down()238 bool Text::_scroll_down()
239 {
240 ++offset;
241 if (text.end() != offset)
242 {
243 --offset;
244 /* update cursor_y if is editing */
245 if (cursor_y != INT_MIN)
246 {
247 cursor_y -= rows_in_line(offset);
248 if (cursor_y < 0)
249 {
250 cursor_y = 0;
251 ++cursor_line;
252 if (cursor_x < (int)cursor_line->length())
253 cursor_col = cursor_x;
254 else
255 cursor_col = cursor_line->length();
256 }
257 }
258 /* if is not in edit mode scroll also the cursor */
259 else
260 {
261 ++cursor_line;
262 if (cursor_line == text.end())
263 {
264 --cursor_line;
265 }
266 else
267 {
268 if (cursor_x < (int)cursor_line->length())
269 cursor_col = cursor_x;
270 else
271 cursor_col = cursor_line->length();
272 }
273 }
274 ++offset;
275 return true;
276 }
277 else
278 {
279 --offset;
280 return false;
281 }
282 }
283
left()284 void Text::left()
285 {
286 if (cursor_col>0)
287 {
288 if (0 == cursor_x) --cursor_y;
289 --cursor_col;
290 }
291 else if (cursor_line != text.begin())
292 {
293 --cursor_y;
294 --cursor_line;
295 cursor_col = cursor_line->length();
296 }
297 if (cursor_y < 0) _scroll_up();
298 }
299
right()300 void Text::right()
301 {
302 if (cursor_col < (int)cursor_line->length())
303 {
304 ++cursor_col;
305 if (0 == cursor_x) ++cursor_y;
306 }
307 else if (cursor_line != --text.end())
308 {
309 cursor_col = 0;
310 ++cursor_y;
311 ++cursor_line;
312 }
313 if (cursor_y >= lines) _scroll_down();
314 }
315
316 #define last_line() ((int)rows_in_line(cursor_line)-1 == cursor_col / cols)
down()317 void Text::down()
318 {
319 if (last_line())
320 {
321 if (cursor_line != --text.end())
322 {
323 ++cursor_y;
324 ++cursor_line;
325 cursor_col = cursor_x;
326 }
327 }
328 else
329 {
330 ++cursor_y;
331 cursor_col += cols;
332 }
333
334 if (cursor_col > (int)cursor_line->length())
335 {
336 cursor_col = cursor_line->length();
337 }
338 if (cursor_y >= lines) _scroll_down();
339 }
340
up()341 void Text::up()
342 {
343 if ((cursor_col >= cols) || (cursor_line != text.begin()))
344 {
345 --cursor_y;
346
347 if (cursor_col < cols)
348 {
349 --cursor_line;
350 if (cursor_x < (int)cursor_line->length() % cols)
351 cursor_col = cursor_x + (rows_in_line(cursor_line)-1) * cols;
352 else
353 cursor_col = cursor_line->length();
354 }
355 else
356 {
357 cursor_col -= cols;
358 }
359
360 if (cursor_y < 0) _scroll_up();
361 }
362 }
363
backspace()364 void Text::backspace()
365 {
366 if (cursor_col > 0)
367 {
368 if (0 == cursor_x) --cursor_y;
369 if (cursor_y < 0) _scroll_up();
370 --cursor_col;
371 cursor_line->erase(cursor_col, 1);
372 }
373 else if (cursor_line != text.begin()) /* delete line break */
374 {
375 list<wstring>::iterator i = cursor_line;
376
377 --cursor_y;
378 --cursor_line;
379 cursor_col = cursor_line->length();
380 if (cursor_y < 0) _scroll_up();
381 *cursor_line += *i;
382 text.erase(i);
383 }
384 }
385
supr()386 void Text::supr()
387 {
388 if ((cursor_col == (int)cursor_line->length()) && (cursor_line != --text.end()))
389 {
390 list<wstring>::iterator i = cursor_line;
391
392 ++i;
393 *cursor_line += *i;
394 text.erase(i);
395 }
396 else
397 {
398 cursor_line->erase(cursor_col, 1);
399 }
400 if (cursor_y >= lines) _scroll_down();
401 }
402
home()403 void Text::home()
404 {
405 for (int i = 0; i < cursor_col/cols; --cursor_y, ++i);
406 cursor_col = 0;
407 if (cursor_y >= lines) _scroll_down();
408 }
409
end()410 void Text::end()
411 {
412 for (int i = 0; i < ((int)cursor_line->length()-cursor_col)/cols;
413 ++cursor_y, ++i);
414 cursor_col = cursor_line->length();
415 if (cursor_y >= lines) _scroll_down();
416 }
417
next_page()418 void Text::next_page()
419 {
420 int line_count = rows_in_line(offset);
421
422 while ((line_count < lines) && (_scroll_down()))
423 {
424 line_count += rows_in_line(offset);
425 }
426 }
427
prev_page()428 void Text::prev_page()
429 {
430 int line_count = rows_in_line(offset);
431
432 while ((line_count < lines) && (_scroll_up()))
433 {
434 line_count += rows_in_line(offset);
435 }
436 }
437
new_line()438 void Text::new_line()
439 {
440 list<wstring>::iterator i = cursor_line;
441
442 ++i;
443 text.insert(i, cursor_line->substr(cursor_col));
444 cursor_line->erase(cursor_col);
445 ++cursor_y;
446 ++cursor_line;
447 cursor_col = 0;
448 if (cursor_y >= lines) _scroll_down();
449 }
450
451 #define TAB_SPACES 4
tab()452 void Text::tab()
453 {
454 cursor_line->insert(cursor_col,TAB_SPACES,' ');
455 cursor_col+=TAB_SPACES;
456 if (TAB_SPACES > cursor_x) ++cursor_y;
457 }
458
operator <<(wostream & os,Text & t)459 wostream& operator<<(wostream& os, Text& t)
460 {
461 os << t.getStr();
462 return os;
463 }
464
operator >>(wistream & is,Text & t)465 wistream& operator>>(wistream& is, Text& t)
466 {
467 wstring str;
468 wchar_t c;
469
470 while (is.get(c))
471 str += c;
472
473 t = str;
474 return is;
475 }
476