add a simple text editor
This commit is contained in:
+1
-2
@@ -33,8 +33,6 @@ add_executable(ezremote_client
|
||||
source/http/iis.cpp
|
||||
source/http/nginx.cpp
|
||||
source/http/npxserve.cpp
|
||||
source/xt_editor/editor.cpp
|
||||
source/xt_editor/getline.c
|
||||
source/actions.cpp
|
||||
source/config.cpp
|
||||
source/fs.cpp
|
||||
@@ -59,6 +57,7 @@ add_self(ezremote_client)
|
||||
add_pkg(ezremote_client ${CMAKE_SOURCE_DIR}/data "RMTC00001" "ezRemote Client" "01.02" 32 0)
|
||||
|
||||
target_link_libraries(ezremote_client
|
||||
dbglogger
|
||||
c
|
||||
c++
|
||||
png
|
||||
|
||||
@@ -115,3 +115,8 @@ STR_ENABLE_RPI=RPI
|
||||
STR_ENABLE_RPI_FTP_SMB_MSG=This option enables Remote Package Installation. This requires a HTTP Server setup on the same host sharing the same folder with anonymous access.
|
||||
STR_ENABLE_RPI_WEBDAV_MSG=This option enables Remote Package Installation. This requires the Server with anonymous access that does not need username/password.
|
||||
STR_FILES=Files
|
||||
STR_EDITOR=Editor
|
||||
STR_SAVE=Save
|
||||
STR_MAX_EDIT_FILE_SIZE_MSG=Cannot edit files bigger than 32KB
|
||||
STR_DELETE_LINE=Delete Selected Line
|
||||
STR_INSERT_LINE=Insert Below Selected Line
|
||||
|
||||
+3
-1
@@ -44,9 +44,11 @@ enum ACTIONS
|
||||
ACTION_LOCAL_CUT,
|
||||
ACTION_LOCAL_COPY,
|
||||
ACTION_LOCAL_PASTE,
|
||||
ACTION_LOCAL_EDIT,
|
||||
ACTION_REMOTE_CUT,
|
||||
ACTION_REMOTE_COPY,
|
||||
ACTION_REMOTE_PASTE
|
||||
ACTION_REMOTE_PASTE,
|
||||
ACTION_REMOTE_EDIT
|
||||
};
|
||||
|
||||
enum OverWriteType
|
||||
|
||||
@@ -27,6 +27,7 @@ std::map<std::string, RemoteSettings> site_settings;
|
||||
PackageUrlInfo install_pkg_url;
|
||||
char favorite_urls[MAX_FAVORITE_URLS][512];
|
||||
bool auto_delete_tmp_pkg;
|
||||
int max_edit_file_size;
|
||||
RemoteClient *remoteclient;
|
||||
|
||||
namespace CONFIG
|
||||
@@ -91,6 +92,9 @@ namespace CONFIG
|
||||
auto_delete_tmp_pkg = ReadBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, true);
|
||||
WriteBool(CONFIG_GLOBAL, CONFIG_AUTO_DELETE_TMP_PKG, auto_delete_tmp_pkg);
|
||||
|
||||
max_edit_file_size = ReadInt(CONFIG_GLOBAL, CONFIG_MAX_EDIT_FILE_SIZE, MAX_EDIT_FILE_SIZE);
|
||||
WriteInt(CONFIG_GLOBAL, CONFIG_MAX_EDIT_FILE_SIZE, max_edit_file_size);
|
||||
|
||||
for (int i = 0; i < sites.size(); i++)
|
||||
{
|
||||
RemoteSettings setting;
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#define DATA_PATH "/data/" APP_ID
|
||||
#define CONFIG_INI_FILE DATA_PATH "/config.ini"
|
||||
#define COOKIE_FILE DATA_PATH "/cookies.txt"
|
||||
#define TMP_EDITOR_FILE DATA_PATH "/tmp_editor.txt"
|
||||
|
||||
#define CONFIG_GLOBAL "Global"
|
||||
|
||||
@@ -28,6 +29,7 @@
|
||||
|
||||
#define CONFIG_FAVORITE_URLS "favorite_urls"
|
||||
#define MAX_FAVORITE_URLS 30
|
||||
#define CONFIG_MAX_EDIT_FILE_SIZE "max_edit_file_size"
|
||||
|
||||
#define CONFIG_LAST_SITE "last_site"
|
||||
#define CONFIG_AUTO_DELETE_TMP_PKG "auto_delete_tmp_pkg"
|
||||
@@ -42,6 +44,8 @@
|
||||
#define HTTP_SERVER_NGINX "Nginx"
|
||||
#define HTTP_SERVER_NPX_SERVE "Serve"
|
||||
|
||||
#define MAX_EDIT_FILE_SIZE 262144
|
||||
|
||||
struct RemoteSettings
|
||||
{
|
||||
char site_name[32];
|
||||
@@ -76,6 +80,7 @@ extern RemoteClient *remoteclient;
|
||||
extern PackageUrlInfo install_pkg_url;
|
||||
extern char favorite_urls[MAX_FAVORITE_URLS][512];
|
||||
extern bool auto_delete_tmp_pkg;
|
||||
extern int max_edit_file_size;
|
||||
|
||||
namespace CONFIG
|
||||
{
|
||||
|
||||
@@ -150,6 +150,67 @@ namespace FS
|
||||
return data;
|
||||
}
|
||||
|
||||
bool LoadText(std::vector<std::string> *lines, const std::string &path)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "r");
|
||||
if (fd == nullptr)
|
||||
return false;
|
||||
|
||||
lines->clear();
|
||||
|
||||
char buffer[1024];
|
||||
short bytes_read;
|
||||
std::vector<char> line = std::vector<char>(0);
|
||||
do
|
||||
{
|
||||
bytes_read = fread(buffer, sizeof(char), 1024, fd);
|
||||
if (bytes_read < 0)
|
||||
{
|
||||
fclose(fd);
|
||||
return false;
|
||||
}
|
||||
|
||||
for (short i = 0; i < bytes_read; i++)
|
||||
{
|
||||
if (buffer[i] != '\r' && buffer[i] != '\n')
|
||||
{
|
||||
line.push_back(buffer[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
lines->push_back(std::string(line.data(), line.size()));
|
||||
line = std::vector<char>(0);
|
||||
if (buffer[i] == '\r' && buffer[i+1] == '\n')
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} while (bytes_read == 1024);
|
||||
if (line.size()>0)
|
||||
lines->push_back(std::string(line.data(), line.size()));
|
||||
|
||||
fclose(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SaveText(std::vector<std::string> *lines, const std::string &path)
|
||||
{
|
||||
FILE *fd = OpenRW(path);
|
||||
if (fd == nullptr)
|
||||
return false;
|
||||
|
||||
char nl[1] = {'\n'};
|
||||
for (int i=0; i < lines->size(); i++)
|
||||
{
|
||||
Write(fd, lines->at(i).c_str(), lines->at(i).length());
|
||||
Write(fd, nl, 1);
|
||||
}
|
||||
|
||||
fclose(fd);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Save(const std::string &path, const void *data, uint32_t size)
|
||||
{
|
||||
FILE *fd = fopen(path.c_str(), "w+");
|
||||
|
||||
@@ -51,6 +51,9 @@ namespace FS
|
||||
int Write(FILE *f, const void *buffer, uint32_t size);
|
||||
|
||||
std::vector<char> Load(const std::string &path);
|
||||
bool LoadText(std::vector<std::string> *lines, const std::string &path);
|
||||
bool SaveText(std::vector<std::string> *lines, const std::string &path);
|
||||
|
||||
void Save(const std::string &path, const void *data, uint32_t size);
|
||||
|
||||
std::vector<std::string> ListFiles(const std::string &path);
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ namespace GUI
|
||||
{
|
||||
ImGui_ImplSDL2_ProcessEvent(&event);
|
||||
}
|
||||
|
||||
GImGui->GcCompactAll = true;
|
||||
ImGui_ImplSDLRenderer_NewFrame();
|
||||
ImGui_ImplSDL2_NewFrame();
|
||||
ImGui::NewFrame();
|
||||
|
||||
@@ -10,9 +10,9 @@
|
||||
#include "ime_dialog.h"
|
||||
|
||||
static int ime_dialog_running = 0;
|
||||
static uint16_t inputTextBuffer[512+1];
|
||||
static uint8_t storebuffer[512];
|
||||
static char initial_ime_text[512];
|
||||
static uint16_t inputTextBuffer[1024+1];
|
||||
static uint8_t storebuffer[1024];
|
||||
static char initial_ime_text[1024];
|
||||
static int max_text_length;
|
||||
|
||||
static void utf16_to_utf8(const uint16_t *src, uint8_t *dst)
|
||||
@@ -83,7 +83,7 @@ namespace Dialog
|
||||
|
||||
uint16_t title[100];
|
||||
|
||||
if ((initialTextBuffer && strlen(initialTextBuffer) > 511) || (Title && strlen(Title) > 99))
|
||||
if ((initialTextBuffer && strlen(initialTextBuffer) > 1023) || (Title && strlen(Title) > 99))
|
||||
{
|
||||
ime_dialog_running = 0;
|
||||
return -1;
|
||||
@@ -95,7 +95,7 @@ namespace Dialog
|
||||
|
||||
if (initialTextBuffer)
|
||||
{
|
||||
snprintf(initial_ime_text, 511, "%s", initialTextBuffer);
|
||||
snprintf(initial_ime_text, 1023, "%s", initialTextBuffer);
|
||||
}
|
||||
|
||||
// converts the multibyte string src to a wide-character string starting at dest.
|
||||
|
||||
@@ -129,6 +129,12 @@ char lang_strings[LANG_STRINGS_NUM][LANG_STR_SIZE] = {
|
||||
"This option enables Remote Package Installation. "
|
||||
"This requires the Server with anonymous access that does not need username/password.", // STR_ENABLE_RPI_WEBDAV_MSG
|
||||
"Files", // STR_FILES
|
||||
"Editor", // STR_EDITOR
|
||||
"Save", // STR_SAVE
|
||||
"Cannot edit files bigger than", // STR_MAX_EDIT_FILE_SIZE_MSG
|
||||
"Delete Selected Line", // STR_DELETE_LINE
|
||||
"Insert Below Selected Line", // STR_INSERT_LINE
|
||||
"Modified", // STR_MODIFIED
|
||||
};
|
||||
|
||||
bool needs_extended_font = false;
|
||||
|
||||
+8
-2
@@ -120,7 +120,13 @@
|
||||
FUNC(STR_ENABLE_RPI) \
|
||||
FUNC(STR_ENABLE_RPI_FTP_SMB_MSG) \
|
||||
FUNC(STR_ENABLE_RPI_WEBDAV_MSG) \
|
||||
FUNC(STR_FILES)
|
||||
FUNC(STR_FILES) \
|
||||
FUNC(STR_EDITOR) \
|
||||
FUNC(STR_SAVE) \
|
||||
FUNC(STR_MAX_EDIT_FILE_SIZE_MSG) \
|
||||
FUNC(STR_DELETE_LINE) \
|
||||
FUNC(STR_INSERT_LINE) \
|
||||
FUNC(STR_MODIFIED)
|
||||
|
||||
#define GET_VALUE(x) x,
|
||||
#define GET_STRING(x) #x,
|
||||
@@ -130,7 +136,7 @@ enum
|
||||
FOREACH_STR(GET_VALUE)
|
||||
};
|
||||
|
||||
#define LANG_STRINGS_NUM 117
|
||||
#define LANG_STRINGS_NUM 123
|
||||
#define LANG_ID_SIZE 64
|
||||
#define LANG_STR_SIZE 384
|
||||
extern char lang_identifiers[LANG_STRINGS_NUM][LANG_ID_SIZE];
|
||||
|
||||
+8
-4
@@ -11,7 +11,7 @@
|
||||
#include <orbis/Pad.h>
|
||||
#include <orbis/AudioOut.h>
|
||||
#include <orbis/Net.h>
|
||||
// #include <dbglogger.h>
|
||||
#include <dbglogger.h>
|
||||
|
||||
#include "imgui.h"
|
||||
#include "SDL2/SDL.h"
|
||||
@@ -118,6 +118,10 @@ void InitImgui()
|
||||
0xF56F, 0xF56F, // compress
|
||||
0xF0F6, 0xF0F6, // properties
|
||||
0xF112, 0xF112, // cancel
|
||||
0xF0DA, 0xF0DA, // arrow right
|
||||
0x0031, 0x0031, // 1
|
||||
0x004C, 0x004C, // L
|
||||
0x0052, 0x0052, // R
|
||||
0,
|
||||
};
|
||||
|
||||
@@ -240,7 +244,7 @@ void InitImgui()
|
||||
colors[ImGuiCol_PlotHistogramHovered] = panelHoverColor;
|
||||
colors[ImGuiCol_ModalWindowDimBg] = bgColorBlur;
|
||||
colors[ImGuiCol_DragDropTarget] = bgColor;
|
||||
colors[ImGuiCol_NavHighlight] = bgColor;
|
||||
colors[ImGuiCol_NavHighlight] = titleColor;
|
||||
colors[ImGuiCol_Tab] = bgColor;
|
||||
colors[ImGuiCol_TabActive] = panelActiveColor;
|
||||
colors[ImGuiCol_TabUnfocused] = bgColor;
|
||||
@@ -257,8 +261,8 @@ static void terminate()
|
||||
|
||||
int main()
|
||||
{
|
||||
// dbglogger_init();
|
||||
// dbglogger_log("If you see this you've set up dbglogger correctly.");
|
||||
dbglogger_init();
|
||||
dbglogger_log("If you see this you've set up dbglogger correctly.");
|
||||
int rc;
|
||||
// No buffering
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
@@ -17,7 +17,8 @@ enum RemoteActions
|
||||
REMOTE_ACTION_DOWNLOAD = 64,
|
||||
REMOTE_ACTION_UPLOAD = 128,
|
||||
REMOTE_ACTION_INSTALL = 256,
|
||||
REMOTE_ACTION_ALL = 511
|
||||
REMOTE_ACTION_EDIT = 512,
|
||||
REMOTE_ACTION_ALL = 1023
|
||||
};
|
||||
|
||||
enum ClientType
|
||||
|
||||
+188
-3
@@ -64,8 +64,18 @@ bool select_url_inprogress = false;
|
||||
int favorite_url_idx = 0;
|
||||
char extract_zip_folder[256];
|
||||
char zip_file_path[384];
|
||||
char label[256];
|
||||
|
||||
// Editor variables
|
||||
std::vector<std::string> edit_buffer;
|
||||
bool editor_inprogress = false;
|
||||
char edit_line[1024];
|
||||
int edit_line_num = 0;
|
||||
char label[256];
|
||||
bool editor_modified = false;
|
||||
char edit_file[256];
|
||||
int edit_line_to_select = -1;
|
||||
|
||||
// Overwrite dialog variables
|
||||
bool dont_prompt_overwrite = false;
|
||||
bool dont_prompt_overwrite_cb = false;
|
||||
int confirm_transfer_state = -1;
|
||||
@@ -789,7 +799,7 @@ namespace Windows
|
||||
{
|
||||
ImGui::SetNextWindowPos(ImVec2(1330, 300));
|
||||
}
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(230, 150), ImVec2(230, 550), NULL, NULL);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(230, 150), ImVec2(230, 600), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_ACTIONS], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImGui::PushID("Select All##settings");
|
||||
@@ -922,6 +932,46 @@ namespace Windows
|
||||
ImGui::PopID();
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::PushID("Edit##settings");
|
||||
flags = ImGuiSelectableFlags_None;
|
||||
if (remote_browser_selected && remoteclient != nullptr && !(remoteclient->SupportedActions() & REMOTE_ACTION_EDIT))
|
||||
{
|
||||
flags = ImGuiSelectableFlags_Disabled;
|
||||
}
|
||||
if (ImGui::Selectable(lang_strings[STR_EDIT], false, flags | ImGuiSelectableFlags_DontClosePopups, ImVec2(220, 0)))
|
||||
{
|
||||
bool can_edit = true;
|
||||
if (local_browser_selected)
|
||||
{
|
||||
if (selected_local_file.file_size > max_edit_file_size)
|
||||
can_edit = false;
|
||||
else
|
||||
{
|
||||
snprintf(edit_file, 255, "%s", selected_local_file.path);
|
||||
FS::LoadText(&edit_buffer, selected_local_file.path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (selected_remote_file.file_size > max_edit_file_size)
|
||||
can_edit = false;
|
||||
else if (remoteclient != nullptr && remoteclient->Get(TMP_EDITOR_FILE, selected_remote_file.path))
|
||||
{
|
||||
snprintf(edit_file, 255, "%s", selected_remote_file.path);
|
||||
FS::LoadText(&edit_buffer, TMP_EDITOR_FILE);
|
||||
}
|
||||
}
|
||||
if (can_edit)
|
||||
editor_inprogress = true;
|
||||
else
|
||||
sprintf(status_message, "%s %d", lang_strings[STR_MAX_EDIT_FILE_SIZE_MSG], max_edit_file_size);
|
||||
editor_modified = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::PopID();
|
||||
ImGui::Separator();
|
||||
|
||||
if (local_browser_selected)
|
||||
{
|
||||
ImGui::PushID("Extract##settings");
|
||||
@@ -1329,6 +1379,131 @@ namespace Windows
|
||||
}
|
||||
}
|
||||
|
||||
void ShowEditorDialog()
|
||||
{
|
||||
if (editor_inprogress)
|
||||
{
|
||||
ImGuiIO &io = ImGui::GetIO();
|
||||
(void)io;
|
||||
ImGuiStyle *style = &ImGui::GetStyle();
|
||||
ImVec4 *colors = style->Colors;
|
||||
|
||||
SetModalMode(true);
|
||||
ImGui::OpenPopup(lang_strings[STR_EDITOR]);
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(320, 115));
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(1280, 80), ImVec2(1280, 850), NULL, NULL);
|
||||
if (ImGui::BeginPopupModal(lang_strings[STR_EDITOR], NULL, ImGuiWindowFlags_AlwaysAutoResize))
|
||||
{
|
||||
ImVec2 cur_pos = ImGui::GetCursorPos();
|
||||
char id[128];
|
||||
sprintf(id, "%s##editor", lang_strings[STR_CANCEL]);
|
||||
if (ImGui::Button(id, ImVec2(635, 0)))
|
||||
{
|
||||
editor_inprogress = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
sprintf(id, "%s##editor", lang_strings[STR_SAVE]);
|
||||
if (ImGui::Button(id, ImVec2(635, 0)))
|
||||
{
|
||||
bool local_browser_selected = saved_selected_browser & LOCAL_BROWSER;
|
||||
bool remote_browser_selected = saved_selected_browser & REMOTE_BROWSER;
|
||||
if (local_browser_selected)
|
||||
{
|
||||
FS::SaveText(&edit_buffer, selected_local_file.path);
|
||||
selected_action = ACTION_REFRESH_LOCAL_FILES;
|
||||
}
|
||||
else
|
||||
{
|
||||
FS::SaveText(&edit_buffer, TMP_EDITOR_FILE);
|
||||
if (remoteclient != nullptr)
|
||||
{
|
||||
remoteclient->Put(TMP_EDITOR_FILE, selected_remote_file.path);
|
||||
selected_action = ACTION_REFRESH_REMOTE_FILES;
|
||||
}
|
||||
}
|
||||
editor_inprogress = false;
|
||||
SetModalMode(false);
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
|
||||
ImGui::Separator();
|
||||
ImGui::BeginChild("Editor##ChildWindow", ImVec2(1275, 680));
|
||||
int j = 0;
|
||||
static int insert_item = -1;
|
||||
for (std::vector<std::string>::iterator it = edit_buffer.begin(); it != edit_buffer.end(); it++)
|
||||
{
|
||||
ImGui::Text("%s", ICON_FA_CARET_RIGHT);
|
||||
ImGui::SameLine();
|
||||
|
||||
sprintf(id, "%d##editor", j);
|
||||
ImGui::PushID(id);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0f, 1.0f));
|
||||
if (ImGui::Selectable(it->c_str(), false, ImGuiSelectableFlags_DontClosePopups, ImVec2(1275, 0)))
|
||||
{
|
||||
edit_line_num = j;
|
||||
snprintf(edit_line, 1023, "%s", it->c_str());
|
||||
ResetImeCallbacks();
|
||||
ime_single_field = edit_line;
|
||||
ime_field_size = 1023;
|
||||
ime_after_update = AfterEditorCallback;
|
||||
ime_callback = SingleValueImeCallback;
|
||||
Dialog::initImeDialog(lang_strings[STR_EDIT], edit_line, 1023, ORBIS_TYPE_BASIC_LATIN, 420, 290);
|
||||
gui_mode = GUI_MODE_IME;
|
||||
}
|
||||
ImGui::PopStyleVar();
|
||||
ImGui::PopID();
|
||||
if ((gui_mode != GUI_MODE_IME && j == edit_line_num) || edit_line_to_select == j)
|
||||
{
|
||||
SetNavFocusHere();
|
||||
edit_line_num = -1;
|
||||
edit_line_to_select = -1;
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
if (ImGui::CalcTextSize(it->c_str()).x > 1275)
|
||||
{
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::Text("%s", it->c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
if (ImGui::IsItemFocused())
|
||||
{
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_GamepadR1, false))
|
||||
{
|
||||
insert_item = j;
|
||||
editor_modified = true;
|
||||
}
|
||||
else if (ImGui::IsKeyPressed(ImGuiKey_GamepadL1, false))
|
||||
{
|
||||
edit_buffer.erase(it--);
|
||||
editor_modified = true;
|
||||
edit_line_to_select = j;
|
||||
}
|
||||
}
|
||||
j++;
|
||||
}
|
||||
if (insert_item > -1)
|
||||
{
|
||||
if (insert_item == edit_buffer.size() - 1)
|
||||
edit_buffer.push_back(std::string());
|
||||
else
|
||||
edit_buffer.insert(edit_buffer.begin() + insert_item + 1, std::string());
|
||||
}
|
||||
insert_item = -1;
|
||||
ImGui::EndChild();
|
||||
|
||||
ImGui::Text("%s%s", (editor_modified? "**" : ""), edit_file);
|
||||
ImGui::Separator();
|
||||
ImGui::Text("L1 - %s R1 - %s", lang_strings[STR_DELETE_LINE], lang_strings[STR_INSERT_LINE]);
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow()
|
||||
{
|
||||
Windows::SetupWindow();
|
||||
@@ -1346,6 +1521,7 @@ namespace Windows
|
||||
ShowProgressDialog();
|
||||
ShowActionsDialog();
|
||||
ShowFavoriteUrlsDialog();
|
||||
ShowEditorDialog();
|
||||
}
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -1626,7 +1802,6 @@ namespace Windows
|
||||
{
|
||||
ime_callback(ime_result);
|
||||
}
|
||||
|
||||
if (ime_after_update != nullptr)
|
||||
{
|
||||
ime_after_update(ime_result);
|
||||
@@ -1754,4 +1929,14 @@ namespace Windows
|
||||
remote_settings->http_port = atoi(txt_http_port);
|
||||
}
|
||||
}
|
||||
|
||||
void AfterEditorCallback(int ime_result)
|
||||
{
|
||||
if (ime_result == IME_DIALOG_RESULT_FINISHED)
|
||||
{
|
||||
std::string str = std::string(edit_line);
|
||||
edit_buffer[edit_line_num] = str;
|
||||
editor_modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ extern ACTIONS action_to_take;
|
||||
extern bool file_transfering;
|
||||
extern char extract_zip_folder[];
|
||||
extern char zip_file_path[];
|
||||
extern std::vector<std::string> edit_buffer;
|
||||
|
||||
static ImVector<ImRect> s_GroupPanelLabelStack;
|
||||
|
||||
@@ -208,6 +209,7 @@ namespace Windows
|
||||
void AfterZipFileCallback(int ime_result);
|
||||
void AferServerChangeCallback(int ime_result);
|
||||
void AfterHttpPortChangeCallback(int ime_result);
|
||||
void AfterEditorCallback(int ime_result);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,40 +0,0 @@
|
||||
#ifndef ARRAY_H
|
||||
#define ARRAY_H
|
||||
|
||||
#define ARRAY_INITIAL_CAPACITY 256
|
||||
|
||||
// note: An array whose length can dynamically change at run-time
|
||||
template <typename T>
|
||||
struct Array {
|
||||
T& operator[](int Index) {
|
||||
return Data[Index];
|
||||
}
|
||||
|
||||
T* Data;
|
||||
size_t Capacity;
|
||||
size_t Index;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
inline Array<T> array_init(size_t Capacity = ARRAY_INITIAL_CAPACITY) {
|
||||
Array<T> Result;
|
||||
|
||||
Result.Data = (T*)malloc(Capacity * sizeof(T));
|
||||
Result.Capacity = Capacity;
|
||||
Result.Index = 0;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void array_add(Array<T>* _Array, T Value) {
|
||||
if (_Array->Index >= _Array->Capacity) {
|
||||
_Array->Capacity *= 2;
|
||||
_Array->Data = (T*)realloc(_Array->Data, _Array->Capacity * sizeof(T));
|
||||
}
|
||||
|
||||
_Array->Data[_Array->Index] = Value;
|
||||
_Array->Index++;
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,385 +0,0 @@
|
||||
#include "xt_editor/types.h"
|
||||
#include "xt_editor/editor.h"
|
||||
struct EditorRow {
|
||||
char* Chars;
|
||||
size_t Size;
|
||||
};
|
||||
|
||||
struct EditorState {
|
||||
int CPosX;
|
||||
int CPosY;
|
||||
|
||||
int Rows;
|
||||
int Columns;
|
||||
|
||||
EditorRow* Row;
|
||||
int RowCount;
|
||||
int CharCount;
|
||||
|
||||
bool IsFileDirty;
|
||||
char* FileName;
|
||||
};
|
||||
|
||||
enum CursorStyle_ {
|
||||
CursorStyle_Block,
|
||||
CursorStyle_Block_Outline,
|
||||
CursorStyle_Line,
|
||||
CursorStyle_Underline,
|
||||
};
|
||||
|
||||
typedef int CursorStyle;
|
||||
|
||||
struct EditorConfig {
|
||||
CursorStyle Style;
|
||||
bool LineBlink;
|
||||
};
|
||||
|
||||
static EditorState State;
|
||||
static EditorConfig Config;
|
||||
static bool IsInitialized = false;
|
||||
static int TextStart = 7;
|
||||
static char LeftBuffer[16];
|
||||
static float BlinkStart = 0;
|
||||
static float BlinkEnd = 0;
|
||||
|
||||
#ifdef BUILD_WIN32
|
||||
#include "editor_input_win32.cpp"
|
||||
#else
|
||||
void Editor_HandleInput()
|
||||
{};
|
||||
#endif
|
||||
|
||||
|
||||
void Editor_OpenFile(char* Filename) {
|
||||
State.FileName = Filename;
|
||||
State.IsFileDirty = false;
|
||||
|
||||
FILE* File = fopen(Filename, "r");
|
||||
if (!File)
|
||||
return;
|
||||
|
||||
char* Line = 0;
|
||||
size_t LineCapacity = 0;
|
||||
ssize_t LineLength;
|
||||
while ((LineLength = getline(&Line, &LineCapacity, File)) != -1) {
|
||||
while (LineLength > 0 && (Line[LineLength - 1] == '\n' || Line[LineLength - 1] == '\r')) {
|
||||
LineLength--;
|
||||
Editor_AppendRow(Line, LineLength);
|
||||
State.CharCount += LineLength;
|
||||
}
|
||||
}
|
||||
free(Line);
|
||||
fclose(File);
|
||||
}
|
||||
|
||||
void Editor_Init() {
|
||||
State.CPosX = 0;
|
||||
State.CPosY = 0;
|
||||
|
||||
ImVec2 WindowSize = ImGui::GetWindowContentRegionMax();
|
||||
float FontSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x;
|
||||
ImVec2 CharAdvance = ImVec2(FontSize, ImGui::GetTextLineHeightWithSpacing() * 1.0f);
|
||||
|
||||
State.Rows = WindowSize.y / CharAdvance.y;
|
||||
State.Columns = WindowSize.x / CharAdvance.x;
|
||||
|
||||
State.Row = (EditorRow*)malloc(sizeof(EditorRow));
|
||||
|
||||
Editor_OpenFile("../src/editor.cpp");
|
||||
|
||||
IsInitialized = true;
|
||||
|
||||
Config.Style = CursorStyle_Block;
|
||||
Config.LineBlink = true;
|
||||
}
|
||||
// https://en.wikipedia.org/wiki/UTF-8
|
||||
// We assume that the char is a standalone character (<128) or a leading byte of an UTF-8 code sequence (non-10xxxxxx code)
|
||||
static int UTF8CharLength(char c) {
|
||||
if ((c & 0xFE) == 0xFC)
|
||||
return 6;
|
||||
if ((c & 0xFC) == 0xF8)
|
||||
return 5;
|
||||
if ((c & 0xF8) == 0xF0)
|
||||
return 4;
|
||||
else if ((c & 0xF0) == 0xE0)
|
||||
return 3;
|
||||
else if ((c & 0xE0) == 0xC0)
|
||||
return 2;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int Editor_GetCharacterIndexByCursor(int X, int Y) {
|
||||
int Index = 0;
|
||||
int Column = 0;
|
||||
EditorRow* Line = &State.Row[Y];
|
||||
if (Line == 0)
|
||||
return 0;
|
||||
|
||||
for (; Index < Line->Size && Column < X;) {
|
||||
Index += UTF8CharLength(Line->Chars[Index]);
|
||||
++Column;
|
||||
}
|
||||
|
||||
return Index;
|
||||
}
|
||||
|
||||
void Editor_RenderRows(ImVec2 WindowSize, ImVec2 Pos) {
|
||||
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImGui::GetStyle().Colors[ImGuiCol_FrameBg]);
|
||||
//ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0.0f, 0.0f));
|
||||
ImGui::BeginChild("Editor", WindowSize, true);
|
||||
ImGui::PushAllowKeyboardFocus(true);
|
||||
|
||||
// Handle input here or else we can't grab the childs input
|
||||
Editor_HandleInput();
|
||||
|
||||
if (State.CPosX < 0)
|
||||
State.CPosX = 0;
|
||||
|
||||
if (State.CPosY < 0)
|
||||
State.CPosY = 0;
|
||||
|
||||
static float FontSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x; // Get the size of the tallest char
|
||||
ImVec2 CharAdvance = ImVec2(FontSize, ImGui::GetTextLineHeightWithSpacing() * 1.0f);
|
||||
|
||||
bool Focused = ImGui::IsWindowFocused();
|
||||
float ScrollX = ImGui::GetScrollX();
|
||||
float ScrollY = ImGui::GetScrollY();
|
||||
|
||||
int LineNum = (int)floor(ScrollY / CharAdvance.y);
|
||||
int LineMax = Maximum(0, Minimum(State.RowCount - 1, LineNum + (int)floor((ScrollY + WindowSize.y) / CharAdvance.y)));
|
||||
|
||||
int ActualTextStart = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, LeftBuffer, nullptr, nullptr).x + TextStart;
|
||||
|
||||
ImDrawList* Draw = ImGui::GetWindowDrawList();
|
||||
|
||||
while (LineNum <= LineMax) {
|
||||
ImVec2 LineStartPos = ImVec2(Pos.x, Pos.y + LineNum * CharAdvance.y);
|
||||
ImVec2 TextPos = ImVec2(LineStartPos.x + ActualTextStart, LineStartPos.y);
|
||||
|
||||
snprintf(LeftBuffer, 16, "%*d ", (TextStart - 1), LineNum + 1);
|
||||
int LineNumWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, LeftBuffer, nullptr, nullptr).x;
|
||||
Draw->AddText(ImVec2(LineStartPos.x, LineStartPos.y), IM_COL32(255, 255, 255, 255), LeftBuffer);
|
||||
|
||||
ImVec2 Start = ImVec2(LineStartPos.x + ScrollX, LineStartPos.y);
|
||||
ImVec2 End = ImVec2(Start.x + ScrollX + WindowSize.x, Start.y + CharAdvance.y);
|
||||
Draw->AddRectFilled(Start, End, 0x141414);
|
||||
Draw->AddRect(Start, End, 0x40808080, 1.0f);
|
||||
|
||||
EditorRow* Row = &State.Row[LineNum];
|
||||
|
||||
size_t Len = Row->Size;
|
||||
if (Len > State.Columns) {
|
||||
Len = State.Columns;
|
||||
}
|
||||
|
||||
if (Config.Style != (CursorStyle_Line))
|
||||
Draw->AddText(TextPos, IM_COL32(255, 255, 255, 255), Row->Chars);
|
||||
|
||||
// Draw the cursor
|
||||
if (State.CPosY == LineNum && Focused) {
|
||||
float CursorWidth = CharAdvance.x;
|
||||
if (Config.Style == CursorStyle_Line || Config.Style == CursorStyle_Underline)
|
||||
CursorWidth = 1.f;
|
||||
|
||||
int Index = Editor_GetCharacterIndexByCursor(State.CPosX, State.CPosY);
|
||||
int ScaledCurX = (Index * CharAdvance.x);
|
||||
int ScaledCurY = (State.CPosY * CharAdvance.y);
|
||||
ImVec2 TextStartPos = ImVec2(Pos.x + ActualTextStart, Pos.y);
|
||||
|
||||
ImVec2 CursorStart, CursorEnd;
|
||||
if (Config.Style == CursorStyle_Underline) { // We are doing underline style
|
||||
CursorStart = ImVec2(TextStartPos.x + ScaledCurX, ((ScaledCurY + TextStartPos.y + CharAdvance.y) - CursorWidth) - 1);
|
||||
CursorEnd = ImVec2(TextStartPos.x + ScaledCurX + CharAdvance.x, (ScaledCurY + TextStartPos.y + CharAdvance.y) - 1);
|
||||
} else {
|
||||
CursorStart = ImVec2(TextStartPos.x + ScaledCurX, ScaledCurY + TextStartPos.y);
|
||||
CursorEnd = ImVec2(TextStartPos.x + ScaledCurX + CursorWidth, ScaledCurY + TextStartPos.y + CharAdvance.y);
|
||||
}
|
||||
|
||||
BlinkEnd++;
|
||||
float Elapsed = (BlinkEnd - BlinkStart);
|
||||
|
||||
static int OldCPosX = 0;
|
||||
static int OldCPosY = 0;
|
||||
if ((OldCPosX != State.CPosX || OldCPosY != State.CPosY) || Config.LineBlink == false) {
|
||||
// Constantly render the cursor if we're in motion
|
||||
(Config.Style == CursorStyle_Block_Outline) ? Draw->AddRect(CursorStart, CursorEnd, 0xffffffff, 1.0f) : Draw->AddRectFilled(CursorStart, CursorEnd, 0xffffffff);
|
||||
|
||||
// Draw the char of text at the cursors location in the opposite color
|
||||
char* Char = (char*)malloc(sizeof(char) * 1);
|
||||
Char[0] = Row->Chars[Index];
|
||||
Draw->AddText(CursorStart, IM_COL32(0, 0, 0, 255), Char);
|
||||
} else {
|
||||
// Blink the cursor rendering
|
||||
static float InitStart = 108;
|
||||
if (Elapsed > InitStart) {
|
||||
(Config.Style == CursorStyle_Block_Outline) ? Draw->AddRect(CursorStart, CursorEnd, 0xffffffff, 1.0f) : Draw->AddRectFilled(CursorStart, CursorEnd, 0xffffffff);
|
||||
|
||||
// Draw the char of text at the cursors location in the opposite color
|
||||
char* Char = (char*)malloc(sizeof(char) * 1);
|
||||
Char[0] = Row->Chars[Index];
|
||||
Draw->AddText(CursorStart, IM_COL32(0, 0, 0, 255), Char);
|
||||
|
||||
if (Elapsed > (InitStart + 40))
|
||||
BlinkStart = BlinkEnd;
|
||||
}
|
||||
}
|
||||
|
||||
OldCPosX = State.CPosX;
|
||||
OldCPosY = State.CPosY;
|
||||
}
|
||||
|
||||
// AddRect doesn't allow for a transparent rectangle so we need to write the character again :/
|
||||
// When we use CursorStyle_Line the original text gets overwritten in a similar way.
|
||||
if (Config.Style == CursorStyle_Block_Outline || Config.Style == CursorStyle_Line)
|
||||
Draw->AddText(TextPos, IM_COL32(255, 255, 255, 255), Row->Chars);
|
||||
|
||||
{
|
||||
// DEBUG DRAW: Cursor position and index
|
||||
int Index = Editor_GetCharacterIndexByCursor(State.CPosX, State.CPosY);
|
||||
char Temp[64];
|
||||
sprintf(Temp, "%d, %d, %d", State.CPosX, State.CPosY, Index);
|
||||
Draw->AddText(ImVec2(Pos.x + 550, Pos.y), IM_COL32(255, 255, 255, 255), Temp);
|
||||
}
|
||||
|
||||
LineNum++;
|
||||
}
|
||||
|
||||
while (LineNum >= LineMax) {
|
||||
ImVec2 LineStartPos = ImVec2(Pos.x, Pos.y + LineNum * CharAdvance.y);
|
||||
ImVec2 TextPos = ImVec2(LineStartPos.x + CharAdvance.x * (TextStart + 1), LineStartPos.y);
|
||||
|
||||
snprintf(LeftBuffer, 16, "%*s ", (TextStart - 1), "~");
|
||||
int LineNumWidth = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, LeftBuffer, nullptr, nullptr).x;
|
||||
Draw->AddText(ImVec2(LineStartPos.x, LineStartPos.y), IM_COL32(255, 255, 255, 255), LeftBuffer);
|
||||
|
||||
ImVec2 Start = ImVec2(LineStartPos.x + ScrollX, LineStartPos.y);
|
||||
ImVec2 End = ImVec2(Start.x + ScrollX + WindowSize.x, Start.y + CharAdvance.y);
|
||||
Draw->AddRectFilled(Start, End, 0x141414);
|
||||
Draw->AddRect(Start, End, 0x40808080, 1.0f);
|
||||
|
||||
LineNum++;
|
||||
|
||||
if (LineNum >= (LineMax)) break; // Impose some limit so that we don't render infinitly
|
||||
}
|
||||
|
||||
ImGui::PopAllowKeyboardFocus();
|
||||
ImGui::EndChild();
|
||||
//ImGui::PopStyleVar();
|
||||
ImGui::PopStyleColor();
|
||||
|
||||
ImGui::Text("xt editor -- \"%s\"%s %2s %dL %dC %8s (%d, %d)", State.FileName, (State.IsFileDirty) ? "*" : "", "", State.RowCount, State.CharCount, "", State.CPosX, State.CPosY);
|
||||
}
|
||||
|
||||
void Editor_AppendRow(char* String, size_t Length) {
|
||||
State.Row = (EditorRow*)realloc(State.Row, sizeof(EditorRow) * (State.RowCount + 1));
|
||||
|
||||
int At = State.RowCount;
|
||||
State.Row[At].Size = Length;
|
||||
State.Row[At].Chars = (char*)malloc(Length + 1);
|
||||
memcpy(State.Row[At].Chars, String, Length);
|
||||
State.Row[At].Chars[Length] = 0;
|
||||
State.RowCount++;
|
||||
}
|
||||
|
||||
bool StringsMatch(char* A, char* B) {
|
||||
while (*A && *B) {
|
||||
if (*A != *B){
|
||||
return false;
|
||||
}
|
||||
|
||||
++A;
|
||||
++B;
|
||||
}
|
||||
|
||||
if (*A != *B){
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
int StringLength(const char* String) {
|
||||
int Count = 0;
|
||||
while (*String++) {
|
||||
++Count;
|
||||
}
|
||||
return Count;
|
||||
}
|
||||
|
||||
char* StringCopy(const char* String) {
|
||||
char* Result = (char*)malloc(sizeof(char) * (StringLength(String) + 1));
|
||||
memcpy(Result, String, sizeof(char) * (StringLength(String) + 1));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
void Editor_Render() {
|
||||
ImGui::Begin("xt Demo Panel", nullptr, ImGuiWindowFlags_MenuBar | ImGuiWindowFlags_NoScrollbar);
|
||||
ImGui::SetWindowSize(ImVec2(1280, 720), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (!IsInitialized) {
|
||||
Editor_Init();
|
||||
}
|
||||
if (ImGui::BeginMenuBar()) {
|
||||
if (ImGui::BeginMenu("File")) {
|
||||
if (ImGui::MenuItem("Quit", "Alt-F4, CTRL-Q")) {
|
||||
exit(0);
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("View")) {
|
||||
if (ImGui::MenuItem("Cursor Blink", NULL, &Config.LineBlink)) {
|
||||
//ImGui::PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);
|
||||
//ImGui::PopItemFlag();
|
||||
}
|
||||
|
||||
{
|
||||
const char* Items[] = { "Block", "Block Outline", "Line", "Underline" };
|
||||
static char* CurrentItem = NULL;
|
||||
ImGuiComboFlags flags = ImGuiComboFlags_NoArrowButton;
|
||||
|
||||
ImGuiStyle& Style = ImGui::GetStyle();
|
||||
|
||||
ImGui::Text("Cursor Style");
|
||||
ImGui::SameLine(0, Style.ItemInnerSpacing.x);
|
||||
ImGui::PushItemWidth(ImGui::CalcItemWidth() - Style.ItemInnerSpacing.x- ImGui::GetFrameHeight());
|
||||
if (ImGui::BeginCombo("##custom combo", CurrentItem, ImGuiComboFlags_NoArrowButton)) {
|
||||
for (int n = 0; n < IM_ARRAYSIZE(Items); n++) {
|
||||
bool is_selected = (CurrentItem == Items[n]);
|
||||
if (ImGui::Selectable(Items[n], is_selected)) {
|
||||
CurrentItem = StringCopy(Items[n]);
|
||||
if (StringsMatch(CurrentItem, "Block")) {
|
||||
Config.Style = CursorStyle_Block;
|
||||
}
|
||||
else if (StringsMatch(CurrentItem, "Block Outline")) {
|
||||
Config.Style = CursorStyle_Block_Outline;
|
||||
}
|
||||
else if (StringsMatch(CurrentItem, "Line")) {
|
||||
Config.Style = CursorStyle_Line;
|
||||
}
|
||||
else if (StringsMatch(CurrentItem, "Underline")) {
|
||||
Config.Style = CursorStyle_Underline;
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::PopItemWidth();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
ImVec2 WindowSize = ImGui::GetWindowContentRegionMax();
|
||||
WindowSize.y -= 215;
|
||||
ImVec2 Pos = ImGui::GetCursorScreenPos();
|
||||
|
||||
Editor_RenderRows(WindowSize, Pos);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
#ifndef EDITOR_H
|
||||
#define EDITOR_H
|
||||
#include "imgui.h"
|
||||
|
||||
void Editor_Init();
|
||||
void Editor_AppendRow(char* String, size_t Length);
|
||||
void Editor_RenderRows(ImVec2 WindowSize, ImVec2 Pos);
|
||||
void Editor_Render();
|
||||
|
||||
#endif
|
||||
@@ -1,56 +0,0 @@
|
||||
// getline() is written to POSIX spec so that it can be used on Windows platforms
|
||||
// This is taken from a stackexchange answer, link has since been lost.
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <errno.h>
|
||||
|
||||
typedef intptr_t ssize_t;
|
||||
|
||||
ssize_t getline(char** lineptr, size_t* n, FILE* stream) {
|
||||
size_t pos;
|
||||
int c;
|
||||
|
||||
if (lineptr == NULL || stream == NULL || n == NULL) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
c = getc(stream);
|
||||
if (c == EOF) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (*lineptr == NULL) {
|
||||
*lineptr = (char*)malloc(128);
|
||||
if (*lineptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*n = 128;
|
||||
}
|
||||
|
||||
pos = 0;
|
||||
while (c != EOF) {
|
||||
if (pos + 1 >= *n) {
|
||||
size_t new_size = *n + (*n >> 2);
|
||||
if (new_size < 128) {
|
||||
new_size = 128;
|
||||
}
|
||||
char* new_ptr = (char*)realloc(*lineptr, new_size);
|
||||
if (new_ptr == NULL) {
|
||||
return -1;
|
||||
}
|
||||
*n = new_size;
|
||||
*lineptr = new_ptr;
|
||||
}
|
||||
|
||||
((unsigned char*)(*lineptr))[pos++] = c;
|
||||
if (c == '\n') {
|
||||
break;
|
||||
}
|
||||
c = getc(stream);
|
||||
}
|
||||
|
||||
(*lineptr)[pos] = '\0';
|
||||
return pos;
|
||||
}
|
||||
@@ -1,215 +0,0 @@
|
||||
#ifndef TYPES_H
|
||||
#define TYPES_H
|
||||
|
||||
#include <float.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <math.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef BUILD_WIN32 // MSVC
|
||||
#define API_EXPORT extern "C" __declspec(dllexport)
|
||||
#define API_IMPORT extern "C" __declspec(dllimport)
|
||||
#elif BUILD_LINUX | BUILD_MACOS // GCC or Clang
|
||||
#define API_EXPORT extern "C" __attribute__((visibility("default")))
|
||||
#define API_IMPORT
|
||||
#endif
|
||||
|
||||
#define global static
|
||||
|
||||
typedef unsigned int uint;
|
||||
|
||||
typedef int8_t int8;
|
||||
typedef int16_t int16;
|
||||
typedef int32_t int32;
|
||||
typedef int64_t int64;
|
||||
typedef int32 bool32;
|
||||
|
||||
typedef uint8_t uint8;
|
||||
typedef uint16_t uint16;
|
||||
typedef uint32_t uint32;
|
||||
typedef uint64_t uint64;
|
||||
|
||||
typedef float real32;
|
||||
typedef double real64;
|
||||
|
||||
typedef int8 s8;
|
||||
typedef int16 s16;
|
||||
typedef int32 s32;
|
||||
typedef int64 s64;
|
||||
typedef bool32 b32;
|
||||
|
||||
typedef uint8 u8;
|
||||
typedef uint16 u16;
|
||||
typedef uint32 u32;
|
||||
typedef uint64 u64;
|
||||
|
||||
typedef real32 f32;
|
||||
typedef real64 f64;
|
||||
|
||||
typedef uintptr_t umm;
|
||||
typedef intptr_t smm;
|
||||
|
||||
#define S32Min ((s32)0x80000000)
|
||||
#define S32Max ((s32)0x7fffffff)
|
||||
#define U16Max 65535
|
||||
#define U32Max ((u32)-1)
|
||||
#define U64Max ((u64)-1)
|
||||
#define F32Max FLT_MAX
|
||||
#define F32Min -FLT_MAX
|
||||
|
||||
#define Minimum(A, B) ((A < B) ? (A) : (B))
|
||||
#define Maximum(A, B) ((A > B) ? (A) : (B))
|
||||
|
||||
#define For(Value) For_e((Value), ArrayCount(Value))
|
||||
#define For_e(Value, End) For_se((Value), 0, (End))
|
||||
#define For_se(Value, Start, End) for (int (Value) = (Start); (Value) < (End); ++(Value))
|
||||
|
||||
// todo(jax): Should these always be 64-bit?
|
||||
#define Kilobytes(Value) (((uint64)Value) * 1024LL)
|
||||
#define Megabytes(Value) (Kilobytes((uint64)Value) * 1024LL)
|
||||
#define Gigabytes(Value) (Megabytes((uint64)Value) * 1024LL)
|
||||
#define Terabytes(Value) (Gigabytes((uint64)Value) * 1024LL)
|
||||
|
||||
#define ArrayCount(Array) (sizeof(Array) / sizeof((Array)[0]))
|
||||
// todo(jax): swap, min, max ... macros???
|
||||
|
||||
#define AlignPow2(Value, Alignment) ((Value + ((Alignment) - 1)) & ~((Alignment) - 1))
|
||||
#define Align4(Value) ((Value + 3) & ~3)
|
||||
#define Align8(Value) ((Value + 7) & ~7)
|
||||
#define Align16(Value) ((Value + 15) & ~15)
|
||||
|
||||
#define Stringize(x) PrimitiveStringize(x)
|
||||
#define PrimitiveStringize(x) #x
|
||||
|
||||
inline b32 IsPow2(u32 Value) {
|
||||
return ((Value & ~(Value - 1)) == Value);
|
||||
}
|
||||
|
||||
// ANSI Color Codes
|
||||
#define BLACK "\33[0;30m"
|
||||
#define RED "\33[0;31m"
|
||||
#define GREEN "\33[0;32m"
|
||||
#define YELLOW "\33[0;33m"
|
||||
#define BLUE "\33[0;34m"
|
||||
#define MAGENTA "\33[0;35m"
|
||||
#define CYAN "\33[0;36m"
|
||||
#define WHITE "\33[0;37m"
|
||||
#define LIGHT_GRAY "\33[0;37m"
|
||||
#define DARK_GRAY "\33[1;30m"
|
||||
#define BOLD_BLACK "\33[1;30m"
|
||||
#define BOLD_RED "\33[1;31m"
|
||||
#define BOLD_GREEN "\33[1;32m"
|
||||
#define BOLD_YELLOW "\33[1;33m"
|
||||
#define BOLD_BLUE "\33[1;34m"
|
||||
#define BOLD_MAGENTA "\33[1;35m"
|
||||
#define BOLD_CYAN "\33[1;36m"
|
||||
#define BOLD_WHITE "\33[1;37m"
|
||||
#define RESET "\33[0m"
|
||||
|
||||
// note(jax): Platform-independent way to perform an assertion.
|
||||
// Flat out writes to zero memory to crash the program.
|
||||
// todo(jax): Create some sort of assert function that creates a message box
|
||||
// like in previous engines I've worked on!
|
||||
#if ENGINE_SLOW
|
||||
#define Assert(Expression) if (!(Expression)) { *(int*)0=0; }
|
||||
#else
|
||||
#define Assert(Expression)
|
||||
#endif
|
||||
|
||||
#define InvalidCodePath Assert(!"InvalidCodePath")
|
||||
|
||||
// A structure that encapsulates a non-terminated buffer
|
||||
struct string {
|
||||
u8* Data;
|
||||
umm Count;
|
||||
};
|
||||
|
||||
inline u32 SafeTruncateU32(u64 Value) {
|
||||
// todo(jax): Defines for min/max values
|
||||
Assert(Value <= 0xFFFFFFFF);
|
||||
u32 Result = (u32)Value;
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline u16 SafeTruncateU16(u32 Value) {
|
||||
// todo(jax): Defines for min/max values
|
||||
Assert(Value <= 0xFFFF);
|
||||
u16 Result = (u16)Value;
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline u8 SafeTruncateU8(u64 Value) {
|
||||
Assert(Value <= 0xFF);
|
||||
u8 Result = (u8)Value;
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline s32 SafeTruncateS32(s64 Value) {
|
||||
if (Value >> 63) {
|
||||
b32 IsSafeOperation = !(!(Value >> 32) && 0xffffffff);
|
||||
if (!IsSafeOperation) {
|
||||
printf("SafeTruncateS32: Performing unsafe truncation on '%lld'\n", Value);
|
||||
}
|
||||
return (s32)Value;
|
||||
} else {
|
||||
b32 IsSafeOperation = !((Value >> 32) && 0xffffffff);
|
||||
if (!IsSafeOperation) {
|
||||
printf("SafeTruncateS32: Performing unsafe truncation on '%lld'\n", Value);
|
||||
}
|
||||
return (s32)Value;
|
||||
}
|
||||
}
|
||||
|
||||
inline s16 SafeTruncateS16(s32 Value) {
|
||||
if (Value >> 31) {
|
||||
b32 IsSafeOperation = !(!(Value >> 16) && 0xffff);
|
||||
if (!IsSafeOperation) {
|
||||
printf("SafeTruncateS16: Performing unsafe truncation on '%d'\n", Value);
|
||||
}
|
||||
return (s16)Value;
|
||||
} else {
|
||||
b32 IsSafeOperation = !((Value >> 16) && 0xffff);
|
||||
if (!IsSafeOperation) {
|
||||
printf("SafeTruncateS16: Performing unsafe truncation on '%d'\n", Value);
|
||||
}
|
||||
return (s16)Value;
|
||||
}
|
||||
}
|
||||
|
||||
inline s8 SafeTruncateS8(s16 Value) {
|
||||
if (Value >> 15) {
|
||||
b32 IsSafeOperation = !(!(Value >> 8) && 0xff);
|
||||
if (!IsSafeOperation) {
|
||||
printf("SafeTruncateS8: Performing unsafe truncation on '%d'\n", Value);
|
||||
}
|
||||
return (s8)Value;
|
||||
} else {
|
||||
b32 IsSafeOperation = !((Value >> 8) && 0xff);
|
||||
if (!IsSafeOperation) {
|
||||
printf("SafeTruncateS8: Performing unsafe truncation on '%d'\n", Value);
|
||||
}
|
||||
return (s8)Value;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// note: Scalar operations
|
||||
//
|
||||
|
||||
// todo(jax): These will eventually go into mathlib
|
||||
|
||||
inline real32 Square(real32 A) {
|
||||
real32 Result = A*A;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
inline real32 Lerp(real32 A, real32 t, real32 B){
|
||||
real32 Result = (1.0f - t)*A + t*B;
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user