/* Copyright (C) 2022 Wildfire Games. * This file is part of 0 A.D. * * 0 A.D. is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 2 of the License, or * (at your option) any later version. * * 0 A.D. is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with 0 A.D. If not, see . */ #ifndef INCLUDED_CINPUT #define INCLUDED_CINPUT #include "gui/CGUISprite.h" #include "gui/ObjectBases/IGUIObject.h" #include "gui/ObjectBases/IGUIScrollBarOwner.h" #include "gui/SettingTypes/CGUIString.h" #include "lib/external_libraries/libsdl.h" #include #include /** * Text field where you can input and edit the text. * * It doesn't use IGUITextOwner, because we don't need * any other features than word-wrapping, and we need to be * able to rapidly change the string. */ class CInput : public IGUIObject, public IGUIScrollBarOwner { GUI_OBJECT(CInput) protected: // forwards struct SRow; public: CInput(CGUI& pGUI); virtual ~CInput(); /** * @see IGUIObject#ResetStates() */ virtual void ResetStates(); // Check where the mouse is hovering, and get the appropriate text position. // return is the text-position index. int GetMouseHoveringTextPosition() const; // Same as above, but only on one row in X, and a given value, not the mouse's. // wanted is filled with x if the row didn't extend as far as the mouse pos. int GetXTextPosition(const std::list::const_iterator& c, const float& x, float& wanted) const; protected: void SetupGeneratedPlaceholderText(); /** * @see IGUIObject#HandleMessage() */ virtual void HandleMessage(SGUIMessage& Message); /** * Handle events manually to catch keyboard inputting. */ virtual InReaction ManuallyHandleKeys(const SDL_Event_* ev); /** * Handle events manually to catch keys which change the text. */ virtual void ManuallyMutableHandleKeyDownEvent(const SDL_Keycode keyCode); /** * Handle events manually to catch keys which don't change the text. */ virtual void ManuallyImmutableHandleKeyDownEvent(const SDL_Keycode keyCode); /** * Handle hotkey events (called by ManuallyHandleKeys) */ virtual InReaction ManuallyHandleHotkeyEvent(const SDL_Event_* ev); /** * @see IGUIObject#UpdateCachedSize() */ virtual void UpdateCachedSize(); /** * Draws the Text */ virtual void Draw(CCanvas2D& canvas); void DrawContent(CCanvas2D& canvas); /** * Calculate m_CharacterPosition * the main task for this function is to perfom word-wrapping * You input from which character it has been changed, because * if we add a character to the very last end, we don't want * process everything all over again! Also notice you can * specify a 'to' also, it will only be used though if a '\n' * appears, because then the word-wrapping won't change after * that. */ void UpdateText(int from = 0, int to_before = -1, int to_after = -1); /** * Draws the text generated for placeholder. * * @param canvas Canvas to draw on. * @param clipping Clipping rectangle, don't even add a parameter * to get no clipping. */ virtual void DrawPlaceholderText(CCanvas2D& canvas, const CRect& clipping = CRect()); /** * Delete the current selection. Also places the pointer at the * crack between the two segments kept. */ void DeleteCurSelection(); /** * Is text selected? It can be denote two ways, m_iBufferPos_Tail * being -1 or the same as m_iBufferPos. This makes for clearer * code. */ bool SelectingText() const; /// Get area of where text can be drawn. float GetTextAreaWidth(); /// Called every time the auto-scrolling should be checked. void UpdateAutoScroll(); /// Clear composed IME input when supported (SDL2 only). void ClearComposedText(); /// Updates the buffer (cursor) position exposed to JS. void UpdateBufferPositionSetting(); protected: /// Cursor position int m_iBufferPos; /// Cursor position we started to select from. (-1 if not selecting) /// (NB: Can be larger than m_iBufferPos if selecting from back to front.) int m_iBufferPos_Tail; /// If we're composing text with an IME bool m_ComposingText; /// The length and position of the current IME composition int m_iComposedLength, m_iComposedPos; /// The position to insert committed text int m_iInsertPos; // the outer vector is lines, and the inner is X positions // in a row. So that we can determine where characters are // placed. It's important because we need to know where the // pointer should be placed when the input control is pressed. struct SRow { // Where the Row starts int m_ListStart; // List of X values for each character. std::vector m_ListOfX; }; /** * List of rows to ease changing its size, so iterators stay valid. * For one-liners only one row is used. */ std::list m_CharacterPositions; // *** Things for a multi-lined input control *** // /** * When you change row with up/down, and the row you jump to does * not have anything at that X position, then it will keep the * m_WantedX position in mind when switching to the next row. * It will keep on being used until it reach a row which meets the * requirements. * 0.0f means not in use. */ float m_WantedX; /** * If we are in the process of selecting a larger selection of text * using the mouse click (hold) and drag, this is true. */ bool m_SelectingText; /** * Whether the cached text is currently valid (if not then SetupText will be called by Draw) */ bool m_GeneratedPlaceholderTextValid; CGUIText m_GeneratedPlaceholderText; // *** Things for one-line input control *** // float m_HorizontalScroll; /// Used to store the previous time for flashing the cursor. double m_PrevTime; /// Cursor blink rate in seconds, if greater than 0.0. double m_CursorBlinkRate; /// If the cursor should be drawn or not. bool m_CursorVisState; static const CStr EventNameTextEdit; static const CStr EventNamePress; static const CStr EventNameTab; CGUISimpleSetting m_BufferPosition; CGUISimpleSetting m_BufferZone; CGUISimpleSetting m_Caption; CGUISimpleSetting m_PlaceholderText; CGUISimpleSetting m_Font; CGUISimpleSetting m_MaskChar; CGUISimpleSetting m_Mask; CGUISimpleSetting m_MaxLength; CGUISimpleSetting m_MultiLine; CGUISimpleSetting m_Readonly; CGUISimpleSetting m_ScrollBar; CGUISimpleSetting m_ScrollBarStyle; CGUISimpleSetting m_Sprite; CGUISimpleSetting m_SpriteOverlay; CGUISimpleSetting m_SpriteSelectArea; CGUISimpleSetting m_TextColor; CGUISimpleSetting m_TextColorSelected; CGUISimpleSetting m_PlaceholderColor; }; #endif // INCLUDED_CINPUT