输出测试,RenderableString基本完成

This commit is contained in:
EmsiaetKadosh
2025-01-17 16:36:39 +08:00
parent 2b7f05d928
commit 1007ac469a
10 changed files with 433 additions and 16 deletions
+1 -1
View File
@@ -121,7 +121,7 @@ CommentPragmas: true
CompactNamespaces: false # BTW false, true 如果为true,连续的namespace声明会被放在同一行里,除非太长 CompactNamespaces: false # BTW false, true 如果为true,连续的namespace声明会被放在同一行里,除非太长
# 构造函数参数列表和继承列表的缩进 # 构造函数参数列表和继承列表的缩进
ConstructorInitializerIndentWidth: 4 # 4 or 2,尽量与IndentWidth一致 ConstructorInitializerIndentWidth: 4 # 4 or 2,尽量与IndentWidth一致
ContinuationIndentWidth: 4 # 4 or 2,尽量与IndentWidth一致 ContinuationIndentWidth: 2 # 4 or 2,尽量与IndentWidth一致
Cpp11BracedListStyle: false # 如果为false,花括号里有东西的时候,会在左花括号右侧、右花括号左侧插入空格 Cpp11BracedListStyle: false # 如果为false,花括号里有东西的时候,会在左花括号右侧、右花括号左侧插入空格
# BTW false, true # BTW false, true
# 如果为true,会检查文件里最常出现的一种&和*的安排方式,然后统一; # 如果为true,会检查文件里最常出现的一种&和*的安排方式,然后统一;
+6 -4
View File
@@ -7,9 +7,9 @@ add_definitions(-DCINTERFACE)
add_definitions(-D__CARLBEKS_CMAKE_VSCODE__) add_definitions(-D__CARLBEKS_CMAKE_VSCODE__)
set(CMAKE_CXX_STANDARD 23) set(CMAKE_CXX_STANDARD 23)
set(CMAKE_WIN32_EXECUTABLE true) set(CMAKE_WIN32_EXECUTABLE true)
#if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang") if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
#add_compile_options(${PROJECT_NAME} -Wno-microsoft-string-literal-from-predefined) add_compile_options(${PROJECT_NAME} -Wno-microsoft-string-literal-from-predefined)
#endif() endif ()
#add_compile_options(${PROJECT_NAME} /utf-8) #add_compile_options(${PROJECT_NAME} /utf-8)
include(CTest) include(CTest)
@@ -27,7 +27,9 @@ add_executable(${PROJECT_NAME} main.cpp
Window.h Window.h
Hud.cpp Hud.cpp
Hud.h Hud.h
includes.h) includes.h
Text.h
Chars.h)
set(CPACK_PROJECT_NAME ${PROJECT_NAME}) set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack) include(CPack)
+71
View File
@@ -0,0 +1,71 @@
//
// Created by EmsiaetKadosh on 25-1-17.
//
#pragma once
#include "def.h"
[[nodiscard]] inline unsigned int wtouib16(const wchar* string) noexcept {
unsigned int ret = 0;
while (*string != L'\0') {
if (ret & 0xf0000000) return 0xffffffff;
if (*string >= L'0' && *string <= L'9') {
ret <<= 4;
ret += *string - L'0';
} else if (*string >= L'A' && *string <= L'F') {
ret <<= 4;
ret += *string - 0x41; // L'A' - 10
} else if (*string >= L'a' && *string <= L'f') {
ret <<= 4;
ret += *string - 0x61; // L'a' - 10
} else return 0xffffffff;
++string;
}
return ret;
}
[[nodiscard]] inline unsigned int wtouib16(const wchar* const string, const unsigned long long length) noexcept {
unsigned int ret = 0;
unsigned long long i = 0;
while (i < length) {
if (ret & 0xf0000000) return 0xffffffff;
if (string[i] >= L'0' && string[i] <= L'9') {
ret <<= 4;
ret += string[i] - L'0';
} else if (string[i] >= L'A' && string[i] <= L'F') {
ret <<= 4;
ret += string[i] - 0x41; // L'A' - 10
} else if (string[i] >= L'a' && string[i] <= L'f') {
ret <<= 4;
ret += string[i] - 0x61; // L'a' - 10
} else return 0xffffffff;
++i;
}
return ret;
}
/**
* 将数字转换为字符串
* @param value 要转换的数字
* @param fills 填充位数。返回的字符串长度一定不小于该值
* @return String类型
*/
[[nodiscard]] inline String uitowb16(unsigned int value, const unsigned int fills = 1) noexcept {
static constexpr const wchar* const table = L"0123456789ABCDEF";
String ret;
if (value < static_cast<unsigned int>(1) << fills - 1) {
ret.assign(fills, L'0');
for (unsigned int i = fills - 1; i != 0; --i) {
ret[i] = table[value & 0xf];
value >>= 4;
}
}
else {
while (value) {
ret.push_back(table[value & 0xf]);
value >>= 4;
}
}
return ret;
}
+8 -6
View File
@@ -5,8 +5,6 @@
#pragma once #pragma once
#include "Hud.h" #include "Hud.h"
#include "InteractManager.h"
#include "Renderer.h"
#include "Window.h" #include "Window.h"
class Game { class Game {
@@ -15,19 +13,23 @@ class Game {
public: public:
explicit Game() = default; explicit Game() = default;
void render() const noexcept { void render() const noexcept {
if (window) window->render(); if (window) window->render();
hud.render(); hud.render();
} }
void setWindow(Window* window) noexcept { int setWindow(Window* window) noexcept {
if (this->window == window) return; if (this->window == window) Success();
if (this->window) this->window->onClose(); if (this->window) this->window->onClose();
this->window = nullptr; this->window = nullptr;
if (window && window->onOpen()) if (window && window->onOpen()) {
this->window = window; this->window = window;
Success();
}
Failed();
} }
[[nodiscard]] Window* getWindow() const noexcept { return window; }
}; };
inline static Game game = Game(); inline static Game game = Game();
+9
View File
@@ -4,4 +4,13 @@
#include "Renderer.h" #include "Renderer.h"
#include "Game.h"
#include "hbp.h"
void Renderer::initialize() noexcept { MainDC = GetDC(MainWindowHandle); } void Renderer::initialize() noexcept { MainDC = GetDC(MainWindowHandle); }
void Renderer::resize(const int width, const int height) noexcept(false) {
windowWidth = width;
windowHeight = height;
if (game.getWindow()) game.getWindow()->onResize();
}
+1 -4
View File
@@ -19,10 +19,7 @@ public:
static void initialize() noexcept; static void initialize() noexcept;
explicit Renderer() = default; explicit Renderer() = default;
void resize(const int width, const int height) noexcept(false) { void resize(int width, int height) noexcept(false);
windowWidth = width;
windowHeight = height;
}
[[nodiscard]] int getWidth() const noexcept { return windowWidth; } [[nodiscard]] int getWidth() const noexcept { return windowWidth; }
[[nodiscard]] int getHeight() const noexcept { return windowHeight; } [[nodiscard]] int getHeight() const noexcept { return windowHeight; }
+265
View File
@@ -0,0 +1,265 @@
//
// Created by EmsiaetKadosh on 25-1-16.
//
#pragma once
#include "Chars.h"
#include "def.h"
class IdentifiedText {};
class RenderableString {
struct StringConfig {
String text;
/**
* 注意。-1也即0xffffffff被用于标记使用传入的默认颜色。
* 其余,以0xAARRGGBB的形式标记颜色。
*/
unsigned int color = -1;
/**
* 注意。-1也即0xffffffff被用于标记使用传入的默认颜色。
* 其余,以0xAARRGGBB的形式标记颜色。
*/
unsigned int background = -1;
wchar idFont = 0;
bool bold = false;
bool italic = false;
bool underline = false;
bool strikeThrough = false;
explicit StringConfig() = default;
void reset() noexcept {
idFont = 0;
color = -1;
background = -1;
bold = false;
italic = false;
underline = false;
strikeThrough = false;
}
[[nodiscard]] StringConfig copyConfig() const noexcept {
StringConfig ret;
ret.idFont = idFont;
ret.color = color;
ret.background = background;
ret.bold = bold;
ret.italic = italic;
ret.underline = underline;
ret.strikeThrough = strikeThrough;
return ret;
}
[[nodiscard]] String toString() const noexcept {
String ret;
ret.append(L"#");
ret.append(uitowb16(color));
ret.append(L".");
ret.append(uitowb16(background));
ret.append(L",F");
ret.append(std::to_wstring(idFont));
ret.append(L",");
if (bold) ret.append(L"=");
if (italic) ret.append(L"/");
if (underline) ret.append(L"_");
if (strikeThrough) ret.append(L"-");
ret.append(L":");
ret.append(text);
return ret;
}
};
List<StringConfig> configs;
public:
explicit RenderableString(const String& string): RenderableString(string.c_str(), string.length()) {}
explicit RenderableString(String&& string) : RenderableString(string.c_str(), string.length()) {}
explicit RenderableString(const wchar* const string, const QWORD length = static_cast<QWORD>(-1)) {
if (length == -1) parseAppend(string);
else parseAppend(string, length);
}
[[nodiscard]] String toString() const noexcept {
String ret;
for (const auto& config : configs) {
ret.append(config.toString());
ret.append(L";\n");
}
return ret;
}
private:
void parseAppend(const wchar* string) noexcept {
StringConfig config;
if (!configs.empty()) {
config = configs.back();
configs.pop_back();
}
while (*string != L'\0') {
const wchar* start = string;
if (!config.text.empty()) {
configs.push_back(std::move(config));
config = config.copyConfig();
}
while (*string != L'\0' && *string != '\\') ++string;
if (*string == L'\0') {
if (*start != L'\0') config.text.append(start, string);
configs.push_back(std::move(config));
return;
}
if (start != string) config.text.append(start, string);
if (*++string == L'\0') {
config.text.append(start, string);
configs.push_back(std::move(config));
return;
}
if (!config.text.empty()) {
configs.push_back(std::move(config));
config = config.copyConfig();
}
switch (*string) {
case L'\\':
config.text.append(1, L'\\');
++string;
continue;
case L'#': {
unsigned long long i = 0;
while (i < 9) if (string[i++] == L'\0') goto end;
config.color = wtouib16(++string, 8);
string += 8;
continue;
}
case L'.': {
unsigned long long i = 0;
while (i < 9) if (string[i++] == L'\0') goto end;
config.background = wtouib16(++string, 8);
string += 8;
continue;
}
case L'F':
case L'f':
if (*++string == L'\0') goto end;
config.idFont = *string;
break;
case L'-':
case L's':
case L'S':
config.strikeThrough = true;
break;
case L'_':
case L'u':
case L'U':
config.underline = true;
break;
case L'/':
case L'i':
case L'I':
config.italic = true;
break;
case L'=':
case L'b':
case L'B':
config.bold = true;
break;
case L'r':
case L'R':
if (!config.text.empty()) configs.push_back(std::move(config));
config = StringConfig();
break;
default:
config.text.append(string - 1, 2);
break;
}
++string;
}
end:
configs.push_back(std::move(config));
}
void parseAppend(const wchar* string, const QWORD length) noexcept {
StringConfig config = StringConfig();
if (!configs.empty()) {
config = configs.back();
configs.pop_back();
}
const wchar* const end = string + length;
while (string < end) {
const wchar* start = string;
if (!config.text.empty()) {
configs.push_back(std::move(config));
config = config.copyConfig();
}
while (string < end && *string != '\\') ++string;
if (string >= end) {
if (start != end) config.text.append(start, end);
configs.push_back(std::move(config));
return;
}
if (start != string) config.text.append(start, string);
if (++string == end) {
config.text.append(start, end);
configs.push_back(std::move(config));
return;
}
if (!config.text.empty()) {
configs.push_back(std::move(config));
config = config.copyConfig();
}
switch (*string) {
case L'\\':
config.text.append(1, L'\\');
++string;
continue;
case L'#': {
if (end - string < 9) break;
config.color = wtouib16(++string, 8);
string += 8;
continue;
}
case L'.': {
if (end - string < 9) break;
config.background = wtouib16(++string, 8);
string += 8;
continue;
}
case L'F':
case L'f':
if (++string == end) break;
config.idFont = *string;
break;
case L'-':
case L's':
case L'S':
config.strikeThrough = true;
break;
case L'_':
case L'u':
case L'U':
config.underline = true;
break;
case L'/':
case L'i':
case L'I':
config.italic = true;
break;
case L'=':
case L'b':
case L'B':
config.bold = true;
break;
case L'r':
case L'R':
if (!config.text.empty()) configs.push_back(std::move(config));
config = StringConfig();
break;
default:
config.text.append(string - 1, 2);
break;
}
++string;
}
configs.push_back(std::move(config));
}
};
+48
View File
@@ -4,10 +4,45 @@
#pragma once #pragma once
#include "def.h"
#include "Renderer.h" #include "Renderer.h"
class Widget : public Renderable {
protected:
int left = 0, top = 0, width = 0, height = 0;
mutable bool hasMouse = false;
public:
using Action = Function<void()>;
double x, y, w, h;
Action hover;
Action longHover;
Action mouseDown;
Action mouseUp;
Action mouseLeave;
explicit Widget(const double x, const double y, const double w, const double h) : x(x), y(y), w(w), h(h) {}
void render() const noexcept override {}
virtual void onResize() {}
virtual bool isMouseIn(int x, int y) noexcept {
x -= left;
y -= top;
if (0 <= x and x <= width and 0 <= y and y <= height) hasMouse = true;
hasMouse = false;
return hasMouse;
}
virtual void onHover() noexcept { if (hover) hover(); }
virtual void onLongHover() noexcept { if (longHover) longHover(); }
virtual void onMouseDown() noexcept { if (mouseDown) mouseDown(); }
virtual void onMouseUp() noexcept { if (mouseUp) mouseUp(); }
virtual void onMouseLeave() noexcept { if (mouseLeave) mouseLeave(); }
};
class Window : public Renderable { class Window : public Renderable {
protected: protected:
List<Widget*> widgets;
Window() = default; Window() = default;
public: public:
@@ -24,4 +59,17 @@ public:
* 注意,关闭未必就是删除。 * 注意,关闭未必就是删除。
*/ */
virtual void onClose() = 0; virtual void onClose() = 0;
virtual void onResize();
};
class FloatWindow final : public Window {
public:
void render() const noexcept override;
bool onOpen() override { return true; }
void onClose() override {}
};
class Button final : public Widget {
public:
explicit Button(const double x, const double y, const double w, const double h) : Widget(x, y, w, h) {}
}; };
+9 -1
View File
@@ -4,7 +4,9 @@
#pragma once #pragma once
#include <functional>
#include <iostream> #include <iostream>
#include <list>
#include <string> #include <string>
#include <map> #include <map>
@@ -12,6 +14,12 @@ using wchar = wchar_t;
using QWORD = unsigned long long int; using QWORD = unsigned long long int;
using String = std::wstring; using String = std::wstring;
template<typename K, typename V, typename Cmp = std::less<K>, typename Alloc = std::allocator<std::pair<const K, V>>> using Map = std::map<K, V, Cmp, Alloc>; template<typename K, typename V, typename Cmp = std::less<K>, typename Alloc = std::allocator<std::pair<const K, V>>> using Map = std::map<K, V, Cmp, Alloc>;
template<typename T, typename Alloc = std::allocator<T>> using List = std::list<T, Alloc>;
template<typename F> using Function = std::function<F>;
#define Success() { return 0; }
#define Failed() { return 1; }
#define Error() { return -1; }
#if false #if false
#ifdef _MSC_VER #ifdef _MSC_VER
@@ -23,8 +31,8 @@ template<typename K, typename V, typename Cmp = std::less<K>, typename Alloc = s
#endif #endif
#endif #endif
#if false
#define _WINSOCKAPI_ /* 防止winsock.h被引入。winsock.h和winsock2.h冲突。 */ #define _WINSOCKAPI_ /* 防止winsock.h被引入。winsock.h和winsock2.h冲突。 */
#if false
#include <WinSock2.h> #include <WinSock2.h>
#endif #endif
+15
View File
@@ -1,5 +1,6 @@
#include "includes.h" #include "includes.h"
#include "Text.h"
LRESULT __stdcall WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { LRESULT __stdcall WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) { switch (uMsg) {
@@ -158,6 +159,20 @@ int __stdcall wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCm
ShowWindow(MainWindowHandle, nCmdShow); ShowWindow(MainWindowHandle, nCmdShow);
InteractManager::initialize(); InteractManager::initialize();
Renderer::initialize(); Renderer::initialize();
SetConsoleOutputCP(65001);
const String string = String(L"\\#12345678Hello\\/\\f\1Well\\.87654321你好\\r\\r\\u\\-");
std::cout << "你好" << std::endl;
std::wcout.imbue(std::locale("zh_CN"));
std::wcout
<< sizeof(L"你好") << " " << sizeof("Hu") << std::endl
<< L"GetConsoleOutputCP => " << GetConsoleOutputCP() << std::endl
#if defined(UNICODE)
<< L"UNICODE" << std::endl
#else
<< L"Non-UNICODE" << std::endl
#endif
<< string << std::endl
<< RenderableString(string).toString() << std::endl;
HACCEL hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCE(109)); HACCEL hAccelTable = LoadAcceleratorsW(hInstance, MAKEINTRESOURCE(109));
MSG msg = { nullptr }; MSG msg = { nullptr };
while (GetMessageW(&msg, nullptr, 0, 0)) { while (GetMessageW(&msg, nullptr, 0, 0)) {