Advertisement
alien_fx_fiend

Binary Tree Visualizer Final (Needs Double/Treble Slash fix)

Nov 3rd, 2024
43
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 12.58 KB | Source Code | 0 0
  1. #define NOMINMAX
  2. #include <windows.h>
  3. #include <windowsx.h>  // Add this line
  4. #include <commctrl.h>
  5. #include <string>
  6. #include <vector>
  7. #include <algorithm>  // Add this at the top with other includes
  8. #include <functional>
  9. #include <ctime>    // for time()
  10. #include <cstdlib>  // for rand() and srand()
  11. #include <random>
  12. #include <sstream>
  13. #include <iostream>
  14. #include <richedit.h> // Include for Rich Edit control
  15. #include <shellapi.h>
  16.  
  17. #pragma comment(lib, "Psapi.lib")
  18. #pragma comment(lib, "comctl32.lib") // Link with the common controls library
  19. //#pragma comment(lib, "riched32.lib")  // Link with the rich edit library
  20. #pragma comment(lib, "Shell32.lib")
  21.  
  22. // Structure for a binary tree node
  23. struct Node {
  24.     int data;
  25.     Node* left;
  26.     Node* right;
  27.  
  28.     Node(int val) : data(val), left(nullptr), right(nullptr) {}
  29. };
  30.  
  31. // Function to insert a new node into the binary tree
  32. Node* insert(Node* root, int val) {
  33.     if (!root) {
  34.         return new Node(val);
  35.     }
  36.  
  37.     if (val < root->data) {
  38.         root->left = insert(root->left, val);
  39.     }
  40.     else {
  41.         root->right = insert(root->right, val);
  42.     }
  43.     return root;
  44. }
  45.  
  46.  
  47. // Helper function to get the height of the tree
  48. int getHeight(Node* root) {
  49.     if (!root) return 0;
  50.     return 1 + std::max(getHeight(root->left), getHeight(root->right));
  51. }
  52.  
  53. // Helper function to add padding
  54. std::string getPadding(int level) {
  55.     return std::string(level * 6, ' ');
  56. }
  57.  
  58. std::string getListString(Node* root, std::string prefix = "") {
  59.     if (!root) return "";
  60.  
  61.     std::string result = prefix + "|_ " + std::to_string(root->data) + "\r\n";
  62.  
  63.     if (root->left) {
  64.         bool hasRight = (root->right != nullptr);
  65.         std::string newPrefix = prefix + (hasRight ? "|  " : "   ");
  66.         result += getListString(root->left, newPrefix);
  67.     }
  68.  
  69.     if (root->right) {
  70.         std::string newPrefix = prefix + "   ";
  71.         result += getListString(root->right, newPrefix);
  72.     }
  73.  
  74.     return result;
  75. }
  76.  
  77. void deleteTree(Node* node) {
  78.     if (node) {
  79.         deleteTree(node->left);
  80.         deleteTree(node->right);
  81.         delete node;
  82.     }
  83. }
  84.  
  85. // Modified getTreeString function with correct lambda capture
  86. std::string getTreeString(Node* root) {
  87.     if (!root) return "";
  88.  
  89.     std::vector<std::string> levels;  // levels vector
  90.  
  91.     //std::vector<std::string> levels;
  92.     int maxLevelWidth = 0;
  93.  
  94.     levels.clear(); // Clear the levels vector at the beginning    
  95.  
  96.     std::function<void(Node*, int, int)> traverse =
  97.         [&](Node* node, int depth, int xOffset) {
  98.         if (!node) return;
  99.  
  100.         // 1. Resize levels to accommodate current depth + children and connecting lines
  101.         levels.resize(std::max((int)levels.size(), depth + 2)); // Ensure enough space
  102.  
  103.         int dataWidth = std::to_string(node->data).length();
  104.         int centerX = xOffset + dataWidth / 2;
  105.  
  106.         // 2. Resize and pad level string for node data
  107.         if (levels[depth].length() < centerX + dataWidth) {
  108.             levels[depth].resize(centerX + dataWidth, ' ');
  109.         }
  110.         levels[depth].replace(centerX, dataWidth, std::to_string(node->data));
  111.  
  112.         maxLevelWidth = std::max(maxLevelWidth, (int)levels[depth].length());
  113.  
  114.         if (node->left || node->right) {
  115.             int spacing = 3;
  116.             int leftChildOffset = xOffset - spacing;
  117.             int rightChildOffset = xOffset + dataWidth + spacing - 1;
  118.  
  119.  
  120.             if (node->left) {
  121.                 // 3. Place left slash
  122.                 levels[depth + 1].resize(std::max((int)levels[depth + 1].length(), centerX), ' '); // Ensure space, pad if needed
  123.                 levels[depth + 1][centerX - 1] = '/';
  124.                 traverse(node->left, depth + 2, leftChildOffset);
  125.             }
  126.  
  127.             if (node->right) {
  128.                 // 4. Place right slash
  129.                 levels[depth + 1].resize(std::max((int)levels[depth + 1].length(), centerX + 2), ' '); // Ensure space, pad if needed
  130.                 levels[depth + 1][centerX + 1] = '\\';
  131.                 traverse(node->right, depth + 2, rightChildOffset);
  132.             }
  133.         }
  134.     };
  135.  
  136.     traverse(root, 0, 20);
  137.  
  138.     std::string result;
  139.     for (size_t i = 0; i < levels.size(); ++i) {
  140.         if (maxLevelWidth > levels[i].length()) {
  141.             levels[i].resize(maxLevelWidth, ' ');
  142.         }
  143.         result += levels[i] + "\r\n";
  144.     }
  145.     return result;
  146. }
  147.  
  148. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  149.  
  150. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) {
  151.  
  152.     const wchar_t CLASS_NAME[] = L"BinaryTreeVisualizer";
  153.  
  154.     WNDCLASS wc = { };
  155.  
  156.     wc.lpfnWndProc = WindowProc;
  157.     wc.hInstance = hInstance;
  158.     wc.lpszClassName = CLASS_NAME;
  159.  
  160.     RegisterClass(&wc);
  161.  
  162.     HWND hwnd = CreateWindowEx(
  163.         0,                              // Optional window styles.
  164.         CLASS_NAME,                     // Window class
  165.         L"Binary Tree Visualizer",    // Window text
  166.         WS_OVERLAPPEDWINDOW,            // Window style
  167.  
  168.         CW_USEDEFAULT, CW_USEDEFAULT, 550, 400,
  169.  
  170.         NULL,       // Parent window    
  171.         NULL,       // Menu
  172.         hInstance,  // Instance handle
  173.         NULL        // Additional application data
  174.     );
  175.  
  176.     if (hwnd == NULL) {
  177.         return 0;
  178.     }
  179.  
  180.     ShowWindow(hwnd, nCmdShow);
  181.  
  182.     // Run the message loop.
  183.     MSG msg = { };
  184.     while (GetMessage(&msg, NULL, 0, 0)) {
  185.         TranslateMessage(&msg);
  186.         DispatchMessage(&msg);
  187.     }
  188.  
  189.     return 0;
  190. }
  191.  
  192. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  193.     static HWND hEdit, hDisplay, hTreeViewRadio, hListViewRadio, hGenerateButton;
  194.     static Node* root = nullptr;
  195.  
  196.     switch (uMsg) {
  197.     case WM_CREATE: {
  198.         // Create Input Field
  199.         hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
  200.             WS_CHILD | WS_VISIBLE | WS_BORDER,
  201.             10, 10, 100, 20, hwnd, NULL, NULL, NULL);
  202.  
  203.         // Create multiline Edit control for display
  204.             // Create display Edit control with proper styles for newlines
  205.         hDisplay = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
  206.             WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
  207.             ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | ES_LEFT,
  208.             10, 40, 510, 300, hwnd, NULL, NULL, NULL);
  209.  
  210.         // Radio Buttons
  211.         hTreeViewRadio = CreateWindowEx(0, L"BUTTON", L"Tree View",
  212.             WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP,
  213.             120, 10, 100, 20, hwnd, (HMENU)1, NULL, NULL);
  214.  
  215.         hListViewRadio = CreateWindowEx(0, L"BUTTON", L"List View",
  216.             WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
  217.             230, 10, 100, 20, hwnd, (HMENU)2, NULL, NULL);
  218.  
  219.         // Generate Button
  220.         hGenerateButton = CreateWindowEx(0, L"BUTTON", L"Generate Tree",
  221.             WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
  222.             340, 10, 100, 20, hwnd, (HMENU)3, NULL, NULL);
  223.  
  224.         Button_SetCheck(hTreeViewRadio, BST_CHECKED);
  225.  
  226.         // Set monospace font
  227.             // Set monospace font for better tree display
  228.         HFONT hFont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
  229.             DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  230.             DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Consolas");
  231.  
  232.         SendMessage(hDisplay, WM_SETFONT, (WPARAM)hFont, TRUE);
  233.  
  234.         // Set tab stops for the display Edit control (optional)
  235.         DWORD tabStops = 16; // in dialog units
  236.         SendMessage(hDisplay, EM_SETTABSTOPS, 1, (LPARAM)&tabStops);
  237.  
  238.         // Set text alignment to center
  239.         //SendMessage(hDisplay, EM_SETALIGNMENT, ES_CENTER, 0);
  240.  
  241.         break;
  242.     }
  243.  
  244.     case WM_COMMAND:
  245.         if (LOWORD(wParam) == 3) { // Generate button clicked
  246.             wchar_t buffer[256];
  247.             GetWindowText(hEdit, buffer, 256);
  248.  
  249.             wchar_t* endptr;
  250.             long numNodes = std::wcstol(buffer, &endptr, 10);
  251.  
  252.             if (*endptr == L'\0' && numNodes > 0 && numNodes <= 100) {
  253.                 //delete root;
  254.                 deleteTree(root);  // Correctly delete the entire tree
  255.                 root = nullptr;
  256.  
  257.                 std::vector<int> numbers(numNodes);
  258.                 for (int i = 0; i < numNodes; ++i) {
  259.                     numbers[i] = i + 1;
  260.                 }
  261.                 std::random_device rd;
  262.                 std::mt19937 g(rd());
  263.                 std::shuffle(numbers.begin(), numbers.end(), g);
  264.  
  265.                 for (int num : numbers) {
  266.                     root = insert(root, num);
  267.                 }
  268.  
  269.                 std::string treeString;
  270.                 try {
  271.                     if (Button_GetCheck(hTreeViewRadio) == BST_CHECKED) {
  272.                         treeString = getTreeString(root);
  273.                         std::string::size_type pos = 0;
  274.                         while ((pos = treeString.find('\n', pos)) != std::string::npos) {
  275.                             treeString.replace(pos, 1, "\r\n");
  276.                             pos += 2;
  277.                         }
  278.                     }
  279.                     else {
  280.                         treeString = getListString(root);
  281.                     }
  282.  
  283.                     int size_needed = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), -1, NULL, 0);
  284.                     if (size_needed == 0) {
  285.                         OutputDebugString(L"MultiByteToWideChar failed\n");
  286.                         break;
  287.                     }
  288.  
  289.                     std::wstring wideStr(size_needed - 1, 0);
  290.                     int converted_chars = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), -1, &wideStr[0], size_needed);
  291.                     if (converted_chars == 0) {
  292.                         OutputDebugString(L"MultiByteToWideChar failed\n");
  293.                         break;
  294.                     }
  295.  
  296.                     SetWindowText(hDisplay, wideStr.c_str());
  297.  
  298.                     LONG_PTR style = GetWindowLongPtr(hDisplay, GWL_STYLE);
  299.                     style |= ES_MULTILINE | ES_AUTOVSCROLL;
  300.                     SetWindowLongPtr(hDisplay, GWL_STYLE, style);
  301.  
  302.                     SendMessage(hDisplay, WM_VSCROLL, SB_TOP, 0);
  303.                     SendMessage(hDisplay, EM_SETSEL, 0, 0);
  304.                     SendMessage(hDisplay, EM_SCROLLCARET, 0, 0);
  305.                 }
  306.                 catch (const std::exception& e) {
  307.                     std::string error = "Exception: ";
  308.                     error += e.what();
  309.                     OutputDebugStringA(error.c_str());
  310.                 }
  311.             }
  312.             else {
  313.                 MessageBox(hwnd, L"Please enter a number between 1 and 100.", L"Invalid Input", MB_OK | MB_ICONWARNING);
  314.             }
  315.         }
  316.         else if (LOWORD(wParam) == 1 || LOWORD(wParam) == 2) {  // Radio button handling
  317.             if (root != nullptr) {
  318.                 std::string treeString;
  319.                 if (Button_GetCheck(hTreeViewRadio) == BST_CHECKED) {
  320.                     treeString = getTreeString(root);
  321.                     std::string::size_type pos = 0;
  322.                     while ((pos = treeString.find('\n', pos)) != std::string::npos) {
  323.                         treeString.replace(pos, 1, "\r\n");
  324.                         pos += 2;
  325.                     }
  326.                 }
  327.                 else {
  328.                     treeString = getListString(root);
  329.                 }
  330.  
  331.                 int size_needed = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), -1, NULL, 0);
  332.                 if (size_needed == 0) {
  333.                     OutputDebugString(L"MultiByteToWideChar failed (Radio)\n");
  334.                     break;
  335.                 }
  336.                 std::wstring wideStr(size_needed - 1, 0);
  337.                 int converted = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), -1, &wideStr[0], size_needed);
  338.                 if (converted == 0) {
  339.                     OutputDebugString(L"MultiByteToWideChar failed (Radio)\n");
  340.                     break;
  341.                 }
  342.  
  343.                 SetWindowText(hDisplay, wideStr.c_str());
  344.  
  345.                 LONG_PTR style = GetWindowLongPtr(hDisplay, GWL_STYLE);
  346.                 style |= ES_MULTILINE | ES_AUTOVSCROLL;
  347.                 SetWindowLongPtr(hDisplay, GWL_STYLE, style);
  348.  
  349.                 SendMessage(hDisplay, WM_VSCROLL, SB_TOP, 0);
  350.                 SendMessage(hDisplay, EM_SETSEL, 0, 0);
  351.                 SendMessage(hDisplay, EM_SCROLLCARET, 0, 0);
  352.             }
  353.         }
  354.         break;
  355.  
  356.     case WM_DESTROY:
  357.         delete root; // Clean up
  358.         PostQuitMessage(0);
  359.         return 0;
  360.     }
  361.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  362. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement