ddnet/src/game/editor/editor.cpp

7004 lines
207 KiB
C++
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <algorithm>
#include <base/color.h>
#include <base/system.h>
2007-05-22 15:03:32 +00:00
2014-01-19 03:02:01 +00:00
#if defined(CONF_FAMILY_UNIX)
#include <pthread.h>
#endif
2010-05-29 07:25:38 +00:00
#include <engine/client.h>
#include <engine/console.h>
#include <engine/gfx/image_manipulation.h>
2010-05-29 07:25:38 +00:00
#include <engine/graphics.h>
#include <engine/input.h>
#include <engine/keys.h>
#include <engine/shared/config.h>
2010-05-29 07:25:38 +00:00
#include <engine/storage.h>
#include <engine/textrender.h>
2007-05-22 15:03:32 +00:00
2020-05-15 14:29:09 +00:00
#include <game/client/components/camera.h>
#include <game/client/components/menu_background.h>
#include <game/client/gameclient.h>
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
#include <game/client/lineinput.h>
2010-05-29 07:25:38 +00:00
#include <game/client/render.h>
#include <game/client/ui.h>
#include <game/client/ui_listbox.h>
#include <game/client/ui_scrollregion.h>
#include <game/generated/client_data.h>
#include <game/localization.h>
2007-05-22 15:03:32 +00:00
#include "auto_map.h"
2011-04-19 08:34:51 +00:00
#include "editor.h"
#include <limits>
using namespace FontIcons;
static const char *VANILLA_IMAGES[] = {
"bg_cloud1",
"bg_cloud2",
"bg_cloud3",
"desert_doodads",
"desert_main",
"desert_mountains",
"desert_mountains2",
"desert_sun",
"generic_deathtiles",
"generic_unhookable",
"grass_doodads",
"grass_main",
"jungle_background",
"jungle_deathtiles",
"jungle_doodads",
"jungle_main",
"jungle_midground",
"jungle_unhookables",
"moon",
"mountains",
"snow",
"stars",
"sun",
"winter_doodads",
"winter_main",
"winter_mountains",
"winter_mountains2",
"winter_mountains3"};
bool CEditor::IsVanillaImage(const char *pImage)
{
2022-01-23 17:56:37 +00:00
return std::any_of(std::begin(VANILLA_IMAGES), std::end(VANILLA_IMAGES), [pImage](const char *pVanillaImage) { return str_comp(pImage, pVanillaImage) == 0; });
}
const void *CEditor::ms_pUiGotContext;
2007-05-22 15:03:32 +00:00
2019-04-26 12:06:32 +00:00
ColorHSVA CEditor::ms_PickerColor;
int CEditor::ms_SVPicker;
int CEditor::ms_HuePicker;
2009-10-27 14:38:53 +00:00
enum
{
BUTTON_CONTEXT = 1,
2009-10-27 14:38:53 +00:00
};
2008-01-13 11:43:43 +00:00
2010-05-29 07:25:38 +00:00
CEditorImage::~CEditorImage()
2009-10-27 14:38:53 +00:00
{
m_pEditor->Graphics()->UnloadTexture(&m_Texture);
free(m_pData);
m_pData = nullptr;
2009-10-27 14:38:53 +00:00
}
2014-10-11 11:38:45 +00:00
CEditorSound::~CEditorSound()
{
m_pEditor->Sound()->UnloadSample(m_SoundID);
free(m_pData);
m_pData = nullptr;
2014-10-11 11:38:45 +00:00
}
2010-05-29 07:25:38 +00:00
CLayerGroup::CLayerGroup()
2007-05-22 15:03:32 +00:00
{
m_vpLayers.clear();
2011-07-12 01:14:46 +00:00
m_aName[0] = 0;
2010-05-29 07:25:38 +00:00
m_Visible = true;
m_Collapse = false;
2010-05-29 07:25:38 +00:00
m_GameGroup = false;
m_OffsetX = 0;
m_OffsetY = 0;
m_ParallaxX = 100;
m_ParallaxY = 100;
m_CustomParallaxZoom = 0;
m_ParallaxZoom = 100;
2010-05-29 07:25:38 +00:00
m_UseClipping = 0;
m_ClipX = 0;
m_ClipY = 0;
m_ClipW = 0;
m_ClipH = 0;
2008-01-12 12:27:55 +00:00
}
2007-05-22 15:03:32 +00:00
template<typename T>
2022-06-15 17:34:41 +00:00
static void DeleteAll(std::vector<T> &vList)
{
Declare variables as `const` when possible According to cppcheck's `constVariable` error: ``` src\engine\client\backend\opengl\opengl_sl.cpp:74:43: style: Variable 'Define' can be declared as reference to const [constVariable] for(CGLSLCompiler::SGLSLCompilerDefine &Define : pCompiler->m_vDefines) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:2149:12: style: Variable 'GraphicThreadCommandBuffer' can be declared as reference to const [constVariable] auto &GraphicThreadCommandBuffer = m_vvThreadDrawCommandBuffers[i + 1][m_CurImageIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3192:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3200:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[State.m_Texture].m_VKStandard3DTexturedDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3810:13: style: Variable 'Mode' can be declared as reference to const [constVariable] for(auto &Mode : vPresentModeList) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3818:13: style: Variable 'Mode' can be declared as reference to const [constVariable] for(auto &Mode : vPresentModeList) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6511:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6555:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_VKStandard3DTexturedDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6660:9: style: Variable 'MemBlock' can be declared as reference to const [constVariable] auto &MemBlock = m_vBufferObjects[BufferIndex].m_BufferObject.m_Mem; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6799:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6808:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6902:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6907:9: style: Variable 'TextTextureDescr' can be declared as reference to const [constVariable] auto &TextTextureDescr = m_vTextures[pCommand->m_TextTextureIndex].m_VKTextDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6961:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6970:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\game\client\components\hud.cpp:178:8: style: Variable 'aFlagCarrier' can be declared as const array [constVariable] int aFlagCarrier[2] = { ^ src\game\client\components\hud.cpp:519:16: style: Variable 's_aTextWidth' can be declared as const array [constVariable] static float s_aTextWidth[5] = {s_TextWidth0, s_TextWidth00, s_TextWidth000, s_TextWidth0000, s_TextWidth00000}; ^ src\game\client\components\killmessages.cpp:305:30: style: Variable 'Client' can be declared as reference to const [constVariable] CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_KillerID]; ^ src\game\client\components\killmessages.cpp:314:30: style: Variable 'Client' can be declared as reference to const [constVariable] CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_VictimID]; ^ src\game\client\components\menus_ingame.cpp:243:12: style: Variable 'pInfoByName' can be declared as reference to const [constVariable] for(auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName) ^ src\game\client\components\menus_ingame.cpp:530:12: style: Variable 'pInfoByName' can be declared as reference to const [constVariable] for(auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName) ^ src\game\client\components\players.cpp:767:44: style: Variable 'CharacterInfo' can be declared as reference to const [constVariable] CGameClient::CSnapState::CCharacterInfo &CharacterInfo = m_pClient->m_Snap.m_aCharacters[i]; ^ src\game\client\components\spectator.cpp:122:27: style: Variable 'Snap' can be declared as reference to const [constVariable] CGameClient::CSnapState &Snap = pSelf->m_pClient->m_Snap; ^ src\game\client\components\spectator.cpp:221:12: style: Variable 'pInfo' can be declared as reference to const [constVariable] for(auto &pInfo : m_pClient->m_Snap.m_apInfoByDDTeamName) ^ src\game\client\gameclient.cpp:2220:15: style: Variable 'OwnClientData' can be declared as reference to const [constVariable] CClientData &OwnClientData = m_aClients[ownID]; ^ src\game\client\gameclient.cpp:2227:16: style: Variable 'cData' can be declared as reference to const [constVariable] CClientData &cData = m_aClients[i]; ^ src\game\client\prediction\entities\character.cpp:397:11: style: Variable 'aSpreading' can be declared as const array [constVariable] float aSpreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; ^ src\game\client\prediction\entities\laser.cpp:53:9: style: Variable 'HitPos' can be declared as reference to const [constVariable] vec2 &HitPos = pHit->Core()->m_Pos; ^ src\game\editor\auto_map.cpp:507:18: style: Variable 'Index' can be declared as reference to const [constVariable] for(auto &Index : pRule->m_vIndexList) ^ src\game\editor\auto_map.cpp:518:18: style: Variable 'Index' can be declared as reference to const [constVariable] for(auto &Index : pRule->m_vIndexList) ^ src\game\editor\editor.cpp:118:12: style: Variable 'Item' can be declared as reference to const [constVariable] for(auto &Item : vList) ^ src\game\editor\editor.cpp:2983:11: style: Variable 'aAspects' can be declared as const array [constVariable] float aAspects[] = {4.0f / 3.0f, 16.0f / 10.0f, 5.0f / 4.0f, 16.0f / 9.0f}; ^ src\game\editor\editor.cpp:3141:15: style: Variable 's_aShift' can be declared as const array [constVariable] static int s_aShift[] = {24, 16, 8, 0}; ^ src\engine\server\server.cpp:2807:14: style: Variable 'Client' can be declared as reference to const [constVariable] for(auto &Client : m_aClients) ^ src\engine\server\sql_string_helpers.cpp:51:6: style: Variable 'aTimes' can be declared as const array [constVariable] int aTimes[7] = ^ src\test\secure_random.cpp:24:6: style: Variable 'BOUNDS' can be declared as const array [constVariable] int BOUNDS[] = {2, 3, 4, 5, 10, 100, 127, 128, 129}; ^ ```
2022-11-13 15:29:13 +00:00
for(const auto &pItem : vList)
delete pItem;
2022-06-15 17:34:41 +00:00
vList.clear();
}
2010-05-29 07:25:38 +00:00
CLayerGroup::~CLayerGroup()
2007-05-22 15:03:32 +00:00
{
DeleteAll(m_vpLayers);
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
void CLayerGroup::Convert(CUIRect *pRect)
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
pRect->x += m_OffsetX;
pRect->y += m_OffsetY;
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
void CLayerGroup::Mapping(float *pPoints)
2007-05-22 15:03:32 +00:00
{
float ParallaxZoom = m_pMap->m_pEditor->m_PreviewZoom ? m_ParallaxZoom : 100.0f;
m_pMap->m_pEditor->RenderTools()->MapScreenToWorld(
2010-05-29 07:25:38 +00:00
m_pMap->m_pEditor->m_WorldOffsetX, m_pMap->m_pEditor->m_WorldOffsetY,
m_ParallaxX, m_ParallaxY, ParallaxZoom, m_OffsetX, m_OffsetY,
2010-05-29 07:25:38 +00:00
m_pMap->m_pEditor->Graphics()->ScreenAspect(), m_pMap->m_pEditor->m_WorldZoom, pPoints);
pPoints[0] += m_pMap->m_pEditor->m_EditorOffsetX;
pPoints[1] += m_pMap->m_pEditor->m_EditorOffsetY;
pPoints[2] += m_pMap->m_pEditor->m_EditorOffsetX;
pPoints[3] += m_pMap->m_pEditor->m_EditorOffsetY;
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
void CLayerGroup::MapScreen()
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
float aPoints[4];
Mapping(aPoints);
m_pMap->m_pEditor->Graphics()->MapScreen(aPoints[0], aPoints[1], aPoints[2], aPoints[3]);
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
void CLayerGroup::Render()
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
MapScreen();
IGraphics *pGraphics = m_pMap->m_pEditor->Graphics();
if(m_UseClipping)
{
float aPoints[4];
m_pMap->m_pGameGroup->Mapping(aPoints);
float x0 = (m_ClipX - aPoints[0]) / (aPoints[2] - aPoints[0]);
float y0 = (m_ClipY - aPoints[1]) / (aPoints[3] - aPoints[1]);
float x1 = ((m_ClipX + m_ClipW) - aPoints[0]) / (aPoints[2] - aPoints[0]);
float y1 = ((m_ClipY + m_ClipH) - aPoints[1]) / (aPoints[3] - aPoints[1]);
2010-05-29 07:25:38 +00:00
pGraphics->ClipEnable((int)(x0 * pGraphics->ScreenWidth()), (int)(y0 * pGraphics->ScreenHeight()),
(int)((x1 - x0) * pGraphics->ScreenWidth()), (int)((y1 - y0) * pGraphics->ScreenHeight()));
2008-03-29 11:44:03 +00:00
}
2010-05-29 07:25:38 +00:00
for(auto &pLayer : m_vpLayers)
2008-01-12 12:27:55 +00:00
{
if(pLayer->m_Visible)
{
if(pLayer->m_Type == LAYERTYPE_TILES)
{
CLayerTiles *pTiles = static_cast<CLayerTiles *>(pLayer);
if(pTiles->m_Game || pTiles->m_Front || pTiles->m_Tele || pTiles->m_Speedup || pTiles->m_Tune || pTiles->m_Switch)
continue;
}
if(m_pMap->m_pEditor->m_ShowDetail || !(pLayer->m_Flags & LAYERFLAG_DETAIL))
pLayer->Render();
}
}
2018-10-02 01:52:01 +00:00
for(auto &pLayer : m_vpLayers)
{
if(pLayer->m_Visible && pLayer->m_Type == LAYERTYPE_TILES && pLayer != m_pMap->m_pGameLayer && pLayer != m_pMap->m_pFrontLayer && pLayer != m_pMap->m_pTeleLayer && pLayer != m_pMap->m_pSpeedupLayer && pLayer != m_pMap->m_pSwitchLayer && pLayer != m_pMap->m_pTuneLayer)
{
CLayerTiles *pTiles = static_cast<CLayerTiles *>(pLayer);
if(pTiles->m_Game || pTiles->m_Front || pTiles->m_Tele || pTiles->m_Speedup || pTiles->m_Tune || pTiles->m_Switch)
{
pLayer->Render();
}
}
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
if(m_UseClipping)
pGraphics->ClipDisable();
2008-01-12 12:27:55 +00:00
}
void CLayerGroup::AddLayer(CLayer *pLayer)
{
2020-05-17 14:11:39 +00:00
m_pMap->m_Modified = true;
m_vpLayers.push_back(pLayer);
}
2010-05-29 07:25:38 +00:00
void CLayerGroup::DeleteLayer(int Index)
2007-05-22 15:03:32 +00:00
{
if(Index < 0 || Index >= (int)m_vpLayers.size())
return;
delete m_vpLayers[Index];
m_vpLayers.erase(m_vpLayers.begin() + Index);
m_pMap->m_Modified = true;
2010-05-29 07:25:38 +00:00
}
2007-05-22 15:03:32 +00:00
void CLayerGroup::DuplicateLayer(int Index)
{
if(Index < 0 || Index >= (int)m_vpLayers.size())
return;
auto *pDup = m_vpLayers[Index]->Duplicate();
m_vpLayers.insert(m_vpLayers.begin() + Index + 1, pDup);
m_pMap->m_Modified = true;
}
void CLayerGroup::GetSize(float *pWidth, float *pHeight) const
2007-05-22 15:03:32 +00:00
{
*pWidth = 0;
*pHeight = 0;
for(const auto &pLayer : m_vpLayers)
2008-01-12 12:27:55 +00:00
{
float lw, lh;
pLayer->GetSize(&lw, &lh);
*pWidth = maximum(*pWidth, lw);
*pHeight = maximum(*pHeight, lh);
2008-01-12 12:27:55 +00:00
}
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
int CLayerGroup::SwapLayers(int Index0, int Index1)
2007-05-22 15:03:32 +00:00
{
if(Index0 < 0 || Index0 >= (int)m_vpLayers.size())
return Index0;
if(Index1 < 0 || Index1 >= (int)m_vpLayers.size())
return Index0;
if(Index0 == Index1)
return Index0;
m_pMap->m_Modified = true;
std::swap(m_vpLayers[Index0], m_vpLayers[Index1]);
2010-05-29 07:25:38 +00:00
return Index1;
2008-03-29 11:44:03 +00:00
}
2010-05-29 07:25:38 +00:00
void CEditorImage::AnalyseTileFlags()
2008-03-29 11:44:03 +00:00
{
2010-05-29 07:25:38 +00:00
mem_zero(m_aTileFlags, sizeof(m_aTileFlags));
int tw = m_Width / 16; // tilesizes
int th = m_Height / 16;
if(tw == th && m_Format == CImageInfo::FORMAT_RGBA)
2011-08-11 08:59:14 +00:00
{
2010-05-29 07:25:38 +00:00
unsigned char *pPixelData = (unsigned char *)m_pData;
int TileID = 0;
2008-09-07 08:30:49 +00:00
for(int ty = 0; ty < 16; ty++)
for(int tx = 0; tx < 16; tx++, TileID++)
2008-09-07 08:30:49 +00:00
{
2010-05-29 07:25:38 +00:00
bool Opaque = true;
2008-09-07 08:30:49 +00:00
for(int x = 0; x < tw; x++)
for(int y = 0; y < th; y++)
2008-03-29 11:44:03 +00:00
{
int p = (ty * tw + y) * m_Width + tx * tw + x;
if(pPixelData[p * 4 + 3] < 250)
2008-09-07 08:30:49 +00:00
{
2010-05-29 07:25:38 +00:00
Opaque = false;
2008-09-07 08:30:49 +00:00
break;
}
2008-03-29 11:44:03 +00:00
}
2010-05-29 07:25:38 +00:00
if(Opaque)
m_aTileFlags[TileID] |= TILEFLAG_OPAQUE;
2008-09-07 08:30:49 +00:00
}
}
2008-03-29 11:44:03 +00:00
}
2008-01-12 12:27:55 +00:00
void CEditor::EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels, void *pUser)
{
CEditor *pThis = (CEditor *)pUser;
if(Env < 0 || Env >= (int)pThis->m_Map.m_vpEnvelopes.size())
{
Channels = ColorRGBA();
return;
}
CEnvelope *pEnv = pThis->m_Map.m_vpEnvelopes[Env];
float t = pThis->m_AnimateTime;
t *= pThis->m_AnimateSpeed;
t += (TimeOffsetMillis / 1000.0f);
pEnv->Eval(t, Channels);
}
2008-01-12 12:27:55 +00:00
/********************************************************
OTHER
*********************************************************/
2008-01-13 22:03:32 +00:00
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
bool CEditor::DoEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners, const char *pToolTip)
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(UI()->LastActiveItem() == pLineInput)
2021-12-03 18:46:31 +00:00
m_EditBoxActive = 2;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UpdateTooltip(pLineInput, pRect, pToolTip);
return UI()->DoEditBox(pLineInput, pRect, FontSize, Corners);
}
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
bool CEditor::DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners, const char *pToolTip)
2008-09-23 13:28:57 +00:00
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(UI()->LastActiveItem() == pLineInput)
m_EditBoxActive = 2;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UpdateTooltip(pLineInput, pRect, pToolTip);
return UI()->DoClearableEditBox(pLineInput, pRect, FontSize, Corners);
2008-09-23 13:28:57 +00:00
}
2008-01-12 12:27:55 +00:00
ColorRGBA CEditor::GetButtonColor(const void *pID, int Checked)
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
if(Checked < 0)
return ColorRGBA(0, 0, 0, 0.5f);
2010-05-29 07:25:38 +00:00
switch(Checked)
{
case 8: // invisible
return ColorRGBA(0, 0, 0, 0);
2015-06-28 13:02:48 +00:00
case 7: // selected + game layers
if(UI()->HotItem() == pID)
return ColorRGBA(1, 0, 0, 0.4f);
return ColorRGBA(1, 0, 0, 0.2f);
2015-06-28 13:02:48 +00:00
case 6: // game layers
if(UI()->HotItem() == pID)
return ColorRGBA(1, 1, 1, 0.4f);
return ColorRGBA(1, 1, 1, 0.2f);
2015-06-28 13:02:48 +00:00
case 5: // selected + image/sound should be embedded
if(UI()->HotItem() == pID)
return ColorRGBA(1, 0, 0, 0.75f);
return ColorRGBA(1, 0, 0, 0.5f);
case 4: // image/sound should be embedded
if(UI()->HotItem() == pID)
return ColorRGBA(1, 0, 0, 1.0f);
return ColorRGBA(1, 0, 0, 0.875f);
case 3: // selected + unused image/sound
if(UI()->HotItem() == pID)
return ColorRGBA(1, 0, 1, 0.75f);
return ColorRGBA(1, 0, 1, 0.5f);
case 2: // unused image/sound
if(UI()->HotItem() == pID)
return ColorRGBA(0, 0, 1, 0.75f);
return ColorRGBA(0, 0, 1, 0.5f);
case 1: // selected
if(UI()->HotItem() == pID)
return ColorRGBA(1, 0, 0, 0.75f);
return ColorRGBA(1, 0, 0, 0.5f);
2010-05-29 07:25:38 +00:00
default: // regular
if(UI()->HotItem() == pID)
return ColorRGBA(1, 1, 1, 0.75f);
return ColorRGBA(1, 1, 1, 0.5f);
}
2007-05-22 15:03:32 +00:00
}
void CEditor::UpdateTooltip(const void *pID, const CUIRect *pRect, const char *pToolTip)
{
if((UI()->MouseInside(pRect) && m_pTooltip) || (UI()->HotItem() == pID && pToolTip))
m_pTooltip = pToolTip;
}
2010-05-29 07:25:38 +00:00
int CEditor::DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
2007-05-22 15:03:32 +00:00
{
2009-10-27 14:38:53 +00:00
if(UI()->MouseInside(pRect))
{
if(Flags & BUTTON_CONTEXT)
2010-05-29 07:25:38 +00:00
ms_pUiGotContext = pID;
2009-10-27 14:38:53 +00:00
}
2010-05-29 07:25:38 +00:00
UpdateTooltip(pID, pRect, pToolTip);
return UI()->DoButtonLogic(pID, Checked, pRect);
2009-10-27 14:38:53 +00:00
}
int CEditor::DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
2009-10-27 14:38:53 +00:00
{
pRect->Draw(GetButtonColor(pID, Checked), IGraphics::CORNER_ALL, 3.0f);
CUIRect NewRect = *pRect;
UI()->DoLabel(&NewRect, pText, 10.0f, TEXTALIGN_MC);
Checked %= 2;
2009-10-27 14:38:53 +00:00
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
2007-05-22 15:03:32 +00:00
}
2023-04-29 00:23:06 +00:00
int CEditor::DoButton_Env(const void *pID, const char *pText, int Checked, const CUIRect *pRect, const char *pToolTip, ColorRGBA BaseColor, int Corners)
2015-07-24 22:04:12 +00:00
{
2017-03-21 10:24:44 +00:00
float Bright = Checked ? 1.0f : 0.5f;
float Alpha = UI()->HotItem() == pID ? 1.0f : 0.75f;
ColorRGBA Color = ColorRGBA(BaseColor.r * Bright, BaseColor.g * Bright, BaseColor.b * Bright, Alpha);
2015-07-24 22:04:12 +00:00
2023-04-29 00:23:06 +00:00
pRect->Draw(Color, Corners, 3.0f);
UI()->DoLabel(pRect, pText, 10.0f, TEXTALIGN_MC);
2015-07-24 22:04:12 +00:00
Checked %= 2;
return DoButton_Editor_Common(pID, pText, Checked, pRect, 0, pToolTip);
}
2010-05-29 07:25:38 +00:00
int CEditor::DoButton_File(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
2008-01-13 16:30:30 +00:00
{
if(Checked)
pRect->Draw(GetButtonColor(pID, Checked), IGraphics::CORNER_ALL, 3.0f);
2010-05-29 07:25:38 +00:00
CUIRect Rect;
pRect->VMargin(5.0f, &Rect);
UI()->DoLabel(&Rect, pText, 10.0f, TEXTALIGN_ML);
2009-10-27 14:38:53 +00:00
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
2008-01-13 16:30:30 +00:00
}
2010-05-29 07:25:38 +00:00
int CEditor::DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
2008-01-13 22:03:32 +00:00
{
pRect->Draw(ColorRGBA(0.5f, 0.5f, 0.5f, 1.0f), IGraphics::CORNER_T, 3.0f);
2008-01-13 22:03:32 +00:00
CUIRect Rect;
pRect->VMargin(5.0f, &Rect);
UI()->DoLabel(&Rect, pText, 10.0f, TEXTALIGN_ML);
2009-10-27 14:38:53 +00:00
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
2008-01-13 22:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
int CEditor::DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
2008-01-13 22:03:32 +00:00
{
2009-10-27 14:38:53 +00:00
if(UI()->HotItem() == pID || Checked)
pRect->Draw(GetButtonColor(pID, Checked), IGraphics::CORNER_ALL, 3.0f);
2010-05-29 07:25:38 +00:00
CUIRect Rect;
pRect->VMargin(5.0f, &Rect);
UI()->DoLabel(&Rect, pText, 10.0f, TEXTALIGN_ML);
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
2008-01-13 22:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
int CEditor::DoButton_Tab(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
2007-05-22 15:03:32 +00:00
{
pRect->Draw(GetButtonColor(pID, Checked), IGraphics::CORNER_T, 5.0f);
UI()->DoLabel(pRect, pText, 10.0f, TEXTALIGN_MC);
2009-10-27 14:38:53 +00:00
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
2007-05-22 15:03:32 +00:00
}
int CEditor::DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize)
2007-05-22 15:03:32 +00:00
{
pRect->Draw(GetButtonColor(pID, Checked), Corners, 3.0f);
UI()->DoLabel(pRect, pText, FontSize, TEXTALIGN_MC);
2009-10-27 14:38:53 +00:00
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
2007-05-22 15:03:32 +00:00
}
int CEditor::DoButton_FontIcon(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize)
{
pRect->Draw(GetButtonColor(pID, Checked), Corners, 3.0f);
TextRender()->SetCurFont(TextRender()->GetFont(TEXT_FONT_ICON_FONT));
UI()->DoLabel(pRect, pText, FontSize, TEXTALIGN_MC);
TextRender()->SetCurFont(nullptr);
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
}
2010-05-29 07:25:38 +00:00
int CEditor::DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
2007-05-22 15:03:32 +00:00
{
pRect->Draw(GetButtonColor(pID, Checked), IGraphics::CORNER_R, 3.0f);
UI()->DoLabel(pRect, pText ? pText : "+", 10.0f, TEXTALIGN_MC);
2009-10-27 14:38:53 +00:00
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
int CEditor::DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip)
2007-05-22 15:03:32 +00:00
{
pRect->Draw(GetButtonColor(pID, Checked), IGraphics::CORNER_L, 3.0f);
UI()->DoLabel(pRect, pText ? pText : "-", 10.0f, TEXTALIGN_MC);
2009-10-27 14:38:53 +00:00
return DoButton_Editor_Common(pID, pText, Checked, pRect, Flags, pToolTip);
2007-05-22 15:03:32 +00:00
}
2019-04-26 12:06:32 +00:00
int CEditor::DoButton_ColorPicker(const void *pID, const CUIRect *pRect, ColorRGBA *pColor, const char *pToolTip)
{
pRect->Draw(*pColor, 0, 0.0f);
return DoButton_Editor_Common(pID, nullptr, 0, pRect, 0, pToolTip);
}
int CEditor::DoButton_DraggableEx(const void *pID, const char *pText, int Checked, const CUIRect *pRect, bool *pClicked, bool *pAbrupted, int Flags, const char *pToolTip, int Corners, float FontSize)
2023-03-15 17:15:43 +00:00
{
pRect->Draw(GetButtonColor(pID, Checked), Corners, 3.0f);
UI()->DoLabel(pRect, pText, FontSize, TEXTALIGN_MC);
2023-03-15 17:15:43 +00:00
if(UI()->MouseInside(pRect))
{
if(Flags & BUTTON_CONTEXT)
ms_pUiGotContext = pID;
}
UpdateTooltip(pID, pRect, pToolTip);
return UI()->DoDraggableButtonLogic(pID, Checked, pRect, pClicked, pAbrupted);
}
2011-07-10 20:16:16 +00:00
void CEditor::RenderGrid(CLayerGroup *pGroup)
{
if(!m_GridActive)
return;
float aGroupPoints[4];
2011-08-11 08:59:14 +00:00
pGroup->Mapping(aGroupPoints);
2011-07-10 20:16:16 +00:00
float w = UI()->Screen()->w;
float h = UI()->Screen()->h;
int LineDistance = GetLineDistance();
int XOffset = aGroupPoints[0] / LineDistance;
int YOffset = aGroupPoints[1] / LineDistance;
2011-07-10 20:16:16 +00:00
int XGridOffset = XOffset % m_GridFactor;
int YGridOffset = YOffset % m_GridFactor;
Graphics()->TextureClear();
2011-07-10 20:16:16 +00:00
Graphics()->LinesBegin();
for(int i = 0; i < (int)w; i++)
{
if((i + YGridOffset) % m_GridFactor == 0)
2011-07-10 20:16:16 +00:00
Graphics()->SetColor(1.0f, 0.3f, 0.3f, 0.3f);
else
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.15f);
IGraphics::CLineItem Line = IGraphics::CLineItem(LineDistance * XOffset, LineDistance * i + LineDistance * YOffset, w + aGroupPoints[2], LineDistance * i + LineDistance * YOffset);
2011-07-10 20:16:16 +00:00
Graphics()->LinesDraw(&Line, 1);
if((i + XGridOffset) % m_GridFactor == 0)
2011-07-10 20:16:16 +00:00
Graphics()->SetColor(1.0f, 0.3f, 0.3f, 0.3f);
else
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 0.15f);
Line = IGraphics::CLineItem(LineDistance * i + LineDistance * XOffset, LineDistance * YOffset, LineDistance * i + LineDistance * XOffset, h + aGroupPoints[3]);
2011-07-10 20:16:16 +00:00
Graphics()->LinesDraw(&Line, 1);
}
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
Graphics()->LinesEnd();
}
void CEditor::SnapToGrid(float &x, float &y)
{
const int GridDistance = GetLineDistance() * m_GridFactor;
x = (int)((x + (x >= 0 ? 1.0f : -1.0f) * GridDistance / 2) / GridDistance) * GridDistance;
y = (int)((y + (y >= 0 ? 1.0f : -1.0f) * GridDistance / 2) / GridDistance) * GridDistance;
}
void CEditor::RenderBackground(CUIRect View, IGraphics::CTextureHandle Texture, float Size, float Brightness)
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
Graphics()->TextureSet(Texture);
2009-10-27 14:38:53 +00:00
Graphics()->BlendNormal();
Graphics()->QuadsBegin();
2010-05-29 07:25:38 +00:00
Graphics()->SetColor(Brightness, Brightness, Brightness, 1.0f);
Graphics()->QuadsSetSubset(0, 0, View.w / Size, View.h / Size);
2010-05-29 07:25:38 +00:00
IGraphics::CQuadItem QuadItem(View.x, View.y, View.w, View.h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
2007-05-22 15:03:32 +00:00
}
int CEditor::UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip, bool IsDegree, bool IsHex, int Corners, ColorRGBA *pColor, bool ShowValue)
{
2015-03-30 09:44:32 +00:00
// logic
static float s_Value;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInputNumber s_NumberInput;
2015-03-30 09:44:32 +00:00
static bool s_TextMode = false;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static void *s_pLastTextID = pID;
const bool Inside = UI()->MouseInside(pRect);
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
const int Base = IsHex ? 16 : 10;
2015-03-30 09:44:32 +00:00
if(UI()->MouseButton(1) && UI()->HotItem() == pID)
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
s_pLastTextID = pID;
2015-03-30 09:44:32 +00:00
s_TextMode = true;
UI()->DisableMouseLock();
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
s_NumberInput.SetInteger(Current, Base);
2015-03-30 09:44:32 +00:00
}
if(UI()->CheckActiveItem(pID))
{
if(!UI()->MouseButton(0))
{
UI()->DisableMouseLock();
UI()->SetActiveItem(nullptr);
s_TextMode = false;
}
}
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(s_TextMode && s_pLastTextID == pID)
2015-03-30 09:44:32 +00:00
{
m_pTooltip = "Type your number";
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
DoEditBox(&s_NumberInput, pRect, 10.0f);
2015-03-30 09:44:32 +00:00
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UI()->SetActiveItem(&s_NumberInput);
2015-03-30 09:44:32 +00:00
if(Input()->KeyIsPressed(KEY_RETURN) || Input()->KeyIsPressed(KEY_KP_ENTER) ||
((UI()->MouseButton(1) || UI()->MouseButton(0)) && !Inside))
2015-03-30 09:44:32 +00:00
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
Current = clamp(s_NumberInput.GetInteger(Base), Min, Max);
UI()->DisableMouseLock();
UI()->SetActiveItem(nullptr);
2015-03-30 09:44:32 +00:00
s_TextMode = false;
}
if(Input()->KeyIsPressed(KEY_ESCAPE))
2015-03-30 09:44:32 +00:00
{
UI()->DisableMouseLock();
UI()->SetActiveItem(nullptr);
2015-03-30 09:44:32 +00:00
s_TextMode = false;
}
}
else
{
if(UI()->CheckActiveItem(pID))
2015-03-30 09:44:32 +00:00
{
if(UI()->MouseButton(0))
2015-03-30 09:44:32 +00:00
{
if(Input()->ShiftIsPressed())
s_Value += m_MouseDeltaX * 0.05f;
2015-03-30 09:44:32 +00:00
else
s_Value += m_MouseDeltaX;
2011-08-11 08:59:14 +00:00
if(absolute(s_Value) >= Scale)
2015-03-30 09:44:32 +00:00
{
int Count = (int)(s_Value / Scale);
s_Value = std::fmod(s_Value, Scale);
Current += Step * Count;
2015-03-30 09:44:32 +00:00
Current = clamp(Current, Min, Max);
// Constrain to discrete steps
if(Count > 0)
Current = Current / Step * Step;
else
Current = std::ceil(Current / (float)Step) * Step;
2015-03-30 09:44:32 +00:00
}
}
if(pToolTip && !s_TextMode)
m_pTooltip = pToolTip;
}
else if(UI()->HotItem() == pID)
{
if(UI()->MouseButton(0))
{
UI()->SetActiveItem(pID);
UI()->EnableMouseLock(pID);
s_Value = 0;
2015-03-30 09:44:32 +00:00
}
if(pToolTip && !s_TextMode)
m_pTooltip = pToolTip;
}
if(Inside)
UI()->SetHotItem(pID);
// render
char aBuf[128];
2015-07-08 11:38:21 +00:00
if(pLabel[0] != '\0')
{
if(ShowValue)
str_format(aBuf, sizeof(aBuf), "%s %d", pLabel, Current);
else
str_copy(aBuf, pLabel);
}
2017-03-21 10:24:44 +00:00
else if(IsDegree)
str_format(aBuf, sizeof(aBuf), "%d°", Current);
2017-03-21 10:24:44 +00:00
else if(IsHex)
str_format(aBuf, sizeof(aBuf), "#%06X", Current);
2015-07-08 11:38:21 +00:00
else
str_format(aBuf, sizeof(aBuf), "%d", Current);
pRect->Draw(pColor ? *pColor : GetButtonColor(pID, 0), Corners, 5.0f);
UI()->DoLabel(pRect, aBuf, 10, TEXTALIGN_MC);
2015-03-30 09:44:32 +00:00
}
2015-07-09 00:08:14 +00:00
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(!s_TextMode)
s_NumberInput.Clear();
2010-05-29 07:25:38 +00:00
return Current;
2007-05-22 15:03:32 +00:00
}
CLayerGroup *CEditor::GetSelectedGroup() const
2007-05-22 15:03:32 +00:00
{
if(m_SelectedGroup >= 0 && m_SelectedGroup < (int)m_Map.m_vpGroups.size())
return m_Map.m_vpGroups[m_SelectedGroup];
return nullptr;
2007-05-22 15:03:32 +00:00
}
CLayer *CEditor::GetSelectedLayer(int Index) const
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
CLayerGroup *pGroup = GetSelectedGroup();
if(!pGroup)
return nullptr;
2018-10-02 01:52:01 +00:00
if(Index < 0 || Index >= (int)m_vSelectedLayers.size())
return nullptr;
2018-10-02 01:52:01 +00:00
int LayerIndex = m_vSelectedLayers[Index];
2008-01-12 12:27:55 +00:00
if(LayerIndex >= 0 && LayerIndex < (int)m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers.size())
return pGroup->m_vpLayers[LayerIndex];
return nullptr;
2007-05-22 15:03:32 +00:00
}
CLayer *CEditor::GetSelectedLayerType(int Index, int Type) const
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
CLayer *p = GetSelectedLayer(Index);
if(p && p->m_Type == Type)
2008-01-12 12:27:55 +00:00
return p;
return nullptr;
2007-05-22 15:03:32 +00:00
}
std::vector<CQuad *> CEditor::GetSelectedQuads()
2008-01-12 12:27:55 +00:00
{
CLayerQuads *pQuadLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
std::vector<CQuad *> vpQuads;
if(!pQuadLayer)
return vpQuads;
vpQuads.resize(m_vSelectedQuads.size());
for(int i = 0; i < (int)m_vSelectedQuads.size(); ++i)
vpQuads[i] = &pQuadLayer->m_vQuads[m_vSelectedQuads[i]];
return vpQuads;
2008-01-12 12:27:55 +00:00
}
2007-12-02 17:55:45 +00:00
CSoundSource *CEditor::GetSelectedSource()
{
CLayerSounds *pSounds = (CLayerSounds *)GetSelectedLayerType(0, LAYERTYPE_SOUNDS);
if(!pSounds)
return nullptr;
if(m_SelectedSource >= 0 && m_SelectedSource < (int)pSounds->m_vSources.size())
return &pSounds->m_vSources[m_SelectedSource];
return nullptr;
}
void CEditor::SelectLayer(int LayerIndex, int GroupIndex)
{
if(GroupIndex != -1)
m_SelectedGroup = GroupIndex;
m_vSelectedLayers.clear();
m_vSelectedQuads.clear();
2022-02-26 17:49:06 +00:00
AddSelectedLayer(LayerIndex);
}
void CEditor::AddSelectedLayer(int LayerIndex)
{
m_vSelectedLayers.push_back(LayerIndex);
2022-02-26 17:49:06 +00:00
m_QuadKnifeActive = false;
}
2018-08-13 09:11:56 +00:00
void CEditor::SelectQuad(int Index)
{
m_vSelectedQuads.clear();
m_vSelectedQuads.push_back(Index);
2018-08-13 09:11:56 +00:00
}
void CEditor::DeleteSelectedQuads()
{
CLayerQuads *pLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
if(!pLayer)
return;
for(int i = 0; i < (int)m_vSelectedQuads.size(); ++i)
2018-08-13 09:11:56 +00:00
{
pLayer->m_vQuads.erase(pLayer->m_vQuads.begin() + m_vSelectedQuads[i]);
for(int j = i + 1; j < (int)m_vSelectedQuads.size(); ++j)
if(m_vSelectedQuads[j] > m_vSelectedQuads[i])
m_vSelectedQuads[j]--;
2018-08-13 09:11:56 +00:00
m_vSelectedQuads.erase(m_vSelectedQuads.begin() + i);
i--;
2018-08-13 09:11:56 +00:00
}
2018-08-13 14:46:53 +00:00
}
bool CEditor::IsQuadSelected(int Index) const
2018-08-13 14:46:53 +00:00
{
return FindSelectedQuadIndex(Index) >= 0;
2018-08-13 14:46:53 +00:00
}
int CEditor::FindSelectedQuadIndex(int Index) const
2018-08-13 14:46:53 +00:00
{
for(size_t i = 0; i < m_vSelectedQuads.size(); ++i)
if(m_vSelectedQuads[i] == Index)
2018-08-13 14:46:53 +00:00
return i;
return -1;
2018-08-13 09:11:56 +00:00
}
bool CEditor::CallbackOpenMap(const char *pFileName, int StorageType, void *pUser)
2010-09-12 11:15:59 +00:00
{
CEditor *pEditor = (CEditor *)pUser;
if(pEditor->Load(pFileName, StorageType))
2010-06-02 16:12:32 +00:00
{
pEditor->m_ValidSaveFilename = StorageType == IStorage::TYPE_SAVE && pEditor->m_pFileDialogPath == pEditor->m_aFileDialogCurrentFolder;
2010-09-12 11:15:59 +00:00
pEditor->m_Dialog = DIALOG_NONE;
return true;
}
else
{
pEditor->ShowFileDialogError("Failed to load map from file '%s'.", pFileName);
return false;
}
2010-06-02 16:12:32 +00:00
}
bool CEditor::CallbackAppendMap(const char *pFileName, int StorageType, void *pUser)
2010-06-02 16:12:32 +00:00
{
CEditor *pEditor = (CEditor *)pUser;
if(pEditor->Append(pFileName, StorageType))
{
pEditor->m_Dialog = DIALOG_NONE;
return true;
}
else
{
2010-06-02 16:12:32 +00:00
pEditor->m_aFileName[0] = 0;
pEditor->ShowFileDialogError("Failed to load map from file '%s'.", pFileName);
return false;
}
2010-06-02 16:12:32 +00:00
}
bool CEditor::CallbackSaveMap(const char *pFileName, int StorageType, void *pUser)
{
CEditor *pEditor = static_cast<CEditor *>(pUser);
char aBuf[1024];
// add map extension
if(!str_endswith(pFileName, ".map"))
{
str_format(aBuf, sizeof(aBuf), "%s.map", pFileName);
pFileName = aBuf;
}
if(pEditor->Save(pFileName))
{
str_copy(pEditor->m_aFileName, pFileName, sizeof(pEditor->m_aFileName));
pEditor->m_ValidSaveFilename = StorageType == IStorage::TYPE_SAVE && pEditor->m_pFileDialogPath == pEditor->m_aFileDialogCurrentFolder;
pEditor->m_Map.m_Modified = false;
pEditor->m_Dialog = DIALOG_NONE;
return true;
}
else
{
pEditor->ShowFileDialogError("Failed to save map to file '%s'.", pFileName);
return false;
}
}
2007-12-02 17:55:45 +00:00
bool CEditor::CallbackSaveCopyMap(const char *pFileName, int StorageType, void *pUser)
{
CEditor *pEditor = static_cast<CEditor *>(pUser);
char aBuf[1024];
// add map extension
if(!str_endswith(pFileName, ".map"))
{
str_format(aBuf, sizeof(aBuf), "%s.map", pFileName);
pFileName = aBuf;
}
if(pEditor->Save(pFileName))
{
pEditor->m_Map.m_Modified = false;
pEditor->m_Dialog = DIALOG_NONE;
return true;
}
else
{
pEditor->ShowFileDialogError("Failed to save map to file '%s'.", pFileName);
return false;
}
}
2010-05-29 07:25:38 +00:00
void CEditor::DoToolbar(CUIRect ToolBar)
{
const bool ModPressed = Input()->ModifierIsPressed();
const bool ShiftPressed = Input()->ShiftIsPressed();
2020-05-15 16:14:39 +00:00
2023-05-01 20:44:03 +00:00
// handle shortcut for info button
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_I) && ModPressed && !ShiftPressed)
{
2023-05-22 12:46:25 +00:00
if(m_ShowTileInfo == SHOW_TILE_HEXADECIMAL)
2023-05-22 18:20:45 +00:00
m_ShowTileInfo = SHOW_TILE_DECIMAL;
2023-05-22 12:46:25 +00:00
else if(m_ShowTileInfo != SHOW_TILE_OFF)
m_ShowTileInfo = SHOW_TILE_OFF;
2023-05-01 20:44:03 +00:00
else
2023-05-22 18:20:45 +00:00
m_ShowTileInfo = SHOW_TILE_DECIMAL;
2023-05-01 20:44:03 +00:00
m_ShowEnvelopePreview = SHOWENV_NONE;
}
2023-05-01 20:44:03 +00:00
// handle shortcut for hex button
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_I) && ModPressed && ShiftPressed)
{
2023-05-22 18:20:45 +00:00
m_ShowTileInfo = m_ShowTileInfo == SHOW_TILE_HEXADECIMAL ? SHOW_TILE_OFF : SHOW_TILE_HEXADECIMAL;
2023-05-01 20:44:03 +00:00
m_ShowEnvelopePreview = SHOWENV_NONE;
}
2023-05-01 20:44:03 +00:00
// handle shortcut for unused button
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_U) && ModPressed)
m_AllowPlaceUnusedTiles = !m_AllowPlaceUnusedTiles;
2020-05-15 16:14:39 +00:00
2010-05-29 07:25:38 +00:00
CUIRect TB_Top, TB_Bottom;
CUIRect Button;
2011-08-11 08:59:14 +00:00
2022-01-26 19:23:50 +00:00
ToolBar.HSplitMid(&TB_Top, &TB_Bottom, 5.0f);
2020-05-17 01:39:23 +00:00
// top line buttons
{
2020-05-17 01:39:23 +00:00
// detail button
TB_Top.VSplitLeft(40.0f, &Button, &TB_Top);
static int s_HqButton = 0;
if(DoButton_Editor(&s_HqButton, "HD", m_ShowDetail, &Button, 0, "[ctrl+h] Toggle High Detail") ||
(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_H) && ModPressed))
2020-05-17 01:39:23 +00:00
{
m_ShowDetail = !m_ShowDetail;
}
TB_Top.VSplitLeft(5.0f, nullptr, &TB_Top);
2010-05-29 07:25:38 +00:00
2020-05-17 01:39:23 +00:00
// animation button
TB_Top.VSplitLeft(40.0f, &Button, &TB_Top);
static int s_AnimateButton = 0;
if(DoButton_Editor(&s_AnimateButton, "Anim", m_Animate, &Button, 0, "[ctrl+m] Toggle animation") ||
(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_M) && ModPressed))
2020-05-17 01:39:23 +00:00
{
m_AnimateStart = time_get();
m_Animate = !m_Animate;
}
2008-01-13 13:42:59 +00:00
TB_Top.VSplitLeft(5.0f, nullptr, &TB_Top);
2008-01-13 13:42:59 +00:00
2020-05-17 01:39:23 +00:00
// proof button
TB_Top.VSplitLeft(40.0f, &Button, &TB_Top);
static int s_ProofButton = 0;
2023-05-21 20:21:13 +00:00
if(DoButton_Ex(&s_ProofButton, "Proof", m_ProofBorders != PROOF_BORDER_OFF, &Button, 0, "[ctrl+p] Toggles proof borders. These borders represent what a player maximum can see.", IGraphics::CORNER_L) ||
(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_P) && ModPressed))
2020-05-17 01:39:23 +00:00
{
2023-05-21 19:26:23 +00:00
m_ProofBorders = m_ProofBorders == PROOF_BORDER_OFF ? PROOF_BORDER_INGAME : PROOF_BORDER_OFF;
}
2023-05-01 21:07:58 +00:00
TB_Top.VSplitLeft(10.0f, &Button, &TB_Top);
static int s_MenuProofButton = 0;
2023-05-01 21:07:58 +00:00
if(DoButton_Ex(&s_MenuProofButton, "", 0, &Button, 0, "Select proof mode.", IGraphics::CORNER_R))
{
2023-05-01 21:07:58 +00:00
static SPopupMenuId s_PopupProofModeId;
UI()->DoPopupMenu(&s_PopupProofModeId, Button.x, Button.y + Button.h, 60.0f, 36.0f, this, PopupProofMode);
2020-05-17 01:39:23 +00:00
}
2008-01-13 13:42:59 +00:00
TB_Top.VSplitLeft(5.0f, nullptr, &TB_Top);
// zoom button
TB_Top.VSplitLeft(40.0f, &Button, &TB_Top);
static int s_ZoomButton = 0;
if(DoButton_Editor(&s_ZoomButton, "Zoom", m_PreviewZoom, &Button, 0, "Toggles preview of how layers will be zoomed in-game"))
{
m_PreviewZoom = !m_PreviewZoom;
}
TB_Top.VSplitLeft(5.0f, nullptr, &TB_Top);
2020-05-17 01:39:23 +00:00
// grid button
TB_Top.VSplitLeft(40.0f, &Button, &TB_Top);
static int s_GridButton = 0;
if(DoButton_Editor(&s_GridButton, "Grid", m_GridActive, &Button, 0, "[ctrl+g] Toggle Grid") ||
(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_G) && ModPressed && !ShiftPressed))
2020-05-17 01:39:23 +00:00
{
m_GridActive = !m_GridActive;
}
2016-05-01 00:34:06 +00:00
TB_Top.VSplitLeft(5.0f, nullptr, &TB_Top);
2016-05-01 00:34:06 +00:00
2020-05-17 01:39:23 +00:00
// zoom group
TB_Top.VSplitLeft(20.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_ZoomOutButton = 0;
if(DoButton_FontIcon(&s_ZoomOutButton, "-", 0, &Button, 0, "[NumPad-] Zoom out", IGraphics::CORNER_L))
{
ChangeZoom(50.0f);
}
2010-05-29 07:25:38 +00:00
TB_Top.VSplitLeft(25.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_ZoomNormalButton = 0;
if(DoButton_FontIcon(&s_ZoomNormalButton, FONT_ICON_MAGNIFYING_GLASS, 0, &Button, 0, "[NumPad*] Zoom to normal and remove editor offset", IGraphics::CORNER_NONE))
2020-05-17 01:39:23 +00:00
{
m_EditorOffsetX = 0;
m_EditorOffsetY = 0;
SetZoom(100.0f);
2020-05-17 01:39:23 +00:00
}
2010-05-29 07:25:38 +00:00
TB_Top.VSplitLeft(20.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_ZoomInButton = 0;
if(DoButton_FontIcon(&s_ZoomInButton, "+", 0, &Button, 0, "[NumPad+] Zoom in", IGraphics::CORNER_R))
{
ChangeZoom(-50.0f);
}
2010-05-29 07:25:38 +00:00
TB_Top.VSplitLeft(5.0f, nullptr, &TB_Top);
2010-05-29 07:25:38 +00:00
2020-05-17 01:39:23 +00:00
// brush manipulation
{
int Enabled = m_Brush.IsEmpty() ? -1 : 0;
2010-05-29 07:25:38 +00:00
2020-05-17 01:39:23 +00:00
// flip buttons
TB_Top.VSplitLeft(25.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_FlipXButton = 0;
if(DoButton_FontIcon(&s_FlipXButton, FONT_ICON_ARROWS_LEFT_RIGHT, Enabled, &Button, 0, "[N] Flip brush horizontal", IGraphics::CORNER_L) || (Input()->KeyPress(KEY_N) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0))
2020-05-17 01:39:23 +00:00
{
for(auto &pLayer : m_Brush.m_vpLayers)
pLayer->BrushFlipX();
2020-05-17 01:39:23 +00:00
}
2010-05-29 07:25:38 +00:00
TB_Top.VSplitLeft(25.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_FlipyButton = 0;
if(DoButton_FontIcon(&s_FlipyButton, FONT_ICON_ARROWS_UP_DOWN, Enabled, &Button, 0, "[M] Flip brush vertical", IGraphics::CORNER_R) || (Input()->KeyPress(KEY_M) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0))
2020-05-17 01:39:23 +00:00
{
for(auto &pLayer : m_Brush.m_vpLayers)
pLayer->BrushFlipY();
2020-05-17 01:39:23 +00:00
}
TB_Top.VSplitLeft(5.0f, nullptr, &TB_Top);
2008-01-12 12:27:55 +00:00
2020-05-17 01:39:23 +00:00
// rotate buttons
TB_Top.VSplitLeft(25.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_RotationAmount = 90;
bool TileLayer = false;
// check for tile layers in brush selection
for(auto &pLayer : m_Brush.m_vpLayers)
if(pLayer->m_Type == LAYERTYPE_TILES)
2020-05-17 01:39:23 +00:00
{
TileLayer = true;
s_RotationAmount = maximum(90, (s_RotationAmount / 90) * 90);
2020-05-17 01:39:23 +00:00
break;
}
2008-01-12 12:27:55 +00:00
2020-05-17 01:39:23 +00:00
static int s_CcwButton = 0;
if(DoButton_FontIcon(&s_CcwButton, FONT_ICON_ARROW_ROTATE_LEFT, Enabled, &Button, 0, "[R] Rotates the brush counter clockwise", IGraphics::CORNER_ALL) || (Input()->KeyPress(KEY_R) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0))
2020-05-17 01:39:23 +00:00
{
for(auto &pLayer : m_Brush.m_vpLayers)
pLayer->BrushRotate(-s_RotationAmount / 360.0f * pi * 2);
2020-05-17 01:39:23 +00:00
}
2008-01-12 12:27:55 +00:00
2020-05-17 01:39:23 +00:00
TB_Top.VSplitLeft(30.0f, &Button, &TB_Top);
s_RotationAmount = UiDoValueSelector(&s_RotationAmount, &Button, "", s_RotationAmount, TileLayer ? 90 : 1, 359, TileLayer ? 90 : 1, TileLayer ? 10.0f : 2.0f, "Rotation of the brush in degrees. Use left mouse button to drag and change the value. Hold shift to be more precise.", true);
TB_Top.VSplitLeft(25.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_CwButton = 0;
if(DoButton_FontIcon(&s_CwButton, FONT_ICON_ARROW_ROTATE_RIGHT, Enabled, &Button, 0, "[T] Rotates the brush clockwise", IGraphics::CORNER_ALL) || (Input()->KeyPress(KEY_T) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0))
2020-05-17 01:39:23 +00:00
{
for(auto &pLayer : m_Brush.m_vpLayers)
pLayer->BrushRotate(s_RotationAmount / 360.0f * pi * 2);
2020-05-17 01:39:23 +00:00
}
2010-05-29 07:25:38 +00:00
2020-05-17 01:39:23 +00:00
TB_Top.VSplitLeft(5.0f, &Button, &TB_Top);
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
2020-05-17 01:39:23 +00:00
// animation speed
if(m_Animate)
2008-01-12 12:27:55 +00:00
{
TB_Top.VSplitLeft(20.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_AnimSlowerButton = 0;
if(DoButton_FontIcon(&s_AnimSlowerButton, "-", 0, &Button, 0, "Decrease animation speed", IGraphics::CORNER_L))
{
2020-05-17 01:39:23 +00:00
if(m_AnimateSpeed > 0.5f)
m_AnimateSpeed -= 0.5f;
}
2010-05-29 07:25:38 +00:00
TB_Top.VSplitLeft(25.0f, &Button, &TB_Top);
static int s_AnimNormalButton = 0;
if(DoButton_FontIcon(&s_AnimNormalButton, FONT_ICON_CIRCLE_PLAY, 0, &Button, 0, "Normal animation speed", 0))
m_AnimateSpeed = 1.0f;
TB_Top.VSplitLeft(20.0f, &Button, &TB_Top);
static int s_AnimFasterButton = 0;
if(DoButton_FontIcon(&s_AnimFasterButton, "+", 0, &Button, 0, "Increase animation speed", IGraphics::CORNER_R))
m_AnimateSpeed += 0.5f;
2020-05-17 01:39:23 +00:00
TB_Top.VSplitLeft(5.0f, &Button, &TB_Top);
}
2010-05-29 07:25:38 +00:00
2020-05-17 01:39:23 +00:00
// grid zoom
if(m_GridActive)
{
TB_Top.VSplitLeft(20.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_GridIncreaseButton = 0;
if(DoButton_FontIcon(&s_GridIncreaseButton, "-", 0, &Button, 0, "Decrease grid", IGraphics::CORNER_L))
2020-05-17 01:39:23 +00:00
{
if(m_GridFactor > 1)
m_GridFactor--;
}
2008-01-12 12:27:55 +00:00
TB_Top.VSplitLeft(25.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_GridNormalButton = 0;
if(DoButton_FontIcon(&s_GridNormalButton, FONT_ICON_BORDER_ALL, 0, &Button, 0, "Normal grid", IGraphics::CORNER_NONE))
2020-05-17 01:39:23 +00:00
m_GridFactor = 1;
TB_Top.VSplitLeft(20.0f, &Button, &TB_Top);
2020-05-17 01:39:23 +00:00
static int s_GridDecreaseButton = 0;
if(DoButton_FontIcon(&s_GridDecreaseButton, "+", 0, &Button, 0, "Increase grid", IGraphics::CORNER_R))
2020-05-17 01:39:23 +00:00
{
if(m_GridFactor < 15)
m_GridFactor++;
}
TB_Top.VSplitLeft(5.0f, &Button, &TB_Top);
2020-05-15 16:51:14 +00:00
}
2008-01-12 12:27:55 +00:00
}
2011-08-11 08:59:14 +00:00
2020-05-17 01:39:23 +00:00
// Bottom line buttons
2010-05-29 07:25:38 +00:00
{
2020-05-17 01:39:23 +00:00
// refocus button
2010-05-29 07:25:38 +00:00
{
2020-05-17 01:39:23 +00:00
TB_Bottom.VSplitLeft(45.0f, &Button, &TB_Bottom);
static int s_RefocusButton = 0;
int FocusButtonChecked;
if(m_ProofBorders == PROOF_BORDER_MENU)
{
if(distance(m_vMenuBackgroundPositions[m_CurrentMenuProofIndex], vec2(m_WorldOffsetX, m_WorldOffsetY)) < 0.0001f)
FocusButtonChecked = -1;
else
FocusButtonChecked = 1;
}
else
2020-05-15 16:51:14 +00:00
{
if(m_WorldOffsetX == 0 && m_WorldOffsetY == 0)
FocusButtonChecked = -1;
else
FocusButtonChecked = 1;
}
if(DoButton_Editor(&s_RefocusButton, "Refocus", FocusButtonChecked, &Button, 0, "[HOME] Restore map focus") || (m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_HOME)))
2020-05-15 16:51:14 +00:00
{
if(m_ProofBorders == PROOF_BORDER_MENU)
{
m_WorldOffsetX = m_vMenuBackgroundPositions[m_CurrentMenuProofIndex].x;
m_WorldOffsetY = m_vMenuBackgroundPositions[m_CurrentMenuProofIndex].y;
}
else
{
m_WorldOffsetX = 0;
m_WorldOffsetY = 0;
}
2020-05-15 16:51:14 +00:00
}
TB_Bottom.VSplitLeft(5.0f, nullptr, &TB_Bottom);
2010-05-29 07:25:38 +00:00
}
2016-05-01 00:34:06 +00:00
2020-05-17 01:39:23 +00:00
// tile manipulation
{
2020-05-17 01:39:23 +00:00
// do tele/tune/switch/speedup button
{
CLayerTiles *pS = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES);
if(pS)
{
const char *pButtonName = nullptr;
CUI::FPopupMenuFunction pfnPopupFunc = nullptr;
int Rows = 0;
2020-05-17 01:39:23 +00:00
if(pS == m_Map.m_pSwitchLayer)
{
pButtonName = "Switch";
pfnPopupFunc = PopupSwitch;
Rows = 2;
2020-05-17 01:39:23 +00:00
}
else if(pS == m_Map.m_pSpeedupLayer)
{
pButtonName = "Speedup";
pfnPopupFunc = PopupSpeedup;
Rows = 3;
2020-05-17 01:39:23 +00:00
}
else if(pS == m_Map.m_pTuneLayer)
{
pButtonName = "Tune";
pfnPopupFunc = PopupTune;
Rows = 1;
2020-05-17 01:39:23 +00:00
}
else if(pS == m_Map.m_pTeleLayer)
{
pButtonName = "Tele";
pfnPopupFunc = PopupTele;
Rows = 1;
2020-05-17 01:39:23 +00:00
}
if(pButtonName != nullptr)
2020-05-15 16:51:14 +00:00
{
static char s_aButtonTooltip[64];
str_format(s_aButtonTooltip, sizeof(s_aButtonTooltip), "[ctrl+t] %s", pButtonName);
2020-05-17 01:39:23 +00:00
TB_Bottom.VSplitLeft(60.0f, &Button, &TB_Bottom);
static int s_ModifierButton = 0;
if(DoButton_Ex(&s_ModifierButton, pButtonName, 0, &Button, 0, s_aButtonTooltip, IGraphics::CORNER_ALL) || (m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && ModPressed && Input()->KeyPress(KEY_T)))
{
static SPopupMenuId s_PopupModifierId;
if(!UI()->IsPopupOpen(&s_PopupModifierId))
2020-05-17 01:39:23 +00:00
{
UI()->DoPopupMenu(&s_PopupModifierId, Button.x, Button.y + Button.h, 120, 10.0f + Rows * 13.0f, this, pfnPopupFunc);
2020-05-17 01:39:23 +00:00
}
}
TB_Bottom.VSplitLeft(5.0f, nullptr, &TB_Bottom);
2020-05-15 16:51:14 +00:00
}
}
}
}
2020-05-17 01:39:23 +00:00
// do add quad/sound button
CLayer *pLayer = GetSelectedLayer(0);
if(pLayer && (pLayer->m_Type == LAYERTYPE_QUADS || pLayer->m_Type == LAYERTYPE_SOUNDS))
{
2020-05-17 01:39:23 +00:00
TB_Bottom.VSplitLeft(60.0f, &Button, &TB_Bottom);
2020-05-19 16:17:02 +00:00
bool Invoked = false;
2020-05-17 01:39:23 +00:00
static int s_AddItemButton = 0;
2016-05-01 00:34:06 +00:00
2020-05-17 01:39:23 +00:00
if(pLayer->m_Type == LAYERTYPE_QUADS)
2020-05-15 16:51:14 +00:00
{
2020-05-19 16:17:02 +00:00
Invoked = DoButton_Editor(&s_AddItemButton, "Add Quad", 0, &Button, 0, "[ctrl+q] Add a new quad") ||
(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_Q) && ModPressed);
2020-05-17 01:39:23 +00:00
}
else if(pLayer->m_Type == LAYERTYPE_SOUNDS)
{
2020-05-19 16:17:02 +00:00
Invoked = DoButton_Editor(&s_AddItemButton, "Add Sound", 0, &Button, 0, "[ctrl+q] Add a new sound source") ||
(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_Q) && ModPressed);
2020-05-15 16:51:14 +00:00
}
2020-05-19 16:17:02 +00:00
if(Invoked)
2020-05-15 16:51:14 +00:00
{
2020-05-17 01:39:23 +00:00
CLayerGroup *pGroup = GetSelectedGroup();
float aMapping[4];
pGroup->Mapping(aMapping);
int x = aMapping[0] + (aMapping[2] - aMapping[0]) / 2;
int y = aMapping[1] + (aMapping[3] - aMapping[1]) / 2;
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_Q) && ModPressed)
2016-05-01 00:34:06 +00:00
{
x += UI()->MouseWorldX() - (m_WorldOffsetX * pGroup->m_ParallaxX / 100) - pGroup->m_OffsetX;
y += UI()->MouseWorldY() - (m_WorldOffsetY * pGroup->m_ParallaxY / 100) - pGroup->m_OffsetY;
2016-05-01 00:34:06 +00:00
}
2020-05-15 16:51:14 +00:00
2020-05-17 01:39:23 +00:00
if(pLayer->m_Type == LAYERTYPE_QUADS)
{
CLayerQuads *pLayerQuads = (CLayerQuads *)pLayer;
2020-05-17 01:39:23 +00:00
int Width = 64;
int Height = 64;
if(pLayerQuads->m_Image >= 0)
2020-05-17 01:39:23 +00:00
{
Width = m_Map.m_vpImages[pLayerQuads->m_Image]->m_Width;
Height = m_Map.m_vpImages[pLayerQuads->m_Image]->m_Height;
2020-05-17 01:39:23 +00:00
}
pLayerQuads->NewQuad(x, y, Width, Height);
2020-05-17 01:39:23 +00:00
}
else if(pLayer->m_Type == LAYERTYPE_SOUNDS)
{
CLayerSounds *pLayerSounds = (CLayerSounds *)pLayer;
pLayerSounds->NewSource(x, y);
2020-05-17 01:39:23 +00:00
}
2016-05-01 00:34:06 +00:00
}
2020-05-17 01:39:23 +00:00
TB_Bottom.VSplitLeft(5.0f, &Button, &TB_Bottom);
2016-05-01 00:34:06 +00:00
}
2020-05-17 01:39:23 +00:00
// Brush draw mode button
{
TB_Bottom.VSplitLeft(65.0f, &Button, &TB_Bottom);
static int s_BrushDrawModeButton = 0;
if(DoButton_Editor(&s_BrushDrawModeButton, "Destructive", m_BrushDrawDestructive, &Button, 0, "[ctrl+d] Toggle brush draw mode") ||
(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_D) && ModPressed && !ShiftPressed))
2020-05-17 01:39:23 +00:00
m_BrushDrawDestructive = !m_BrushDrawDestructive;
TB_Bottom.VSplitLeft(5.0f, &Button, &TB_Bottom);
}
2020-05-15 16:51:14 +00:00
}
2007-05-22 15:03:32 +00:00
}
static void Rotate(const CPoint *pCenter, CPoint *pPoint, float Rotation)
2007-07-15 13:25:10 +00:00
{
2010-05-29 07:25:38 +00:00
int x = pPoint->x - pCenter->x;
int y = pPoint->y - pCenter->y;
pPoint->x = (int)(x * std::cos(Rotation) - y * std::sin(Rotation) + pCenter->x);
pPoint->y = (int)(x * std::sin(Rotation) + y * std::cos(Rotation) + pCenter->y);
2007-07-15 13:25:10 +00:00
}
void CEditor::DoSoundSource(CSoundSource *pSource, int Index)
{
enum
{
OP_NONE = 0,
OP_MOVE,
OP_CONTEXT_MENU,
};
void *pID = &pSource->m_Position;
static int s_Operation = OP_NONE;
float wx = UI()->MouseWorldX();
float wy = UI()->MouseWorldY();
float CenterX = fx2f(pSource->m_Position.x);
float CenterY = fx2f(pSource->m_Position.y);
float dx = (CenterX - wx) / m_MouseWScale;
float dy = (CenterY - wy) / m_MouseWScale;
if(dx * dx + dy * dy < 50)
UI()->SetHotItem(pID);
const bool IgnoreGrid = Input()->AltIsPressed();
if(UI()->CheckActiveItem(pID))
{
if(m_MouseDeltaWx * m_MouseDeltaWx + m_MouseDeltaWy * m_MouseDeltaWy > 0.0f)
{
if(s_Operation == OP_MOVE)
{
float x = wx;
float y = wy;
if(m_GridActive && !IgnoreGrid)
SnapToGrid(x, y);
pSource->m_Position.x = f2fx(x);
pSource->m_Position.y = f2fx(y);
}
}
if(s_Operation == OP_CONTEXT_MENU)
{
if(!UI()->MouseButton(1))
{
if(m_vSelectedLayers.size() == 1)
{
static SPopupMenuId s_PopupSourceId;
UI()->DoPopupMenu(&s_PopupSourceId, UI()->MouseX(), UI()->MouseY(), 120, 200, this, PopupSource);
UI()->DisableMouseLock();
}
s_Operation = OP_NONE;
UI()->SetActiveItem(nullptr);
}
}
else
{
if(!UI()->MouseButton(0))
{
UI()->DisableMouseLock();
s_Operation = OP_NONE;
UI()->SetActiveItem(nullptr);
}
}
Graphics()->SetColor(1, 1, 1, 1);
}
else if(UI()->HotItem() == pID)
{
ms_pUiGotContext = pID;
Graphics()->SetColor(1, 1, 1, 1);
m_pTooltip = "Left mouse button to move. Hold alt to ignore grid.";
if(UI()->MouseButton(0))
{
s_Operation = OP_MOVE;
UI()->SetActiveItem(pID);
m_SelectedSource = Index;
}
if(UI()->MouseButton(1))
{
m_SelectedSource = Index;
s_Operation = OP_CONTEXT_MENU;
UI()->SetActiveItem(pID);
}
}
else
{
Graphics()->SetColor(0, 1, 0, 1);
}
IGraphics::CQuadItem QuadItem(CenterX, CenterY, 5.0f * m_MouseWScale, 5.0f * m_MouseWScale);
Graphics()->QuadsDraw(&QuadItem, 1);
}
void CEditor::DoQuad(CQuad *pQuad, int Index)
2007-05-22 15:03:32 +00:00
{
2008-01-12 12:27:55 +00:00
enum
{
OP_NONE = 0,
2008-01-12 12:27:55 +00:00
OP_MOVE_ALL,
OP_MOVE_PIVOT,
OP_ROTATE,
2008-01-17 23:09:49 +00:00
OP_CONTEXT_MENU,
OP_DELETE,
2008-01-12 12:27:55 +00:00
};
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
// some basic values
void *pID = &pQuad->m_aPoints[4]; // use pivot addr as id
2022-06-15 17:34:41 +00:00
static std::vector<std::vector<CPoint>> s_vvRotatePoints;
2010-05-29 07:25:38 +00:00
static int s_Operation = OP_NONE;
static float s_RotateAngle = 0;
2009-10-27 14:38:53 +00:00
float wx = UI()->MouseWorldX();
float wy = UI()->MouseWorldY();
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
// get pivot
float CenterX = fx2f(pQuad->m_aPoints[4].x);
float CenterY = fx2f(pQuad->m_aPoints[4].y);
2008-01-12 12:27:55 +00:00
float dx = (CenterX - wx) / m_MouseWScale;
float dy = (CenterY - wy) / m_MouseWScale;
if(dx * dx + dy * dy < 50)
UI()->SetHotItem(pID);
2008-01-12 12:27:55 +00:00
const bool IgnoreGrid = Input()->AltIsPressed();
2010-05-29 07:25:38 +00:00
// draw selection background
2018-08-13 09:11:56 +00:00
if(IsQuadSelected(Index))
2007-05-22 15:03:32 +00:00
{
Graphics()->SetColor(0, 0, 0, 1);
IGraphics::CQuadItem QuadItem(CenterX, CenterY, 7.0f * m_MouseWScale, 7.0f * m_MouseWScale);
2010-05-29 07:25:38 +00:00
Graphics()->QuadsDraw(&QuadItem, 1);
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
if(UI()->CheckActiveItem(pID))
2007-05-22 15:03:32 +00:00
{
if(m_MouseDeltaWx * m_MouseDeltaWx + m_MouseDeltaWy * m_MouseDeltaWy > 0.0f)
2008-01-12 12:27:55 +00:00
{
// check if we only should move pivot
if(s_Operation == OP_MOVE_PIVOT)
2008-01-12 12:27:55 +00:00
{
float x = wx;
float y = wy;
if(m_GridActive && !IgnoreGrid)
SnapToGrid(x, y);
pQuad->m_aPoints[4].x = f2fx(x);
pQuad->m_aPoints[4].y = f2fx(y);
2011-07-10 20:16:16 +00:00
}
else if(s_Operation == OP_MOVE_ALL)
2008-01-12 12:27:55 +00:00
{
// move all points including pivot
float x = wx;
float y = wy;
if(m_GridActive && !IgnoreGrid)
SnapToGrid(x, y);
2011-08-11 08:59:14 +00:00
int OffsetX = f2fx(x) - pQuad->m_aPoints[4].x;
int OffsetY = f2fx(y) - pQuad->m_aPoints[4].y;
2011-08-11 08:59:14 +00:00
CLayerQuads *pLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
for(auto &Selected : m_vSelectedQuads)
2011-07-10 20:16:16 +00:00
{
CQuad *pCurrentQuad = &pLayer->m_vQuads[Selected];
for(auto &Point : pCurrentQuad->m_aPoints)
{
Point.x += OffsetX;
Point.y += OffsetY;
}
2011-07-10 20:16:16 +00:00
}
2008-01-12 12:27:55 +00:00
}
else if(s_Operation == OP_ROTATE)
2008-01-12 12:27:55 +00:00
{
2018-08-13 09:11:56 +00:00
CLayerQuads *pLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
for(size_t i = 0; i < m_vSelectedQuads.size(); ++i)
{
CQuad *pCurrentQuad = &pLayer->m_vQuads[m_vSelectedQuads[i]];
2018-08-13 09:11:56 +00:00
for(int v = 0; v < 4; v++)
{
2022-06-15 17:34:41 +00:00
pCurrentQuad->m_aPoints[v] = s_vvRotatePoints[i][v];
2018-08-13 09:11:56 +00:00
Rotate(&pCurrentQuad->m_aPoints[4], &pCurrentQuad->m_aPoints[v], s_RotateAngle);
}
}
2008-01-12 12:27:55 +00:00
}
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
s_RotateAngle += (m_MouseDeltaX)*0.002f;
2010-05-29 07:25:38 +00:00
if(s_Operation == OP_CONTEXT_MENU)
2007-05-22 15:03:32 +00:00
{
2009-10-27 14:38:53 +00:00
if(!UI()->MouseButton(1))
2008-01-17 23:09:49 +00:00
{
if(m_vSelectedLayers.size() == 1)
{
2018-08-13 09:11:56 +00:00
m_SelectedQuadIndex = FindSelectedQuadIndex(Index);
static SPopupMenuId s_PopupQuadId;
UI()->DoPopupMenu(&s_PopupQuadId, UI()->MouseX(), UI()->MouseY(), 120, 198, this, PopupQuad);
UI()->DisableMouseLock();
}
2010-05-29 07:25:38 +00:00
s_Operation = OP_NONE;
UI()->SetActiveItem(nullptr);
2008-01-17 23:09:49 +00:00
}
2007-05-22 15:03:32 +00:00
}
else if(s_Operation == OP_DELETE)
{
if(!UI()->MouseButton(1))
{
if(m_vSelectedLayers.size() == 1)
{
UI()->DisableMouseLock();
m_Map.m_Modified = true;
2018-08-13 09:11:56 +00:00
DeleteSelectedQuads();
}
s_Operation = OP_NONE;
UI()->SetActiveItem(nullptr);
}
}
2008-01-17 23:09:49 +00:00
else
{
2009-10-27 14:38:53 +00:00
if(!UI()->MouseButton(0))
2008-01-17 23:09:49 +00:00
{
UI()->DisableMouseLock();
2010-05-29 07:25:38 +00:00
s_Operation = OP_NONE;
UI()->SetActiveItem(nullptr);
2008-01-17 23:09:49 +00:00
}
2010-05-29 07:25:38 +00:00
}
2008-01-12 12:27:55 +00:00
Graphics()->SetColor(1, 1, 1, 1);
2008-01-12 12:27:55 +00:00
}
else if(UI()->HotItem() == pID)
2008-01-12 12:27:55 +00:00
{
ms_pUiGotContext = pID;
2010-05-29 07:25:38 +00:00
Graphics()->SetColor(1, 1, 1, 1);
m_pTooltip = "Left mouse button to move. Hold shift to move pivot. Hold ctrl to rotate. Hold alt to ignore grid. Hold shift and right click to delete.";
2010-05-29 07:25:38 +00:00
2009-10-27 14:38:53 +00:00
if(UI()->MouseButton(0))
2008-01-12 12:27:55 +00:00
{
if(Input()->ShiftIsPressed())
2018-08-13 09:11:56 +00:00
{
2010-05-29 07:25:38 +00:00
s_Operation = OP_MOVE_PIVOT;
2018-08-13 09:11:56 +00:00
SelectQuad(Index);
}
else if(Input()->ModifierIsPressed())
2008-01-12 12:27:55 +00:00
{
UI()->EnableMouseLock(pID);
2010-05-29 07:25:38 +00:00
s_Operation = OP_ROTATE;
s_RotateAngle = 0;
2018-10-02 01:52:01 +00:00
2018-08-13 09:11:56 +00:00
if(!IsQuadSelected(Index))
SelectQuad(Index);
2018-10-02 01:52:01 +00:00
2018-08-13 09:11:56 +00:00
CLayerQuads *pLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
2022-06-15 17:34:41 +00:00
s_vvRotatePoints.clear();
s_vvRotatePoints.resize(m_vSelectedQuads.size());
for(size_t i = 0; i < m_vSelectedQuads.size(); ++i)
2018-08-13 09:11:56 +00:00
{
CQuad *pCurrentQuad = &pLayer->m_vQuads[m_vSelectedQuads[i]];
2018-08-13 09:11:56 +00:00
2022-06-15 17:34:41 +00:00
s_vvRotatePoints[i].resize(4);
s_vvRotatePoints[i][0] = pCurrentQuad->m_aPoints[0];
s_vvRotatePoints[i][1] = pCurrentQuad->m_aPoints[1];
s_vvRotatePoints[i][2] = pCurrentQuad->m_aPoints[2];
s_vvRotatePoints[i][3] = pCurrentQuad->m_aPoints[3];
2018-08-13 09:11:56 +00:00
}
2008-01-12 12:27:55 +00:00
}
else
2018-08-13 09:11:56 +00:00
{
2010-05-29 07:25:38 +00:00
s_Operation = OP_MOVE_ALL;
2018-10-02 01:52:01 +00:00
2018-08-13 09:11:56 +00:00
if(!IsQuadSelected(Index))
SelectQuad(Index);
}
2010-05-29 07:25:38 +00:00
UI()->SetActiveItem(pID);
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
2009-10-27 14:38:53 +00:00
if(UI()->MouseButton(1))
2008-01-17 23:09:49 +00:00
{
if(Input()->ShiftIsPressed())
{
s_Operation = OP_DELETE;
2018-08-13 09:11:56 +00:00
if(!IsQuadSelected(Index))
SelectQuad(Index);
UI()->SetActiveItem(pID);
}
else
{
s_Operation = OP_CONTEXT_MENU;
2018-08-13 09:11:56 +00:00
if(!IsQuadSelected(Index))
SelectQuad(Index);
UI()->SetActiveItem(pID);
}
2008-01-17 23:09:49 +00:00
}
2007-05-22 15:03:32 +00:00
}
2008-01-12 12:27:55 +00:00
else
Graphics()->SetColor(0, 1, 0, 1);
2008-01-12 12:27:55 +00:00
IGraphics::CQuadItem QuadItem(CenterX, CenterY, 5.0f * m_MouseWScale, 5.0f * m_MouseWScale);
2010-05-29 07:25:38 +00:00
Graphics()->QuadsDraw(&QuadItem, 1);
2008-01-12 12:27:55 +00:00
}
void CEditor::DoQuadPoint(CQuad *pQuad, int QuadIndex, int V)
2008-01-12 12:27:55 +00:00
{
void *pID = &pQuad->m_aPoints[V];
2008-01-12 12:27:55 +00:00
2009-10-27 14:38:53 +00:00
float wx = UI()->MouseWorldX();
float wy = UI()->MouseWorldY();
2010-05-29 07:25:38 +00:00
float px = fx2f(pQuad->m_aPoints[V].x);
float py = fx2f(pQuad->m_aPoints[V].y);
2010-05-29 07:25:38 +00:00
float dx = (px - wx) / m_MouseWScale;
float dy = (py - wy) / m_MouseWScale;
if(dx * dx + dy * dy < 50)
UI()->SetHotItem(pID);
2008-01-12 12:27:55 +00:00
2010-05-29 07:25:38 +00:00
// draw selection background
if(IsQuadSelected(QuadIndex) && m_SelectedPoints & (1 << V))
2008-01-12 12:27:55 +00:00
{
Graphics()->SetColor(0, 0, 0, 1);
IGraphics::CQuadItem QuadItem(px, py, 7.0f * m_MouseWScale, 7.0f * m_MouseWScale);
2010-05-29 07:25:38 +00:00
Graphics()->QuadsDraw(&QuadItem, 1);
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
enum
{
OP_NONE = 0,
2008-01-12 12:27:55 +00:00
OP_MOVEPOINT,
2008-01-17 23:09:49 +00:00
OP_MOVEUV,
OP_CONTEXT_MENU
2008-01-12 12:27:55 +00:00
};
2010-05-29 07:25:38 +00:00
static bool s_Moved;
static int s_Operation = OP_NONE;
const bool IgnoreGrid = Input()->AltIsPressed();
if(UI()->CheckActiveItem(pID))
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
if(!s_Moved)
2007-05-22 15:03:32 +00:00
{
if(m_MouseDeltaWx * m_MouseDeltaWx + m_MouseDeltaWy * m_MouseDeltaWy > 0.0f)
2010-05-29 07:25:38 +00:00
s_Moved = true;
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
if(s_Moved)
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
if(s_Operation == OP_MOVEPOINT)
2007-05-22 15:03:32 +00:00
{
float x = wx;
float y = wy;
if(m_GridActive && !IgnoreGrid)
SnapToGrid(x, y);
2011-07-10 20:16:16 +00:00
int OffsetX = f2fx(x) - pQuad->m_aPoints[V].x;
int OffsetY = f2fx(y) - pQuad->m_aPoints[V].y;
2018-08-13 09:11:56 +00:00
CLayerQuads *pLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
for(auto &Selected : m_vSelectedQuads)
2011-07-10 20:16:16 +00:00
{
CQuad *pCurrentQuad = &pLayer->m_vQuads[Selected];
for(int m = 0; m < 4; m++)
2018-08-13 09:11:56 +00:00
{
if(m_SelectedPoints & (1 << m))
{
pCurrentQuad->m_aPoints[m].x += OffsetX;
pCurrentQuad->m_aPoints[m].y += OffsetY;
}
2018-08-13 09:11:56 +00:00
}
2011-07-10 20:16:16 +00:00
}
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
else if(s_Operation == OP_MOVEUV)
2008-01-12 12:27:55 +00:00
{
2018-08-13 09:11:56 +00:00
CLayerQuads *pLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
for(auto &Selected : m_vSelectedQuads)
2018-08-13 09:11:56 +00:00
{
CQuad *pCurrentQuad = &pLayer->m_vQuads[Selected];
2018-08-13 09:11:56 +00:00
for(int m = 0; m < 4; m++)
if(m_SelectedPoints & (1 << m))
2018-08-13 09:11:56 +00:00
{
// 0,2;1,3 - line x
// 0,1;2,3 - line y
pCurrentQuad->m_aTexcoords[m].x += f2fx(m_MouseDeltaWx * 0.001f);
pCurrentQuad->m_aTexcoords[(m + 2) % 4].x += f2fx(m_MouseDeltaWx * 0.001f);
2011-08-11 08:59:14 +00:00
pCurrentQuad->m_aTexcoords[m].y += f2fx(m_MouseDeltaWy * 0.001f);
pCurrentQuad->m_aTexcoords[m ^ 1].y += f2fx(m_MouseDeltaWy * 0.001f);
2018-08-13 09:11:56 +00:00
}
}
2007-05-22 15:03:32 +00:00
}
}
2010-05-29 07:25:38 +00:00
if(s_Operation == OP_CONTEXT_MENU)
2007-05-22 15:03:32 +00:00
{
2009-10-27 14:38:53 +00:00
if(!UI()->MouseButton(1))
2007-05-22 15:03:32 +00:00
{
if(m_vSelectedLayers.size() == 1)
{
2018-08-13 09:11:56 +00:00
m_SelectedQuadPoint = V;
m_SelectedQuadIndex = FindSelectedQuadIndex(QuadIndex);
static SPopupMenuId s_PopupPointId;
UI()->DoPopupMenu(&s_PopupPointId, UI()->MouseX(), UI()->MouseY(), 120, 150, this, PopupPoint);
}
UI()->SetActiveItem(nullptr);
2008-01-17 23:09:49 +00:00
}
}
else
{
2009-10-27 14:38:53 +00:00
if(!UI()->MouseButton(0))
2008-01-17 23:09:49 +00:00
{
2010-05-29 07:25:38 +00:00
if(!s_Moved)
2008-01-17 23:09:49 +00:00
{
if(Input()->ShiftIsPressed())
m_SelectedPoints ^= 1 << V;
2008-01-17 23:09:49 +00:00
else
m_SelectedPoints = 1 << V;
2008-01-17 23:09:49 +00:00
}
2014-01-19 17:06:56 +00:00
UI()->DisableMouseLock();
UI()->SetActiveItem(nullptr);
2007-05-22 15:03:32 +00:00
}
}
2008-01-12 12:27:55 +00:00
Graphics()->SetColor(1, 1, 1, 1);
2007-05-22 15:03:32 +00:00
}
else if(UI()->HotItem() == pID)
2008-01-12 12:27:55 +00:00
{
ms_pUiGotContext = pID;
2010-05-29 07:25:38 +00:00
Graphics()->SetColor(1, 1, 1, 1);
m_pTooltip = "Left mouse button to move. Hold shift to move the texture. Hold alt to ignore grid.";
2010-05-29 07:25:38 +00:00
2009-10-27 14:38:53 +00:00
if(UI()->MouseButton(0))
2008-01-12 12:27:55 +00:00
{
UI()->SetActiveItem(pID);
2010-05-29 07:25:38 +00:00
s_Moved = false;
if(Input()->ShiftIsPressed())
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
s_Operation = OP_MOVEUV;
UI()->EnableMouseLock(pID);
2008-01-12 12:27:55 +00:00
}
else
2010-05-29 07:25:38 +00:00
s_Operation = OP_MOVEPOINT;
if(!(m_SelectedPoints & (1 << V)))
2008-01-12 12:27:55 +00:00
{
if(Input()->ShiftIsPressed())
m_SelectedPoints |= 1 << V;
2008-01-12 12:27:55 +00:00
else
m_SelectedPoints = 1 << V;
2011-11-26 00:44:24 +00:00
s_Moved = true;
2008-01-12 12:27:55 +00:00
}
2018-10-02 01:52:01 +00:00
2018-08-13 09:11:56 +00:00
if(!IsQuadSelected(QuadIndex))
SelectQuad(QuadIndex);
2008-01-17 23:09:49 +00:00
}
2009-10-27 14:38:53 +00:00
else if(UI()->MouseButton(1))
2008-01-17 23:09:49 +00:00
{
2010-05-29 07:25:38 +00:00
s_Operation = OP_CONTEXT_MENU;
2018-08-13 09:11:56 +00:00
if(!IsQuadSelected(QuadIndex))
SelectQuad(QuadIndex);
UI()->SetActiveItem(pID);
if(!(m_SelectedPoints & (1 << V)))
{
if(Input()->ShiftIsPressed())
m_SelectedPoints |= 1 << V;
else
m_SelectedPoints = 1 << V;
s_Moved = true;
}
2008-01-12 12:27:55 +00:00
}
}
else
Graphics()->SetColor(1, 0, 0, 1);
2010-05-29 07:25:38 +00:00
IGraphics::CQuadItem QuadItem(px, py, 5.0f * m_MouseWScale, 5.0f * m_MouseWScale);
2010-05-29 07:25:38 +00:00
Graphics()->QuadsDraw(&QuadItem, 1);
2007-05-22 15:03:32 +00:00
}
2022-02-26 17:49:06 +00:00
float CEditor::TriangleArea(vec2 A, vec2 B, vec2 C)
{
return absolute(((B.x - A.x) * (C.y - A.y) - (C.x - A.x) * (B.y - A.y)) * 0.5f);
2022-02-26 17:49:06 +00:00
}
bool CEditor::IsInTriangle(vec2 Point, vec2 A, vec2 B, vec2 C)
{
// Normalize to increase precision
2022-02-26 23:44:34 +00:00
vec2 Min(minimum(A.x, B.x, C.x), minimum(A.y, B.y, C.y));
vec2 Max(maximum(A.x, B.x, C.x), maximum(A.y, B.y, C.y));
2022-02-26 17:49:06 +00:00
vec2 Size(Max.x - Min.x, Max.y - Min.y);
2022-02-26 23:44:34 +00:00
if(Size.x < 0.0000001f || Size.y < 0.0000001f)
2022-02-26 17:49:06 +00:00
return false;
vec2 Normal(1.f / Size.x, 1.f / Size.y);
A = (A - Min) * Normal;
B = (B - Min) * Normal;
C = (C - Min) * Normal;
Point = (Point - Min) * Normal;
float Area = TriangleArea(A, B, C);
return Area > 0.f && absolute(TriangleArea(Point, A, B) + TriangleArea(Point, B, C) + TriangleArea(Point, C, A) - Area) < 0.000001f;
2022-02-26 17:49:06 +00:00
}
void CEditor::DoQuadKnife(int QuadIndex)
{
CLayerQuads *pLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
CQuad *pQuad = &pLayer->m_vQuads[QuadIndex];
2022-02-26 17:49:06 +00:00
const bool IgnoreGrid = Input()->AltIsPressed();
float SnapRadius = 4.f * m_MouseWScale;
2022-02-26 17:49:06 +00:00
vec2 Mouse = vec2(UI()->MouseWorldX(), UI()->MouseWorldY());
vec2 Point = Mouse;
vec2 v[4] = {
vec2(fx2f(pQuad->m_aPoints[0].x), fx2f(pQuad->m_aPoints[0].y)),
vec2(fx2f(pQuad->m_aPoints[1].x), fx2f(pQuad->m_aPoints[1].y)),
vec2(fx2f(pQuad->m_aPoints[3].x), fx2f(pQuad->m_aPoints[3].y)),
vec2(fx2f(pQuad->m_aPoints[2].x), fx2f(pQuad->m_aPoints[2].y))};
m_pTooltip = "Left click inside the quad to select an area to slice. Hold alt to ignore grid. Right click to leave knife mode";
if(UI()->MouseButtonClicked(1))
{
m_QuadKnifeActive = false;
return;
}
2022-03-01 10:33:53 +00:00
2022-02-26 17:49:06 +00:00
// Handle snapping
if(m_GridActive && !IgnoreGrid)
{
float CellSize = (float)GetLineDistance();
vec2 OnGrid = vec2(std::round(Mouse.x / CellSize) * CellSize, std::round(Mouse.y / CellSize) * CellSize);
2022-02-26 17:49:06 +00:00
2022-03-01 10:33:53 +00:00
if(IsInTriangle(OnGrid, v[0], v[1], v[2]) || IsInTriangle(OnGrid, v[0], v[3], v[2]))
2022-02-26 17:49:06 +00:00
Point = OnGrid;
else
{
float MinDistance = -1.f;
for(int i = 0; i < 4; i++)
{
int j = (i + 1) % 4;
vec2 Min(minimum(v[i].x, v[j].x), minimum(v[i].y, v[j].y));
vec2 Max(maximum(v[i].x, v[j].x), maximum(v[i].y, v[j].y));
2022-02-26 23:44:34 +00:00
if(in_range(OnGrid.y, Min.y, Max.y) && Max.y - Min.y > 0.0000001f)
2022-02-26 17:49:06 +00:00
{
vec2 OnEdge(v[i].x + (OnGrid.y - v[i].y) / (v[j].y - v[i].y) * (v[j].x - v[i].x), OnGrid.y);
float Distance = absolute(OnGrid.x - OnEdge.x);
2022-02-26 17:49:06 +00:00
if(Distance < CellSize && (Distance < MinDistance || MinDistance < 0.f))
{
MinDistance = Distance;
Point = OnEdge;
}
}
2022-03-01 10:33:53 +00:00
2022-02-26 23:44:34 +00:00
if(in_range(OnGrid.x, Min.x, Max.x) && Max.x - Min.x > 0.0000001f)
2022-02-26 17:49:06 +00:00
{
vec2 OnEdge(OnGrid.x, v[i].y + (OnGrid.x - v[i].x) / (v[j].x - v[i].x) * (v[j].y - v[i].y));
float Distance = absolute(OnGrid.y - OnEdge.y);
2022-02-26 17:49:06 +00:00
if(Distance < CellSize && (Distance < MinDistance || MinDistance < 0.f))
{
MinDistance = Distance;
Point = OnEdge;
}
}
}
}
}
else
{
float MinDistance = -1.f;
// Try snapping to corners
2022-03-01 10:33:53 +00:00
for(const auto &x : v)
2022-02-26 17:49:06 +00:00
{
2022-03-01 10:33:53 +00:00
float Distance = distance(Mouse, x);
2022-02-26 17:49:06 +00:00
if(Distance <= SnapRadius && (Distance < MinDistance || MinDistance < 0.f))
{
MinDistance = Distance;
2022-03-01 10:33:53 +00:00
Point = x;
2022-02-26 17:49:06 +00:00
}
}
2022-03-01 10:33:53 +00:00
if(MinDistance < 0.f)
2022-02-26 17:49:06 +00:00
{
// Try snapping to edges
for(int i = 0; i < 4; i++)
{
int j = (i + 1) % 4;
vec2 s(v[j] - v[i]);
float t = ((Mouse.x - v[i].x) * s.x + (Mouse.y - v[i].y) * s.y) / (s.x * s.x + s.y * s.y);
if(in_range(t, 0.f, 1.f))
{
vec2 OnEdge = vec2((v[i].x + t * s.x), (v[i].y + t * s.y));
float Distance = distance(Mouse, OnEdge);
if(Distance <= SnapRadius && (Distance < MinDistance || MinDistance < 0.f))
{
MinDistance = Distance;
Point = OnEdge;
}
}
}
}
}
bool ValidPosition = IsInTriangle(Point, v[0], v[1], v[2]) || IsInTriangle(Point, v[0], v[3], v[2]);
2022-03-01 10:33:53 +00:00
if(UI()->MouseButtonClicked(0) && ValidPosition)
2022-02-26 23:44:34 +00:00
{
m_aQuadKnifePoints[m_QuadKnifeCount] = Point;
m_QuadKnifeCount++;
}
2022-02-26 17:49:06 +00:00
if(m_QuadKnifeCount == 4)
{
if(IsInTriangle(m_aQuadKnifePoints[3], m_aQuadKnifePoints[0], m_aQuadKnifePoints[1], m_aQuadKnifePoints[2]) ||
IsInTriangle(m_aQuadKnifePoints[1], m_aQuadKnifePoints[0], m_aQuadKnifePoints[2], m_aQuadKnifePoints[3]))
{
// Fix concave order
2022-05-15 17:25:36 +00:00
std::swap(m_aQuadKnifePoints[0], m_aQuadKnifePoints[3]);
std::swap(m_aQuadKnifePoints[1], m_aQuadKnifePoints[2]);
2022-02-26 17:49:06 +00:00
}
2022-05-15 17:25:36 +00:00
std::swap(m_aQuadKnifePoints[2], m_aQuadKnifePoints[3]);
2022-02-26 17:49:06 +00:00
CQuad *pResult = pLayer->NewQuad(64, 64, 64, 64);
pQuad = &pLayer->m_vQuads[QuadIndex];
2022-02-26 17:49:06 +00:00
for(int i = 0; i < 4; i++)
{
int t = IsInTriangle(m_aQuadKnifePoints[i], v[0], v[3], v[2]) ? 2 : 1;
2022-03-01 10:33:53 +00:00
2022-02-26 17:49:06 +00:00
vec2 A = vec2(fx2f(pQuad->m_aPoints[0].x), fx2f(pQuad->m_aPoints[0].y));
vec2 B = vec2(fx2f(pQuad->m_aPoints[3].x), fx2f(pQuad->m_aPoints[3].y));
vec2 C = vec2(fx2f(pQuad->m_aPoints[t].x), fx2f(pQuad->m_aPoints[t].y));
float TriArea = TriangleArea(A, B, C);
float WeightA = TriangleArea(m_aQuadKnifePoints[i], B, C) / TriArea;
float WeightB = TriangleArea(m_aQuadKnifePoints[i], C, A) / TriArea;
float WeightC = TriangleArea(m_aQuadKnifePoints[i], A, B) / TriArea;
pResult->m_aColors[i].r = (int)std::round(pQuad->m_aColors[0].r * WeightA + pQuad->m_aColors[3].r * WeightB + pQuad->m_aColors[t].r * WeightC);
pResult->m_aColors[i].g = (int)std::round(pQuad->m_aColors[0].g * WeightA + pQuad->m_aColors[3].g * WeightB + pQuad->m_aColors[t].g * WeightC);
pResult->m_aColors[i].b = (int)std::round(pQuad->m_aColors[0].b * WeightA + pQuad->m_aColors[3].b * WeightB + pQuad->m_aColors[t].b * WeightC);
pResult->m_aColors[i].a = (int)std::round(pQuad->m_aColors[0].a * WeightA + pQuad->m_aColors[3].a * WeightB + pQuad->m_aColors[t].a * WeightC);
2022-02-26 17:49:06 +00:00
pResult->m_aTexcoords[i].x = (int)std::round(pQuad->m_aTexcoords[0].x * WeightA + pQuad->m_aTexcoords[3].x * WeightB + pQuad->m_aTexcoords[t].x * WeightC);
pResult->m_aTexcoords[i].y = (int)std::round(pQuad->m_aTexcoords[0].y * WeightA + pQuad->m_aTexcoords[3].y * WeightB + pQuad->m_aTexcoords[t].y * WeightC);
2022-02-26 17:49:06 +00:00
pResult->m_aPoints[i].x = f2fx(m_aQuadKnifePoints[i].x);
pResult->m_aPoints[i].y = f2fx(m_aQuadKnifePoints[i].y);
}
pResult->m_aPoints[4].x = ((pResult->m_aPoints[0].x + pResult->m_aPoints[3].x) / 2 + (pResult->m_aPoints[1].x + pResult->m_aPoints[2].x) / 2) / 2;
pResult->m_aPoints[4].y = ((pResult->m_aPoints[0].y + pResult->m_aPoints[3].y) / 2 + (pResult->m_aPoints[1].y + pResult->m_aPoints[2].y) / 2) / 2;
m_QuadKnifeCount = 0;
}
// Render
2022-02-28 22:45:57 +00:00
Graphics()->TextureClear();
2022-03-01 10:33:53 +00:00
Graphics()->LinesBegin();
2022-02-28 22:45:57 +00:00
2022-02-26 17:49:06 +00:00
IGraphics::CLineItem aEdges[4] = {
IGraphics::CLineItem(v[0].x, v[0].y, v[1].x, v[1].y),
IGraphics::CLineItem(v[1].x, v[1].y, v[2].x, v[2].y),
IGraphics::CLineItem(v[2].x, v[2].y, v[3].x, v[3].y),
IGraphics::CLineItem(v[3].x, v[3].y, v[0].x, v[0].y)};
2022-02-28 22:45:57 +00:00
Graphics()->SetColor(1.f, 0.5f, 0.f, 1.f);
Graphics()->LinesDraw(aEdges, 4);
2022-02-26 17:49:06 +00:00
IGraphics::CLineItem aLines[4];
int LineCount = maximum(m_QuadKnifeCount - 1, 0);
for(int i = 0; i < LineCount; i++)
aLines[i] = IGraphics::CLineItem(m_aQuadKnifePoints[i].x, m_aQuadKnifePoints[i].y, m_aQuadKnifePoints[i + 1].x, m_aQuadKnifePoints[i + 1].y);
2022-02-28 22:45:57 +00:00
Graphics()->SetColor(1.f, 1.f, 1.f, 1.f);
Graphics()->LinesDraw(aLines, LineCount);
2022-02-26 17:49:06 +00:00
if(ValidPosition)
{
if(m_QuadKnifeCount > 0)
2022-02-26 23:44:34 +00:00
{
2022-02-28 22:45:57 +00:00
IGraphics::CLineItem LineCurrent(Point.x, Point.y, m_aQuadKnifePoints[m_QuadKnifeCount - 1].x, m_aQuadKnifePoints[m_QuadKnifeCount - 1].y);
Graphics()->LinesDraw(&LineCurrent, 1);
2022-02-26 23:44:34 +00:00
}
2022-02-26 17:49:06 +00:00
2022-02-28 22:45:57 +00:00
if(m_QuadKnifeCount == 3)
2022-02-26 23:44:34 +00:00
{
2022-02-28 22:45:57 +00:00
IGraphics::CLineItem LineClose(Point.x, Point.y, m_aQuadKnifePoints[0].x, m_aQuadKnifePoints[0].y);
Graphics()->LinesDraw(&LineClose, 1);
2022-02-26 23:44:34 +00:00
}
2022-02-26 17:49:06 +00:00
}
Graphics()->LinesEnd();
Graphics()->QuadsBegin();
2022-02-28 22:45:57 +00:00
IGraphics::CQuadItem aMarkers[4];
for(int i = 0; i < m_QuadKnifeCount; i++)
aMarkers[i] = IGraphics::CQuadItem(m_aQuadKnifePoints[i].x, m_aQuadKnifePoints[i].y, 5.f * m_MouseWScale, 5.f * m_MouseWScale);
2022-02-28 22:45:57 +00:00
2022-02-26 17:49:06 +00:00
Graphics()->SetColor(0.f, 0.f, 1.f, 1.f);
2022-02-28 22:45:57 +00:00
Graphics()->QuadsDraw(aMarkers, m_QuadKnifeCount);
if(ValidPosition)
{
IGraphics::CQuadItem MarkerCurrent(Point.x, Point.y, 5.f * m_MouseWScale, 5.f * m_MouseWScale);
2022-02-28 22:45:57 +00:00
Graphics()->QuadsDraw(&MarkerCurrent, 1);
}
2022-03-01 10:33:53 +00:00
2022-02-26 17:49:06 +00:00
Graphics()->QuadsEnd();
}
void CEditor::DoQuadEnvelopes(const std::vector<CQuad> &vQuads, IGraphics::CTextureHandle Texture)
2011-08-15 18:12:31 +00:00
{
size_t Num = vQuads.size();
CEnvelope **apEnvelope = new CEnvelope *[Num];
mem_zero(apEnvelope, sizeof(CEnvelope *) * Num); // NOLINT(bugprone-sizeof-expression)
for(size_t i = 0; i < Num; i++)
{
if((m_ShowEnvelopePreview == SHOWENV_SELECTED && vQuads[i].m_PosEnv == m_SelectedEnvelope) || m_ShowEnvelopePreview == SHOWENV_ALL)
if(vQuads[i].m_PosEnv >= 0 && vQuads[i].m_PosEnv < (int)m_Map.m_vpEnvelopes.size())
apEnvelope[i] = m_Map.m_vpEnvelopes[vQuads[i].m_PosEnv];
}
2011-08-15 18:12:31 +00:00
//Draw Lines
Graphics()->TextureClear();
2011-08-15 18:12:31 +00:00
Graphics()->LinesBegin();
Graphics()->SetColor(80.0f / 255, 150.0f / 255, 230.f / 255, 0.5f);
for(size_t j = 0; j < Num; j++)
{
if(!apEnvelope[j])
continue;
//QuadParams
const CPoint *pPoints = vQuads[j].m_aPoints;
for(size_t i = 0; i < apEnvelope[j]->m_vPoints.size() - 1; i++)
2011-08-15 18:12:31 +00:00
{
float OffsetX = fx2f(apEnvelope[j]->m_vPoints[i].m_aValues[0]);
float OffsetY = fx2f(apEnvelope[j]->m_vPoints[i].m_aValues[1]);
vec2 Pos0 = vec2(fx2f(pPoints[4].x) + OffsetX, fx2f(pPoints[4].y) + OffsetY);
2011-08-15 18:12:31 +00:00
OffsetX = fx2f(apEnvelope[j]->m_vPoints[i + 1].m_aValues[0]);
OffsetY = fx2f(apEnvelope[j]->m_vPoints[i + 1].m_aValues[1]);
vec2 Pos1 = vec2(fx2f(pPoints[4].x) + OffsetX, fx2f(pPoints[4].y) + OffsetY);
2011-08-15 18:12:31 +00:00
IGraphics::CLineItem Line = IGraphics::CLineItem(Pos0.x, Pos0.y, Pos1.x, Pos1.y);
Graphics()->LinesDraw(&Line, 1);
}
}
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
2011-08-15 18:12:31 +00:00
Graphics()->LinesEnd();
//Draw Quads
Graphics()->TextureSet(Texture);
Graphics()->QuadsBegin();
2015-07-09 00:08:14 +00:00
for(size_t j = 0; j < Num; j++)
{
if(!apEnvelope[j])
continue;
//QuadParams
const CPoint *pPoints = vQuads[j].m_aPoints;
for(size_t i = 0; i < apEnvelope[j]->m_vPoints.size(); i++)
2011-08-15 18:12:31 +00:00
{
//Calc Env Position
float OffsetX = fx2f(apEnvelope[j]->m_vPoints[i].m_aValues[0]);
float OffsetY = fx2f(apEnvelope[j]->m_vPoints[i].m_aValues[1]);
float Rot = fx2f(apEnvelope[j]->m_vPoints[i].m_aValues[2]) / 360.0f * pi * 2;
//Set Colours
float Alpha = (m_SelectedQuadEnvelope == vQuads[j].m_PosEnv && m_SelectedEnvelopePoint == (int)i) ? 0.65f : 0.35f;
IGraphics::CColorVertex aArray[4] = {
IGraphics::CColorVertex(0, vQuads[j].m_aColors[0].r, vQuads[j].m_aColors[0].g, vQuads[j].m_aColors[0].b, Alpha),
IGraphics::CColorVertex(1, vQuads[j].m_aColors[1].r, vQuads[j].m_aColors[1].g, vQuads[j].m_aColors[1].b, Alpha),
IGraphics::CColorVertex(2, vQuads[j].m_aColors[2].r, vQuads[j].m_aColors[2].g, vQuads[j].m_aColors[2].b, Alpha),
IGraphics::CColorVertex(3, vQuads[j].m_aColors[3].r, vQuads[j].m_aColors[3].g, vQuads[j].m_aColors[3].b, Alpha)};
Graphics()->SetColorVertex(aArray, 4);
//Rotation
if(Rot != 0)
{
static CPoint aRotated[4];
aRotated[0] = vQuads[j].m_aPoints[0];
aRotated[1] = vQuads[j].m_aPoints[1];
aRotated[2] = vQuads[j].m_aPoints[2];
aRotated[3] = vQuads[j].m_aPoints[3];
pPoints = aRotated;
Rotate(&vQuads[j].m_aPoints[4], &aRotated[0], Rot);
Rotate(&vQuads[j].m_aPoints[4], &aRotated[1], Rot);
Rotate(&vQuads[j].m_aPoints[4], &aRotated[2], Rot);
Rotate(&vQuads[j].m_aPoints[4], &aRotated[3], Rot);
}
//Set Texture Coords
Graphics()->QuadsSetSubsetFree(
fx2f(vQuads[j].m_aTexcoords[0].x), fx2f(vQuads[j].m_aTexcoords[0].y),
fx2f(vQuads[j].m_aTexcoords[1].x), fx2f(vQuads[j].m_aTexcoords[1].y),
fx2f(vQuads[j].m_aTexcoords[2].x), fx2f(vQuads[j].m_aTexcoords[2].y),
fx2f(vQuads[j].m_aTexcoords[3].x), fx2f(vQuads[j].m_aTexcoords[3].y));
//Set Quad Coords & Draw
IGraphics::CFreeformItem Freeform(
fx2f(pPoints[0].x) + OffsetX, fx2f(pPoints[0].y) + OffsetY,
fx2f(pPoints[1].x) + OffsetX, fx2f(pPoints[1].y) + OffsetY,
fx2f(pPoints[2].x) + OffsetX, fx2f(pPoints[2].y) + OffsetY,
fx2f(pPoints[3].x) + OffsetX, fx2f(pPoints[3].y) + OffsetY);
Graphics()->QuadsDrawFreeform(&Freeform, 1);
2011-08-15 18:12:31 +00:00
}
}
Graphics()->QuadsEnd();
Graphics()->TextureClear();
Graphics()->QuadsBegin();
2011-08-15 18:12:31 +00:00
// Draw QuadPoints
for(size_t j = 0; j < Num; j++)
{
if(!apEnvelope[j])
continue;
for(size_t i = 0; i < apEnvelope[j]->m_vPoints.size(); i++)
DoQuadEnvPoint(&vQuads[j], j, i);
2011-08-15 18:12:31 +00:00
}
Graphics()->QuadsEnd();
delete[] apEnvelope;
2011-08-14 14:31:48 +00:00
}
2011-08-15 18:12:31 +00:00
void CEditor::DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int PIndex)
2011-08-14 14:31:48 +00:00
{
enum
{
OP_NONE = 0,
2011-08-15 18:12:31 +00:00
OP_MOVE,
OP_ROTATE,
2011-08-14 14:31:48 +00:00
};
// some basic values
static float s_LastWx = 0;
static float s_LastWy = 0;
2011-08-14 14:31:48 +00:00
static int s_Operation = OP_NONE;
float wx = UI()->MouseWorldX();
2011-08-15 18:12:31 +00:00
float wy = UI()->MouseWorldY();
CEnvelope *pEnvelope = m_Map.m_vpEnvelopes[pQuad->m_PosEnv];
void *pID = &pEnvelope->m_vPoints[PIndex];
static int s_CurQIndex = -1;
2011-08-14 14:31:48 +00:00
// get pivot
float CenterX = fx2f(pQuad->m_aPoints[4].x) + fx2f(pEnvelope->m_vPoints[PIndex].m_aValues[0]);
float CenterY = fx2f(pQuad->m_aPoints[4].y) + fx2f(pEnvelope->m_vPoints[PIndex].m_aValues[1]);
2011-08-14 14:31:48 +00:00
float dx = (CenterX - wx) / m_MouseWScale;
float dy = (CenterY - wy) / m_MouseWScale;
if(dx * dx + dy * dy < 50.0f && UI()->CheckActiveItem(nullptr))
{
2011-08-14 14:31:48 +00:00
UI()->SetHotItem(pID);
s_CurQIndex = QIndex;
}
2011-08-14 14:31:48 +00:00
const bool IgnoreGrid = Input()->AltIsPressed();
if(UI()->CheckActiveItem(pID) && s_CurQIndex == QIndex)
2011-08-14 14:31:48 +00:00
{
2011-08-15 18:12:31 +00:00
if(s_Operation == OP_MOVE)
2011-08-14 14:31:48 +00:00
{
if(m_GridActive && !IgnoreGrid)
2011-08-15 18:12:31 +00:00
{
float x = wx;
float y = wy;
SnapToGrid(x, y);
pEnvelope->m_vPoints[PIndex].m_aValues[0] = f2fx(x) - pQuad->m_aPoints[4].x;
pEnvelope->m_vPoints[PIndex].m_aValues[1] = f2fx(y) - pQuad->m_aPoints[4].y;
2011-08-15 18:12:31 +00:00
}
else
{
pEnvelope->m_vPoints[PIndex].m_aValues[0] += f2fx(wx - s_LastWx);
pEnvelope->m_vPoints[PIndex].m_aValues[1] += f2fx(wy - s_LastWy);
2011-08-15 18:12:31 +00:00
}
2011-08-14 14:31:48 +00:00
}
2011-08-15 18:12:31 +00:00
else if(s_Operation == OP_ROTATE)
pEnvelope->m_vPoints[PIndex].m_aValues[2] += 10 * m_MouseDeltaX;
2011-08-14 14:31:48 +00:00
s_LastWx = wx;
s_LastWy = wy;
2011-08-15 18:12:31 +00:00
if(!UI()->MouseButton(0))
{
UI()->DisableMouseLock();
2011-08-15 18:12:31 +00:00
s_Operation = OP_NONE;
UI()->SetActiveItem(nullptr);
2011-08-14 14:31:48 +00:00
}
2011-08-15 18:12:31 +00:00
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
2011-08-14 14:31:48 +00:00
}
else if(UI()->HotItem() == pID && s_CurQIndex == QIndex)
2011-08-14 14:31:48 +00:00
{
ms_pUiGotContext = pID;
2011-08-15 18:12:31 +00:00
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
m_pTooltip = "Left mouse button to move. Hold ctrl to rotate. Hold alt to ignore grid.";
2011-08-14 14:31:48 +00:00
if(UI()->MouseButton(0))
{
if(Input()->ModifierIsPressed())
2011-08-15 18:12:31 +00:00
{
UI()->EnableMouseLock(pID);
2011-08-15 18:12:31 +00:00
s_Operation = OP_ROTATE;
2018-08-13 09:11:56 +00:00
SelectQuad(QIndex);
2011-08-15 18:12:31 +00:00
}
else
2018-08-13 09:11:56 +00:00
{
2011-08-15 18:12:31 +00:00
s_Operation = OP_MOVE;
2018-08-13 09:11:56 +00:00
SelectQuad(QIndex);
}
2011-08-15 18:12:31 +00:00
m_SelectedEnvelopePoint = PIndex;
m_SelectedQuadEnvelope = pQuad->m_PosEnv;
2011-08-14 14:31:48 +00:00
UI()->SetActiveItem(pID);
s_LastWx = wx;
s_LastWy = wy;
2011-08-15 18:12:31 +00:00
}
else
{
m_SelectedEnvelopePoint = -1;
m_SelectedQuadEnvelope = -1;
2011-08-14 14:31:48 +00:00
}
}
2011-08-15 18:12:31 +00:00
else
Graphics()->SetColor(0.0f, 1.0f, 0.0f, 1.0f);
2011-08-14 14:31:48 +00:00
IGraphics::CQuadItem QuadItem(CenterX, CenterY, 5.0f * m_MouseWScale, 5.0f * m_MouseWScale);
2011-08-14 14:31:48 +00:00
Graphics()->QuadsDraw(&QuadItem, 1);
}
2018-04-04 19:41:14 +00:00
void CEditor::DoMapEditor(CUIRect View)
2007-05-22 15:03:32 +00:00
{
2008-01-12 12:27:55 +00:00
// render all good stuff
if(!m_ShowPicker)
2008-01-12 12:27:55 +00:00
{
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->ShiftIsPressed() && !Input()->ModifierIsPressed() && Input()->KeyPress(KEY_G))
{
const bool AnyHidden =
!m_Map.m_pGameLayer->m_Visible ||
(m_Map.m_pFrontLayer && !m_Map.m_pFrontLayer->m_Visible) ||
(m_Map.m_pTeleLayer && !m_Map.m_pTeleLayer->m_Visible) ||
(m_Map.m_pSpeedupLayer && !m_Map.m_pSpeedupLayer->m_Visible) ||
(m_Map.m_pTuneLayer && !m_Map.m_pTuneLayer->m_Visible) ||
(m_Map.m_pSwitchLayer && !m_Map.m_pSwitchLayer->m_Visible);
m_Map.m_pGameLayer->m_Visible = AnyHidden;
if(m_Map.m_pFrontLayer)
m_Map.m_pFrontLayer->m_Visible = AnyHidden;
if(m_Map.m_pTeleLayer)
m_Map.m_pTeleLayer->m_Visible = AnyHidden;
if(m_Map.m_pSpeedupLayer)
m_Map.m_pSpeedupLayer->m_Visible = AnyHidden;
if(m_Map.m_pTuneLayer)
m_Map.m_pTuneLayer->m_Visible = AnyHidden;
if(m_Map.m_pSwitchLayer)
m_Map.m_pSwitchLayer->m_Visible = AnyHidden;
}
for(auto &pGroup : m_Map.m_vpGroups)
{
if(pGroup->m_Visible)
pGroup->Render();
2008-01-12 12:27:55 +00:00
}
// render the game, tele, speedup, front, tune and switch above everything else
if(m_Map.m_pGameGroup->m_Visible)
{
m_Map.m_pGameGroup->MapScreen();
for(auto &pLayer : m_Map.m_pGameGroup->m_vpLayers)
{
if(pLayer->m_Visible && pLayer->IsEntitiesLayer())
pLayer->Render();
}
}
CLayerTiles *pT = static_cast<CLayerTiles *>(GetSelectedLayerType(0, LAYERTYPE_TILES));
2023-05-22 12:46:25 +00:00
if(m_ShowTileInfo != SHOW_TILE_OFF && pT && pT->m_Visible && m_Zoom <= 300.0f)
{
GetSelectedGroup()->MapScreen();
pT->ShowInfo();
}
2008-01-12 12:27:55 +00:00
}
else
{
// fix aspect ratio of the image in the picker
2019-04-26 19:36:49 +00:00
float Max = minimum(View.w, View.h);
View.w = View.h = Max;
}
2008-01-12 12:27:55 +00:00
static void *s_pEditorID = (void *)&s_pEditorID;
const bool Inside = !m_GuiActive || UI()->MouseInside(&View);
2008-01-12 12:27:55 +00:00
2008-03-29 11:44:03 +00:00
// fetch mouse position
2009-10-27 14:38:53 +00:00
float wx = UI()->MouseWorldX();
float wy = UI()->MouseWorldY();
2014-08-22 13:40:23 +00:00
float mx = UI()->MouseX();
float my = UI()->MouseY();
2010-05-29 07:25:38 +00:00
static float s_StartWx = 0;
static float s_StartWy = 0;
2008-01-12 12:27:55 +00:00
enum
2007-05-22 15:03:32 +00:00
{
OP_NONE = 0,
2008-01-12 12:27:55 +00:00
OP_BRUSH_GRAB,
OP_BRUSH_DRAW,
2010-05-29 07:25:38 +00:00
OP_BRUSH_PAINT,
2008-01-12 12:27:55 +00:00
OP_PAN_WORLD,
OP_PAN_EDITOR,
};
// remap the screen so it can display the whole tileset
if(m_ShowPicker)
2010-05-29 07:25:38 +00:00
{
CUIRect Screen = *UI()->Screen();
2022-03-21 06:10:44 +00:00
float Size = 32.0f * 16.0f;
float w = Size * (Screen.w / View.w);
float h = Size * (Screen.h / View.h);
float x = -(View.x / Screen.w) * w;
float y = -(View.y / Screen.h) * h;
wx = x + w * mx / Screen.w;
wy = y + h * my / Screen.h;
CLayerTiles *pTileLayer = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES);
if(pTileLayer)
2008-01-12 12:27:55 +00:00
{
Graphics()->MapScreen(x, y, x + w, y + h);
m_TilesetPicker.m_Image = pTileLayer->m_Image;
m_TilesetPicker.m_Texture = pTileLayer->m_Texture;
if(m_BrushColorEnabled)
{
m_TilesetPicker.m_Color = pTileLayer->m_Color;
m_TilesetPicker.m_Color.a = 255;
}
else
{
m_TilesetPicker.m_Color = {255, 255, 255, 255};
}
2018-08-19 17:05:42 +00:00
m_TilesetPicker.m_Game = pTileLayer->m_Game;
m_TilesetPicker.m_Tele = pTileLayer->m_Tele;
m_TilesetPicker.m_Speedup = pTileLayer->m_Speedup;
m_TilesetPicker.m_Front = pTileLayer->m_Front;
m_TilesetPicker.m_Switch = pTileLayer->m_Switch;
m_TilesetPicker.m_Tune = pTileLayer->m_Tune;
2018-08-19 17:05:42 +00:00
m_TilesetPicker.Render(true);
2023-05-22 12:46:25 +00:00
if(m_ShowTileInfo != SHOW_TILE_OFF)
m_TilesetPicker.ShowInfo();
2008-01-12 12:27:55 +00:00
}
else
{
CLayerQuads *pQuadLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
if(pQuadLayer)
{
m_QuadsetPicker.m_Image = pQuadLayer->m_Image;
m_QuadsetPicker.m_vQuads[0].m_aPoints[0].x = f2fx(View.x);
m_QuadsetPicker.m_vQuads[0].m_aPoints[0].y = f2fx(View.y);
m_QuadsetPicker.m_vQuads[0].m_aPoints[1].x = f2fx((View.x + View.w));
m_QuadsetPicker.m_vQuads[0].m_aPoints[1].y = f2fx(View.y);
m_QuadsetPicker.m_vQuads[0].m_aPoints[2].x = f2fx(View.x);
m_QuadsetPicker.m_vQuads[0].m_aPoints[2].y = f2fx((View.y + View.h));
m_QuadsetPicker.m_vQuads[0].m_aPoints[3].x = f2fx((View.x + View.w));
m_QuadsetPicker.m_vQuads[0].m_aPoints[3].y = f2fx((View.y + View.h));
m_QuadsetPicker.m_vQuads[0].m_aPoints[4].x = f2fx((View.x + View.w / 2));
m_QuadsetPicker.m_vQuads[0].m_aPoints[4].y = f2fx((View.y + View.h / 2));
m_QuadsetPicker.Render();
}
}
2007-05-22 15:03:32 +00:00
}
2010-05-29 07:25:38 +00:00
static int s_Operation = OP_NONE;
2008-01-12 12:27:55 +00:00
// draw layer borders
CLayer *apEditLayers[128];
size_t NumEditLayers = 0;
2010-05-29 07:25:38 +00:00
if(m_ShowPicker && GetSelectedLayer(0) && GetSelectedLayer(0)->m_Type == LAYERTYPE_TILES)
2007-05-22 15:03:32 +00:00
{
apEditLayers[0] = &m_TilesetPicker;
2010-05-29 07:25:38 +00:00
NumEditLayers++;
2007-05-22 15:03:32 +00:00
}
else if(m_ShowPicker)
{
apEditLayers[0] = &m_QuadsetPicker;
NumEditLayers++;
}
2007-05-22 15:03:32 +00:00
else
2008-01-12 12:27:55 +00:00
{
2022-10-25 16:51:56 +00:00
// pick a type of layers to edit, preferring Tiles layers.
int EditingType = -1;
for(size_t i = 0; i < m_vSelectedLayers.size(); i++)
{
CLayer *pLayer = GetSelectedLayer(i);
if(pLayer && (EditingType == -1 || pLayer->m_Type == LAYERTYPE_TILES))
{
EditingType = pLayer->m_Type;
if(EditingType == LAYERTYPE_TILES)
break;
}
}
for(size_t i = 0; i < m_vSelectedLayers.size() && NumEditLayers < 128; i++)
{
apEditLayers[NumEditLayers] = GetSelectedLayerType(i, EditingType);
if(apEditLayers[NumEditLayers])
{
NumEditLayers++;
}
}
2008-01-12 12:27:55 +00:00
CLayerGroup *pGroup = GetSelectedGroup();
if(pGroup)
2008-01-12 12:27:55 +00:00
{
pGroup->MapScreen();
2010-05-29 07:25:38 +00:00
RenderGrid(pGroup);
2011-07-10 20:16:16 +00:00
for(size_t i = 0; i < NumEditLayers; i++)
2008-01-12 12:27:55 +00:00
{
if(apEditLayers[i]->m_Type != LAYERTYPE_TILES)
2008-01-12 12:27:55 +00:00
continue;
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
float w, h;
apEditLayers[i]->GetSize(&w, &h);
2008-01-12 12:27:55 +00:00
2010-05-29 07:25:38 +00:00
IGraphics::CLineItem Array[4] = {
IGraphics::CLineItem(0, 0, w, 0),
IGraphics::CLineItem(w, 0, w, h),
IGraphics::CLineItem(w, h, 0, h),
IGraphics::CLineItem(0, h, 0, 0)};
Graphics()->TextureClear();
2009-10-27 14:38:53 +00:00
Graphics()->LinesBegin();
2010-05-29 07:25:38 +00:00
Graphics()->LinesDraw(Array, 4);
2009-10-27 14:38:53 +00:00
Graphics()->LinesEnd();
2008-01-12 12:27:55 +00:00
}
}
}
2010-05-29 07:25:38 +00:00
if(Inside)
2008-01-12 12:27:55 +00:00
{
UI()->SetHotItem(s_pEditorID);
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
// do global operations like pan and zoom
if(UI()->CheckActiveItem(nullptr) && (UI()->MouseButton(0) || UI()->MouseButton(2)))
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
s_StartWx = wx;
s_StartWy = wy;
if(Input()->ModifierIsPressed() || UI()->MouseButton(2))
2008-01-12 12:27:55 +00:00
{
if(Input()->ShiftIsPressed())
2010-05-29 07:25:38 +00:00
s_Operation = OP_PAN_EDITOR;
2008-01-12 12:27:55 +00:00
else
2010-05-29 07:25:38 +00:00
s_Operation = OP_PAN_WORLD;
UI()->SetActiveItem(s_pEditorID);
2008-01-12 12:27:55 +00:00
}
else
s_Operation = OP_NONE;
2008-01-12 12:27:55 +00:00
}
// brush editing
if(UI()->HotItem() == s_pEditorID)
2008-01-12 12:27:55 +00:00
{
int Layer = NUM_LAYERS;
if(m_ShowPicker)
{
CLayer *pLayer = GetSelectedLayer(0);
if(pLayer == m_Map.m_pGameLayer)
Layer = LAYER_GAME;
else if(pLayer == m_Map.m_pFrontLayer)
Layer = LAYER_FRONT;
else if(pLayer == m_Map.m_pSwitchLayer)
Layer = LAYER_SWITCH;
else if(pLayer == m_Map.m_pTeleLayer)
Layer = LAYER_TELE;
else if(pLayer == m_Map.m_pSpeedupLayer)
Layer = LAYER_SPEEDUP;
else if(pLayer == m_Map.m_pTuneLayer)
Layer = LAYER_TUNE;
}
if(m_ShowPicker && Layer != NUM_LAYERS)
{
if(m_SelectEntitiesImage == "DDNet")
m_pTooltip = Explain(EXPLANATION_DDNET, (int)wx / 32 + (int)wy / 32 * 16, Layer);
else if(m_SelectEntitiesImage == "FNG")
m_pTooltip = Explain(EXPLANATION_FNG, (int)wx / 32 + (int)wy / 32 * 16, Layer);
2021-08-28 17:51:38 +00:00
else if(m_SelectEntitiesImage == "Vanilla")
m_pTooltip = Explain(EXPLANATION_VANILLA, (int)wx / 32 + (int)wy / 32 * 16, Layer);
}
else if(m_Brush.IsEmpty())
m_pTooltip = "Use left mouse button to drag and create a brush. Hold shift to select multiple quads. Use ctrl+right mouse to select layer.";
2008-01-12 12:27:55 +00:00
else
2011-03-20 16:04:03 +00:00
m_pTooltip = "Use left mouse button to paint with the brush. Right button clears the brush.";
2008-01-12 12:27:55 +00:00
if(UI()->CheckActiveItem(s_pEditorID))
2008-01-12 12:27:55 +00:00
{
2009-10-27 14:38:53 +00:00
CUIRect r;
2010-05-29 07:25:38 +00:00
r.x = s_StartWx;
r.y = s_StartWy;
r.w = wx - s_StartWx;
r.h = wy - s_StartWy;
2008-01-12 12:27:55 +00:00
if(r.w < 0)
{
r.x += r.w;
r.w = -r.w;
}
if(r.h < 0)
{
r.y += r.h;
r.h = -r.h;
}
2010-05-29 07:25:38 +00:00
if(s_Operation == OP_BRUSH_DRAW)
{
if(!m_Brush.IsEmpty())
2008-01-12 12:27:55 +00:00
{
// draw with brush
for(size_t k = 0; k < NumEditLayers; k++)
2008-01-12 12:27:55 +00:00
{
size_t BrushIndex = k % m_Brush.m_vpLayers.size();
if(apEditLayers[k]->m_Type == m_Brush.m_vpLayers[BrushIndex]->m_Type)
{
if(apEditLayers[k]->m_Type == LAYERTYPE_TILES)
{
CLayerTiles *pLayer = (CLayerTiles *)apEditLayers[k];
CLayerTiles *pBrushLayer = (CLayerTiles *)m_Brush.m_vpLayers[BrushIndex];
if(pLayer->m_Tele <= pBrushLayer->m_Tele && pLayer->m_Speedup <= pBrushLayer->m_Speedup && pLayer->m_Front <= pBrushLayer->m_Front && pLayer->m_Game <= pBrushLayer->m_Game && pLayer->m_Switch <= pBrushLayer->m_Switch && pLayer->m_Tune <= pBrushLayer->m_Tune)
pLayer->BrushDraw(pBrushLayer, wx, wy);
}
else
{
apEditLayers[k]->BrushDraw(m_Brush.m_vpLayers[BrushIndex], wx, wy);
}
}
2008-01-12 12:27:55 +00:00
}
}
}
2010-05-29 07:25:38 +00:00
else if(s_Operation == OP_BRUSH_GRAB)
2008-01-12 12:27:55 +00:00
{
2009-10-27 14:38:53 +00:00
if(!UI()->MouseButton(0))
2008-01-12 12:27:55 +00:00
{
if(Input()->ShiftIsPressed())
2018-08-13 09:11:56 +00:00
{
CLayerQuads *pQuadLayer = (CLayerQuads *)GetSelectedLayerType(0, LAYERTYPE_QUADS);
if(pQuadLayer)
2018-08-13 09:11:56 +00:00
{
for(size_t i = 0; i < pQuadLayer->m_vQuads.size(); i++)
2018-08-13 09:11:56 +00:00
{
CQuad *pQuad = &pQuadLayer->m_vQuads[i];
float px = fx2f(pQuad->m_aPoints[4].x);
float py = fx2f(pQuad->m_aPoints[4].y);
2010-05-29 07:25:38 +00:00
if(px > r.x && px < r.x + r.w && py > r.y && py < r.y + r.h)
2018-08-13 09:11:56 +00:00
if(!IsQuadSelected(i))
m_vSelectedQuads.push_back(i);
2018-08-13 09:11:56 +00:00
}
}
}
else
{
// grab brush
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "grabbing %f %f %f %f", r.x, r.y, r.w, r.h);
2018-08-13 09:11:56 +00:00
Console()->Print(IConsole::OUTPUT_LEVEL_DEBUG, "editor", aBuf);
// TODO: do all layers
int Grabs = 0;
for(size_t k = 0; k < NumEditLayers; k++)
Grabs += apEditLayers[k]->BrushGrab(&m_Brush, r);
2018-08-13 09:11:56 +00:00
if(Grabs == 0)
m_Brush.Clear();
for(auto &pLayer : m_Brush.m_vpLayers)
pLayer->m_BrushRefCount = 1;
2018-10-02 01:52:01 +00:00
m_vSelectedQuads.clear();
2018-08-13 09:11:56 +00:00
m_SelectedPoints = 0;
}
2008-01-12 12:27:55 +00:00
}
else
{
for(size_t k = 0; k < NumEditLayers; k++)
apEditLayers[k]->BrushSelecting(r);
2021-09-22 19:48:55 +00:00
UI()->MapScreen();
2008-01-12 12:27:55 +00:00
}
}
2010-05-29 07:25:38 +00:00
else if(s_Operation == OP_BRUSH_PAINT)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
if(!UI()->MouseButton(0))
{
for(size_t k = 0; k < NumEditLayers; k++)
{
size_t BrushIndex = k;
if(m_Brush.m_vpLayers.size() != NumEditLayers)
BrushIndex = 0;
CLayer *pBrush = m_Brush.IsEmpty() ? nullptr : m_Brush.m_vpLayers[BrushIndex];
apEditLayers[k]->FillSelection(m_Brush.IsEmpty(), pBrush, r);
}
2010-05-29 07:25:38 +00:00
}
2008-01-12 12:27:55 +00:00
else
{
for(size_t k = 0; k < NumEditLayers; k++)
apEditLayers[k]->BrushSelecting(r);
2021-09-22 19:48:55 +00:00
UI()->MapScreen();
2010-05-29 07:25:38 +00:00
}
}
}
else
{
2015-07-22 22:43:09 +00:00
if(UI()->MouseButton(1))
2018-10-02 01:52:01 +00:00
{
for(auto &pLayer : m_Brush.m_vpLayers)
2018-10-02 01:52:01 +00:00
{
if(pLayer->m_BrushRefCount == 1)
delete pLayer;
2018-10-02 01:52:01 +00:00
}
2010-05-29 07:25:38 +00:00
m_Brush.Clear();
2018-10-02 01:52:01 +00:00
}
2010-05-29 07:25:38 +00:00
2022-02-26 17:49:06 +00:00
if(UI()->MouseButton(0) && s_Operation == OP_NONE && !m_QuadKnifeActive)
2010-05-29 07:25:38 +00:00
{
UI()->SetActiveItem(s_pEditorID);
2010-05-29 07:25:38 +00:00
if(m_Brush.IsEmpty())
s_Operation = OP_BRUSH_GRAB;
else
{
s_Operation = OP_BRUSH_DRAW;
for(size_t k = 0; k < NumEditLayers; k++)
2008-01-12 12:27:55 +00:00
{
size_t BrushIndex = k;
if(m_Brush.m_vpLayers.size() != NumEditLayers)
BrushIndex = 0;
if(apEditLayers[k]->m_Type == m_Brush.m_vpLayers[BrushIndex]->m_Type)
apEditLayers[k]->BrushPlace(m_Brush.m_vpLayers[BrushIndex], wx, wy);
2008-01-12 12:27:55 +00:00
}
}
2011-08-11 08:59:14 +00:00
CLayerTiles *pLayer = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES);
if(Input()->ShiftIsPressed() && pLayer)
2011-08-11 08:59:14 +00:00
s_Operation = OP_BRUSH_PAINT;
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
if(!m_Brush.IsEmpty())
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
m_Brush.m_OffsetX = -(int)wx;
m_Brush.m_OffsetY = -(int)wy;
for(const auto &pLayer : m_Brush.m_vpLayers)
2008-01-12 12:27:55 +00:00
{
if(pLayer->m_Type == LAYERTYPE_TILES)
2008-01-12 12:27:55 +00:00
{
m_Brush.m_OffsetX = -(int)(wx / 32.0f) * 32;
m_Brush.m_OffsetY = -(int)(wy / 32.0f) * 32;
2008-01-12 12:27:55 +00:00
break;
}
}
2010-05-29 07:25:38 +00:00
CLayerGroup *pGroup = GetSelectedGroup();
if(!m_ShowPicker && pGroup)
2010-06-25 16:56:58 +00:00
{
m_Brush.m_OffsetX += pGroup->m_OffsetX;
m_Brush.m_OffsetY += pGroup->m_OffsetY;
m_Brush.m_ParallaxX = pGroup->m_ParallaxX;
m_Brush.m_ParallaxY = pGroup->m_ParallaxY;
m_Brush.m_ParallaxZoom = pGroup->m_ParallaxZoom;
2010-06-25 16:56:58 +00:00
m_Brush.Render();
float w, h;
m_Brush.GetSize(&w, &h);
IGraphics::CLineItem Array[4] = {
IGraphics::CLineItem(0, 0, w, 0),
IGraphics::CLineItem(w, 0, w, h),
IGraphics::CLineItem(w, h, 0, h),
IGraphics::CLineItem(0, h, 0, 0)};
Graphics()->TextureClear();
2010-06-25 16:56:58 +00:00
Graphics()->LinesBegin();
Graphics()->LinesDraw(Array, 4);
Graphics()->LinesEnd();
}
2008-01-12 12:27:55 +00:00
}
}
}
2010-05-29 07:25:38 +00:00
// quad & sound editing
2008-01-12 12:27:55 +00:00
{
if(!m_ShowPicker && m_Brush.IsEmpty())
2008-01-12 12:27:55 +00:00
{
2008-01-13 22:03:32 +00:00
// fetch layers
CLayerGroup *pGroup = GetSelectedGroup();
if(pGroup)
pGroup->MapScreen();
2010-05-29 07:25:38 +00:00
for(size_t k = 0; k < NumEditLayers; k++)
2008-01-12 12:27:55 +00:00
{
if(apEditLayers[k]->m_Type == LAYERTYPE_QUADS)
2008-01-12 12:27:55 +00:00
{
CLayerQuads *pLayer = (CLayerQuads *)apEditLayers[k];
2010-05-29 07:25:38 +00:00
if(m_ShowEnvelopePreview == SHOWENV_NONE)
m_ShowEnvelopePreview = SHOWENV_ALL;
2010-05-29 07:25:38 +00:00
2022-02-26 17:49:06 +00:00
if(m_QuadKnifeActive)
DoQuadKnife(m_vSelectedQuads[m_SelectedQuadIndex]);
2022-02-26 17:49:06 +00:00
else
2008-01-13 22:03:32 +00:00
{
2022-02-26 17:49:06 +00:00
Graphics()->TextureClear();
Graphics()->QuadsBegin();
for(size_t i = 0; i < pLayer->m_vQuads.size(); i++)
2022-02-26 17:49:06 +00:00
{
for(int v = 0; v < 4; v++)
DoQuadPoint(&pLayer->m_vQuads[i], i, v);
2010-05-29 07:25:38 +00:00
DoQuad(&pLayer->m_vQuads[i], i);
2022-02-26 17:49:06 +00:00
}
Graphics()->QuadsEnd();
2008-01-13 22:03:32 +00:00
}
2008-01-12 12:27:55 +00:00
}
if(apEditLayers[k]->m_Type == LAYERTYPE_SOUNDS)
{
CLayerSounds *pLayer = (CLayerSounds *)apEditLayers[k];
Graphics()->TextureClear();
Graphics()->QuadsBegin();
for(size_t i = 0; i < pLayer->m_vSources.size(); i++)
{
DoSoundSource(&pLayer->m_vSources[i], i);
}
Graphics()->QuadsEnd();
}
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
2021-09-22 19:48:55 +00:00
UI()->MapScreen();
2010-05-29 07:25:38 +00:00
}
}
2010-05-29 07:25:38 +00:00
// menu proof selection
2023-05-21 16:00:41 +00:00
if(m_ProofBorders == PROOF_BORDER_MENU && !m_ShowPicker)
{
ResetMenuBackgroundPositions();
for(int i = 0; i < (int)m_vMenuBackgroundPositions.size(); i++)
{
vec2 Pos = m_vMenuBackgroundPositions[i];
Pos += vec2(m_WorldOffsetX, m_WorldOffsetY) - m_vMenuBackgroundPositions[m_CurrentMenuProofIndex];
Pos.y -= 3.0f;
vec2 MousePos(m_MouseWorldNoParaX, m_MouseWorldNoParaY);
if(distance(Pos, MousePos) <= 20.0f)
{
UI()->SetHotItem(&m_vMenuBackgroundPositions[i]);
2023-03-18 06:53:18 +00:00
if(i != m_CurrentMenuProofIndex && UI()->CheckActiveItem(&m_vMenuBackgroundPositions[i]))
{
if(!UI()->MouseButton(0))
{
m_CurrentMenuProofIndex = i;
m_WorldOffsetX = m_vMenuBackgroundPositions[i].x;
m_WorldOffsetY = m_vMenuBackgroundPositions[i].y;
UI()->SetActiveItem(nullptr);
}
}
else if(UI()->HotItem() == &m_vMenuBackgroundPositions[i])
{
2023-03-27 06:51:02 +00:00
char aTooltipPrefix[32] = "Switch proof position to";
if(i == m_CurrentMenuProofIndex)
str_copy(aTooltipPrefix, "Current proof position at");
2023-03-18 06:53:18 +00:00
char aNumBuf[8];
if(i < (TILE_TIME_CHECKPOINT_LAST - TILE_TIME_CHECKPOINT_FIRST))
str_format(aNumBuf, sizeof(aNumBuf), "#%d", i + 1);
else
aNumBuf[0] = '\0';
2023-03-27 06:51:02 +00:00
char aTooltipPositions[128];
str_format(aTooltipPositions, sizeof(aTooltipPositions), "%s %s", m_vpMenuBackgroundPositionNames[i], aNumBuf);
for(int k : m_vMenuBackgroundCollisions.at(i))
{
if(k == m_CurrentMenuProofIndex)
str_copy(aTooltipPrefix, "Current proof position at");
Pos = m_vMenuBackgroundPositions[k];
Pos += vec2(m_WorldOffsetX, m_WorldOffsetY) - m_vMenuBackgroundPositions[m_CurrentMenuProofIndex];
Pos.y -= 3.0f;
MousePos = vec2(m_MouseWorldNoParaX, m_MouseWorldNoParaY);
if(distance(Pos, MousePos) > 20.0f)
continue;
if(i < (TILE_TIME_CHECKPOINT_LAST - TILE_TIME_CHECKPOINT_FIRST))
str_format(aNumBuf, sizeof(aNumBuf), "#%d", k + 1);
else
aNumBuf[0] = '\0';
char aTooltipPositionsCopy[128];
str_copy(aTooltipPositionsCopy, aTooltipPositions);
str_format(aTooltipPositions, sizeof(aTooltipPositions), "%s, %s %s", aTooltipPositionsCopy, m_vpMenuBackgroundPositionNames[k], aNumBuf);
}
str_format(m_aMenuBackgroundTooltip, sizeof(m_aMenuBackgroundTooltip), "%s %s", aTooltipPrefix, aTooltipPositions);
2023-03-18 06:53:18 +00:00
m_pTooltip = m_aMenuBackgroundTooltip;
if(UI()->MouseButton(0))
UI()->SetActiveItem(&m_vMenuBackgroundPositions[i]);
}
2023-03-27 06:51:02 +00:00
break;
}
}
}
// do panning
if(UI()->CheckActiveItem(s_pEditorID))
{
if(s_Operation == OP_PAN_WORLD)
2008-01-12 12:27:55 +00:00
{
m_WorldOffsetX -= m_MouseDeltaX * m_MouseWScale;
m_WorldOffsetY -= m_MouseDeltaY * m_MouseWScale;
}
else if(s_Operation == OP_PAN_EDITOR)
{
m_EditorOffsetX -= m_MouseDeltaX * m_MouseWScale;
m_EditorOffsetY -= m_MouseDeltaY * m_MouseWScale;
}
2008-01-12 12:27:55 +00:00
// release mouse
if(!UI()->MouseButton(0))
{
s_Operation = OP_NONE;
UI()->SetActiveItem(nullptr);
2008-01-13 22:03:32 +00:00
}
2008-01-12 12:27:55 +00:00
}
if(!Input()->ShiftIsPressed() && !Input()->ModifierIsPressed() && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0)
2021-11-06 15:44:40 +00:00
{
float PanSpeed = 64.0f;
if(Input()->KeyPress(KEY_A))
m_WorldOffsetX -= PanSpeed * m_MouseWScale;
2021-11-06 15:44:40 +00:00
else if(Input()->KeyPress(KEY_D))
m_WorldOffsetX += PanSpeed * m_MouseWScale;
2021-11-06 15:44:40 +00:00
if(Input()->KeyPress(KEY_W))
m_WorldOffsetY -= PanSpeed * m_MouseWScale;
2021-11-06 15:44:40 +00:00
else if(Input()->KeyPress(KEY_S))
m_WorldOffsetY += PanSpeed * m_MouseWScale;
2021-11-06 15:44:40 +00:00
}
2008-01-12 12:27:55 +00:00
}
else if(UI()->CheckActiveItem(s_pEditorID))
{
// release mouse
if(!UI()->MouseButton(0))
{
s_Operation = OP_NONE;
UI()->SetActiveItem(nullptr);
}
}
2010-05-29 07:25:38 +00:00
if(!m_ShowPicker && GetSelectedGroup() && GetSelectedGroup()->m_UseClipping)
2008-03-29 11:44:03 +00:00
{
CLayerGroup *pGameGroup = m_Map.m_pGameGroup;
pGameGroup->MapScreen();
2011-08-11 08:59:14 +00:00
Graphics()->TextureClear();
2009-10-27 14:38:53 +00:00
Graphics()->LinesBegin();
CUIRect r;
r.x = GetSelectedGroup()->m_ClipX;
r.y = GetSelectedGroup()->m_ClipY;
r.w = GetSelectedGroup()->m_ClipW;
r.h = GetSelectedGroup()->m_ClipH;
IGraphics::CLineItem Array[4] = {
IGraphics::CLineItem(r.x, r.y, r.x + r.w, r.y),
IGraphics::CLineItem(r.x + r.w, r.y, r.x + r.w, r.y + r.h),
IGraphics::CLineItem(r.x + r.w, r.y + r.h, r.x, r.y + r.h),
IGraphics::CLineItem(r.x, r.y + r.h, r.x, r.y)};
Graphics()->SetColor(1, 0, 0, 1);
Graphics()->LinesDraw(Array, 4);
2010-05-29 07:25:38 +00:00
2009-10-27 14:38:53 +00:00
Graphics()->LinesEnd();
2008-03-29 11:44:03 +00:00
}
2008-01-12 12:27:55 +00:00
2010-05-29 07:25:38 +00:00
// render screen sizes
2023-05-21 20:21:13 +00:00
if(m_ProofBorders != PROOF_BORDER_OFF && !m_ShowPicker)
2008-01-12 12:27:55 +00:00
{
CLayerGroup *pGameGroup = m_Map.m_pGameGroup;
pGameGroup->MapScreen();
2010-05-29 07:25:38 +00:00
Graphics()->TextureClear();
2009-10-27 14:38:53 +00:00
Graphics()->LinesBegin();
2010-05-29 07:25:38 +00:00
2016-07-18 06:55:35 +00:00
// possible screen sizes (white border)
2010-05-29 07:25:38 +00:00
float aLastPoints[4];
float Start = 1.0f; //9.0f/16.0f;
float End = 16.0f / 9.0f;
2010-05-29 07:25:38 +00:00
const int NumSteps = 20;
for(int i = 0; i <= NumSteps; i++)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
float aPoints[4];
float Aspect = Start + (End - Start) * (i / (float)NumSteps);
2010-05-29 07:25:38 +00:00
float Zoom = (m_ProofBorders == PROOF_BORDER_MENU) ? 0.7f : 1.0f;
RenderTools()->MapScreenToWorld(
2010-05-29 07:25:38 +00:00
m_WorldOffsetX, m_WorldOffsetY,
100.0f, 100.0f, 100.0f, 0.0f, 0.0f, Aspect, Zoom, aPoints);
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
if(i == 0)
{
2010-05-29 07:25:38 +00:00
IGraphics::CLineItem Array[2] = {
IGraphics::CLineItem(aPoints[0], aPoints[1], aPoints[2], aPoints[1]),
IGraphics::CLineItem(aPoints[0], aPoints[3], aPoints[2], aPoints[3])};
Graphics()->LinesDraw(Array, 2);
2008-01-12 12:27:55 +00:00
}
if(i != 0)
{
2010-05-29 07:25:38 +00:00
IGraphics::CLineItem Array[4] = {
IGraphics::CLineItem(aPoints[0], aPoints[1], aLastPoints[0], aLastPoints[1]),
IGraphics::CLineItem(aPoints[2], aPoints[1], aLastPoints[2], aLastPoints[1]),
IGraphics::CLineItem(aPoints[0], aPoints[3], aLastPoints[0], aLastPoints[3]),
IGraphics::CLineItem(aPoints[2], aPoints[3], aLastPoints[2], aLastPoints[3])};
Graphics()->LinesDraw(Array, 4);
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
if(i == NumSteps)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
IGraphics::CLineItem Array[2] = {
IGraphics::CLineItem(aPoints[0], aPoints[1], aPoints[0], aPoints[3]),
IGraphics::CLineItem(aPoints[2], aPoints[1], aPoints[2], aPoints[3])};
Graphics()->LinesDraw(Array, 2);
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
mem_copy(aLastPoints, aPoints, sizeof(aPoints));
2008-01-12 12:27:55 +00:00
}
2016-07-18 06:55:35 +00:00
// two screen sizes (green and red border)
2008-01-12 12:27:55 +00:00
{
Graphics()->SetColor(1, 0, 0, 1);
2008-01-17 23:09:49 +00:00
for(int i = 0; i < 2; i++)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
float aPoints[4];
Declare variables as `const` when possible According to cppcheck's `constVariable` error: ``` src\engine\client\backend\opengl\opengl_sl.cpp:74:43: style: Variable 'Define' can be declared as reference to const [constVariable] for(CGLSLCompiler::SGLSLCompilerDefine &Define : pCompiler->m_vDefines) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:2149:12: style: Variable 'GraphicThreadCommandBuffer' can be declared as reference to const [constVariable] auto &GraphicThreadCommandBuffer = m_vvThreadDrawCommandBuffers[i + 1][m_CurImageIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3192:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3200:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[State.m_Texture].m_VKStandard3DTexturedDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3810:13: style: Variable 'Mode' can be declared as reference to const [constVariable] for(auto &Mode : vPresentModeList) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3818:13: style: Variable 'Mode' can be declared as reference to const [constVariable] for(auto &Mode : vPresentModeList) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6511:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6555:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_VKStandard3DTexturedDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6660:9: style: Variable 'MemBlock' can be declared as reference to const [constVariable] auto &MemBlock = m_vBufferObjects[BufferIndex].m_BufferObject.m_Mem; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6799:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6808:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6902:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6907:9: style: Variable 'TextTextureDescr' can be declared as reference to const [constVariable] auto &TextTextureDescr = m_vTextures[pCommand->m_TextTextureIndex].m_VKTextDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6961:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6970:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\game\client\components\hud.cpp:178:8: style: Variable 'aFlagCarrier' can be declared as const array [constVariable] int aFlagCarrier[2] = { ^ src\game\client\components\hud.cpp:519:16: style: Variable 's_aTextWidth' can be declared as const array [constVariable] static float s_aTextWidth[5] = {s_TextWidth0, s_TextWidth00, s_TextWidth000, s_TextWidth0000, s_TextWidth00000}; ^ src\game\client\components\killmessages.cpp:305:30: style: Variable 'Client' can be declared as reference to const [constVariable] CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_KillerID]; ^ src\game\client\components\killmessages.cpp:314:30: style: Variable 'Client' can be declared as reference to const [constVariable] CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_VictimID]; ^ src\game\client\components\menus_ingame.cpp:243:12: style: Variable 'pInfoByName' can be declared as reference to const [constVariable] for(auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName) ^ src\game\client\components\menus_ingame.cpp:530:12: style: Variable 'pInfoByName' can be declared as reference to const [constVariable] for(auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName) ^ src\game\client\components\players.cpp:767:44: style: Variable 'CharacterInfo' can be declared as reference to const [constVariable] CGameClient::CSnapState::CCharacterInfo &CharacterInfo = m_pClient->m_Snap.m_aCharacters[i]; ^ src\game\client\components\spectator.cpp:122:27: style: Variable 'Snap' can be declared as reference to const [constVariable] CGameClient::CSnapState &Snap = pSelf->m_pClient->m_Snap; ^ src\game\client\components\spectator.cpp:221:12: style: Variable 'pInfo' can be declared as reference to const [constVariable] for(auto &pInfo : m_pClient->m_Snap.m_apInfoByDDTeamName) ^ src\game\client\gameclient.cpp:2220:15: style: Variable 'OwnClientData' can be declared as reference to const [constVariable] CClientData &OwnClientData = m_aClients[ownID]; ^ src\game\client\gameclient.cpp:2227:16: style: Variable 'cData' can be declared as reference to const [constVariable] CClientData &cData = m_aClients[i]; ^ src\game\client\prediction\entities\character.cpp:397:11: style: Variable 'aSpreading' can be declared as const array [constVariable] float aSpreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; ^ src\game\client\prediction\entities\laser.cpp:53:9: style: Variable 'HitPos' can be declared as reference to const [constVariable] vec2 &HitPos = pHit->Core()->m_Pos; ^ src\game\editor\auto_map.cpp:507:18: style: Variable 'Index' can be declared as reference to const [constVariable] for(auto &Index : pRule->m_vIndexList) ^ src\game\editor\auto_map.cpp:518:18: style: Variable 'Index' can be declared as reference to const [constVariable] for(auto &Index : pRule->m_vIndexList) ^ src\game\editor\editor.cpp:118:12: style: Variable 'Item' can be declared as reference to const [constVariable] for(auto &Item : vList) ^ src\game\editor\editor.cpp:2983:11: style: Variable 'aAspects' can be declared as const array [constVariable] float aAspects[] = {4.0f / 3.0f, 16.0f / 10.0f, 5.0f / 4.0f, 16.0f / 9.0f}; ^ src\game\editor\editor.cpp:3141:15: style: Variable 's_aShift' can be declared as const array [constVariable] static int s_aShift[] = {24, 16, 8, 0}; ^ src\engine\server\server.cpp:2807:14: style: Variable 'Client' can be declared as reference to const [constVariable] for(auto &Client : m_aClients) ^ src\engine\server\sql_string_helpers.cpp:51:6: style: Variable 'aTimes' can be declared as const array [constVariable] int aTimes[7] = ^ src\test\secure_random.cpp:24:6: style: Variable 'BOUNDS' can be declared as const array [constVariable] int BOUNDS[] = {2, 3, 4, 5, 10, 100, 127, 128, 129}; ^ ```
2022-11-13 15:29:13 +00:00
const float aAspects[] = {4.0f / 3.0f, 16.0f / 10.0f, 5.0f / 4.0f, 16.0f / 9.0f};
2010-05-29 07:25:38 +00:00
float Aspect = aAspects[i];
float Zoom = (m_ProofBorders == PROOF_BORDER_MENU) ? 0.7f : 1.0f;
RenderTools()->MapScreenToWorld(
2010-05-29 07:25:38 +00:00
m_WorldOffsetX, m_WorldOffsetY,
100.0f, 100.0f, 100.0f, 0.0f, 0.0f, Aspect, Zoom, aPoints);
2010-05-29 07:25:38 +00:00
2009-10-27 14:38:53 +00:00
CUIRect r;
2010-05-29 07:25:38 +00:00
r.x = aPoints[0];
r.y = aPoints[1];
r.w = aPoints[2] - aPoints[0];
r.h = aPoints[3] - aPoints[1];
2010-05-29 07:25:38 +00:00
IGraphics::CLineItem Array[4] = {
IGraphics::CLineItem(r.x, r.y, r.x + r.w, r.y),
IGraphics::CLineItem(r.x + r.w, r.y, r.x + r.w, r.y + r.h),
IGraphics::CLineItem(r.x + r.w, r.y + r.h, r.x, r.y + r.h),
IGraphics::CLineItem(r.x, r.y + r.h, r.x, r.y)};
2010-05-29 07:25:38 +00:00
Graphics()->LinesDraw(Array, 4);
Graphics()->SetColor(0, 1, 0, 1);
2008-01-12 12:27:55 +00:00
}
}
2009-10-27 14:38:53 +00:00
Graphics()->LinesEnd();
2016-07-18 06:55:35 +00:00
// tee position (blue circle) and other screen positions
2016-07-18 06:55:35 +00:00
{
Graphics()->TextureClear();
2016-07-18 06:55:35 +00:00
Graphics()->QuadsBegin();
Graphics()->SetColor(0, 0, 1, 0.3f);
Graphics()->DrawCircle(m_WorldOffsetX, m_WorldOffsetY - 3.0f, 20.0f, 32);
if(m_ProofBorders == PROOF_BORDER_MENU)
{
Graphics()->SetColor(0, 1, 0, 0.3f);
2023-03-27 06:51:02 +00:00
std::set<int> indices;
for(int i = 0; i < (int)m_vMenuBackgroundPositions.size(); i++)
2023-03-27 06:51:02 +00:00
indices.insert(i);
while(!indices.empty())
{
2023-03-27 06:51:02 +00:00
int i = *indices.begin();
indices.erase(i);
for(int k : m_vMenuBackgroundCollisions.at(i))
indices.erase(k);
2023-03-27 06:51:02 +00:00
vec2 Pos = m_vMenuBackgroundPositions[i];
Pos += vec2(m_WorldOffsetX, m_WorldOffsetY) - m_vMenuBackgroundPositions[m_CurrentMenuProofIndex];
2023-03-27 06:51:02 +00:00
if(distance(Pos, vec2(m_WorldOffsetX, m_WorldOffsetY)) < 0.001f)
continue;
Graphics()->DrawCircle(Pos.x, Pos.y - 3.0f, 20.0f, 32);
}
}
2016-07-18 06:55:35 +00:00
Graphics()->QuadsEnd();
}
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
2023-05-22 12:46:25 +00:00
if(!m_ShowPicker && m_ShowTileInfo != SHOW_TILE_OFF && m_ShowEnvelopePreview != SHOWENV_NONE && GetSelectedLayer(0) && GetSelectedLayer(0)->m_Type == LAYERTYPE_QUADS)
2011-08-15 18:12:31 +00:00
{
GetSelectedGroup()->MapScreen();
CLayerQuads *pLayer = (CLayerQuads *)GetSelectedLayer(0);
IGraphics::CTextureHandle Texture;
if(pLayer->m_Image >= 0 && pLayer->m_Image < (int)m_Map.m_vpImages.size())
Texture = m_Map.m_vpImages[pLayer->m_Image]->m_Texture;
2011-08-15 18:12:31 +00:00
DoQuadEnvelopes(pLayer->m_vQuads, Texture);
m_ShowEnvelopePreview = SHOWENV_NONE;
2014-01-19 03:02:01 +00:00
}
2011-08-14 14:31:48 +00:00
2021-09-22 19:48:55 +00:00
UI()->MapScreen();
2007-05-22 15:03:32 +00:00
}
float CEditor::ScaleFontSize(char *pText, int TextSize, float FontSize, int Width)
{
while(TextRender()->TextWidth(FontSize, pText, -1, -1.0f) > Width)
{
if(FontSize > 6.0f)
{
FontSize--;
}
else
{
pText[str_length(pText) - 4] = '\0';
2020-12-31 09:03:15 +00:00
str_append(pText, "", TextSize);
}
}
return FontSize;
}
int CEditor::DoProperties(CUIRect *pToolBox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color)
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
int Change = -1;
2008-01-12 12:27:55 +00:00
2010-05-29 07:25:38 +00:00
for(int i = 0; pProps[i].m_pName; i++)
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
CUIRect Slot;
pToolBox->HSplitTop(13.0f, &Slot, pToolBox);
CUIRect Label, Shifter;
Slot.VSplitMid(&Label, &Shifter);
Shifter.HMargin(1.0f, &Shifter);
UI()->DoLabel(&Label, pProps[i].m_pName, 10.0f, TEXTALIGN_ML);
2010-05-29 07:25:38 +00:00
if(pProps[i].m_Type == PROPTYPE_INT_STEP)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
CUIRect Inc, Dec;
char aBuf[64];
Shifter.VSplitRight(10.0f, &Shifter, &Inc);
Shifter.VSplitLeft(10.0f, &Dec, &Shifter);
str_format(aBuf, sizeof(aBuf), "%d", pProps[i].m_Value);
int NewValue = UiDoValueSelector((char *)&pIDs[i], &Shifter, "", pProps[i].m_Value, pProps[i].m_Min, pProps[i].m_Max, 1, 1.0f, "Use left mouse button to drag and change the value. Hold shift to be more precise. Rightclick to edit as text.", false, false, 0, &Color);
if(NewValue != pProps[i].m_Value)
2016-06-02 11:50:06 +00:00
{
*pNewVal = NewValue;
Change = i;
}
if(DoButton_ButtonDec((char *)&pIDs[i] + 1, nullptr, 0, &Dec, 0, "Decrease"))
2008-01-12 12:27:55 +00:00
{
*pNewVal = pProps[i].m_Value - 1;
2010-05-29 07:25:38 +00:00
Change = i;
2008-01-12 12:27:55 +00:00
}
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 2, nullptr, 0, &Inc, 0, "Increase"))
2008-01-12 12:27:55 +00:00
{
*pNewVal = pProps[i].m_Value + 1;
2010-05-29 07:25:38 +00:00
Change = i;
2008-01-12 12:27:55 +00:00
}
}
2010-05-29 07:25:38 +00:00
else if(pProps[i].m_Type == PROPTYPE_BOOL)
{
2010-05-29 07:25:38 +00:00
CUIRect No, Yes;
Shifter.VSplitMid(&No, &Yes);
2011-03-20 16:04:03 +00:00
if(DoButton_ButtonDec(&pIDs[i], "No", !pProps[i].m_Value, &No, 0, ""))
{
2010-05-29 07:25:38 +00:00
*pNewVal = 0;
Change = i;
}
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 1, "Yes", pProps[i].m_Value, &Yes, 0, ""))
{
2010-05-29 07:25:38 +00:00
*pNewVal = 1;
Change = i;
}
2010-05-29 07:25:38 +00:00
}
else if(pProps[i].m_Type == PROPTYPE_INT_SCROLL)
2008-01-12 12:27:55 +00:00
{
2015-03-30 09:44:32 +00:00
int NewValue = UiDoValueSelector(&pIDs[i], &Shifter, "", pProps[i].m_Value, pProps[i].m_Min, pProps[i].m_Max, 1, 1.0f, "Use left mouse button to drag and change the value. Hold shift to be more precise. Rightclick to edit as text.");
2010-05-29 07:25:38 +00:00
if(NewValue != pProps[i].m_Value)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
*pNewVal = NewValue;
Change = i;
2008-01-12 12:27:55 +00:00
}
}
else if(pProps[i].m_Type == PROPTYPE_ANGLE_SCROLL)
{
2016-06-02 13:31:12 +00:00
CUIRect Inc, Dec;
Shifter.VSplitRight(10.0f, &Shifter, &Inc);
Shifter.VSplitLeft(10.0f, &Dec, &Shifter);
const bool Shift = Input()->ShiftIsPressed();
int Step = Shift ? 1 : 45;
2015-07-15 00:34:50 +00:00
int Value = pProps[i].m_Value;
int NewValue = UiDoValueSelector(&pIDs[i], &Shifter, "", Value, pProps[i].m_Min, pProps[i].m_Max, Shift ? 1 : 45, Shift ? 1.0f : 10.0f, "Use left mouse button to drag and change the value. Hold shift to be more precise. Rightclick to edit as text.", false, false, 0);
if(DoButton_ButtonDec(&pIDs[i] + 1, nullptr, 0, &Dec, 0, "Decrease"))
2016-06-02 13:31:12 +00:00
{
NewValue = (std::ceil((pProps[i].m_Value / (float)Step)) - 1) * Step;
if(NewValue < 0)
NewValue += 360;
2016-06-02 13:31:12 +00:00
}
if(DoButton_ButtonInc(&pIDs[i] + 2, nullptr, 0, &Inc, 0, "Increase"))
NewValue = (pProps[i].m_Value + Step) / Step * Step;
if(NewValue != pProps[i].m_Value)
2016-06-02 13:31:12 +00:00
{
*pNewVal = NewValue % 360;
2016-06-02 13:31:12 +00:00
Change = i;
}
}
2010-05-29 07:25:38 +00:00
else if(pProps[i].m_Type == PROPTYPE_COLOR)
2008-01-12 12:27:55 +00:00
{
static const char *s_apTexts[4] = {"R", "G", "B", "A"};
Declare variables as `const` when possible According to cppcheck's `constVariable` error: ``` src\engine\client\backend\opengl\opengl_sl.cpp:74:43: style: Variable 'Define' can be declared as reference to const [constVariable] for(CGLSLCompiler::SGLSLCompilerDefine &Define : pCompiler->m_vDefines) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:2149:12: style: Variable 'GraphicThreadCommandBuffer' can be declared as reference to const [constVariable] auto &GraphicThreadCommandBuffer = m_vvThreadDrawCommandBuffers[i + 1][m_CurImageIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3192:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3200:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[State.m_Texture].m_VKStandard3DTexturedDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3810:13: style: Variable 'Mode' can be declared as reference to const [constVariable] for(auto &Mode : vPresentModeList) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:3818:13: style: Variable 'Mode' can be declared as reference to const [constVariable] for(auto &Mode : vPresentModeList) ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6511:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6555:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_VKStandard3DTexturedDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6660:9: style: Variable 'MemBlock' can be declared as reference to const [constVariable] auto &MemBlock = m_vBufferObjects[BufferIndex].m_BufferObject.m_Mem; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6799:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6808:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[pCommand->m_State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6902:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6907:9: style: Variable 'TextTextureDescr' can be declared as reference to const [constVariable] auto &TextTextureDescr = m_vTextures[pCommand->m_TextTextureIndex].m_VKTextDescrSet; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6961:9: style: Variable 'BufferObject' can be declared as reference to const [constVariable] auto &BufferObject = m_vBufferObjects[BufferObjectIndex]; ^ src\engine\client\backend\vulkan\backend_vulkan.cpp:6970:10: style: Variable 'DescrSet' can be declared as reference to const [constVariable] auto &DescrSet = m_vTextures[State.m_Texture].m_aVKStandardTexturedDescrSets[AddressModeIndex]; ^ src\game\client\components\hud.cpp:178:8: style: Variable 'aFlagCarrier' can be declared as const array [constVariable] int aFlagCarrier[2] = { ^ src\game\client\components\hud.cpp:519:16: style: Variable 's_aTextWidth' can be declared as const array [constVariable] static float s_aTextWidth[5] = {s_TextWidth0, s_TextWidth00, s_TextWidth000, s_TextWidth0000, s_TextWidth00000}; ^ src\game\client\components\killmessages.cpp:305:30: style: Variable 'Client' can be declared as reference to const [constVariable] CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_KillerID]; ^ src\game\client\components\killmessages.cpp:314:30: style: Variable 'Client' can be declared as reference to const [constVariable] CGameClient::CClientData &Client = GameClient()->m_aClients[m_aKillmsgs[r].m_VictimID]; ^ src\game\client\components\menus_ingame.cpp:243:12: style: Variable 'pInfoByName' can be declared as reference to const [constVariable] for(auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName) ^ src\game\client\components\menus_ingame.cpp:530:12: style: Variable 'pInfoByName' can be declared as reference to const [constVariable] for(auto &pInfoByName : m_pClient->m_Snap.m_apInfoByName) ^ src\game\client\components\players.cpp:767:44: style: Variable 'CharacterInfo' can be declared as reference to const [constVariable] CGameClient::CSnapState::CCharacterInfo &CharacterInfo = m_pClient->m_Snap.m_aCharacters[i]; ^ src\game\client\components\spectator.cpp:122:27: style: Variable 'Snap' can be declared as reference to const [constVariable] CGameClient::CSnapState &Snap = pSelf->m_pClient->m_Snap; ^ src\game\client\components\spectator.cpp:221:12: style: Variable 'pInfo' can be declared as reference to const [constVariable] for(auto &pInfo : m_pClient->m_Snap.m_apInfoByDDTeamName) ^ src\game\client\gameclient.cpp:2220:15: style: Variable 'OwnClientData' can be declared as reference to const [constVariable] CClientData &OwnClientData = m_aClients[ownID]; ^ src\game\client\gameclient.cpp:2227:16: style: Variable 'cData' can be declared as reference to const [constVariable] CClientData &cData = m_aClients[i]; ^ src\game\client\prediction\entities\character.cpp:397:11: style: Variable 'aSpreading' can be declared as const array [constVariable] float aSpreading[] = {-0.185f, -0.070f, 0, 0.070f, 0.185f}; ^ src\game\client\prediction\entities\laser.cpp:53:9: style: Variable 'HitPos' can be declared as reference to const [constVariable] vec2 &HitPos = pHit->Core()->m_Pos; ^ src\game\editor\auto_map.cpp:507:18: style: Variable 'Index' can be declared as reference to const [constVariable] for(auto &Index : pRule->m_vIndexList) ^ src\game\editor\auto_map.cpp:518:18: style: Variable 'Index' can be declared as reference to const [constVariable] for(auto &Index : pRule->m_vIndexList) ^ src\game\editor\editor.cpp:118:12: style: Variable 'Item' can be declared as reference to const [constVariable] for(auto &Item : vList) ^ src\game\editor\editor.cpp:2983:11: style: Variable 'aAspects' can be declared as const array [constVariable] float aAspects[] = {4.0f / 3.0f, 16.0f / 10.0f, 5.0f / 4.0f, 16.0f / 9.0f}; ^ src\game\editor\editor.cpp:3141:15: style: Variable 's_aShift' can be declared as const array [constVariable] static int s_aShift[] = {24, 16, 8, 0}; ^ src\engine\server\server.cpp:2807:14: style: Variable 'Client' can be declared as reference to const [constVariable] for(auto &Client : m_aClients) ^ src\engine\server\sql_string_helpers.cpp:51:6: style: Variable 'aTimes' can be declared as const array [constVariable] int aTimes[7] = ^ src\test\secure_random.cpp:24:6: style: Variable 'BOUNDS' can be declared as const array [constVariable] int BOUNDS[] = {2, 3, 4, 5, 10, 100, 127, 128, 129}; ^ ```
2022-11-13 15:29:13 +00:00
static const int s_aShift[] = {24, 16, 8, 0};
2015-08-22 15:50:34 +00:00
int NewColor = 0;
// extra space
CUIRect ColorBox, ColorSlots;
pToolBox->HSplitTop(3.0f * 13.0f, &Slot, pToolBox);
Slot.VSplitMid(&ColorBox, &ColorSlots);
ColorBox.HMargin(1.0f, &ColorBox);
ColorBox.VMargin(6.0f, &ColorBox);
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
for(int c = 0; c < 4; c++)
{
int v = (pProps[i].m_Value >> s_aShift[c]) & 0xff;
NewColor |= UiDoValueSelector(((char *)&pIDs[i]) + c, &Shifter, s_apTexts[c], v, 0, 255, 1, 1.0f, "Use left mouse button to drag and change the color value. Hold shift to be more precise. Rightclick to edit as text.") << s_aShift[c];
2008-01-12 12:27:55 +00:00
if(c != 3)
{
ColorSlots.HSplitTop(13.0f, &Shifter, &ColorSlots);
2010-05-29 07:25:38 +00:00
Shifter.HMargin(1.0f, &Shifter);
2008-01-12 12:27:55 +00:00
}
}
2010-05-29 07:25:38 +00:00
// hex
pToolBox->HSplitTop(13.0f, &Slot, pToolBox);
Slot.VSplitMid(nullptr, &Shifter);
Shifter.HMargin(1.0f, &Shifter);
int NewColorHex = pProps[i].m_Value & 0xff;
NewColorHex |= UiDoValueSelector(((char *)&pIDs[i] - 1), &Shifter, "", (pProps[i].m_Value >> 8) & 0xFFFFFF, 0, 0xFFFFFF, 1, 1.0f, "Use left mouse button to drag and change the color value. Hold shift to be more precise. Rightclick to edit as text.", false, true) << 8;
// color picker
ColorRGBA ColorPick = ColorRGBA(
((pProps[i].m_Value >> s_aShift[0]) & 0xff) / 255.0f,
((pProps[i].m_Value >> s_aShift[1]) & 0xff) / 255.0f,
((pProps[i].m_Value >> s_aShift[2]) & 0xff) / 255.0f,
1.0f);
2017-02-21 16:10:08 +00:00
2023-03-31 19:18:13 +00:00
static int s_ColorPicker;
if(DoButton_ColorPicker(&s_ColorPicker, &ColorBox, &ColorPick))
{
2022-04-04 18:51:19 +00:00
ms_PickerColor = color_cast<ColorHSVA>(ColorPick);
static SPopupMenuId s_PopupColorPickerId;
UI()->DoPopupMenu(&s_PopupColorPickerId, UI()->MouseX(), UI()->MouseY(), 180, 150, this, PopupColorPicker);
}
if(UI()->HotItem() == &ms_SVPicker || UI()->HotItem() == &ms_HuePicker)
{
2019-04-26 12:06:32 +00:00
ColorRGBA c = color_cast<ColorRGBA>(ms_PickerColor);
NewColor = ((int)(c.r * 255.0f) & 0xff) << 24 | ((int)(c.g * 255.0f) & 0xff) << 16 | ((int)(c.b * 255.0f) & 0xff) << 8 | (pProps[i].m_Value & 0xff);
}
//
2010-05-29 07:25:38 +00:00
if(NewColor != pProps[i].m_Value)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
*pNewVal = NewColor;
Change = i;
2008-01-12 12:27:55 +00:00
}
else if(NewColorHex != pProps[i].m_Value)
{
*pNewVal = NewColorHex;
Change = i;
}
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
else if(pProps[i].m_Type == PROPTYPE_IMAGE)
2008-01-13 22:37:58 +00:00
{
2010-05-29 07:25:38 +00:00
char aBuf[64];
if(pProps[i].m_Value < 0)
2011-03-20 16:04:03 +00:00
str_copy(aBuf, "None", sizeof(aBuf));
2008-01-17 23:09:49 +00:00
else
str_copy(aBuf, m_Map.m_vpImages[pProps[i].m_Value]->m_aName);
2010-05-29 07:25:38 +00:00
float FontSize = ScaleFontSize(aBuf, sizeof(aBuf), 10.0f, Shifter.w);
if(DoButton_Ex(&pIDs[i], aBuf, 0, &Shifter, 0, nullptr, IGraphics::CORNER_ALL, FontSize))
2010-05-29 07:25:38 +00:00
PopupSelectImageInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY());
int r = PopupSelectImageResult();
2008-01-17 23:09:49 +00:00
if(r >= -1)
2008-01-13 22:37:58 +00:00
{
2010-05-29 07:25:38 +00:00
*pNewVal = r;
Change = i;
2008-01-13 22:37:58 +00:00
}
}
else if(pProps[i].m_Type == PROPTYPE_SHIFT)
{
CUIRect Left, Right, Up, Down;
2022-01-26 19:19:44 +00:00
Shifter.VSplitMid(&Left, &Up, 2.0f);
Left.VSplitLeft(10.0f, &Left, &Shifter);
Shifter.VSplitRight(10.0f, &Shifter, &Right);
Shifter.Draw(ColorRGBA(1, 1, 1, 0.5f), 0, 0.0f);
UI()->DoLabel(&Shifter, "X", 10.0f, TEXTALIGN_MC);
Up.VSplitLeft(10.0f, &Up, &Shifter);
Shifter.VSplitRight(10.0f, &Shifter, &Down);
Shifter.Draw(ColorRGBA(1, 1, 1, 0.5f), 0, 0.0f);
UI()->DoLabel(&Shifter, "Y", 10.0f, TEXTALIGN_MC);
2011-03-20 16:04:03 +00:00
if(DoButton_ButtonDec(&pIDs[i], "-", 0, &Left, 0, "Left"))
{
*pNewVal = DIRECTION_LEFT;
Change = i;
}
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 3, "+", 0, &Right, 0, "Right"))
{
*pNewVal = DIRECTION_RIGHT;
Change = i;
}
if(DoButton_ButtonDec(((char *)&pIDs[i]) + 1, "-", 0, &Up, 0, "Up"))
{
*pNewVal = DIRECTION_UP;
Change = i;
}
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 2, "+", 0, &Down, 0, "Down"))
{
*pNewVal = DIRECTION_DOWN;
Change = i;
}
}
2014-10-08 15:33:06 +00:00
else if(pProps[i].m_Type == PROPTYPE_SOUND)
{
char aBuf[64];
if(pProps[i].m_Value < 0)
str_copy(aBuf, "None", sizeof(aBuf));
else
str_copy(aBuf, m_Map.m_vpSounds[pProps[i].m_Value]->m_aName);
2014-10-08 15:33:06 +00:00
float FontSize = ScaleFontSize(aBuf, sizeof(aBuf), 10.0f, Shifter.w);
if(DoButton_Ex(&pIDs[i], aBuf, 0, &Shifter, 0, nullptr, IGraphics::CORNER_ALL, FontSize))
2014-10-08 15:33:06 +00:00
PopupSelectSoundInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY());
int r = PopupSelectSoundResult();
if(r >= -1)
{
*pNewVal = r;
Change = i;
}
}
else if(pProps[i].m_Type == PROPTYPE_AUTOMAPPER)
{
char aBuf[64];
if(pProps[i].m_Value < 0 || pProps[i].m_Min < 0 || pProps[i].m_Min >= (int)m_Map.m_vpImages.size())
str_copy(aBuf, "None", sizeof(aBuf));
else
str_copy(aBuf, m_Map.m_vpImages[pProps[i].m_Min]->m_AutoMapper.GetConfigName(pProps[i].m_Value));
float FontSize = ScaleFontSize(aBuf, sizeof(aBuf), 10.0f, Shifter.w);
if(DoButton_Ex(&pIDs[i], aBuf, 0, &Shifter, 0, nullptr, IGraphics::CORNER_ALL, FontSize))
PopupSelectConfigAutoMapInvoke(pProps[i].m_Value, UI()->MouseX(), UI()->MouseY());
int r = PopupSelectConfigAutoMapResult();
if(r >= -1)
{
*pNewVal = r;
Change = i;
}
}
2020-01-23 19:26:06 +00:00
else if(pProps[i].m_Type == PROPTYPE_ENVELOPE)
{
CUIRect Inc, Dec;
char aBuf[8];
2020-01-23 20:24:48 +00:00
int CurValue = pProps[i].m_Value;
2020-01-23 19:26:06 +00:00
Shifter.VSplitRight(10.0f, &Shifter, &Inc);
Shifter.VSplitLeft(10.0f, &Dec, &Shifter);
2020-01-23 20:24:48 +00:00
if(CurValue <= 0)
str_copy(aBuf, "None:", sizeof(aBuf));
else if(m_Map.m_vpEnvelopes[CurValue - 1]->m_aName[0])
{
str_format(aBuf, sizeof(aBuf), "%s:", m_Map.m_vpEnvelopes[CurValue - 1]->m_aName);
if(!str_endswith(aBuf, ":"))
{
aBuf[sizeof(aBuf) - 2] = ':';
aBuf[sizeof(aBuf) - 1] = '\0';
}
}
2020-01-23 19:48:42 +00:00
else
aBuf[0] = '\0';
2020-01-23 19:26:06 +00:00
int NewVal = UiDoValueSelector((char *)&pIDs[i], &Shifter, aBuf, CurValue, 0, m_Map.m_vpEnvelopes.size(), 1, 1.0f, "Set Envelope", false, false, IGraphics::CORNER_NONE);
if(NewVal != CurValue)
{
*pNewVal = NewVal;
Change = i;
}
2020-01-23 19:26:06 +00:00
if(DoButton_ButtonDec((char *)&pIDs[i] + 1, nullptr, 0, &Dec, 0, "Previous Envelope"))
2020-01-23 19:26:06 +00:00
{
*pNewVal = pProps[i].m_Value - 1;
2020-01-23 19:26:06 +00:00
Change = i;
}
if(DoButton_ButtonInc(((char *)&pIDs[i]) + 2, nullptr, 0, &Inc, 0, "Next Envelope"))
2020-01-23 19:26:06 +00:00
{
*pNewVal = pProps[i].m_Value + 1;
2020-01-23 19:26:06 +00:00
Change = i;
}
}
2007-05-22 15:03:32 +00:00
}
2008-03-21 00:13:55 +00:00
2010-05-29 07:25:38 +00:00
return Change;
2007-05-22 15:03:32 +00:00
}
void CEditor::RenderLayers(CUIRect LayersBox)
2007-05-22 15:03:32 +00:00
{
const float RowHeight = 12.0f;
2010-05-29 07:25:38 +00:00
char aBuf[64];
2007-12-02 17:55:45 +00:00
2023-03-15 17:15:43 +00:00
CUIRect UnscrolledLayersBox = LayersBox;
static CScrollRegion s_ScrollRegion;
vec2 ScrollOffset(0.0f, 0.0f);
CScrollRegionParams ScrollParams;
ScrollParams.m_ScrollbarWidth = 10.0f;
ScrollParams.m_ScrollbarMargin = 3.0f;
ScrollParams.m_ScrollUnit = RowHeight * 5.0f;
s_ScrollRegion.Begin(&LayersBox, &ScrollOffset, &ScrollParams);
LayersBox.y += ScrollOffset.y;
2023-03-15 17:15:43 +00:00
enum
{
OP_NONE = 0,
OP_CLICK,
OP_LAYER_DRAG,
OP_GROUP_DRAG
};
static int s_Operation = OP_NONE;
static const void *s_pDraggedButton = 0;
static float s_InitialMouseY = 0;
static float s_InitialCutHeight = 0;
int GroupAfterDraggedLayer = -1;
int LayerAfterDraggedLayer = -1;
bool DraggedPositionFound = false;
bool MoveLayers = false;
bool MoveGroup = false;
bool StartDragLayer = false;
bool StartDragGroup = false;
std::vector<int> vButtonsPerGroup;
vButtonsPerGroup.reserve(m_Map.m_vpGroups.size());
for(CLayerGroup *pGroup : m_Map.m_vpGroups)
{
vButtonsPerGroup.push_back(pGroup->m_vpLayers.size() + 1);
}
if(!UI()->CheckActiveItem(s_pDraggedButton))
s_Operation = OP_NONE;
if(s_Operation == OP_LAYER_DRAG || s_Operation == OP_GROUP_DRAG)
{
float MinDraggableValue = UnscrolledLayersBox.y;
float MaxDraggableValue = MinDraggableValue;
for(int NumButtons : vButtonsPerGroup)
{
MaxDraggableValue += NumButtons * (RowHeight + 2.0f) + 5.0f;
}
MaxDraggableValue += ScrollOffset.y;
if(s_Operation == OP_GROUP_DRAG)
{
MaxDraggableValue -= vButtonsPerGroup[m_SelectedGroup] * (RowHeight + 2.0f) + 5.0f;
}
else if(s_Operation == OP_LAYER_DRAG)
{
MinDraggableValue += RowHeight + 2.0f;
MaxDraggableValue -= m_vSelectedLayers.size() * (RowHeight + 2.0f) + 5.0f;
}
UnscrolledLayersBox.HSplitTop(s_InitialCutHeight, nullptr, &UnscrolledLayersBox);
UnscrolledLayersBox.y -= s_InitialMouseY - UI()->MouseY();
UnscrolledLayersBox.y = clamp(UnscrolledLayersBox.y, MinDraggableValue, MaxDraggableValue);
UnscrolledLayersBox.w = LayersBox.w;
}
static bool s_ScrollToSelectionNext = false;
const bool ScrollToSelection = SelectLayerByTile() || s_ScrollToSelectionNext;
s_ScrollToSelectionNext = false;
2010-05-29 07:25:38 +00:00
// render layers
2022-08-13 17:02:55 +00:00
for(int g = 0; g < (int)m_Map.m_vpGroups.size(); g++)
2007-12-02 17:55:45 +00:00
{
2023-03-15 17:15:43 +00:00
if(s_Operation == OP_LAYER_DRAG && g > 0 && !DraggedPositionFound && UI()->MouseY() < LayersBox.y + RowHeight / 2)
{
DraggedPositionFound = true;
GroupAfterDraggedLayer = g;
LayerAfterDraggedLayer = m_Map.m_vpGroups[g - 1]->m_vpLayers.size();
CUIRect Slot;
LayersBox.HSplitTop(m_vSelectedLayers.size() * (RowHeight + 2.0f), &Slot, &LayersBox);
s_ScrollRegion.AddRect(Slot);
}
CUIRect Slot, VisibleToggle;
2023-03-15 17:15:43 +00:00
if(s_Operation == OP_GROUP_DRAG)
{
if(g == m_SelectedGroup)
{
UnscrolledLayersBox.HSplitTop(RowHeight, &Slot, &UnscrolledLayersBox);
UnscrolledLayersBox.HSplitTop(2.0f, nullptr, &UnscrolledLayersBox);
}
else if(!DraggedPositionFound && UI()->MouseY() < LayersBox.y + RowHeight * vButtonsPerGroup[g] / 2 + 3.0f)
{
DraggedPositionFound = true;
GroupAfterDraggedLayer = g;
CUIRect TmpSlot;
if(m_Map.m_vpGroups[m_SelectedGroup]->m_Collapse)
LayersBox.HSplitTop(RowHeight + 7.0f, &TmpSlot, &LayersBox);
else
LayersBox.HSplitTop(vButtonsPerGroup[m_SelectedGroup] * (RowHeight + 2.0f) + 5.0f, &TmpSlot, &LayersBox);
s_ScrollRegion.AddRect(TmpSlot, false);
}
}
if(s_Operation != OP_GROUP_DRAG || g != m_SelectedGroup)
{
LayersBox.HSplitTop(RowHeight, &Slot, &LayersBox);
CUIRect TmpRect;
LayersBox.HSplitTop(2.0f, &TmpRect, &LayersBox);
s_ScrollRegion.AddRect(TmpRect);
}
if(s_ScrollRegion.AddRect(Slot))
2022-08-13 17:02:55 +00:00
{
Slot.VSplitLeft(15.0f, &VisibleToggle, &Slot);
if(DoButton_FontIcon(&m_Map.m_vpGroups[g]->m_Visible, m_Map.m_vpGroups[g]->m_Visible ? FONT_ICON_EYE : FONT_ICON_EYE_SLASH, m_Map.m_vpGroups[g]->m_Collapse ? 1 : 0, &VisibleToggle, 0, "Toggle group visibility", IGraphics::CORNER_L, 8.0f))
2022-08-13 17:02:55 +00:00
m_Map.m_vpGroups[g]->m_Visible = !m_Map.m_vpGroups[g]->m_Visible;
2022-08-13 17:02:55 +00:00
str_format(aBuf, sizeof(aBuf), "#%d %s", g, m_Map.m_vpGroups[g]->m_aName);
float FontSize = 10.0f;
while(TextRender()->TextWidth(FontSize, aBuf, -1, -1.0f) > Slot.w && FontSize >= 7.0f)
2022-08-13 17:02:55 +00:00
FontSize--;
2023-03-15 17:15:43 +00:00
bool Clicked;
bool Abrupted;
if(int Result = DoButton_DraggableEx(&m_Map.m_vpGroups[g], aBuf, g == m_SelectedGroup, &Slot, &Clicked, &Abrupted,
2022-08-13 17:02:55 +00:00
BUTTON_CONTEXT, m_Map.m_vpGroups[g]->m_Collapse ? "Select group. Shift click to select all layers. Double click to expand." : "Select group. Shift click to select all layers. Double click to collapse.", IGraphics::CORNER_R, FontSize))
2008-01-12 12:27:55 +00:00
{
2023-03-15 17:15:43 +00:00
if(s_Operation == OP_NONE)
{
s_InitialMouseY = UI()->MouseY();
s_InitialCutHeight = s_InitialMouseY - UnscrolledLayersBox.y;
s_Operation = OP_CLICK;
2010-05-29 07:25:38 +00:00
2023-03-15 17:15:43 +00:00
if(g != m_SelectedGroup)
SelectLayer(0, g);
}
if(Abrupted)
s_Operation = OP_NONE;
if(s_Operation == OP_CLICK)
{
2023-03-15 17:15:43 +00:00
if(absolute(UI()->MouseY() - s_InitialMouseY) > 5)
StartDragGroup = true;
s_pDraggedButton = &m_Map.m_vpGroups[g];
}
if(s_Operation == OP_CLICK && Clicked)
{
if(g != m_SelectedGroup)
SelectLayer(0, g);
if(Input()->ShiftIsPressed() && m_SelectedGroup == g)
{
2023-03-15 17:15:43 +00:00
m_vSelectedLayers.clear();
for(size_t i = 0; i < m_Map.m_vpGroups[g]->m_vpLayers.size(); i++)
{
AddSelectedLayer(i);
}
}
2010-05-29 07:25:38 +00:00
2023-03-15 17:15:43 +00:00
if(Result == 2)
2023-04-01 21:18:27 +00:00
{
static SPopupMenuId s_PopupGroupId;
UI()->DoPopupMenu(&s_PopupGroupId, UI()->MouseX(), UI()->MouseY(), 145, 256, this, PopupGroup);
2023-04-01 21:18:27 +00:00
}
2023-03-15 17:15:43 +00:00
if(!m_Map.m_vpGroups[g]->m_vpLayers.empty() && Input()->MouseDoubleClick())
m_Map.m_vpGroups[g]->m_Collapse ^= 1;
s_Operation = OP_NONE;
}
if(s_Operation == OP_GROUP_DRAG && Clicked)
MoveGroup = true;
}
2023-04-28 23:13:47 +00:00
else if(s_pDraggedButton == &m_Map.m_vpGroups[g])
{
s_Operation = OP_NONE;
}
2022-08-13 17:02:55 +00:00
}
2022-08-13 17:02:55 +00:00
for(int i = 0; i < (int)m_Map.m_vpGroups[g]->m_vpLayers.size(); i++)
{
if(m_Map.m_vpGroups[g]->m_Collapse)
2022-08-13 17:02:55 +00:00
continue;
bool IsLayerSelected = false;
if(m_SelectedGroup == g)
{
for(const auto &Selected : m_vSelectedLayers)
{
if(Selected == i)
{
IsLayerSelected = true;
break;
}
}
2022-08-13 17:02:55 +00:00
}
2023-03-15 17:15:43 +00:00
if(s_Operation == OP_GROUP_DRAG && g == m_SelectedGroup)
{
UnscrolledLayersBox.HSplitTop(RowHeight + 2.0f, &Slot, &UnscrolledLayersBox);
}
else if(s_Operation == OP_LAYER_DRAG)
{
if(IsLayerSelected)
{
UnscrolledLayersBox.HSplitTop(RowHeight + 2.0f, &Slot, &UnscrolledLayersBox);
}
else
{
if(!DraggedPositionFound && UI()->MouseY() < LayersBox.y + RowHeight / 2)
{
DraggedPositionFound = true;
GroupAfterDraggedLayer = g + 1;
LayerAfterDraggedLayer = i;
for(size_t j = 0; j < m_vSelectedLayers.size(); j++)
{
LayersBox.HSplitTop(RowHeight + 2.0f, nullptr, &LayersBox);
s_ScrollRegion.AddRect(Slot);
}
}
LayersBox.HSplitTop(RowHeight + 2.0f, &Slot, &LayersBox);
if(!s_ScrollRegion.AddRect(Slot, ScrollToSelection && IsLayerSelected))
continue;
}
}
else
{
LayersBox.HSplitTop(RowHeight + 2.0f, &Slot, &LayersBox);
if(!s_ScrollRegion.AddRect(Slot, ScrollToSelection && IsLayerSelected))
continue;
}
Slot.HSplitTop(RowHeight, &Slot, nullptr);
CUIRect Button;
Slot.VSplitLeft(12.0f, nullptr, &Slot);
Slot.VSplitLeft(15.0f, &VisibleToggle, &Button);
2008-01-12 12:27:55 +00:00
if(DoButton_FontIcon(&m_Map.m_vpGroups[g]->m_vpLayers[i]->m_Visible, m_Map.m_vpGroups[g]->m_vpLayers[i]->m_Visible ? FONT_ICON_EYE : FONT_ICON_EYE_SLASH, 0, &VisibleToggle, 0, "Toggle layer visibility", IGraphics::CORNER_L, 8.0f))
2022-08-13 17:02:55 +00:00
m_Map.m_vpGroups[g]->m_vpLayers[i]->m_Visible = !m_Map.m_vpGroups[g]->m_vpLayers[i]->m_Visible;
2008-01-12 12:27:55 +00:00
2022-08-13 17:02:55 +00:00
if(m_Map.m_vpGroups[g]->m_vpLayers[i]->m_aName[0])
str_copy(aBuf, m_Map.m_vpGroups[g]->m_vpLayers[i]->m_aName, sizeof(aBuf));
else
{
if(m_Map.m_vpGroups[g]->m_vpLayers[i]->m_Type == LAYERTYPE_TILES)
{
2022-08-13 17:02:55 +00:00
CLayerTiles *pTiles = (CLayerTiles *)m_Map.m_vpGroups[g]->m_vpLayers[i];
str_copy(aBuf, pTiles->m_Image >= 0 ? m_Map.m_vpImages[pTiles->m_Image]->m_aName : "Tiles", sizeof(aBuf));
}
2022-08-13 17:02:55 +00:00
else if(m_Map.m_vpGroups[g]->m_vpLayers[i]->m_Type == LAYERTYPE_QUADS)
{
CLayerQuads *pQuads = (CLayerQuads *)m_Map.m_vpGroups[g]->m_vpLayers[i];
str_copy(aBuf, pQuads->m_Image >= 0 ? m_Map.m_vpImages[pQuads->m_Image]->m_aName : "Quads", sizeof(aBuf));
}
else if(m_Map.m_vpGroups[g]->m_vpLayers[i]->m_Type == LAYERTYPE_SOUNDS)
{
CLayerSounds *pSounds = (CLayerSounds *)m_Map.m_vpGroups[g]->m_vpLayers[i];
str_copy(aBuf, pSounds->m_Sound >= 0 ? m_Map.m_vpSounds[pSounds->m_Sound]->m_aName : "Sounds", sizeof(aBuf));
}
if(str_length(aBuf) > 11)
str_format(aBuf, sizeof(aBuf), "%.8s...", aBuf);
}
2011-07-12 01:14:46 +00:00
2022-08-13 17:02:55 +00:00
float FontSize = 10.0f;
while(TextRender()->TextWidth(FontSize, aBuf, -1, -1.0f) > Button.w && FontSize >= 7.0f)
2022-08-13 17:02:55 +00:00
FontSize--;
2018-10-02 01:52:01 +00:00
int Checked = IsLayerSelected ? 1 : 0;
if(m_Map.m_vpGroups[g]->m_vpLayers[i]->IsEntitiesLayer())
2022-08-13 17:02:55 +00:00
{
Checked += 6;
}
2023-03-15 17:15:43 +00:00
bool Clicked;
bool Abrupted;
if(int Result = DoButton_DraggableEx(m_Map.m_vpGroups[g]->m_vpLayers[i], aBuf, Checked, &Button, &Clicked, &Abrupted,
2022-08-13 17:02:55 +00:00
BUTTON_CONTEXT, "Select layer. Shift click to select multiple.", IGraphics::CORNER_R, FontSize))
{
2023-03-15 17:15:43 +00:00
if(s_Operation == OP_NONE)
2008-01-12 12:27:55 +00:00
{
2023-03-15 17:15:43 +00:00
s_InitialMouseY = UI()->MouseY();
s_InitialCutHeight = s_InitialMouseY - UnscrolledLayersBox.y;
s_Operation = OP_CLICK;
if(!Input()->ShiftIsPressed() && !IsLayerSelected)
2020-02-28 15:25:27 +00:00
{
2022-08-13 17:02:55 +00:00
SelectLayer(i, g);
}
}
2023-03-15 17:15:43 +00:00
if(Abrupted)
s_Operation = OP_NONE;
if(s_Operation == OP_CLICK)
2022-08-13 17:02:55 +00:00
{
2023-03-15 17:15:43 +00:00
if(absolute(UI()->MouseY() - s_InitialMouseY) > 5)
2022-08-13 17:02:55 +00:00
{
2023-03-15 17:15:43 +00:00
bool EntitiesLayerSelected = false;
for(int k : m_vSelectedLayers)
{
if(m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers[k]->IsEntitiesLayer())
EntitiesLayerSelected = true;
}
if(!EntitiesLayerSelected)
StartDragLayer = true;
2022-08-13 17:02:55 +00:00
}
2023-03-15 17:15:43 +00:00
s_pDraggedButton = m_Map.m_vpGroups[g]->m_vpLayers[i];
}
if(s_Operation == OP_CLICK && Clicked)
{
static SLayerPopupContext s_LayerPopupContext = {};
s_LayerPopupContext.m_pEditor = this;
2023-03-15 17:15:43 +00:00
if(Result == 1)
2022-08-13 17:02:55 +00:00
{
2023-03-15 17:15:43 +00:00
if(Input()->ShiftIsPressed() && m_SelectedGroup == g)
2020-02-28 15:25:27 +00:00
{
2023-03-15 17:15:43 +00:00
auto Position = std::find(m_vSelectedLayers.begin(), m_vSelectedLayers.end(), i);
if(Position != m_vSelectedLayers.end())
m_vSelectedLayers.erase(Position);
2022-08-13 17:02:55 +00:00
else
2023-03-15 17:15:43 +00:00
AddSelectedLayer(i);
}
else if(!Input()->ShiftIsPressed())
{
SelectLayer(i, g);
2020-02-28 15:25:27 +00:00
}
2023-03-15 17:15:43 +00:00
}
else if(Result == 2)
{
if(!IsLayerSelected)
{
SelectLayer(i, g);
}
if(m_vSelectedLayers.size() > 1)
{
bool AllTile = true;
for(size_t j = 0; AllTile && j < m_vSelectedLayers.size(); j++)
{
if(m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers[m_vSelectedLayers[j]]->m_Type == LAYERTYPE_TILES)
s_LayerPopupContext.m_vpLayers.push_back((CLayerTiles *)m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers[m_vSelectedLayers[j]]);
else
AllTile = false;
}
2020-02-28 15:25:27 +00:00
2023-03-15 17:15:43 +00:00
// Don't allow editing if all selected layers are tile layers
if(!AllTile)
s_LayerPopupContext.m_vpLayers.clear();
}
else
2022-08-13 17:02:55 +00:00
s_LayerPopupContext.m_vpLayers.clear();
2023-03-15 17:15:43 +00:00
UI()->DoPopupMenu(&s_LayerPopupContext, UI()->MouseX(), UI()->MouseY(), 120, 320, &s_LayerPopupContext, PopupLayer);
2020-02-28 15:25:27 +00:00
}
2010-05-29 07:25:38 +00:00
2023-03-15 17:15:43 +00:00
s_Operation = OP_NONE;
}
if(s_Operation == OP_LAYER_DRAG && Clicked)
{
MoveLayers = true;
2022-08-13 17:02:55 +00:00
}
2008-01-12 12:27:55 +00:00
}
2023-04-28 23:13:47 +00:00
else if(s_pDraggedButton == m_Map.m_vpGroups[g]->m_vpLayers[i])
{
s_Operation = OP_NONE;
}
2007-12-02 17:55:45 +00:00
}
2023-03-15 17:15:43 +00:00
if(s_Operation != OP_GROUP_DRAG || g != m_SelectedGroup)
{
LayersBox.HSplitTop(5.0f, &Slot, &LayersBox);
s_ScrollRegion.AddRect(Slot);
}
}
if(!DraggedPositionFound && s_Operation == OP_LAYER_DRAG)
{
GroupAfterDraggedLayer = m_Map.m_vpGroups.size();
LayerAfterDraggedLayer = m_Map.m_vpGroups[GroupAfterDraggedLayer - 1]->m_vpLayers.size();
CUIRect TmpSlot;
LayersBox.HSplitTop(m_vSelectedLayers.size() * (RowHeight + 2.0f), &TmpSlot, &LayersBox);
s_ScrollRegion.AddRect(TmpSlot);
}
if(!DraggedPositionFound && s_Operation == OP_GROUP_DRAG)
{
GroupAfterDraggedLayer = m_Map.m_vpGroups.size();
CUIRect TmpSlot;
if(m_Map.m_vpGroups[m_SelectedGroup]->m_Collapse)
LayersBox.HSplitTop(RowHeight + 7.0f, &TmpSlot, &LayersBox);
else
LayersBox.HSplitTop(vButtonsPerGroup[m_SelectedGroup] * (RowHeight + 2.0f) + 5.0f, &TmpSlot, &LayersBox);
s_ScrollRegion.AddRect(TmpSlot, false);
}
if(MoveLayers && 1 <= GroupAfterDraggedLayer && GroupAfterDraggedLayer <= (int)m_Map.m_vpGroups.size())
{
std::vector<CLayer *> &vpNewGroupLayers = m_Map.m_vpGroups[GroupAfterDraggedLayer - 1]->m_vpLayers;
if(0 <= LayerAfterDraggedLayer && LayerAfterDraggedLayer <= (int)vpNewGroupLayers.size())
{
std::vector<CLayer *> vpSelectedLayers;
std::vector<CLayer *> &vpSelectedGroupLayers = m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers;
CLayer *pNextLayer = nullptr;
if(LayerAfterDraggedLayer < (int)vpNewGroupLayers.size())
pNextLayer = vpNewGroupLayers[LayerAfterDraggedLayer];
std::sort(m_vSelectedLayers.begin(), m_vSelectedLayers.end(), std::greater<>());
for(int k : m_vSelectedLayers)
{
vpSelectedLayers.insert(vpSelectedLayers.begin(), vpSelectedGroupLayers[k]);
}
for(int k : m_vSelectedLayers)
{
vpSelectedGroupLayers.erase(vpSelectedGroupLayers.begin() + k);
}
auto InsertPosition = std::find(vpNewGroupLayers.begin(), vpNewGroupLayers.end(), pNextLayer);
vpNewGroupLayers.insert(InsertPosition, vpSelectedLayers.begin(), vpSelectedLayers.end());
m_SelectedGroup = GroupAfterDraggedLayer - 1;
m_vSelectedLayers.clear();
m_vSelectedQuads.clear();
m_Map.m_Modified = true;
}
}
if(MoveGroup && 0 <= GroupAfterDraggedLayer && GroupAfterDraggedLayer <= (int)m_Map.m_vpGroups.size())
{
CLayerGroup *pSelectedGroup = m_Map.m_vpGroups[m_SelectedGroup];
CLayerGroup *pNextGroup = nullptr;
if(GroupAfterDraggedLayer < (int)m_Map.m_vpGroups.size())
pNextGroup = m_Map.m_vpGroups[GroupAfterDraggedLayer];
m_Map.m_vpGroups.erase(m_Map.m_vpGroups.begin() + m_SelectedGroup);
auto InsertPosition = std::find(m_Map.m_vpGroups.begin(), m_Map.m_vpGroups.end(), pNextGroup);
m_Map.m_vpGroups.insert(InsertPosition, pSelectedGroup);
m_SelectedGroup = InsertPosition - m_Map.m_vpGroups.begin();
2023-03-15 17:15:43 +00:00
m_Map.m_Modified = true;
}
if(MoveLayers || MoveGroup)
s_Operation = OP_NONE;
if(StartDragLayer)
s_Operation = OP_LAYER_DRAG;
if(StartDragGroup)
s_Operation = OP_GROUP_DRAG;
if(s_Operation == OP_LAYER_DRAG || s_Operation == OP_GROUP_DRAG)
{
s_ScrollRegion.DoEdgeScrolling();
UI()->SetActiveItem(s_pDraggedButton);
2007-12-02 17:55:45 +00:00
}
2010-05-29 07:25:38 +00:00
2023-03-15 17:15:43 +00:00
if(Input()->KeyPress(KEY_DOWN) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && s_Operation == OP_NONE)
{
if(Input()->ShiftIsPressed())
{
if(m_vSelectedLayers[m_vSelectedLayers.size() - 1] < (int)m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers.size() - 1)
AddSelectedLayer(m_vSelectedLayers[m_vSelectedLayers.size() - 1] + 1);
}
else
{
int CurrentLayer = 0;
for(const auto &Selected : m_vSelectedLayers)
CurrentLayer = maximum(Selected, CurrentLayer);
SelectLayer(CurrentLayer);
if(m_vSelectedLayers[0] < (int)m_Map.m_vpGroups[m_SelectedGroup]->m_vpLayers.size() - 1)
{
SelectLayer(m_vSelectedLayers[0] + 1);
}
else
{
for(size_t Group = m_SelectedGroup + 1; Group < m_Map.m_vpGroups.size(); Group++)
{
if(!m_Map.m_vpGroups[Group]->m_vpLayers.empty())
{
SelectLayer(0, Group);
break;
}
}
}
}
s_ScrollToSelectionNext = true;
}
2023-03-15 17:15:43 +00:00
if(Input()->KeyPress(KEY_UP) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && s_Operation == OP_NONE)
{
if(Input()->ShiftIsPressed())
{
if(m_vSelectedLayers[m_vSelectedLayers.size() - 1] > 0)
AddSelectedLayer(m_vSelectedLayers[m_vSelectedLayers.size() - 1] - 1);
}
else
{
int CurrentLayer = std::numeric_limits<int>::max();
for(const auto &Selected : m_vSelectedLayers)
CurrentLayer = minimum(Selected, CurrentLayer);
SelectLayer(CurrentLayer);
if(m_vSelectedLayers[0] > 0)
{
SelectLayer(m_vSelectedLayers[0] - 1);
}
else
{
for(int Group = m_SelectedGroup - 1; Group >= 0; Group--)
{
if(!m_Map.m_vpGroups[Group]->m_vpLayers.empty())
{
SelectLayer(m_Map.m_vpGroups[Group]->m_vpLayers.size() - 1, Group);
break;
}
}
}
}
s_ScrollToSelectionNext = true;
}
CUIRect AddGroupButton;
LayersBox.HSplitTop(RowHeight + 1.0f, &AddGroupButton, &LayersBox);
if(s_ScrollRegion.AddRect(AddGroupButton))
2007-12-02 17:55:45 +00:00
{
AddGroupButton.HSplitTop(RowHeight, &AddGroupButton, 0);
static int s_AddGroupButton = 0;
if(DoButton_Editor(&s_AddGroupButton, "Add group", 0, &AddGroupButton, IGraphics::CORNER_R, "Adds a new group"))
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
m_Map.NewGroup();
m_SelectedGroup = m_Map.m_vpGroups.size() - 1;
2007-12-02 17:55:45 +00:00
}
}
s_ScrollRegion.End();
}
bool CEditor::SelectLayerByTile()
{
// ctrl+rightclick a map index to select the layer that has a tile there
static bool s_CtrlClick = false;
static int s_Selected = 0;
int MatchedGroup = -1;
int MatchedLayer = -1;
int Matches = 0;
bool IsFound = false;
if(UI()->MouseButton(1) && Input()->ModifierIsPressed())
{
if(s_CtrlClick)
return false;
s_CtrlClick = true;
for(size_t g = 0; g < m_Map.m_vpGroups.size(); g++)
{
for(size_t l = 0; l < m_Map.m_vpGroups[g]->m_vpLayers.size(); l++)
{
if(IsFound)
continue;
if(m_Map.m_vpGroups[g]->m_vpLayers[l]->m_Type != LAYERTYPE_TILES)
continue;
CLayerTiles *pTiles = (CLayerTiles *)m_Map.m_vpGroups[g]->m_vpLayers[l];
int x = (int)UI()->MouseWorldX() / 32 + m_Map.m_vpGroups[g]->m_OffsetX;
int y = (int)UI()->MouseWorldY() / 32 + m_Map.m_vpGroups[g]->m_OffsetY;
if(x < 0 || x >= pTiles->m_Width)
continue;
if(y < 0 || y >= pTiles->m_Height)
continue;
CTile Tile = pTiles->GetTile(x, y);
if(Tile.m_Index)
{
if(MatchedGroup == -1)
{
MatchedGroup = g;
MatchedLayer = l;
}
if(++Matches > s_Selected)
{
s_Selected++;
MatchedGroup = g;
MatchedLayer = l;
IsFound = true;
}
}
}
}
if(MatchedGroup != -1 && MatchedLayer != -1)
{
if(!IsFound)
s_Selected = 1;
SelectLayer(MatchedLayer, MatchedGroup);
return true;
}
}
else
s_CtrlClick = false;
return false;
2008-01-12 12:27:55 +00:00
}
bool CEditor::ReplaceImage(const char *pFileName, int StorageType, bool CheckDuplicate)
2008-01-19 12:32:08 +00:00
{
// check if we have that image already
char aBuf[128];
IStorage::StripPathAndExtension(pFileName, aBuf, sizeof(aBuf));
if(CheckDuplicate)
{
for(const auto &pImage : m_Map.m_vpImages)
{
if(!str_comp(pImage->m_aName, aBuf))
{
ShowFileDialogError("Image named '%s' was already added.", pImage->m_aName);
return false;
}
}
}
CEditorImage ImgInfo(this);
if(!Graphics()->LoadPNG(&ImgInfo, pFileName, StorageType))
{
ShowFileDialogError("Failed to load image from file '%s'.", pFileName);
return false;
}
2010-05-29 07:25:38 +00:00
CEditorImage *pImg = m_Map.m_vpImages[m_SelectedImage];
Graphics()->UnloadTexture(&(pImg->m_Texture));
free(pImg->m_pData);
pImg->m_pData = nullptr;
2010-05-29 07:25:38 +00:00
*pImg = ImgInfo;
str_copy(pImg->m_aName, aBuf);
2019-07-17 01:00:09 +00:00
pImg->m_External = IsVanillaImage(pImg->m_aName);
if(!pImg->m_External && g_Config.m_ClEditorDilate == 1 && pImg->m_Format == CImageInfo::FORMAT_RGBA)
{
int ColorChannelCount = 0;
if(ImgInfo.m_Format == CImageInfo::FORMAT_RGBA)
ColorChannelCount = 4;
DilateImage((unsigned char *)ImgInfo.m_pData, ImgInfo.m_Width, ImgInfo.m_Height, ColorChannelCount);
}
pImg->m_AutoMapper.Load(pImg->m_aName);
int TextureLoadFlag = Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0)
TextureLoadFlag = 0;
pImg->m_Texture = Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, TextureLoadFlag, pFileName);
ImgInfo.m_pData = nullptr;
SortImages();
for(size_t i = 0; i < m_Map.m_vpImages.size(); ++i)
{
if(!str_comp(m_Map.m_vpImages[i]->m_aName, pImg->m_aName))
m_SelectedImage = i;
}
m_Dialog = DIALOG_NONE;
return true;
2008-01-19 12:32:08 +00:00
}
bool CEditor::ReplaceImageCallback(const char *pFileName, int StorageType, void *pUser)
{
return static_cast<CEditor *>(pUser)->ReplaceImage(pFileName, StorageType, true);
}
bool CEditor::AddImage(const char *pFileName, int StorageType, void *pUser)
2008-01-13 16:30:30 +00:00
{
2010-05-29 07:25:38 +00:00
CEditor *pEditor = (CEditor *)pUser;
2008-01-13 16:30:30 +00:00
// check if we have that image already
char aBuf[128];
IStorage::StripPathAndExtension(pFileName, aBuf, sizeof(aBuf));
for(const auto &pImage : pEditor->m_Map.m_vpImages)
2010-05-29 07:25:38 +00:00
{
if(!str_comp(pImage->m_aName, aBuf))
{
pEditor->ShowFileDialogError("Image named '%s' was already added.", pImage->m_aName);
return false;
}
2010-05-29 07:25:38 +00:00
}
if(pEditor->m_Map.m_vpImages.size() >= 64) // hard limit for teeworlds
{
pEditor->m_PopupEventType = POPEVENT_IMAGE_MAX;
pEditor->m_PopupEventActivated = true;
return false;
}
CEditorImage ImgInfo(pEditor);
if(!pEditor->Graphics()->LoadPNG(&ImgInfo, pFileName, StorageType))
{
pEditor->ShowFileDialogError("Failed to load image from file '%s'.", pFileName);
return false;
}
CEditorImage *pImg = new CEditorImage(pEditor);
*pImg = ImgInfo;
pImg->m_External = IsVanillaImage(aBuf);
if(!pImg->m_External && g_Config.m_ClEditorDilate == 1 && pImg->m_Format == CImageInfo::FORMAT_RGBA)
{
int ColorChannelCount = 0;
if(ImgInfo.m_Format == CImageInfo::FORMAT_RGBA)
ColorChannelCount = 4;
DilateImage((unsigned char *)ImgInfo.m_pData, ImgInfo.m_Width, ImgInfo.m_Height, ColorChannelCount);
}
int TextureLoadFlag = pEditor->Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
if(ImgInfo.m_Width % 16 != 0 || ImgInfo.m_Height % 16 != 0)
TextureLoadFlag = 0;
pImg->m_Texture = pEditor->Graphics()->LoadTextureRaw(ImgInfo.m_Width, ImgInfo.m_Height, ImgInfo.m_Format, ImgInfo.m_pData, CImageInfo::FORMAT_AUTO, TextureLoadFlag, pFileName);
ImgInfo.m_pData = nullptr;
str_copy(pImg->m_aName, aBuf, sizeof(pImg->m_aName));
pImg->m_AutoMapper.Load(pImg->m_aName);
pEditor->m_Map.m_vpImages.push_back(pImg);
2010-06-02 16:12:32 +00:00
pEditor->SortImages();
if(pEditor->m_SelectedImage >= 0 && (size_t)pEditor->m_SelectedImage < pEditor->m_Map.m_vpImages.size())
{
for(int i = 0; i <= pEditor->m_SelectedImage; ++i)
if(!str_comp(pEditor->m_Map.m_vpImages[i]->m_aName, aBuf))
{
pEditor->m_SelectedImage++;
break;
}
}
pEditor->m_Dialog = DIALOG_NONE;
return true;
2008-01-13 16:30:30 +00:00
}
bool CEditor::AddSound(const char *pFileName, int StorageType, void *pUser)
{
CEditor *pEditor = (CEditor *)pUser;
2014-10-24 20:13:46 +00:00
// check if we have that sound already
char aBuf[128];
IStorage::StripPathAndExtension(pFileName, aBuf, sizeof(aBuf));
for(const auto &pSound : pEditor->m_Map.m_vpSounds)
{
if(!str_comp(pSound->m_aName, aBuf))
{
pEditor->ShowFileDialogError("Sound named '%s' was already added.", pSound->m_aName);
return false;
}
}
2014-10-11 12:50:16 +00:00
// load external
void *pData;
unsigned DataSize;
if(!pEditor->Storage()->ReadFile(pFileName, StorageType, &pData, &DataSize))
2014-10-24 23:07:24 +00:00
{
pEditor->ShowFileDialogError("Failed to open sound file '%s'.", pFileName);
return false;
2014-10-24 23:07:24 +00:00
}
2014-10-11 12:50:16 +00:00
// load sound
const int SoundId = pEditor->Sound()->LoadOpusFromMem(pData, DataSize, true);
if(SoundId == -1)
{
free(pData);
pEditor->ShowFileDialogError("Failed to load sound from file '%s'.", pFileName);
return false;
}
// add sound
2014-10-11 11:38:45 +00:00
CEditorSound *pSound = new CEditorSound(pEditor);
pSound->m_SoundID = SoundId;
pSound->m_DataSize = DataSize;
2014-10-11 12:50:16 +00:00
pSound->m_pData = pData;
str_copy(pSound->m_aName, aBuf, sizeof(pSound->m_aName));
pEditor->m_Map.m_vpSounds.push_back(pSound);
if(pEditor->m_SelectedSound >= 0 && (size_t)pEditor->m_SelectedSound < pEditor->m_Map.m_vpSounds.size())
{
for(int i = 0; i <= pEditor->m_SelectedSound; ++i)
if(!str_comp(pEditor->m_Map.m_vpSounds[i]->m_aName, aBuf))
{
pEditor->m_SelectedSound++;
break;
}
}
2015-07-09 00:08:14 +00:00
pEditor->m_Dialog = DIALOG_NONE;
return true;
}
bool CEditor::ReplaceSound(const char *pFileName, int StorageType, bool CheckDuplicate)
2014-11-09 13:58:28 +00:00
{
// check if we have that sound already
char aBuf[128];
IStorage::StripPathAndExtension(pFileName, aBuf, sizeof(aBuf));
if(CheckDuplicate)
{
for(const auto &pSound : m_Map.m_vpSounds)
{
if(!str_comp(pSound->m_aName, aBuf))
{
ShowFileDialogError("Sound named '%s' was already added.", pSound->m_aName);
return false;
}
}
}
2014-11-09 13:58:28 +00:00
// load external
void *pData;
unsigned DataSize;
if(!Storage()->ReadFile(pFileName, StorageType, &pData, &DataSize))
2014-11-09 13:58:28 +00:00
{
ShowFileDialogError("Failed to open sound file '%s'.", pFileName);
return false;
}
// load sound
const int SoundId = Sound()->LoadOpusFromMem(pData, DataSize, true);
if(SoundId == -1)
{
free(pData);
ShowFileDialogError("Failed to load sound from file '%s'.", pFileName);
return false;
2014-11-09 13:58:28 +00:00
}
CEditorSound *pSound = m_Map.m_vpSounds[m_SelectedSound];
2014-11-09 13:58:28 +00:00
// unload sample
Sound()->UnloadSample(pSound->m_SoundID);
free(pSound->m_pData);
2014-11-09 13:58:28 +00:00
// replace sound
str_copy(pSound->m_aName, aBuf);
pSound->m_SoundID = SoundId;
2014-11-09 13:58:28 +00:00
pSound->m_pData = pData;
pSound->m_DataSize = DataSize;
m_Dialog = DIALOG_NONE;
return true;
2014-11-09 13:58:28 +00:00
}
bool CEditor::ReplaceSoundCallback(const char *pFileName, int StorageType, void *pUser)
{
return static_cast<CEditor *>(pUser)->ReplaceSound(pFileName, StorageType, true);
}
void CEditor::SelectGameLayer()
{
for(size_t g = 0; g < m_Map.m_vpGroups.size(); g++)
{
for(size_t i = 0; i < m_Map.m_vpGroups[g]->m_vpLayers.size(); i++)
{
if(m_Map.m_vpGroups[g]->m_vpLayers[i] == m_Map.m_pGameLayer)
{
SelectLayer(i, g);
return;
}
}
}
}
2020-10-09 20:49:52 +00:00
static bool ImageNameLess(const CEditorImage *const &a, const CEditorImage *const &b)
2010-06-02 16:12:32 +00:00
{
2020-10-09 20:49:52 +00:00
return str_comp(a->m_aName, b->m_aName) < 0;
2010-06-02 16:12:32 +00:00
}
static int *gs_pSortedIndex = nullptr;
2010-06-02 16:12:32 +00:00
static void ModifySortedIndex(int *pIndex)
{
2020-10-09 20:49:52 +00:00
if(*pIndex >= 0)
2010-06-02 16:12:32 +00:00
*pIndex = gs_pSortedIndex[*pIndex];
}
void CEditor::SortImages()
{
if(!std::is_sorted(m_Map.m_vpImages.begin(), m_Map.m_vpImages.end(), ImageNameLess))
2010-06-02 16:12:32 +00:00
{
std::vector<CEditorImage *> vpTemp = m_Map.m_vpImages;
gs_pSortedIndex = new int[vpTemp.size()];
2010-06-02 16:12:32 +00:00
std::sort(m_Map.m_vpImages.begin(), m_Map.m_vpImages.end(), ImageNameLess);
for(size_t OldIndex = 0; OldIndex < vpTemp.size(); OldIndex++)
2020-10-09 20:49:52 +00:00
{
for(size_t NewIndex = 0; NewIndex < m_Map.m_vpImages.size(); NewIndex++)
2020-10-09 20:49:52 +00:00
{
if(vpTemp[OldIndex] == m_Map.m_vpImages[NewIndex])
2020-10-09 20:49:52 +00:00
{
2010-06-02 16:12:32 +00:00
gs_pSortedIndex[OldIndex] = NewIndex;
2020-10-09 20:49:52 +00:00
break;
}
}
}
2010-06-02 16:12:32 +00:00
m_Map.ModifyImageIndex(ModifySortedIndex);
delete[] gs_pSortedIndex;
gs_pSortedIndex = nullptr;
2010-06-02 16:12:32 +00:00
}
}
2011-08-11 08:59:14 +00:00
void CEditor::RenderImagesList(CUIRect ToolBox)
2008-01-12 12:27:55 +00:00
{
const float RowHeight = 12.0f;
static CScrollRegion s_ScrollRegion;
vec2 ScrollOffset(0.0f, 0.0f);
CScrollRegionParams ScrollParams;
ScrollParams.m_ScrollbarWidth = 10.0f;
ScrollParams.m_ScrollbarMargin = 3.0f;
ScrollParams.m_ScrollUnit = RowHeight * 5;
s_ScrollRegion.Begin(&ToolBox, &ScrollOffset, &ScrollParams);
ToolBox.y += ScrollOffset.y;
bool ScrollToSelection = false;
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && !m_Map.m_vpImages.empty())
{
if(Input()->KeyPress(KEY_DOWN))
{
int OldImage = m_SelectedImage;
m_SelectedImage = clamp(m_SelectedImage, 0, (int)m_Map.m_vpImages.size() - 1);
for(size_t i = m_SelectedImage + 1; i < m_Map.m_vpImages.size(); i++)
{
if(m_Map.m_vpImages[i]->m_External == m_Map.m_vpImages[m_SelectedImage]->m_External)
{
m_SelectedImage = i;
break;
}
}
if(m_SelectedImage == OldImage && !m_Map.m_vpImages[m_SelectedImage]->m_External)
{
for(size_t i = 0; i < m_Map.m_vpImages.size(); i++)
{
if(m_Map.m_vpImages[i]->m_External)
{
m_SelectedImage = i;
break;
}
}
}
ScrollToSelection = OldImage != m_SelectedImage;
}
else if(Input()->KeyPress(KEY_UP))
{
int OldImage = m_SelectedImage;
m_SelectedImage = clamp(m_SelectedImage, 0, (int)m_Map.m_vpImages.size() - 1);
for(int i = m_SelectedImage - 1; i >= 0; i--)
{
if(m_Map.m_vpImages[i]->m_External == m_Map.m_vpImages[m_SelectedImage]->m_External)
{
m_SelectedImage = i;
break;
}
}
if(m_SelectedImage == OldImage && m_Map.m_vpImages[m_SelectedImage]->m_External)
{
for(int i = (int)m_Map.m_vpImages.size() - 1; i >= 0; i--)
{
if(!m_Map.m_vpImages[i]->m_External)
{
m_SelectedImage = i;
break;
}
}
}
ScrollToSelection = OldImage != m_SelectedImage;
}
}
for(int e = 0; e < 2; e++) // two passes, first embedded, then external
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
CUIRect Slot;
ToolBox.HSplitTop(RowHeight + 3.0f, &Slot, &ToolBox);
if(s_ScrollRegion.AddRect(Slot))
UI()->DoLabel(&Slot, e == 0 ? "Embedded" : "External", 12.0f, TEXTALIGN_MC);
2010-05-29 07:25:38 +00:00
for(int i = 0; i < (int)m_Map.m_vpImages.size(); i++)
2008-01-13 22:03:32 +00:00
{
if((e && !m_Map.m_vpImages[i]->m_External) ||
(!e && m_Map.m_vpImages[i]->m_External))
{
continue;
}
2010-05-29 07:25:38 +00:00
ToolBox.HSplitTop(RowHeight + 2.0f, &Slot, &ToolBox);
int Selected = m_SelectedImage == i;
if(!s_ScrollRegion.AddRect(Slot, Selected && ScrollToSelection))
continue;
Slot.HSplitTop(RowHeight, &Slot, nullptr);
const bool ImageUsed = std::any_of(m_Map.m_vpGroups.cbegin(), m_Map.m_vpGroups.cend(), [i](const auto &pGroup) {
return std::any_of(pGroup->m_vpLayers.cbegin(), pGroup->m_vpLayers.cend(), [i](const auto &pLayer) {
if(pLayer->m_Type == LAYERTYPE_QUADS)
return static_cast<CLayerQuads *>(pLayer)->m_Image == i;
else if(pLayer->m_Type == LAYERTYPE_TILES)
return static_cast<CLayerTiles *>(pLayer)->m_Image == i;
return false;
});
});
if(!ImageUsed)
Selected += 2; // Image is unused
if(Selected < 2 && e == 1)
{
if(!IsVanillaImage(m_Map.m_vpImages[i]->m_aName))
{
Selected += 4; // Image should be embedded
}
}
float FontSize = 10.0f;
while(TextRender()->TextWidth(FontSize, m_Map.m_vpImages[i]->m_aName, -1, -1.0f) > Slot.w)
FontSize--;
if(int Result = DoButton_Ex(&m_Map.m_vpImages[i], m_Map.m_vpImages[i]->m_aName, Selected, &Slot,
BUTTON_CONTEXT, "Select image.", IGraphics::CORNER_ALL, FontSize))
{
2010-05-29 07:25:38 +00:00
m_SelectedImage = i;
if(Result == 2)
{
2023-04-01 21:20:11 +00:00
const CEditorImage *pImg = m_Map.m_vpImages[m_SelectedImage];
const int Height = pImg->m_External || IsVanillaImage(pImg->m_aName) ? 73 : 56;
static SPopupMenuId s_PopupImageId;
UI()->DoPopupMenu(&s_PopupImageId, UI()->MouseX(), UI()->MouseY(), 120, Height, this, PopupImage);
}
}
2007-12-02 17:55:45 +00:00
}
// separator
ToolBox.HSplitTop(5.0f, &Slot, &ToolBox);
if(s_ScrollRegion.AddRect(Slot))
{
IGraphics::CLineItem LineItem(Slot.x, Slot.y + Slot.h / 2, Slot.x + Slot.w, Slot.y + Slot.h / 2);
Graphics()->TextureClear();
Graphics()->LinesBegin();
Graphics()->LinesDraw(&LineItem, 1);
Graphics()->LinesEnd();
}
}
// new image
static int s_AddImageButton = 0;
CUIRect AddImageButton;
ToolBox.HSplitTop(5.0f + RowHeight + 1.0f, &AddImageButton, &ToolBox);
if(s_ScrollRegion.AddRect(AddImageButton))
{
AddImageButton.HSplitTop(5.0f, nullptr, &AddImageButton);
AddImageButton.HSplitTop(RowHeight, &AddImageButton, nullptr);
if(DoButton_Editor(&s_AddImageButton, "Add", 0, &AddImageButton, 0, "Load a new image to use in the map"))
InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_IMG, "Add Image", "Add", "mapres", "", AddImage, this);
}
s_ScrollRegion.End();
}
2010-06-14 01:18:44 +00:00
void CEditor::RenderSelectedImage(CUIRect View)
{
if(m_SelectedImage < 0 || (size_t)m_SelectedImage >= m_Map.m_vpImages.size())
return;
2008-01-13 16:30:30 +00:00
View.Margin(10.0f, &View);
if(View.h < View.w)
View.w = View.h;
else
View.h = View.w;
float Max = maximum<float>(m_Map.m_vpImages[m_SelectedImage]->m_Width, m_Map.m_vpImages[m_SelectedImage]->m_Height);
View.w *= m_Map.m_vpImages[m_SelectedImage]->m_Width / Max;
View.h *= m_Map.m_vpImages[m_SelectedImage]->m_Height / Max;
Graphics()->TextureSet(m_Map.m_vpImages[m_SelectedImage]->m_Texture);
Graphics()->BlendNormal();
Graphics()->WrapClamp();
Graphics()->QuadsBegin();
IGraphics::CQuadItem QuadItem(View.x, View.y, View.w, View.h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
Graphics()->WrapNormal();
2010-05-29 07:25:38 +00:00
}
void CEditor::RenderSounds(CUIRect ToolBox)
{
const float RowHeight = 12.0f;
static CScrollRegion s_ScrollRegion;
vec2 ScrollOffset(0.0f, 0.0f);
CScrollRegionParams ScrollParams;
ScrollParams.m_ScrollbarWidth = 10.0f;
ScrollParams.m_ScrollbarMargin = 3.0f;
ScrollParams.m_ScrollUnit = RowHeight * 5;
s_ScrollRegion.Begin(&ToolBox, &ScrollOffset, &ScrollParams);
ToolBox.y += ScrollOffset.y;
bool ScrollToSelection = false;
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && !m_Map.m_vpSounds.empty())
{
if(Input()->KeyPress(KEY_DOWN))
{
m_SelectedSound = (m_SelectedSound + 1) % m_Map.m_vpSounds.size();
ScrollToSelection = true;
}
else if(Input()->KeyPress(KEY_UP))
{
m_SelectedSound = (m_SelectedSound + m_Map.m_vpSounds.size() - 1) % m_Map.m_vpSounds.size();
ScrollToSelection = true;
}
}
CUIRect Slot;
ToolBox.HSplitTop(RowHeight + 3.0f, &Slot, &ToolBox);
if(s_ScrollRegion.AddRect(Slot))
UI()->DoLabel(&Slot, "Embedded", 12.0f, TEXTALIGN_MC);
for(int i = 0; i < (int)m_Map.m_vpSounds.size(); i++)
{
ToolBox.HSplitTop(RowHeight + 2.0f, &Slot, &ToolBox);
int Selected = m_SelectedSound == i;
if(!s_ScrollRegion.AddRect(Slot, Selected && ScrollToSelection))
continue;
Slot.HSplitTop(RowHeight, &Slot, nullptr);
const bool SoundUsed = std::any_of(m_Map.m_vpGroups.cbegin(), m_Map.m_vpGroups.cend(), [i](const auto &pGroup) {
return std::any_of(pGroup->m_vpLayers.cbegin(), pGroup->m_vpLayers.cend(), [i](const auto &pLayer) {
if(pLayer->m_Type == LAYERTYPE_SOUNDS)
return static_cast<CLayerSounds *>(pLayer)->m_Sound == i;
return false;
});
});
if(!SoundUsed)
Selected += 2; // Sound is unused
float FontSize = 10.0f;
while(TextRender()->TextWidth(FontSize, m_Map.m_vpSounds[i]->m_aName, -1, -1.0f) > Slot.w)
FontSize--;
if(int Result = DoButton_Ex(&m_Map.m_vpSounds[i], m_Map.m_vpSounds[i]->m_aName, Selected, &Slot,
BUTTON_CONTEXT, "Select sound.", IGraphics::CORNER_ALL, FontSize))
{
m_SelectedSound = i;
if(Result == 2)
2023-04-02 10:21:57 +00:00
{
static SPopupMenuId s_PopupSoundId;
UI()->DoPopupMenu(&s_PopupSoundId, UI()->MouseX(), UI()->MouseY(), 120, 56, this, PopupSound);
2023-04-02 10:21:57 +00:00
}
}
}
// separator
ToolBox.HSplitTop(5.0f, &Slot, &ToolBox);
if(s_ScrollRegion.AddRect(Slot))
{
IGraphics::CLineItem LineItem(Slot.x, Slot.y + Slot.h / 2, Slot.x + Slot.w, Slot.y + Slot.h / 2);
Graphics()->TextureClear();
Graphics()->LinesBegin();
Graphics()->LinesDraw(&LineItem, 1);
Graphics()->LinesEnd();
}
// new sound
static int s_AddSoundButton = 0;
CUIRect AddSoundButton;
ToolBox.HSplitTop(5.0f + RowHeight + 1.0f, &AddSoundButton, &ToolBox);
if(s_ScrollRegion.AddRect(AddSoundButton))
{
AddSoundButton.HSplitTop(5.0f, nullptr, &AddSoundButton);
AddSoundButton.HSplitTop(RowHeight, &AddSoundButton, nullptr);
if(DoButton_Editor(&s_AddSoundButton, "Add", 0, &AddSoundButton, 0, "Load a new sound to use in the map"))
InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_SOUND, "Add Sound", "Add", "mapres", "", AddSound, this);
}
s_ScrollRegion.End();
}
2023-03-12 17:54:57 +00:00
static int EditorListdirCallback(const CFsFileInfo *pInfo, int IsDir, int StorageType, void *pUser)
2008-01-12 12:27:55 +00:00
{
CEditor *pEditor = (CEditor *)pUser;
2023-03-12 17:54:57 +00:00
if((pInfo->m_pName[0] == '.' && (pInfo->m_pName[1] == 0 ||
(pInfo->m_pName[1] == '.' && pInfo->m_pName[2] == 0 && (!str_comp(pEditor->m_pFileDialogPath, "maps") || !str_comp(pEditor->m_pFileDialogPath, "mapres"))))) ||
(!IsDir && ((pEditor->m_FileDialogFileType == CEditor::FILETYPE_MAP && !str_endswith(pInfo->m_pName, ".map")) ||
(pEditor->m_FileDialogFileType == CEditor::FILETYPE_IMG && !str_endswith(pInfo->m_pName, ".png")) ||
(pEditor->m_FileDialogFileType == CEditor::FILETYPE_SOUND && !str_endswith(pInfo->m_pName, ".opus")))))
return 0;
2010-05-29 07:25:38 +00:00
2010-10-06 21:07:35 +00:00
CEditor::CFilelistItem Item;
2023-03-12 17:54:57 +00:00
str_copy(Item.m_aFilename, pInfo->m_pName, sizeof(Item.m_aFilename));
2010-10-06 21:07:35 +00:00
if(IsDir)
2023-03-12 17:54:57 +00:00
str_format(Item.m_aName, sizeof(Item.m_aName), "%s/", pInfo->m_pName);
2010-10-06 21:07:35 +00:00
else
2014-10-11 11:38:45 +00:00
{
2020-10-26 11:56:21 +00:00
int LenEnding = pEditor->m_FileDialogFileType == CEditor::FILETYPE_SOUND ? 5 : 4;
2023-03-12 17:54:57 +00:00
str_truncate(Item.m_aName, sizeof(Item.m_aName), pInfo->m_pName, str_length(pInfo->m_pName) - LenEnding);
2014-10-11 11:38:45 +00:00
}
2010-10-06 21:07:35 +00:00
Item.m_IsDir = IsDir != 0;
Item.m_IsLink = false;
2010-10-06 21:07:35 +00:00
Item.m_StorageType = StorageType;
2023-03-12 17:54:57 +00:00
Item.m_TimeModified = pInfo->m_TimeModified;
pEditor->m_vCompleteFileList.push_back(Item);
return 0;
}
void CEditor::SortFilteredFileList()
{
if(m_SortByFilename == 1)
{
2023-03-12 18:41:58 +00:00
std::sort(m_vpFilteredFileList.begin(), m_vpFilteredFileList.end(), CEditor::CompareFilenameAscending);
}
else
{
2023-03-12 18:41:58 +00:00
std::sort(m_vpFilteredFileList.begin(), m_vpFilteredFileList.end(), CEditor::CompareFilenameDescending);
}
if(m_SortByTimeModified == 1)
{
2023-03-12 18:41:58 +00:00
std::stable_sort(m_vpFilteredFileList.begin(), m_vpFilteredFileList.end(), CEditor::CompareTimeModifiedAscending);
}
else if(m_SortByTimeModified == -1)
{
2023-03-12 18:41:58 +00:00
std::stable_sort(m_vpFilteredFileList.begin(), m_vpFilteredFileList.end(), CEditor::CompareTimeModifiedDescending);
}
}
2010-05-29 07:25:38 +00:00
void CEditor::RenderFileDialog()
2008-01-12 12:27:55 +00:00
{
// GUI coordsys
2021-09-22 19:48:55 +00:00
UI()->MapScreen();
2010-05-29 07:25:38 +00:00
CUIRect View = *UI()->Screen();
2014-03-28 21:47:57 +00:00
CUIRect Preview;
float Width = View.w, Height = View.h;
View.Draw(ColorRGBA(0, 0, 0, 0.25f), 0, 0);
2010-05-29 07:25:38 +00:00
View.VMargin(150.0f, &View);
View.HMargin(50.0f, &View);
View.Draw(ColorRGBA(0, 0, 0, 0.75f), IGraphics::CORNER_ALL, 5.0f);
2010-05-29 07:25:38 +00:00
View.Margin(10.0f, &View);
CUIRect Title, FileBox, FileBoxLabel, ButtonBar, PathBox;
2010-05-29 07:25:38 +00:00
View.HSplitTop(18.0f, &Title, &View);
View.HSplitTop(5.0f, nullptr, &View); // some spacing
2010-05-29 07:25:38 +00:00
View.HSplitBottom(14.0f, &View, &ButtonBar);
View.HSplitBottom(10.0f, &View, nullptr); // some spacing
View.HSplitBottom(14.0f, &View, &PathBox);
View.HSplitBottom(5.0f, &View, nullptr); // some spacing
2010-05-29 07:25:38 +00:00
View.HSplitBottom(14.0f, &View, &FileBox);
FileBox.VSplitLeft(55.0f, &FileBoxLabel, &FileBox);
View.HSplitBottom(10.0f, &View, nullptr); // some spacing
if(m_FileDialogFileType == CEditor::FILETYPE_IMG)
2014-03-28 21:47:57 +00:00
View.VSplitMid(&View, &Preview);
2010-05-29 07:25:38 +00:00
2008-01-13 16:30:30 +00:00
// title
CUIRect ButtonTimeModified, ButtonFileName;
Title.VSplitRight(10.0f, &Title, nullptr);
Title.VSplitRight(90.0f, &Title, &ButtonTimeModified);
Title.VSplitRight(10.0f, &Title, nullptr);
Title.VSplitRight(90.0f, &Title, &ButtonFileName);
Title.VSplitRight(10.0f, &Title, nullptr);
2023-03-12 18:57:46 +00:00
const char *aSortIndicator[3] = {"", "", ""};
static int s_ButtonTimeModified = 0;
char aBufLabelButtonTimeModified[64];
2023-03-12 18:41:58 +00:00
str_format(aBufLabelButtonTimeModified, sizeof(aBufLabelButtonTimeModified), "Time modified %s", aSortIndicator[m_SortByTimeModified + 1]);
if(DoButton_Editor(&s_ButtonTimeModified, aBufLabelButtonTimeModified, 0, &ButtonTimeModified, 0, "Sort by time modified"))
{
if(m_SortByTimeModified == 1)
{
m_SortByTimeModified = -1;
}
else if(m_SortByTimeModified == -1)
{
m_SortByTimeModified = 0;
}
else
{
m_SortByTimeModified = 1;
}
2023-03-14 16:17:24 +00:00
RefreshFilteredFileList();
}
static int s_ButtonFileName = 0;
char aBufLabelButtonFilename[64];
2023-03-12 18:41:58 +00:00
str_format(aBufLabelButtonFilename, sizeof(aBufLabelButtonFilename), "Filename %s", aSortIndicator[m_SortByFilename + 1]);
if(DoButton_Editor(&s_ButtonFileName, aBufLabelButtonFilename, 0, &ButtonFileName, 0, "Sort by file name"))
{
if(m_SortByFilename == 1)
{
m_SortByFilename = -1;
2023-03-14 16:17:24 +00:00
m_SortByTimeModified = 0;
}
else
{
m_SortByFilename = 1;
2023-03-14 16:17:24 +00:00
m_SortByTimeModified = 0;
}
2023-03-14 16:17:24 +00:00
RefreshFilteredFileList();
}
Title.Draw(ColorRGBA(1, 1, 1, 0.25f), IGraphics::CORNER_ALL, 4.0f);
2010-05-29 07:25:38 +00:00
Title.VMargin(10.0f, &Title);
UI()->DoLabel(&Title, m_pFileDialogTitle, 12.0f, TEXTALIGN_ML);
2010-05-29 07:25:38 +00:00
// pathbox
char aPath[IO_MAX_PATH_LENGTH], aBuf[128 + IO_MAX_PATH_LENGTH];
if(m_FilesSelectedIndex != -1)
Storage()->GetCompletePath(m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType, m_pFileDialogPath, aPath, sizeof(aPath));
else
aPath[0] = 0;
str_format(aBuf, sizeof(aBuf), "Current path: %s", aPath);
UI()->DoLabel(&PathBox, aBuf, 10.0f, TEXTALIGN_ML);
2017-02-21 16:10:08 +00:00
// filebox
static CListBox s_ListBox;
static bool s_ListBoxUsed = false;
s_ListBoxUsed = !UI()->IsPopupOpen();
if(m_FileDialogStorageType == IStorage::TYPE_SAVE)
{
UI()->DoLabel(&FileBoxLabel, "Filename:", 10.0f, TEXTALIGN_ML);
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(DoEditBox(&m_FileDialogFileNameInput, &FileBox, 10.0f))
{
// remove '/' and '\'
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
for(int i = 0; m_FileDialogFileNameInput.GetString()[i]; ++i)
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(m_FileDialogFileNameInput.GetString()[i] == '/' || m_FileDialogFileNameInput.GetString()[i] == '\\')
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.SetRange(m_FileDialogFileNameInput.GetString() + i + 1, i, m_FileDialogFileNameInput.GetLength());
--i;
}
}
m_FilesSelectedIndex = -1;
m_aFilesSelectedName[0] = '\0';
// find first valid entry, if it exists
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(str_comp_nocase(m_vpFilteredFileList[i]->m_aName, m_FileDialogFileNameInput.GetString()) == 0)
{
m_FilesSelectedIndex = i;
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[i]->m_aName);
break;
}
}
if(m_FilesSelectedIndex >= 0)
s_ListBox.ScrollToSelected();
}
if(m_FileDialogOpening)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UI()->SetActiveItem(&m_FileDialogFileNameInput);
}
2016-08-20 23:47:39 +00:00
else
{
// render search bar
UI()->DoLabel(&FileBoxLabel, "Search:", 10.0f, TEXTALIGN_ML);
if(m_FileDialogOpening)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UI()->SetActiveItem(&m_FileDialogFilterInput);
if(UI()->DoClearableEditBox(&m_FileDialogFilterInput, &FileBox, 10.0f))
{
RefreshFilteredFileList();
if(m_vpFilteredFileList.empty())
{
m_FilesSelectedIndex = -1;
}
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
else if(m_FilesSelectedIndex == -1 || (!m_FileDialogFilterInput.IsEmpty() && !str_find_nocase(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName, m_FileDialogFilterInput.GetString())))
{
// we need to refresh selection
m_FilesSelectedIndex = -1;
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(str_find_nocase(m_vpFilteredFileList[i]->m_aName, m_FileDialogFilterInput.GetString()))
{
m_FilesSelectedIndex = i;
break;
}
}
if(m_FilesSelectedIndex == -1)
{
// select first item
m_FilesSelectedIndex = 0;
}
}
if(m_FilesSelectedIndex >= 0)
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
else
m_aFilesSelectedName[0] = '\0';
if(m_FilesSelectedIndex >= 0 && !m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.Set(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
else
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.Clear();
s_ListBox.ScrollToSelected();
m_PreviewImageState = PREVIEWIMAGE_UNLOADED;
}
}
m_FileDialogOpening = false;
2014-03-28 21:47:57 +00:00
if(m_FilesSelectedIndex > -1)
{
if(m_FileDialogFileType == CEditor::FILETYPE_IMG && m_PreviewImageState == PREVIEWIMAGE_UNLOADED && m_FilesSelectedIndex > -1)
2014-03-28 21:47:57 +00:00
{
if(str_endswith(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, ".png"))
2014-03-28 21:47:57 +00:00
{
char aBuffer[IO_MAX_PATH_LENGTH];
str_format(aBuffer, sizeof(aBuffer), "%s/%s", m_pFileDialogPath, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
if(Graphics()->LoadPNG(&m_FilePreviewImageInfo, aBuffer, IStorage::TYPE_ALL))
{
Graphics()->UnloadTexture(&m_FilePreviewImage);
2021-05-21 12:57:55 +00:00
m_FilePreviewImage = Graphics()->LoadTextureRaw(m_FilePreviewImageInfo.m_Width, m_FilePreviewImageInfo.m_Height, m_FilePreviewImageInfo.m_Format, m_FilePreviewImageInfo.m_pData, m_FilePreviewImageInfo.m_Format, 0);
Graphics()->FreePNG(&m_FilePreviewImageInfo);
m_PreviewImageState = PREVIEWIMAGE_LOADED;
}
else
{
m_PreviewImageState = PREVIEWIMAGE_ERROR;
}
2014-03-28 21:47:57 +00:00
}
}
if(m_FileDialogFileType == CEditor::FILETYPE_IMG && m_PreviewImageState == PREVIEWIMAGE_LOADED)
2014-03-28 21:47:57 +00:00
{
int w = m_FilePreviewImageInfo.m_Width;
int h = m_FilePreviewImageInfo.m_Height;
if(m_FilePreviewImageInfo.m_Width > Preview.w) // NOLINT(clang-analyzer-core.UndefinedBinaryOperatorResult)
2014-03-28 21:47:57 +00:00
{
h = m_FilePreviewImageInfo.m_Height * Preview.w / m_FilePreviewImageInfo.m_Width;
w = Preview.w;
}
if(h > Preview.h)
2014-03-28 21:47:57 +00:00
{
2022-05-28 00:15:42 +00:00
w = w * Preview.h / h;
2014-03-28 21:47:57 +00:00
h = Preview.h;
}
Graphics()->TextureSet(m_FilePreviewImage);
Graphics()->BlendNormal();
Graphics()->QuadsBegin();
IGraphics::CQuadItem QuadItem(Preview.x, Preview.y, w, h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
Graphics()->QuadsEnd();
}
}
s_ListBox.DoStart(15.0f, m_vpFilteredFileList.size(), 1, 5, m_FilesSelectedIndex, &View, false, &s_ListBoxUsed);
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
{
const CListboxItem Item = s_ListBox.DoNextItem(m_vpFilteredFileList[i], m_FilesSelectedIndex >= 0 && (size_t)m_FilesSelectedIndex == i, &s_ListBoxUsed);
if(!Item.m_Visible)
continue;
CUIRect Button, FileIcon, TimeModified;
Item.m_Rect.VSplitLeft(Item.m_Rect.h, &FileIcon, &Button);
Button.VSplitLeft(5.0f, nullptr, &Button);
Button.VSplitRight(100.0f, &Button, &TimeModified);
2010-05-29 07:25:38 +00:00
const char *pIconType;
if(!m_vpFilteredFileList[i]->m_IsDir)
{
switch(m_FileDialogFileType)
{
case FILETYPE_MAP:
pIconType = FONT_ICON_MAP;
break;
case FILETYPE_IMG:
pIconType = FONT_ICON_IMAGE;
break;
case FILETYPE_SOUND:
pIconType = FONT_ICON_MUSIC;
break;
default:
pIconType = FONT_ICON_FILE;
}
}
else
{
if(str_comp(m_vpFilteredFileList[i]->m_aFilename, "..") == 0)
pIconType = FONT_ICON_FOLDER_TREE;
else
pIconType = FONT_ICON_FOLDER;
}
2010-05-29 07:25:38 +00:00
TextRender()->SetCurFont(TextRender()->GetFont(TEXT_FONT_ICON_FONT));
UI()->DoLabel(&FileIcon, pIconType, 12.0f, TEXTALIGN_ML);
TextRender()->SetCurFont(nullptr);
2010-05-29 07:25:38 +00:00
UI()->DoLabel(&Button, m_vpFilteredFileList[i]->m_aName, 10.0f, TEXTALIGN_ML);
2023-03-12 18:41:58 +00:00
if(!m_vpFilteredFileList[i]->m_IsLink && str_comp(m_vpFilteredFileList[i]->m_aFilename, "..") != 0)
{
char aBufTimeModified[64];
str_timestamp_ex(m_vpFilteredFileList[i]->m_TimeModified, aBufTimeModified, sizeof(aBufTimeModified), "%d.%m.%Y %H:%M");
UI()->DoLabel(&TimeModified, aBufTimeModified, 10.0f, TEXTALIGN_MR);
}
}
2010-05-29 07:25:38 +00:00
const int NewSelection = s_ListBox.DoEnd();
if(NewSelection != m_FilesSelectedIndex)
{
m_FilesSelectedIndex = NewSelection;
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
if(!m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.Set(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
else
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.Clear();
m_PreviewImageState = PREVIEWIMAGE_UNLOADED;
}
2010-05-29 07:25:38 +00:00
const float ButtonSpacing = ButtonBar.w > 600.0f ? 40.0f : 10.0f;
2008-01-13 16:30:30 +00:00
// the buttons
2010-05-29 07:25:38 +00:00
static int s_OkButton = 0;
static int s_CancelButton = 0;
static int s_RefreshButton = 0;
static int s_ShowDirectoryButton = 0;
static int s_DeleteButton = 0;
static int s_NewFolderButton = 0;
2008-01-13 16:30:30 +00:00
2010-05-29 07:25:38 +00:00
CUIRect Button;
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
bool IsDir = m_FilesSelectedIndex >= 0 && m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir;
if(DoButton_Editor(&s_OkButton, IsDir ? "Open" : m_pFileDialogButtonText, 0, &Button, 0, nullptr) || s_ListBox.WasItemActivated())
2008-01-13 16:30:30 +00:00
{
if(IsDir) // folder
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFilterInput.Clear();
if(str_comp(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, "..") == 0) // parent folder
{
if(fs_parent_dir(m_pFileDialogPath))
m_pFileDialogPath = m_aFileDialogCurrentFolder; // leave the link
}
else // sub folder
{
if(m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsLink)
{
m_pFileDialogPath = m_aFileDialogCurrentLink; // follow the link
str_copy(m_aFileDialogCurrentLink, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, sizeof(m_aFileDialogCurrentLink));
}
else
{
char aTemp[IO_MAX_PATH_LENGTH];
str_copy(aTemp, m_pFileDialogPath, sizeof(aTemp));
str_format(m_pFileDialogPath, IO_MAX_PATH_LENGTH, "%s/%s", aTemp, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
}
}
FilelistPopulate(!str_comp(m_pFileDialogPath, "maps") || !str_comp(m_pFileDialogPath, "mapres") ? m_FileDialogStorageType :
m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType);
if(m_FilesSelectedIndex >= 0 && !m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsDir)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.Set(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
else
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.Clear();
}
else // file
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
str_format(m_aFileSaveName, sizeof(m_aFileSaveName), "%s/%s", m_pFileDialogPath, m_FileDialogFileNameInput.GetString());
if(!str_comp(m_pFileDialogButtonText, "Save"))
{
if(Storage()->FileExists(m_aFileSaveName, IStorage::TYPE_SAVE))
{
m_PopupEventType = POPEVENT_SAVE;
m_PopupEventActivated = true;
}
else if(m_pfnFileDialogFunc)
m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType : m_FileDialogStorageType, m_pFileDialogUser);
}
else if(m_pfnFileDialogFunc)
m_pfnFileDialogFunc(m_aFileSaveName, m_FilesSelectedIndex >= 0 ? m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType : m_FileDialogStorageType, m_pFileDialogUser);
}
2008-01-13 16:30:30 +00:00
}
ButtonBar.VSplitRight(ButtonSpacing, &ButtonBar, nullptr);
2010-05-29 07:25:38 +00:00
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
if(DoButton_Editor(&s_CancelButton, "Cancel", 0, &Button, 0, nullptr) || (s_ListBoxUsed && UI()->ConsumeHotkey(CUI::HOTKEY_ESCAPE)))
2010-05-29 07:25:38 +00:00
m_Dialog = DIALOG_NONE;
ButtonBar.VSplitRight(ButtonSpacing, &ButtonBar, nullptr);
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
if(DoButton_Editor(&s_RefreshButton, "Refresh", 0, &Button, 0, nullptr) || (s_ListBoxUsed && (Input()->KeyIsPressed(KEY_F5) || (Input()->ModifierIsPressed() && Input()->KeyIsPressed(KEY_R)))))
FilelistPopulate(m_FileDialogLastPopulatedStorageType, true);
ButtonBar.VSplitRight(ButtonSpacing, &ButtonBar, nullptr);
ButtonBar.VSplitRight(90.0f, &ButtonBar, &Button);
if(DoButton_Editor(&s_ShowDirectoryButton, "Show directory", 0, &Button, 0, "Open the current directory in the file browser"))
{
if(!open_file(aPath))
{
ShowFileDialogError("Failed to open the directory '%s'.", aPath);
}
}
ButtonBar.VSplitRight(ButtonSpacing, &ButtonBar, nullptr);
ButtonBar.VSplitRight(50.0f, &ButtonBar, &Button);
static CUI::SConfirmPopupContext s_ConfirmDeletePopupContext;
if(m_FilesSelectedIndex >= 0 && m_vpFilteredFileList[m_FilesSelectedIndex]->m_StorageType == IStorage::TYPE_SAVE && !m_vpFilteredFileList[m_FilesSelectedIndex]->m_IsLink && str_comp(m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename, "..") != 0)
{
if(DoButton_Editor(&s_DeleteButton, "Delete", 0, &Button, 0, nullptr) || (s_ListBoxUsed && UI()->ConsumeHotkey(CUI::HOTKEY_DELETE)))
{
s_ConfirmDeletePopupContext.Reset();
s_ConfirmDeletePopupContext.YesNoButtons();
str_format(s_ConfirmDeletePopupContext.m_aMessage, sizeof(s_ConfirmDeletePopupContext.m_aMessage), "Are you sure that you want to delete the %s '%s/%s'?", IsDir ? "folder" : "file", m_pFileDialogPath, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
UI()->ShowPopupConfirm(UI()->MouseX(), UI()->MouseY(), &s_ConfirmDeletePopupContext);
}
if(s_ConfirmDeletePopupContext.m_Result == CUI::SConfirmPopupContext::CONFIRMED)
{
char aDeleteFilePath[IO_MAX_PATH_LENGTH];
str_format(aDeleteFilePath, sizeof(aDeleteFilePath), "%s/%s", m_pFileDialogPath, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aFilename);
if(IsDir)
{
if(Storage()->RemoveFolder(aDeleteFilePath, IStorage::TYPE_SAVE))
FilelistPopulate(m_FileDialogLastPopulatedStorageType, true);
else
ShowFileDialogError("Failed to delete folder '%s'. Make sure it's empty first.", aDeleteFilePath);
}
else
{
if(Storage()->RemoveFile(aDeleteFilePath, IStorage::TYPE_SAVE))
FilelistPopulate(m_FileDialogLastPopulatedStorageType, true);
else
ShowFileDialogError("Failed to delete file '%s'.", aDeleteFilePath);
}
}
if(s_ConfirmDeletePopupContext.m_Result != CUI::SConfirmPopupContext::UNSET)
s_ConfirmDeletePopupContext.Reset();
}
else
s_ConfirmDeletePopupContext.Reset();
2011-07-12 21:31:39 +00:00
if(m_FileDialogStorageType == IStorage::TYPE_SAVE)
{
ButtonBar.VSplitLeft(70.0f, &Button, &ButtonBar);
if(DoButton_Editor(&s_NewFolderButton, "New folder", 0, &Button, 0, nullptr))
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogNewFolderNameInput.Clear();
static SPopupMenuId s_PopupNewFolderId;
constexpr float PopupWidth = 400.0f;
constexpr float PopupHeight = 110.0f;
UI()->DoPopupMenu(&s_PopupNewFolderId, Width / 2.0f - PopupWidth / 2.0f, Height / 2.0f - PopupHeight / 2.0f, PopupWidth, PopupHeight, this, PopupNewFolder);
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UI()->SetActiveItem(&m_FileDialogNewFolderNameInput);
}
2011-07-12 21:31:39 +00:00
}
2008-01-13 16:30:30 +00:00
}
void CEditor::RefreshFilteredFileList()
{
m_vpFilteredFileList.clear();
for(const CFilelistItem &Item : m_vCompleteFileList)
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(m_FileDialogFilterInput.IsEmpty() || str_find_nocase(Item.m_aName, m_FileDialogFilterInput.GetString()))
{
m_vpFilteredFileList.push_back(&Item);
}
}
2023-03-14 16:17:24 +00:00
SortFilteredFileList();
if(!m_vpFilteredFileList.empty())
{
if(m_aFilesSelectedName[0])
{
for(size_t i = 0; i < m_vpFilteredFileList.size(); i++)
{
if(m_aFilesSelectedName[0] && str_comp(m_vpFilteredFileList[i]->m_aName, m_aFilesSelectedName) == 0)
{
m_FilesSelectedIndex = i;
break;
}
}
}
m_FilesSelectedIndex = clamp<int>(m_FilesSelectedIndex, 0, m_vpFilteredFileList.size() - 1);
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
}
else
{
m_FilesSelectedIndex = -1;
m_aFilesSelectedName[0] = '\0';
}
}
void CEditor::FilelistPopulate(int StorageType, bool KeepSelection)
2010-09-12 11:15:59 +00:00
{
m_FileDialogLastPopulatedStorageType = StorageType;
m_vCompleteFileList.clear();
if(m_FileDialogStorageType != IStorage::TYPE_SAVE && !str_comp(m_pFileDialogPath, "maps"))
{
CFilelistItem Item;
str_copy(Item.m_aFilename, "downloadedmaps", sizeof(Item.m_aFilename));
str_copy(Item.m_aName, "downloadedmaps/", sizeof(Item.m_aName));
Item.m_IsDir = true;
Item.m_IsLink = true;
Item.m_StorageType = IStorage::TYPE_SAVE;
Item.m_TimeModified = 0;
m_vCompleteFileList.push_back(Item);
}
Storage()->ListDirectoryInfo(StorageType, m_pFileDialogPath, EditorListdirCallback, this);
RefreshFilteredFileList();
if(!KeepSelection)
{
m_FilesSelectedIndex = m_vpFilteredFileList.empty() ? -1 : 0;
if(m_FilesSelectedIndex >= 0)
str_copy(m_aFilesSelectedName, m_vpFilteredFileList[m_FilesSelectedIndex]->m_aName);
else
m_aFilesSelectedName[0] = '\0';
}
m_PreviewImageState = PREVIEWIMAGE_UNLOADED;
2010-09-12 11:15:59 +00:00
}
void CEditor::InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText,
2010-05-29 07:25:38 +00:00
const char *pBasePath, const char *pDefaultName,
bool (*pfnFunc)(const char *pFileName, int StorageType, void *pUser), void *pUser)
2008-01-13 16:30:30 +00:00
{
UI()->ClosePopupMenus();
2010-10-06 21:07:35 +00:00
m_FileDialogStorageType = StorageType;
2010-09-12 11:15:59 +00:00
m_pFileDialogTitle = pTitle;
m_pFileDialogButtonText = pButtonText;
m_pfnFileDialogFunc = pfnFunc;
m_pFileDialogUser = pUser;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.Clear();
m_FileDialogFilterInput.Clear();
m_aFileDialogCurrentFolder[0] = 0;
m_aFileDialogCurrentLink[0] = 0;
m_pFileDialogPath = m_aFileDialogCurrentFolder;
m_FileDialogFileType = FileType;
m_PreviewImageState = PREVIEWIMAGE_UNLOADED;
m_FileDialogOpening = true;
2010-05-29 07:25:38 +00:00
if(pDefaultName)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_FileDialogFileNameInput.Set(pDefaultName);
2010-05-29 07:25:38 +00:00
if(pBasePath)
str_copy(m_aFileDialogCurrentFolder, pBasePath, sizeof(m_aFileDialogCurrentFolder));
2011-08-11 08:59:14 +00:00
FilelistPopulate(m_FileDialogStorageType);
2010-05-29 07:25:38 +00:00
m_FileDialogOpening = true;
2010-05-29 07:25:38 +00:00
m_Dialog = DIALOG_FILE;
2007-12-02 17:55:45 +00:00
}
void CEditor::ShowFileDialogError(const char *pFormat, ...)
{
static CUI::SMessagePopupContext s_MessagePopupContext;
s_MessagePopupContext.ErrorColor();
va_list VarArgs;
va_start(VarArgs, pFormat);
str_format_v(s_MessagePopupContext.m_aMessage, sizeof(s_MessagePopupContext.m_aMessage), pFormat, VarArgs);
va_end(VarArgs);
UI()->ShowPopupMessage(UI()->MouseX(), UI()->MouseY(), &s_MessagePopupContext);
}
2010-05-29 07:25:38 +00:00
void CEditor::RenderModebar(CUIRect View)
2007-12-02 17:55:45 +00:00
{
2010-05-29 07:25:38 +00:00
CUIRect Button;
2007-12-02 17:55:45 +00:00
2008-01-12 12:27:55 +00:00
// mode buttons
2007-12-02 17:55:45 +00:00
{
2010-05-29 07:25:38 +00:00
View.VSplitLeft(65.0f, &Button, &View);
Button.HSplitTop(30.0f, nullptr, &Button);
2010-05-29 07:25:38 +00:00
static int s_Button = 0;
const char *pButName = "";
if(m_Mode == MODE_LAYERS)
pButName = "Layers";
else if(m_Mode == MODE_IMAGES)
pButName = "Images";
else if(m_Mode == MODE_SOUNDS)
pButName = "Sounds";
2018-02-04 15:00:47 +00:00
int MouseButton = DoButton_Tab(&s_Button, pButName, 0, &Button, 0, "Switch between images, sounds and layers management.");
if(MouseButton == 2 || (Input()->KeyPress(KEY_LEFT) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0))
{
if(m_Mode == MODE_LAYERS)
m_Mode = MODE_SOUNDS;
else if(m_Mode == MODE_IMAGES)
m_Mode = MODE_LAYERS;
else
m_Mode = MODE_IMAGES;
}
else if(MouseButton == 1 || (Input()->KeyPress(KEY_RIGHT) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0))
2010-05-29 07:25:38 +00:00
{
if(m_Mode == MODE_LAYERS)
2011-08-11 08:59:14 +00:00
m_Mode = MODE_IMAGES;
else if(m_Mode == MODE_IMAGES)
m_Mode = MODE_SOUNDS;
2011-08-11 08:59:14 +00:00
else
m_Mode = MODE_LAYERS;
2010-05-29 07:25:38 +00:00
}
2007-12-02 17:55:45 +00:00
}
2008-01-12 12:27:55 +00:00
View.VSplitLeft(5.0f, nullptr, &View);
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
void CEditor::RenderStatusbar(CUIRect View)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
CUIRect Button;
View.VSplitRight(60.0f, &View, &Button);
static int s_EnvelopeButton = 0;
if(DoButton_Editor(&s_EnvelopeButton, "Envelopes", m_ShowEnvelopeEditor, &Button, 0, "Toggles the envelope editor."))
{
m_ShowEnvelopeEditor ^= 1;
m_ShowServerSettingsEditor = false;
}
View.VSplitRight(100.0f, &View, &Button);
Button.VSplitRight(10.0f, &Button, nullptr);
static int s_SettingsButton = 0;
if(DoButton_Editor(&s_SettingsButton, "Server settings", m_ShowServerSettingsEditor, &Button, 0, "Toggles the server settings editor."))
{
m_ShowEnvelopeEditor = false;
m_ShowServerSettingsEditor ^= 1;
}
2010-05-29 07:25:38 +00:00
if(m_pTooltip)
2008-01-17 23:09:49 +00:00
{
char aBuf[512];
2010-05-29 07:25:38 +00:00
if(ms_pUiGotContext && ms_pUiGotContext == UI()->HotItem())
2011-03-20 16:04:03 +00:00
str_format(aBuf, sizeof(aBuf), "%s Right click for context menu.", m_pTooltip);
2008-01-17 23:09:49 +00:00
else
str_copy(aBuf, m_pTooltip, sizeof(aBuf));
float FontSize = ScaleFontSize(aBuf, sizeof(aBuf), 10.0f, View.w);
2022-03-11 16:34:48 +00:00
SLabelProperties Props;
Props.m_MaxWidth = View.w;
UI()->DoLabel(&View, aBuf, FontSize, TEXTALIGN_ML, Props);
2008-01-17 23:09:49 +00:00
}
2008-01-12 12:27:55 +00:00
}
bool CEditor::IsEnvelopeUsed(int EnvelopeIndex) const
2018-10-14 13:53:14 +00:00
{
for(const auto &pGroup : m_Map.m_vpGroups)
2018-10-14 13:53:14 +00:00
{
for(const auto &pLayer : pGroup->m_vpLayers)
2018-10-14 13:53:14 +00:00
{
if(pLayer->m_Type == LAYERTYPE_QUADS)
2018-10-14 13:53:14 +00:00
{
CLayerQuads *pLayerQuads = (CLayerQuads *)pLayer;
for(const auto &Quad : pLayerQuads->m_vQuads)
2018-10-14 13:53:14 +00:00
{
if(Quad.m_PosEnv == EnvelopeIndex || Quad.m_ColorEnv == EnvelopeIndex)
2018-10-14 13:53:14 +00:00
{
return true;
}
}
}
else if(pLayer->m_Type == LAYERTYPE_SOUNDS)
2018-10-14 13:53:14 +00:00
{
CLayerSounds *pLayerSounds = (CLayerSounds *)pLayer;
for(const auto &Source : pLayerSounds->m_vSources)
2018-10-14 13:53:14 +00:00
{
if(Source.m_PosEnv == EnvelopeIndex || Source.m_SoundEnv == EnvelopeIndex)
2018-10-14 13:53:14 +00:00
{
return true;
}
}
}
else if(pLayer->m_Type == LAYERTYPE_TILES)
2018-10-14 13:53:14 +00:00
{
CLayerTiles *pLayerTiles = (CLayerTiles *)pLayer;
if(pLayerTiles->m_ColorEnv == EnvelopeIndex)
2018-10-14 13:53:14 +00:00
return true;
}
}
}
return false;
}
void CEditor::RemoveUnusedEnvelopes()
{
for(size_t Envelope = 0; Envelope < m_Map.m_vpEnvelopes.size();)
{
if(IsEnvelopeUsed(Envelope))
{
++Envelope;
}
else
{
m_Map.DeleteEnvelope(Envelope);
}
}
}
2010-05-29 07:25:38 +00:00
void CEditor::RenderEnvelopeEditor(CUIRect View)
2008-01-12 12:27:55 +00:00
{
RenderExtraEditorDragBar(View, &m_EnvelopeEditorSplit);
if(m_SelectedEnvelope < 0)
m_SelectedEnvelope = 0;
if(m_SelectedEnvelope >= (int)m_Map.m_vpEnvelopes.size())
m_SelectedEnvelope = m_Map.m_vpEnvelopes.size() - 1;
2008-01-12 12:27:55 +00:00
CEnvelope *pEnvelope = nullptr;
if(m_SelectedEnvelope >= 0 && m_SelectedEnvelope < (int)m_Map.m_vpEnvelopes.size())
pEnvelope = m_Map.m_vpEnvelopes[m_SelectedEnvelope];
2008-01-12 12:27:55 +00:00
2010-05-29 07:25:38 +00:00
CUIRect ToolBar, CurveBar, ColorBar;
View.HSplitTop(15.0f, &ToolBar, &View);
View.HSplitTop(15.0f, &CurveBar, &View);
ToolBar.Margin(2.0f, &ToolBar);
CurveBar.Margin(2.0f, &CurveBar);
2008-01-12 12:27:55 +00:00
bool CurrentEnvelopeSwitched = false;
2008-01-12 12:27:55 +00:00
// do the toolbar
2007-12-02 17:55:45 +00:00
{
2010-05-29 07:25:38 +00:00
CUIRect Button;
CEnvelope *pNewEnv = nullptr;
2010-05-29 07:25:38 +00:00
2014-10-11 14:05:36 +00:00
ToolBar.VSplitRight(50.0f, &ToolBar, &Button);
static int s_NewSoundButton = 0;
2014-10-24 20:13:46 +00:00
if(DoButton_Editor(&s_NewSoundButton, "Sound+", 0, &Button, 0, "Creates a new sound envelope"))
2014-10-11 14:05:36 +00:00
{
m_Map.m_Modified = true;
pNewEnv = m_Map.NewEnvelope(1);
2014-10-11 14:05:36 +00:00
}
ToolBar.VSplitRight(5.0f, &ToolBar, nullptr);
2010-05-29 07:25:38 +00:00
ToolBar.VSplitRight(50.0f, &ToolBar, &Button);
static int s_New4dButton = 0;
2011-03-20 16:04:03 +00:00
if(DoButton_Editor(&s_New4dButton, "Color+", 0, &Button, 0, "Creates a new color envelope"))
{
m_Map.m_Modified = true;
2010-05-29 07:25:38 +00:00
pNewEnv = m_Map.NewEnvelope(4);
}
2010-05-29 07:25:38 +00:00
ToolBar.VSplitRight(5.0f, &ToolBar, nullptr);
2010-05-29 07:25:38 +00:00
ToolBar.VSplitRight(50.0f, &ToolBar, &Button);
static int s_New2dButton = 0;
2014-10-24 20:15:55 +00:00
if(DoButton_Editor(&s_New2dButton, "Pos.+", 0, &Button, 0, "Creates a new position envelope"))
{
m_Map.m_Modified = true;
2010-05-29 07:25:38 +00:00
pNewEnv = m_Map.NewEnvelope(3);
}
2011-01-06 03:46:10 +00:00
if(m_SelectedEnvelope >= 0)
{
// Delete button
ToolBar.VSplitRight(10.0f, &ToolBar, nullptr);
ToolBar.VSplitRight(25.0f, &ToolBar, &Button);
static int s_DeleteButton = 0;
if(DoButton_Editor(&s_DeleteButton, "", 0, &Button, 0, "Delete this envelope"))
{
m_Map.DeleteEnvelope(m_SelectedEnvelope);
if(m_SelectedEnvelope >= (int)m_Map.m_vpEnvelopes.size())
m_SelectedEnvelope = m_Map.m_vpEnvelopes.size() - 1;
pEnvelope = m_SelectedEnvelope >= 0 ? m_Map.m_vpEnvelopes[m_SelectedEnvelope] : nullptr;
}
// Move right button
ToolBar.VSplitRight(5.0f, &ToolBar, nullptr);
ToolBar.VSplitRight(25.0f, &ToolBar, &Button);
static int s_MoveRightButton = 0;
if(DoButton_Ex(&s_MoveRightButton, "", 0, &Button, 0, "Move this envelope to the right", IGraphics::CORNER_R))
{
m_Map.SwapEnvelopes(m_SelectedEnvelope, m_SelectedEnvelope + 1);
m_SelectedEnvelope = clamp<int>(m_SelectedEnvelope + 1, 0, m_Map.m_vpEnvelopes.size() - 1);
pEnvelope = m_Map.m_vpEnvelopes[m_SelectedEnvelope];
}
// Move left button
ToolBar.VSplitRight(25.0f, &ToolBar, &Button);
static int s_MoveLeftButton = 0;
if(DoButton_Ex(&s_MoveLeftButton, "", 0, &Button, 0, "Move this envelope to the left", IGraphics::CORNER_L))
{
m_Map.SwapEnvelopes(m_SelectedEnvelope - 1, m_SelectedEnvelope);
m_SelectedEnvelope = clamp<int>(m_SelectedEnvelope - 1, 0, m_Map.m_vpEnvelopes.size() - 1);
pEnvelope = m_Map.m_vpEnvelopes[m_SelectedEnvelope];
}
// Margin on the right side
ToolBar.VSplitRight(7.0f, &ToolBar, nullptr);
}
2010-05-29 07:25:38 +00:00
if(pNewEnv) // add the default points
2007-12-02 17:55:45 +00:00
{
2010-05-29 07:25:38 +00:00
if(pNewEnv->m_Channels == 4)
2008-01-12 12:27:55 +00:00
{
pNewEnv->AddPoint(0, f2fx(1.0f), f2fx(1.0f), f2fx(1.0f), f2fx(1.0f));
pNewEnv->AddPoint(1000, f2fx(1.0f), f2fx(1.0f), f2fx(1.0f), f2fx(1.0f));
2008-01-12 12:27:55 +00:00
}
else
{
2010-05-29 07:25:38 +00:00
pNewEnv->AddPoint(0, 0);
pNewEnv->AddPoint(1000, 0);
2008-01-12 12:27:55 +00:00
}
}
2010-05-29 07:25:38 +00:00
CUIRect Shifter, Inc, Dec;
ToolBar.VSplitLeft(60.0f, &Shifter, &ToolBar);
Shifter.VSplitRight(15.0f, &Shifter, &Inc);
Shifter.VSplitLeft(15.0f, &Dec, &Shifter);
2023-01-24 20:16:11 +00:00
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "%d/%d", m_SelectedEnvelope + 1, (int)m_Map.m_vpEnvelopes.size());
2018-10-09 10:41:52 +00:00
ColorRGBA EnvColor = ColorRGBA(1, 1, 1, 0.5f);
if(!m_Map.m_vpEnvelopes.empty())
2018-10-09 10:41:52 +00:00
{
2018-10-14 13:53:14 +00:00
EnvColor = IsEnvelopeUsed(m_SelectedEnvelope) ?
ColorRGBA(1, 0.7f, 0.7f, 0.5f) :
ColorRGBA(0.7f, 1, 0.7f, 0.5f);
2018-10-09 10:41:52 +00:00
}
static int s_EnvelopeSelector = 0;
int NewValue = UiDoValueSelector(&s_EnvelopeSelector, &Shifter, aBuf, m_SelectedEnvelope + 1, 1, m_Map.m_vpEnvelopes.size(), 1, 1.0f, "Select Envelope", false, false, IGraphics::CORNER_NONE, &EnvColor, false);
if(NewValue - 1 != m_SelectedEnvelope)
{
m_SelectedEnvelope = NewValue - 1;
CurrentEnvelopeSwitched = true;
}
2010-05-29 07:25:38 +00:00
static int s_PrevButton = 0;
if(DoButton_ButtonDec(&s_PrevButton, nullptr, 0, &Dec, 0, "Previous Envelope"))
{
2010-05-29 07:25:38 +00:00
m_SelectedEnvelope--;
if(m_SelectedEnvelope < 0)
m_SelectedEnvelope = m_Map.m_vpEnvelopes.size() - 1;
CurrentEnvelopeSwitched = true;
}
2010-05-29 07:25:38 +00:00
static int s_NextButton = 0;
if(DoButton_ButtonInc(&s_NextButton, nullptr, 0, &Inc, 0, "Next Envelope"))
{
2010-05-29 07:25:38 +00:00
m_SelectedEnvelope++;
if(m_SelectedEnvelope >= (int)m_Map.m_vpEnvelopes.size())
m_SelectedEnvelope = 0;
CurrentEnvelopeSwitched = true;
}
2010-05-29 07:25:38 +00:00
if(pEnvelope)
2008-01-12 12:27:55 +00:00
{
ToolBar.VSplitLeft(15.0f, nullptr, &ToolBar);
ToolBar.VSplitLeft(40.0f, &Button, &ToolBar);
UI()->DoLabel(&Button, "Name:", 10.0f, TEXTALIGN_MR);
2010-05-29 07:25:38 +00:00
ToolBar.VSplitLeft(3.0f, nullptr, &ToolBar);
ToolBar.VSplitLeft(ToolBar.w > ToolBar.h * 40 ? 80.0f : 60.0f, &Button, &ToolBar);
2010-05-29 07:25:38 +00:00
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInput s_NameInput;
s_NameInput.SetBuffer(pEnvelope->m_aName, sizeof(pEnvelope->m_aName));
if(DoEditBox(&s_NameInput, &Button, 10.0f, IGraphics::CORNER_ALL, "The name of the selected envelope"))
2014-01-19 03:02:01 +00:00
{
m_Map.m_Modified = true;
2014-01-19 03:02:01 +00:00
}
2007-12-02 17:55:45 +00:00
}
}
2010-05-29 07:25:38 +00:00
bool ShowColorBar = false;
if(pEnvelope && pEnvelope->m_Channels == 4)
{
ShowColorBar = true;
View.HSplitTop(20.0f, &ColorBar, &View);
ColorBar.Margin(2.0f, &ColorBar);
RenderBackground(ColorBar, m_CheckerTexture, 16.0f, 1.0f);
}
RenderBackground(View, m_CheckerTexture, 32.0f, 0.1f);
2010-05-29 07:25:38 +00:00
if(pEnvelope)
2007-12-02 17:55:45 +00:00
{
2022-06-15 17:34:41 +00:00
static std::vector<int> s_vSelection;
static int s_EnvelopeEditorID = 0;
2010-05-29 07:25:38 +00:00
static int s_ActiveChannels = 0xf;
ColorRGBA aColors[] = {ColorRGBA(1, 0.2f, 0.2f), ColorRGBA(0.2f, 1, 0.2f), ColorRGBA(0.2f, 0.2f, 1), ColorRGBA(1, 1, 0.2f)};
2015-07-24 22:04:12 +00:00
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
CUIRect Button;
2010-05-29 07:25:38 +00:00
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
ToolBar.VSplitLeft(15.0f, &Button, &ToolBar);
2023-01-24 19:11:33 +00:00
static const char *s_aapNames[4][CEnvPoint::MAX_CHANNELS] = {
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
{"V", "", "", ""},
{"", "", "", ""},
{"X", "Y", "R", ""},
{"R", "G", "B", "A"},
};
2010-05-29 07:25:38 +00:00
2023-01-24 19:11:33 +00:00
static const char *s_aapDescriptions[4][CEnvPoint::MAX_CHANNELS] = {
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
{"Volume of the envelope", "", "", ""},
{"", "", "", ""},
{"X-axis of the envelope", "Y-axis of the envelope", "Rotation of the envelope", ""},
{"Red value of the envelope", "Green value of the envelope", "Blue value of the envelope", "Alpha value of the envelope"},
};
2010-05-29 07:25:38 +00:00
2023-01-24 19:11:33 +00:00
static int s_aChannelButtons[CEnvPoint::MAX_CHANNELS] = {0};
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
int Bit = 1;
for(int i = 0; i < CEnvPoint::MAX_CHANNELS; i++, Bit <<= 1)
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
{
ToolBar.VSplitLeft(15.0f, &Button, &ToolBar);
if(i < pEnvelope->m_Channels)
{
2023-04-29 00:23:06 +00:00
int Corners = IGraphics::CORNER_NONE;
if(pEnvelope->m_Channels == 1)
Corners = IGraphics::CORNER_ALL;
else if(i == 0)
Corners = IGraphics::CORNER_L;
else if(i == pEnvelope->m_Channels - 1)
Corners = IGraphics::CORNER_R;
if(DoButton_Env(&s_aChannelButtons[i], s_aapNames[pEnvelope->m_Channels - 1][i], s_ActiveChannels & Bit, &Button, s_aapDescriptions[pEnvelope->m_Channels - 1][i], aColors[i], Corners))
s_ActiveChannels ^= Bit;
}
2010-05-29 07:25:38 +00:00
}
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
// sync checkbox
ToolBar.VSplitLeft(15.0f, nullptr, &ToolBar);
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
ToolBar.VSplitLeft(12.0f, &Button, &ToolBar);
static int s_SyncButton;
if(DoButton_Editor(&s_SyncButton, pEnvelope->m_Synchronized ? "X" : "", 0, &Button, 0, "Synchronize envelope animation to game time (restarts when you touch the start line)"))
pEnvelope->m_Synchronized = !pEnvelope->m_Synchronized;
ToolBar.VSplitLeft(4.0f, nullptr, &ToolBar);
ToolBar.VSplitLeft(40.0f, &Button, &ToolBar);
UI()->DoLabel(&Button, "Sync.", 10.0f, TEXTALIGN_ML);
Remove redundant conditions (always either true or false) According to cppcheck's `knownConditionTrueFalse` error: ``` src\base\system.cpp:1776:11: style: The comparison 'bytes == 0' is always true. [knownConditionTrueFalse] if(bytes == 0 && sock->ipv4sock >= 0) ^ src\base\system.cpp:1742:14: note: 'bytes' is assigned value '0' here. int bytes = 0; ^ src\base\system.cpp:1776:11: note: The comparison 'bytes == 0' is always true. if(bytes == 0 && sock->ipv4sock >= 0) ^ src\game\editor\io.cpp:887:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:874:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:887:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:914:33: style: Condition 'pSoundsItem->m_Version>=1' is always true [knownConditionTrueFalse] if(pSoundsItem->m_Version >= 1) ^ src\game\editor\io.cpp:901:33: note: Assuming that condition 'pSoundsItem->m_Version<1' is not redundant if(pSoundsItem->m_Version < 1 || pSoundsItem->m_Version > CMapItemLayerSounds::CURRENT_VERSION) ^ src\game\editor\io.cpp:914:33: note: Condition 'pSoundsItem->m_Version>=1' is always true if(pSoundsItem->m_Version >= 1) ^ src\engine\client\backend\opengl\backend_opengl.cpp:207:68: style: Condition '*pStr=='\0'' is always false [knownConditionTrueFalse] else if(LastWasNumber && (*pStr == '.' || *pStr == ' ' || *pStr == '\0')) ^ src\game\client\components\maplayers.cpp:851:110: style: Condition 'DoTextureCoords' is always true [knownConditionTrueFalse] mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\components\maplayers.cpp:849:11: note: Assuming that condition 'DoTextureCoords' is not redundant if(DoTextureCoords) ^ src\game\client\components\maplayers.cpp:851:110: note: Condition 'DoTextureCoords' is always true mem_copy_special(pUploadData + sizeof(vec2), pTmpTileTexCoords, sizeof(vec3), vtmpTiles.size() * 4, (DoTextureCoords ? (sizeof(vec2)) : 0)); ^ src\game\client\prediction\gameworld.cpp:567:5: style: Condition 'm_pParent' is always true [knownConditionTrueFalse] if(m_pParent && m_pParent->m_pChild && m_pParent->m_pChild != this) ^ src\game\client\components\menu_background.cpp:271:7: style: Condition 'NeedImageLoading' is always true [knownConditionTrueFalse] if(NeedImageLoading) ^ src\game\client\components\menu_background.cpp:268:23: note: Assignment 'NeedImageLoading=true', assigned value is 1 NeedImageLoading = true; ^ src\game\client\components\menu_background.cpp:271:7: note: Condition 'NeedImageLoading' is always true if(NeedImageLoading) ^ src\game\editor\editor.cpp:4991:6: style: Condition 'pEnvelope' is always true [knownConditionTrueFalse] if(pEnvelope) ^ ```
2022-10-30 12:52:20 +00:00
2010-05-29 07:25:38 +00:00
float EndTime = pEnvelope->EndTime();
if(EndTime < 1)
EndTime = 1;
pEnvelope->FindTopBottom(s_ActiveChannels);
float Top = pEnvelope->m_Top;
float Bottom = pEnvelope->m_Bottom;
if(Top < 1)
Top = 1;
if(Bottom >= 0)
Bottom = 0;
float TimeScale = EndTime / View.w;
float ValueScale = (Top - Bottom) / View.h;
2010-05-29 07:25:38 +00:00
if(UI()->MouseInside(&View))
2022-06-15 17:34:41 +00:00
UI()->SetHotItem(&s_EnvelopeEditorID);
2010-05-29 07:25:38 +00:00
2022-06-15 17:34:41 +00:00
if(UI()->HotItem() == &s_EnvelopeEditorID)
2008-01-12 12:27:55 +00:00
{
// do stuff
Remove redundant null-checks According to cppcheck's `nullPointerRedundantCheck` check: ``` src\game\client\components\menus_settings.cpp:729:8: warning: Either the condition 'pSkinToBeSelected==0' is redundant or there is possible null pointer dereference: pSkinToBeSelected. [nullPointerRedundantCheck] if((pSkinToBeSelected->GetName()[0] == 'x' && pSkinToBeSelected->GetName()[1] == '_')) ^ src\game\client\components\menus_settings.cpp:732:25: note: Assuming that condition 'pSkinToBeSelected==0' is not redundant if(pSkinToBeSelected == 0) ^ src\game\client\components\menus_settings.cpp:729:8: note: Null pointer dereference if((pSkinToBeSelected->GetName()[0] == 'x' && pSkinToBeSelected->GetName()[1] == '_')) ^ src\game\editor\editor.cpp:5034:19: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float EndTime = pEnvelope->EndTime(); ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5034:19: note: Null pointer dereference float EndTime = pEnvelope->EndTime(); ^ src\game\editor\editor.cpp:5038:3: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] pEnvelope->FindTopBottom(s_ActiveChannels); ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5038:3: note: Null pointer dereference pEnvelope->FindTopBottom(s_ActiveChannels); ^ src\game\editor\editor.cpp:5039:15: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float Top = pEnvelope->m_Top; ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5039:15: note: Null pointer dereference float Top = pEnvelope->m_Top; ^ src\game\editor\editor.cpp:5040:18: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float Bottom = pEnvelope->m_Bottom; ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5040:18: note: Null pointer dereference float Bottom = pEnvelope->m_Bottom; ^ src\game\editor\editor.cpp:5081:23: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] for(int c = 0; c < pEnvelope->m_Channels; c++) ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5081:23: note: Null pointer dereference for(int c = 0; c < pEnvelope->m_Channels; c++) ^ ```
2022-10-30 12:57:12 +00:00
if(UI()->MouseButtonClicked(1))
2008-01-12 12:27:55 +00:00
{
Remove redundant null-checks According to cppcheck's `nullPointerRedundantCheck` check: ``` src\game\client\components\menus_settings.cpp:729:8: warning: Either the condition 'pSkinToBeSelected==0' is redundant or there is possible null pointer dereference: pSkinToBeSelected. [nullPointerRedundantCheck] if((pSkinToBeSelected->GetName()[0] == 'x' && pSkinToBeSelected->GetName()[1] == '_')) ^ src\game\client\components\menus_settings.cpp:732:25: note: Assuming that condition 'pSkinToBeSelected==0' is not redundant if(pSkinToBeSelected == 0) ^ src\game\client\components\menus_settings.cpp:729:8: note: Null pointer dereference if((pSkinToBeSelected->GetName()[0] == 'x' && pSkinToBeSelected->GetName()[1] == '_')) ^ src\game\editor\editor.cpp:5034:19: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float EndTime = pEnvelope->EndTime(); ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5034:19: note: Null pointer dereference float EndTime = pEnvelope->EndTime(); ^ src\game\editor\editor.cpp:5038:3: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] pEnvelope->FindTopBottom(s_ActiveChannels); ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5038:3: note: Null pointer dereference pEnvelope->FindTopBottom(s_ActiveChannels); ^ src\game\editor\editor.cpp:5039:15: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float Top = pEnvelope->m_Top; ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5039:15: note: Null pointer dereference float Top = pEnvelope->m_Top; ^ src\game\editor\editor.cpp:5040:18: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float Bottom = pEnvelope->m_Bottom; ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5040:18: note: Null pointer dereference float Bottom = pEnvelope->m_Bottom; ^ src\game\editor\editor.cpp:5081:23: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] for(int c = 0; c < pEnvelope->m_Channels; c++) ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5081:23: note: Null pointer dereference for(int c = 0; c < pEnvelope->m_Channels; c++) ^ ```
2022-10-30 12:57:12 +00:00
// add point
int Time = (int)(((UI()->MouseX() - View.x) * TimeScale) * 1000.0f);
ColorRGBA Channels;
pEnvelope->Eval(Time / 1000.0f, Channels);
pEnvelope->AddPoint(Time,
f2fx(Channels.r), f2fx(Channels.g),
f2fx(Channels.b), f2fx(Channels.a));
m_Map.m_Modified = true;
2008-01-12 12:27:55 +00:00
}
Remove redundant null-checks According to cppcheck's `nullPointerRedundantCheck` check: ``` src\game\client\components\menus_settings.cpp:729:8: warning: Either the condition 'pSkinToBeSelected==0' is redundant or there is possible null pointer dereference: pSkinToBeSelected. [nullPointerRedundantCheck] if((pSkinToBeSelected->GetName()[0] == 'x' && pSkinToBeSelected->GetName()[1] == '_')) ^ src\game\client\components\menus_settings.cpp:732:25: note: Assuming that condition 'pSkinToBeSelected==0' is not redundant if(pSkinToBeSelected == 0) ^ src\game\client\components\menus_settings.cpp:729:8: note: Null pointer dereference if((pSkinToBeSelected->GetName()[0] == 'x' && pSkinToBeSelected->GetName()[1] == '_')) ^ src\game\editor\editor.cpp:5034:19: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float EndTime = pEnvelope->EndTime(); ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5034:19: note: Null pointer dereference float EndTime = pEnvelope->EndTime(); ^ src\game\editor\editor.cpp:5038:3: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] pEnvelope->FindTopBottom(s_ActiveChannels); ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5038:3: note: Null pointer dereference pEnvelope->FindTopBottom(s_ActiveChannels); ^ src\game\editor\editor.cpp:5039:15: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float Top = pEnvelope->m_Top; ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5039:15: note: Null pointer dereference float Top = pEnvelope->m_Top; ^ src\game\editor\editor.cpp:5040:18: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] float Bottom = pEnvelope->m_Bottom; ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5040:18: note: Null pointer dereference float Bottom = pEnvelope->m_Bottom; ^ src\game\editor\editor.cpp:5081:23: warning: Either the condition 'pEnvelope' is redundant or there is possible null pointer dereference: pEnvelope. [nullPointerRedundantCheck] for(int c = 0; c < pEnvelope->m_Channels; c++) ^ src\game\editor\editor.cpp:5056:7: note: Assuming that condition 'pEnvelope' is not redundant if(pEnvelope) ^ src\game\editor\editor.cpp:5081:23: note: Null pointer dereference for(int c = 0; c < pEnvelope->m_Channels; c++) ^ ```
2022-10-30 12:57:12 +00:00
m_ShowEnvelopePreview = SHOWENV_SELECTED;
m_pTooltip = "Press right mouse button to create a new point";
2008-01-12 12:27:55 +00:00
}
// render lines
{
2010-05-29 07:25:38 +00:00
UI()->ClipEnable(&View);
Graphics()->TextureClear();
2009-10-27 14:38:53 +00:00
Graphics()->LinesBegin();
2010-05-29 07:25:38 +00:00
for(int c = 0; c < pEnvelope->m_Channels; c++)
2008-01-12 12:27:55 +00:00
{
if(s_ActiveChannels & (1 << c))
Graphics()->SetColor(aColors[c].r, aColors[c].g, aColors[c].b, 1);
2008-01-12 12:27:55 +00:00
else
Graphics()->SetColor(aColors[c].r * 0.5f, aColors[c].g * 0.5f, aColors[c].b * 0.5f, 1);
2010-05-29 07:25:38 +00:00
float PrevX = 0;
ColorRGBA Channels;
pEnvelope->Eval(0.000001f, Channels);
float PrevValue = Channels[c];
2010-05-29 07:25:38 +00:00
int Steps = (int)((View.w / UI()->Screen()->w) * Graphics()->ScreenWidth());
2010-05-29 07:25:38 +00:00
for(int i = 1; i <= Steps; i++)
2008-01-12 12:27:55 +00:00
{
float a = i / (float)Steps;
pEnvelope->Eval(a * EndTime, Channels);
float v = Channels[c];
v = (v - Bottom) / (Top - Bottom);
2010-05-29 07:25:38 +00:00
IGraphics::CLineItem LineItem(View.x + PrevX * View.w, View.y + View.h - PrevValue * View.h, View.x + a * View.w, View.y + View.h - v * View.h);
2010-05-29 07:25:38 +00:00
Graphics()->LinesDraw(&LineItem, 1);
PrevX = a;
PrevValue = v;
2008-01-12 12:27:55 +00:00
}
}
2009-10-27 14:38:53 +00:00
Graphics()->LinesEnd();
UI()->ClipDisable();
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
// render curve options
2007-12-02 17:55:45 +00:00
{
for(int i = 0; i < (int)pEnvelope->m_vPoints.size() - 1; i++)
2008-01-12 12:27:55 +00:00
{
float t0 = pEnvelope->m_vPoints[i].m_Time / 1000.0f / EndTime;
float t1 = pEnvelope->m_vPoints[i + 1].m_Time / 1000.0f / EndTime;
2008-01-12 12:27:55 +00:00
2009-10-27 14:38:53 +00:00
CUIRect v;
v.x = CurveBar.x + (t0 + (t1 - t0) * 0.5f) * CurveBar.w;
2010-05-29 07:25:38 +00:00
v.y = CurveBar.y;
v.h = CurveBar.h;
v.w = CurveBar.h;
v.x -= v.w / 2;
void *pID = &pEnvelope->m_vPoints[i].m_Curvetype;
const char *apTypeName[] = {
"N", "L", "S", "F", "M"};
const char *pTypeName = "Invalid";
if(0 <= pEnvelope->m_vPoints[i].m_Curvetype && pEnvelope->m_vPoints[i].m_Curvetype < (int)std::size(apTypeName))
pTypeName = apTypeName[pEnvelope->m_vPoints[i].m_Curvetype];
if(DoButton_Editor(pID, pTypeName, 0, &v, 0, "Switch curve type"))
pEnvelope->m_vPoints[i].m_Curvetype = (pEnvelope->m_vPoints[i].m_Curvetype + 1) % NUM_CURVETYPES;
2008-01-12 12:27:55 +00:00
}
}
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
// render colorbar
2010-05-29 07:25:38 +00:00
if(ShowColorBar)
2008-01-12 12:27:55 +00:00
{
Graphics()->TextureClear();
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
for(int i = 0; i < (int)pEnvelope->m_vPoints.size() - 1; i++)
2008-01-12 12:27:55 +00:00
{
float r0 = fx2f(pEnvelope->m_vPoints[i].m_aValues[0]);
float g0 = fx2f(pEnvelope->m_vPoints[i].m_aValues[1]);
float b0 = fx2f(pEnvelope->m_vPoints[i].m_aValues[2]);
float a0 = fx2f(pEnvelope->m_vPoints[i].m_aValues[3]);
float r1 = fx2f(pEnvelope->m_vPoints[i + 1].m_aValues[0]);
float g1 = fx2f(pEnvelope->m_vPoints[i + 1].m_aValues[1]);
float b1 = fx2f(pEnvelope->m_vPoints[i + 1].m_aValues[2]);
float a1 = fx2f(pEnvelope->m_vPoints[i + 1].m_aValues[3]);
2010-05-29 07:25:38 +00:00
IGraphics::CColorVertex Array[4] = {IGraphics::CColorVertex(0, r0, g0, b0, a0),
IGraphics::CColorVertex(1, r1, g1, b1, a1),
IGraphics::CColorVertex(2, r1, g1, b1, a1),
IGraphics::CColorVertex(3, r0, g0, b0, a0)};
2010-05-29 07:25:38 +00:00
Graphics()->SetColorVertex(Array, 4);
float x0 = pEnvelope->m_vPoints[i].m_Time / 1000.0f / EndTime;
float x1 = pEnvelope->m_vPoints[i + 1].m_Time / 1000.0f / EndTime;
2010-05-29 07:25:38 +00:00
2023-01-24 17:09:56 +00:00
IGraphics::CQuadItem QuadItem(ColorBar.x + x0 * ColorBar.w, ColorBar.y, (x1 - x0) * ColorBar.w, ColorBar.h);
2010-05-29 07:25:38 +00:00
Graphics()->QuadsDrawTL(&QuadItem, 1);
2008-01-12 12:27:55 +00:00
}
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
// render handles
2015-03-30 03:06:08 +00:00
2015-03-30 09:44:32 +00:00
// keep track of last Env
static void *s_pID = nullptr;
2015-03-30 03:06:08 +00:00
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
static CLineInputNumber s_CurValueInput;
static CLineInputNumber s_CurTimeInput;
2015-03-30 03:06:08 +00:00
if(CurrentEnvelopeSwitched)
{
s_pID = nullptr;
// update displayed text
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
s_CurValueInput.SetFloat(0.0f);
s_CurTimeInput.SetFloat(0.0f);
}
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
int CurrentValue = 0, CurrentTime = 0;
Graphics()->TextureClear();
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
2010-05-29 07:25:38 +00:00
for(int c = 0; c < pEnvelope->m_Channels; c++)
2008-01-12 12:27:55 +00:00
{
if(!(s_ActiveChannels & (1 << c)))
2008-01-12 12:27:55 +00:00
continue;
2010-05-29 07:25:38 +00:00
for(size_t i = 0; i < pEnvelope->m_vPoints.size(); i++)
2008-01-12 12:27:55 +00:00
{
float x0 = pEnvelope->m_vPoints[i].m_Time / 1000.0f / EndTime;
float y0 = (fx2f(pEnvelope->m_vPoints[i].m_aValues[c]) - Bottom) / (Top - Bottom);
2010-05-29 07:25:38 +00:00
CUIRect Final;
Final.x = View.x + x0 * View.w;
Final.y = View.y + View.h - y0 * View.h;
2010-05-29 07:25:38 +00:00
Final.x -= 2.0f;
Final.y -= 2.0f;
Final.w = 4.0f;
Final.h = 4.0f;
void *pID = &pEnvelope->m_vPoints[i].m_aValues[c];
2008-01-12 12:27:55 +00:00
2010-05-29 07:25:38 +00:00
if(UI()->MouseInside(&Final))
UI()->SetHotItem(pID);
2010-05-29 07:25:38 +00:00
float ColorMod = 1.0f;
if(UI()->CheckActiveItem(pID))
2008-01-12 12:27:55 +00:00
{
2009-10-27 14:38:53 +00:00
if(!UI()->MouseButton(0))
2008-01-12 12:27:55 +00:00
{
2011-08-15 18:12:31 +00:00
m_SelectedQuadEnvelope = -1;
m_SelectedEnvelopePoint = -1;
2011-08-14 14:31:48 +00:00
UI()->SetActiveItem(nullptr);
2008-01-12 12:27:55 +00:00
}
else
2011-08-11 08:59:14 +00:00
{
if(Input()->ShiftIsPressed())
2008-01-12 12:27:55 +00:00
{
if(i != 0)
{
if(Input()->ModifierIsPressed())
pEnvelope->m_vPoints[i].m_Time += (int)((m_MouseDeltaX));
2010-07-18 11:44:30 +00:00
else
pEnvelope->m_vPoints[i].m_Time += (int)((m_MouseDeltaX * TimeScale) * 1000.0f);
if(pEnvelope->m_vPoints[i].m_Time < pEnvelope->m_vPoints[i - 1].m_Time)
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i - 1].m_Time + 1;
if(i + 1 != pEnvelope->m_vPoints.size() && pEnvelope->m_vPoints[i].m_Time > pEnvelope->m_vPoints[i + 1].m_Time)
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i + 1].m_Time - 1;
2008-01-12 12:27:55 +00:00
}
}
else
{
if(Input()->ModifierIsPressed())
pEnvelope->m_vPoints[i].m_aValues[c] -= f2fx(m_MouseDeltaY * 0.001f);
else
pEnvelope->m_vPoints[i].m_aValues[c] -= f2fx(m_MouseDeltaY * ValueScale);
}
2011-08-15 18:12:31 +00:00
m_SelectedQuadEnvelope = m_SelectedEnvelope;
m_ShowEnvelopePreview = SHOWENV_SELECTED;
2011-08-15 18:12:31 +00:00
m_SelectedEnvelopePoint = i;
2015-03-30 09:44:32 +00:00
m_Map.m_Modified = true;
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
ColorMod = 100.0f;
Graphics()->SetColor(1, 1, 1, 1);
2008-01-12 12:27:55 +00:00
}
else if(UI()->HotItem() == pID)
2008-01-12 12:27:55 +00:00
{
2009-10-27 14:38:53 +00:00
if(UI()->MouseButton(0))
2008-01-12 12:27:55 +00:00
{
2022-06-15 17:34:41 +00:00
s_vSelection.clear();
s_vSelection.push_back(i);
UI()->SetActiveItem(pID);
2015-03-30 09:44:32 +00:00
// track it
s_pID = pID;
2008-01-12 12:27:55 +00:00
}
// remove point
2015-03-30 09:44:32 +00:00
if(UI()->MouseButtonClicked(1))
{
if(s_pID == pID)
{
s_pID = nullptr;
// update displayed text
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
s_CurValueInput.SetFloat(0.0f);
s_CurTimeInput.SetFloat(0.0f);
}
pEnvelope->m_vPoints.erase(pEnvelope->m_vPoints.begin() + i);
m_Map.m_Modified = true;
}
2010-05-29 07:25:38 +00:00
m_ShowEnvelopePreview = SHOWENV_SELECTED;
2010-05-29 07:25:38 +00:00
ColorMod = 100.0f;
Graphics()->SetColor(1, 0.75f, 0.75f, 1);
2018-02-04 15:00:47 +00:00
m_pTooltip = "Left mouse to drag. Hold ctrl to be more precise. Hold shift to alter time point as well. Right click to delete.";
2008-01-12 12:27:55 +00:00
}
if(pID == s_pID && (Input()->KeyIsPressed(KEY_RETURN) || Input()->KeyIsPressed(KEY_KP_ENTER)))
2015-03-30 09:44:32 +00:00
{
if(i != 0)
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
pEnvelope->m_vPoints[i].m_Time = s_CurTimeInput.GetFloat() * 1000.0f;
2015-03-30 03:06:08 +00:00
if(pEnvelope->m_vPoints[i].m_Time < pEnvelope->m_vPoints[i - 1].m_Time)
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i - 1].m_Time + 1;
if(i + 1 != pEnvelope->m_vPoints.size() && pEnvelope->m_vPoints[i].m_Time > pEnvelope->m_vPoints[i + 1].m_Time)
pEnvelope->m_vPoints[i].m_Time = pEnvelope->m_vPoints[i + 1].m_Time - 1;
2015-03-30 09:44:32 +00:00
}
else
pEnvelope->m_vPoints[i].m_Time = 0.0f;
2015-03-30 03:06:08 +00:00
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
s_CurTimeInput.SetFloat(pEnvelope->m_vPoints[i].m_Time / 1000.0f);
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
pEnvelope->m_vPoints[i].m_aValues[c] = f2fx(s_CurValueInput.GetFloat());
s_CurValueInput.SetFloat(fx2f(pEnvelope->m_vPoints[i].m_aValues[c]));
2015-03-30 09:44:32 +00:00
}
2015-03-30 03:06:08 +00:00
2022-05-30 20:44:12 +00:00
if(UI()->CheckActiveItem(pID))
2015-03-30 09:44:32 +00:00
{
CurrentTime = pEnvelope->m_vPoints[i].m_Time;
CurrentValue = pEnvelope->m_vPoints[i].m_aValues[c];
2015-03-30 03:06:08 +00:00
2015-03-30 09:44:32 +00:00
// update displayed text
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
s_CurValueInput.SetFloat(fx2f(CurrentValue));
s_CurTimeInput.SetFloat(CurrentTime / 1000.0f);
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
if(m_SelectedQuadEnvelope == m_SelectedEnvelope && m_SelectedEnvelopePoint == (int)i)
2011-08-15 18:12:31 +00:00
Graphics()->SetColor(1.0f, 1.0f, 1.0f, 1.0f);
else
Graphics()->SetColor(aColors[c].r * ColorMod, aColors[c].g * ColorMod, aColors[c].b * ColorMod, 1.0f);
2010-05-29 07:25:38 +00:00
IGraphics::CQuadItem QuadItem(Final.x, Final.y, Final.w, Final.h);
Graphics()->QuadsDrawTL(&QuadItem, 1);
2008-01-12 12:27:55 +00:00
}
}
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
2008-01-12 12:27:55 +00:00
2015-03-30 09:44:32 +00:00
CUIRect ToolBar1;
CUIRect ToolBar2;
ToolBar.VSplitMid(&ToolBar1, &ToolBar2);
ToolBar1.VSplitRight(3.0f, &ToolBar1, nullptr);
ToolBar2.VSplitRight(3.0f, &ToolBar2, nullptr);
if(ToolBar.w > ToolBar.h * 21)
{
CUIRect Label1;
CUIRect Label2;
ToolBar1.VSplitMid(&Label1, &ToolBar1);
ToolBar2.VSplitMid(&Label2, &ToolBar2);
Label1.VSplitRight(3.0f, &Label1, nullptr);
Label2.VSplitRight(3.0f, &Label2, nullptr);
UI()->DoLabel(&Label1, "Value:", 10.0f, TEXTALIGN_MR);
UI()->DoLabel(&Label2, "Time (in s):", 10.0f, TEXTALIGN_MR);
}
2015-03-30 03:06:08 +00:00
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
DoEditBox(&s_CurValueInput, &ToolBar1, 10.0f, IGraphics::CORNER_ALL, "The value of the selected envelope point");
DoEditBox(&s_CurTimeInput, &ToolBar2, 10.0f, IGraphics::CORNER_ALL, "The time of the selected envelope point");
2007-12-02 17:55:45 +00:00
}
}
2008-01-12 12:27:55 +00:00
}
void CEditor::RenderServerSettingsEditor(CUIRect View, bool ShowServerSettingsEditorLast)
{
RenderExtraEditorDragBar(View, &m_ServerSettingsEditorSplit);
static int s_CommandSelectedIndex = -1;
CUIRect ToolBar;
View.HSplitTop(20.0f, &ToolBar, &View);
ToolBar.Margin(2.0f, &ToolBar);
// do the toolbar
{
CUIRect Button;
// command line
ToolBar.VSplitLeft(5.0f, nullptr, &Button);
UI()->DoLabel(&Button, "Command:", 12.0f, TEXTALIGN_ML);
Button.VSplitLeft(70.0f, nullptr, &Button);
Button.VSplitLeft(180.0f, &Button, nullptr);
if(!ShowServerSettingsEditorLast) // Just activated
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UI()->SetActiveItem(&m_SettingsCommandInput);
DoClearableEditBox(&m_SettingsCommandInput, &Button, 12.0f);
// buttons
ToolBar.VSplitRight(50.0f, &ToolBar, &Button);
static int s_AddButton = 0;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(DoButton_Editor(&s_AddButton, "Add", 0, &Button, 0, "Add a command to command list.") || ((Input()->KeyPress(KEY_RETURN) || Input()->KeyPress(KEY_KP_ENTER)) && UI()->LastActiveItem() == &m_SettingsCommandInput && m_Dialog == DIALOG_NONE))
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(!m_SettingsCommandInput.IsEmpty() && str_find(m_SettingsCommandInput.GetString(), " "))
{
bool Found = false;
for(const auto &Setting : m_Map.m_vSettings)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(!str_comp(Setting.m_aCommand, m_SettingsCommandInput.GetString()))
{
Found = true;
break;
}
if(!Found)
{
CEditorMap::CSetting Setting;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
str_copy(Setting.m_aCommand, m_SettingsCommandInput.GetString());
m_Map.m_vSettings.push_back(Setting);
s_CommandSelectedIndex = m_Map.m_vSettings.size() - 1;
}
}
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UI()->SetActiveItem(&m_SettingsCommandInput);
}
if(!m_Map.m_vSettings.empty() && s_CommandSelectedIndex >= 0 && (size_t)s_CommandSelectedIndex < m_Map.m_vSettings.size())
{
ToolBar.VSplitRight(50.0f, &ToolBar, &Button);
Button.VSplitRight(5.0f, &Button, nullptr);
static int s_ModButton = 0;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(DoButton_Editor(&s_ModButton, "Mod", 0, &Button, 0, "Modify a command from the command list.") || (Input()->KeyPress(KEY_M) && UI()->LastActiveItem() != &m_SettingsCommandInput && m_Dialog == DIALOG_NONE))
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(!m_SettingsCommandInput.IsEmpty() && str_comp(m_Map.m_vSettings[s_CommandSelectedIndex].m_aCommand, m_SettingsCommandInput.GetString()) != 0 && str_find(m_SettingsCommandInput.GetString(), " "))
{
bool Found = false;
int i;
for(i = 0; i < (int)m_Map.m_vSettings.size(); i++)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(i != s_CommandSelectedIndex && !str_comp(m_Map.m_vSettings[i].m_aCommand, m_SettingsCommandInput.GetString()))
{
Found = true;
break;
}
if(Found)
{
m_Map.m_vSettings.erase(m_Map.m_vSettings.begin() + s_CommandSelectedIndex);
s_CommandSelectedIndex = i > s_CommandSelectedIndex ? i - 1 : i;
}
else
{
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
str_copy(m_Map.m_vSettings[s_CommandSelectedIndex].m_aCommand, m_SettingsCommandInput.GetString());
}
}
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
UI()->SetActiveItem(&m_SettingsCommandInput);
}
ToolBar.VSplitRight(50.0f, &ToolBar, &Button);
Button.VSplitRight(5.0f, &Button, nullptr);
static int s_DelButton = 0;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
if(DoButton_Editor(&s_DelButton, "Del", 0, &Button, 0, "Delete a command from the command list.") || (Input()->KeyPress(KEY_DELETE) && UI()->LastActiveItem() != &m_SettingsCommandInput && m_Dialog == DIALOG_NONE))
{
m_Map.m_vSettings.erase(m_Map.m_vSettings.begin() + s_CommandSelectedIndex);
if(s_CommandSelectedIndex >= (int)m_Map.m_vSettings.size())
s_CommandSelectedIndex = m_Map.m_vSettings.size() - 1;
if(s_CommandSelectedIndex >= 0)
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_SettingsCommandInput.Set(m_Map.m_vSettings[s_CommandSelectedIndex].m_aCommand);
UI()->SetActiveItem(&m_SettingsCommandInput);
}
ToolBar.VSplitRight(25.0f, &ToolBar, &Button);
Button.VSplitRight(5.0f, &Button, nullptr);
static int s_DownButton = 0;
if(s_CommandSelectedIndex < (int)m_Map.m_vSettings.size() - 1 && DoButton_Editor(&s_DownButton, "", 0, &Button, 0, "Move command down"))
{
std::swap(m_Map.m_vSettings[s_CommandSelectedIndex], m_Map.m_vSettings[s_CommandSelectedIndex + 1]);
s_CommandSelectedIndex++;
}
ToolBar.VSplitRight(25.0f, &ToolBar, &Button);
Button.VSplitRight(5.0f, &Button, nullptr);
static int s_UpButton = 0;
if(s_CommandSelectedIndex > 0 && DoButton_Editor(&s_UpButton, "", 0, &Button, 0, "Move command up"))
{
std::swap(m_Map.m_vSettings[s_CommandSelectedIndex], m_Map.m_vSettings[s_CommandSelectedIndex - 1]);
s_CommandSelectedIndex--;
}
}
}
View.HSplitTop(2.0f, nullptr, &View);
RenderBackground(View, m_CheckerTexture, 32.0f, 0.1f);
CUIRect ListBox;
View.Margin(1.0f, &ListBox);
const float ButtonHeight = 15.0f;
const float ButtonMargin = 2.0f;
static CScrollRegion s_ScrollRegion;
vec2 ScrollOffset(0.0f, 0.0f);
CScrollRegionParams ScrollParams;
ScrollParams.m_ScrollUnit = (ButtonHeight + ButtonMargin) * 5.0f;
s_ScrollRegion.Begin(&ListBox, &ScrollOffset, &ScrollParams);
ListBox.y += ScrollOffset.y;
for(size_t i = 0; i < m_Map.m_vSettings.size(); i++)
{
CUIRect Button;
ListBox.HSplitTop(ButtonHeight, &Button, &ListBox);
ListBox.HSplitTop(ButtonMargin, nullptr, &ListBox);
Button.VSplitLeft(5.0f, nullptr, &Button);
if(s_ScrollRegion.AddRect(Button))
{
if(DoButton_MenuItem(&m_Map.m_vSettings[i], m_Map.m_vSettings[i].m_aCommand, s_CommandSelectedIndex >= 0 && (size_t)s_CommandSelectedIndex == i, &Button, 0, nullptr))
{
s_CommandSelectedIndex = i;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_SettingsCommandInput.Set(m_Map.m_vSettings[i].m_aCommand);
UI()->SetActiveItem(&m_SettingsCommandInput);
}
}
}
s_ScrollRegion.End();
}
void CEditor::RenderExtraEditorDragBar(CUIRect View, float *pSplit)
{
const CUIRect DragBar = {
View.x,
View.y - 2.0f, // use margin
View.w,
22.0f,
};
enum EDragOperation
{
OP_NONE,
OP_DRAGGING,
OP_CLICKED
};
static EDragOperation s_Operation = OP_NONE;
static float s_InitialMouseY = 0.0f;
static float s_InitialMouseOffsetY = 0.0f;
bool Clicked;
bool Abrupted;
if(int Result = DoButton_DraggableEx(&s_Operation, "", 8, &DragBar, &Clicked, &Abrupted, 0, "Change the size of the editor by dragging."))
{
if(s_Operation == OP_NONE && Result == 1)
{
s_InitialMouseY = UI()->MouseY();
s_InitialMouseOffsetY = UI()->MouseY() - DragBar.y;
s_Operation = OP_CLICKED;
}
if(Clicked || Abrupted)
s_Operation = OP_NONE;
if(s_Operation == OP_CLICKED && absolute(UI()->MouseY() - s_InitialMouseY) > 5.0f)
s_Operation = OP_DRAGGING;
if(s_Operation == OP_DRAGGING)
*pSplit = clamp(s_InitialMouseOffsetY + View.y + View.h - UI()->MouseY(), 100.0f, 400.0f);
}
}
2010-05-29 07:25:38 +00:00
void CEditor::RenderMenubar(CUIRect MenuBar)
2008-01-13 22:03:32 +00:00
{
CUIRect FileButton;
static int s_FileButton = 0;
MenuBar.VSplitLeft(60.0f, &FileButton, &MenuBar);
if(DoButton_Menu(&s_FileButton, "File", 0, &FileButton, 0, nullptr))
{
static SPopupMenuId s_PopupMenuFileId;
UI()->DoPopupMenu(&s_PopupMenuFileId, FileButton.x, FileButton.y + FileButton.h - 1.0f, 120.0f, 174.0f, this, PopupMenuFile, IGraphics::CORNER_R | IGraphics::CORNER_B);
}
MenuBar.VSplitLeft(5.0f, nullptr, &MenuBar);
CUIRect ToolsButton;
static int s_ToolsButton = 0;
MenuBar.VSplitLeft(60.0f, &ToolsButton, &MenuBar);
if(DoButton_Menu(&s_ToolsButton, "Tools", 0, &ToolsButton, 0, nullptr))
{
static SPopupMenuId s_PopupMenuToolsId;
UI()->DoPopupMenu(&s_PopupMenuToolsId, ToolsButton.x, ToolsButton.y + ToolsButton.h - 1.0f, 200.0f, 50.0f, this, PopupMenuTools, IGraphics::CORNER_R | IGraphics::CORNER_B);
}
MenuBar.VSplitLeft(5.0f, nullptr, &MenuBar);
CUIRect SettingsButton;
static int s_SettingsButton = 0;
MenuBar.VSplitLeft(60.0f, &SettingsButton, &MenuBar);
if(DoButton_Menu(&s_SettingsButton, "Settings", 0, &SettingsButton, 0, nullptr))
{
static SPopupMenuId s_PopupMenuEntitiesId;
2023-05-01 20:44:03 +00:00
UI()->DoPopupMenu(&s_PopupMenuEntitiesId, SettingsButton.x, SettingsButton.y + SettingsButton.h - 1.0f, 200.0f, 64.0f, this, PopupMenuSettings, IGraphics::CORNER_R | IGraphics::CORNER_B);
}
2008-01-13 22:03:32 +00:00
CUIRect Info, Close;
MenuBar.VSplitLeft(5.0f, nullptr, &MenuBar);
MenuBar.VSplitRight(20.0f, &MenuBar, &Close);
Close.VSplitLeft(5.0f, nullptr, &Close);
MenuBar.VSplitLeft(MenuBar.w * 0.75f, &MenuBar, &Info);
char aBuf[128];
2011-03-20 16:04:03 +00:00
str_format(aBuf, sizeof(aBuf), "File: %s", m_aFileName);
UI()->DoLabel(&MenuBar, aBuf, 10.0f, TEXTALIGN_ML);
2017-09-03 06:53:54 +00:00
char aTimeStr[6];
2017-09-03 06:48:21 +00:00
str_timestamp_format(aTimeStr, sizeof(aTimeStr), "%H:%M");
str_format(aBuf, sizeof(aBuf), "X: %i, Y: %i, Z: %.1f, A: %.1f, G: %i %s", (int)UI()->MouseWorldX() / 32, (int)UI()->MouseWorldY() / 32, m_Zoom, m_AnimateSpeed, m_GridFactor, aTimeStr);
UI()->DoLabel(&Info, aBuf, 10.0f, TEXTALIGN_MR);
static int s_CloseButton = 0;
if(DoButton_Editor(&s_CloseButton, "×", 0, &Close, 0, "Exits from the editor") || (m_Dialog == DIALOG_NONE && !UI()->IsPopupOpen() && !m_PopupEventActivated && Input()->KeyPress(KEY_ESCAPE)))
g_Config.m_ClEditor = 0;
2008-01-13 22:03:32 +00:00
}
2008-01-13 13:42:59 +00:00
2010-05-29 07:25:38 +00:00
void CEditor::Render()
2008-01-12 12:27:55 +00:00
{
// basic start
2022-03-20 17:04:00 +00:00
Graphics()->Clear(0.0f, 0.0f, 0.0f);
2010-05-29 07:25:38 +00:00
CUIRect View = *UI()->Screen();
2021-09-22 19:48:55 +00:00
UI()->MapScreen();
2010-05-29 07:25:38 +00:00
float Width = View.w;
float Height = View.h;
2008-01-12 12:27:55 +00:00
// reset tip
m_pTooltip = nullptr;
2010-05-29 07:25:38 +00:00
if(m_EditBoxActive)
--m_EditBoxActive;
2008-01-12 12:27:55 +00:00
// render checker
RenderBackground(View, m_CheckerTexture, 32.0f, 1.0f);
2010-05-29 07:25:38 +00:00
CUIRect MenuBar, CModeBar, ToolBar, StatusBar, ExtraEditor, ToolBox;
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
m_ShowPicker = Input()->KeyIsPressed(KEY_SPACE) && m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && UI()->LastActiveItem() != &m_SettingsCommandInput && m_vSelectedLayers.size() == 1;
2010-05-29 07:25:38 +00:00
if(m_GuiActive)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
View.HSplitTop(16.0f, &MenuBar, &View);
View.HSplitTop(53.0f, &ToolBar, &View);
View.VSplitLeft(100.0f, &ToolBox, &View);
2010-05-29 07:25:38 +00:00
View.HSplitBottom(16.0f, &View, &StatusBar);
if(m_ShowEnvelopeEditor && !m_ShowPicker)
View.HSplitBottom(m_EnvelopeEditorSplit, &View, &ExtraEditor);
if(m_ShowServerSettingsEditor && !m_ShowPicker)
View.HSplitBottom(m_ServerSettingsEditorSplit, &View, &ExtraEditor);
2008-03-29 11:44:03 +00:00
}
else
{
// hack to get keyboard inputs from toolbar even when GUI is not active
ToolBar.x = -100;
ToolBar.y = -100;
ToolBar.w = 50;
ToolBar.h = 50;
}
2010-05-29 07:25:38 +00:00
2008-03-29 11:44:03 +00:00
// a little hack for now
2010-05-29 07:25:38 +00:00
if(m_Mode == MODE_LAYERS)
2018-04-04 19:41:14 +00:00
DoMapEditor(View);
2010-05-29 07:25:38 +00:00
// do zooming
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0)
{
if(Input()->KeyPress(KEY_KP_MINUS))
ChangeZoom(50.0f);
if(Input()->KeyPress(KEY_KP_PLUS))
ChangeZoom(-50.0f);
if(Input()->KeyPress(KEY_KP_MULTIPLY))
{
m_EditorOffsetX = 0;
m_EditorOffsetY = 0;
SetZoom(100.0f);
}
}
2018-10-02 01:52:01 +00:00
for(int i = KEY_1; i <= KEY_0; i++)
{
if(m_Dialog != DIALOG_NONE || m_EditBoxActive != 0)
break;
if(Input()->KeyPress(i))
{
int Slot = i - KEY_1;
if(Input()->ModifierIsPressed() && !m_Brush.IsEmpty())
2018-10-02 01:52:01 +00:00
{
dbg_msg("editor", "saving current brush to %d", Slot);
if(m_apSavedBrushes[Slot])
{
CLayerGroup *pPrev = m_apSavedBrushes[Slot];
for(auto &pLayer : pPrev->m_vpLayers)
2018-10-02 01:52:01 +00:00
{
if(pLayer->m_BrushRefCount == 1)
delete pLayer;
2018-10-02 01:52:01 +00:00
else
pLayer->m_BrushRefCount--;
2018-10-02 01:52:01 +00:00
}
}
delete m_apSavedBrushes[Slot];
m_apSavedBrushes[Slot] = new CLayerGroup(m_Brush);
for(auto &pLayer : m_apSavedBrushes[Slot]->m_vpLayers)
pLayer->m_BrushRefCount++;
2018-10-02 01:52:01 +00:00
}
else if(m_apSavedBrushes[Slot])
{
dbg_msg("editor", "loading brush from slot %d", Slot);
CLayerGroup *pNew = m_apSavedBrushes[Slot];
for(auto &pLayer : pNew->m_vpLayers)
pLayer->m_BrushRefCount++;
2018-10-02 01:52:01 +00:00
m_Brush = *pNew;
}
}
}
float Brightness = 0.25f;
2010-05-29 07:25:38 +00:00
if(m_GuiActive)
2008-03-29 11:44:03 +00:00
{
RenderBackground(MenuBar, m_BackgroundTexture, 128.0f, Brightness * 0);
2010-05-29 07:25:38 +00:00
MenuBar.Margin(2.0f, &MenuBar);
2008-03-29 11:44:03 +00:00
RenderBackground(ToolBox, m_BackgroundTexture, 128.0f, Brightness);
2010-05-29 07:25:38 +00:00
ToolBox.Margin(2.0f, &ToolBox);
RenderBackground(ToolBar, m_BackgroundTexture, 128.0f, Brightness);
2010-05-29 07:25:38 +00:00
ToolBar.Margin(2.0f, &ToolBar);
ToolBar.VSplitLeft(100.0f, &CModeBar, &ToolBar);
RenderBackground(StatusBar, m_BackgroundTexture, 128.0f, Brightness);
2010-05-29 07:25:38 +00:00
StatusBar.Margin(2.0f, &StatusBar);
}
2007-05-22 15:03:32 +00:00
2019-04-05 23:15:02 +00:00
// show mentions
if(m_GuiActive && m_Mentions)
{
char aBuf[16];
if(m_Mentions == 1)
{
2019-04-06 11:46:47 +00:00
str_copy(aBuf, Localize("1 new mention"), sizeof(aBuf));
2019-04-05 23:15:02 +00:00
}
else if(m_Mentions <= 9)
{
2019-04-06 11:46:47 +00:00
str_format(aBuf, sizeof(aBuf), Localize("%d new mentions"), m_Mentions);
2019-04-05 23:15:02 +00:00
}
else
{
2019-04-06 11:46:47 +00:00
str_copy(aBuf, Localize("9+ new mentions"), sizeof(aBuf));
2019-04-05 23:15:02 +00:00
}
TextRender()->TextColor(1.0f, 0.0f, 0.0f, 1.0f);
TextRender()->Text(5.0f, 27.0f, 10.0f, aBuf, -1.0f);
2019-04-05 23:15:02 +00:00
TextRender()->TextColor(1.0f, 1.0f, 1.0f, 1.0f);
}
// do the toolbar
if(m_Mode == MODE_LAYERS)
DoToolbar(ToolBar);
2010-05-29 07:25:38 +00:00
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0)
{
const bool ModPressed = Input()->ModifierIsPressed();
const bool ShiftPressed = Input()->ShiftIsPressed();
const bool AltPressed = Input()->AltIsPressed();
// ctrl+n to create new map
if(Input()->KeyPress(KEY_N) && ModPressed)
{
if(HasUnsavedData())
{
if(!m_PopupEventWasActivated)
{
m_PopupEventType = POPEVENT_NEW;
m_PopupEventActivated = true;
}
}
else
{
Reset();
m_aFileName[0] = 0;
}
}
// ctrl+a to append map
if(Input()->KeyPress(KEY_A) && ModPressed)
{
InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Append map", "Append", "maps", "", CallbackAppendMap, this);
}
// ctrl+o or ctrl+l to open
if((Input()->KeyPress(KEY_O) || Input()->KeyPress(KEY_L)) && ModPressed)
{
if(ShiftPressed)
{
if(HasUnsavedData())
{
if(!m_PopupEventWasActivated)
{
m_PopupEventType = POPEVENT_LOADCURRENT;
m_PopupEventActivated = true;
}
}
else
{
LoadCurrentMap();
}
}
else
{
if(HasUnsavedData())
{
if(!m_PopupEventWasActivated)
{
m_PopupEventType = POPEVENT_LOAD;
m_PopupEventActivated = true;
}
}
else
{
InvokeFileDialog(IStorage::TYPE_ALL, FILETYPE_MAP, "Load map", "Load", "maps", "", CallbackOpenMap, this);
}
}
}
// ctrl+shift+alt+s to save as
if(Input()->KeyPress(KEY_S) && ModPressed && ShiftPressed && AltPressed)
InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", CallbackSaveCopyMap, this);
// ctrl+shift+s to save as
else if(Input()->KeyPress(KEY_S) && ModPressed && ShiftPressed)
InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", CallbackSaveMap, this);
// ctrl+s to save
else if(Input()->KeyPress(KEY_S) && ModPressed)
{
if(m_aFileName[0] && m_ValidSaveFilename)
{
if(!m_PopupEventWasActivated)
{
str_copy(m_aFileSaveName, m_aFileName, sizeof(m_aFileSaveName));
CallbackSaveMap(m_aFileSaveName, IStorage::TYPE_SAVE, this);
}
}
else
InvokeFileDialog(IStorage::TYPE_SAVE, FILETYPE_MAP, "Save map", "Save", "maps", "", CallbackSaveMap, this);
}
}
if(m_GuiActive)
{
2019-03-18 01:34:24 +00:00
if(!m_ShowPicker)
2008-01-12 12:27:55 +00:00
{
2019-03-18 01:34:24 +00:00
if(m_ShowEnvelopeEditor || m_ShowServerSettingsEditor)
{
RenderBackground(ExtraEditor, m_BackgroundTexture, 128.0f, Brightness);
2019-03-18 01:34:24 +00:00
ExtraEditor.Margin(2.0f, &ExtraEditor);
}
2014-01-19 03:02:01 +00:00
}
2010-05-29 07:25:38 +00:00
2018-04-04 19:41:14 +00:00
if(m_Mode == MODE_LAYERS)
RenderLayers(ToolBox);
2018-04-04 19:41:14 +00:00
else if(m_Mode == MODE_IMAGES)
{
RenderImagesList(ToolBox);
RenderSelectedImage(View);
}
2018-04-04 19:41:14 +00:00
else if(m_Mode == MODE_SOUNDS)
RenderSounds(ToolBox);
2018-04-04 19:41:14 +00:00
}
2008-03-29 11:44:03 +00:00
2021-09-22 19:48:55 +00:00
UI()->MapScreen();
2008-01-12 12:27:55 +00:00
2010-05-29 07:25:38 +00:00
if(m_GuiActive)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
RenderMenubar(MenuBar);
RenderModebar(CModeBar);
if(!m_ShowPicker)
{
if(m_ShowEnvelopeEditor)
RenderEnvelopeEditor(ExtraEditor);
static bool s_ShowServerSettingsEditorLast = false;
if(m_ShowServerSettingsEditor)
{
RenderServerSettingsEditor(ExtraEditor, s_ShowServerSettingsEditorLast);
}
s_ShowServerSettingsEditorLast = m_ShowServerSettingsEditor;
}
2008-01-12 12:27:55 +00:00
}
2008-01-13 16:30:30 +00:00
2010-05-29 07:25:38 +00:00
if(m_Dialog == DIALOG_FILE)
2008-01-13 22:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
static int s_NullUiTarget = 0;
UI()->SetHotItem(&s_NullUiTarget);
RenderFileDialog();
2008-01-13 22:03:32 +00:00
}
if(m_PopupEventActivated)
{
static SPopupMenuId s_PopupEventId;
constexpr float PopupWidth = 400.0f;
constexpr float PopupHeight = 150.0f;
UI()->DoPopupMenu(&s_PopupEventId, Width / 2.0f - PopupWidth / 2.0f, Height / 2.0f - PopupHeight / 2.0f, PopupWidth, PopupHeight, this, PopupEvent);
m_PopupEventActivated = false;
m_PopupEventWasActivated = true;
}
if(m_Dialog == DIALOG_NONE && !UI()->IsPopupHovered() && (!m_GuiActive || UI()->MouseInside(&View)))
2020-09-24 16:52:31 +00:00
{
if(Input()->KeyPress(KEY_MOUSE_WHEEL_DOWN))
ChangeZoom(20.0f);
if(Input()->KeyPress(KEY_MOUSE_WHEEL_UP))
ChangeZoom(-20.0f);
2020-09-24 16:52:31 +00:00
}
UpdateZoom();
2020-09-24 16:52:31 +00:00
// Popup menus must be rendered before the statusbar, because UI elements in
// popup menus can set tooltips, which are rendered in the status bar.
UI()->RenderPopupMenus();
2010-05-29 07:25:38 +00:00
if(m_GuiActive)
RenderStatusbar(StatusBar);
//
2010-05-29 07:25:38 +00:00
if(g_Config.m_EdShowkeys)
{
2021-09-22 19:48:55 +00:00
UI()->MapScreen();
2010-05-29 07:25:38 +00:00
CTextCursor Cursor;
TextRender()->SetCursor(&Cursor, View.x + 10, View.y + View.h - 24 - 10, 24.0f, TEXTFLAG_RENDER);
2010-05-29 07:25:38 +00:00
int NKeys = 0;
for(int i = 0; i < KEY_LAST; i++)
{
if(Input()->KeyIsPressed(i))
{
2010-05-29 07:25:38 +00:00
if(NKeys)
TextRender()->TextEx(&Cursor, " + ", -1);
TextRender()->TextEx(&Cursor, Input()->KeyName(i), -1);
NKeys++;
}
}
}
2010-05-29 07:25:38 +00:00
if(m_ShowMousePointer)
2008-09-01 18:38:08 +00:00
{
// render butt ugly mouse cursor
2009-10-27 14:38:53 +00:00
float mx = UI()->MouseX();
float my = UI()->MouseY();
2020-09-15 14:18:12 +00:00
Graphics()->WrapClamp();
Graphics()->TextureSet(m_CursorTexture);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsBegin();
2010-05-29 07:25:38 +00:00
if(ms_pUiGotContext == UI()->HotItem())
Graphics()->SetColor(1, 0, 0, 1);
IGraphics::CQuadItem QuadItem(mx, my, 16.0f, 16.0f);
2010-05-29 07:25:38 +00:00
Graphics()->QuadsDrawTL(&QuadItem, 1);
2009-10-27 14:38:53 +00:00
Graphics()->QuadsEnd();
2020-09-15 14:18:12 +00:00
Graphics()->WrapNormal();
2008-09-01 18:38:08 +00:00
}
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
void CEditor::Reset(bool CreateDefault)
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
m_Map.Clean();
2008-01-12 12:27:55 +00:00
2014-01-19 03:02:01 +00:00
//delete undo file
char aBuffer[1024];
m_pStorage->GetCompletePath(IStorage::TYPE_SAVE, "editor/", aBuffer, sizeof(aBuffer));
2018-10-02 01:52:01 +00:00
mem_zero(m_apSavedBrushes, sizeof m_apSavedBrushes);
2008-01-12 12:27:55 +00:00
// create default layers
2010-05-29 07:25:38 +00:00
if(CreateDefault)
{
m_EditorWasUsedBefore = true;
m_Map.CreateDefault(GetEntitiesTexture());
}
2010-05-29 07:25:38 +00:00
SelectGameLayer();
m_vSelectedQuads.clear();
2010-05-29 07:25:38 +00:00
m_SelectedPoints = 0;
m_SelectedEnvelope = 0;
m_SelectedImage = 0;
m_SelectedSound = 0;
m_SelectedSource = -1;
2011-08-11 08:59:14 +00:00
2010-06-09 23:09:51 +00:00
m_WorldOffsetX = 0;
m_WorldOffsetY = 0;
m_EditorOffsetX = 0.0f;
m_EditorOffsetY = 0.0f;
2011-08-11 08:59:14 +00:00
m_Zoom = 200.0f;
m_Zooming = false;
2010-06-09 23:09:51 +00:00
m_WorldZoom = 1.0f;
m_MouseDeltaX = 0;
m_MouseDeltaY = 0;
m_MouseDeltaWx = 0;
m_MouseDeltaWy = 0;
m_Map.m_Modified = false;
2011-08-14 14:31:48 +00:00
m_ShowEnvelopePreview = SHOWENV_NONE;
2017-02-21 16:10:08 +00:00
m_ShiftBy = 1;
2007-05-22 15:03:32 +00:00
}
int CEditor::GetLineDistance() const
2011-07-10 20:16:16 +00:00
{
if(m_Zoom <= 100.0f)
return 16;
else if(m_Zoom <= 250.0f)
return 32;
else if(m_Zoom <= 450.0f)
return 64;
else if(m_Zoom <= 850.0f)
return 128;
else if(m_Zoom <= 1550.0f)
return 256;
else
return 512;
}
void CEditor::SetZoom(float Target)
{
Target = clamp(Target, MinZoomLevel(), MaxZoomLevel());
const float Now = Client()->GlobalTime();
float Current = m_Zoom;
float Derivative = 0.0f;
if(m_Zooming)
{
const float Progress = ZoomProgress(Now);
Current = m_ZoomSmoothing.Evaluate(Progress);
Derivative = m_ZoomSmoothing.Derivative(Progress);
}
m_ZoomSmoothingTarget = Target;
m_ZoomSmoothing = CCubicBezier::With(Current, Derivative, 0.0f, m_ZoomSmoothingTarget);
m_ZoomSmoothingStart = Now;
m_ZoomSmoothingEnd = Now + g_Config.m_EdSmoothZoomTime / 1000.0f;
m_Zooming = true;
}
void CEditor::ChangeZoom(float Amount)
{
const float CurrentTarget = m_Zooming ? m_ZoomSmoothingTarget : m_Zoom;
SetZoom(CurrentTarget + Amount);
2011-07-10 20:16:16 +00:00
}
void CEditor::ZoomMouseTarget(float ZoomFactor)
{
// zoom to the current mouse position
// get absolute mouse position
float aPoints[4];
RenderTools()->MapScreenToWorld(
m_WorldOffsetX, m_WorldOffsetY,
100.0f, 100.0f, 100.0f, 0.0f, 0.0f, Graphics()->ScreenAspect(), m_WorldZoom, aPoints);
float WorldWidth = aPoints[2] - aPoints[0];
float WorldHeight = aPoints[3] - aPoints[1];
float Mwx = aPoints[0] + WorldWidth * (UI()->MouseX() / UI()->Screen()->w);
float Mwy = aPoints[1] + WorldHeight * (UI()->MouseY() / UI()->Screen()->h);
// adjust camera
m_WorldOffsetX += (Mwx - m_WorldOffsetX) * (1.0f - ZoomFactor);
m_WorldOffsetY += (Mwy - m_WorldOffsetY) * (1.0f - ZoomFactor);
}
void CEditor::UpdateZoom()
{
if(m_Zooming)
{
const float Time = Client()->GlobalTime();
const float OldLevel = m_Zoom;
if(Time >= m_ZoomSmoothingEnd)
{
m_Zoom = m_ZoomSmoothingTarget;
m_Zooming = false;
}
else
{
m_Zoom = m_ZoomSmoothing.Evaluate(ZoomProgress(Time));
if((OldLevel < m_ZoomSmoothingTarget && m_Zoom > m_ZoomSmoothingTarget) || (OldLevel > m_ZoomSmoothingTarget && m_Zoom < m_ZoomSmoothingTarget))
{
m_Zoom = m_ZoomSmoothingTarget;
m_Zooming = false;
}
}
m_Zoom = clamp(m_Zoom, MinZoomLevel(), MaxZoomLevel());
if(g_Config.m_EdZoomTarget)
ZoomMouseTarget(m_Zoom / OldLevel);
}
m_WorldZoom = m_Zoom / 100.0f;
}
float CEditor::MinZoomLevel() const
{
return 10.0f;
}
float CEditor::MaxZoomLevel() const
{
return g_Config.m_EdLimitMaxZoomLevel ? 2000.0f : std::numeric_limits<float>::max();
}
float CEditor::ZoomProgress(float CurrentTime) const
{
return (CurrentTime - m_ZoomSmoothingStart) / (m_ZoomSmoothingEnd - m_ZoomSmoothingStart);
}
2022-08-20 18:47:46 +00:00
void CEditor::Goto(float X, float Y)
{
m_WorldOffsetX = X * 32;
m_WorldOffsetY = Y * 32;
}
void CEditorMap::DeleteEnvelope(int Index)
{
if(Index < 0 || Index >= (int)m_vpEnvelopes.size())
return;
m_Modified = true;
VisitEnvelopeReferences([Index](int &ElementIndex) {
if(ElementIndex == Index)
ElementIndex = -1;
else if(ElementIndex > Index)
ElementIndex--;
});
m_vpEnvelopes.erase(m_vpEnvelopes.begin() + Index);
}
void CEditorMap::SwapEnvelopes(int Index0, int Index1)
{
if(Index0 < 0 || Index0 >= (int)m_vpEnvelopes.size())
return;
if(Index1 < 0 || Index1 >= (int)m_vpEnvelopes.size())
return;
if(Index0 == Index1)
return;
m_Modified = true;
VisitEnvelopeReferences([Index0, Index1](int &ElementIndex) {
if(ElementIndex == Index0)
ElementIndex = Index1;
else if(ElementIndex == Index1)
ElementIndex = Index0;
});
std::swap(m_vpEnvelopes[Index0], m_vpEnvelopes[Index1]);
}
template<typename F>
void CEditorMap::VisitEnvelopeReferences(F &&Visitor)
{
for(auto &pGroup : m_vpGroups)
{
for(auto &pLayer : pGroup->m_vpLayers)
{
if(pLayer->m_Type == LAYERTYPE_QUADS)
{
CLayerQuads *pLayerQuads = static_cast<CLayerQuads *>(pLayer);
for(auto &Quad : pLayerQuads->m_vQuads)
{
Visitor(Quad.m_PosEnv);
Visitor(Quad.m_ColorEnv);
}
}
else if(pLayer->m_Type == LAYERTYPE_TILES)
{
CLayerTiles *pLayerTiles = static_cast<CLayerTiles *>(pLayer);
Visitor(pLayerTiles->m_ColorEnv);
}
else if(pLayer->m_Type == LAYERTYPE_SOUNDS)
{
CLayerSounds *pLayerSounds = static_cast<CLayerSounds *>(pLayer);
for(auto &Source : pLayerSounds->m_vSources)
{
Visitor(Source.m_PosEnv);
Visitor(Source.m_SoundEnv);
}
}
}
}
}
2010-05-29 07:25:38 +00:00
void CEditorMap::MakeGameLayer(CLayer *pLayer)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
m_pGameLayer = (CLayerGame *)pLayer;
m_pGameLayer->m_pEditor = m_pEditor;
m_pGameLayer->m_Texture = m_pEditor->GetEntitiesTexture();
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
void CEditorMap::MakeGameGroup(CLayerGroup *pGroup)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
m_pGameGroup = pGroup;
m_pGameGroup->m_GameGroup = true;
2011-07-12 01:14:46 +00:00
str_copy(m_pGameGroup->m_aName, "Game", sizeof(m_pGameGroup->m_aName));
2008-01-12 12:27:55 +00:00
}
2010-05-29 07:25:38 +00:00
void CEditorMap::Clean()
{
for(auto &pGroup : m_vpGroups)
{
DeleteAll(pGroup->m_vpLayers);
}
DeleteAll(m_vpGroups);
DeleteAll(m_vpEnvelopes);
DeleteAll(m_vpImages);
DeleteAll(m_vpSounds);
2010-05-29 07:25:38 +00:00
2011-07-12 21:31:39 +00:00
m_MapInfo.Reset();
m_MapInfoTmp.Reset();
2011-07-12 21:31:39 +00:00
m_vSettings.clear();
m_pGameLayer = nullptr;
m_pGameGroup = nullptr;
m_Modified = false;
m_pTeleLayer = nullptr;
m_pSpeedupLayer = nullptr;
m_pFrontLayer = nullptr;
m_pSwitchLayer = nullptr;
m_pTuneLayer = nullptr;
}
void CEditorMap::CreateDefault(IGraphics::CTextureHandle EntitiesTexture)
{
// add background
CLayerGroup *pGroup = NewGroup();
pGroup->m_ParallaxX = 0;
pGroup->m_ParallaxY = 0;
pGroup->m_CustomParallaxZoom = 0;
pGroup->m_ParallaxZoom = 0;
CLayerQuads *pLayer = new CLayerQuads;
pLayer->m_pEditor = m_pEditor;
CQuad *pQuad = pLayer->NewQuad(0, 0, 1600, 1200);
pQuad->m_aColors[0].r = pQuad->m_aColors[1].r = 94;
pQuad->m_aColors[0].g = pQuad->m_aColors[1].g = 132;
pQuad->m_aColors[0].b = pQuad->m_aColors[1].b = 174;
pQuad->m_aColors[2].r = pQuad->m_aColors[3].r = 204;
pQuad->m_aColors[2].g = pQuad->m_aColors[3].g = 232;
pQuad->m_aColors[2].b = pQuad->m_aColors[3].b = 255;
pGroup->AddLayer(pLayer);
// add game layer and reset front, tele, speedup, tune and switch layer pointers
2010-05-29 07:25:38 +00:00
MakeGameGroup(NewGroup());
MakeGameLayer(new CLayerGame(50, 50));
m_pGameGroup->AddLayer(m_pGameLayer);
m_pFrontLayer = nullptr;
m_pTeleLayer = nullptr;
m_pSpeedupLayer = nullptr;
m_pSwitchLayer = nullptr;
m_pTuneLayer = nullptr;
}
int CEditor::GetTextureUsageFlag()
{
return Graphics()->HasTextureArrays() ? IGraphics::TEXLOAD_TO_2D_ARRAY_TEXTURE : IGraphics::TEXLOAD_TO_3D_TEXTURE;
}
IGraphics::CTextureHandle CEditor::GetFrontTexture()
{
int TextureLoadFlag = GetTextureUsageFlag();
if(!m_FrontTexture.IsValid())
m_FrontTexture = Graphics()->LoadTexture("editor/front.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
return m_FrontTexture;
}
IGraphics::CTextureHandle CEditor::GetTeleTexture()
{
int TextureLoadFlag = GetTextureUsageFlag();
if(!m_TeleTexture.IsValid())
m_TeleTexture = Graphics()->LoadTexture("editor/tele.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
return m_TeleTexture;
}
IGraphics::CTextureHandle CEditor::GetSpeedupTexture()
{
int TextureLoadFlag = GetTextureUsageFlag();
if(!m_SpeedupTexture.IsValid())
m_SpeedupTexture = Graphics()->LoadTexture("editor/speedup.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
return m_SpeedupTexture;
}
IGraphics::CTextureHandle CEditor::GetSwitchTexture()
{
int TextureLoadFlag = GetTextureUsageFlag();
if(!m_SwitchTexture.IsValid())
m_SwitchTexture = Graphics()->LoadTexture("editor/switch.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
return m_SwitchTexture;
}
IGraphics::CTextureHandle CEditor::GetTuneTexture()
{
int TextureLoadFlag = GetTextureUsageFlag();
if(!m_TuneTexture.IsValid())
m_TuneTexture = Graphics()->LoadTexture("editor/tune.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
return m_TuneTexture;
}
IGraphics::CTextureHandle CEditor::GetEntitiesTexture()
{
int TextureLoadFlag = GetTextureUsageFlag();
if(!m_EntitiesTexture.IsValid())
m_EntitiesTexture = Graphics()->LoadTexture("editor/entities/DDNet.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, TextureLoadFlag);
return m_EntitiesTexture;
}
2010-05-29 07:25:38 +00:00
void CEditor::Init()
2007-05-22 15:03:32 +00:00
{
2010-05-29 07:25:38 +00:00
m_pInput = Kernel()->RequestInterface<IInput>();
m_pClient = Kernel()->RequestInterface<IClient>();
m_pConfig = Kernel()->RequestInterface<IConfigManager>()->Values();
m_pConsole = Kernel()->RequestInterface<IConsole>();
2010-05-29 07:25:38 +00:00
m_pGraphics = Kernel()->RequestInterface<IGraphics>();
m_pTextRender = Kernel()->RequestInterface<ITextRender>();
2010-09-12 11:15:59 +00:00
m_pStorage = Kernel()->RequestInterface<IStorage>();
m_pSound = Kernel()->RequestInterface<ISound>();
m_UI.Init(Kernel());
m_UI.SetPopupMenuClosedCallback([this]() {
m_PopupEventWasActivated = false;
});
m_RenderTools.Init(m_pGraphics, m_pTextRender);
2010-05-29 07:25:38 +00:00
m_Map.m_pEditor = this;
m_CheckerTexture = Graphics()->LoadTexture("editor/checker.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
m_BackgroundTexture = Graphics()->LoadTexture("editor/background.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
m_CursorTexture = Graphics()->LoadTexture("editor/cursor.png", IStorage::TYPE_ALL, CImageInfo::FORMAT_AUTO, 0);
2010-05-29 07:25:38 +00:00
m_TilesetPicker.m_pEditor = this;
m_TilesetPicker.MakePalette();
m_TilesetPicker.m_Readonly = true;
m_QuadsetPicker.m_pEditor = this;
m_QuadsetPicker.NewQuad(0, 0, 64, 64);
m_QuadsetPicker.m_Readonly = true;
2010-05-29 07:25:38 +00:00
m_Brush.m_pMap = &m_Map;
Reset(false);
m_Map.m_Modified = false;
ms_PickerColor = ColorHSVA(1.0f, 0.0f, 0.0f);
2023-03-18 06:53:18 +00:00
ResetMenuBackgroundPositions();
m_vpMenuBackgroundPositionNames.resize(CMenuBackground::NUM_POS);
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_START] = "start";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_INTERNET] = "browser(internet)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_LAN] = "browser(lan)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_DEMOS] = "demos";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_NEWS] = "news";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_FAVORITES] = "favorites";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_LANGUAGE] = "settings(language)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_GENERAL] = "settings(general)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_PLAYER] = "settings(player)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_TEE] = "settings(tee)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_APPEARANCE] = "settings(appearance)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_CONTROLS] = "settings(controls)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_GRAPHICS] = "settings(graphics)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_SOUND] = "settings(sound)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_DDNET] = "settings(ddnet)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_ASSETS] = "settings(assets)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM0] = "custom(ddnet)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM1] = "custom(kog)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM2] = "custom(3)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_BROWSER_CUSTOM3] = "custom(4)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_RESERVED0] = "reserved settings(1)";
2023-03-27 06:51:02 +00:00
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_SETTINGS_RESERVED1] = "reserved settings(2)";
2023-03-18 06:53:18 +00:00
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_RESERVED0] = "reserved(1)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_RESERVED1] = "reserved(2)";
m_vpMenuBackgroundPositionNames[CMenuBackground::POS_RESERVED2] = "reserved(3)";
2007-12-02 17:55:45 +00:00
}
void CEditor::PlaceBorderTiles()
2007-12-02 17:55:45 +00:00
{
2011-08-11 08:59:14 +00:00
CLayerTiles *pT = (CLayerTiles *)GetSelectedLayerType(0, LAYERTYPE_TILES);
for(int i = 0; i < pT->m_Width * 2; ++i)
2011-08-11 08:59:14 +00:00
pT->m_pTiles[i].m_Index = 1;
for(int i = 0; i < pT->m_Width * pT->m_Height; ++i)
2011-08-11 08:59:14 +00:00
{
if(i % pT->m_Width < 2 || i % pT->m_Width > pT->m_Width - 3)
2011-08-11 08:59:14 +00:00
pT->m_pTiles[i].m_Index = 1;
}
for(int i = (pT->m_Width * (pT->m_Height - 2)); i < pT->m_Width * pT->m_Height; ++i)
2011-08-11 08:59:14 +00:00
pT->m_pTiles[i].m_Index = 1;
2010-05-29 07:25:38 +00:00
}
void CEditor::OnUpdate()
2010-05-29 07:25:38 +00:00
{
CUIElementBase::Init(UI()); // update static pointer because game and editor use separate UI
if(!m_EditorWasUsedBefore)
{
m_EditorWasUsedBefore = true;
Reset();
}
2022-06-16 19:01:23 +00:00
// handle cursor movement
2021-09-15 21:52:09 +00:00
{
2022-06-16 19:01:51 +00:00
static float s_MouseX = 0.0f;
static float s_MouseY = 0.0f;
float MouseRelX = 0.0f, MouseRelY = 0.0f;
IInput::ECursorType CursorType = Input()->CursorRelative(&MouseRelX, &MouseRelY);
if(CursorType != IInput::CURSOR_NONE)
UI()->ConvertMouseMove(&MouseRelX, &MouseRelY, CursorType);
2007-12-02 17:55:45 +00:00
m_MouseDeltaX += MouseRelX;
m_MouseDeltaY += MouseRelY;
if(!UI()->CheckMouseLock())
{
s_MouseX = clamp<float>(s_MouseX + MouseRelX, 0.0f, Graphics()->WindowWidth());
s_MouseY = clamp<float>(s_MouseY + MouseRelY, 0.0f, Graphics()->WindowHeight());
}
2021-09-15 21:52:09 +00:00
// update positions for ui, but only update ui when rendering
m_MouseX = UI()->Screen()->w * ((float)s_MouseX / Graphics()->WindowWidth());
m_MouseY = UI()->Screen()->h * ((float)s_MouseY / Graphics()->WindowHeight());
2010-05-29 07:25:38 +00:00
2008-01-12 12:27:55 +00:00
// fix correct world x and y
CLayerGroup *pGroup = GetSelectedGroup();
if(pGroup)
2008-01-12 12:27:55 +00:00
{
2010-05-29 07:25:38 +00:00
float aPoints[4];
pGroup->Mapping(aPoints);
2010-05-29 07:25:38 +00:00
float WorldWidth = aPoints[2] - aPoints[0];
float WorldHeight = aPoints[3] - aPoints[1];
2010-05-29 07:25:38 +00:00
m_MouseWScale = WorldWidth / Graphics()->WindowWidth();
m_MouseWorldX = aPoints[0] + WorldWidth * (s_MouseX / Graphics()->WindowWidth());
m_MouseWorldY = aPoints[1] + WorldHeight * (s_MouseY / Graphics()->WindowHeight());
m_MouseDeltaWx = m_MouseDeltaX * (WorldWidth / Graphics()->WindowWidth());
m_MouseDeltaWy = m_MouseDeltaY * (WorldHeight / Graphics()->WindowHeight());
}
else
{
m_MouseWorldX = 0.0f;
m_MouseWorldY = 0.0f;
2008-01-12 12:27:55 +00:00
}
for(CLayerGroup *pGameGroup : m_Map.m_vpGroups)
{
if(!pGameGroup->m_GameGroup)
continue;
float aPoints[4];
pGameGroup->Mapping(aPoints);
float WorldWidth = aPoints[2] - aPoints[0];
float WorldHeight = aPoints[3] - aPoints[1];
m_MouseWorldNoParaX = aPoints[0] + WorldWidth * (s_MouseX / Graphics()->WindowWidth());
m_MouseWorldNoParaY = aPoints[1] + WorldHeight * (s_MouseY / Graphics()->WindowHeight());
}
2007-05-22 15:03:32 +00:00
}
}
2010-05-29 07:25:38 +00:00
void CEditor::OnRender()
{
UI()->ResetMouseSlow();
2008-01-12 12:27:55 +00:00
// toggle gui
if(m_Dialog == DIALOG_NONE && m_EditBoxActive == 0 && Input()->KeyPress(KEY_TAB))
2010-05-29 07:25:38 +00:00
m_GuiActive = !m_GuiActive;
2007-12-02 17:55:45 +00:00
if(Input()->KeyPress(KEY_F10))
2010-05-29 07:25:38 +00:00
m_ShowMousePointer = false;
if(m_Animate)
m_AnimateTime = (time_get() - m_AnimateStart) / (float)time_freq();
else
m_AnimateTime = 0;
ms_pUiGotContext = nullptr;
UI()->StartCheck();
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
for(size_t i = 0; i < Input()->NumEvents(); i++)
UI()->OnInput(Input()->GetEvent(i));
UI()->Update(m_MouseX, m_MouseY, m_MouseDeltaX, m_MouseDeltaY, m_MouseWorldX, m_MouseWorldY);
2010-05-29 07:25:38 +00:00
Render();
m_MouseDeltaX = 0.0f;
m_MouseDeltaY = 0.0f;
m_MouseDeltaWx = 0.0f;
m_MouseDeltaWy = 0.0f;
if(Input()->KeyPress(KEY_F10))
2008-09-01 18:38:08 +00:00
{
Graphics()->TakeScreenshot(nullptr);
2010-05-29 07:25:38 +00:00
m_ShowMousePointer = true;
2008-09-01 18:38:08 +00:00
}
2010-05-29 07:25:38 +00:00
UI()->FinishCheck();
UI()->ClearHotkeys();
Input()->Clear();
Port line input and IME support from 0.7 Port the line input (UI edit boxes, chat, console) and Input Method Editor (IME) support from upstream. Closes #4397. General ------------------------------ Fix issues with the text input. Closes #4346. Closes #4524. Word skipping (when holding Ctrl) is overhauled to be consistent with the Windows / Firefox experience that I took as reference. Improve usability by not blinking (i.e. always rendering) the caret shortly after is has been moved. UI text input ------------------------------ Fix inconsistent mouse-based left and right scrolling (closes #4347). Support smooth left and right scrolling. Chat ------------------------------ Support keyboard-based text selection of the chat input. Mouse-based selection could be support in the future when we decide to add something like an ingame UI cursor. Support smooth up and down scrolling of the chat input, removing the old hack that offsets the input string to simulate scrolling. Console ------------------------------ Also support mouse-based text selection of the command input. Only text from either the command input or the console log can be selected at the same time. This ensures that Ctrl+C will always copy the text that is currently visually selected in the console. Check for Ctrl+C input event in event handler instead of in render function, to hopefully fix the issue that copying does not work sometimes (closes #5974 until further notice). When Ctrl+C is used to copy text from the console log, the selection is cleared. This should make it more clear when text was copied from the log. Fix an issue that was preventing the console log selection from being cleared, when all log lines are selected. Remove Ctrl+A/E hotkeys that move cursor to beginning/end respectively. Ctrl+A now selectes all text like for all other inputs. Home and End keys can still be used to go the beginning and end. Remove Ctrl+U/K hotkeys that clear everything before/after the cursor respectively. Hold shift and use Home/End to select everything instead. IME support ------------------------------ Render list of IME candidates in the client on Windows, so the candidate list can also be viewed in fullscreen mode. There is no API available to retrieve a candidate list on the other operating systems. Improve composition rendering by underlining the composition text instead of putting it in square brackets. Track active input globally to properly activate and deactivate IME through the SDL functions. Closes #1030. Closes #1008. Password rendering ------------------------------ Fix rendering of passwords containing unicode. Instead of rendering one star character for each UTF-8 `char`, render on star for every unicode codepoint. Show the composition text also for passwords. Without seeing the composition text it's hard to type a password containing those characters. The candidate window exposes the composition anyway. If you don't want to expose your password this way, e.g. while streaming, you could: 1. Use a latin password and switch off the IME for the password input with the IME hotkey. 2. Blank your screen with an external program while you are streaming and entering passwords. 3. Use binds to authenticate in rcon or to set the server browser password. Refactoring ------------------------------ Move all text input logic and general rendering to `CLineInput`. A `CLineInput` is associated with a particular `char` buffer given as a pointer either in the constructor or with `SetBuffer`. The maximum byte size of the buffer must also be specified. The maximum length in unicode codepoints can also be specified separately (e.g. on upstream, name are limited by the number of unicode codepoints instead). Add `CLineInputBuffered`, which is a `CLineInput` that own a `char` buffer of a fixed size, which is specified as a template argument. As `CLineInput` does not own a buffer anymore, this reduces duplicate code for line inputs that need their own buffer. Add `CLineInputNumber` which has additional convenience functions to consider the text as an `int` or `float`, to reduce duplicate code in those cases. In the future we could also add an input filter function so that only numbers can be entered in the number input. Add `CLineInput::SetClipboardLineCallback` to handle the case that multiple lines of text are pasted into a lineinput. This reduces duplicate code, as this behavior was previously implemented separately for chat and console. The behavior is also fixed to be consistent with the console on Windows, so the first line being pasted edits the current input text and then sends it instead of being sent on its own without the existing input text. Add `CalcFontSizeAndBoundingBox` to UI to reduce duplicate code. Expose `CalcAlignedCursorPos` as static member function to reuse it for line input. Dispatch input events to UI inputs through the event handler instead of storing them in a duplicate buffer. Use `size_t` for line input cursor position, length etc. and for `str_utf8_stats`. Add `IButtonColorFunction` to UI to describe a functions that defines colors for the Default, Active and Hovered states of UI elements. Add some default button color functions. Use button color function to reduce duplicate code in scrollbar rendering. Use `vec2` instead of two `floats` to represent the mouse positions in the text renderer. Remove `CaretPosition` again, as it does not calculate the correct Y position near line breaks due to the wrapping being different when not rendering the entire string. Instead, calculate the exact caret position when rending a text container and store the caret position in the text cursor for later use. IME usage guide (Windows) ------------------------------ 1. Install the respective language and the Microsoft-IME keyboard (e.g. for Chinese, Japanese or Korean). 2. Launch the game (or a text editor to first try out the IME). Note that Windows may track the input language separately for every application. You can change this in the Windows input settings so the input language is changed globally. 2. Switch the input language using the hotkey Windows+Space or another hotkey that you configured in the Windows input settings (Alt+Shift is the default, but you should consider disabling it, to avoid accidentally changing the input language while playing). 3. Switch from Latin/English input mode to the respective asian input mode. - Chinese: Use Ctrl+Space to switch between English and Chinese input mode. You can change this hotkey in the IME's settings. - Japanese: Use Ctrl+Space to switch between Alphanumeric and Hiragana/Katakana input mode. You can change this hotkey in the IME's settings. - Korean: Use Right Alt to switch between English and Hangul input mode. You cannot change this hotkey as of yet. - Note that the input mode is also tracked per application, but there is no setting to change this behavior as far as I know, so you'll need to switch for every application separately. 4. Start typing. The underlined text is the current composition text. While a composition is active, you can only edit the composition text. Confirm the composition with Space or by selecting a candidate from the candidate list with the arrow keys. Cancel the composition with Escape or by using Backspace to delete the composition text. Note that not all languages offer a candidate list. SDL version-specific issues ------------------------------ - 2.26.5, 2.24.2, 2.0.22: IME candidates work. But there are minor bugs when moving the composition cursor. - 2.0.18, 2.0.20: IME candidates work. - 2.0.16 (our current version): IME candidates cannot be determined with Windows API. Windows tries to draw the composition window like before, so this does not work in fullscreen mode. - 2.0.8 (upstream 0.7): IME candidates work. But this SDL version is too old for us.
2023-01-03 21:28:38 +00:00
CLineInput::RenderCandidates();
2007-05-22 15:03:32 +00:00
}
2020-05-15 14:29:09 +00:00
void CEditor::LoadCurrentMap()
{
Load(m_pClient->GetCurrentMapPath(), IStorage::TYPE_ALL);
m_ValidSaveFilename = true;
CGameClient *pGameClient = (CGameClient *)Kernel()->RequestInterface<IGameClient>();
2021-07-12 09:43:56 +00:00
vec2 Center = pGameClient->m_Camera.m_Center;
2020-05-15 14:29:09 +00:00
2020-05-19 16:08:27 +00:00
m_WorldOffsetX = Center.x;
m_WorldOffsetY = Center.y;
2020-05-15 14:29:09 +00:00
}
2010-06-22 00:07:52 +00:00
IEditor *CreateEditor() { return new CEditor; }
void CEditor::ResetMenuBackgroundPositions()
{
std::array<vec2, CMenuBackground::NUM_POS> aBackgroundPositions = GenerateMenuBackgroundPositions();
m_vMenuBackgroundPositions.assign(aBackgroundPositions.begin(), aBackgroundPositions.end());
CLayerGame *pLayer = m_Map.m_pGameLayer;
if(pLayer)
{
for(int y = 0; y < pLayer->m_Height; ++y)
{
for(int x = 0; x < pLayer->m_Width; ++x)
{
CTile Tile = pLayer->GetTile(x, y);
if(Tile.m_Index >= TILE_TIME_CHECKPOINT_FIRST && Tile.m_Index <= TILE_TIME_CHECKPOINT_LAST)
{
int ArrayIndex = clamp<int>((Tile.m_Index - TILE_TIME_CHECKPOINT_FIRST), 0, CMenuBackground::NUM_POS);
m_vMenuBackgroundPositions[ArrayIndex] = vec2(x * 32.0f + 16.0f, y * 32.0f + 16.0f);
}
x += Tile.m_Skip;
}
}
}
2023-03-27 06:51:02 +00:00
m_vMenuBackgroundCollisions.clear();
m_vMenuBackgroundCollisions.resize(m_vMenuBackgroundPositions.size());
for(size_t i = 0; i < m_vMenuBackgroundPositions.size(); i++)
{
2023-03-18 06:53:18 +00:00
for(size_t j = i + 1; j < m_vMenuBackgroundPositions.size(); j++)
{
if(i != j && distance(m_vMenuBackgroundPositions[i], m_vMenuBackgroundPositions[j]) < 0.001f)
2023-03-27 06:51:02 +00:00
m_vMenuBackgroundCollisions.at(i).push_back(j);
}
}
}
// DDRace
void CEditorMap::MakeTeleLayer(CLayer *pLayer)
{
m_pTeleLayer = (CLayerTele *)pLayer;
m_pTeleLayer->m_pEditor = m_pEditor;
m_pTeleLayer->m_Texture = m_pEditor->GetTeleTexture();
}
void CEditorMap::MakeSpeedupLayer(CLayer *pLayer)
{
m_pSpeedupLayer = (CLayerSpeedup *)pLayer;
m_pSpeedupLayer->m_pEditor = m_pEditor;
m_pSpeedupLayer->m_Texture = m_pEditor->GetSpeedupTexture();
}
void CEditorMap::MakeFrontLayer(CLayer *pLayer)
{
m_pFrontLayer = (CLayerFront *)pLayer;
m_pFrontLayer->m_pEditor = m_pEditor;
m_pFrontLayer->m_Texture = m_pEditor->GetFrontTexture();
}
void CEditorMap::MakeSwitchLayer(CLayer *pLayer)
{
m_pSwitchLayer = (CLayerSwitch *)pLayer;
m_pSwitchLayer->m_pEditor = m_pEditor;
m_pSwitchLayer->m_Texture = m_pEditor->GetSwitchTexture();
}
void CEditorMap::MakeTuneLayer(CLayer *pLayer)
{
m_pTuneLayer = (CLayerTune *)pLayer;
m_pTuneLayer->m_pEditor = m_pEditor;
m_pTuneLayer->m_Texture = m_pEditor->GetTuneTexture();
}