mirror of
https://github.com/aimrebirth/tools.git
synced 2026-04-14 17:33:25 +00:00
Initial language switcher.
This commit is contained in:
parent
f443a5df8f
commit
11369f5778
2 changed files with 258 additions and 13 deletions
234
src/aim1_language_switcher/language_switcher.cpp
Normal file
234
src/aim1_language_switcher/language_switcher.cpp
Normal file
|
|
@ -0,0 +1,234 @@
|
|||
#include <filesystem>
|
||||
#include <format>
|
||||
#include <set>
|
||||
using namespace std::literals;
|
||||
namespace fs = std::filesystem;
|
||||
fs::path datadir = fs::current_path();
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include <windows.h>
|
||||
#include <CommCtrl.h>
|
||||
#include <objbase.h>
|
||||
|
||||
auto read_file(const fs::path &fn) {
|
||||
auto sz = fs::file_size(fn);
|
||||
std::string s(sz, 0);
|
||||
FILE *f = fopen(fn.string().c_str(), "rb");
|
||||
fread(s.data(), s.size(), 1, f);
|
||||
fclose(f);
|
||||
return s;
|
||||
}
|
||||
void write_file(const fs::path &fn, const std::string &s = {}) {
|
||||
fs::create_directories(fn.parent_path());
|
||||
|
||||
FILE *f = fopen(fn.string().c_str(), "wb");
|
||||
fwrite(s.data(), s.size(), 1, f);
|
||||
fclose(f);
|
||||
}
|
||||
void err(const std::wstring &s) {
|
||||
MessageBox(0, s.c_str(), TEXT("ERROR"), MB_OK);
|
||||
exit(1);
|
||||
}
|
||||
struct cfg {
|
||||
fs::path cfgfn;
|
||||
std::string findstr = "TextFile="s;
|
||||
size_t pos{UINT64_MAX},pose{UINT64_MAX};
|
||||
std::string s;
|
||||
|
||||
cfg() {
|
||||
if (fs::exists(datadir / "data")) {
|
||||
datadir /= "data";
|
||||
} else if (datadir.filename() == "data") {
|
||||
} else {
|
||||
err(L"Can't find data directory!");
|
||||
}
|
||||
cfgfn = datadir / "config" / "cfg.ini";
|
||||
}
|
||||
std::wstring get_current_lang() {
|
||||
s = read_file(cfgfn);
|
||||
pos = s.find(findstr);
|
||||
if (pos == -1) {
|
||||
err(L"cant find");
|
||||
return {};
|
||||
}
|
||||
pose = s.find_first_of("\r\n", pos);
|
||||
fs::path fn = s.substr(pos + findstr.size(), pose - (pos + findstr.size()));
|
||||
auto w = fn.stem().wstring();
|
||||
std::transform(w.begin(), w.end(), w.begin(), ::towlower);
|
||||
auto tofind = L"quest_"s;
|
||||
if (w.starts_with(tofind)) {
|
||||
auto lang = w.substr(tofind.size());
|
||||
std::transform(lang.begin(), lang.end(), lang.begin(), ::tolower);
|
||||
return lang;
|
||||
}
|
||||
return L"no language set (your default language)";
|
||||
}
|
||||
bool set_lang(auto &&lang) {
|
||||
if (lang.contains(L' ') || lang.contains(L" ")) {
|
||||
return false;
|
||||
}
|
||||
auto out = s.substr(0, pos + findstr.size()) + std::format("Data\\Quest_{}.dat", fs::path{lang}.string()) + s.substr(pose);
|
||||
write_file(cfgfn, out);
|
||||
write_file(cfgfn.parent_path() / "language.txt", fs::path{lang}.string());
|
||||
return true;
|
||||
}
|
||||
} c;
|
||||
|
||||
#ifndef HINST_THISCOMPONENT
|
||||
EXTERN_C IMAGE_DOS_HEADER __ImageBase;
|
||||
#define HINST_THISCOMPONENT ((HINSTANCE) & __ImageBase)
|
||||
#endif
|
||||
|
||||
struct DemoApp {
|
||||
HRESULT Initialize() {
|
||||
WNDCLASSEX wcex = {sizeof(WNDCLASSEX)};
|
||||
wcex.style = CS_HREDRAW | CS_VREDRAW;
|
||||
wcex.lpfnWndProc = DemoApp::WndProc;
|
||||
wcex.cbClsExtra = 0;
|
||||
wcex.cbWndExtra = sizeof(LONG_PTR);
|
||||
wcex.hInstance = HINST_THISCOMPONENT;
|
||||
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
|
||||
wcex.lpszMenuName = NULL;
|
||||
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wcex.lpszClassName = TEXT("DemoApp");
|
||||
RegisterClassEx(&wcex);
|
||||
|
||||
// Create the application window.
|
||||
int dpiX = 0;
|
||||
int dpiY = 0;
|
||||
int horpix{}, vertpix{};
|
||||
HDC hdc = GetDC(NULL);
|
||||
if (hdc) {
|
||||
dpiX = GetDeviceCaps(hdc, LOGPIXELSX);
|
||||
dpiY = GetDeviceCaps(hdc, LOGPIXELSY);
|
||||
|
||||
horpix = GetDeviceCaps(hdc, HORZRES);
|
||||
vertpix = GetDeviceCaps(hdc, VERTRES);
|
||||
ReleaseDC(NULL, hdc);
|
||||
}
|
||||
|
||||
int width = 400;
|
||||
int height = 100;
|
||||
m_hwnd = CreateWindow(TEXT("DemoApp"), TEXT("AIM1 Language Switcher"), WS_OVERLAPPEDWINDOW
|
||||
, (horpix - width) / 2
|
||||
, (vertpix - height) / 2
|
||||
, static_cast<UINT>(ceil(width * dpiX / 96.f))
|
||||
, static_cast<UINT>(ceil(height * dpiY / 96.f))
|
||||
, NULL, NULL, HINST_THISCOMPONENT, this);
|
||||
|
||||
auto hr = m_hwnd ? S_OK : E_FAIL;
|
||||
if (SUCCEEDED(hr)) {
|
||||
ShowWindow(m_hwnd, SW_SHOWNORMAL);
|
||||
UpdateWindow(m_hwnd);
|
||||
}
|
||||
|
||||
// Create the Combobox
|
||||
int nwidth = 300; // Width of the window
|
||||
int nheight = 200; // Height of the window
|
||||
int xpos = (width - nwidth) / 2; // Horizontal position of the window.
|
||||
int ypos = 15;//(height - nheight) / 2; // Vertical position of the window.
|
||||
HWND hwndParent = m_hwnd; // Handle to the parent window
|
||||
|
||||
HWND hWndComboBox =
|
||||
CreateWindow(WC_COMBOBOX, TEXT(""), CBS_DROPDOWN | CBS_HASSTRINGS | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE
|
||||
| CBS_AUTOHSCROLL | WS_HSCROLL | WS_VSCROLL,
|
||||
xpos, ypos, nwidth, nheight, hwndParent, NULL, HINST_THISCOMPONENT, NULL);
|
||||
|
||||
std::set<std::wstring> langs;
|
||||
for (auto &&fn : fs::directory_iterator(datadir)) {
|
||||
if (!fs::is_regular_file(fn)) {
|
||||
continue;
|
||||
}
|
||||
auto q = fn.path().stem().wstring();
|
||||
auto tofind = L"quest_"s;
|
||||
if (!q.starts_with(tofind)) {
|
||||
continue;
|
||||
}
|
||||
auto lang = q.substr(tofind.size());
|
||||
std::transform(lang.begin(), lang.end(), lang.begin(), ::towlower);
|
||||
langs.insert(lang);
|
||||
}
|
||||
auto [it,_] = langs.insert(c.get_current_lang());
|
||||
auto dist = std::distance(langs.begin(), it);
|
||||
for (auto &&l : langs) {
|
||||
SendMessage(hWndComboBox, (UINT)CB_ADDSTRING, (WPARAM)0, (LPARAM)l.c_str());
|
||||
}
|
||||
// Send the CB_SETCURSEL message to display an initial item in the selection field
|
||||
SendMessage(hWndComboBox, CB_SETCURSEL, (WPARAM)dist, (LPARAM)0);
|
||||
return hr;
|
||||
}
|
||||
void RunMessageLoop() {
|
||||
MSG msg;
|
||||
while (GetMessage(&msg, NULL, 0, 0)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
private:
|
||||
static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
|
||||
LRESULT result = 0;
|
||||
if (message == WM_CREATE) {
|
||||
auto pcs = (LPCREATESTRUCT)lParam;
|
||||
auto pDemoApp = (DemoApp *)pcs->lpCreateParams;
|
||||
::SetWindowLongPtr(hwnd, GWLP_USERDATA, PtrToUlong(pDemoApp));
|
||||
result = 1;
|
||||
} else {
|
||||
auto pDemoApp = reinterpret_cast<DemoApp *>(static_cast<LONG_PTR>(::GetWindowLongPtr(hwnd, GWLP_USERDATA)));
|
||||
bool wasHandled = false;
|
||||
if (pDemoApp) {
|
||||
switch (message) {
|
||||
case WM_COMMAND:
|
||||
if (HIWORD(wParam) == CBN_SELCHANGE) {
|
||||
// If the user makes a selection from the list:
|
||||
// Send CB_GETCURSEL message to get the index of the selected list item.
|
||||
// Send CB_GETLBTEXT message to get the item.
|
||||
// Display the item in a messagebox.
|
||||
int ItemIndex = SendMessage((HWND)lParam, (UINT)CB_GETCURSEL, (WPARAM)0, (LPARAM)0);
|
||||
TCHAR ListItem[256]{};
|
||||
SendMessage((HWND)lParam, (UINT)CB_GETLBTEXT, (WPARAM)ItemIndex, (LPARAM)ListItem);
|
||||
std::wstring s = ListItem;
|
||||
if (c.set_lang(s)) {
|
||||
std::wstring msg = L"Language changed to " + s;
|
||||
MessageBox(hwnd, msg.c_str(), TEXT("Language Changed"), MB_OK);
|
||||
}
|
||||
}
|
||||
wasHandled = true;
|
||||
result = 0;
|
||||
break;
|
||||
case WM_DISPLAYCHANGE:
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
wasHandled = true;
|
||||
result = 0;
|
||||
break;
|
||||
case WM_DESTROY:
|
||||
PostQuitMessage(0);
|
||||
wasHandled = true;
|
||||
result = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!wasHandled) {
|
||||
result = DefWindowProc(hwnd, message, wParam, lParam);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private:
|
||||
HWND m_hwnd{};
|
||||
};
|
||||
|
||||
int WINAPI WinMain(HINSTANCE, HINSTANCE, LPSTR, int) {
|
||||
HeapSetInformation(NULL, HeapEnableTerminationOnCorruption, NULL, 0);
|
||||
if (SUCCEEDED(CoInitialize(NULL))) {
|
||||
{
|
||||
DemoApp app;
|
||||
if (SUCCEEDED(app.Initialize())) {
|
||||
app.RunMessageLoop();
|
||||
}
|
||||
}
|
||||
CoUninitialize();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
37
sw.cpp
37
sw.cpp
|
|
@ -16,31 +16,31 @@ void build(Solution &s)
|
|||
common.Public += "pub.egorpugin.primitives.templates2"_dep;
|
||||
}
|
||||
|
||||
auto add_exe_base = [&](const String &name) -> decltype(auto)
|
||||
auto add_exe_base = [&](const String &name, String dirname = {}) -> decltype(auto)
|
||||
{
|
||||
if (dirname.empty())
|
||||
dirname = name;
|
||||
auto &t = tools.addExecutable(name);
|
||||
t.PackageDefinitions = true;
|
||||
t += cppstd;
|
||||
t.setRootDirectory("src/" + name);
|
||||
t.setRootDirectory("src/" + dirname);
|
||||
return t;
|
||||
};
|
||||
auto add_exe = [&](const String &name) -> decltype(auto)
|
||||
auto add_exe = [&](const String &name, const String &dirname = {}) -> decltype(auto)
|
||||
{
|
||||
auto &t = add_exe_base(name);
|
||||
auto &t = add_exe_base(name, dirname);
|
||||
t.Public += "pub.egorpugin.primitives.sw.main"_dep;
|
||||
return t;
|
||||
};
|
||||
|
||||
auto add_exe_with_common = [&](const String &name) -> decltype(auto)
|
||||
auto add_exe_with_common = [&](const String &name, const String &dirname = {}) -> decltype(auto)
|
||||
{
|
||||
auto &t = add_exe(name);
|
||||
auto &t = add_exe(name, dirname);
|
||||
t.Public += common;
|
||||
return t;
|
||||
};
|
||||
|
||||
auto add_exe_with_data_manager = [&](const String &name) -> decltype(auto)
|
||||
auto add_exe_with_data_manager = [&](const String &name, const String &dirname = {}) -> decltype(auto)
|
||||
{
|
||||
auto &t = add_exe_with_common(name);
|
||||
auto &t = add_exe_with_common(name, dirname);
|
||||
t.Public += "pub.lzwdgc.Polygon4.DataManager-master"_dep;
|
||||
return t;
|
||||
};
|
||||
|
|
@ -80,13 +80,24 @@ void build(Solution &s)
|
|||
;
|
||||
}
|
||||
|
||||
auto &aim1_mod_activator = add_exe_with_common("aim1_mod_activator");
|
||||
auto &language_switcher = tools.addExecutable("aim1.language_switcher");
|
||||
{
|
||||
auto &t = language_switcher;
|
||||
t += cppstd;
|
||||
t += "src/aim1_language_switcher/.*"_rr;
|
||||
t += "UNICODE"_def;
|
||||
t += "gdi32.lib"_slib, "ole32.lib"_slib, "user32.lib"_slib;
|
||||
if (auto L = t.getSelectedTool()->as<VisualStudioLinker*>(); L)
|
||||
L->Subsystem = vs::Subsystem::Windows;
|
||||
}
|
||||
|
||||
auto &aim1_mod_activator = add_exe_with_common("aim1.mod_activator", "aim1_mod_activator");
|
||||
aim1_mod_activator += "pub.egorpugin.primitives.pack"_dep;
|
||||
|
||||
auto &aim1_mod_maker = add_exe_with_common("aim1_mod_maker"); // actually a library
|
||||
auto &aim1_mod_maker = add_exe_with_common("aim1.mod_maker", "aim1_mod_maker"); // actually a library
|
||||
aim1_mod_maker.Public += "pub.egorpugin.primitives.command"_dep;
|
||||
|
||||
auto &aim1_community_fix = tools.addExecutable("examples.mods.aim1_community_fix");
|
||||
auto &aim1_community_fix = tools.addExecutable("examples.mods.aim1.community_fix");
|
||||
{
|
||||
auto &t = aim1_community_fix;
|
||||
t.PackageDefinitions = true;
|
||||
|
|
|
|||
Loading…
Reference in a new issue