alien_fx_fiend

Analog Clock Win32 (V4 0-flicker + OverExtension + Thicker Markers/ More Polished) *FINAL RELASE #2*

Oct 28th, 2024
15
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 14.64 KB | Source Code | 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. #include "resource.h"  // Add this with your other includes
  9. #pragma comment(lib, "Msimg32.lib")
  10. #pragma comment(lib, "comctl32.lib")
  11. #define ID_TIMER 1
  12. #define SIZE 475
  13. #define CLOCK_MARGIN 20
  14. #define ID_STATUSBAR 100
  15. //SIZE 425
  16. LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
  17. void DrawClock(HDC, int, int, int);
  18. void DrawHand(HDC hdc, int x, int y, double angle, int length, COLORREF color, bool drawLineToCenter = true);
  19. void UpdateStatusBar(HWND, SYSTEMTIME);
  20. LRESULT CALLBACK StatusBarProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData);
  21.  
  22. int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) {
  23.     static TCHAR szAppName[] = TEXT("My Clock");
  24.     HWND hwnd;
  25.     MSG msg;
  26.     WNDCLASS wndclass;
  27.     wndclass.style = CS_HREDRAW | CS_VREDRAW;
  28.     wndclass.lpfnWndProc = WndProc;
  29.     wndclass.cbClsExtra = 0;
  30.     wndclass.cbWndExtra = 0;
  31.     wndclass.hInstance = hInstance;
  32.     wndclass.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
  33.     //wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  34.     wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
  35.     wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
  36.     wndclass.lpszMenuName = NULL;
  37.     wndclass.lpszClassName = szAppName;
  38.     if (!RegisterClass(&wndclass)) {
  39.         MessageBox(NULL, TEXT("Program requires Windows NT!"), szAppName, MB_ICONERROR);
  40.         return 0;
  41.     }
  42.     RECT rect = { 0, 0, SIZE + 2 * CLOCK_MARGIN, SIZE + 2 * CLOCK_MARGIN + 30 };
  43.     AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
  44.  
  45.     // Get screen dimensions
  46.     int screenWidth = GetSystemMetrics(SM_CXSCREEN);
  47.     int screenHeight = GetSystemMetrics(SM_CYSCREEN);
  48.  
  49.     // Calculate centered position
  50.     int windowWidth = rect.right - rect.left;
  51.     int windowHeight = rect.bottom - rect.top;
  52.     int xPos = (screenWidth - windowWidth) / 2;
  53.     int yPos = (screenHeight - windowHeight) / 2;
  54.  
  55.     hwnd = CreateWindow(szAppName, TEXT("Time is Meaningless The Insurgency is Live & Well (F1=About)"),
  56.         WS_OVERLAPPEDWINDOW, xPos, yPos,
  57.         windowWidth, windowHeight,
  58.         NULL, NULL, hInstance, NULL);
  59.  
  60.     ShowWindow(hwnd, iCmdShow);
  61.     UpdateWindow(hwnd);
  62.  
  63.     while (GetMessage(&msg, NULL, 0, 0)) {
  64.         TranslateMessage(&msg);
  65.         DispatchMessage(&msg);
  66.     }
  67.     return (int)msg.wParam;
  68. }
  69.  
  70. LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) {
  71.     static HWND hwndStatus;
  72.     static HBITMAP hBitmap;
  73.     static int cxClient, cyClient;
  74.     HDC hdc, memDC;
  75.     PAINTSTRUCT ps;
  76.     SYSTEMTIME st;
  77.     RECT rect;
  78.     int centerX, centerY;
  79.  
  80.     // Moved the declaration outside the switch
  81.     int statwidths[] = { -1 };
  82.  
  83.     switch (message) {
  84.     case WM_CREATE:
  85.         // Enable double buffering
  86.         SetWindowLong(hwnd, GWL_STYLE, GetWindowLong(hwnd, GWL_STYLE) | WS_CLIPCHILDREN);
  87.  
  88.         hwndStatus = CreateWindowEx(0, STATUSCLASSNAME, NULL,
  89.             WS_CHILD | WS_VISIBLE | SBARS_SIZEGRIP, 0, 0, 0, 0,
  90.             hwnd, (HMENU)ID_STATUSBAR, GetModuleHandle(NULL), NULL);
  91.  
  92.         SendMessage(hwndStatus, SB_SETPARTS, 1, (LPARAM)statwidths);
  93.         SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)TEXT(""));
  94.         SetWindowSubclass(hwndStatus, StatusBarProc, 0, 0);
  95.         SetTimer(hwnd, ID_TIMER, 1000, NULL);
  96.         return 0;
  97.     case WM_KEYDOWN:
  98.         if (wParam == VK_ESCAPE) {
  99.             PostQuitMessage(0);
  100.             return 0;
  101.         }
  102.         // Add this new code block
  103.         else if (wParam == VK_F1) {
  104.             MessageBox(hwnd, TEXT("Analog Clock (incorporates SubClassing Controls) Programmed in C++ Win32 API (395 lines of code) by Entisoft Software (c) Evans Thorpemorton"), TEXT("Information"), MB_OK | MB_ICONINFORMATION);
  105.             return 0;
  106.         }
  107.         break;
  108.     case WM_SIZE:
  109.         cxClient = LOWORD(lParam);
  110.         cyClient = HIWORD(lParam);
  111.         if (hBitmap) {
  112.             DeleteObject(hBitmap);
  113.         }
  114.         hdc = GetDC(hwnd);
  115.         hBitmap = CreateCompatibleBitmap(hdc, cxClient, cyClient);
  116.         ReleaseDC(hwnd, hdc);
  117.         SendMessage(hwndStatus, WM_SIZE, 0, 0);
  118.         return 0;
  119.     case WM_PAINT:
  120.         hdc = BeginPaint(hwnd, &ps);
  121.         memDC = CreateCompatibleDC(hdc);
  122.         SelectObject(memDC, hBitmap);
  123.         GetClientRect(hwnd, &rect);
  124.         centerX = (rect.right - rect.left) / 2;
  125.         centerY = ((rect.bottom - rect.top) - 20) / 2;
  126.         FillRect(memDC, &rect, (HBRUSH)GetStockObject(WHITE_BRUSH));
  127.         DrawClock(memDC, centerX, centerY, min(centerX, centerY) - CLOCK_MARGIN);
  128.         BitBlt(hdc, 0, 0, cxClient, cyClient, memDC, 0, 0, SRCCOPY);
  129.         DeleteDC(memDC);
  130.         EndPaint(hwnd, &ps);
  131.         return 0;
  132.     case WM_TIMER:
  133.         GetLocalTime(&st);
  134.         UpdateStatusBar(hwndStatus, st);
  135.         InvalidateRect(hwnd, NULL, FALSE);
  136.         return 0;
  137.     case WM_DESTROY:
  138.         KillTimer(hwnd, ID_TIMER);
  139.         if (hBitmap) DeleteObject(hBitmap);
  140.         PostQuitMessage(0);
  141.         return 0;
  142.     }
  143.     return DefWindowProc(hwnd, message, wParam, lParam);
  144. }
  145.  
  146. void DrawClock(HDC hdc, int x, int y, int r) {
  147.     SYSTEMTIME st;
  148.     GetLocalTime(&st);
  149.  
  150.     // Create memory DC for double buffering
  151.     HDC memDC = CreateCompatibleDC(hdc);
  152.     HBITMAP hBitmap = CreateCompatibleBitmap(hdc, 2 * r, 2 * r);
  153.     HBITMAP hOldBitmap = (HBITMAP)SelectObject(memDC, hBitmap);
  154.  
  155.     // Calculate center point for the memory DC
  156.     int centerX = r;  // Center X in memory DC coordinates
  157.     int centerY = r;  // Center Y in memory DC coordinates
  158.  
  159.     // Draw gradient background
  160.     TRIVERTEX vertex[2];
  161.     vertex[0].x = 0;
  162.     vertex[0].y = 0;
  163.     vertex[0].Red = 0xc000;
  164.     vertex[0].Green = 0xc000;
  165.     vertex[0].Blue = 0xc000;
  166.     vertex[0].Alpha = 0x0000;
  167.     vertex[1].x = 2 * r;
  168.     vertex[1].y = 2 * r;
  169.     vertex[1].Red = 0x4000;
  170.     vertex[1].Green = 0x4000;
  171.     vertex[1].Blue = 0x4000;
  172.     vertex[1].Alpha = 0x0000;
  173.     GRADIENT_RECT gRect = { 0, 1 };
  174.     GradientFill(memDC, vertex, 2, &gRect, 1, GRADIENT_FILL_RECT_H);
  175.  
  176.     // Draw clock outline
  177.     HPEN hPen = CreatePen(PS_SOLID, 8, RGB(128, 128, 128));
  178.     HPEN hOldPen = (HPEN)SelectObject(memDC, hPen);
  179.     Ellipse(memDC, 0, 0, 2 * r, 2 * r);
  180.  
  181.     // Draw hour numbers
  182.     HFONT hFont = CreateFont(12, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
  183.         ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  184.         DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, TEXT("Segoe UI"));
  185.     HFONT hOldFont = (HFONT)SelectObject(memDC, hFont);
  186.     SetTextColor(memDC, RGB(112, 128, 144));
  187.     SetTextAlign(memDC, TA_CENTER | TA_BASELINE);
  188.     SetBkMode(memDC, TRANSPARENT);
  189.  
  190.     for (int i = 1; i <= 12; i++) {
  191.         double angle = (i * 30 - 90) * (3.14159265358979323846 / 180);
  192.         int numX = centerX + (int)(cos(angle) * (r - 25));
  193.         int numY = centerY + (int)(sin(angle) * (r - 25));
  194.         WCHAR numStr[3];
  195.         wsprintf(numStr, L"%d", i);
  196.         TextOut(memDC, numX, numY, numStr, lstrlen(numStr));
  197.     }
  198.  
  199.     // Draw markers
  200.     for (int i = 0; i < 60; i++) {
  201.         if (i % 5 == 0) {
  202.             DrawHand(memDC, centerX, centerY, i * 6, r - 10, RGB(0, 0, 0), false);
  203.         }
  204.         else {
  205.             DrawHand(memDC, centerX, centerY, i * 6, r - 5, RGB(0, 0, 0), false);
  206.         }
  207.     }
  208.  
  209.     // Draw clock hands
  210.     DrawHand(memDC, centerX, centerY, st.wSecond * 6, r - 30, RGB(255, 0, 0));
  211.     DrawHand(memDC, centerX, centerY, (st.wMinute * 6) + (st.wSecond / 10.0), r - 60, RGB(0, 0, 0));
  212.     DrawHand(memDC, centerX, centerY, (st.wHour * 30) + (st.wMinute / 2.0), r - 90, RGB(0, 0, 255));
  213.  
  214.     // Draw center white circle
  215.     HBRUSH whiteBrush = CreateSolidBrush(RGB(255, 255, 255));
  216.     HBRUSH oldBrush = (HBRUSH)SelectObject(memDC, whiteBrush);
  217.     Ellipse(memDC, centerX - 10, centerY - 10, centerX + 10, centerY + 10);
  218.     SelectObject(memDC, oldBrush);
  219.     DeleteObject(whiteBrush);
  220.  
  221.     // Add AM/PM text
  222.     SelectObject(memDC, hOldFont);
  223.     DeleteObject(hFont);
  224.  
  225.     hFont = CreateFont(18, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE,
  226.         ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  227.         DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, TEXT("Segoe UI"));
  228.     SelectObject(memDC, hFont);
  229.     SetTextColor(memDC, RGB(128, 128, 128));
  230.     TextOut(memDC, centerX, centerY + (r - 70), st.wHour < 12 ? TEXT("AM") : TEXT("PM"), 2);
  231.  
  232.     // Copy the final result to the screen
  233.     BitBlt(hdc, x - r, y - r, 2 * r, 2 * r, memDC, 0, 0, SRCCOPY);
  234.  
  235.     // Final cleanup
  236.     SelectObject(memDC, hOldFont);
  237.     SelectObject(memDC, hOldPen);
  238.     SelectObject(memDC, hOldBitmap);
  239.     DeleteObject(hFont);
  240.     DeleteObject(hPen);
  241.     DeleteObject(hBitmap);
  242.     DeleteDC(memDC);
  243. }
  244.  
  245. void DrawHand(HDC hdc, int x, int y, double angle, int length, COLORREF color, bool drawLineToCenter) {
  246.     double radian = (angle - 90) * (3.14159265358979323846 / 180);
  247.  
  248.     // Calculate the extension length (10% of hand length)
  249.     int extensionLength = length * 0.1;
  250.  
  251.     if (drawLineToCenter) {
  252.         if (color == RGB(255, 0, 0)) {  // Second hand
  253.             // Create pointed second hand with triangular shape
  254.             POINT pts[3];
  255.  
  256.             // Calculate the tip point
  257.             pts[0].x = x + (int)(cos(radian) * length);
  258.             pts[0].y = y + (int)(sin(radian) * length);
  259.  
  260.             // Calculate base points (wider at base)
  261.             double perpRadian = radian + 3.14159265358979323846 / 2;
  262.             int baseWidth = 8;  // Increased base width
  263.             pts[1].x = x - (int)(cos(radian) * extensionLength) + (int)(cos(perpRadian) * baseWidth);
  264.             pts[1].y = y - (int)(sin(radian) * extensionLength) + (int)(sin(perpRadian) * baseWidth);
  265.             pts[2].x = x - (int)(cos(radian) * extensionLength) - (int)(cos(perpRadian) * baseWidth);
  266.             pts[2].y = y - (int)(sin(radian) * extensionLength) - (int)(sin(perpRadian) * baseWidth);
  267.  
  268.             // Create and select pen and brush
  269.             HPEN hPen = CreatePen(PS_SOLID, 1, color);
  270.             HBRUSH hBrush = CreateSolidBrush(color);
  271.             HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
  272.             HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
  273.  
  274.             // Draw the triangular second hand
  275.             Polygon(hdc, pts, 3);
  276.  
  277.             // Cleanup
  278.             SelectObject(hdc, hOldPen);
  279.             SelectObject(hdc, hOldBrush);
  280.             DeleteObject(hPen);
  281.             DeleteObject(hBrush);
  282.         }
  283.         else {
  284.             // Regular hands (hour and minute)
  285.             int penThickness = (color == RGB(0, 0, 255)) ? 6 : 4;  // Hour : Minute
  286.             HPEN hPen = CreatePen(PS_SOLID, penThickness, color);
  287.             HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
  288.  
  289.             // Draw the hand
  290.             int endX = x + (int)(cos(radian) * length);
  291.             int endY = y + (int)(sin(radian) * length);
  292.             int startX = x - (int)(cos(radian) * extensionLength);
  293.             int startY = y - (int)(sin(radian) * extensionLength);
  294.  
  295.             MoveToEx(hdc, startX, startY, NULL);
  296.             LineTo(hdc, endX, endY);
  297.  
  298.             // Cleanup
  299.             SelectObject(hdc, hOldPen);
  300.             DeleteObject(hPen);
  301.         }
  302.     }
  303.     else {
  304.         // For markers, increase thickness for hour markers
  305.         int markerThickness = ((int)angle % 30 == 0) ? 4 : 2;
  306.         HPEN hPen = CreatePen(PS_SOLID, markerThickness, color);
  307.         HPEN hOldPen = (HPEN)SelectObject(hdc, hPen);
  308.  
  309.         int endX = x + (int)(cos(radian) * length);
  310.         int endY = y + (int)(sin(radian) * length);
  311.  
  312.         MoveToEx(hdc, endX, endY, NULL);
  313.         LineTo(hdc, endX + (int)(cos(radian) * 5), endY + (int)(sin(radian) * 5));
  314.  
  315.         // Cleanup
  316.         SelectObject(hdc, hOldPen);
  317.         DeleteObject(hPen);
  318.     }
  319. }
  320.  
  321. void UpdateStatusBar(HWND hwndStatus, SYSTEMTIME st) {
  322.     TCHAR szStatus[256];
  323.     TCHAR szDayOfWeek[32], szMonth[32];
  324.     TCHAR szSuffix[3];
  325.     int weekNumber;
  326.  
  327.     GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, TEXT("dddd"), szDayOfWeek, sizeof(szDayOfWeek) / sizeof(TCHAR));
  328.     GetDateFormat(LOCALE_USER_DEFAULT, 0, &st, TEXT("MMMM"), szMonth, sizeof(szMonth) / sizeof(TCHAR));
  329.  
  330.     SYSTEMTIME newYearDay = { st.wYear, 1, 0, 1 };
  331.     FILETIME ftNewYearDay, ftCurrentDay;
  332.     SystemTimeToFileTime(&newYearDay, &ftNewYearDay);
  333.     SystemTimeToFileTime(&st, &ftCurrentDay);
  334.     ULARGE_INTEGER uliNewYearDay, uliCurrentDay;
  335.     uliNewYearDay.LowPart = ftNewYearDay.dwLowDateTime;
  336.     uliNewYearDay.HighPart = ftNewYearDay.dwHighDateTime;
  337.     uliCurrentDay.LowPart = ftCurrentDay.dwLowDateTime;
  338.     uliCurrentDay.HighPart = ftCurrentDay.dwHighDateTime;
  339.     weekNumber = (int)(((uliCurrentDay.QuadPart - uliNewYearDay.QuadPart) / (7 * 24 * 60 * 60 * 10000000ULL)) + 1);
  340.  
  341.     if (st.wDay == 1 || st.wDay == 21 || st.wDay == 31)
  342.         _tcscpy_s(szSuffix, _T("st"));
  343.     else if (st.wDay == 2 || st.wDay == 22)
  344.         _tcscpy_s(szSuffix, _T("nd"));
  345.     else if (st.wDay == 3 || st.wDay == 23)
  346.         _tcscpy_s(szSuffix, _T("rd"));
  347.     else
  348.         _tcscpy_s(szSuffix, _T("th"));
  349.  
  350.     // Get time zone information
  351.     TIME_ZONE_INFORMATION tzi;
  352.     GetTimeZoneInformation(&tzi);
  353.     int bias = -(tzi.Bias); // Negative because Bias is in opposite direction
  354.     int hours = bias / 60;
  355.     int minutes = abs(bias % 60);
  356.  
  357.     StringCbPrintf(szStatus, sizeof(szStatus),
  358.         TEXT("%s %d%s %s %d #%d %d/%02d/%04d %02d:%02d:%02d %s GMT%s%d:%02d"),
  359.         szDayOfWeek, st.wDay, szSuffix, szMonth, st.wYear, weekNumber,
  360.         st.wDay, st.wMonth, st.wYear,
  361.         (st.wHour == 0 || st.wHour == 12) ? 12 : st.wHour % 12,
  362.         st.wMinute, st.wSecond,
  363.         st.wHour < 12 ? TEXT("AM") : TEXT("PM"),
  364.         (hours >= 0) ? TEXT("+") : TEXT(""),
  365.         hours,
  366.         minutes);
  367.  
  368.     SendMessage(hwndStatus, SB_SETTEXT, 0, (LPARAM)szStatus);
  369.     InvalidateRect(hwndStatus, NULL, TRUE);
  370. }
  371.  
  372. LRESULT CALLBACK StatusBarProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, UINT_PTR uIdSubclass, DWORD_PTR dwRefData) {
  373.     if (uMsg == WM_PAINT) {
  374.         PAINTSTRUCT ps;
  375.         HDC hdc = BeginPaint(hWnd, &ps);
  376.  
  377.         RECT rc;
  378.         GetClientRect(hWnd, &rc);
  379.  
  380.         TCHAR szText[256];
  381.         int len = SendMessage(hWnd, SB_GETTEXT, 0, (LPARAM)szText);
  382.  
  383.         SetBkMode(hdc, TRANSPARENT);
  384.         SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT));
  385.  
  386.         DrawText(hdc, szText, len, &rc, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
  387.  
  388.         EndPaint(hWnd, &ps);
  389.         return 0;
  390.     }
  391.  
  392.     return DefSubclassProc(hWnd, uMsg, wParam, lParam);
  393. }
Add Comment
Please, Sign In to add comment