Changeset View
Standalone View
source/gui/CInput.cpp
/* Copyright (C) 2017 Wildfire Games. | /* Copyright (C) 2018 Wildfire Games. | ||||
* This file is part of 0 A.D. | * This file is part of 0 A.D. | ||||
* | * | ||||
* 0 A.D. is free software: you can redistribute it and/or modify | * 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 | * it under the terms of the GNU General Public License as published by | ||||
* the Free Software Foundation, either version 2 of the License, or | * the Free Software Foundation, either version 2 of the License, or | ||||
* (at your option) any later version. | * (at your option) any later version. | ||||
* | * | ||||
* 0 A.D. is distributed in the hope that it will be useful, | * 0 A.D. is distributed in the hope that it will be useful, | ||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||||
* GNU General Public License for more details. | * GNU General Public License for more details. | ||||
* | * | ||||
* You should have received a copy of the GNU General Public License | * You should have received a copy of the GNU General Public License | ||||
* along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | * along with 0 A.D. If not, see <http://www.gnu.org/licenses/>. | ||||
*/ | */ | ||||
#include "precompiled.h" | #include "precompiled.h" | ||||
#include "CInput.h" | #include "CInput.h" | ||||
#include "CGUIScrollBarVertical.h" | #include "CGUIScrollBarVertical.h" | ||||
#include "GUI.h" | #include "GUI.h" | ||||
#include "GUIManager.h" | |||||
#include "graphics/FontMetrics.h" | #include "graphics/FontMetrics.h" | ||||
#include "graphics/ShaderManager.h" | #include "graphics/ShaderManager.h" | ||||
#include "graphics/TextRenderer.h" | #include "graphics/TextRenderer.h" | ||||
#include "lib/ogl.h" | #include "lib/ogl.h" | ||||
#include "lib/sysdep/clipboard.h" | #include "lib/sysdep/clipboard.h" | ||||
#include "lib/timer.h" | #include "lib/timer.h" | ||||
#include "lib/utf8.h" | #include "lib/utf8.h" | ||||
#include "ps/CLogger.h" | #include "ps/CLogger.h" | ||||
#include "ps/ConfigDB.h" | #include "ps/ConfigDB.h" | ||||
#include "ps/GameSetup/Config.h" | #include "ps/GameSetup/Config.h" | ||||
#include "ps/Globals.h" | #include "ps/Globals.h" | ||||
#include "ps/Hotkey.h" | #include "ps/Hotkey.h" | ||||
#include "renderer/Renderer.h" | #include "renderer/Renderer.h" | ||||
#include <sstream> | #include <sstream> | ||||
extern int g_yres; | extern int g_yres; | ||||
CInput::CInput() | CInput::CInput() | ||||
: m_iBufferPos(-1), m_iBufferPos_Tail(-1), m_SelectingText(false), m_HorizontalScroll(0.f), | : m_Focus(false), m_iBufferPos(-1), m_iBufferPos_Tail(-1), m_SelectingText(false), | ||||
vladislavbelov: It's the 112 characters long for no reason. | |||||
m_PrevTime(0.0), m_CursorVisState(true), m_CursorBlinkRate(0.5), m_ComposingText(false), | m_HorizontalScroll(0.f), m_PrevTime(0.0), m_CursorVisState(true), m_CursorBlinkRate(0.5), | ||||
m_iComposedLength(0), m_iComposedPos(0), m_iInsertPos(0), m_Readonly(false) | m_ComposingText(false), m_iComposedLength(0), m_iComposedPos(0), m_iInsertPos(0), m_Readonly(false) | ||||
{ | { | ||||
AddSetting(GUIST_int, "buffer_position"); | AddSetting(GUIST_int, "buffer_position"); | ||||
AddSetting(GUIST_float, "buffer_zone"); | AddSetting(GUIST_float, "buffer_zone"); | ||||
AddSetting(GUIST_CStrW, "caption"); | AddSetting(GUIST_CStrW, "caption"); | ||||
AddSetting(GUIST_int, "cell_id"); | AddSetting(GUIST_int, "cell_id"); | ||||
AddSetting(GUIST_CStrW, "font"); | AddSetting(GUIST_CStrW, "font"); | ||||
AddSetting(GUIST_CStrW, "mask_char"); | AddSetting(GUIST_CStrW, "mask_char"); | ||||
AddSetting(GUIST_bool, "mask"); | AddSetting(GUIST_bool, "mask"); | ||||
Show All 9 Lines | CInput::CInput() | ||||
AddSetting(GUIST_CStrW, "tooltip"); | AddSetting(GUIST_CStrW, "tooltip"); | ||||
AddSetting(GUIST_CStr, "tooltip_style"); | AddSetting(GUIST_CStr, "tooltip_style"); | ||||
CFG_GET_VAL("gui.cursorblinkrate", m_CursorBlinkRate); | CFG_GET_VAL("gui.cursorblinkrate", m_CursorBlinkRate); | ||||
CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(); | CGUIScrollBarVertical* bar = new CGUIScrollBarVertical(); | ||||
bar->SetRightAligned(true); | bar->SetRightAligned(true); | ||||
AddScrollBar(bar); | AddScrollBar(bar); | ||||
// Stop the text input on initializing the input field, so we can enable it again when the field is focussed. | |||||
SDL_StopTextInput(); | |||||
// When initializing an input field on a keypress while having another field focussed which stays focussed | |||||
// the old field is still focussed but recieves no text input. Fix this by activating the page again. | |||||
elexisUnsubmitted Not Done Inline Actions
Which could be fixed in the previously focused object, when it loses the focus? Shouldn't this just be if m_Focused then SDL_StartTextInput? Does calling the stop then the start function differ from noop? elexis: > the old field is still focussed
Which could be fixed in the previously focused object, when… | |||||
g_GUI->ActivateTopPage(); | |||||
elexisUnsubmitted Not Done Inline ActionsThis reference to the top-page sounds investigateable. It may not always the topmost page that that creates the CInput object. Would a reference to the GUI page that owns this object be more precise / universal / reliable? elexis: This reference to the top-page sounds investigateable.
It may not always the topmost page that… | |||||
bbAuthorUnsubmitted Done Inline Actionscertainly investigation It doen't matter that the topmost page has the CInput object or not, but I would expect any other page than the top page would not recieve textInputs, even if it is the only page with a textinput. What we want to achieve with this call is that whatever happens, the the SDL_TEXTINPTUT thingy is set correctly for the topmost page, so every time a gui page switches we need to check it (whether it is pushing, switching or popping a page, doesn't matter). So I guess these two calls could get a better location. bb: certainly investigation
It doen't matter that the topmost page has the CInput object or not… | |||||
elexisUnsubmitted Not Done Inline Actions
If the topmost page differs from the the page that owns this object, then the call to the topmost page would be unrelated to this GUI object instance, no? If m_pGUI is not used here, there should be a very good reason for a GUIObject of page X to do something for GUI page Y. elexis: > It doen't matter that the topmost page has the CInput object or not
If the topmost page… | |||||
} | } | ||||
CInput::~CInput() | CInput::~CInput() | ||||
{ | { | ||||
} | } | ||||
void CInput::ActivatePage() | |||||
{ | |||||
if (m_Focus) | |||||
SDL_StartTextInput(); | |||||
} | |||||
void CInput::UpdateBufferPositionSetting() | void CInput::UpdateBufferPositionSetting() | ||||
{ | { | ||||
int* bufferPos = (int*)m_Settings["buffer_position"].m_pSetting; | int* bufferPos = (int*)m_Settings["buffer_position"].m_pSetting; | ||||
*bufferPos = m_iBufferPos; | *bufferPos = m_iBufferPos; | ||||
} | } | ||||
void CInput::ClearComposedText() | void CInput::ClearComposedText() | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 993 Lines • ▼ Show 20 Lines | case GUIM_LOAD: | ||||
UpdateText(); | UpdateText(); | ||||
UpdateAutoScroll(); | UpdateAutoScroll(); | ||||
GUI<bool>::GetSetting(this, "readonly", m_Readonly); | GUI<bool>::GetSetting(this, "readonly", m_Readonly); | ||||
break; | break; | ||||
} | } | ||||
case GUIM_GOT_FOCUS: | case GUIM_GOT_FOCUS: | ||||
{ | { | ||||
m_Focus = true; | |||||
elexisUnsubmitted Not Done Inline ActionsPerhaps we don't need the "activate" function at all, but just call SDL_StartTextInput(); here (perhaps only if the GUI page is the topmost one too)? elexis: Perhaps we don't need the "activate" function at all, but just call `SDL_StartTextInput();`… | |||||
bbAuthorUnsubmitted Done Inline Actionswell no, that call already is there 12 lines below... bb: well no, that call already is there 12 lines below... | |||||
elexisUnsubmitted Not Done Inline ActionsThen one could consider whether sending the GUIM_GOT_FOCUS message upon pagestack changes would be more versatile or shorter. (I'm uninformed) elexis: Then one could consider whether sending the `GUIM_GOT_FOCUS` message upon pagestack changes… | |||||
bbAuthorUnsubmitted Done Inline Actions^ bb: ^ | |||||
m_iBufferPos = 0; | m_iBufferPos = 0; | ||||
m_PrevTime = 0.0; | m_PrevTime = 0.0; | ||||
m_CursorVisState = false; | m_CursorVisState = false; | ||||
// Tell the IME where to draw the candidate list | // Tell the IME where to draw the candidate list | ||||
SDL_Rect rect; | SDL_Rect rect; | ||||
rect.h = m_CachedActualSize.GetSize().cy; | rect.h = m_CachedActualSize.GetSize().cy; | ||||
rect.w = m_CachedActualSize.GetSize().cx; | rect.w = m_CachedActualSize.GetSize().cx; | ||||
Show All 14 Lines | if (m_ComposingText) | ||||
evt.ev.edit.start = 0; | evt.ev.edit.start = 0; | ||||
evt.ev.edit.text[0] = 0; | evt.ev.edit.text[0] = 0; | ||||
ManuallyHandleEvent(&evt); | ManuallyHandleEvent(&evt); | ||||
} | } | ||||
SDL_StopTextInput(); | SDL_StopTextInput(); | ||||
m_iBufferPos = -1; | m_iBufferPos = -1; | ||||
m_iBufferPos_Tail = -1; | m_iBufferPos_Tail = -1; | ||||
m_Focus = false; | |||||
break; | break; | ||||
} | } | ||||
default: | default: | ||||
{ | { | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
UpdateBufferPositionSetting(); | UpdateBufferPositionSetting(); | ||||
▲ Show 20 Lines • Show All 1,005 Lines • ▼ Show 20 Lines | if (m_HorizontalScroll != 0.f && | ||||
x_total - m_HorizontalScroll + buffer_zone*2.f < m_CachedActualSize.GetWidth()) | x_total - m_HorizontalScroll + buffer_zone*2.f < m_CachedActualSize.GetWidth()) | ||||
m_HorizontalScroll = x_total - m_CachedActualSize.GetWidth() + buffer_zone*2.f; | m_HorizontalScroll = x_total - m_CachedActualSize.GetWidth() + buffer_zone*2.f; | ||||
// Now this is the fail-safe, if x_total isn't even the length of the control, | // Now this is the fail-safe, if x_total isn't even the length of the control, | ||||
// remove all scrolling | // remove all scrolling | ||||
if (x_total + buffer_zone*2.f < m_CachedActualSize.GetWidth()) | if (x_total + buffer_zone*2.f < m_CachedActualSize.GetWidth()) | ||||
m_HorizontalScroll = 0.f; | m_HorizontalScroll = 0.f; | ||||
} | } | ||||
} | } | ||||
Not Done Inline ActionsI think, it may lead to weird behaviour with GUI (not sure that it exists in the public, but it's real in mods), when a player entering a chat text and at the same time some text field is closing. I.e. a temporal message box with the CInput. Did you test it? vladislavbelov: I think, it may lead to weird behaviour with GUI (not sure that it exists in the public, but… | |||||
Not Done Inline ActionsIsnt this only called when the GUI page is irrecoverably closed and deleted in c++? So the only way this to be wrong is having a text field focused in page 1, then opening page 2 that has a text field, closing page 2, then the textfield in page 1 might still be focused without the SDL_StartTextInput thign being called? elexis: Isnt this only called when the GUI page is irrecoverably closed and deleted in c++?
So the… | |||||
Not Done Inline ActionsWell probably even easier: have two pages open simultaneously, focus a textfield on one, close the other (without dropping focus) That is a very hypothetical case however, since closing a page without dropping focus would be meh. But for the sake of completeness we could add a check for being focussed on this inputfield (we would still bug then if both fields have a inputfield which both are focussed, but considering that a bug already) bb: Well probably even easier: have two pages open simultaneously, focus a textfield on one, close… | |||||
Not Done Inline ActionsThere is not really a situation where two GUI pages are open and processed simultaneously. elexis: There is not really a situation where two GUI pages are open and processed simultaneously.
You… |
It's the 112 characters long for no reason.