/* Copyright (c) 2020 Alex Diener This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. Alex Diener alex@ludobloom.com */ #ifndef __UIEditText_H__ #define __UIEditText_H__ #ifdef __cplusplus extern "C" { #endif typedef struct UIEditText UIEditText; #define UIEditText_superclass UIElement #include "font/String.h" #include "shell/Shell.h" #include "uitoolkit/UIElement.h" #include "uitoolkit/UITextLayout.h" #include "utilities/HashTable.h" #define EDIT_TEXT_UNFOCUS_HIT_TEST_PRIORITY 10 #define EDIT_TEXT_KEY_DOWN_PRIORITY 200 typedef enum UIEditText_action { UIEditText_action_ignore, UIEditText_action_focus, UIEditText_action_selectAll, UIEditText_action_clear } UIEditText_action; typedef enum UIEditText_newlineBehavior { UIEditText_newline_neverInsert, UIEditText_newline_controlToCommit, UIEditText_newline_shiftToInsert } UIEditText_newlineBehavior; typedef void (* UIEditTextCallback)(UIEditText * editText, double referenceTime, void * context); typedef bool (* UIEditTextNewlineActionCallback)(UIEditText * editText, unsigned int modifiers, double referenceTime, void * context); #define UIEditText_ivars \ UIElement_ivars \ \ UITextLayout * textLayout; \ String lastCommittedText; \ String editBuffer; \ size_t private_ivar(editBufferAllocatedSize); \ Vector2f size; \ Vector2f innerSize; \ Vector2f minSize; \ Vector2f lastSize; \ UIOverflowMode overflowModeX; \ UIOverflowMode overflowModeY; \ UIEditTextNewlineActionCallback newlineActionCallback; \ UIEditTextCallback textChangedCallback; \ UIEditTextCallback textChangeCompleteCallback; \ UIEditTextCallback textChangeCanceledCallback; \ void * callbackContext; \ size_t cursorIndex; \ size_t selectionAnchorIndex; \ Vector2f scrollOffset; \ float cursorPreferredX; \ ShellTimer cursorBlinkTimer; \ bool cursorBlinkState; \ double lastMouseDownReferenceTime; \ Vector2f lastMouseDownPosition; \ size_t wordSelectionStartIndex; \ unsigned int lineSelectionStartIndex; \ bool draggingSelection; \ bool selectAllOnMouseUp; \ bool hasFocus; \ bool editedSinceFocus; \ ShellTimer dragScrollTimer; \ Vector2f dragScrollForce; \ HashTable * blacklist; \ HashTable * whitelist; \ /* Set these externally after initialization to change behavior */ \ bool selectAllOnFocus; \ bool selectAllOnTabFocus; \ bool selectionEnabled; \ bool editingEnabled; \ UIEditText_action rightClickAction; \ bool forwardDialogKeypresses; \ bool tabKeyInputsCharacter; \ UIEditText_newlineBehavior newlineBehavior; #define UIEditText_vtable(self_type) \ UIElement_vtable(self_type) \ \ String (* getText)(self_type * self); \ void (* setText)(self_type * self, String text); \ String (* getSelectedText)(self_type * self); \ void (* inputText)(self_type * self, String text); \ void (* commitText)(self_type * self); \ void (* revertText)(self_type * self); \ void (* selectAll)(self_type * self); \ void (* getSelectionRange)(self_type * self, size_t * outSelectionStartIndex, size_t * outSelectionEndIndex); \ bool (* canCopyToClipboard)(self_type * self); \ bool (* copyToClipboard)(self_type * self, bool cut); \ bool (* canPasteClipboardContents)(self_type * self); \ bool (* pasteClipboardContents)(self_type * self); \ void (* setBlacklist)(self_type * self, String blacklistCharacters); \ void (* setWhitelist)(self_type * self, String whitelistCharacters); \ void (* setAlignMode)(self_type * self, TextAlignMode alignMode); \ void (* scrollToIndex)(self_type * self, size_t index); \ void (* scrollToRange)(self_type * self, size_t index1, size_t index2); stemobject_declare(UIEditText) // newlineActionCallback is called when the enter key is pressed. Setting it to non-NULL prevents newlines from being inserted. // textChangedCallback, if defined, is called on every user-initiated character insertion or deletion. // textChangeCompleteCallback is called on user-initiated focus loss or newline action after text has been modified. // If newlineActionCallback will be called and textChangeCompleteCallback is defined, newlineActionCallback is called first. // If newlineActionCallback returns true, textChangeCompleteCallback will not be called afterward. UIEditText * UIEditText_create(String text, Vector2f position, Vector2f size, Vector2f relativeOrigin, TextAlignMode alignMode, WordWrapBehavior wrapBehavior, UIOverflowMode overflowModeX, UIOverflowMode overflowModeY, UIEditTextNewlineActionCallback newlineActionCallback, UIEditTextCallback textChangedCallback, UIEditTextCallback textChangeCompleteCallback, UIEditTextCallback textChangeCanceledCallback, void * callbackContext, UIAppearance appearance); bool UIEditText_init(UIEditText * self, String text, Vector2f position, Vector2f size, Vector2f relativeOrigin, TextAlignMode alignMode, WordWrapBehavior wrapBehavior, UIOverflowMode overflowModeX, UIOverflowMode overflowModeY, UIEditTextNewlineActionCallback newlineActionCallback, UIEditTextCallback textChangedCallback, UIEditTextCallback textChangeCompleteCallback, UIEditTextCallback textChangeCanceledCallback, void * callbackContext, UIAppearance appearance); void UIEditText_dispose(UIEditText * self); // Creates a single line UIEditText with reasonable default settings UIEditText * UIEditText_createSimple(String text, Vector2f position, Vector2f relativeOrigin, float width, TextAlignMode alignMode, UIEditTextCallback textChangeCompleteCallback, void * callbackContext, UIAppearance appearance); bool UIEditText_initSimple(UIEditText * self, String text, Vector2f position, Vector2f relativeOrigin, float width, TextAlignMode alignMode, UIEditTextCallback textChangeCompleteCallback, void * callbackContext, UIAppearance appearance); bool UIEditText_hitTest(UIEditText * self, float x, float y, UIHitTestType type, int * outPriority, bool * outForwardNext); UIEventResponse UIEditText_mouseDown(UIEditText * self, unsigned int buttonNumber, unsigned int buttonMask, float x, float y, unsigned int modifiers, bool isFinalTarget, double referenceTime); bool UIEditText_mouseDragged(UIEditText * self, unsigned int buttonMask, float x, float y, float deltaX, float deltaY, unsigned int modifiers, double referenceTime); bool UIEditText_mouseUp(UIEditText * self, unsigned int buttonNumber, unsigned int buttonMask, float x, float y, unsigned int modifiers, double referenceTime); UIEventResponse UIEditText_scrollWheel(UIEditText * self, float x, float y, int deltaX, int deltaY, unsigned int modifiers, bool isFinalTarget, double referenceTime); UIEventResponse UIEditText_keyDown(UIEditText * self, unsigned int charCode, unsigned int keyCode, unsigned int modifiers, bool isRepeat, bool isFinalTarget, double referenceTime); bool UIEditText_menuActionDown(UIEditText * self, unsigned int actionNumber, bool isRepeat, double referenceTime); bool UIEditText_setFocusedElement(UIEditText * self, compat_type(UIElement *) element, compat_type(UIElement *) fromElement, UINavigationDirection directionFromElement); bool UIEditText_acceptsFocus(UIEditText * self); void UIEditText_focusLost(UIEditText * self); Rect4f UIEditText_getBounds(UIEditText * self); bool UIEditText_ignoreClipForHitTest(UIEditText * self, UIHitTestType type); void UIEditText_draw(UIEditText * self, Vector2f offset, UIDrawingInterface * drawingInterface, VertexIO * vertexIO); bool UIEditText_needsRedraw(UIEditText * self); ShellCursorID UIEditText_getCursorAtPosition(UIEditText * self, float x, float y); bool UIEditText_shouldAutoconnect(UIEditText * self); String UIEditText_getText(UIEditText * self); void UIEditText_setText(UIEditText * self, String text); // Returns the selected substring, or an empty string if no text is selected. String UIEditText_getSelectedText(UIEditText * self); // Inserts text at the cursor position as though typed by the user, replacing the selection if any void UIEditText_inputText(UIEditText * self, String text); // Sets the text field's current contents as a restore point for UIEditText_revertText(). Automatically done on init and UIEditText_setText(). void UIEditText_commitText(UIEditText * self); // Copies the last committed string into the text field, overwriting any uncommitted changes void UIEditText_revertText(UIEditText * self); void UIEditText_selectAll(UIEditText * self); void UIEditText_getSelectionRange(UIEditText * self, size_t * outSelectionStartIndex, size_t * outSelectionEndIndex); bool UIEditText_canCopyToClipboard(UIEditText * self); bool UIEditText_copyToClipboard(UIEditText * self, bool cut); bool UIEditText_canPasteClipboardContents(UIEditText * self); bool UIEditText_pasteClipboardContents(UIEditText * self); void UIEditText_setBlacklist(UIEditText * self, String blacklistCharacters); void UIEditText_setWhitelist(UIEditText * self, String whitelistCharacters); void UIEditText_setAlignMode(UIEditText * self, TextAlignMode alignMode); void UIEditText_setWrapBehavior(UIEditText * self, WordWrapBehavior wrapBehavior); void UIEditText_scrollToIndex(UIEditText * self, size_t index); void UIEditText_scrollToRange(UIEditText * self, size_t index1, size_t index2); // Can be passed as create() or init()'s newlineActionCallback. Text is committed, field is unfocused, and textChangeCompletedCallback is called if text has changed. bool UIEditText_defaultNewlineActionCallback(UIEditText * editText, unsigned int modifiers, double referenceTime, void * context); // Can be passed as create() or init()'s textChangeCanceledCallback. Text is reverted and field is unfocused. void UIEditText_defaultCancelActionCallback(UIEditText * editText, double referenceTime, void * context); #ifdef __cplusplus } #endif #endif