| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481 |
- // ================================================================================
- // == This file is a part of Turbo Badger. (C) 2011-2014, Emil Segerås ==
- // == See tb_core.h for more information. ==
- // ================================================================================
- #ifndef TBStyleEdit_H
- #define TBStyleEdit_H
- #include "tb_core.h"
- #include "tb_linklist.h"
- #include "tb_widgets_common.h"
- #include "tb_list.h"
- namespace tb {
- class TBStyleEdit;
- class TBBlock;
- class TBTextFragment;
- class TBTextFragmentContent;
- class TBTextFragmentContentFactory;
- // TBG
- class TBTextTheme;
- // END TBG
- /** Listener for TBStyleEdit. Implement in the enviorment the TBStyleEdit should render its content. */
- class TBStyleEditListener
- {
- public:
- virtual ~TBStyleEditListener() {}
- virtual void OnChange() {};
- virtual bool OnEnter() { return false; };
- virtual void Invalidate(const TBRect &rect) = 0;
- virtual void DrawString(int32 x, int32 y, TBFontFace *font, const TBColor &color, const char *str, int32 len = TB_ALL_TO_TERMINATION) = 0;
- virtual void DrawRect(const TBRect &rect, const TBColor &color) = 0;
- virtual void DrawRectFill(const TBRect &rect, const TBColor &color) = 0;
- virtual void DrawTextSelectionBg(const TBRect &rect) = 0;
- virtual void DrawContentSelectionFg(const TBRect &rect) = 0;
- virtual void DrawCaret(const TBRect &rect) = 0;
- virtual void Scroll(int32 dx, int32 dy) = 0;
- virtual void UpdateScrollbars() = 0;
- virtual void CaretBlinkStart() = 0;
- virtual void CaretBlinkStop() = 0;
- };
- class TBStyleEditTextChangeListener
- {
- public:
- virtual ~TBStyleEditTextChangeListener() {}
- virtual void OnChange(TBStyleEdit* styleEdit) {}
- };
- /** Creates TBTextFragmentContent if the sequence of text matches known content. */
- class TBTextFragmentContentFactory
- {
- public:
- virtual ~TBTextFragmentContentFactory() {}
- /** Should return then length of the text that represents content
- that can be created by this factory, or 0 there's no match with any content.
- F.ex if we can create contet for "<u>" it should return 3 if that is the beginning of
- text. That length will be consumed from the text output for the created content. */
- virtual int GetContent(const char *text);
- /** Create content for a string previosly consumed by calling GetContent. */
- virtual TBTextFragmentContent *CreateFragmentContent(const char *text, int text_len);
- };
- #define TB_MAX_TEXT_THEME_COLORS 256
- class TBTextTheme
- {
- public:
- TBColor themeColors[TB_MAX_TEXT_THEME_COLORS];
- };
- class TBTextOfs
- {
- public:
- TBTextOfs() : block(nullptr), ofs(0) {}
- TBTextOfs(TBBlock *block, int32 ofs) : block(block), ofs(ofs) {}
- void Set(TBBlock *new_block, int32 new_ofs) { block = new_block; ofs = new_ofs; }
- void Set(const TBTextOfs &pos) { block = pos.block; ofs = pos.ofs; }
- int32 GetGlobalOfs(TBStyleEdit *se) const;
- bool SetGlobalOfs(TBStyleEdit *se, int32 gofs);
- public:
- TBBlock *block;
- int32 ofs;
- };
- /** Handles the selected text in a TBStyleEdit. */
- class TBSelection
- {
- public:
- TBSelection(TBStyleEdit *styledit);
- void Invalidate() const;
- void Select(const TBTextOfs &new_start, const TBTextOfs &new_stop);
- void Select(const TBPoint &from, const TBPoint &to);
- void Select(int glob_ofs_from, int glob_ofs_to);
- void SelectToCaret(TBBlock *old_caret_block, int32 old_caret_ofs);
- void SelectAll();
- void SelectNothing();
- void CorrectOrder();
- void CopyToClipboard();
- bool IsBlockSelected(TBBlock *block) const;
- bool IsFragmentSelected(TBTextFragment *elm) const;
- bool IsSelected() const;
- void RemoveContent();
- bool GetText(TBStr &text) const;
- public:
- TBStyleEdit *styledit;
- TBTextOfs start, stop;
- };
- enum TB_CARET_POS {
- TB_CARET_POS_BEGINNING,
- TB_CARET_POS_END
- };
- /** The caret in a TBStyleEdit. */
- class TBCaret
- {
- public:
- TBCaret(TBStyleEdit *styledit);
- void Invalidate();
- void UpdatePos();
- bool Move(bool forward, bool word);
- bool Place(const TBPoint &point);
- bool Place(TBBlock *block, int ofs, bool allow_snap = true, bool snap_forward = false);
- void Place(TB_CARET_POS place);
- void AvoidLineBreak();
- void Paint(int32 translate_x, int32 translate_y);
- void ResetBlink();
- void UpdateWantedX();
- int32 GetGlobalOfs() const { return pos.GetGlobalOfs(styledit); }
- void SetGlobalOfs(int32 gofs, bool allow_snap = true, bool snap_forward = false);
- TBTextFragment *GetFragment();
- private:
- void SwitchBlock(bool second);
- public:
- TBStyleEdit *styledit;
- int32 x, y; ///< Relative to the styledit
- int32 width;
- int32 height;
- int32 wanted_x;
- bool on;
- bool prefer_first;
- TBTextOfs pos;
- };
- /** TBTextProps is a stack of properties used during layout & paint of TBStyleEdit. */
- class TBTextProps
- {
- public:
- class Data : public TBLinkOf<Data>
- {
- public:
- TBFontDescription font_desc;
- TBColor text_color;
- bool underline;
- };
- TBTextProps(const TBFontDescription &font_desc, const TBColor &text_color);
- Data *Push();
- void Pop();
- /** Get the font face from the current font description. */
- TBFontFace *GetFont();
- public:
- TBLinkListOf<Data> data_list;
- Data base_data;
- Data *data;
- };
- /** A block of text (a line, that might be wrapped) */
- class TBBlock : public TBLinkOf<TBBlock>
- {
- public:
- TBBlock(TBStyleEdit *styledit);
- ~TBBlock();
- void Clear();
- void Set(const char *newstr, int32 len);
- void SetAlign(TB_TEXT_ALIGN align);
- int32 InsertText(int32 ofs, const char *text, int32 len, bool allow_line_recurse);
- void RemoveContent(int32 ofs, int32 len);
- /** Check if this block contains extra line breaks and split into new blocks if it does. */
- void Split();
- /** Check if we've lost the ending break on this block and if so merge it with the next block. */
- void Merge();
- /** Layout the block. To be called when the text has changed or the layout width has changed.
- @param update_fragments Should be true if the text has been changed (will recreate elements).
- @param propagate_height If true, all following blocks will be moved if the height changed. */
- void Layout(bool update_fragments, bool propagate_height);
- /** Update the size of this block. If propagate_height is true, all following blocks will be
- moved if the height changed. */
- void SetSize(int32 old_w, int32 new_w, int32 new_h, bool propagate_height);
- TBTextFragment *FindFragment(int32 ofs, bool prefer_first = false) const;
- TBTextFragment *FindFragment(int32 x, int32 y) const;
- int32 CalculateStringWidth(TBFontFace *font, const char *str, int len = TB_ALL_TO_TERMINATION) const;
- int32 CalculateTabWidth(TBFontFace *font, int32 xpos) const;
- int32 CalculateLineHeight(TBFontFace *font) const;
- int32 CalculateBaseline(TBFontFace *font) const;
- int32 FirstNonTabPos() const;
- void Invalidate();
- void BuildSelectionRegion(int32 translate_x, int32 translate_y, TBTextProps *props,
- TBRegion &bg_region, TBRegion &fg_region);
- void Paint(int32 translate_x, int32 translate_y, TBTextProps *props);
- public:
- TBStyleEdit *styledit;
- TBLinkListOf<TBTextFragment> fragments;
- int32 ypos;
- int16 height;
- int8 align;
- int line_width_max;
- TBStr str;
- int32 str_len;
- private:
- int GetStartIndentation(TBFontFace *font, int first_line_len) const;
- };
- /** Event in the TBUndoRedoStack. Each insert or remove change is stored as a TBUndoEvent, but they may also be merged when appropriate. */
- class TBUndoEvent
- {
- public:
- int32 gofs;
- TBStr text;
- bool insert;
- bool chain;
- TBUndoEvent() : gofs(0), insert(false), chain(false) {}
- };
- /** Keeps track of all TBUndoEvents used for undo and redo functionality. */
- class TBUndoRedoStack
- {
- public:
- TBUndoRedoStack() : applying(false) {}
- ~TBUndoRedoStack();
- void Undo(TBStyleEdit *styledit);
- void Redo(TBStyleEdit *styledit);
- void Clear(bool clear_undo, bool clear_redo);
- TBUndoEvent *Commit(TBStyleEdit *styledit, int32 gofs, int32 len, const char *text, bool insert);
- public:
- TBListOf<TBUndoEvent> undos;
- TBListOf<TBUndoEvent> redos;
- bool applying;
- private:
- void Apply(TBStyleEdit *styledit, TBUndoEvent *e, bool reverse);
- };
- /** The textfragment baseclass for TBStyleEdit.
- TODO: This object is allocated on vast amounts and need
- to shrink in size. Remove all cached positioning
- and implement a fragment traverser (for TBBlock).
- Also allocate fragments in chunks. */
- class TBTextFragment : public TBLinkOf<TBTextFragment>
- {
- public:
- TBTextFragment(TBTextFragmentContent *content = nullptr)
- : xpos(0)
- , ypos(0)
- , ofs(0)
- , len(0)
- , line_ypos(0)
- , line_height(0)
- , block(nullptr)
- , themeColor(0)
- , content(content) {}
- ~TBTextFragment();
- void Init(TBBlock *block, uint16 ofs, uint16 len);
- void UpdateContentPos();
- void BuildSelectionRegion(int32 translate_x, int32 translate_y, TBTextProps *props,
- TBRegion &bg_region, TBRegion &fg_region);
- void Paint(int32 translate_x, int32 translate_y, TBTextProps *props);
- void Click(int button, uint32 modifierkeys);
- bool IsText() const { return !IsEmbedded(); }
- bool IsEmbedded() const { return content ? true : false; }
- bool IsBreak() const;
- bool IsSpace() const;
- bool IsTab() const;
- int32 GetCharX(TBFontFace *font, int32 ofs);
- int32 GetCharOfs(TBFontFace *font, int32 x);
- /** Get the stringwidth. Handles passwordmode, tab, linebreaks etc automatically. */
- int32 GetStringWidth(TBFontFace *font, const char *str, int len);
- bool GetAllowBreakBefore() const;
- bool GetAllowBreakAfter() const;
- const char *Str() const { return block->str.CStr() + ofs; }
- int32 GetWidth(TBFontFace *font);
- int32 GetHeight(TBFontFace *font);
- int32 GetBaseline(TBFontFace *font);
- int32 GetGlobalOfs() const;
- public:
- int16 xpos, ypos;
- uint16 ofs, len;
- uint16 line_ypos;
- uint16 line_height;
- TBBlock *block;
- uint16 themeColor;
- TBTextFragmentContent *content;
- };
- /** Edit and formats TBTextFragment's. It handles the text in a TBStyleEditView. */
- class TBStyleEdit
- {
- public:
- TBStyleEdit();
- virtual ~TBStyleEdit();
- void SetListener(TBStyleEditListener *listener);
- void SetContentFactory(TBTextFragmentContentFactory *content_factory);
- void SetFont(const TBFontDescription &font_desc);
- void Paint(const TBRect &rect, const TBFontDescription &font_desc, const TBColor &text_color);
- bool KeyDown(int key, SPECIAL_KEY special_key, MODIFIER_KEYS modifierkeys);
- bool MouseDown(const TBPoint &point, int button, int clicks, MODIFIER_KEYS modifierkeys, bool touch);
- bool MouseUp(const TBPoint &point, int button, MODIFIER_KEYS modifierkeys, bool touch);
- bool MouseMove(const TBPoint &point);
- void Focus(bool focus);
- void Clear(bool init_new = true);
- bool Load(const char *filename);
- bool SetText(const char *text, TB_CARET_POS pos = TB_CARET_POS_BEGINNING);
- bool SetText(const char *text, int text_len, TB_CARET_POS pos = TB_CARET_POS_BEGINNING);
- bool GetText(TBStr &text);
- bool IsEmpty() const;
- /** Set the default text alignment and all currently selected blocks,
- or the block of the current caret position if nothing is selected. */
- void SetAlign(TB_TEXT_ALIGN align);
- void SetMultiline(bool multiline = true);
- void SetStyling(bool styling = true);
- void SetReadOnly(bool readonly = true);
- void SetSelection(bool selection = true);
- void SetPassword(bool password = true);
- void SetWrapping(bool wrapping = true);
- /** Set if line breaks should be inserted in windows style (\r\n)
- or unix style (\n). The default is windows style on the windows
- platform and disabled elsewhere.
- Note: This only affects InsertBreak (pressing enter). Content set from
- SetText (and clipboard etc.) maintains the used line break. */
- void SetWindowsStyleBreak(bool win_style_br) { packed.win_style_br = win_style_br; }
- void Cut();
- void Copy();
- void Paste();
- void Delete();
- void Undo();
- void Redo();
- bool CanUndo() const { return undoredo.undos.GetNumItems() ? true : false; }
- bool CanRedo() const { return undoredo.redos.GetNumItems() ? true : false; }
- void InsertText(const char *text, int32 len = TB_ALL_TO_TERMINATION, bool after_last = false, bool clear_undo_redo = false);
- void AppendText(const char *text, int32 len = TB_ALL_TO_TERMINATION, bool clear_undo_redo = false) { InsertText(text, len, true, clear_undo_redo); }
- void InsertBreak();
- TBBlock *FindBlock(int32 y) const;
- int32 GetCaretLine();
- void ScrollIfNeeded(bool x = true, bool y = true);
- void SetScrollPos(int32 x, int32 y);
- void SetLayoutSize(int32 width, int32 height, bool is_virtual_reformat);
- void Reformat(bool update_fragments);
- int32 GetContentWidth();
- int32 GetContentHeight() const;
- int32 GetOverflowX() const { return MAX(content_width - layout_width, 0); }
- int32 GetOverflowY() const { return MAX(content_height - layout_height, 0); }
- void SetTextTheme(TBTextTheme* theme) { text_theme = theme; }
- public:
- TBStyleEditListener *listener;
- TBTextFragmentContentFactory default_content_factory;
- TBTextFragmentContentFactory *content_factory;
- TBStyleEditTextChangeListener* text_change_listener;
- // TBG
- TBTextTheme* text_theme;
- // END TBG
- int32 layout_width;
- int32 layout_height;
- int32 content_width;
- int32 content_height;
- TBLinkListOf<TBBlock> blocks;
- TBCaret caret;
- TBSelection selection;
- TBUndoRedoStack undoredo;
- int32 scroll_x;
- int32 scroll_y;
- int8 select_state;
- TBPoint mousedown_point;
- TBTextFragment *mousedown_fragment;
- /** DEPRECATED! This will be removed when using different fonts is properly supported! */
- TBFontFace *font;
- TBFontDescription font_desc;
- TB_TEXT_ALIGN align;
- union { struct {
- uint32 multiline_on : 1;
- uint32 styling_on : 1;
- uint32 read_only : 1;
- uint32 selection_on : 1;
- uint32 show_whitespace : 1;
- uint32 password_on : 1;
- uint32 wrapping : 1;
- uint32 win_style_br : 1;
- uint32 calculate_content_width_needed : 1; ///< If content_width needs to be updated next GetContentWidth-
- uint32 lock_scrollbars_counter : 5; ///< Incremental counter for if UpdateScrollbar should be probhited.
- } packed;
- uint32 packed_init;
- };
- /** Call BeginLockScrollbars & EndLockScrollbars around a scope which does lots of changes,
- to prevent UpdateScrollbar from happening for each block (May cause recalculation of
- content_width by iterating through all blocks) */
- void BeginLockScrollbars();
- void EndLockScrollbars();
- /** Return true if changing layout_width and layout_height requires relayouting. */
- bool GetSizeAffectsLayout() const;
- };
- }; // namespace tb
- #endif
|