tb_style_edit.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481
  1. // ================================================================================
  2. // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
  3. // == See tb_core.h for more information. ==
  4. // ================================================================================
  5. #ifndef TBStyleEdit_H
  6. #define TBStyleEdit_H
  7. #include "tb_core.h"
  8. #include "tb_linklist.h"
  9. #include "tb_widgets_common.h"
  10. #include "tb_list.h"
  11. namespace tb {
  12. class TBStyleEdit;
  13. class TBBlock;
  14. class TBTextFragment;
  15. class TBTextFragmentContent;
  16. class TBTextFragmentContentFactory;
  17. // TBG
  18. class TBTextTheme;
  19. // END TBG
  20. /** Listener for TBStyleEdit. Implement in the enviorment the TBStyleEdit should render its content. */
  21. class TBStyleEditListener
  22. {
  23. public:
  24. virtual ~TBStyleEditListener() {}
  25. virtual void OnChange() {};
  26. virtual bool OnEnter() { return false; };
  27. virtual void Invalidate(const TBRect &rect) = 0;
  28. virtual void DrawString(int32 x, int32 y, TBFontFace *font, const TBColor &color, const char *str, int32 len = TB_ALL_TO_TERMINATION) = 0;
  29. virtual void DrawRect(const TBRect &rect, const TBColor &color) = 0;
  30. virtual void DrawRectFill(const TBRect &rect, const TBColor &color) = 0;
  31. virtual void DrawTextSelectionBg(const TBRect &rect) = 0;
  32. virtual void DrawContentSelectionFg(const TBRect &rect) = 0;
  33. virtual void DrawCaret(const TBRect &rect) = 0;
  34. virtual void Scroll(int32 dx, int32 dy) = 0;
  35. virtual void UpdateScrollbars() = 0;
  36. virtual void CaretBlinkStart() = 0;
  37. virtual void CaretBlinkStop() = 0;
  38. };
  39. class TBStyleEditTextChangeListener
  40. {
  41. public:
  42. virtual ~TBStyleEditTextChangeListener() {}
  43. virtual void OnChange(TBStyleEdit* styleEdit) {}
  44. };
  45. /** Creates TBTextFragmentContent if the sequence of text matches known content. */
  46. class TBTextFragmentContentFactory
  47. {
  48. public:
  49. virtual ~TBTextFragmentContentFactory() {}
  50. /** Should return then length of the text that represents content
  51. that can be created by this factory, or 0 there's no match with any content.
  52. F.ex if we can create contet for "<u>" it should return 3 if that is the beginning of
  53. text. That length will be consumed from the text output for the created content. */
  54. virtual int GetContent(const char *text);
  55. /** Create content for a string previosly consumed by calling GetContent. */
  56. virtual TBTextFragmentContent *CreateFragmentContent(const char *text, int text_len);
  57. };
  58. #define TB_MAX_TEXT_THEME_COLORS 256
  59. class TBTextTheme
  60. {
  61. public:
  62. TBColor themeColors[TB_MAX_TEXT_THEME_COLORS];
  63. };
  64. class TBTextOfs
  65. {
  66. public:
  67. TBTextOfs() : block(nullptr), ofs(0) {}
  68. TBTextOfs(TBBlock *block, int32 ofs) : block(block), ofs(ofs) {}
  69. void Set(TBBlock *new_block, int32 new_ofs) { block = new_block; ofs = new_ofs; }
  70. void Set(const TBTextOfs &pos) { block = pos.block; ofs = pos.ofs; }
  71. int32 GetGlobalOfs(TBStyleEdit *se) const;
  72. bool SetGlobalOfs(TBStyleEdit *se, int32 gofs);
  73. public:
  74. TBBlock *block;
  75. int32 ofs;
  76. };
  77. /** Handles the selected text in a TBStyleEdit. */
  78. class TBSelection
  79. {
  80. public:
  81. TBSelection(TBStyleEdit *styledit);
  82. void Invalidate() const;
  83. void Select(const TBTextOfs &new_start, const TBTextOfs &new_stop);
  84. void Select(const TBPoint &from, const TBPoint &to);
  85. void Select(int glob_ofs_from, int glob_ofs_to);
  86. void SelectToCaret(TBBlock *old_caret_block, int32 old_caret_ofs);
  87. void SelectAll();
  88. void SelectNothing();
  89. void CorrectOrder();
  90. void CopyToClipboard();
  91. bool IsBlockSelected(TBBlock *block) const;
  92. bool IsFragmentSelected(TBTextFragment *elm) const;
  93. bool IsSelected() const;
  94. void RemoveContent();
  95. bool GetText(TBStr &text) const;
  96. public:
  97. TBStyleEdit *styledit;
  98. TBTextOfs start, stop;
  99. };
  100. enum TB_CARET_POS {
  101. TB_CARET_POS_BEGINNING,
  102. TB_CARET_POS_END
  103. };
  104. /** The caret in a TBStyleEdit. */
  105. class TBCaret
  106. {
  107. public:
  108. TBCaret(TBStyleEdit *styledit);
  109. void Invalidate();
  110. void UpdatePos();
  111. bool Move(bool forward, bool word);
  112. bool Place(const TBPoint &point);
  113. bool Place(TBBlock *block, int ofs, bool allow_snap = true, bool snap_forward = false);
  114. void Place(TB_CARET_POS place);
  115. void AvoidLineBreak();
  116. void Paint(int32 translate_x, int32 translate_y);
  117. void ResetBlink();
  118. void UpdateWantedX();
  119. int32 GetGlobalOfs() const { return pos.GetGlobalOfs(styledit); }
  120. void SetGlobalOfs(int32 gofs, bool allow_snap = true, bool snap_forward = false);
  121. TBTextFragment *GetFragment();
  122. private:
  123. void SwitchBlock(bool second);
  124. public:
  125. TBStyleEdit *styledit;
  126. int32 x, y; ///< Relative to the styledit
  127. int32 width;
  128. int32 height;
  129. int32 wanted_x;
  130. bool on;
  131. bool prefer_first;
  132. TBTextOfs pos;
  133. };
  134. /** TBTextProps is a stack of properties used during layout & paint of TBStyleEdit. */
  135. class TBTextProps
  136. {
  137. public:
  138. class Data : public TBLinkOf<Data>
  139. {
  140. public:
  141. TBFontDescription font_desc;
  142. TBColor text_color;
  143. bool underline;
  144. };
  145. TBTextProps(const TBFontDescription &font_desc, const TBColor &text_color);
  146. Data *Push();
  147. void Pop();
  148. /** Get the font face from the current font description. */
  149. TBFontFace *GetFont();
  150. public:
  151. TBLinkListOf<Data> data_list;
  152. Data base_data;
  153. Data *data;
  154. };
  155. /** A block of text (a line, that might be wrapped) */
  156. class TBBlock : public TBLinkOf<TBBlock>
  157. {
  158. public:
  159. TBBlock(TBStyleEdit *styledit);
  160. ~TBBlock();
  161. void Clear();
  162. void Set(const char *newstr, int32 len);
  163. void SetAlign(TB_TEXT_ALIGN align);
  164. int32 InsertText(int32 ofs, const char *text, int32 len, bool allow_line_recurse);
  165. void RemoveContent(int32 ofs, int32 len);
  166. /** Check if this block contains extra line breaks and split into new blocks if it does. */
  167. void Split();
  168. /** Check if we've lost the ending break on this block and if so merge it with the next block. */
  169. void Merge();
  170. /** Layout the block. To be called when the text has changed or the layout width has changed.
  171. @param update_fragments Should be true if the text has been changed (will recreate elements).
  172. @param propagate_height If true, all following blocks will be moved if the height changed. */
  173. void Layout(bool update_fragments, bool propagate_height);
  174. /** Update the size of this block. If propagate_height is true, all following blocks will be
  175. moved if the height changed. */
  176. void SetSize(int32 old_w, int32 new_w, int32 new_h, bool propagate_height);
  177. TBTextFragment *FindFragment(int32 ofs, bool prefer_first = false) const;
  178. TBTextFragment *FindFragment(int32 x, int32 y) const;
  179. int32 CalculateStringWidth(TBFontFace *font, const char *str, int len = TB_ALL_TO_TERMINATION) const;
  180. int32 CalculateTabWidth(TBFontFace *font, int32 xpos) const;
  181. int32 CalculateLineHeight(TBFontFace *font) const;
  182. int32 CalculateBaseline(TBFontFace *font) const;
  183. int32 FirstNonTabPos() const;
  184. void Invalidate();
  185. void BuildSelectionRegion(int32 translate_x, int32 translate_y, TBTextProps *props,
  186. TBRegion &bg_region, TBRegion &fg_region);
  187. void Paint(int32 translate_x, int32 translate_y, TBTextProps *props);
  188. public:
  189. TBStyleEdit *styledit;
  190. TBLinkListOf<TBTextFragment> fragments;
  191. int32 ypos;
  192. int16 height;
  193. int8 align;
  194. int line_width_max;
  195. TBStr str;
  196. int32 str_len;
  197. private:
  198. int GetStartIndentation(TBFontFace *font, int first_line_len) const;
  199. };
  200. /** Event in the TBUndoRedoStack. Each insert or remove change is stored as a TBUndoEvent, but they may also be merged when appropriate. */
  201. class TBUndoEvent
  202. {
  203. public:
  204. int32 gofs;
  205. TBStr text;
  206. bool insert;
  207. bool chain;
  208. TBUndoEvent() : gofs(0), insert(false), chain(false) {}
  209. };
  210. /** Keeps track of all TBUndoEvents used for undo and redo functionality. */
  211. class TBUndoRedoStack
  212. {
  213. public:
  214. TBUndoRedoStack() : applying(false) {}
  215. ~TBUndoRedoStack();
  216. void Undo(TBStyleEdit *styledit);
  217. void Redo(TBStyleEdit *styledit);
  218. void Clear(bool clear_undo, bool clear_redo);
  219. TBUndoEvent *Commit(TBStyleEdit *styledit, int32 gofs, int32 len, const char *text, bool insert);
  220. public:
  221. TBListOf<TBUndoEvent> undos;
  222. TBListOf<TBUndoEvent> redos;
  223. bool applying;
  224. private:
  225. void Apply(TBStyleEdit *styledit, TBUndoEvent *e, bool reverse);
  226. };
  227. /** The textfragment baseclass for TBStyleEdit.
  228. TODO: This object is allocated on vast amounts and need
  229. to shrink in size. Remove all cached positioning
  230. and implement a fragment traverser (for TBBlock).
  231. Also allocate fragments in chunks. */
  232. class TBTextFragment : public TBLinkOf<TBTextFragment>
  233. {
  234. public:
  235. TBTextFragment(TBTextFragmentContent *content = nullptr)
  236. : xpos(0)
  237. , ypos(0)
  238. , ofs(0)
  239. , len(0)
  240. , line_ypos(0)
  241. , line_height(0)
  242. , block(nullptr)
  243. , themeColor(0)
  244. , content(content) {}
  245. ~TBTextFragment();
  246. void Init(TBBlock *block, uint16 ofs, uint16 len);
  247. void UpdateContentPos();
  248. void BuildSelectionRegion(int32 translate_x, int32 translate_y, TBTextProps *props,
  249. TBRegion &bg_region, TBRegion &fg_region);
  250. void Paint(int32 translate_x, int32 translate_y, TBTextProps *props);
  251. void Click(int button, uint32 modifierkeys);
  252. bool IsText() const { return !IsEmbedded(); }
  253. bool IsEmbedded() const { return content ? true : false; }
  254. bool IsBreak() const;
  255. bool IsSpace() const;
  256. bool IsTab() const;
  257. int32 GetCharX(TBFontFace *font, int32 ofs);
  258. int32 GetCharOfs(TBFontFace *font, int32 x);
  259. /** Get the stringwidth. Handles passwordmode, tab, linebreaks etc automatically. */
  260. int32 GetStringWidth(TBFontFace *font, const char *str, int len);
  261. bool GetAllowBreakBefore() const;
  262. bool GetAllowBreakAfter() const;
  263. const char *Str() const { return block->str.CStr() + ofs; }
  264. int32 GetWidth(TBFontFace *font);
  265. int32 GetHeight(TBFontFace *font);
  266. int32 GetBaseline(TBFontFace *font);
  267. int32 GetGlobalOfs() const;
  268. public:
  269. int16 xpos, ypos;
  270. uint16 ofs, len;
  271. uint16 line_ypos;
  272. uint16 line_height;
  273. TBBlock *block;
  274. uint16 themeColor;
  275. TBTextFragmentContent *content;
  276. };
  277. /** Edit and formats TBTextFragment's. It handles the text in a TBStyleEditView. */
  278. class TBStyleEdit
  279. {
  280. public:
  281. TBStyleEdit();
  282. virtual ~TBStyleEdit();
  283. void SetListener(TBStyleEditListener *listener);
  284. void SetContentFactory(TBTextFragmentContentFactory *content_factory);
  285. void SetFont(const TBFontDescription &font_desc);
  286. void Paint(const TBRect &rect, const TBFontDescription &font_desc, const TBColor &text_color);
  287. bool KeyDown(int key, SPECIAL_KEY special_key, MODIFIER_KEYS modifierkeys);
  288. bool MouseDown(const TBPoint &point, int button, int clicks, MODIFIER_KEYS modifierkeys, bool touch);
  289. bool MouseUp(const TBPoint &point, int button, MODIFIER_KEYS modifierkeys, bool touch);
  290. bool MouseMove(const TBPoint &point);
  291. void Focus(bool focus);
  292. void Clear(bool init_new = true);
  293. bool Load(const char *filename);
  294. bool SetText(const char *text, TB_CARET_POS pos = TB_CARET_POS_BEGINNING);
  295. bool SetText(const char *text, int text_len, TB_CARET_POS pos = TB_CARET_POS_BEGINNING);
  296. bool GetText(TBStr &text);
  297. bool IsEmpty() const;
  298. /** Set the default text alignment and all currently selected blocks,
  299. or the block of the current caret position if nothing is selected. */
  300. void SetAlign(TB_TEXT_ALIGN align);
  301. void SetMultiline(bool multiline = true);
  302. void SetStyling(bool styling = true);
  303. void SetReadOnly(bool readonly = true);
  304. void SetSelection(bool selection = true);
  305. void SetPassword(bool password = true);
  306. void SetWrapping(bool wrapping = true);
  307. /** Set if line breaks should be inserted in windows style (\r\n)
  308. or unix style (\n). The default is windows style on the windows
  309. platform and disabled elsewhere.
  310. Note: This only affects InsertBreak (pressing enter). Content set from
  311. SetText (and clipboard etc.) maintains the used line break. */
  312. void SetWindowsStyleBreak(bool win_style_br) { packed.win_style_br = win_style_br; }
  313. void Cut();
  314. void Copy();
  315. void Paste();
  316. void Delete();
  317. void Undo();
  318. void Redo();
  319. bool CanUndo() const { return undoredo.undos.GetNumItems() ? true : false; }
  320. bool CanRedo() const { return undoredo.redos.GetNumItems() ? true : false; }
  321. void InsertText(const char *text, int32 len = TB_ALL_TO_TERMINATION, bool after_last = false, bool clear_undo_redo = false);
  322. void AppendText(const char *text, int32 len = TB_ALL_TO_TERMINATION, bool clear_undo_redo = false) { InsertText(text, len, true, clear_undo_redo); }
  323. void InsertBreak();
  324. TBBlock *FindBlock(int32 y) const;
  325. int32 GetCaretLine();
  326. void ScrollIfNeeded(bool x = true, bool y = true);
  327. void SetScrollPos(int32 x, int32 y);
  328. void SetLayoutSize(int32 width, int32 height, bool is_virtual_reformat);
  329. void Reformat(bool update_fragments);
  330. int32 GetContentWidth();
  331. int32 GetContentHeight() const;
  332. int32 GetOverflowX() const { return MAX(content_width - layout_width, 0); }
  333. int32 GetOverflowY() const { return MAX(content_height - layout_height, 0); }
  334. void SetTextTheme(TBTextTheme* theme) { text_theme = theme; }
  335. public:
  336. TBStyleEditListener *listener;
  337. TBTextFragmentContentFactory default_content_factory;
  338. TBTextFragmentContentFactory *content_factory;
  339. TBStyleEditTextChangeListener* text_change_listener;
  340. // TBG
  341. TBTextTheme* text_theme;
  342. // END TBG
  343. int32 layout_width;
  344. int32 layout_height;
  345. int32 content_width;
  346. int32 content_height;
  347. TBLinkListOf<TBBlock> blocks;
  348. TBCaret caret;
  349. TBSelection selection;
  350. TBUndoRedoStack undoredo;
  351. int32 scroll_x;
  352. int32 scroll_y;
  353. int8 select_state;
  354. TBPoint mousedown_point;
  355. TBTextFragment *mousedown_fragment;
  356. /** DEPRECATED! This will be removed when using different fonts is properly supported! */
  357. TBFontFace *font;
  358. TBFontDescription font_desc;
  359. TB_TEXT_ALIGN align;
  360. union { struct {
  361. uint32 multiline_on : 1;
  362. uint32 styling_on : 1;
  363. uint32 read_only : 1;
  364. uint32 selection_on : 1;
  365. uint32 show_whitespace : 1;
  366. uint32 password_on : 1;
  367. uint32 wrapping : 1;
  368. uint32 win_style_br : 1;
  369. uint32 calculate_content_width_needed : 1; ///< If content_width needs to be updated next GetContentWidth-
  370. uint32 lock_scrollbars_counter : 5; ///< Incremental counter for if UpdateScrollbar should be probhited.
  371. } packed;
  372. uint32 packed_init;
  373. };
  374. /** Call BeginLockScrollbars & EndLockScrollbars around a scope which does lots of changes,
  375. to prevent UpdateScrollbar from happening for each block (May cause recalculation of
  376. content_width by iterating through all blocks) */
  377. void BeginLockScrollbars();
  378. void EndLockScrollbars();
  379. /** Return true if changing layout_width and layout_height requires relayouting. */
  380. bool GetSizeAffectsLayout() const;
  381. };
  382. }; // namespace tb
  383. #endif