From 20f4ef1cee310b96b9314674d5be54157761f25a Mon Sep 17 00:00:00 2001 From: EmsiaetKadosh Date: Fri, 21 Mar 2025 11:06:51 +0800 Subject: [PATCH] =?UTF-8?q?Translator=E5=88=9D=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .clang-tidy | 1 + CMakeLists.txt | 2 ++ File.cpp | 17 +++++++++++++++++ File.h | 9 +++++++++ Game.h | 2 -- IText.cpp | 25 +++++++++++++++++++------ IText.h | 14 ++++++++++---- Renderer.h | 2 -- Window.cpp | 27 ++++++++++++++------------- def.h | 3 +++ xWindows.h | 30 ++++++++++-------------------- 11 files changed, 85 insertions(+), 47 deletions(-) create mode 100644 File.cpp diff --git a/.clang-tidy b/.clang-tidy index da28d6f..43828ad 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -4,6 +4,7 @@ Checks: > -altera-struct-pack-align, -altera-unroll-loops, -boost-*, + -bugprone-assignment-in-if-condition, -bugprone-easily-swappable-parameters, -bugprone-forward-declaration-namespace, -bugprone-reserved-identifier, diff --git a/CMakeLists.txt b/CMakeLists.txt index 819751b..82ffaa9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,6 +37,8 @@ add_executable(${PROJECT_NAME} IText.h exception.cpp exception.h + File.h + File.cpp TextureManager.cpp TextureManager.h diff --git a/File.cpp b/File.cpp new file mode 100644 index 0000000..711ada2 --- /dev/null +++ b/File.cpp @@ -0,0 +1,17 @@ + +#include "def.h" + +#include "exception.h" +#include "File.h" + +File FileAccessor::getAccess(const String& path) { + namespace fs = std::filesystem; + using Path = fs::path; + Path original = path; + Path p = original.parent_path(); + if (!fs::exists(p)) { + create_directories(p); + Logger.info(L"Created directory " + p.wstring()); + } + return File(p); +} diff --git a/File.h b/File.h index b18bf26..d797ce8 100644 --- a/File.h +++ b/File.h @@ -153,3 +153,12 @@ public: return loadUntil(line); } }; + +class FileAccessor { +public: + [[nodiscard]] bool exists(const String& path) const { return std::filesystem::exists(path); } + + File getAccess(const String& path); +}; + +inline FileAccessor fileAccessor = FileAccessor(); diff --git a/Game.h b/Game.h index 4397d52..e963eaf 100644 --- a/Game.h +++ b/Game.h @@ -4,8 +4,6 @@ #pragma once -#include - #include "gc.h" #include "Hud.h" #include "Task.h" diff --git a/IText.cpp b/IText.cpp index 1b0afb9..ad2d594 100644 --- a/IText.cpp +++ b/IText.cpp @@ -61,7 +61,7 @@ void Font::drawDirect(const RenderableString::StringConfig& config, const int x, } void Font::clear() const { - for (const auto& fnt : fonts | std::views::values) renderer.deleteObject(fnt); + for (const auto& [_, fnt] : fonts) renderer.deleteObject(fnt); fonts.clear(); } @@ -103,7 +103,7 @@ void Font::drawCenter(const RenderableString& text, int x, int y, const int w, c } int Font::getWidth(const RenderableString::StringConfig& config) const { - HFONT font = tryCreate(config); + HFONT const font = tryCreate(config); RECT rect{}; SelectObject(renderer.assistDC, font); DrawTextW(renderer.assistDC, config.text.c_str(), static_cast(config.text.length()), &rect, DT_CALCRECT | DT_NOCLIP | DT_SINGLELINE); @@ -129,10 +129,23 @@ void TranslatableText::refreshText() const noexcept { void languageMakeChinese(Language& lang) { Logger.debug(L"languageMakeChinese called"); - Map& map = lang.translateTable; - map.emplace(String(L"hbp.title"), TranslatedText(L"高血压")); - map.emplace(String(L"hbp.confirm.confirm"), TranslatedText(L"确认")); - map.emplace(String(L"hbp.confirm.cancel"), TranslatedText(L"取消")); + Map& map = lang.translateTable; + map.emplace(L"hbp.title", TranslatedText(L"高血压")); + map.emplace(L"hbp.confirm.confirm", TranslatedText(L"确认")); + map.emplace(L"hbp.confirm.cancel", TranslatedText(L"取消")); + map.emplace(L"hbp.caption.close", TranslatedText(L"\\#ffee0000关闭窗口")); + map.emplace(L"hbp.caption.maximize", TranslatedText(L"\\#ff4488ee最大化窗口")); + map.emplace(L"hbp.caption.restore", TranslatedText(L"\\#ff4488ee复原窗口")); + map.emplace(L"hbp.caption.minimize", TranslatedText(L"\\#ffeeaaaa最小化窗口")); + map.emplace(L"hbp.float.freshCanvas", TranslatedText(L"\\.ff4488aa\\#ff000000右键以刷新窗口绘制")); + map.emplace(L"hbp.button.exit", TranslatedText(L"\\#ff44ee66退出")); + map.emplace(L"hbp.float.exit", TranslatedText(L"\\#ff44ee66退出游戏")); + map.emplace(L"hbp.confirming.exit", TranslatedText(L"是否\\#ff44ee66退出游戏\\r?")); + map.emplace(L"hbp.button.settings", TranslatedText(L"\\#ff4488aa设置")); + map.emplace(L"hbp.float.settings", TranslatedText(L"\\#ff4488aa设置")); + map.emplace(L"hbp.button.start", TranslatedText(L"\\#ffee0000开始")); + map.emplace(L"hbp.float.start", TranslatedText(L"\\#ffee0000开始游戏")); + map.emplace(L"hbp.confirming.start", TranslatedText(L"是否\\#ffee0000退出游戏\\r?")); } inline Translator translator = Translator(); diff --git a/IText.h b/IText.h index f10ddef..da83a0d 100644 --- a/IText.h +++ b/IText.h @@ -4,7 +4,6 @@ #pragma once -#include #include "def.h" #include "Chars.h" @@ -355,8 +354,7 @@ private: } }; -inline RenderableString operator""_renderable(const wchar* const text, const QWORD) noexcept { return RenderableString(text); } - +inline RenderableString operator""_renderable(const wchar* const text, const QWORD length) noexcept { return RenderableString(String(text, length)); } class Font { public: @@ -468,7 +466,7 @@ public: [[nodiscard]] Font& getDefault() const noexcept { return *defaultFont; } void resize(const int width, const int height) { - for (auto& font : fonts | std::views::values) + for (auto& [_, font] : fonts) if (font.resize) font.resize(width, height); else { font.height = static_cast(interactSettings.actual.fontHeight * font.heightModifier); @@ -497,6 +495,8 @@ public: const RenderableString& getRenderableString() const noexcept override { return renderableString; } } TranslatedText; +inline LiteralText operator""_literal(const wchar* const text, const QWORD length) noexcept { return LiteralText(String(text, length)); } + class TranslatableText final : public IText { const String idSrc; mutable const LiteralText* target = nullptr; @@ -505,11 +505,17 @@ class TranslatableText final : public IText { public: TranslatableText(const String& id) : idSrc(id) {} TranslatableText(String&& id) : idSrc(std::move(id)) {} + TranslatableText(const TranslatableText& other) : idSrc(other.idSrc) {} + TranslatableText(TranslatableText&& other) noexcept : idSrc(std::move(other.idSrc)) {} + const String& getID() const noexcept { return idSrc; } const String& getText() const noexcept override; const RenderableString& getRenderableString() const noexcept override; void refreshText() const noexcept; }; +inline TranslatableText operator""_translates(const wchar* const text, const QWORD length) noexcept { return TranslatableText(String(text, length)); } +inline TranslatedText operator""__translated(const wchar* const text, const QWORD length) noexcept { return TranslatedText(String(text, length)); } + using LangID = unsigned int; struct Language { diff --git a/Renderer.h b/Renderer.h index d0b1cb6..2eb3853 100644 --- a/Renderer.h +++ b/Renderer.h @@ -4,8 +4,6 @@ #pragma once -#include - #include "def.h" #include "exception.h" #include "Task.h" diff --git a/Window.cpp b/Window.cpp index df2fad3..553866a 100644 --- a/Window.cpp +++ b/Window.cpp @@ -45,9 +45,9 @@ void WindowManager::clear() noexcept { } CaptionWindow::CaptionWindow() { - Widget* close = widgets.emplace_back(Button(0, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, Location::RIGHT_TOP, LiteralText(L"\\f\1\u2716"))); + Widget* close = widgets.emplace_back(Button(0, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, Location::RIGHT_TOP, L"\\f\1\u2716"_literal)); close->mouseClick = [](Widget&, MouseButtonCode) { DestroyWindow(MainWindowHandle); }; - close->onTick = [this](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(L"\\#ffee0000关闭窗口"_renderable); }; + close->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(TranslatableText(L"hbp.caption.close").getRenderableString()); }; close->absolute(); close->backgroundColor.hover = 0xffee0000; close->backgroundColor.active = 0; @@ -58,15 +58,15 @@ CaptionWindow::CaptionWindow() { close->foregroundColor.inactive = 0xff000000; close->foregroundColor.clicked = 0xff000000; - Widget* maxRestore = widgets.emplace_back(Button(-interactSettings.actual.captionHeight, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, Location::RIGHT_TOP, LiteralText(IsZoomed(MainWindowHandle) ? L"\\f\1🗗" : L"\\f\1🗖" ))); + Widget* maxRestore = widgets.emplace_back(Button(-interactSettings.actual.captionHeight, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, Location::RIGHT_TOP, IsZoomed(MainWindowHandle) ? L"\\f\1🗗"_literal : L"\\f\1🗖"_literal )); maxRestore->mouseClick = [](Widget&, MouseButtonCode) {}; maxRestore->mouseClick = [](Widget& self, MouseButtonCode) { - if ((self.unused[1] = IsZoomed(MainWindowHandle))) ShowWindow(MainWindowHandle, SW_RESTORE); + if ((self.unused[1] = static_cast(IsZoomed(MainWindowHandle)))) ShowWindow(MainWindowHandle, SW_RESTORE); else ShowWindow(MainWindowHandle, SW_MAXIMIZE); }; - maxRestore->onTick = [this](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(self.unused[1] ? L"\\#ff4488ee复原窗口"_renderable : L"\\#ff4488ee最大化窗口"_renderable); }; + maxRestore->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(self.unused[1] ? TranslatableText(L"hbp.caption.maximize").getRenderableString() : TranslatableText(L"hbp.caption.restore").getRenderableString() ); }; maxRestore->absolute(); - maxRestore->unused[1] = IsZoomed(MainWindowHandle); + maxRestore->unused[1] = static_cast(IsZoomed(MainWindowHandle)); maxRestore->backgroundColor.hover = 0xffcccccc; maxRestore->backgroundColor.active = 0; maxRestore->backgroundColor.inactive = 0xff555555; @@ -76,7 +76,8 @@ CaptionWindow::CaptionWindow() { maxRestore->foregroundColor.inactive = 0xff000000; maxRestore->foregroundColor.clicked = 0xff000000; - Widget* hide = widgets.emplace_back(Button(-2 * interactSettings.actual.captionHeight, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, Location::RIGHT_TOP, LiteralText(L"\\f\1🗕"))); + Widget* hide = widgets.emplace_back(Button(-2 * interactSettings.actual.captionHeight, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, Location::RIGHT_TOP, L"\\f\1🗕"_literal)); + hide->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(TranslatableText(L"hbp.caption.minimize").getRenderableString()); }; hide->mouseClick = [](Widget&, MouseButtonCode) { ShowWindow(MainWindowHandle, SW_MINIMIZE); }; hide->absolute(); hide->backgroundColor.hover = 0xffcccccc; @@ -88,11 +89,11 @@ CaptionWindow::CaptionWindow() { hide->foregroundColor.inactive = 0xff000000; hide->foregroundColor.clicked = 0xff000000; - Widget* options = widgets.emplace_back(Button(0, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, Location::LEFT_TOP, LiteralText(L"\\f\1⛭"))); + Widget* options = widgets.emplace_back(Button(0, 0, interactSettings.actual.captionHeight, interactSettings.actual.captionHeight, Location::LEFT_TOP, L"\\f\1⛭"_literal)); options->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) { - game.getFloatWindow().push(L"\\#ff4488aa设置"_renderable); - game.getFloatWindow().push(L"\\.ff4488aa\\#ff000000右键以刷新窗口绘制"_renderable); + game.getFloatWindow().push(TranslatableText(L"hbp.float.settings").getRenderableString()); + game.getFloatWindow().push(TranslatableText(L"hbp.float.freshCanvas").getRenderableString()); } }; options->mouseClick = [](Widget&, const MouseButtonCode code) { if (static_cast(MouseButtonCodeEnum::MBC_R_DOWN) & code) { game.tasks.pushThis(renderer.resizeReloadBitmap); } }; @@ -157,7 +158,7 @@ void FloatWindow::render() const noexcept { width += fwm2; height += fwm2; if (x + width > renderer.getWidth()) x = renderer.getWidth() - width; - y = y < height ? 0 : y - height; + y = y < height + interactSettings.actual.captionHeight ? interactSettings.actual.captionHeight : y - height; renderer.fill(x, y, width, height, interactSettings.constants.floatWindowBackground); const int xf = x + interactSettings.actual.floatWindowMargin; @@ -327,8 +328,8 @@ ConfirmWindow& ConfirmWindow::requireCancel(const Function& func) cancel->x = 0.125; cancel->w = 0.5; } - cancel->onTick = [](Widget& cancel, MouseButtonCode) { if (cancel.containsMouse()) cancel.backgroundColor.hover = static_cast(cancel).animation.adaptsColor(0x99880000, 0x99ff0000); }; - cancel->mouseLeave = [](Widget& cancel, int) { static_cast(cancel).animation.reset(); }; + cancel->onTick = [](Widget& cancel, MouseButtonCode) { if (cancel.containsMouse()) cancel.backgroundColor.hover = dynamic_cast(cancel).animation.adaptsColor(0x99880000, 0x99ff0000); }; + cancel->mouseLeave = [](Widget& cancel, int) { dynamic_cast(cancel).animation.reset(); }; if (func) func(*cancel); cancel->onResize(); return *this; diff --git a/def.h b/def.h index 34de0d2..dbba7fc 100644 --- a/def.h +++ b/def.h @@ -11,6 +11,7 @@ #include #include +#include #include #include #include @@ -21,6 +22,8 @@ #include #include #include +#include +#include using wchar = wchar_t; using QWORD = unsigned long long int; diff --git a/xWindows.h b/xWindows.h index 933e393..a78f622 100644 --- a/xWindows.h +++ b/xWindows.h @@ -10,32 +10,22 @@ class StartWindow final : public Window { TranslatableText title = TranslatableText(L"hbp.title"); StartWindow() { - Button* start = dynamic_cast(widgets.emplace_back(std::move(Button(0, 0.1, 0.4, 0.08, Location::CENTER, LiteralText(L"\\f\4\\#ff44ee66Exit")))).ptr()); - start->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(L"\\#ff44ee66退出游戏"_renderable); }; + Button* start = dynamic_cast(widgets.emplace_back(std::move(Button(0, 0.1, 0.4, 0.08, Location::CENTER, L"hbp.button.exit"_translates))).ptr()); + start->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(L"hbp.float.exit"_translates.getRenderableString()); }; start->mouseClick = [](Widget&, MouseButtonCode) { - game.setWindow(&ConfirmWindow::of(LiteralText(L"是否\\#ff44ee66退出游戏\\r?"))->requireCancel().requireConfirm([](Button& confirm) { + game.setWindow(&ConfirmWindow::of(L"hbp.confirming.exit"_translates)->requireCancel().requireConfirm([](Button& confirm) { confirm.mouseClick = [](Widget&, MouseButtonCode) { DestroyWindow(MainWindowHandle); }; - confirm.onTick = [](Widget& self, MouseButtonCode) { - if (self.containsMouse()) { - game.getFloatWindow().push(L"\\#ff44ee66确定退出游戏"_renderable); - self.backgroundColor.hover = static_cast(self).animation.adaptsColor(0x99008800, 0x9900ff00); - } - }; + confirm.onTick = [](Widget& self, MouseButtonCode) { if (self.containsMouse()) self.backgroundColor.hover = static_cast(self).animation.adaptsColor(0x99008800, 0x9900ff00); }; })); }; - Button* optn = dynamic_cast(widgets.emplace_back(std::move(Button(0, 0.2, 0.4, 0.08, Location::CENTER, LiteralText(L"\\f\4\\#ff4488eeOptions")))).ptr()); - optn->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(L"\\#ff4488ee设置"_renderable); }; - Button* exit = dynamic_cast(widgets.emplace_back(std::move(Button(0, 0.3, 0.4, 0.08, Location::CENTER, LiteralText(L"\\f\4\\#ffee0000Start")))).ptr()); - exit->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(L"\\#ffee0000开始游戏"_renderable); }; + Button* optn = dynamic_cast(widgets.emplace_back(std::move(Button(0, 0.2, 0.4, 0.08, Location::CENTER, L"hbp.button.settings"_translates))).ptr()); + optn->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(L"hbp.float.settings"_translates.getRenderableString()); }; + Button* exit = dynamic_cast(widgets.emplace_back(std::move(Button(0, 0.3, 0.4, 0.08, Location::CENTER, L"hbp.button.start"_translates))).ptr()); + exit->onTick = [](const Widget& self, MouseButtonCode) { if (self.containsMouse()) game.getFloatWindow().push(L"hbp.float.start"_translates.getRenderableString()); }; exit->mouseClick = [](Widget&, MouseButtonCode) { - game.setWindow(&ConfirmWindow::of(LiteralText(L"是否\\#ffee0000退出游戏\\r?"))->requireCancel().requireConfirm([](Button& confirm) { + game.setWindow(&ConfirmWindow::of(L"hbp.confirming.start"_translates)->requireCancel().requireConfirm([](Button& confirm) { confirm.mouseClick = [](Widget&, MouseButtonCode) { DestroyWindow(MainWindowHandle); }; - confirm.onTick = [](Widget& self, MouseButtonCode) { - if (self.containsMouse()) { - game.getFloatWindow().push(L"\\#ff44ee66确定退出游戏"_renderable); - self.backgroundColor.hover = static_cast(self).animation.adaptsColor(0x99008800, 0x9900ff00); - } - }; + confirm.onTick = [](Widget& self, MouseButtonCode) { if (self.containsMouse()) self.backgroundColor.hover = static_cast(self).animation.adaptsColor(0x99008800, 0x9900ff00); }; })); }; }