From 8bd64534154a0c4b1925ca177aecbe1dff003cba Mon Sep 17 00:00:00 2001 From: Chen Peng Date: Tue, 28 Jul 2026 23:35:51 +0800 Subject: [PATCH] =?UTF-8?q?Toast=E6=BC=94=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CMakeLists.txt | 1 + GUITest/FontStr.c | 106 +++++++++++++++++++++++++ GUITest/FontStr.h | 21 +++++ GUITest/FontsExp.h | 12 +++ GUITest/FontsExp.rc | 6 ++ GUITest/FontsExp.t.c | 184 ++++++++++++++++++++++++++++++++++++++++++- c_WinGUI.h | 8 ++ c_WinUI_Toast.c | 112 ++++++++++++++++++++++++++ c_WinUI_Toast.h | 14 ++++ 9 files changed, 460 insertions(+), 4 deletions(-) create mode 100644 GUITest/FontStr.c create mode 100644 GUITest/FontStr.h create mode 100644 GUITest/FontsExp.h create mode 100644 GUITest/FontsExp.rc create mode 100644 c_WinUI_Toast.c create mode 100644 c_WinUI_Toast.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 50af47f..b8f5724 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,3 +32,4 @@ endforeach () target_sources(Resource.t PRIVATE GUITest/Resource.rc) target_sources(Snake.t PRIVATE GUITest/Snake.rc) target_sources(SimpFont.t PRIVATE GUITest/SimpFont.rc) +target_sources(FontsExp.t PRIVATE GUITest/FontsExp.rc GUITest/FontStr.c) diff --git a/GUITest/FontStr.c b/GUITest/FontStr.c new file mode 100644 index 0000000..c602b2c --- /dev/null +++ b/GUITest/FontStr.c @@ -0,0 +1,106 @@ +#include +#include + +static char TheFaceName[80]; + +char* GetType(char* s, TEXTMETRIC TextMetrics) { + if (!s) return NULL; + strcpy(s, "Font Type:"); + if ((TextMetrics.tmAveCharWidth & TMPF_FIXED_PITCH)==TMPF_FIXED_PITCH) { + strcat(s, "Fixed<>"); + } + if ((TextMetrics.tmAveCharWidth & TMPF_VECTOR)==TMPF_VECTOR) { + strcat(s, "Vector<>"); + } + if ((TextMetrics.tmAveCharWidth & TMPF_TRUETYPE)==TMPF_TRUETYPE) { + strcat(s, "TrueType<>"); + } + if ((TextMetrics.tmAveCharWidth & TMPF_DEVICE)==TMPF_DEVICE) { + strcat(s, "Device<>"); + } + if (strlen(s) > 11) { + int len = strlen(s); + s[len - 3]='\0'; + } + return s; +} + +char* GetFamily(char* s, TEXTMETRIC TextMetrics) { + int R = TextMetrics.tmPitchAndFamily & 0xF0; + strcpy(s, "Family:"); + if (R==FF_DONTCARE) { + strcat(s, "Don't Care or don't know"); + } + if (R==FF_ROMAN) { + strcat(s, "Roman"); + } + if (R==FF_SWISS) { + strcat(s, "Swiss"); + } + if (R==FF_MODERN) { + strcat(s, "Modern"); + } + if (R==FF_SCRIPT) { + strcat(s, "Script"); + } + if (R==FF_DECORATIVE) { + strcat(s, "Decorative"); + } + return s; +} + +char* GetCharSet(char* s, TEXTMETRIC TextMetrics) { + strcpy(s, "Char Set:"); + if (TextMetrics.tmCharSet==ANSI_CHARSET) { + strcat(s, "Ansi"); + } + if (TextMetrics.tmCharSet==DEFAULT_CHARSET) { + strcat(s, "Default"); + } + if (TextMetrics.tmCharSet==SYMBOL_CHARSET) { + strcat(s, "Symbol"); + } + if (TextMetrics.tmCharSet==OEM_CHARSET) { + strcat(s, "OEM"); + } + return s; +} + +char* GetFontString(char* s, int s_len, TEXTMETRIC TextMetric, char* FaceName) { + if (!s || !FaceName) { + return NULL; + } + + char szType[99]; + char szFamily[99]; + char szCharSet[99]; + + GetType(szType, TextMetric); + GetFamily(szFamily, TextMetric); + GetCharSet(szCharSet, TextMetric); + + snprintf(s, s_len, "Font: %s\n" + "Height: %d\n" + "Ascent: %d\n" + "Descent: %d\n" + "AveCharW: %d\n" + "MaxCharW: %d\n" + "Weight: %d\n" + "Italic: %hd\n" + "Underlined: %d\n" + "%s\n" + "%s\n" + "%s", + FaceName, + TextMetric.tmHeight, + TextMetric.tmAscent, + TextMetric.tmDescent, + TextMetric.tmAveCharWidth, + TextMetric.tmMaxCharWidth, + TextMetric.tmWeight, + TextMetric.tmItalic, + TextMetric.tmUnderlined, + szType, szFamily, szCharSet + ); + return s; +} diff --git a/GUITest/FontStr.h b/GUITest/FontStr.h new file mode 100644 index 0000000..21a1eaf --- /dev/null +++ b/GUITest/FontStr.h @@ -0,0 +1,21 @@ +#ifndef INCLUDED_FONTSTR_H +#define INCLUDED_FONTSTR_H + +#ifndef INCLUDED_WINDOWS_H +#define INCLUDED_WINDOWS_H +#include +#endif /*INCLUDED_WINDOWS_H*/ + +#ifndef INCLUDED_STRING_H +#define INCLUDED_STRING_H +#include +#endif /*INCLUDED_STRING_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + + +char* GetFontString(char* s, int s_len, TEXTMETRIC TextMetric, char* FaceName); + +#endif /*INCLUDED_FONTSTR_H*/ diff --git a/GUITest/FontsExp.h b/GUITest/FontsExp.h new file mode 100644 index 0000000..a85323e --- /dev/null +++ b/GUITest/FontsExp.h @@ -0,0 +1,12 @@ +#ifndef INCLUDED_FONTSEXP_H +#define INCLUDED_FONTSEXP_H + +#define WM_STARTFONTS (WM_USER +0) +#define WM_NEWFONT (WM_USER +1) + +#define ID_LISTBOX 1 +#define CM_INFO 101 + + + +#endif /*INCLUDED_FONTSEXP_H*/ diff --git a/GUITest/FontsExp.rc b/GUITest/FontsExp.rc new file mode 100644 index 0000000..556913e --- /dev/null +++ b/GUITest/FontsExp.rc @@ -0,0 +1,6 @@ +#include "FontsExp.h" + +Menu MENU +BEGIN + MENUITEM "&Info", CM_INFO +END diff --git a/GUITest/FontsExp.t.c b/GUITest/FontsExp.t.c index 509aca4..3b9aaef 100644 --- a/GUITest/FontsExp.t.c +++ b/GUITest/FontsExp.t.c @@ -1,21 +1,198 @@ +#include + #include "c_WinApp.h" +#include "FontsExp.h" +#include "FontStr.h" +#include "c_WinUI_Toast.h" +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +typedef struct { + int Count; + HWND hWindow; +}ENUMSTRUCT; /* ------------------------------------------------------------------------------------------------------------------ */ /* */ -#define WINDOW_CLASS_NAME "WinGUI.Main" +static TEXTMETRIC TextMetrics; +static char aTextFace[80]; + +static HFONT TheFont; +static LPLOGFONT TheLogFont; + +static HWND hFontList; +static HWND hAlphaEdit; +static HWND hTrueType; +static HWND hNumFonts; +static HWND hFontName; +static HWND ButtonWindows[3]; + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +#define WINDOW_CLASS_NAME "FontsExp.Main" + + +static +int CALLBACK DescribeFontCallback(LPENUMLOGFONT lpnlf, LPNEWTEXTMETRIC lpntm, int FontType, ENUMSTRUCT FAR * lpData); + + +static void HandleMetrics(TEXTMETRIC TextMetrics) { + if ((TextMetrics.tmPitchAndFamily & TMPF_TRUETYPE) == TMPF_TRUETYPE) { + SendMessage(ButtonWindows[0], BM_SETCHECK, 1, 0); + }else { + SendMessage(ButtonWindows[0], BM_SETCHECK, 0, 0); + } + + if ((TextMetrics.tmWeight > 600)) { + SendMessage(ButtonWindows[1], BM_SETCHECK, 1, 0); + }else { + SendMessage(ButtonWindows[1], BM_SETCHECK, 0, 0); + } + + if ((TextMetrics.tmItalic)) { + SendMessage(ButtonWindows[2], BM_SETCHECK, 1, 0); + }else { + SendMessage(ButtonWindows[2], BM_SETCHECK, 0, 0); + } + +} + +static void ShowTheFont(HWND hwnd) { + // FONTENUMPROC lpfnEnumProc; + ENUMSTRUCT EnumStruct; + char lpszBuffer[150]; + HFONT SaveIt; + char* Alpha="1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; + HDC DC = GetDC(hwnd); + + LRESULT Index = SendMessage(hFontList, LB_GETCURSEL, 0, 0); + SendMessage(hFontList, LB_GETTEXT, (WPARAM)Index, (LPARAM)(lpszBuffer)); + // lpfnEnumProc = (FONTENUMPROC)MakeProcInstance((FARPROC)DescribeFontCallback, WinApp.hInstance); + EnumStruct.Count = 0; + EnumStruct.hWindow = hwnd; + // EnumFontFamilies(DC, lpszBuffer, lpfnEnumProc, (LONG)&EnumStruct); + EnumFontFamilies(DC, lpszBuffer, (FONTENUMPROC)DescribeFontCallback, (LPARAM)&EnumStruct); + if (TheFont) { + SaveIt = SelectFont(DC, TheFont); + } + GetTextMetrics(DC, &TextMetrics); + HandleMetrics(TextMetrics); + GetTextFace(DC, 150, aTextFace); + if (TheFont) { + SelectFont(DC, SaveIt); + } + ReleaseDC(hwnd, DC); + SendMessage(hFontName, WM_SETTEXT, 0, (LPARAM)&lpszBuffer); + SendMessage(hFontName, WM_SETFONT, (WPARAM)TheFont, 0); + + SendMessage(hAlphaEdit, WM_SETTEXT, 0, (LPARAM)Alpha); + SendMessage(hAlphaEdit, WM_SETFONT, (WPARAM)TheFont, 0); + + c_WinUI_Toast_Show(WinApp.hInstance, TEXT("ѡ"), lpszBuffer, 2000); +} + +static +BOOL CALLBACK FontCallback(const LOGFONT * lpelf, const TEXTMETRIC* lpntm, DWORD FontType, ENUMSTRUCT FAR * lpData) { + SendMessage(lpData->hWindow, LB_ADDSTRING, 0, (LPARAM)lpelf->lfFaceName); + lpData->Count++; + return 1; +} + +static +int CALLBACK DescribeFontCallback(LPENUMLOGFONT lpnlf, LPNEWTEXTMETRIC lpntm, int FontType, ENUMSTRUCT FAR * lpData) { + SendMessage(lpData->hWindow, WM_NEWFONT, 0, (LPARAM)&lpnlf->elfLogFont); + return 1; +} c_WinGUI_EventHandlerDef(WM_DESTROY, Main_Destroy) { + if (TheFont) { + DeleteObject(TheFont); + } PostQuitMessage(0); } c_WinGUI_EventHandlerDef(WM_CREATE, Main_Create) { + static char* Titles[] = {"TrueType", "Heavy", "Italic"}; + hFontList = CreateWindow("listbox", NULL, WS_CHILD | WS_VISIBLE | LBS_STANDARD, + 9, 30, 201, 180, + hwnd, (HMENU)(ID_LISTBOX), WinApp.hInstance, NULL); + hNumFonts = CreateWindow("static", NULL, + WS_CHILD | WS_VISIBLE | WS_BORDER, + 10, 10, 200, 20, + hwnd, (HMENU)(-1), WinApp.hInstance, NULL); + hFontName = CreateWindow("edit", NULL, + WS_CHILD | ES_LEFT | WS_VISIBLE | WS_BORDER | ES_READONLY, + 260, 10, 850, 70, + hwnd, (HMENU)(-1), WinApp.hInstance, NULL); + hAlphaEdit = CreateWindow("edit", NULL, + WS_CHILD | ES_LEFT | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL | ES_MULTILINE | WS_HSCROLL , + 260, 90, 850, 70, + hwnd, (HMENU)(-1), WinApp.hInstance, NULL); + for (int i=0; i<3; i++) { + ButtonWindows[i] = CreateWindow("button", Titles[i], + WS_CHILD|WS_VISIBLE|BS_CHECKBOX, + 260 + (i*125), 180, 100, 35, + hwnd, (HMENU)(-1), WinApp.hInstance, NULL); + } + TheFont = 0; + PostMessage(hwnd, WM_STARTFONTS, 0, 0); return TRUE; } +c_WinGUI_EventHandlerDef(WM_COMMAND, Main_Command) { + char s[500]; + switch (id) { + case ID_LISTBOX: { + if (codeNotify==LBN_SELCHANGE) { + ShowTheFont(hwnd); + } + break; + } + case CM_INFO: { + GetFontString(s, sizeof(s), TextMetrics, aTextFace); + MessageBox(hwnd, s, "Info", MB_OK); + break; + } + } +} + +c_WinGUI_EventHandlerDef(WM_USERDEFINED, Main_StartFonts) { + char s[100]; + HDC DC = GetDC(hwnd); + // FONTENUMPROC lpfnEnumProc = (FONTENUMPROC) MakeProcInstance((FARPROC)FontCallback, WinApp.hInstance); + ENUMSTRUCT EnumStruct; + EnumStruct.Count = 0; + EnumStruct.hWindow = hFontList; + // EnumFontFamilies(DC, NULL, lpfnEnumProc, (LONG)&EnumStruct); + // FreeProcInstance(lpfnEnumProc); + EnumFontFamilies(DC, NULL, (FONTENUMPROC)FontCallback, (LPARAM)&EnumStruct); + ReleaseDC(hwnd, DC); + + snprintf(s, sizeof(s), "There are %d fonts available", EnumStruct.Count); + SetWindowText(hNumFonts, s); + SetFocus(hFontList); + SendMessage(hFontList, LB_SETCURSEL, 0, 0); + ShowTheFont(hwnd); + return 1; +} + +c_WinGUI_EventHandlerDef(WM_USERDEFINED, Main_NewFont) { + if (TheFont) { + DeleteObject(TheFont); + } + TheLogFont = (LPLOGFONT) lParam; + TheFont = CreateFontIndirect(TheLogFont); + return 1; +} + c_WinGUI_EventMapBegin(WndProc) c_WinGUI_EventMap(WM_DESTROY, Main_Destroy); -c_WinGUI_EventMap(WM_CREATE, Main_Create); + c_WinGUI_EventMap(WM_CREATE, Main_Create); + c_WinGUI_EventMap(WM_COMMAND, Main_Command); + c_WinGUI_UDEventMap(WM_STARTFONTS, Main_StartFonts); + c_WinGUI_UDEventMap(WM_NEWFONT, Main_NewFont); c_WinGUI_EventMapEnd() @@ -30,7 +207,7 @@ BOOL Register(HINSTANCE hInstance) { WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION); WndClass.hCursor = LoadCursor(NULL, IDC_ARROW); WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - WndClass.lpszMenuName = NULL; + WndClass.lpszMenuName = "Menu"; WndClass.lpszClassName = WINDOW_CLASS_NAME; return RegisterClass(&WndClass); } @@ -67,7 +244,6 @@ c_WinGUI_Main(){ WinApp.hInstance = hInstance; - HWND MainHwnd = Create(hInstance, nShowCmd); if (!MainHwnd) { return FALSE; diff --git a/c_WinGUI.h b/c_WinGUI.h index 4ffec66..6e76120 100644 --- a/c_WinGUI.h +++ b/c_WinGUI.h @@ -427,6 +427,9 @@ #define c_WinGUI_EventFn_WM_HOTKEY(fn) \ void fn(HWND hwnd, int idHotKey, UINT fuModifiers, UINT vk) +#define c_WinGUI_EventFn_WM_USERDEFINED(fn) \ + LRESULT fn(HWND hwnd, WPARAM wParam, LPARAM lParam) + /* ------------------------------------------------------------------------------------------------------------------ */ /* */ @@ -437,6 +440,9 @@ static LRESULT CALLBACK fn(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam){ \ #define c_WinGUI_EventMap(message, fn) \ case message: return HANDLE_##message(hwnd, wParam, lParam, fn) +#define c_WinGUI_UDEventMap(message, fn) \ + case message: return fn(hwnd, wParam, lParam) + #define c_WinGUI_EventMapEnd() \ default: return DefWindowProc(hwnd, msg, wParam, lParam); \ } \ @@ -448,4 +454,6 @@ static c_WinGUI_EventFn_##message(fn) #define c_WinGUI_Main() \ int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd) + + #endif /*INCLUDED_C_WINGUI_H*/ diff --git a/c_WinUI_Toast.c b/c_WinUI_Toast.c new file mode 100644 index 0000000..8cfeb16 --- /dev/null +++ b/c_WinUI_Toast.c @@ -0,0 +1,112 @@ +#include +#include + +// 定义定时器 ID +#define TIMER_CLOSE_ID 1 + +// Toast 窗口的全局配置 +#define TOAST_WIDTH 320 +#define TOAST_HEIGHT 80 +#define MARGIN_RIGHT 20 +#define MARGIN_BOTTOM 60 + +#define WINDOW_CLASS_NAME "c_WinUI_Toast" + +#define PROP_KEY_TITLE "c_WinUI_Toast.Title" +#define PROP_KEY_MESSAGE "c_WinUI_Toast.Message" + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +c_WinGUI_EventHandlerDef(WM_PAINT, Toast_Paint) { + PAINTSTRUCT ps; + HDC hdc = BeginPaint(hwnd, &ps); + + char* title = GetProp(hwnd, PROP_KEY_TITLE); + char* message = GetProp(hwnd, PROP_KEY_MESSAGE); + + if (title && message) { + SetBkMode(hdc, TRANSPARENT); + SetTextColor(hdc, RGB(255, 255, 255)); + RECT rcTitle = {15, 12, TOAST_WIDTH-15, 35}; + DrawText(hdc, title, -1, &rcTitle, DT_LEFT|DT_TOP|DT_END_ELLIPSIS); + + SetTextColor(hdc, RGB(200, 200, 200)); + RECT rcMsg = {15, 38, TOAST_WIDTH-15, TOAST_HEIGHT-10}; + DrawText(hdc, message, -1, &rcMsg, DT_LEFT|DT_TOP|DT_WORDBREAK|DT_END_ELLIPSIS); + } + + EndPaint(hwnd, &ps); +} + +c_WinGUI_EventHandlerDef(WM_TIMER, Toast_Timer) { + if (id==TIMER_CLOSE_ID) { + KillTimer(hwnd, TIMER_CLOSE_ID); + AnimateWindow(hwnd, 300, AW_HIDE|AW_BLEND); + DestroyWindow(hwnd); + } +} + +c_WinGUI_EventHandlerDef(WM_LBUTTONDOWN, Toast_LButtonDown) { + PostMessage(hwnd, WM_TIMER, TIMER_CLOSE_ID, 0); +} + +c_WinGUI_EventHandlerDef(WM_DESTROY, Toast_Destroy) { + char* title = GetProp(hwnd, PROP_KEY_TITLE); + char* message = GetProp(hwnd, PROP_KEY_MESSAGE); + if (title){ free(title); } + if (message){ free(message); } + RemoveProp(hwnd, PROP_KEY_TITLE); + RemoveProp(hwnd, PROP_KEY_MESSAGE); +} + +c_WinGUI_EventMapBegin(WndProc) + c_WinGUI_EventMap(WM_DESTROY, Toast_Destroy); + c_WinGUI_EventMap(WM_TIMER, Toast_Timer); + c_WinGUI_EventMap(WM_LBUTTONDOWN, Toast_LButtonDown); + c_WinGUI_EventMap(WM_PAINT, Toast_Paint); + +c_WinGUI_EventMapEnd() + +void c_WinUI_Toast_Show(HINSTANCE hInst, const char* title, const char* message, UINT timeoutMs) { + if (!title || !message) { + return; + } + + WNDCLASS wc = {0}; + wc.lpfnWndProc = WndProc; + wc.hInstance = hInst; + wc.lpszClassName = WINDOW_CLASS_NAME; + wc.hbrBackground = CreateSolidBrush(RGB(32, 32, 32)); + // wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.hCursor = LoadCursor(NULL, IDC_ARROW); + RegisterClass(&wc); + + int screenWidth = GetSystemMetrics(SM_CXSCREEN); + int screenHeight = GetSystemMetrics(SM_CYSCREEN); + + int posX = screenWidth - TOAST_WIDTH - MARGIN_RIGHT; + int posY = screenHeight - TOAST_HEIGHT - MARGIN_BOTTOM; + + HWND hwnd = CreateWindowEx(WS_EX_TOPMOST | WS_EX_TOOLWINDOW, + WINDOW_CLASS_NAME, title, + WS_POPUP, + posX, posY, TOAST_WIDTH, TOAST_HEIGHT, + NULL, NULL, hInst, NULL); + + if (!hwnd) { + return; + } + char* p_title = strdup(title); + char* p_message = strdup(message); + + SetProp(hwnd, PROP_KEY_TITLE, p_title); + SetProp(hwnd, PROP_KEY_MESSAGE, p_message); + + SetTimer(hwnd, TIMER_CLOSE_ID, timeoutMs, NULL); + + AnimateWindow(hwnd, 200, AW_SLIDE | AW_VER_NEGATIVE | AW_ACTIVATE); + + InvalidateRect(hwnd, NULL, TRUE); // 标记整个窗口需要重绘 + UpdateWindow(hwnd); // 立即发送 WM_PAINT 消息 +} \ No newline at end of file diff --git a/c_WinUI_Toast.h b/c_WinUI_Toast.h new file mode 100644 index 0000000..6b29f99 --- /dev/null +++ b/c_WinUI_Toast.h @@ -0,0 +1,14 @@ +#ifndef INCLUDED_C_WINUI_TOAST_H +#define INCLUDED_C_WINUI_TOAST_H + +#ifndef INCLUDED_C_WINAPP_H +#include +#endif /*INCLUDED_C_WINAPP_H*/ + + +/* ------------------------------------------------------------------------------------------------------------------ */ +/* */ + +void c_WinUI_Toast_Show(HINSTANCE hInst, const char* title, const char* message, UINT timeoutMs); + +#endif /*INCLUDED_C_WINUI_TOAST_H*/