Initial language switcher.

This commit is contained in:
lzwdgc 2024-02-25 18:56:02 +03:00
parent f443a5df8f
commit 11369f5778
2 changed files with 258 additions and 13 deletions

View 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
View file

@ -16,31 +16,31 @@ void build(Solution &s)
common.Public += "pub.egorpugin.primitives.templates2"_dep; 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); auto &t = tools.addExecutable(name);
t.PackageDefinitions = true; t.PackageDefinitions = true;
t += cppstd; t += cppstd;
t.setRootDirectory("src/" + name); t.setRootDirectory("src/" + dirname);
return t; 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; t.Public += "pub.egorpugin.primitives.sw.main"_dep;
return t; return t;
}; };
auto add_exe_with_common = [&](const String &name, const String &dirname = {}) -> decltype(auto)
auto add_exe_with_common = [&](const String &name) -> decltype(auto)
{ {
auto &t = add_exe(name); auto &t = add_exe(name, dirname);
t.Public += common; t.Public += common;
return t; return t;
}; };
auto add_exe_with_data_manager = [&](const String &name, const String &dirname = {}) -> decltype(auto)
auto add_exe_with_data_manager = [&](const String &name) -> 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; t.Public += "pub.lzwdgc.Polygon4.DataManager-master"_dep;
return t; 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; 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; 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; auto &t = aim1_community_fix;
t.PackageDefinitions = true; t.PackageDefinitions = true;