| 1 | /* |
| 2 | * LegacyClonk |
| 3 | * |
| 4 | * Copyright (c) RedWolf Design |
| 5 | * Copyright (c) 2001, Sven2 |
| 6 | * Copyright (c) 2017-2023, The LegacyClonk Team and contributors |
| 7 | * |
| 8 | * Distributed under the terms of the ISC license; see accompanying file |
| 9 | * "COPYING" for details. |
| 10 | * |
| 11 | * "Clonk" is a registered trademark of Matthes Bender, used with permission. |
| 12 | * See accompanying file "TRADEMARK" for details. |
| 13 | * |
| 14 | * To redistribute this file separately, substitute the full license texts |
| 15 | * for the above references. |
| 16 | */ |
| 17 | |
| 18 | #pragma once |
| 19 | |
| 20 | #include "C4Gui.h" |
| 21 | |
| 22 | namespace C4GUI |
| 23 | { |
| 24 | // an edit control to type text in |
| 25 | class Edit : public Control |
| 26 | { |
| 27 | public: |
| 28 | Edit(const C4Rect &rtBounds, bool fFocusEdit = false); |
| 29 | ~Edit(); |
| 30 | |
| 31 | private: |
| 32 | enum CursorOperation { COP_BACK, COP_DELETE, COP_LEFT, COP_RIGHT, COP_HOME, COP_END, }; |
| 33 | |
| 34 | bool KeyCursorOp(C4KeyCodeEx key, CursorOperation op); |
| 35 | bool KeyEnter(); |
| 36 | bool KeyCopy() { Copy(); return true; } |
| 37 | bool KeyPaste() { Paste(); return true; } |
| 38 | bool KeyCut() { Cut(); return true; } |
| 39 | bool KeySelectAll() { SelectAll(); return true; } |
| 40 | |
| 41 | class C4KeyBinding *RegisterCursorOp(CursorOperation op, C4KeyCode key, const char *szName, C4CustomKey::Priority eKeyPrio); |
| 42 | |
| 43 | class C4KeyBinding *pKeyCursorBack, *pKeyCursorDel, *pKeyCursorLeft, *pKeyCursorRight, *pKeyCursorHome, *pKeyCursorEnd, |
| 44 | *pKeyEnter, *pKeyCopy, *pKeyPaste, *pKeyCut, *pKeySelAll; |
| 45 | |
| 46 | protected: |
| 47 | // context callbacks |
| 48 | ContextMenu *OnContext(C4GUI::Element *pListItem, int32_t iX, int32_t iY); |
| 49 | void OnCtxCopy(C4GUI::Element *pThis) { Copy(); } |
| 50 | void OnCtxPaste(C4GUI::Element *pThis) { Paste(); } |
| 51 | void OnCtxCut(C4GUI::Element *pThis) { Cut(); } |
| 52 | void OnCtxClear(C4GUI::Element *pThis) { DeleteSelection(); } |
| 53 | void OnCtxSelAll(C4GUI::Element *pThis) { SelectAll(); } |
| 54 | |
| 55 | private: |
| 56 | void Deselect(); // clear selection range |
| 57 | |
| 58 | public: |
| 59 | bool InsertText(C4NullableStringView text, bool fUser); // insert text at cursor pos (returns whether all text could be inserted) |
| 60 | void ClearText(); // remove all the text |
| 61 | void DeleteSelection(); // deletes the selected text. Adjust cursor position if necessary |
| 62 | bool SetText(const C4NullableStringView text, bool fUser) { ClearText(); return InsertText(text, fUser); } |
| 63 | void SetPasswordMask(char cNewPasswordMask) { cPasswordMask = cNewPasswordMask; } // mask edit box contents using the given character |
| 64 | |
| 65 | private: |
| 66 | int32_t GetCharPos(int32_t iControlXPos); // get character index of pixel position; always resides within current text length |
| 67 | void EnsureBufferSize(int32_t iMinBufferSize); // ensure buffer has desired size |
| 68 | void ScrollCursorInView(); // ensure cursor pos is visible in edit control |
| 69 | bool DoFinishInput(bool fPasting, bool fPastingMore); // do OnFinishInput callback and process result - returns whether pasting operation should be continued |
| 70 | |
| 71 | bool Copy(); bool Cut(); bool Paste(); // clipboard operations |
| 72 | |
| 73 | protected: |
| 74 | CStdFont *pFont; // font for edit |
| 75 | char *Text; // edit text |
| 76 | uint32_t dwBGClr, dwFontClr, dwBorderColor; // drawing colors for edit box |
| 77 | int32_t iBufferSize; // size of current buffer |
| 78 | int32_t iCursorPos; // cursor position: char, before which the cursor is located |
| 79 | int32_t iSelectionStart, iSelectionEnd; // selection range (start may be larger than end) |
| 80 | int32_t iMaxTextLength; // maximum number of characters to be input here |
| 81 | uint32_t dwLastInputTime; // time of last input (for cursor flashing) |
| 82 | int32_t iXScroll; // horizontal scrolling |
| 83 | char cPasswordMask; // character to be used for masking the contents. 0 for none. |
| 84 | |
| 85 | bool fLeftBtnDown; // flag whether left mouse button is down or not |
| 86 | |
| 87 | virtual bool CharIn(const char *c) override; // input: character key pressed - should return false for none-character-inputs |
| 88 | virtual void MouseInput(CMouse &rMouse, int32_t iButton, int32_t iX, int32_t iY, uint32_t dwKeyParam) override; // input: mouse movement or buttons |
| 89 | virtual void DoDragging(CMouse &rMouse, int32_t iX, int32_t iY, uint32_t dwKeyParam) override; // dragging: allow text selection outside the component |
| 90 | virtual bool IsFocusOnClick() override { return true; } // edit fields do get focus on click |
| 91 | virtual void OnGetFocus(bool fByMouse) override; // edit control gets focus |
| 92 | virtual void OnLooseFocus() override; // edit control looses focus |
| 93 | |
| 94 | virtual void DrawElement(C4FacetEx &cgo) override; // draw edit control |
| 95 | |
| 96 | // called when user presses enter in single-line edit control - closes the current dialog |
| 97 | virtual InputResult OnFinishInput(bool fPasting, bool fPastingMore) { return IR_CloseDlg; } |
| 98 | virtual void OnAbortInput() {} |
| 99 | virtual void OnTextChange() {} |
| 100 | |
| 101 | // get margins from bounds to client rect |
| 102 | virtual int32_t GetMarginTop() override { return 2; } |
| 103 | virtual int32_t GetMarginLeft() override { return 4; } |
| 104 | virtual int32_t GetMarginRight() override { return 4; } |
| 105 | virtual int32_t GetMarginBottom() override { return 2; } |
| 106 | |
| 107 | public: |
| 108 | const char *GetText() { return Text; } |
| 109 | void SelectAll(); // select all the text |
| 110 | |
| 111 | static int32_t GetDefaultEditHeight(); |
| 112 | static int32_t GetCustomEditHeight(CStdFont *pUseFont); |
| 113 | |
| 114 | bool GetCurrentWord(char *szTargetBuf, int32_t iMaxTargetBufLen); // get word before cursor pos (for nick completion) |
| 115 | |
| 116 | // layout |
| 117 | void SetFont(CStdFont *pToFont) { pFont = pToFont; ScrollCursorInView(); } |
| 118 | |
| 119 | void SetColors(uint32_t dwNewBGClr, uint32_t dwNewFontClr, uint32_t dwNewBorderColor) |
| 120 | { |
| 121 | dwBGClr = dwNewBGClr; dwFontClr = dwNewFontClr; dwBorderColor = dwNewBorderColor; |
| 122 | } |
| 123 | |
| 124 | void SetMaxText(int32_t iTo) { iMaxTextLength = iTo; } |
| 125 | }; |
| 126 | |
| 127 | // an edit doing some callback |
| 128 | template <class CallbackCtrl> class CallbackEdit : public Edit |
| 129 | { |
| 130 | private: |
| 131 | CallbackCtrl *pCBCtrl; |
| 132 | |
| 133 | protected: |
| 134 | typedef InputResult(CallbackCtrl::*CBFunc)(Edit *, bool, bool); |
| 135 | typedef void (CallbackCtrl::*CBAbortFunc)(); |
| 136 | CBFunc pCBFunc; CBAbortFunc pCBAbortFunc; |
| 137 | |
| 138 | virtual InputResult OnFinishInput(bool fPasting, bool fPastingMore) override |
| 139 | { |
| 140 | if (pCBFunc && pCBCtrl) return (pCBCtrl->*pCBFunc)(this, fPasting, fPastingMore); else return IR_CloseDlg; |
| 141 | } |
| 142 | |
| 143 | virtual void OnAbortInput() override |
| 144 | { |
| 145 | if (pCBAbortFunc && pCBCtrl)(pCBCtrl->*pCBAbortFunc)(); |
| 146 | } |
| 147 | |
| 148 | public: |
| 149 | CallbackEdit(const C4Rect &rtBounds, CallbackCtrl *pCBCtrl, CBFunc pCBFunc, CBAbortFunc pCBAbortFunc = nullptr) |
| 150 | : Edit(rtBounds), pCBCtrl(pCBCtrl), pCBFunc(pCBFunc), pCBAbortFunc(pCBAbortFunc) {} |
| 151 | }; |
| 152 | |
| 153 | // an edit control that renames a label - some less decoration; abort on Escape and focus loss |
| 154 | class RenameEdit : public Edit |
| 155 | { |
| 156 | private: |
| 157 | C4KeyBinding *pKeyAbort; // key bindings |
| 158 | bool fFinishing; // set during deletion process |
| 159 | Label *pForLabel; // label that is being renamed |
| 160 | Control *pPrevFocusCtrl; // previous focus element to be restored after rename |
| 161 | |
| 162 | public: |
| 163 | RenameEdit(Label *pLabel); // construct for label; add element; set focus |
| 164 | virtual ~RenameEdit(); |
| 165 | |
| 166 | void Abort(); |
| 167 | |
| 168 | private: |
| 169 | void FinishRename(); // renaming aborted or finished - remove this element and restore label |
| 170 | |
| 171 | protected: |
| 172 | bool KeyAbort() { Abort(); return true; } |
| 173 | virtual InputResult OnFinishInput(bool fPasting, bool fPastingMore) override; // forward last input to OnOKRename |
| 174 | virtual void OnLooseFocus() override; // callback when control looses focus: OK input |
| 175 | |
| 176 | virtual void OnCancelRename() {} // renaming was aborted |
| 177 | virtual RenameResult OnOKRename(const char *szNewName) = 0; // rename performed - return whether name was accepted |
| 178 | }; |
| 179 | |
| 180 | template <class CallbackDlg, class ParType> class CallbackRenameEdit : public RenameEdit |
| 181 | { |
| 182 | protected: |
| 183 | typedef void (CallbackDlg::*CBCancelFunc)(ParType); |
| 184 | typedef RenameResult(CallbackDlg::*CBOKFunc)(ParType, const char *); |
| 185 | |
| 186 | CBCancelFunc pCBCancelFunc; CBOKFunc pCBOKFunc; |
| 187 | CallbackDlg *pDlg; ParType par; |
| 188 | |
| 189 | virtual void OnCancelRename() override { if (pDlg && pCBCancelFunc)(pDlg->*pCBCancelFunc)(par); } |
| 190 | virtual RenameResult OnOKRename(const char *szNewName) override { return (pDlg && pCBOKFunc) ? (pDlg->*pCBOKFunc)(par, szNewName) : RR_Accepted; } |
| 191 | |
| 192 | public: |
| 193 | CallbackRenameEdit(Label *pForLabel, CallbackDlg *pDlg, const ParType &par, CBOKFunc pCBOKFunc, CBCancelFunc pCBCancelFunc) |
| 194 | : RenameEdit(pForLabel), pDlg(pDlg), par(par), pCBOKFunc(pCBOKFunc), pCBCancelFunc(pCBCancelFunc) {} |
| 195 | }; |
| 196 | |
| 197 | // editbox below descriptive label sharing one window for common tooltip |
| 198 | class LabeledEdit : public C4GUI::Window |
| 199 | { |
| 200 | public: |
| 201 | LabeledEdit(const C4Rect &rcBounds, const char *szName, bool fMultiline, const char *szPrefText = nullptr, CStdFont *pUseFont = nullptr, uint32_t dwTextClr = C4GUI_CaptionFontClr); |
| 202 | |
| 203 | private: |
| 204 | C4GUI::Edit *pEdit; |
| 205 | |
| 206 | public: |
| 207 | const char *GetText() const { return pEdit->GetText(); } |
| 208 | C4GUI::Edit *GetEdit() const { return pEdit; } |
| 209 | static bool GetControlSize(int *piWdt, int *piHgt, const char *szForText, CStdFont *pForFont, bool fMultiline); |
| 210 | }; |
| 211 | } |
| 212 | |