changed mod menu to use gdi

This commit is contained in:
Soda Can 2026-03-10 16:47:33 +11:00
parent a498f5ea5e
commit ee8d07b6f7
94 changed files with 475 additions and 190 deletions

View file

@ -3,139 +3,462 @@
#include "UIScene_ModsMenu.h" #include "UIScene_ModsMenu.h"
#include "ModLoader.h" #include "ModLoader.h"
#include <windows.h> #include <windows.h>
#include <commctrl.h>
#include <string> #include <string>
#include <vector>
#pragma comment(lib, "comctl32.lib") // ---------------------------------------------------------------------------
// Colours
#define IDC_MODLIST 1001 // ---------------------------------------------------------------------------
#define IDC_CLOSE 1002 #define MC_DARK_GRY RGB(33, 33, 33)
#define IDC_MOD_NAME 1003 #define MC_MID_GRY RGB(50, 50, 50)
#define IDC_MOD_ID 1004
#define IDC_MOD_AUTHOR 1005
#define IDC_MOD_VERSION 1006
#define IDC_MOD_DESC 1007
#define IDC_MINI_X 1008
#define MC_BLACK RGB(0, 0, 0)
#define MC_DARK_GRY RGB(33, 33, 33)
#define MC_LIGHT_GRY RGB(198, 198, 198) #define MC_LIGHT_GRY RGB(198, 198, 198)
#define MC_SEL_BLU RGB(60, 60, 60) #define MC_SEL_BLU RGB(60, 60, 60)
#define MC_WHITE RGB(255, 255, 255)
#define MC_BORDER RGB(80, 80, 80)
#define MC_HOVER RGB(80, 80, 80)
#define MC_PRESS RGB(30, 30, 30)
#define MC_SCROLLBAR RGB(100, 100, 100)
static HWND g_hModsWindow = nullptr; // ---------------------------------------------------------------------------
static HWND g_hList = nullptr; // Layout constants
// ---------------------------------------------------------------------------
#define WW 1200
#define WH 600
#define LIST_X 20
#define LIST_Y 20
#define LIST_W 300
#define LIST_H 480
#define ITEM_H 32
#define INFO_X 340
#define INFO_W 820
#define BTN_X 340
#define BTN_Y 520
#define BTN_W 200
#define BTN_H 40
// ---------------------------------------------------------------------------
// Global state
// ---------------------------------------------------------------------------
static HWND g_hWnd = nullptr;
static UIScene_ModsMenu* g_pScene = nullptr; static UIScene_ModsMenu* g_pScene = nullptr;
static HBRUSH g_hBackBrush = nullptr;
static HBRUSH g_hSelBrush = nullptr;
static HBRUSH g_hBackBrush = nullptr;
static HFONT g_hFont = nullptr;
static HFONT g_hFontBold = nullptr;
static std::vector<std::string> g_modNames;
static int g_selIdx = -1;
static int g_listScroll = 0;
static std::string g_iName, g_iId, g_iAuthor, g_iVersion, g_iDesc;
static int g_descScroll = 0;
static int g_descTextH = 0;
static bool g_btnHover = false;
static bool g_btnPress = false;
static bool g_trackingMouse = false;
// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------
static void Redraw() { if (g_hWnd) InvalidateRect(g_hWnd, nullptr, FALSE); }
static RECT RectOf(int x, int y, int w, int h) { return { x, y, x + w, y + h }; }
static RECT ListRect() { return RectOf(LIST_X, LIST_Y, LIST_W, LIST_H); }
static RECT BtnRect() { return RectOf(BTN_X, BTN_Y, BTN_W, BTN_H); }
static int MaxListScroll()
{
int visible = LIST_H / ITEM_H;
return max(0, (int)g_modNames.size() - visible);
}
static int MeasureDescHeight(HDC hdc, const std::string& text, int width)
{
if (text.empty()) return 0;
RECT r = { 0, 0, width, 32000 };
HFONT old = (HFONT)SelectObject(hdc, g_hFont);
DrawTextA(hdc, text.c_str(), -1, &r, DT_WORDBREAK | DT_CALCRECT);
SelectObject(hdc, old);
return r.bottom;
}
// ---------------------------------------------------------------------------
// GDI drawing primitives
// ---------------------------------------------------------------------------
static void FillRoundRect(HDC hdc, RECT r, int rx, COLORREF fill, COLORREF border)
{
HBRUSH br = CreateSolidBrush(fill);
HPEN pen = CreatePen(PS_SOLID, 1, border);
HBRUSH ob = (HBRUSH)SelectObject(hdc, br);
HPEN op = (HPEN)SelectObject(hdc, pen);
RoundRect(hdc, r.left, r.top, r.right, r.bottom, rx, rx);
SelectObject(hdc, ob); DeleteObject(br);
SelectObject(hdc, op); DeleteObject(pen);
}
static void GdiText(HDC hdc, const std::string& s, RECT r, COLORREF col,
HFONT font, UINT flags = DT_SINGLELINE | DT_VCENTER | DT_LEFT)
{
SetTextColor(hdc, col);
SetBkMode(hdc, TRANSPARENT);
HFONT old = (HFONT)SelectObject(hdc, font);
DrawTextA(hdc, s.c_str(), -1, &r, flags);
SelectObject(hdc, old);
}
static void HLine(HDC hdc, int x0, int x1, int y, COLORREF col)
{
HPEN pen = CreatePen(PS_SOLID, 1, col);
HPEN old = (HPEN)SelectObject(hdc, pen);
MoveToEx(hdc, x0, y, nullptr);
LineTo(hdc, x1, y);
SelectObject(hdc, old);
DeleteObject(pen);
}
// ---------------------------------------------------------------------------
// Paint
// ---------------------------------------------------------------------------
static void Paint(HWND hWnd)
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
RECT rcClient;
GetClientRect(hWnd, &rcClient);
HDC mem = CreateCompatibleDC(hdc);
HBITMAP bmp = CreateCompatibleBitmap(hdc, rcClient.right, rcClient.bottom);
HBITMAP obmp = (HBITMAP)SelectObject(mem, bmp);
FillRect(mem, &rcClient, g_hBackBrush);
// -----------------------------------------------------------------------
// List panel
// -----------------------------------------------------------------------
RECT listRect = ListRect();
FillRoundRect(mem,
{ listRect.left - 1, listRect.top - 1, listRect.right + 1, listRect.bottom + 1 },
4, MC_DARK_GRY, MC_BORDER);
HRGN listClip = CreateRectRgn(listRect.left, listRect.top,
listRect.right, listRect.bottom);
SelectClipRgn(mem, listClip);
if (g_modNames.empty())
{
GdiText(mem, "No mods installed", listRect, MC_LIGHT_GRY, g_hFont,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
else
{
int visible = LIST_H / ITEM_H;
for (int i = g_listScroll; i < g_listScroll + visible + 1; ++i)
{
if (i >= (int)g_modNames.size()) break;
int drawY = LIST_Y + (i - g_listScroll) * ITEM_H;
RECT ir = { LIST_X, drawY, LIST_X + LIST_W, drawY + ITEM_H };
bool sel = (i == g_selIdx);
HBRUSH ibr = CreateSolidBrush(sel ? MC_SEL_BLU : MC_DARK_GRY);
FillRect(mem, &ir, ibr);
DeleteObject(ibr);
if (i > g_listScroll)
HLine(mem, LIST_X, LIST_X + LIST_W, drawY, MC_BORDER);
RECT tr = ir;
tr.left += 8;
GdiText(mem, g_modNames[i], tr, sel ? MC_WHITE : MC_LIGHT_GRY, g_hFont);
}
}
SelectClipRgn(mem, nullptr);
DeleteObject(listClip);
if (MaxListScroll() > 0)
{
int total = (int)g_modNames.size();
int visible = LIST_H / ITEM_H;
int thumbH = max(20, (int)(((float)visible / total) * LIST_H));
int thumbY = LIST_Y + (int)(((float)g_listScroll / (total - visible)) * (LIST_H - thumbH));
RECT sb = { LIST_X + LIST_W - 6, thumbY,
LIST_X + LIST_W - 2, thumbY + thumbH };
HBRUSH sbr = CreateSolidBrush(MC_SCROLLBAR);
FillRect(mem, &sb, sbr);
DeleteObject(sbr);
}
// -----------------------------------------------------------------------
// Info panel rows
// -----------------------------------------------------------------------
int iy = 20;
auto DrawRow = [&](const std::string& label, const std::string& value)
{
RECT lr = { INFO_X, iy, INFO_X + 75, iy + 24 };
RECT vr = { INFO_X + 78, iy, INFO_X + INFO_W, iy + 24 };
GdiText(mem, label, lr, MC_LIGHT_GRY, g_hFontBold);
GdiText(mem, value, vr, MC_WHITE, g_hFont,
DT_SINGLELINE | DT_VCENTER | DT_LEFT | DT_END_ELLIPSIS);
iy += 30;
};
DrawRow("Name:", g_iName);
DrawRow("ID:", g_iId);
DrawRow("Author:", g_iAuthor);
DrawRow("Version:", g_iVersion);
RECT dlr = { INFO_X, iy, INFO_X + 200, iy + 22 };
GdiText(mem, "Description:", dlr, MC_LIGHT_GRY, g_hFontBold);
iy += 26;
int descBoxH = BTN_Y - 10 - iy;
RECT descBox = { INFO_X, iy, INFO_X + INFO_W, iy + descBoxH };
FillRoundRect(mem, descBox, 4, MC_MID_GRY, MC_BORDER);
int descInnerW = INFO_W - 14;
RECT descTextR = { descBox.left + 6,
descBox.top + 4 - g_descScroll,
descBox.left + 6 + descInnerW,
descBox.top + 4 - g_descScroll + 32000 };
HRGN descClip = CreateRectRgn(descBox.left + 2, descBox.top + 2,
descBox.right - 2, descBox.bottom - 2);
SelectClipRgn(mem, descClip);
if (!g_iDesc.empty())
{
SetTextColor(mem, MC_LIGHT_GRY);
SetBkMode(mem, TRANSPARENT);
HFONT of = (HFONT)SelectObject(mem, g_hFont);
DrawTextA(mem, g_iDesc.c_str(), -1, &descTextR, DT_WORDBREAK | DT_LEFT);
SelectObject(mem, of);
}
SelectClipRgn(mem, nullptr);
DeleteObject(descClip);
if (g_descTextH > descBoxH)
{
int maxDs = g_descTextH - descBoxH;
int thumbH = max(20, (int)(((float)descBoxH / g_descTextH) * descBoxH));
int thumbY = descBox.top + (int)(((float)g_descScroll / maxDs) * (descBoxH - thumbH));
RECT dsb = { descBox.right - 6, thumbY,
descBox.right - 2, thumbY + thumbH };
HBRUSH dsbr = CreateSolidBrush(MC_SCROLLBAR);
FillRect(mem, &dsb, dsbr);
DeleteObject(dsbr);
}
// -----------------------------------------------------------------------
// Done button
// -----------------------------------------------------------------------
RECT btnR = BtnRect();
COLORREF bc = g_btnPress ? MC_PRESS : g_btnHover ? MC_HOVER : MC_SEL_BLU;
FillRoundRect(mem, btnR, 6, bc, MC_BORDER);
GdiText(mem, "Done", btnR, MC_WHITE, g_hFontBold,
DT_CENTER | DT_VCENTER | DT_SINGLELINE);
BitBlt(hdc, 0, 0, rcClient.right, rcClient.bottom, mem, 0, 0, SRCCOPY);
SelectObject(mem, obmp);
DeleteObject(bmp);
DeleteDC(mem);
EndPaint(hWnd, &ps);
}
// ---------------------------------------------------------------------------
// Window procedure
// ---------------------------------------------------------------------------
static LRESULT CALLBACK ModsWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) static LRESULT CALLBACK ModsWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
switch (msg) switch (msg)
{ {
case WM_COMMAND: // -----------------------------------------------------------------------
if (LOWORD(wParam) == IDC_CLOSE || LOWORD(wParam) == IDC_MINI_X) case WM_PAINT:
{ Paint(hWnd);
DestroyWindow(hWnd); return 0;
}
else if (LOWORD(wParam) == IDC_MODLIST && HIWORD(wParam) == LBN_SELCHANGE)
{
int sel = (int)SendMessage(g_hList, LB_GETCURSEL, 0, 0);
if (g_pScene && sel >= 0)
g_pScene->ShowModInfoInWindow(sel);
}
break;
case WM_MEASUREITEM:
{
LPMEASUREITEMSTRUCT lpmis = (LPMEASUREITEMSTRUCT)lParam;
if (lpmis->CtlID == IDC_MODLIST)
{
lpmis->itemHeight = 32;
return TRUE;
}
break;
}
case WM_DRAWITEM:
{
LPDRAWITEMSTRUCT lpdis = (LPDRAWITEMSTRUCT)lParam;
if (lpdis->CtlID == IDC_MODLIST && lpdis->itemID != (UINT)-1)
{
char text[256];
SendMessage(lpdis->hwndItem, LB_GETTEXT, lpdis->itemID, (LPARAM)text);
if (lpdis->itemState & ODS_SELECTED)
{
FillRect(lpdis->hDC, &lpdis->rcItem, g_hSelBrush);
SetTextColor(lpdis->hDC, RGB(255, 255, 255));
}
else
{
FillRect(lpdis->hDC, &lpdis->rcItem, g_hBackBrush);
SetTextColor(lpdis->hDC, MC_LIGHT_GRY);
}
SetBkMode(lpdis->hDC, TRANSPARENT);
RECT textRect = lpdis->rcItem;
textRect.left += 5;
DrawTextA(lpdis->hDC, text, -1, &textRect, DT_SINGLELINE | DT_VCENTER);
if (lpdis->itemState & ODS_FOCUS)
DrawFocusRect(lpdis->hDC, &lpdis->rcItem);
return TRUE;
}
break;
}
case WM_CTLCOLORSTATIC:
case WM_CTLCOLOREDIT:
{
HDC hdc = (HDC)wParam;
SetTextColor(hdc, MC_LIGHT_GRY);
SetBkColor(hdc, MC_DARK_GRY);
return (LRESULT)g_hBackBrush;
}
case WM_ERASEBKGND: case WM_ERASEBKGND:
{
RECT rc;
GetClientRect(hWnd, &rc);
FillRect((HDC)wParam, &rc, g_hBackBrush);
return 1; return 1;
}
case WM_DESTROY: // -----------------------------------------------------------------------
if (g_pScene) case WM_MOUSEMOVE:
g_pScene->m_bWindowClosed = true; {
if (!g_trackingMouse)
if (g_hSelBrush)
{ {
DeleteObject(g_hSelBrush); TRACKMOUSEEVENT tme = { sizeof(tme), TME_LEAVE, hWnd, 0 };
g_hSelBrush = nullptr; TrackMouseEvent(&tme);
g_trackingMouse = true;
} }
g_hModsWindow = nullptr; int mx = (short)LOWORD(lParam), my = (short)HIWORD(lParam);
g_hList = nullptr; RECT btnR = BtnRect();
bool prev = g_btnHover;
g_btnHover = (PtInRect(&btnR, { mx, my }) != 0);
if (prev != g_btnHover) Redraw();
return 0;
}
case WM_MOUSELEAVE:
g_trackingMouse = false;
if (g_btnHover) { g_btnHover = false; Redraw(); }
return 0;
case WM_LBUTTONDOWN:
{
int mx = (short)LOWORD(lParam), my = (short)HIWORD(lParam);
RECT listR = ListRect();
RECT btnR = BtnRect();
if (PtInRect(&listR, { mx, my }))
{
int row = (my - LIST_Y) / ITEM_H + g_listScroll;
if (row >= 0 && row < (int)g_modNames.size())
{
g_selIdx = row;
g_descScroll = 0;
if (g_pScene) g_pScene->ShowModInfoInWindow(row);
Redraw();
}
}
else if (PtInRect(&btnR, { mx, my }))
{
g_btnPress = true;
SetCapture(hWnd);
Redraw();
}
return 0;
}
case WM_LBUTTONUP:
{
int mx = (short)LOWORD(lParam), my = (short)HIWORD(lParam);
if (g_btnPress)
{
g_btnPress = false;
ReleaseCapture();
RECT btnR = BtnRect();
if (PtInRect(&btnR, { mx, my }))
{
DestroyWindow(hWnd);
return 0;
}
Redraw();
}
return 0;
}
case WM_MOUSEWHEEL:
{
POINT pt = { (short)LOWORD(lParam), (short)HIWORD(lParam) };
ScreenToClient(hWnd, &pt);
int delta = GET_WHEEL_DELTA_WPARAM(wParam) / WHEEL_DELTA;
RECT listR = ListRect();
if (PtInRect(&listR, pt))
{
g_listScroll -= delta;
g_listScroll = max(0, min(g_listScroll, MaxListScroll()));
Redraw();
return 0;
}
int iy = 20 + 4 * 30 + 26;
int descBoxH = BTN_Y - 10 - iy;
RECT descR = { INFO_X, iy, INFO_X + INFO_W, iy + descBoxH };
if (PtInRect(&descR, pt) && g_descTextH > descBoxH)
{
int maxDs = g_descTextH - descBoxH;
g_descScroll -= delta * 20;
g_descScroll = max(0, min(g_descScroll, maxDs));
Redraw();
}
return 0;
}
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
{
DestroyWindow(hWnd);
return 0;
}
if (wParam == VK_UP || wParam == VK_DOWN)
{
int next = g_selIdx + (wParam == VK_DOWN ? 1 : -1);
next = max(0, min(next, (int)g_modNames.size() - 1));
if (next != g_selIdx)
{
g_selIdx = next;
g_descScroll = 0;
if (g_selIdx < g_listScroll)
g_listScroll = g_selIdx;
else if (g_selIdx >= g_listScroll + LIST_H / ITEM_H)
g_listScroll = g_selIdx - LIST_H / ITEM_H + 1;
if (g_pScene) g_pScene->ShowModInfoInWindow(g_selIdx);
Redraw();
}
return 0;
}
break;
case WM_DESTROY:
if (g_pScene) g_pScene->m_bWindowClosed = true;
g_hWnd = nullptr;
break; break;
} }
return DefWindowProc(hWnd, msg, wParam, lParam); return DefWindowProc(hWnd, msg, wParam, lParam);
} }
// ---------------------------------------------------------------------------
// Window creation
// ---------------------------------------------------------------------------
static void CreateModsWindow(UIScene_ModsMenu* pScene) static void CreateModsWindow(UIScene_ModsMenu* pScene)
{ {
if (g_hModsWindow) return; if (g_hWnd) return;
g_pScene = pScene; g_pScene = pScene;
if (!g_hBackBrush) g_hBackBrush = CreateSolidBrush(MC_DARK_GRY); g_selIdx = -1;
if (!g_hSelBrush) g_hSelBrush = CreateSolidBrush(MC_SEL_BLU); g_listScroll = 0;
g_descScroll = 0;
g_descTextH = 0;
g_iName = g_iId = g_iAuthor = g_iVersion = g_iDesc = "";
g_btnHover = g_btnPress = false;
g_trackingMouse = false;
if (!g_hBackBrush)
g_hBackBrush = CreateSolidBrush(MC_DARK_GRY);
if (!g_hFont)
g_hFont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Segoe UI");
if (!g_hFontBold)
g_hFontBold = CreateFont(16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
CLEARTYPE_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "Segoe UI");
WNDCLASSEX wc = { sizeof(WNDCLASSEX) }; WNDCLASSEX wc = { sizeof(WNDCLASSEX) };
if (!GetClassInfoEx(GetModuleHandle(nullptr), "ModsMenuWindow", &wc)) if (!GetClassInfoEx(GetModuleHandle(nullptr), "ModsMenuWindow", &wc))
{ {
wc.lpfnWndProc = ModsWndProc; wc.lpfnWndProc = ModsWndProc;
wc.hInstance = GetModuleHandle(nullptr); wc.hInstance = GetModuleHandle(nullptr);
wc.hbrBackground = g_hBackBrush; wc.hbrBackground = nullptr;
wc.lpszClassName = "ModsMenuWindow"; wc.lpszClassName = "ModsMenuWindow";
wc.hCursor = LoadCursor(nullptr, IDC_ARROW); wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
RegisterClassEx(&wc); RegisterClassEx(&wc);
@ -143,72 +466,38 @@ static void CreateModsWindow(UIScene_ModsMenu* pScene)
HWND hParent = GetActiveWindow(); HWND hParent = GetActiveWindow();
LONG style = GetWindowLong(hParent, GWL_STYLE); LONG style = GetWindowLong(hParent, GWL_STYLE);
if (!(style & WS_CLIPCHILDREN)) SetWindowLong(hParent, GWL_STYLE, style | WS_CLIPCHILDREN); if (!(style & WS_CLIPCHILDREN))
SetWindowLong(hParent, GWL_STYLE, style | WS_CLIPCHILDREN);
RECT rcParent; RECT rcParent;
GetClientRect(hParent, &rcParent); GetClientRect(hParent, &rcParent);
int sw = rcParent.right - rcParent.left; int wx = (rcParent.right - WW) / 2;
int sh = rcParent.bottom - rcParent.top; int wy = (rcParent.bottom - WH) / 2;
int ww = 1200, wh = 600; g_hWnd = CreateWindowEx(
int wx = (sw - ww) / 2; WS_EX_NOPARENTNOTIFY,
int wy = (sh - 520) / 2;
g_hModsWindow = CreateWindowEx(
WS_EX_NOPARENTNOTIFY | WS_EX_CONTROLPARENT,
"ModsMenuWindow", nullptr, "ModsMenuWindow", nullptr,
WS_CHILD | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS, WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS,
wx, wy, ww, wh, wx, wy, WW, WH,
hParent, hParent, nullptr, GetModuleHandle(nullptr), nullptr
nullptr, GetModuleHandle(nullptr), nullptr
);
auto CreateLabel = [](const char* txt, int x, int y, int w, int id = -1) {
return CreateWindow("STATIC", txt, WS_CHILD | WS_VISIBLE, x, y, w, 20, g_hModsWindow, (HMENU)id, nullptr, nullptr);
};
g_hList = CreateWindow(
"LISTBOX", nullptr,
WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | LBS_NOTIFY | LBS_HASSTRINGS | LBS_OWNERDRAWFIXED,
20, 20, 300, 480,
g_hModsWindow, (HMENU)IDC_MODLIST, GetModuleHandle(nullptr), nullptr
);
CreateLabel("Name:", 340, 20, 60);
CreateLabel("", 410, 20, 400, IDC_MOD_NAME);
CreateLabel("ID:", 340, 50, 60);
CreateLabel("", 410, 50, 400, IDC_MOD_ID);
CreateLabel("Author:", 340, 80, 60);
CreateLabel("", 410, 80, 400, IDC_MOD_AUTHOR);
CreateLabel("Version:", 340, 110, 60);
CreateLabel("", 410, 110, 400, IDC_MOD_VERSION);
CreateLabel("Description:", 340, 140, 100);
CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_MULTILINE | ES_READONLY | WS_VSCROLL,
340, 165, 480, 335, g_hModsWindow, (HMENU)IDC_MOD_DESC, nullptr, nullptr);
CreateWindow("BUTTON", "Done",
WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
340, 520, 200, 40,
g_hModsWindow, (HMENU)IDC_CLOSE, GetModuleHandle(nullptr), nullptr
); );
SetFocus(g_hWnd);
g_modNames.clear();
const auto& mods = ModLoader::Get().GetMods(); const auto& mods = ModLoader::Get().GetMods();
for (int i = 0; i < (int)mods.size(); ++i) for (const auto& m : mods)
{ {
if (!mods[i].instance) continue; if (!m.instance) continue;
std::string displayName = mods[i].instance->GetInfo()->name; std::string name = m.instance->GetInfo()->name;
if (!mods[i].healthy) displayName += " (disabled)"; if (!m.healthy) name += " (disabled)";
SendMessageA(g_hList, LB_ADDSTRING, 0, (LPARAM)displayName.c_str()); g_modNames.push_back(name);
}
if (SendMessage(g_hList, LB_GETCOUNT, 0, 0) == 0)
{
SendMessageA(g_hList, LB_ADDSTRING, 0, (LPARAM)"No mods installed");
} }
} }
// ---------------------------------------------------------------------------
// UIScene_ModsMenu implementation
// ---------------------------------------------------------------------------
UIScene_ModsMenu::UIScene_ModsMenu(int iPad, void* initData, UILayer* parentLayer) UIScene_ModsMenu::UIScene_ModsMenu(int iPad, void* initData, UILayer* parentLayer)
: UIScene(iPad, parentLayer) : UIScene(iPad, parentLayer)
, m_selectedIndex(-1) , m_selectedIndex(-1)
@ -219,31 +508,26 @@ UIScene_ModsMenu::UIScene_ModsMenu(int iPad, void* initData, UILayer* parentLaye
UIScene_ModsMenu::~UIScene_ModsMenu() UIScene_ModsMenu::~UIScene_ModsMenu()
{ {
if (g_hModsWindow) if (g_hWnd)
{ {
DestroyWindow(g_hModsWindow); DestroyWindow(g_hWnd);
g_hModsWindow = nullptr; g_hWnd = nullptr;
} }
} }
wstring UIScene_ModsMenu::getMoviePath() wstring UIScene_ModsMenu::getMoviePath() { return L""; }
{
return L"";
}
void UIScene_ModsMenu::handleGainFocus(bool navBack) void UIScene_ModsMenu::handleGainFocus(bool navBack) {}
{
}
void UIScene_ModsMenu::tick() void UIScene_ModsMenu::tick()
{ {
m_hasTickedOnce = true; m_hasTickedOnce = true;
m_bCanHandleInput = true; m_bCanHandleInput = true;
if (g_hModsWindow && IsWindow(g_hModsWindow)) if (g_hWnd && IsWindow(g_hWnd))
{ {
MSG msg; MSG msg;
while (PeekMessage(&msg, g_hModsWindow, 0, 0, PM_REMOVE)) while (PeekMessage(&msg, g_hWnd, 0, 0, PM_REMOVE))
{ {
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
@ -257,13 +541,14 @@ void UIScene_ModsMenu::tick()
} }
} }
void UIScene_ModsMenu::handleInput(int iPad, int key, bool repeat, bool pressed, bool released, bool& handled) void UIScene_ModsMenu::handleInput(int iPad, int key, bool repeat,
bool pressed, bool released, bool& handled)
{ {
if (g_hModsWindow && IsWindow(g_hModsWindow)) handled = true; if (g_hWnd && IsWindow(g_hWnd)) handled = true;
if (key == ACTION_MENU_CANCEL && pressed && m_hasTickedOnce) if (key == ACTION_MENU_CANCEL && pressed && m_hasTickedOnce)
{ {
if (g_hModsWindow) DestroyWindow(g_hModsWindow); if (g_hWnd) DestroyWindow(g_hWnd);
} }
} }
@ -271,23 +556,31 @@ void UIScene_ModsMenu::handlePress(F64 controlId, F64 childId) {}
void UIScene_ModsMenu::ShowModInfoInWindow(int index) void UIScene_ModsMenu::ShowModInfoInWindow(int index)
{ {
if (!g_hModsWindow) return; if (!g_hWnd) return;
const auto& mods = ModLoader::Get().GetMods(); const auto& mods = ModLoader::Get().GetMods();
if (index < 0 || index >= (int)mods.size() || !mods[index].instance) return; if (index < 0 || index >= (int)mods.size() || !mods[index].instance) return;
const ModInfo* info = mods[index].instance->GetInfo(); const ModInfo* info = mods[index].instance->GetInfo();
SetWindowTextA(GetDlgItem(g_hModsWindow, IDC_MOD_NAME), info->name ? info->name : ""); g_iName = info->name ? info->name : "";
SetWindowTextA(GetDlgItem(g_hModsWindow, IDC_MOD_ID), info->id ? info->id : ""); g_iId = info->id ? info->id : "";
SetWindowTextA(GetDlgItem(g_hModsWindow, IDC_MOD_AUTHOR), info->author ? info->author : ""); g_iAuthor = info->author ? info->author : "";
g_iVersion = std::to_string(info->version.major) + "." +
std::to_string(info->version.minor) + "." +
std::to_string(info->version.patch);
g_iDesc = info->description ? info->description : "";
if (!mods[index].healthy)
g_iDesc += "\r\n[This mod has been disabled due to an error.]";
std::string ver = std::to_string(info->version.major) + "." + std::to_string(info->version.minor) + "." + std::to_string(info->version.patch); g_descScroll = 0;
SetWindowTextA(GetDlgItem(g_hModsWindow, IDC_MOD_VERSION), ver.c_str());
std::string desc = info->description ? info->description : ""; HDC hdc = GetDC(g_hWnd);
if (!mods[index].healthy) desc += "\r\n[This mod has been disabled due to an error.]"; int descInnerW = INFO_W - 14;
SetWindowTextA(GetDlgItem(g_hModsWindow, IDC_MOD_DESC), desc.c_str()); g_descTextH = MeasureDescHeight(hdc, g_iDesc, descInnerW);
ReleaseDC(g_hWnd, hdc);
Redraw();
} }
void UIScene_ModsMenu::PopulateModList() {} void UIScene_ModsMenu::PopulateModList() {}

Binary file not shown.

Binary file not shown.

View file

@ -1,5 +1,4 @@
 SDK.cpp  UIScene_ModsMenu.cpp
ServerLevel.cpp
Microsoft (R) Incremental Linker Version 14.44.35222.0 Microsoft (R) Incremental Linker Version 14.44.35222.0
Copyright (C) Microsoft Corporation. All rights reserved. Copyright (C) Microsoft Corporation. All rights reserved.
"/OUT:S:\GitHub\Faucet\x64\Debug\Faucet.exe" /INCREMENTAL "/ILK:x64\Debug\Faucet.ilk" d3d11.lib ..\Minecraft.World\x64_Debug\Minecraft.World.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib XInput9_1_0.lib ..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib wsock32.lib /MANIFEST "/MANIFESTUAC:level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG "/PDB:S:\GitHub\Faucet\x64\Debug\Minecraft.Client.pdb" /TLBID:1 /DYNAMICBASE /NXCOMPAT "/IMPLIB:S:\GitHub\Faucet\x64\Debug\Faucet.lib" /MACHINE:X64 x64\Debug\MinecraftWindows.res "/OUT:S:\GitHub\Faucet\x64\Debug\Faucet.exe" /INCREMENTAL "/ILK:x64\Debug\Faucet.ilk" d3d11.lib ..\Minecraft.World\x64_Debug\Minecraft.World.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib XInput9_1_0.lib ..\Minecraft.Client\Windows64\Miles\Lib\mss64.lib wsock32.lib /MANIFEST "/MANIFESTUAC:level='asInvoker' uiAccess='false'" /manifest:embed /DEBUG "/PDB:S:\GitHub\Faucet\x64\Debug\Minecraft.Client.pdb" /TLBID:1 /DYNAMICBASE /NXCOMPAT "/IMPLIB:S:\GitHub\Faucet\x64\Debug\Faucet.lib" /MACHINE:X64 x64\Debug\MinecraftWindows.res

Binary file not shown.

Binary file not shown.

View file

@ -1,10 +1,3 @@
[15:49:36] === Faucet ModLoader starting === [16:46:29] === Faucet ModLoader starting ===
[15:49:36] Found 0 mod(s) to load [16:46:29] Found 0 mod(s) to load
[15:49:36] Initialization complete — 0 loaded, 0 failed, 181ms total [16:46:29] Initialization complete — 0 loaded, 0 failed, 116ms total
[15:49:57] Level loaded
[15:49:57] Level loaded
[15:49:57] Level loaded
[15:50:28] Level unloaded
[15:50:28] Level unloaded
[15:50:28] Level unloaded
[15:50:28] Shutting down ModLoader