1 //============================================================================ 2 // 3 // SSSS tt lll lll 4 // SS SS tt ll ll 5 // SS tttttt eeee ll ll aaaa 6 // SSSS tt ee ee ll ll aa 7 // SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator" 8 // SS SS tt ee ll ll aa aa 9 // SSSS ttt eeeee llll llll aaaaa 10 // 11 // Copyright (c) 1995-2021 by Bradford W. Mott, Stephen Anthony 12 // and the Stella Team 13 // 14 // See the file "License.txt" for information on usage and redistribution of 15 // this file, and for a DISCLAIMER OF ALL WARRANTIES. 16 //============================================================================ 17 18 #ifndef EDITABLE_WIDGET_HXX 19 #define EDITABLE_WIDGET_HXX 20 21 #include <functional> 22 23 #include "Widget.hxx" 24 #include "Rect.hxx" 25 #include "ContextMenu.hxx" 26 #include "UndoHandler.hxx" 27 28 /** 29 * Base class for widgets which need to edit text, like ListWidget and 30 * EditTextWidget. 31 * 32 * Widgets wishing to enforce their own editing restrictions are able 33 * to use a 'TextFilter' as described below. 34 */ 35 class EditableWidget : public Widget, public CommandSender 36 { 37 public: 38 /** Function used to test if a specified character can be inserted 39 into the internal buffer */ 40 using TextFilter = std::function<bool(char)>; 41 42 enum { 43 kAcceptCmd = 'EDac', 44 kCancelCmd = 'EDcl', 45 kChangedCmd = 'EDch' 46 }; 47 48 public: 49 EditableWidget(GuiObject* boss, const GUI::Font& font, 50 int x, int y, int w, int h, const string& str = ""); 51 ~EditableWidget() override = default; 52 53 virtual void setText(const string& str, bool changed = false); setMaxLen(int len)54 void setMaxLen(int len) { _maxLen = len; } getText() const55 const string& getText() const { return _editString; } 56 isEditable() const57 bool isEditable() const { return _editable; } isChanged()58 bool isChanged() { return editString() != backupString(); } 59 virtual void setEditable(bool editable, bool hiliteBG = false); 60 61 bool handleText(char text) override; 62 bool handleKeyDown(StellaKey key, StellaMod mod) override; 63 64 // We only want to focus this widget when we can edit its contents wantsFocus() const65 bool wantsFocus() const override { return _editable; } 66 67 // Set filter used to test whether a character can be inserted setTextFilter(const TextFilter & filter)68 void setTextFilter(const TextFilter& filter) { _filter = filter; } 69 70 protected: 71 void handleMouseDown(int x, int y, MouseButton b, int clickCount) override; 72 void handleMouseUp(int x, int y, MouseButton b, int clickCount) override; 73 void handleMouseMoved(int x, int y) override; 74 void handleCommand(CommandSender* sender, int cmd, int data, int id) override; caretOfs() const75 virtual int caretOfs() const { return _editScrollOffset; } 76 int toCaretPos(int x) const; 77 78 void receivedFocusWidget() override; 79 void lostFocusWidget() override; 80 void tick() override; 81 bool wantsToolTip() const override; 82 startEditMode()83 virtual void startEditMode() { setFlags(Widget::FLAG_WANTS_RAWDATA); } endEditMode()84 virtual void endEditMode() { 85 clearFlags(Widget::FLAG_WANTS_RAWDATA); 86 commit(); 87 } abortEditMode()88 virtual void abortEditMode() 89 { 90 clearFlags(Widget::FLAG_WANTS_RAWDATA); 91 abort(); 92 } commit()93 void commit() { _backupString = _editString; } abort()94 void abort() { setText(_backupString); } 95 96 virtual Common::Rect getEditRect() const = 0; 97 virtual int getCaretOffset() const; 98 void drawCaretSelection(); 99 bool setCaretPos(int newPos); 100 bool moveCaretPos(int direction); 101 bool adjustOffset(); 102 103 // This method is used internally by child classes wanting to 104 // access/edit the internal buffer editString()105 string& editString() { return _editString; } backupString()106 string& backupString() { return _backupString; } 107 const string selectString() const; resetSelection()108 void resetSelection() { _selectSize = 0; } 109 int scrollOffset(); 110 111 private: 112 // Line editing 113 bool killChar(int direction, bool addEdit = true); 114 bool killLine(int direction); 115 bool killWord(int direction); 116 bool moveWord(int direction, bool select); 117 bool markWord(); 118 119 bool killSelectedText(bool addEdit = true); 120 int selectStartPos(); 121 int selectEndPos(); 122 // Clipboard 123 bool cutSelectedText(); 124 bool copySelectedText(); 125 bool pasteSelectedText(); 126 127 // Use the current TextFilter to insert a character into the 128 // internal buffer 129 bool tryInsertChar(char c, int pos); 130 131 ContextMenu& mouseMenu(); 132 133 private: 134 unique_ptr<ContextMenu> myMouseMenu; 135 bool _isDragging{false}; 136 137 bool _editable{true}; 138 string _editString; 139 string _backupString; 140 int _maxLen{0}; 141 unique_ptr<UndoHandler> myUndoHandler; 142 143 int _caretPos{0}; 144 int _caretTimer{0}; 145 bool _caretEnabled{true}; 146 147 // Size of current selected text 148 // 0 = no selection 149 // <0 = selected left of caret 150 // >0 = selected right of caret 151 int _selectSize{0}; 152 153 protected: 154 int _editScrollOffset{0}; 155 bool _editMode{true}; 156 int _dyText{0}; 157 158 private: 159 TextFilter _filter; 160 161 private: 162 // Following constructors and assignment operators not supported 163 EditableWidget() = delete; 164 EditableWidget(const EditableWidget&) = delete; 165 EditableWidget(EditableWidget&&) = delete; 166 EditableWidget& operator=(const EditableWidget&) = delete; 167 EditableWidget& operator=(EditableWidget&&) = delete; 168 }; 169 170 #endif 171