ddnet/src/game/editor/editor.h

1031 lines
32 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. */
2011-04-19 08:34:51 +00:00
#ifndef GAME_EDITOR_EDITOR_H
#define GAME_EDITOR_EDITOR_H
2010-05-29 07:25:38 +00:00
#include <base/bezier.h>
#include <base/system.h>
#include <game/client/render.h>
#include <game/client/ui.h>
2010-05-29 07:25:38 +00:00
#include <game/mapitems.h>
2023-10-05 20:42:24 +00:00
#include <game/editor/mapitems/envelope.h>
#include <game/editor/mapitems/layer.h>
#include <game/editor/mapitems/layer_front.h>
#include <game/editor/mapitems/layer_game.h>
#include <game/editor/mapitems/layer_group.h>
#include <game/editor/mapitems/layer_quads.h>
#include <game/editor/mapitems/layer_sounds.h>
#include <game/editor/mapitems/layer_speedup.h>
#include <game/editor/mapitems/layer_switch.h>
#include <game/editor/mapitems/layer_tele.h>
#include <game/editor/mapitems/layer_tiles.h>
#include <game/editor/mapitems/layer_tune.h>
2010-05-29 07:25:38 +00:00
#include <engine/editor.h>
#include <engine/engine.h>
2010-05-29 07:25:38 +00:00
#include <engine/graphics.h>
#include <engine/shared/datafile.h>
#include <engine/shared/jobs.h>
2010-05-29 07:25:38 +00:00
#include "auto_map.h"
2023-10-02 13:14:38 +00:00
#include "editor_history.h"
#include "editor_trackers.h"
#include "map_view.h"
#include "smooth_value.h"
2010-05-29 07:25:38 +00:00
#include <deque>
#include <functional>
#include <map>
#include <memory>
#include <string>
#include <vector>
2022-05-18 16:00:05 +00:00
typedef std::function<void(int *pIndex)> FIndexModifyFunction;
2010-05-29 07:25:38 +00:00
// CEditor SPECIFIC
enum
{
MODE_LAYERS = 0,
2010-05-29 07:25:38 +00:00
MODE_IMAGES,
MODE_SOUNDS,
NUM_MODES,
DIALOG_NONE = 0,
2010-05-29 07:25:38 +00:00
DIALOG_FILE,
};
class CEditorImage;
class CEditorSound;
2010-05-29 07:25:38 +00:00
class CEditorMap
{
void MakeGameGroup(std::shared_ptr<CLayerGroup> pGroup);
void MakeGameLayer(const std::shared_ptr<CLayer> &pLayer);
2010-05-29 07:25:38 +00:00
public:
CEditor *m_pEditor;
CEditorMap()
{
Clean();
}
2017-07-21 18:02:46 +00:00
~CEditorMap()
{
Clean();
}
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
bool m_Modified; // unsaved changes in manual save
bool m_ModifiedAuto; // unsaved changes in autosave
float m_LastModifiedTime;
float m_LastSaveTime;
float m_LastAutosaveUpdateTime;
void OnModify();
std::vector<std::shared_ptr<CLayerGroup>> m_vpGroups;
std::vector<std::shared_ptr<CEditorImage>> m_vpImages;
std::vector<std::shared_ptr<CEnvelope>> m_vpEnvelopes;
std::vector<std::shared_ptr<CEditorSound>> m_vpSounds;
2011-07-12 21:31:39 +00:00
class CMapInfo
{
public:
char m_aAuthor[32];
char m_aVersion[16];
char m_aCredits[128];
char m_aLicense[32];
2011-07-12 21:31:39 +00:00
void Reset()
{
m_aAuthor[0] = '\0';
m_aVersion[0] = '\0';
m_aCredits[0] = '\0';
m_aLicense[0] = '\0';
}
void Copy(const CMapInfo &Source)
{
str_copy(m_aAuthor, Source.m_aAuthor);
str_copy(m_aVersion, Source.m_aVersion);
str_copy(m_aCredits, Source.m_aCredits);
str_copy(m_aLicense, Source.m_aLicense);
2011-07-12 21:31:39 +00:00
}
};
CMapInfo m_MapInfo;
CMapInfo m_MapInfoTmp;
2011-07-12 21:31:39 +00:00
struct CSetting
{
2018-04-27 19:36:29 +00:00
char m_aCommand[256];
CSetting(const char *pCommand)
{
str_copy(m_aCommand, pCommand);
}
};
std::vector<CSetting> m_vSettings;
std::shared_ptr<class CLayerGame> m_pGameLayer;
std::shared_ptr<CLayerGroup> m_pGameGroup;
2023-10-05 21:16:47 +00:00
std::shared_ptr<CEnvelope> NewEnvelope(CEnvelope::EType Type)
2010-05-29 07:25:38 +00:00
{
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
OnModify();
2023-10-05 21:16:47 +00:00
std::shared_ptr<CEnvelope> pEnv = std::make_shared<CEnvelope>(Type);
m_vpEnvelopes.push_back(pEnv);
return pEnv;
2010-05-29 07:25:38 +00:00
}
void DeleteEnvelope(int Index);
void SwapEnvelopes(int Index0, int Index1);
template<typename F>
void VisitEnvelopeReferences(F &&Visitor);
std::shared_ptr<CLayerGroup> NewGroup()
2010-05-29 07:25:38 +00:00
{
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
OnModify();
std::shared_ptr<CLayerGroup> pGroup = std::make_shared<CLayerGroup>();
pGroup->m_pMap = this;
m_vpGroups.push_back(pGroup);
return pGroup;
2010-05-29 07:25:38 +00:00
}
2010-05-29 07:25:38 +00:00
int SwapGroups(int Index0, int Index1)
{
if(Index0 < 0 || Index0 >= (int)m_vpGroups.size())
return Index0;
if(Index1 < 0 || Index1 >= (int)m_vpGroups.size())
return Index0;
if(Index0 == Index1)
return Index0;
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
OnModify();
std::swap(m_vpGroups[Index0], m_vpGroups[Index1]);
2010-05-29 07:25:38 +00:00
return Index1;
}
2010-05-29 07:25:38 +00:00
void DeleteGroup(int Index)
{
if(Index < 0 || Index >= (int)m_vpGroups.size())
return;
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
OnModify();
m_vpGroups.erase(m_vpGroups.begin() + Index);
2010-05-29 07:25:38 +00:00
}
void ModifyImageIndex(FIndexModifyFunction pfnFunc)
2010-05-29 07:25:38 +00:00
{
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
OnModify();
for(auto &pGroup : m_vpGroups)
pGroup->ModifyImageIndex(pfnFunc);
2010-05-29 07:25:38 +00:00
}
void ModifyEnvelopeIndex(FIndexModifyFunction pfnFunc)
2010-05-29 07:25:38 +00:00
{
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
OnModify();
for(auto &pGroup : m_vpGroups)
pGroup->ModifyEnvelopeIndex(pfnFunc);
2010-05-29 07:25:38 +00:00
}
void ModifySoundIndex(FIndexModifyFunction pfnFunc)
2014-10-11 11:38:45 +00:00
{
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
OnModify();
for(auto &pGroup : m_vpGroups)
pGroup->ModifySoundIndex(pfnFunc);
2014-10-11 11:38:45 +00:00
}
2010-05-29 07:25:38 +00:00
void Clean();
void CreateDefault(IGraphics::CTextureHandle EntitiesTexture);
2010-05-29 07:25:38 +00:00
// io
bool Save(const char *pFilename);
bool Load(const char *pFilename, int StorageType, const std::function<void(const char *pErrorMessage)> &ErrorHandler);
void PerformSanityChecks(const std::function<void(const char *pErrorMessage)> &ErrorHandler);
// DDRace
std::shared_ptr<class CLayerTele> m_pTeleLayer;
std::shared_ptr<class CLayerSpeedup> m_pSpeedupLayer;
std::shared_ptr<class CLayerFront> m_pFrontLayer;
std::shared_ptr<class CLayerSwitch> m_pSwitchLayer;
std::shared_ptr<class CLayerTune> m_pTuneLayer;
void MakeTeleLayer(const std::shared_ptr<CLayer> &pLayer);
void MakeSpeedupLayer(const std::shared_ptr<CLayer> &pLayer);
void MakeFrontLayer(const std::shared_ptr<CLayer> &pLayer);
void MakeSwitchLayer(const std::shared_ptr<CLayer> &pLayer);
void MakeTuneLayer(const std::shared_ptr<CLayer> &pLayer);
2010-05-29 07:25:38 +00:00
};
struct CProperty
{
const char *m_pName;
int m_Value;
int m_Type;
int m_Min;
int m_Max;
};
enum
{
PROPTYPE_NULL = 0,
2010-05-29 07:25:38 +00:00
PROPTYPE_BOOL,
PROPTYPE_INT_STEP,
PROPTYPE_INT_SCROLL,
PROPTYPE_ANGLE_SCROLL,
2010-05-29 07:25:38 +00:00
PROPTYPE_COLOR,
PROPTYPE_IMAGE,
PROPTYPE_ENVELOPE,
PROPTYPE_SHIFT,
2014-10-08 15:33:06 +00:00
PROPTYPE_SOUND,
PROPTYPE_AUTOMAPPER,
2010-05-29 07:25:38 +00:00
};
class CDataFileWriterFinishJob : public IJob
{
char m_aRealFileName[IO_MAX_PATH_LENGTH];
char m_aTempFileName[IO_MAX_PATH_LENGTH];
CDataFileWriter m_Writer;
void Run() override
{
m_Writer.Finish();
}
public:
CDataFileWriterFinishJob(const char *pRealFileName, const char *pTempFileName, CDataFileWriter &&Writer) :
m_Writer(std::move(Writer))
{
str_copy(m_aRealFileName, pRealFileName);
str_copy(m_aTempFileName, pTempFileName);
}
const char *GetRealFileName() const { return m_aRealFileName; }
const char *GetTempFileName() const { return m_aTempFileName; }
};
2010-05-29 07:25:38 +00:00
class CEditor : public IEditor
{
class IInput *m_pInput = nullptr;
class IClient *m_pClient = nullptr;
class CConfig *m_pConfig = nullptr;
class IConsole *m_pConsole = nullptr;
class IEngine *m_pEngine = nullptr;
class IGraphics *m_pGraphics = nullptr;
class ITextRender *m_pTextRender = nullptr;
class ISound *m_pSound = nullptr;
class IStorage *m_pStorage = nullptr;
2010-05-29 07:25:38 +00:00
CRenderTools m_RenderTools;
CUI m_UI;
std::vector<std::reference_wrapper<CEditorComponent>> m_vComponents;
CMapView m_MapView;
bool m_EditorWasUsedBefore = false;
IGraphics::CTextureHandle m_EntitiesTexture;
IGraphics::CTextureHandle m_FrontTexture;
IGraphics::CTextureHandle m_TeleTexture;
IGraphics::CTextureHandle m_SpeedupTexture;
IGraphics::CTextureHandle m_SwitchTexture;
IGraphics::CTextureHandle m_TuneTexture;
int GetTextureUsageFlag();
enum EPreviewState
{
PREVIEW_UNLOADED,
PREVIEW_LOADED,
PREVIEW_ERROR,
};
std::shared_ptr<CLayerGroup> m_apSavedBrushes[10];
2010-05-29 07:25:38 +00:00
public:
class IInput *Input() { return m_pInput; }
class IClient *Client() { return m_pClient; }
class CConfig *Config() { return m_pConfig; }
class IConsole *Console() { return m_pConsole; }
class IEngine *Engine() { return m_pEngine; }
class IGraphics *Graphics() { return m_pGraphics; }
class ISound *Sound() { return m_pSound; }
class ITextRender *TextRender() { return m_pTextRender; }
class IStorage *Storage() { return m_pStorage; }
2010-05-29 07:25:38 +00:00
CUI *UI() { return &m_UI; }
CRenderTools *RenderTools() { return &m_RenderTools; }
CMapView *MapView() { return &m_MapView; }
const CMapView *MapView() const { return &m_MapView; }
CEditor() :
m_ZoomEnvelopeX(1.0f, 0.1f, 600.0f),
m_ZoomEnvelopeY(640.0f, 0.1f, 32000.0f)
2010-05-29 07:25:38 +00:00
{
m_EntitiesTexture.Invalidate();
m_FrontTexture.Invalidate();
m_TeleTexture.Invalidate();
m_SpeedupTexture.Invalidate();
m_SwitchTexture.Invalidate();
m_TuneTexture.Invalidate();
2010-05-29 07:25:38 +00:00
m_Mode = MODE_LAYERS;
m_Dialog = 0;
m_BrushColorEnabled = true;
m_aFileName[0] = '\0';
2023-08-26 16:14:13 +00:00
m_aFileNamePending[0] = '\0';
m_aFileSaveName[0] = '\0';
m_ValidSaveFilename = false;
m_PopupEventActivated = false;
m_PopupEventWasActivated = false;
2010-10-06 21:07:35 +00:00
m_FileDialogStorageType = 0;
m_FileDialogLastPopulatedStorageType = 0;
m_pFileDialogTitle = nullptr;
m_pFileDialogButtonText = nullptr;
m_pFileDialogUser = nullptr;
m_aFileDialogCurrentFolder[0] = '\0';
m_aFileDialogCurrentLink[0] = '\0';
m_aFilesSelectedName[0] = '\0';
m_pFileDialogPath = m_aFileDialogCurrentFolder;
m_FileDialogOpening = false;
m_FilesSelectedIndex = -1;
2010-05-29 07:25:38 +00:00
m_FilePreviewImage.Invalidate();
m_FilePreviewSound = -1;
m_FilePreviewState = PREVIEW_UNLOADED;
2023-10-18 11:27:31 +00:00
m_ToolbarPreviewSound = -1;
2018-10-02 21:39:22 +00:00
m_SelectEntitiesImage = "DDNet";
m_ResetZoomEnvelope = true;
m_OffsetEnvelopeX = 0.1f;
m_OffsetEnvelopeY = 0.5f;
2010-05-29 07:25:38 +00:00
m_ShowMousePointer = true;
m_MouseDeltaX = 0;
m_MouseDeltaY = 0;
m_MouseDeltaWx = 0;
m_MouseDeltaWy = 0;
2010-05-29 07:25:38 +00:00
m_GuiActive = true;
m_PreviewZoom = false;
2023-05-22 12:46:25 +00:00
m_ShowTileInfo = SHOW_TILE_OFF;
2010-05-29 07:25:38 +00:00
m_ShowDetail = true;
m_Animate = false;
m_AnimateStart = 0;
m_AnimateTime = 0;
m_AnimateSpeed = 1;
m_ShowEnvelopePreview = SHOWENV_NONE;
2011-08-15 18:12:31 +00:00
m_SelectedQuadEnvelope = -1;
2023-07-23 08:15:01 +00:00
m_vSelectedEnvelopePoints = {};
m_UpdateEnvPointInfo = false;
m_SelectedTangentInPoint = std::pair(-1, -1);
m_SelectedTangentOutPoint = std::pair(-1, -1);
2023-07-23 08:15:01 +00:00
m_CurrentQuadIndex = -1;
2011-08-14 14:31:48 +00:00
2022-02-26 17:49:06 +00:00
m_QuadKnifeActive = false;
m_QuadKnifeCount = 0;
2023-11-19 16:33:34 +00:00
mem_zero(m_aQuadKnifePoints, sizeof(m_aQuadKnifePoints));
2022-02-26 17:49:06 +00:00
m_CheckerTexture.Invalidate();
m_BackgroundTexture.Invalidate();
m_CursorTexture.Invalidate();
ms_pUiGotContext = nullptr;
// DDRace
2010-12-07 15:51:59 +00:00
m_TeleNumber = 1;
m_SwitchNum = 1;
m_TuningNum = 1;
2010-11-22 20:43:22 +00:00
m_SwitchDelay = 0;
m_SpeedupForce = 50;
m_SpeedupMaxSpeed = 0;
m_SpeedupAngle = 0;
m_LargeLayerWasWarned = false;
m_PreventUnusedTilesWasWarned = false;
m_AllowPlaceUnusedTiles = 0;
m_BrushDrawDestructive = true;
2010-05-29 07:25:38 +00:00
}
void Init() override;
void OnUpdate() override;
void OnRender() override;
void OnActivate() override;
void OnWindowResize() override;
2023-10-18 11:27:31 +00:00
void OnClose() override;
2023-10-23 10:48:53 +00:00
void OnDialogClose() override;
bool HasUnsavedData() const override { return m_Map.m_Modified; }
void UpdateMentions() override { m_Mentions++; }
void ResetMentions() override { m_Mentions = 0; }
void OnIngameMoved() override { m_IngameMoved = true; }
void ResetIngameMoved() override { m_IngameMoved = false; }
void HandleCursorMovement();
void DispatchInputEvents();
Autosave copy of current editor map periodically to `auto` folder A copy of the map currently open in the editor is saved every 10 minutes to the `maps/auto` folder (interval configurable, see below). The automatically saved map uses the filename of the original map with an additional timestamp. Per map name 10 autosaves are kept in the `auto` folder before old autosaves will be deleted (number configurable, see below). Add config variable `ed_autosave_interval` (0 - 240, default 10) to configure the interval in minutes at which a copy of the current editor map is automatically saved to the 'auto' folder. Add config variable `ed_autosave_max` (0 - 1000, default 10) to configure the maximum number of autosaves that are kept per map name (0 = no limit). Autosaving will not take place in the 5 seconds immediately after the map was last modified by the user, to avoid interrupting the user with the autosave. This will only delay autosaving for up to 1 minute though, so autosaves are not prevented entirely, should the user continuously edit the map. When the editor is reopened after being closed for more than 10 seconds, the autosave timer will be adjusted to compensate for the time that was not spent on editing in the editor. When the map is saved manually by the user the autosave file is also updated, if it's outdated by at least half of the configured autosave interval. This ensures that autosaves are always available as a periodic backup of the map. When a copy of the current map is saved, this does not update the autosave and will also no longer reset the modified state. The modified state should reflect whether changes have been made that are not saved to the current map file. As saving a copy does not update the current file, the modified state should not be reset in this case. Closes #6693.
2023-06-23 15:39:05 +00:00
void HandleAutosave();
bool PerformAutosave();
void HandleWriterFinishJobs();
void RefreshFilteredFileList();
void FilelistPopulate(int StorageType, bool KeepSelection = false);
void InvokeFileDialog(int StorageType, int FileType, const char *pTitle, const char *pButtonText,
const char *pBasepath, bool FilenameAsDefault,
bool (*pfnFunc)(const char *pFilename, int StorageType, void *pUser), void *pUser);
struct SStringKeyComparator
{
bool operator()(const char *pLhs, const char *pRhs) const
{
return str_comp(pLhs, pRhs) < 0;
}
};
std::map<const char *, CUI::SMessagePopupContext *, SStringKeyComparator> m_PopupMessageContexts;
void ShowFileDialogError(const char *pFormat, ...)
GNUC_ATTRIBUTE((format(printf, 2, 3)));
void Reset(bool CreateDefault = true);
bool Save(const char *pFilename) override;
bool Load(const char *pFilename, int StorageType) override;
2023-08-26 20:13:13 +00:00
bool HandleMapDrop(const char *pFilename, int StorageType) override;
2023-10-02 13:14:38 +00:00
bool Append(const char *pFilename, int StorageType, bool IgnoreHistory = false);
2016-08-23 01:08:36 +00:00
void LoadCurrentMap();
2010-05-29 07:25:38 +00:00
void Render();
2018-10-02 01:52:01 +00:00
void RenderPressedKeys(CUIRect View);
void RenderSavingIndicator(CUIRect View);
void FreeDynamicPopupMenus();
void RenderMousePointer();
std::vector<CQuad *> GetSelectedQuads();
std::shared_ptr<CLayer> GetSelectedLayerType(int Index, int Type) const;
std::shared_ptr<CLayer> GetSelectedLayer(int Index) const;
std::shared_ptr<CLayerGroup> GetSelectedGroup() const;
CSoundSource *GetSelectedSource() const;
void SelectLayer(int LayerIndex, int GroupIndex = -1);
2022-02-26 17:49:06 +00:00
void AddSelectedLayer(int LayerIndex);
2018-08-13 09:11:56 +00:00
void SelectQuad(int Index);
void ToggleSelectQuad(int Index);
void DeselectQuads();
void DeselectQuadPoints();
void SelectQuadPoint(int QuadIndex, int Index);
void ToggleSelectQuadPoint(int QuadIndex, int Index);
2018-08-13 09:11:56 +00:00
void DeleteSelectedQuads();
bool IsQuadSelected(int Index) const;
bool IsQuadCornerSelected(int Index) const;
bool IsQuadPointSelected(int QuadIndex, int Index) const;
int FindSelectedQuadIndex(int Index) const;
2018-08-13 09:11:56 +00:00
int FindEnvPointIndex(int Index, int Channel) const;
void SelectEnvPoint(int Index);
void SelectEnvPoint(int Index, int Channel);
void ToggleEnvPoint(int Index, int Channel);
bool IsEnvPointSelected(int Index, int Channel) const;
bool IsEnvPointSelected(int Index) const;
void DeselectEnvPoints();
void SelectTangentOutPoint(int Index, int Channel);
bool IsTangentOutPointSelected(int Index, int Channel) const;
void SelectTangentInPoint(int Index, int Channel);
bool IsTangentInPointSelected(int Index, int Channel) const;
bool IsTangentInSelected() const;
bool IsTangentOutSelected() const;
bool IsTangentSelected() const;
2023-10-02 13:14:38 +00:00
std::pair<int, int> EnvGetSelectedTimeAndValue() const;
2023-10-02 13:14:38 +00:00
template<typename E>
SEditResult<E> DoPropertiesWithState(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f));
int DoProperties(CUIRect *pToolbox, CProperty *pProps, int *pIDs, int *pNewVal, ColorRGBA Color = ColorRGBA(1, 1, 1, 0.5f));
CUI::SColorPickerPopupContext m_ColorPickerPopupContext;
const void *m_pColorPickerPopupActiveID = nullptr;
void DoColorPickerButton(const void *pID, const CUIRect *pRect, ColorRGBA Color, const std::function<void(ColorRGBA Color)> &SetColor);
2010-05-29 07:25:38 +00:00
int m_Mode;
int m_Dialog;
char m_aTooltip[256] = "";
2010-05-29 07:25:38 +00:00
bool m_BrushColorEnabled;
char m_aFileName[IO_MAX_PATH_LENGTH];
2023-08-26 16:14:13 +00:00
char m_aFileNamePending[IO_MAX_PATH_LENGTH];
char m_aFileSaveName[IO_MAX_PATH_LENGTH];
bool m_ValidSaveFilename;
enum
{
POPEVENT_EXIT = 0,
POPEVENT_LOAD,
2016-08-23 01:08:36 +00:00
POPEVENT_LOADCURRENT,
2023-08-26 16:14:13 +00:00
POPEVENT_LOADDROP,
POPEVENT_NEW,
POPEVENT_SAVE,
POPEVENT_SAVE_COPY,
2023-09-14 15:50:31 +00:00
POPEVENT_SAVE_IMG,
2023-09-30 15:28:47 +00:00
POPEVENT_SAVE_SOUND,
POPEVENT_LARGELAYER,
2020-06-20 23:14:36 +00:00
POPEVENT_PREVENTUNUSEDTILES,
POPEVENT_IMAGEDIV16,
POPEVENT_IMAGE_MAX,
POPEVENT_SOUND_MAX,
2023-08-12 10:13:27 +00:00
POPEVENT_PLACE_BORDER_TILES,
POPEVENT_PIXELART_BIG_IMAGE,
POPEVENT_PIXELART_MANY_COLORS,
POPEVENT_PIXELART_TOO_MANY_COLORS
};
int m_PopupEventType;
int m_PopupEventActivated;
int m_PopupEventWasActivated;
bool m_LargeLayerWasWarned;
bool m_PreventUnusedTilesWasWarned;
int m_AllowPlaceUnusedTiles;
bool m_BrushDrawDestructive;
int m_Mentions = 0;
bool m_IngameMoved = false;
2019-04-05 23:15:02 +00:00
enum
{
FILETYPE_MAP,
FILETYPE_IMG,
FILETYPE_SOUND,
NUM_FILETYPES
};
2010-10-06 21:07:35 +00:00
int m_FileDialogStorageType;
int m_FileDialogLastPopulatedStorageType;
2010-09-12 11:15:59 +00:00
const char *m_pFileDialogTitle;
const char *m_pFileDialogButtonText;
bool (*m_pfnFileDialogFunc)(const char *pFileName, int StorageType, void *pUser);
2010-09-12 11:15:59 +00:00
void *m_pFileDialogUser;
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
CLineInputBuffered<IO_MAX_PATH_LENGTH> m_FileDialogFileNameInput;
char m_aFileDialogCurrentFolder[IO_MAX_PATH_LENGTH];
char m_aFileDialogCurrentLink[IO_MAX_PATH_LENGTH];
char m_aFilesSelectedName[IO_MAX_PATH_LENGTH];
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
CLineInputBuffered<IO_MAX_PATH_LENGTH> m_FileDialogFilterInput;
char *m_pFileDialogPath;
int m_FileDialogFileType;
2023-06-16 22:15:04 +00:00
bool m_FileDialogMultipleStorages = false;
bool m_FileDialogShowingRoot = false;
int m_FilesSelectedIndex;
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
CLineInputBuffered<IO_MAX_PATH_LENGTH> m_FileDialogNewFolderNameInput;
IGraphics::CTextureHandle m_FilePreviewImage;
int m_FilePreviewSound;
EPreviewState m_FilePreviewState;
2014-03-28 21:47:57 +00:00
CImageInfo m_FilePreviewImageInfo;
bool m_FileDialogOpening;
2014-03-28 21:47:57 +00:00
2023-10-18 11:27:31 +00:00
int m_ToolbarPreviewSound;
2010-10-06 21:07:35 +00:00
struct CFilelistItem
{
char m_aFilename[IO_MAX_PATH_LENGTH];
char m_aName[IO_MAX_PATH_LENGTH];
2010-10-06 21:07:35 +00:00
bool m_IsDir;
bool m_IsLink;
2010-10-06 21:07:35 +00:00
int m_StorageType;
time_t m_TimeModified;
2010-10-06 21:07:35 +00:00
};
std::vector<CFilelistItem> m_vCompleteFileList;
std::vector<const CFilelistItem *> m_vpFilteredFileList;
2010-05-29 07:25:38 +00:00
2023-03-12 18:41:58 +00:00
static bool CompareFilenameAscending(const CFilelistItem *pLhs, const CFilelistItem *pRhs)
{
2023-03-12 18:41:58 +00:00
if(str_comp(pLhs->m_aFilename, "..") == 0)
return true;
2023-03-12 18:41:58 +00:00
if(str_comp(pRhs->m_aFilename, "..") == 0)
return false;
2023-06-16 22:15:04 +00:00
if(pLhs->m_IsLink != pRhs->m_IsLink)
return pLhs->m_IsLink;
2023-03-12 18:41:58 +00:00
if(pLhs->m_IsDir != pRhs->m_IsDir)
return pLhs->m_IsDir;
return str_comp_filenames(pLhs->m_aName, pRhs->m_aName) < 0;
}
2023-03-12 18:41:58 +00:00
static bool CompareFilenameDescending(const CFilelistItem *pLhs, const CFilelistItem *pRhs)
{
2023-03-12 18:41:58 +00:00
if(str_comp(pLhs->m_aFilename, "..") == 0)
return true;
2023-03-12 18:41:58 +00:00
if(str_comp(pRhs->m_aFilename, "..") == 0)
return false;
2023-06-16 22:15:04 +00:00
if(pLhs->m_IsLink != pRhs->m_IsLink)
return pLhs->m_IsLink;
2023-03-12 18:41:58 +00:00
if(pLhs->m_IsDir != pRhs->m_IsDir)
return pLhs->m_IsDir;
return str_comp_filenames(pLhs->m_aName, pRhs->m_aName) > 0;
}
2023-03-12 18:41:58 +00:00
static bool CompareTimeModifiedAscending(const CFilelistItem *pLhs, const CFilelistItem *pRhs)
{
2023-03-12 18:41:58 +00:00
if(str_comp(pLhs->m_aFilename, "..") == 0)
return true;
if(str_comp(pRhs->m_aFilename, "..") == 0)
return false;
if(pLhs->m_IsLink || pRhs->m_IsLink)
return pLhs->m_IsLink;
if(pLhs->m_IsDir != pRhs->m_IsDir)
return pLhs->m_IsDir;
return pLhs->m_TimeModified < pRhs->m_TimeModified;
}
2023-03-12 18:41:58 +00:00
static bool CompareTimeModifiedDescending(const CFilelistItem *pLhs, const CFilelistItem *pRhs)
{
2023-03-12 18:41:58 +00:00
if(str_comp(pLhs->m_aFilename, "..") == 0)
return true;
if(str_comp(pRhs->m_aFilename, "..") == 0)
return false;
if(pLhs->m_IsLink || pRhs->m_IsLink)
return pLhs->m_IsLink;
if(pLhs->m_IsDir != pRhs->m_IsDir)
return pLhs->m_IsDir;
return pLhs->m_TimeModified > pRhs->m_TimeModified;
}
void SortFilteredFileList();
int m_SortByFilename = 1;
int m_SortByTimeModified = 0;
std::vector<std::string> m_vSelectEntitiesFiles;
2018-10-02 21:39:22 +00:00
std::string m_SelectEntitiesImage;
// Zooming
CSmoothValue m_ZoomEnvelopeX;
CSmoothValue m_ZoomEnvelopeY;
bool m_ResetZoomEnvelope;
float m_OffsetEnvelopeX;
float m_OffsetEnvelopeY;
2010-05-29 07:25:38 +00:00
bool m_ShowMousePointer;
bool m_GuiActive;
2023-03-27 06:51:02 +00:00
char m_aMenuBackgroundTooltip[256];
bool m_PreviewZoom;
float m_MouseWScale = 1.0f; // Mouse (i.e. UI) scale relative to the World (selected Group)
float m_MouseX = 0.0f;
float m_MouseY = 0.0f;
float m_MouseWorldX = 0.0f;
float m_MouseWorldY = 0.0f;
float m_MouseWorldNoParaX = 0.0f;
float m_MouseWorldNoParaY = 0.0f;
2010-05-29 07:25:38 +00:00
float m_MouseDeltaX;
float m_MouseDeltaY;
float m_MouseDeltaWx;
float m_MouseDeltaWy;
2023-05-23 18:27:08 +00:00
2023-05-23 19:57:57 +00:00
enum EShowTile
2023-05-22 12:46:25 +00:00
{
SHOW_TILE_OFF,
SHOW_TILE_DECIMAL,
SHOW_TILE_HEXADECIMAL
};
EShowTile m_ShowTileInfo;
2010-05-29 07:25:38 +00:00
bool m_ShowDetail;
bool m_Animate;
2021-06-23 05:05:49 +00:00
int64_t m_AnimateStart;
2010-05-29 07:25:38 +00:00
float m_AnimateTime;
float m_AnimateSpeed;
enum EExtraEditor
{
EXTRAEDITOR_NONE = -1,
EXTRAEDITOR_ENVELOPES,
EXTRAEDITOR_SERVER_SETTINGS,
2023-10-02 13:14:38 +00:00
EXTRAEDITOR_HISTORY,
NUM_EXTRAEDITORS,
};
EExtraEditor m_ActiveExtraEditor = EXTRAEDITOR_NONE;
2023-10-02 13:14:38 +00:00
float m_aExtraEditorSplits[NUM_EXTRAEDITORS] = {250.0f, 250.0f, 250.0f};
enum EShowEnvelope
{
SHOWENV_NONE = 0,
SHOWENV_SELECTED,
SHOWENV_ALL
};
EShowEnvelope m_ShowEnvelopePreview;
bool m_ShowPicker;
std::vector<int> m_vSelectedLayers;
std::vector<int> m_vSelectedQuads;
2018-08-13 09:11:56 +00:00
int m_SelectedQuadPoint;
int m_SelectedQuadIndex;
2010-05-29 07:25:38 +00:00
int m_SelectedGroup;
int m_SelectedQuadPoints;
2010-05-29 07:25:38 +00:00
int m_SelectedEnvelope;
std::vector<std::pair<int, int>> m_vSelectedEnvelopePoints;
int m_SelectedQuadEnvelope;
2023-07-23 08:15:01 +00:00
int m_CurrentQuadIndex;
2010-05-29 07:25:38 +00:00
int m_SelectedImage;
int m_SelectedSound;
int m_SelectedSource;
std::pair<int, int> m_SelectedTangentInPoint;
std::pair<int, int> m_SelectedTangentOutPoint;
bool m_UpdateEnvPointInfo;
2022-02-26 17:49:06 +00:00
bool m_QuadKnifeActive;
int m_QuadKnifeCount;
vec2 m_aQuadKnifePoints[4];
IGraphics::CTextureHandle m_CheckerTexture;
IGraphics::CTextureHandle m_BackgroundTexture;
IGraphics::CTextureHandle m_CursorTexture;
IGraphics::CTextureHandle GetEntitiesTexture();
std::shared_ptr<CLayerGroup> m_pBrush;
std::shared_ptr<CLayerTiles> m_pTilesetPicker;
std::shared_ptr<CLayerQuads> m_pQuadsetPicker;
2010-05-29 07:25:38 +00:00
static const void *ms_pUiGotContext;
2010-05-29 07:25:38 +00:00
CEditorMap m_Map;
std::deque<std::shared_ptr<CDataFileWriterFinishJob>> m_WriterFinishJobs;
int m_ShiftBy;
static void EnvelopeEval(int TimeOffsetMillis, int Env, ColorRGBA &Channels, void *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
CLineInputBuffered<256> m_SettingsCommandInput;
2023-08-12 10:13:27 +00:00
CImageInfo m_TileartImageInfo;
char m_aTileartFilename[IO_MAX_PATH_LENGTH];
2023-10-02 13:14:38 +00:00
void AddTileart(bool IgnoreHistory = false);
2023-08-12 10:13:27 +00:00
void TileartCheckColors();
void PlaceBorderTiles();
void UpdateTooltip(const void *pID, const CUIRect *pRect, const char *pToolTip);
2010-05-29 07:25:38 +00:00
int DoButton_Editor_Common(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
int DoButton_Editor(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
2023-04-29 00:23:06 +00:00
int DoButton_Env(const void *pID, const char *pText, int Checked, const CUIRect *pRect, const char *pToolTip, ColorRGBA Color, int Corners);
2010-05-29 07:25:38 +00:00
int DoButton_Ex(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize = 10.0f);
int DoButton_FontIcon(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip, int Corners, float FontSize = 10.0f);
2010-05-29 07:25:38 +00:00
int DoButton_ButtonDec(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
int DoButton_ButtonInc(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
int DoButton_File(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
2010-05-29 07:25:38 +00:00
int DoButton_Menu(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags, const char *pToolTip);
int DoButton_MenuItem(const void *pID, const char *pText, int Checked, const CUIRect *pRect, int Flags = 0, const char *pToolTip = nullptr);
int DoButton_DraggableEx(const void *pID, const char *pText, int Checked, const CUIRect *pRect, bool *pClicked, bool *pAbrupted, int Flags, const char *pToolTip = nullptr, int Corners = IGraphics::CORNER_ALL, float FontSize = 10.0f);
2023-03-15 17:15:43 +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 DoEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL, const char *pToolTip = nullptr);
bool DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL, const char *pToolTip = nullptr);
2010-05-29 07:25:38 +00:00
void RenderBackground(CUIRect View, IGraphics::CTextureHandle Texture, float Size, float Brightness);
2010-05-29 07:25:38 +00:00
2023-10-02 13:14:38 +00:00
SEditResult<int> UiDoValueSelector(void *pID, CUIRect *pRect, const char *pLabel, int Current, int Min, int Max, int Step, float Scale, const char *pToolTip, bool IsDegree = false, bool IsHex = false, int corners = IGraphics::CORNER_ALL, ColorRGBA *pColor = nullptr, bool ShowValue = true);
2010-05-29 07:25:38 +00:00
static CUI::EPopupMenuFunctionResult PopupMenuFile(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupMenuTools(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupMenuSettings(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupGroup(void *pContext, CUIRect View, bool Active);
struct SLayerPopupContext : public SPopupMenuId
2020-02-28 15:25:27 +00:00
{
CEditor *m_pEditor;
std::vector<std::shared_ptr<CLayerTiles>> m_vpLayers;
2023-10-02 13:14:38 +00:00
std::vector<int> m_vLayerIndices;
2020-02-28 15:25:27 +00:00
CLayerTiles::SCommonPropState m_CommonPropState;
};
static CUI::EPopupMenuFunctionResult PopupLayer(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupQuad(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupSource(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupPoint(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupEnvPoint(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupEnvPointMulti(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupEnvPointCurveType(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupImage(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupSound(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupNewFolder(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupMapInfo(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupEvent(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupSelectImage(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupSelectSound(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupSelectGametileOp(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupSelectConfigAutoMap(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupTele(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupSpeedup(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupSwitch(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupTune(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupGoto(void *pContext, CUIRect View, bool Active);
static CUI::EPopupMenuFunctionResult PopupEntities(void *pContext, CUIRect View, bool Active);
2023-05-01 21:07:58 +00:00
static CUI::EPopupMenuFunctionResult PopupProofMode(void *pContext, CUIRect View, bool Active);
static bool CallbackOpenMap(const char *pFileName, int StorageType, void *pUser);
static bool CallbackAppendMap(const char *pFileName, int StorageType, void *pUser);
static bool CallbackSaveMap(const char *pFileName, int StorageType, void *pUser);
static bool CallbackSaveCopyMap(const char *pFileName, int StorageType, void *pUser);
2023-08-12 10:13:27 +00:00
static bool CallbackAddTileart(const char *pFilepath, int StorageType, void *pUser);
2023-09-14 15:50:31 +00:00
static bool CallbackSaveImage(const char *pFileName, int StorageType, void *pUser);
2023-09-30 15:28:47 +00:00
static bool CallbackSaveSound(const char *pFileName, int StorageType, void *pUser);
2010-05-29 07:25:38 +00:00
void PopupSelectImageInvoke(int Current, float x, float y);
int PopupSelectImageResult();
void PopupSelectGametileOpInvoke(float x, float y);
int PopupSelectGameTileOpResult();
2011-08-11 08:59:14 +00:00
void PopupSelectConfigAutoMapInvoke(int Current, float x, float y);
int PopupSelectConfigAutoMapResult();
2014-10-08 15:33:06 +00:00
void PopupSelectSoundInvoke(int Current, float x, float y);
2015-07-09 00:08:14 +00:00
int PopupSelectSoundResult();
2014-10-08 15:33:06 +00:00
void DoQuadEnvelopes(const std::vector<CQuad> &vQuads, IGraphics::CTextureHandle Texture = IGraphics::CTextureHandle());
void DoQuadEnvPoint(const CQuad *pQuad, int QIndex, int pIndex);
2023-10-02 13:14:38 +00:00
void DoQuadPoint(const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int QuadIndex, int v);
void SetHotQuadPoint(const std::shared_ptr<CLayerQuads> &pLayer);
2011-08-14 14:31:48 +00:00
2022-02-26 17:49:06 +00:00
float TriangleArea(vec2 A, vec2 B, vec2 C);
bool IsInTriangle(vec2 Point, vec2 A, vec2 B, vec2 C);
void DoQuadKnife(int QuadIndex);
void DoSoundSource(CSoundSource *pSource, int Index);
2018-04-04 19:41:14 +00:00
void DoMapEditor(CUIRect View);
void DoToolbarLayers(CUIRect Toolbar);
void DoToolbarSounds(CUIRect Toolbar);
2023-10-02 13:14:38 +00:00
void DoQuad(const std::shared_ptr<CLayerQuads> &pLayer, CQuad *pQuad, int Index);
ColorRGBA GetButtonColor(const void *pID, int Checked);
bool ReplaceImage(const char *pFilename, int StorageType, bool CheckDuplicate);
static bool ReplaceImageCallback(const char *pFilename, int StorageType, void *pUser);
bool ReplaceSound(const char *pFileName, int StorageType, bool CheckDuplicate);
static bool ReplaceSoundCallback(const char *pFileName, int StorageType, void *pUser);
static bool AddImage(const char *pFilename, int StorageType, void *pUser);
static bool AddSound(const char *pFileName, int StorageType, void *pUser);
bool IsEnvelopeUsed(int EnvelopeIndex) const;
void RemoveUnusedEnvelopes();
2018-10-14 13:53:14 +00:00
static bool IsVanillaImage(const char *pImage);
void RenderLayers(CUIRect LayersBox);
void RenderImagesList(CUIRect Toolbox);
void RenderSelectedImage(CUIRect View);
void RenderSounds(CUIRect Toolbox);
2010-05-29 07:25:38 +00:00
void RenderModebar(CUIRect View);
void RenderStatusbar(CUIRect View, CUIRect *pTooltipRect);
void RenderTooltip(CUIRect TooltipRect);
2010-05-29 07:25:38 +00:00
void RenderEnvelopeEditor(CUIRect View);
void RenderServerSettingsEditor(CUIRect View, bool ShowServerSettingsEditorLast);
2023-10-02 13:14:38 +00:00
void RenderEditorHistory(CUIRect View);
2023-07-23 08:15:01 +00:00
void RenderExtraEditorDragBar(CUIRect View, CUIRect DragBar);
void SetHotEnvelopePoint(const CUIRect &View, const std::shared_ptr<CEnvelope> &pEnvelope, int ActiveChannels);
2023-07-23 08:15:01 +00:00
2010-05-29 07:25:38 +00:00
void RenderMenubar(CUIRect Menubar);
void RenderFileDialog();
void SelectGameLayer();
2023-10-02 13:14:38 +00:00
std::vector<int> SortImages();
bool SelectLayerByTile();
2021-08-27 18:28:11 +00:00
void DoAudioPreview(CUIRect View, const void *pPlayPauseButtonID, const void *pStopButtonID, const void *pSeekBarID, const int SampleID);
2023-05-23 19:57:57 +00:00
// Tile Numbers For Explanations - TODO: Add/Improve tiles and explanations
enum
{
2021-08-28 17:51:38 +00:00
TILE_PUB_AIR,
TILE_PUB_HOOKABLE,
TILE_PUB_DEATH,
TILE_PUB_UNHOOKABLE,
TILE_PUB_CREDITS1 = 140,
TILE_PUB_CREDITS2,
TILE_PUB_CREDITS3,
TILE_PUB_CREDITS4,
TILE_PUB_CREDITS5 = 156,
TILE_PUB_CREDITS6,
TILE_PUB_CREDITS7,
TILE_PUB_CREDITS8,
TILE_PUB_ENTITIES_OFF1 = 190,
TILE_PUB_ENTITIES_OFF2,
};
2021-08-28 17:51:38 +00:00
enum
{
TILE_FNG_SPIKE_GOLD = 7,
TILE_FNG_SPIKE_NORMAL,
TILE_FNG_SPIKE_RED,
TILE_FNG_SPIKE_BLUE,
2021-08-28 17:51:38 +00:00
TILE_FNG_SCORE_RED,
TILE_FNG_SCORE_BLUE,
TILE_FNG_SPIKE_GREEN = 14,
2021-08-27 21:20:39 +00:00
TILE_FNG_SPIKE_PURPLE,
TILE_FNG_SPAWN = 192,
TILE_FNG_SPAWN_RED,
TILE_FNG_SPAWN_BLUE,
TILE_FNG_FLAG_RED,
TILE_FNG_FLAG_BLUE,
TILE_FNG_SHIELD,
TILE_FNG_HEART,
TILE_FNG_SHOTGUN,
TILE_FNG_GRENADE,
TILE_FNG_NINJA,
TILE_FNG_LASER,
TILE_FNG_SPIKE_OLD1 = 208,
TILE_FNG_SPIKE_OLD2,
TILE_FNG_SPIKE_OLD3
};
2021-08-28 17:51:38 +00:00
enum
{
TILE_VANILLA_SPAWN = 192,
TILE_VANILLA_SPAWN_RED,
TILE_VANILLA_SPAWN_BLUE,
TILE_VANILLA_FLAG_RED,
TILE_VANILLA_FLAG_BLUE,
TILE_VANILLA_SHIELD,
TILE_VANILLA_HEART,
TILE_VANILLA_SHOTGUN,
TILE_VANILLA_GRENADE,
TILE_VANILLA_NINJA,
TILE_VANILLA_LASER,
};
2023-05-23 19:57:57 +00:00
// Explanations
enum class EExplanation
{
NONE,
DDNET,
FNG,
RACE,
VANILLA,
BLOCKWORLDS
};
static const char *ExplainDDNet(int Tile, int Layer);
static const char *ExplainFNG(int Tile, int Layer);
static const char *ExplainVanilla(int Tile, int Layer);
static const char *Explain(EExplanation Explanation, int Tile, int Layer);
// Zooming
void ZoomAdaptOffsetX(float ZoomFactor, const CUIRect &View);
void UpdateZoomEnvelopeX(const CUIRect &View);
void ZoomAdaptOffsetY(float ZoomFactor, const CUIRect &View);
void UpdateZoomEnvelopeY(const CUIRect &View);
void ResetZoomEnvelope(const std::shared_ptr<CEnvelope> &pEnvelope, int ActiveChannels);
void RemoveTimeOffsetEnvelope(const std::shared_ptr<CEnvelope> &pEnvelope);
float ScreenToEnvelopeX(const CUIRect &View, float x) const;
float EnvelopeToScreenX(const CUIRect &View, float x) const;
float ScreenToEnvelopeY(const CUIRect &View, float y) const;
float EnvelopeToScreenY(const CUIRect &View, float y) const;
float ScreenToEnvelopeDX(const CUIRect &View, float dx);
float ScreenToEnvelopeDY(const CUIRect &View, float dy);
// DDRace
IGraphics::CTextureHandle GetFrontTexture();
IGraphics::CTextureHandle GetTeleTexture();
IGraphics::CTextureHandle GetSpeedupTexture();
IGraphics::CTextureHandle GetSwitchTexture();
IGraphics::CTextureHandle GetTuneTexture();
2010-12-07 15:51:59 +00:00
unsigned char m_TeleNumber;
2015-07-09 00:08:14 +00:00
unsigned char m_TuningNum;
unsigned char m_SpeedupForce;
unsigned char m_SpeedupMaxSpeed;
short m_SpeedupAngle;
unsigned char m_SwitchNum;
2010-11-22 20:43:22 +00:00
unsigned char m_SwitchDelay;
2023-10-02 13:14:38 +00:00
// Undo/Redo
CEditorHistory m_EditorHistory;
CEditorHistory m_ServerSettingsHistory;
CEditorHistory m_EnvelopeEditorHistory;
CQuadEditTracker m_QuadTracker;
CEnvelopeEditorOperationTracker m_EnvOpTracker;
private:
void UndoLastAction();
void RedoLastAction();
2010-05-29 07:25:38 +00:00
};
// make sure to inline this function
inline class IGraphics *CLayer::Graphics() { return m_pEditor->Graphics(); }
inline class ITextRender *CLayer::TextRender() { return m_pEditor->TextRender(); }
#endif