Advertisement
alien_fx_fiend

Analog Clock Win32 (MemDC + StatusBar) [*NEW FINAL*]

Jul 26th, 2024
116
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 8.54 KB | None | 0 0
  1. #include <windows.h>
  2. #include <time.h>
  3. #include <math.h>
  4. #include <stdio.h>
  5. #include <commctrl.h>
  6. #include <tchar.h>
  7. #include <strsafe.h>
  8. #pragma comment(lib, "Msimg32.lib")
  9. #pragma comment(lib, "comctl32.lib")
  10. #define ID_TIMER 1
  11. #define SIZE 425
  12. #define CLOCK_MARGIN 20
  13. #define ID_STATUSBAR 100
  14.  
  15. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  16. void DrawClock(HDC, int, int, int);
  17. void DrawHand(HDC, int, int, double, int, COLORREF, bool drawLineToCenter = true);
  18. void UpdateStatusBar(HWND, SYSTEMTIME);
  19.  
  20. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
  21.     static TCHAR szAppName[] = TEXT("My Clock");
  22.     HWND hwnd;
  23.     MSG msg;
  24.     WNDCLASS wndclass;
  25.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  26.     wndclass.lpfnWndProc = WndProc;
  27.     wndclass.cbClsExtra = 0;
  28.     wndclass.cbWndExtra = 0;
  29.     wndclass.hInstance = hInstance;
  30.     wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  31.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  32.     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  33.     wndclass.lpszMenuName = NULL;
  34.     wndclass.lpszClassName = szAppName;
  35.     if (!RegisterClass(&wndclass)) {
  36.         MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR);
  37.         return 0;
  38.     }
  39.     RECT rect = { 0, 0, SIZE + 2 * CLOCK_MARGIN, SIZE + 2 * CLOCK_MARGIN + 30 }; // Added 30 for status bar
  40.     AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
  41.     hwnd = CreateWindow(szAppName, TEXT("Time is Meaningless The Insurgency is Live & Well"),
  42.         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
  43.         rect.right - rect.left, rect.bottom - rect.top,
  44.         NULL, NULL, hInstance, NULL);
  45.  
  46.     ShowWindow(hwnd, iCmdShow);
  47.     UpdateWindow(hwnd);
  48.  
  49.     while (GetMessage(&msg, NULL, 0, 0)) {
  50.         TranslateMessage(&msg);
  51.         DispatchMessage(&msg);
  52.     }
  53.     return (int)msg.wParam;
  54. }
  55.  
  56. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  57.     static HWND hwndStatus;
  58.     static HBITMAP hBitmap;
  59.     static int cxClient, cyClient;
  60.     HDC hdc, memDC;
  61.     PAINTSTRUCT ps;
  62.     SYSTEMTIME st;
  63.     RECT rect;
  64.     int centerX, centerY;
  65.     switch (message) {
  66.     case WM_CREATE:
  67.         hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
  68.             WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
  69.             hwnd, (HMENU)ID_STATUSBAR, GetModuleHandle(NULL), NULL);
  70.         SetTimer(hwnd, ID_TIMER, 1000, NULL);
  71.         return 0;
  72.     case WM_SIZE:
  73.         cxClient = LOWORD(lParam);
  74.         cyClient = HIWORD(lParam);
  75.         if (hBitmap) {
  76.             DeleteObject(hBitmap);
  77.         }
  78.         hdc = GetDC(hwnd);
  79.         hBitmap = CreateCompatibleBitmap(hdc, cxClient, cyClient);
  80.         ReleaseDC(hwnd, hdc);
  81.         SendMessage(hwndStatus, WM_SIZE, 0, 0);
  82.         return 0;
  83.     case WM_PAINT:
  84.         hdc = BeginPaint(hwnd, &ps);
  85.         memDC = CreateCompatibleDC(hdc);
  86.         SelectObject(memDC, hBitmap);
  87.         GetClientRect(hwnd, &rect);
  88.         centerX = (rect.right - rect.left) / 2;
  89.         centerY = ((rect.bottom - rect.top) - 20) / 2; // Adjust for status bar
  90.         FillRect(memDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
  91.         DrawClock(memDC, centerX, centerY, min(centerX, centerY) - CLOCK_MARGIN);
  92.         BitBlt(hdc, 0, 0, cxClient, cyClient, memDC, 0, 0, SRCCOPY);
  93.         DeleteDC(memDC);
  94.         EndPaint(hwnd, &ps);
  95.         return 0;
  96.     case WM_TIMER:
  97.         GetLocalTime(&st);
  98.         UpdateStatusBar(hwndStatus, st);
  99.         InvalidateRect(hwnd, NULL, FALSE);
  100.         return 0;
  101.     case WM_DESTROY:
  102.         KillTimer(hwnd, ID_TIMER);
  103.         if (hBitmap) DeleteObject(hBitmap);
  104.         PostQuitMessage(0);
  105.         return 0;
  106.     }
  107.     return DefWindowProc(hwnd, message, wParam, lParam);
  108. }
  109.  
  110.  
  111. void DrawClock(HDC hdc, int x, int y, int r) {
  112.     SYSTEMTIME st;
  113.     GetLocalTime(&st);
  114.     HDC memDC = CreateCompatibleDC(hdc);
  115.     HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 2 * r, 2 * r);
  116.     SelectObject(memDC, hBitmap);
  117.     TRIVERTEX vertex[2];
  118.     vertex[0].x = 0;
  119.     vertex[0].y = 0;
  120.     vertex[0].Red = 0xc000;
  121.     vertex[0].Green = 0xc000;
  122.     vertex[0].Blue = 0xc000;
  123.     vertex[0].Alpha = 0x0000;
  124.     vertex[1].x = 2 * r;
  125.     vertex[1].y = 2 * r;
  126.     vertex[1].Red = 0x4000;
  127.     vertex[1].Green = 0x4000;
  128.     vertex[1].Blue = 0x4000;
  129.     vertex[1].Alpha = 0x0000;
  130.     GRADIENT_RECT gRect = { 0, 1 };
  131.     GradientFill(memDC, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H);
  132.     HPEN hPen = CreatePen(PS_SOLID, 8, RGB(128, 128, 128));
  133.     HPEN hOldPen = (HPEN)SelectObject(memDC, hPen);
  134.     Ellipse(memDC, 0, 0, 2 * r, 2 * r);
  135.     BitBlt(hdc, x - r, y - r, 2 * r, 2 * r, memDC, 0, 0, SRCCOPY);
  136.     SelectObject(memDC, hOldPen);
  137.     DeleteObject(hPen);
  138.     DeleteObject(hBitmap);
  139.     DeleteDC(memDC);
  140.     DrawHand(hdc, x, y, st.wSecond * 6, r - 30, RGB(255, 0, 0));
  141.     DrawHand(hdc, x, y, (st.wMinute * 6) + (st.wSecond / 10.0), r - 60, RGB(0, 0, 0));
  142.     DrawHand(hdc, x, y, (st.wHour * 30) + (st.wMinute / 2.0), r - 90, RGB(0, 0, 255));
  143.     HFONT hFont = CreateFont(12, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, TEXT("Segoe UI"));
  144.     HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
  145.     SetTextColor(hdc, RGB(112, 128, 144));
  146.     SetTextAlign(hdc, TA_CENTER | TA_BASELINE);
  147.     SetBkMode(hdc, TRANSPARENT);
  148.     for (int i = 1; i <= 12; i++) {
  149.         double angle = (i * 30 - 90) * (3.14159265358979323846 / 180);
  150.         int numX = x + (int)(cos(angle) * (r - 25));
  151.         int numY = y + (int)(sin(angle) * (r - 25));
  152.         WCHAR numStr[3];
  153.         wsprintf(numStr, L"%d", i);
  154.         TextOut(hdc, numX, numY, numStr, lstrlen(numStr));
  155.     }
  156.     SelectObject(hdc, hOldFont);
  157.     DeleteObject(hFont);
  158.     for (int i = 0; i < 60; i++) {
  159.         if (i % 5 == 0) {
  160.             DrawHand(hdc, x, y, i * 6, r - 10, RGB(0, 0, 0), false);
  161.         }
  162.         else {
  163.             DrawHand(hdc, x, y, i * 6, r - 5, RGB(0, 0, 0), false);
  164.         }
  165.     }
  166. }
  167.  
  168. void DrawHand(HDC hdc, int x, int y, double angle, int length, COLORREF color, bool drawLineToCenter) {
  169.     double radian = (angle - 90) * (3.14159265358979323846 / 180);
  170.     int endX = x + (int)(cos(radian) * length);
  171.     int endY = y + (int)(sin(radian) * length);
  172.     HPEN hPen = CreatePen(PS_SOLID, 2, color);
  173.     HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
  174.     if (drawLineToCenter) {
  175.         MoveToEx(hdc, x, y, NULL);
  176.         LineTo(hdc, endX, endY);
  177.     }
  178.     else {
  179.         MoveToEx(hdc, endX, endY, NULL);
  180.         LineTo(hdc, endX + (int)(cos(radian) * 5), endY + (int)(sin(radian) * 5));
  181.     }
  182.     SelectObject(hdc, hOldPen);
  183.     DeleteObject(hPen);
  184. }
  185.  
  186. void UpdateStatusBar(HWND hwndStatus, SYSTEMTIME st) {
  187.     TCHAR szStatus[256];
  188.     TCHAR szDayOfWeek[32], szMonth[32];
  189.     TCHAR szSuffix[3];
  190.     int weekNumber;
  191.  
  192.     // Get day of week and month names
  193.     GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, TEXT("dddd"), szDayOfWeek, sizeof(szDayOfWeek) / sizeof(TCHAR));
  194.     GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, TEXT("MMMM"), szMonth, sizeof(szMonth) / sizeof(TCHAR));
  195.  
  196.     // Calculate week number
  197.     SYSTEMTIME newYearDay = { st.wYear, 1, 0, 1 };
  198.     FILETIME ftNewYearDay, ftCurrentDay;
  199.     SystemTimeToFileTime(&newYearDay, &ftNewYearDay);
  200.     SystemTimeToFileTime(&st, &ftCurrentDay);
  201.     ULARGE_INTEGER uliNewYearDay, uliCurrentDay;
  202.     uliNewYearDay.LowPart = ftNewYearDay.dwLowDateTime;
  203.     uliNewYearDay.HighPart = ftNewYearDay.dwHighDateTime;
  204.     uliCurrentDay.LowPart = ftCurrentDay.dwLowDateTime;
  205.     uliCurrentDay.HighPart = ftCurrentDay.dwHighDateTime;
  206.     weekNumber = (int)(((uliCurrentDay.QuadPart - uliNewYearDay.QuadPart) / (7 * 24 * 60 * 60 * 10000000ULL)) + 1);
  207.  
  208.     // Get day suffix
  209.     if (st.wDay == 1 || st.wDay == 21 || st.wDay == 31)
  210.         _tcscpy_s(szSuffix, _T("st"));
  211.     else if (st.wDay == 2 || st.wDay == 22)
  212.         _tcscpy_s(szSuffix, _T("nd"));
  213.     else if (st.wDay == 3 || st.wDay == 23)
  214.         _tcscpy_s(szSuffix, _T("rd"));
  215.     else
  216.         _tcscpy_s(szSuffix, _T("th"));
  217.  
  218.     // Format the status string
  219.     StringCbPrintf(szStatus, sizeof(szStatus),
  220.         TEXT("%s %d%s %s %d #%d %d/%02d/%04d %02d:%02d:%02d %s"),
  221.         szDayOfWeek, st.wDay, szSuffix, szMonth, st.wYear, weekNumber,
  222.         st.wDay, st.wMonth, st.wYear,
  223.         (st.wHour == 0 || st.wHour == 12) ? 12 : st.wHour % 12,
  224.         st.wMinute, st.wSecond,
  225.         st.wHour < 12 ? TEXT("AM") : TEXT("PM"));
  226.  
  227.     SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)szStatus);
  228. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement