editbox.h 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827
  1. // Copyright (C) 2003 Mooffie <mooffie@typo.co.il>
  2. //
  3. // This program is free software; you can redistribute it and/or modify
  4. // it under the terms of the GNU General Public License as published by
  5. // the Free Software Foundation; either version 2 of the License, or
  6. // (at your option) any later version.
  7. //
  8. // This program is distributed in the hope that it will be useful,
  9. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. // GNU General Public License for more details.
  12. //
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program; if not, write to the Free Software
  15. // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
  16. #ifndef BDE_EDITBOX_H
  17. #define BDE_EDITBOX_H
  18. #include <vector>
  19. #include "directvect.h"
  20. #include "widget.h"
  21. #include "bidi.h"
  22. #include "transtbl.h"
  23. #include "undo.h"
  24. #include "point.h"
  25. // End-of-paragraph type
  26. enum eop_t { eopNone, eopUnix, eopDOS, eopMac, eopUnicode };
  27. // A "Paragraph" is a fundamental text element in our editor widget,
  28. // EditBox. EditBox stores the text in paragraphs. Paragraphs correspond
  29. // to "lines" in traditional unix text editors, but we reserve the term
  30. // "lines" to screen lines, that is, a single row on the screen.
  31. class Paragraph {
  32. public:
  33. typedef DirectVector<idx_t> IdxArray;
  34. unistring str; // the text itself
  35. // The text is wrapped into several lines to fit the screen width.
  36. // Since this wrapping process is costly (calculating widths, etc), we
  37. // store the resulting line breaks in "line_breaks" and re-apply the
  38. // wrapping process only upon text modification.
  39. IdxArray line_breaks;
  40. // The end-of-paragraph character (CR, LF, etc) is not stored directly
  41. // in "str", but we keep a record of it in "eop".
  42. eop_t eop;
  43. // "individual_base_dir" holds the directionality of the paragraph. It
  44. // is updated when the text is modified.
  45. direction_t individual_base_dir;
  46. // "contextual_base_dir" holds the directionality of the paragraph
  47. // taking into account its surrounding paragraphs (that is, its
  48. // context). "individual_base_dir", too, is used in calculating it.
  49. // EditBox uses this variable, mainly through is_rtl(), to reorder and
  50. // render the text.
  51. direction_t contextual_base_dir;
  52. public:
  53. int breaks_count() const { return line_breaks.size(); }
  54. direction_t base_dir() const { return contextual_base_dir; }
  55. bool is_rtl() const { return contextual_base_dir == dirRTL; }
  56. Paragraph() {
  57. line_breaks.push_back(0);
  58. individual_base_dir = contextual_base_dir = dirN;
  59. eop = eopNone;
  60. }
  61. void determine_base_dir(diralgo_t dir_algo)
  62. {
  63. individual_base_dir = BiDi::determine_base_dir(str.begin(),
  64. str.len(), dir_algo);
  65. // If we're not asked to use the contextual algorithm, then
  66. // calculating "contextual_base_dir", which is what EditBox looks
  67. // at, is a simple assignment.
  68. if (dir_algo != algoContextStrong && dir_algo != algoContextRTL)
  69. contextual_base_dir = individual_base_dir;
  70. }
  71. };
  72. #define MIN(x,y) ((x)<(y)?(x):(y))
  73. #define MAX(x,y) ((x)>(y)?(x):(y))
  74. // EditBox is one widget that doesn't visually notify the user about
  75. // changes in its state. Such chores are the responsibility of a
  76. // higher-level class, like the status line or the editor. In order to let
  77. // other objects know about state changes and various errors, EditBox let's
  78. // them register themselves as "listeners". This concept is similar to
  79. // Java's listeners and adapters.
  80. class EditBoxStatusListener {
  81. public:
  82. virtual void on_wrap_change() {}
  83. virtual void on_modification_change() {}
  84. virtual void on_selection_change() {}
  85. virtual void on_position_change() {}
  86. virtual void on_auto_indent_change() {}
  87. virtual void on_auto_justify_change() {}
  88. virtual void on_dir_algo_change() {}
  89. virtual void on_alt_kbd_change() {}
  90. virtual void on_formatting_marks_change() {}
  91. virtual void on_read_only_change() {}
  92. virtual void on_smart_typing_change() {}
  93. virtual void on_rtl_nsm_change() {}
  94. virtual void on_maqaf_change() {}
  95. virtual void on_translation_mode_change() {}
  96. };
  97. class EditBoxErrorListener {
  98. public:
  99. virtual void on_read_only_error(unichar ch = 0) {}
  100. virtual void on_no_selection_error() {}
  101. virtual void on_no_alt_kbd_error() {}
  102. virtual void on_no_translation_table_error() {}
  103. virtual void on_cant_display_nsm_error() {}
  104. };
  105. // A CombinedLine object addresses a line. Remember that a "line" in our
  106. // terminology is a screen line. Therefore CombineLine is a combination of
  107. // a paragraph number (para) and a line number inside this paragraph
  108. // (inner_line).
  109. class CombinedLine {
  110. public:
  111. int para;
  112. int inner_line;
  113. public:
  114. CombinedLine() {
  115. para = 0;
  116. inner_line = 0;
  117. }
  118. CombinedLine(int para, int inner_line) {
  119. this->para = para;
  120. this->inner_line = inner_line;
  121. }
  122. CombinedLine(const CombinedLine &other) {
  123. para = other.para;
  124. inner_line = other.inner_line;
  125. }
  126. bool operator< (const CombinedLine &other) const {
  127. return para < other.para
  128. || (para == other.para && inner_line < other.inner_line);
  129. }
  130. bool operator== (const CombinedLine &other) const {
  131. return para == other.para
  132. && inner_line == other.inner_line;
  133. }
  134. bool operator> (const CombinedLine &other) const {
  135. return !(*this < other
  136. || *this == other);
  137. }
  138. void swap(CombinedLine &other) {
  139. CombinedLine tmp = other;
  140. other = *this;
  141. *this = tmp;
  142. }
  143. // Some operations, like calculating the difference between two lines,
  144. // were meant be used on lines that are close together. the is_near()
  145. // method helps us avoid this problem by telling us that the lines are
  146. // far apart. (the exact number is unimportant, but it should be of
  147. // the same magnitude as the window height.)
  148. bool is_near(const CombinedLine &other) const {
  149. int diff = para - other.para;
  150. return diff < 40 && diff > -40;
  151. }
  152. };
  153. // EditBox is the central widget in our editor. It stores the text and does
  154. // the actual editing.
  155. //
  156. // The text is stored as a vector of pointers to Paragraphs. Professional
  157. // editors are not built that way. What I did here is not an effective
  158. // data-structure for an editor.
  159. //
  160. // It's too late to "fix" this as it would require major modifications.
  161. // This editor started as a tiny project and from the start I intended it
  162. // for simple editing tasks, like composing mail messages and nothing more.
  163. //
  164. // Data Transfer:
  165. //
  166. // EditBox does not handle loading and saving files. This is the task of an
  167. // I/O module. To allow other objects to access EditBox's textual data, we
  168. // provide a data transfer interface:
  169. //
  170. // start_data_transfer(direction);
  171. // transfer_data(buffer);
  172. // end_data_transfer();
  173. class Scrollbar;
  174. class EditBox : public Widget {
  175. public:
  176. // the following typedef's are shorthands for STL's types. There're
  177. // all used by the reordering algorithm (BiDi related).
  178. typedef DirectVector<level_t> LevelsArray;
  179. typedef Paragraph::IdxArray IdxArray;
  180. typedef DirectVector<attribute_t> AttributeArray;
  181. typedef DirectVector<int> IntArray;
  182. // EditBox supports two types of wrap (in addition to no-wrap):
  183. // wrpAnywhere, that breaks lines even inside words; and
  184. // wrpAtWhiteSpace, that doesn't break words (unless they're longer
  185. // than the window width).
  186. enum WrapType { wrpOff, wrpAnywhere, wrpAtWhiteSpace };
  187. // How to display the Hebrew maqaf?
  188. // 1. mqfAsis ("as is") is used when the user has Unicode fonts -- they
  189. // usually have maqaf.
  190. // 2. 8-bit fonts don't have it, that's why we may have to convert it
  191. // to ASCII's dash (mqfTransliterate).
  192. // 3. mqfHighlighed makes the maqaf very visible, in case the user
  193. // wants to know whether the document is dominated by maqafs.
  194. enum maqaf_display_t { mqfAsis, mqfTransliterated, mqfHighlighted };
  195. // How to display RTL NSMs?
  196. // 1. rtlnsmOff -- don't print them.
  197. // 2. rtlnsmTransliterated -- use ASCII characters to represent them.
  198. // 3. rtlnsmAsis -- if the user is lucky to have a system (terminal +
  199. // font) that is capable of displaying Hebrew points, print them as-is.
  200. enum rtl_nsm_display_t { rtlnsmOff, rtlnsmTransliterated, rtlnsmAsis };
  201. enum syn_hlt_t { synhltOff, synhltHTML, synhltEmail };
  202. // In the update() method we draw only the region that needs to be
  203. // redrawn.
  204. // rgnCursor -- only position the cursor; rgnCurrent -- draw the
  205. // current paragraph and position the cursor; rgnRange -- draw a range
  206. // of paragraphs; argnAll -- draw all visible paragraphs.
  207. enum region { rgnNone = 0, rgnCursor = 1, rgnCurrent = 2,
  208. rgnRange = 4, rgnAll = 8 };
  209. enum data_transfer_direction { dataTransferIn, dataTransferOut };
  210. protected:
  211. // for translating the next char typed.
  212. static TranslationTable transtbl;
  213. // ASCII representations of various non-displayable characters and
  214. // concepts, like line continuation.
  215. static TranslationTable reprtbl;
  216. // Alternate keyboard -- usually the user's national language.
  217. static TranslationTable altkbdtbl;
  218. EditBoxStatusListener *status_listener;
  219. EditBoxErrorListener *error_listener;
  220. #define NOTIFY_CHANGE(event) \
  221. do { \
  222. if (status_listener) \
  223. status_listener->on_ ## event ## _change(); \
  224. } while (0)
  225. #define NOTIFY_ERROR(event) \
  226. do { \
  227. if (error_listener) \
  228. error_listener->on_ ## event ## _error(); \
  229. } while (0)
  230. #define NOTIFY_ERROR_ARG(event, arg) \
  231. do { \
  232. if (error_listener) \
  233. error_listener->on_ ## event ## _error(arg); \
  234. } while (0)
  235. // The text itself: a vector of pointers to Paragraphs
  236. std::vector<Paragraph *> paragraphs;
  237. // The cursor position
  238. Point cursor;
  239. UndoStack undo_stack;
  240. unistring clipboard;
  241. // Margins make it easier for us to implement features such as line
  242. // numbering. Currently EditBox only uses "margin_after" to reserve
  243. // one column for the '$' character (the indicator that, in no-wrap
  244. // mode, tells the user that only part of the line is shown), and for
  245. // the cursor, when it stands past the last character in the line.
  246. //
  247. // Other editors call these "left_margin" and "right_margin", but since
  248. // this is a BiDi editor, where paragraphs may be RTL oriented, I use
  249. // "before" and "after" to mean "left" and "right", respectively, for
  250. // LTR paragraphs, and "right" and "left", respectively, for RTL
  251. // paragraphs.
  252. int margin_before;
  253. int margin_after;
  254. // top_line refers to the first visible line in our window.
  255. CombinedLine top_line;
  256. // The "selection" (shown highlighted when active) stretches from the
  257. // curser position till this primary_mark.
  258. Point primary_mark;
  259. // When the user moves the cursor vertically, the editor tries to
  260. // reposition the cursor on the same visual column. This is not always
  261. // possible, e.g. when that column would be inside a TAB segment, or
  262. // when the new line is not long enough to contain this column.
  263. // optinal_vis_colum holds the column on which the cursor _should_
  264. // stand.
  265. int optimal_vis_column;
  266. // Has the buffer been modified?
  267. bool modified;
  268. // justification_column holds the maximum line length to use when
  269. // justifying paragraphs.
  270. idx_t justification_column;
  271. // when rfc2646_trailing_space is true, we keep a trailing space on
  272. // each line when justifying paragraphs.
  273. bool rfc2646_trailing_space;
  274. // When the user moves the cursor past the top or the bottom of the window,
  275. // EditBox scrolls scroll_step lines up or down.
  276. int scroll_step;
  277. // update_region tells the update() method which part of the window to
  278. // paint. it's a bitmask of 'enum region'.
  279. int update_region;
  280. // when drawing a range of paragraphs (rgnRange), update_from and
  281. // update_to denote the region.
  282. int update_from;
  283. int update_to;
  284. // Modes
  285. bool alt_kbd; // is the alternative keyboard active? (cf. altkbdtbl)
  286. bool auto_justify; // is auto-justify mode active?
  287. bool auto_indent; // whether to auto-indent lines.
  288. bool translation_mode; // translate next char? (cf. transtbl)
  289. bool read_only; // is the user allowed to make changes to the buffer?
  290. bool smart_typing; // replace simple ASCII chars with fancy ones.
  291. // Display
  292. WrapType wrap_type;
  293. diralgo_t dir_algo;
  294. int tab_width;
  295. bool show_explicits; // display BiDi formatting codes?
  296. bool show_paragraph_endings; // display paragraph endings?
  297. bool show_tabs;
  298. rtl_nsm_display_t rtl_nsm_display;
  299. maqaf_display_t maqaf_display;
  300. syn_hlt_t syn_hlt;
  301. bool underline_hlt;
  302. int non_interactive_text_width;
  303. // on resize event, compare new width to old_width
  304. // and wrap lines only if they're different.
  305. int old_width;
  306. bool bidi_enabled;
  307. bool visual_cursor_movement;
  308. // Where the last edit operation took place?
  309. Point last_modification;
  310. // We emulate some emacs commands (e.g. C-k) with these
  311. // flags. When prev_command_type is cmdtpKill, we know
  312. // we need to append to the clipboard.
  313. enum CommandType { cmdtpUnknown, cmdtpKill };
  314. CommandType prev_command_type, current_command_type;
  315. private:
  316. struct _t_data_transfer {
  317. bool in_transfer;
  318. data_transfer_direction dir;
  319. Point cursor_origin;
  320. bool skip_undo;
  321. bool clear_modified_flag;
  322. bool at_eof;
  323. bool prev_is_cr;
  324. int ntransferred_out;
  325. int ntransferred_out_max;
  326. } data_transfer;
  327. public:
  328. void set_read_only(bool value);
  329. bool is_read_only() const { return read_only; }
  330. INTERACTIVE void toggle_read_only() { set_read_only(!is_read_only()); }
  331. void set_cursor_position(const Point &point);
  332. void get_cursor_position(Point& point) const { point = cursor; }
  333. void set_maqaf_display(maqaf_display_t disp);
  334. maqaf_display_t get_maqaf_display() const { return maqaf_display; }
  335. INTERACTIVE void toggle_maqaf();
  336. INTERACTIVE void set_maqaf_display_transliterated() {
  337. set_maqaf_display(mqfTransliterated);
  338. }
  339. INTERACTIVE void set_maqaf_display_highlighted() {
  340. set_maqaf_display(mqfHighlighted);
  341. }
  342. INTERACTIVE void set_maqaf_display_asis() {
  343. set_maqaf_display(mqfAsis);
  344. }
  345. void set_smart_typing(bool val);
  346. bool is_smart_typing() const { return smart_typing; }
  347. INTERACTIVE void toggle_smart_typing()
  348. { set_smart_typing(!is_smart_typing()); }
  349. bool set_rtl_nsm_display(rtl_nsm_display_t disp);
  350. rtl_nsm_display_t get_rtl_nsm_display() const
  351. { return rtl_nsm_display; }
  352. INTERACTIVE void toggle_rtl_nsm();
  353. INTERACTIVE void set_rtl_nsm_off() {
  354. set_rtl_nsm_display(rtlnsmOff);
  355. }
  356. INTERACTIVE void set_rtl_nsm_asis() {
  357. set_rtl_nsm_display(rtlnsmAsis);
  358. }
  359. INTERACTIVE void set_rtl_nsm_transliterated() {
  360. set_rtl_nsm_display(rtlnsmTransliterated);
  361. }
  362. void set_formatting_marks(bool value);
  363. bool has_formatting_marks() const { return show_paragraph_endings; }
  364. INTERACTIVE void toggle_formatting_marks();
  365. void set_tab_width(int value);
  366. int get_tab_width() const { return tab_width; }
  367. void set_modified(bool value);
  368. bool is_modified() const { return modified; }
  369. void set_auto_indent(bool value);
  370. bool is_auto_indent() const { return auto_indent; }
  371. INTERACTIVE void toggle_auto_indent()
  372. { set_auto_indent(!is_auto_indent()); }
  373. void set_auto_justify(bool value);
  374. bool is_auto_justify() const { return auto_justify; }
  375. INTERACTIVE void toggle_auto_justify()
  376. { set_auto_justify(!is_auto_justify()); }
  377. void set_justification_column(int value);
  378. int get_justification_column() const { return justification_column; }
  379. void set_rfc2646_trailing_space(bool value) { rfc2646_trailing_space = value; }
  380. void set_translation_table(const TranslationTable &tbl) { transtbl = tbl; }
  381. void set_translation_mode(bool value);
  382. bool in_translation_mode() const { return translation_mode; }
  383. INTERACTIVE void set_translate_next_char() { set_translation_mode(true); }
  384. void set_scroll_step(int value);
  385. int get_scroll_step() const { return scroll_step; }
  386. void set_wrap_type(WrapType value);
  387. WrapType get_wrap_type() const { return wrap_type; }
  388. INTERACTIVE void toggle_wrap();
  389. INTERACTIVE void set_wrap_type_at_white_space() {
  390. set_wrap_type(wrpAtWhiteSpace);
  391. }
  392. INTERACTIVE void set_wrap_type_anywhere() {
  393. set_wrap_type(wrpAnywhere);
  394. }
  395. INTERACTIVE void set_wrap_type_off() {
  396. set_wrap_type(wrpOff);
  397. }
  398. void set_non_interactive_text_width(int cols)
  399. { non_interactive_text_width = cols; }
  400. void set_dir_algo(diralgo_t value);
  401. diralgo_t get_dir_algo() const { return dir_algo; }
  402. INTERACTIVE void toggle_dir_algo();
  403. INTERACTIVE void set_dir_algo_unicode() { set_dir_algo(algoUnicode); }
  404. INTERACTIVE void set_dir_algo_force_ltr() { set_dir_algo(algoForceLTR); }
  405. INTERACTIVE void set_dir_algo_force_rtl() { set_dir_algo(algoForceRTL); }
  406. INTERACTIVE void set_dir_algo_context_strong() { set_dir_algo(algoContextStrong); }
  407. INTERACTIVE void set_dir_algo_context_rtl() { set_dir_algo(algoContextRTL); }
  408. void set_alt_kbd_table(const TranslationTable &tbl) { altkbdtbl = tbl; }
  409. void set_alt_kbd(bool val);
  410. bool get_alt_kbd() const { return alt_kbd; }
  411. INTERACTIVE void toggle_alt_kbd();
  412. void set_primary_mark(const Point &point);
  413. void set_primary_mark() { set_primary_mark(cursor); }
  414. void unset_primary_mark();
  415. bool is_primary_mark_set() const { return primary_mark.para != -1; }
  416. bool has_selected_text() const { return is_primary_mark_set(); }
  417. INTERACTIVE void toggle_primary_mark();
  418. void set_repr_table(const TranslationTable &tbl)
  419. { reprtbl = tbl; }
  420. void set_status_listener(EditBoxStatusListener *obj)
  421. { status_listener = obj; }
  422. void set_error_listener(EditBoxErrorListener *obj)
  423. { error_listener = obj; }
  424. void set_undo_size_limit(size_t limit)
  425. { undo_stack.set_size_limit(limit); }
  426. void set_key_for_key_undo(bool value)
  427. { undo_stack.set_merge(!value); }
  428. bool is_key_for_key_undo() const
  429. { return !undo_stack.is_merge(); }
  430. INTERACTIVE void toggle_key_for_key_undo();
  431. void sync_scrollbar(Scrollbar *scrollbar);
  432. void enable_bidi(bool value);
  433. bool is_bidi_enabled() const { return bidi_enabled; }
  434. INTERACTIVE void toggle_bidi();
  435. void set_syn_hlt(syn_hlt_t sh);
  436. syn_hlt_t get_syn_hlt() const
  437. { return syn_hlt; }
  438. void detect_syntax();
  439. INTERACTIVE void menu_set_syn_hlt_none();
  440. INTERACTIVE void menu_set_syn_hlt_html();
  441. INTERACTIVE void menu_set_syn_hlt_email();
  442. void set_underline(bool v);
  443. bool get_underline() const
  444. { return underline_hlt; }
  445. INTERACTIVE void toggle_underline();
  446. void set_visual_cursor_movement(bool v);
  447. bool get_visual_cursor_movement() const { return visual_cursor_movement; }
  448. INTERACTIVE void toggle_visual_cursor_movement();
  449. protected:
  450. int parags_count() const { return paragraphs.size(); }
  451. inline Paragraph *curr_para() { return paragraphs[cursor.para]; };
  452. public:
  453. HAS_ACTIONS_MAP(EditBox, Widget);
  454. HAS_BINDINGS_MAP(EditBox, Widget);
  455. ///////////////////////////////////////////////////////////////////////
  456. // Initialization
  457. ///////////////////////////////////////////////////////////////////////
  458. EditBox();
  459. virtual ~EditBox();
  460. void new_document();
  461. ///////////////////////////////////////////////////////////////////////
  462. // Data Transfer
  463. ///////////////////////////////////////////////////////////////////////
  464. public:
  465. void start_data_transfer(data_transfer_direction dir,
  466. bool new_document = false,
  467. bool selection_only = false);
  468. int transfer_data(unichar *buf, int len);
  469. void end_data_transfer();
  470. protected:
  471. int transfer_data_in(unichar *data, int len);
  472. int transfer_data_out(unichar *buf, int len);
  473. bool is_in_data_transfer() const;
  474. ///////////////////////////////////////////////////////////////////////
  475. // Movement
  476. ///////////////////////////////////////////////////////////////////////
  477. public:
  478. INTERACTIVE void move_forward_char();
  479. INTERACTIVE void move_backward_char();
  480. INTERACTIVE void move_next_line();
  481. INTERACTIVE void move_previous_line();
  482. INTERACTIVE void move_forward_page();
  483. INTERACTIVE void move_backward_page();
  484. INTERACTIVE void move_beginning_of_line();
  485. INTERACTIVE void move_end_of_line();
  486. INTERACTIVE void move_beginning_of_buffer();
  487. INTERACTIVE void move_end_of_buffer();
  488. INTERACTIVE void move_backward_word();
  489. INTERACTIVE void move_forward_word();
  490. INTERACTIVE void move_last_modification();
  491. INTERACTIVE void key_left();
  492. INTERACTIVE void key_right();
  493. INTERACTIVE void key_home();
  494. INTERACTIVE void center_line();
  495. void move_first_char(unichar ch);
  496. bool search_forward(unistring str);
  497. unichar get_current_char();
  498. void move_absolute_line(int line);
  499. // Visual cursor movement:
  500. INTERACTIVE void move_forward_visual_char();
  501. INTERACTIVE void move_backward_visual_char();
  502. INTERACTIVE void move_beginning_of_visual_line();
  503. protected:
  504. void post_horizontal_movement();
  505. void post_vertical_movement();
  506. bool is_at_end_of_buffer();
  507. bool is_at_beginning_of_buffer();
  508. bool is_at_beginning_of_word();
  509. void move_relative_line(int diff);
  510. void add_rows_to_line(CombinedLine &line, int rows);
  511. int lines_diff(CombinedLine L1, CombinedLine L2);
  512. void scroll_to_cursor_line();
  513. int calc_inner_line();
  514. int calc_vis_column();
  515. void move_to_vis_column(int column);
  516. void invalidate_optimal_vis_column()
  517. { optimal_vis_column = -1; }
  518. bool valid_optimal_vis_column() const
  519. { return optimal_vis_column != -1; }
  520. int get_effective_scroll_step() const
  521. { return MAX(1, MIN(window_height() / 2 + 0 , scroll_step)); }
  522. // Visual cursor movement related:
  523. bool is_at_end_of_screen_line();
  524. bool is_at_first_screen_line();
  525. bool is_at_last_screen_line();
  526. ///////////////////////////////////////////////////////////////////////
  527. // Modification
  528. ///////////////////////////////////////////////////////////////////////
  529. public:
  530. INTERACTIVE void delete_paragraph();
  531. INTERACTIVE void cut_end_of_paragraph();
  532. INTERACTIVE void delete_forward_word();
  533. INTERACTIVE void delete_backward_word();
  534. INTERACTIVE void delete_forward_char();
  535. INTERACTIVE void delete_backward_char();
  536. void delete_text(int len, bool skip_undo = false,
  537. unistring *alt_deleted = NULL);
  538. void insert_char(unichar ch);
  539. void insert_text(const unichar *str, int len, bool skip_undo = false);
  540. void insert_text(const unistring &str, bool skip_undo = false)
  541. { insert_text(str.begin(), str.len(), skip_undo); }
  542. void replace_text(const unichar *str, int len, int delete_len,
  543. bool skip_undo = false);
  544. void replace_text(const unistring &str, int delete_len,
  545. bool skip_undo = false)
  546. { replace_text(str.begin(), str.len(), delete_len, skip_undo); }
  547. INTERACTIVE void copy();
  548. INTERACTIVE void cut();
  549. INTERACTIVE void paste();
  550. INTERACTIVE void undo();
  551. INTERACTIVE void redo();
  552. INTERACTIVE void justify();
  553. INTERACTIVE void insert_maqaf();
  554. INTERACTIVE void toggle_eops();
  555. void set_eops(eop_t new_eop);
  556. eop_t get_dominant_eop() { return paragraphs[0]->eop; }
  557. INTERACTIVE void set_eops_unix() { set_eops(eopUnix); }
  558. INTERACTIVE void set_eops_dos() { set_eops(eopDOS); }
  559. INTERACTIVE void set_eops_mac() { set_eops(eopMac); }
  560. INTERACTIVE void set_eops_unicode() { set_eops(eopUnicode); }
  561. void log2vis(const char *options);
  562. void key_enter();
  563. void key_dash();
  564. protected:
  565. void post_modification();
  566. void post_para_modification(Paragraph &p);
  567. void undo_op(UndoOp *opp);
  568. void redo_op(UndoOp *opp);
  569. void calc_contextual_dirs(int min_para, int max_para, bool update_display);
  570. inline void set_contextual_dir(Paragraph &p, direction_t dir,
  571. bool update_display);
  572. int calc_distance(Point p1, Point p2);
  573. void copy_text(int len, bool append = false);
  574. void cut_or_copy(bool just_copy);
  575. inline unichar get_eop_char(eop_t eop);
  576. inline unichar get_curr_eop_char();
  577. ////////////////////////////////////////////////////////////////////////////
  578. // Rendering
  579. ////////////////////////////////////////////////////////////////////////////
  580. public:
  581. virtual void update();
  582. virtual void update_cursor() { request_update(rgnCursor); update(); }
  583. virtual bool is_dirty() const { return update_region != rgnNone; }
  584. virtual void invalidate_view() { request_update(rgnAll); }
  585. void reformat();
  586. protected:
  587. // get_char_width() returns the width of a characetr, but since
  588. // this character may be part of a LAM-ALEF ligature, we need
  589. // to keep state information between calls - wdstate.
  590. struct wdstate {
  591. bool may_start_lam_alef;
  592. void clear() {
  593. may_start_lam_alef = false;
  594. }
  595. wdstate() {
  596. clear();
  597. }
  598. };
  599. int get_text_width() const;
  600. // :TODO: try to make this inline. FreeBSD's compiler complains...
  601. /*inline*/
  602. int get_char_width(unichar ch, int pos,
  603. wdstate *stt = NULL, bool visual = false);
  604. int get_str_width(const unichar *str, idx_t len, bool visual = false);
  605. int get_rev_str_width(const unichar *str, idx_t len);
  606. void wrap_para(Paragraph &para);
  607. void rewrap_all();
  608. void request_update(region rgn);
  609. void request_update(int lo, int hi);
  610. struct _t_cache {
  611. int owner_para;
  612. LevelsArray levels;
  613. IdxArray position_L_to_V;
  614. IdxArray position_V_to_L;
  615. AttributeArray attributes;
  616. unistring vis;
  617. void invalidate() {
  618. owner_para = -1;
  619. }
  620. bool owned_by(int para) {
  621. return owner_para == para;
  622. }
  623. void set_owner(int para) {
  624. owner_para = para;
  625. }
  626. } cache;
  627. virtual void redraw_paragraph(
  628. Paragraph &p,
  629. int window_start_line,
  630. bool only_cursor,
  631. int para_num
  632. );
  633. void redraw_unwrapped_paragraph(
  634. Paragraph &p,
  635. int window_start_line,
  636. bool only_cursor,
  637. int para_num,
  638. LevelsArray &levels,
  639. IdxArray& position_L_to_V,
  640. IdxArray& position_V_to_L,
  641. AttributeArray& attributes,
  642. bool eop_is_selected
  643. );
  644. void redraw_wrapped_paragraph(
  645. Paragraph &p,
  646. int window_start_line,
  647. bool only_cursor,
  648. int para_num,
  649. LevelsArray &levels,
  650. IdxArray& position_L_to_V,
  651. IdxArray& position_V_to_L,
  652. AttributeArray& attributes,
  653. bool eop_is_selected
  654. );
  655. void draw_unistr(const unichar *str, idx_t len,
  656. attribute_t *attributes = NULL, int *tab_widths = NULL);
  657. void calc_tab_widths(const unichar *str, idx_t len,
  658. bool rev, IntArray &tab_widths);
  659. void draw_rev_unistr(const unichar *str, idx_t len,
  660. attribute_t *attributes = NULL);
  661. unichar get_char_repr(unichar ch);
  662. void put_unichar_attr_at(int line, int col, unichar ch, int attr);
  663. void draw_eop(int y, int x, Paragraph &p, bool selected);
  664. virtual void do_syntax_highlight(const unistring &str,
  665. AttributeArray &attributes, int para_num);
  666. ///////////////////////////////////////////////////////////////////////
  667. // Misc
  668. ///////////////////////////////////////////////////////////////////////
  669. public:
  670. virtual bool handle_event(const Event &evt);
  671. virtual void resize(int lines, int columns, int y, int x);
  672. public:
  673. int get_number_of_paragraphs() const
  674. { return parags_count(); }
  675. const unistring &get_paragraph_text(int i) {
  676. return paragraphs[i]->str;
  677. }
  678. };
  679. #endif