alien_fx_fiend

Binary Tree Visualizer Missing Slash But DoubleSlash *FINAL RELEASE*

Nov 3rd, 2024 (edited)
34
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 17.01 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 <map>
  15. #include <richedit.h> // Include for Rich Edit control
  16. #include <shellapi.h>
  17. #include "resource.h"
  18.  
  19. #pragma comment(lib, "Psapi.lib")
  20. #pragma comment(lib, "comctl32.lib") // Link with the common controls library
  21. //#pragma comment(lib, "riched32.lib")  // Link with the rich edit library
  22. #pragma comment(lib, "Shell32.lib")
  23.  
  24. #define WIN_WIDTH 550
  25. #define WIN_HEIGHT 400
  26.  
  27. // Structure for a binary tree node
  28. struct Node {
  29.     int data;
  30.     Node* left;
  31.     Node* right;
  32.  
  33.     Node(int val) : data(val), left(nullptr), right(nullptr) {}
  34. };
  35.  
  36. // Function to insert a new node into the binary tree
  37. Node* insert(Node* root, int val) {
  38.     if (!root) {
  39.         return new Node(val);
  40.     }
  41.  
  42.     if (val < root->data) {
  43.         root->left = insert(root->left, val);
  44.     }
  45.     else {
  46.         root->right = insert(root->right, val);
  47.     }
  48.     return root;
  49. }
  50.  
  51.  
  52. // Helper function to get the height of the tree
  53. int getHeight(Node* root) {
  54.     if (!root) return 0;
  55.     return 1 + std::max(getHeight(root->left), getHeight(root->right));
  56. }
  57.  
  58. // Helper function to add padding
  59. std::string getPadding(int level) {
  60.     return std::string(level * 6, ' ');
  61. }
  62.  
  63. std::string getListString(Node* root, std::string prefix = "") {
  64.     if (!root) return "";
  65.  
  66.     std::string result = prefix + "|_ " + std::to_string(root->data) + "\r\n";
  67.  
  68.     if (root->left) {
  69.         bool hasRight = (root->right != nullptr);
  70.         std::string newPrefix = prefix + (hasRight ? "|  " : "   ");
  71.         result += getListString(root->left, newPrefix);
  72.     }
  73.  
  74.     if (root->right) {
  75.         std::string newPrefix = prefix + "   ";
  76.         result += getListString(root->right, newPrefix);
  77.     }
  78.  
  79.     return result;
  80. }
  81.  
  82. void deleteTree(Node* node) {
  83.     if (node) {
  84.         deleteTree(node->left);
  85.         deleteTree(node->right);
  86.         delete node;
  87.     }
  88. }
  89.  
  90. // Modified getTreeString function with correct lambda capture
  91. std::string getTreeString(Node* root) {
  92.     if (!root) return "";
  93.  
  94.     struct NodePosition {
  95.         int x;          // x coordinate
  96.         int width;      // node width
  97.         int parentX;    // parent's x coordinate
  98.         int depth;      // depth in tree
  99.         bool isLeft;    // is left child
  100.         Node* node;     // pointer to actual node
  101.     };
  102.  
  103.     std::vector<std::string> levels;
  104.     std::vector<NodePosition> nodePositions;
  105.     int maxLevelWidth = 0;
  106.     const int BASE_OFFSET = 25; //orig 40
  107.     const int MIN_SPACING = 3; //orig 4
  108.  
  109.     // First pass: Calculate positions and store node information
  110.     std::function<void(Node*, int, int, int, bool)> calculatePositions =
  111.         [&](Node* node, int depth, int x, int parentX, bool isLeft) {
  112.         if (!node) return;
  113.  
  114.         std::string nodeStr = std::to_string(node->data);
  115.         int nodeWidth = nodeStr.length();
  116.  
  117.         // Store node information
  118.         nodePositions.push_back({
  119.             x,          // x coordinate
  120.             nodeWidth,  // width
  121.             parentX,    // parent x
  122.             depth,      // depth
  123.             isLeft,     // is left child
  124.             node       // node pointer
  125.             });
  126.  
  127.         // Calculate spacing based on depth and node width
  128.         int spacing = std::max(MIN_SPACING, nodeWidth + 2);
  129.         if (depth > 4) {
  130.             spacing = std::max(3, spacing - (depth - 4) / 2);
  131.         }
  132.  
  133.         // Calculate children positions
  134.         if (node->left) {
  135.             calculatePositions(node->left, depth + 2, x - spacing, x, true);
  136.         }
  137.         if (node->right) {
  138.             calculatePositions(node->right, depth + 2, x + spacing, x + nodeWidth - 1, false);
  139.         }
  140.     };
  141.  
  142.     // Second pass: Draw nodes and validate connections
  143.     std::function<void(const NodePosition&)> drawNode =
  144.         [&](const NodePosition& pos) {
  145.         // Ensure enough levels
  146.         while (levels.size() <= pos.depth + 1) {
  147.             levels.push_back(std::string());
  148.         }
  149.  
  150.         // Extend level if needed
  151.         if (levels[pos.depth].length() <= pos.x + pos.width) {
  152.             levels[pos.depth].resize(pos.x + pos.width + 1, ' ');
  153.         }
  154.  
  155.         // Place node value
  156.         std::string nodeStr = std::to_string(pos.node->data);
  157.         levels[pos.depth].replace(pos.x, pos.width, nodeStr);
  158.  
  159.         // Handle branch to parent (if not root)
  160.         if (pos.depth > 0) {
  161.             int branchRow = pos.depth - 1;
  162.  
  163.             // Ensure branch level is wide enough
  164.             int maxX = std::max(pos.x + pos.width, pos.parentX) + 1;
  165.             if (levels[branchRow].length() <= maxX) {
  166.                 levels[branchRow].resize(maxX + 1, ' ');
  167.             }
  168.  
  169.             // Clear existing branches in the area
  170.             for (int i = std::min(pos.x, pos.parentX); i <= std::max(pos.x + pos.width, pos.parentX); i++) {
  171.                 if (levels[branchRow][i] != '/' && levels[branchRow][i] != '\\') {
  172.                     levels[branchRow][i] = ' ';
  173.                 }
  174.             }
  175.  
  176.             // Place branch character
  177.             if (pos.isLeft) {
  178.                 levels[branchRow][pos.x + pos.width - 1] = '/';
  179.             }
  180.             else {
  181.                 levels[branchRow][pos.x] = '\\';
  182.             }
  183.         }
  184.  
  185.         maxLevelWidth = std::max(maxLevelWidth, (int)levels[pos.depth].length());
  186.     };
  187.  
  188.     // Third pass: Validate and fix connections
  189.     auto validateConnections = [&]() {
  190.         for (size_t i = 1; i < levels.size(); i++) {
  191.             std::vector<bool> hasConnection(levels[i].length(), false);
  192.  
  193.             // Mark existing connections
  194.             for (const auto& pos : nodePositions) {
  195.                 if (pos.depth == i) {
  196.                     int start = std::max(0, pos.x - 2);
  197.                     int end = std::min((int)levels[i - 1].length() - 1, pos.x + pos.width + 1);
  198.                     for (int j = start; j <= end; j++) {
  199.                         if (levels[i - 1][j] == '/' || levels[i - 1][j] == '\\') {
  200.                             hasConnection[pos.x] = true;
  201.                             break;
  202.                         }
  203.                     }
  204.                 }
  205.             }
  206.  
  207.             // Fix missing connections
  208.             for (const auto& pos : nodePositions) {
  209.                 if (pos.depth == i && !hasConnection[pos.x]) {
  210.                     if (pos.isLeft) {
  211.                         if (pos.x + pos.width - 1 < levels[i - 1].length()) {
  212.                             levels[i - 1][pos.x + pos.width - 1] = '/';
  213.                         }
  214.                     }
  215.                     else {
  216.                         if (pos.x < levels[i - 1].length()) {
  217.                             levels[i - 1][pos.x] = '\\';
  218.                         }
  219.                     }
  220.                 }
  221.             }
  222.  
  223.             // Remove duplicate slashes
  224.             for (size_t j = 1; j < levels[i - 1].length(); j++) {
  225.                 if ((levels[i - 1][j] == '/' && levels[i - 1][j - 1] == '/') ||
  226.                     (levels[i - 1][j] == '\\' && levels[i - 1][j - 1] == '\\')) {
  227.                     levels[i - 1][j - 1] = ' ';
  228.                 }
  229.             }
  230.         }
  231.     };
  232.  
  233.     // Execute all passes
  234.     calculatePositions(root, 0, BASE_OFFSET, 0, false);
  235.  
  236.     // Sort nodes by depth for proper drawing order
  237.     std::sort(nodePositions.begin(), nodePositions.end(),
  238.         [](const NodePosition& a, const NodePosition& b) {
  239.             return a.depth < b.depth;
  240.         });
  241.  
  242.     // Draw all nodes
  243.     for (const auto& pos : nodePositions) {
  244.         drawNode(pos);
  245.     }
  246.  
  247.     // Validate and fix connections
  248.     validateConnections();
  249.  
  250.     // Build final string with proper alignment
  251.     std::string result;
  252.     for (const auto& level : levels) {
  253.         std::string trimmedLevel = level;
  254.         while (!trimmedLevel.empty() && trimmedLevel.back() == ' ') {
  255.             trimmedLevel.pop_back();
  256.         }
  257.         result += trimmedLevel + "\r\n";
  258.     }
  259.  
  260.     return result;
  261. }
  262.  
  263. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  264.  
  265. int WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE, PWSTR pCmdLine, int nCmdShow) {
  266.  
  267.     const wchar_t CLASS_NAME[] = L"BinaryTreeVisualizer (Graphing Application)";
  268.  
  269.     WNDCLASS wc = { };
  270.  
  271.     wc.lpfnWndProc = WindowProc;
  272.     wc.hInstance = hInstance;
  273.     wc.lpszClassName = CLASS_NAME;
  274.     wc.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON1));
  275.  
  276.     RegisterClass(&wc);
  277.  
  278.     // Remove WS_MAXIMIZEBOX and WS_THICKFRAME from the window style
  279.     DWORD style = (WS_OVERLAPPEDWINDOW & ~WS_MAXIMIZEBOX) & ~WS_THICKFRAME;
  280.  
  281.     // Get the screen dimensions
  282.     int screenWidth = GetSystemMetrics(SM_CXSCREEN);
  283.     int screenHeight = GetSystemMetrics(SM_CYSCREEN);
  284.  
  285.     // Calculate the window position to center it
  286.     int windowWidth = WIN_WIDTH + 16;
  287.     int windowHeight = WIN_HEIGHT + 39;
  288.     int posX = (screenWidth - windowWidth) / 2;
  289.     int posY = (screenHeight - windowHeight) / 2;
  290.  
  291.     HWND hwnd = CreateWindowEx(
  292.         0,                              // Optional window styles.
  293.         CLASS_NAME,                     // Window class
  294.         L"Binary Tree Visualizer (MathxCore) F1=About",    // Window text
  295.         style,            // Window style
  296.  
  297.         posX, posY, 535, 385,
  298.  
  299.         NULL,       // Parent window    
  300.         NULL,       // Menu
  301.         hInstance,  // Instance handle
  302.         NULL        // Additional application data
  303.     );
  304.  
  305.     if (hwnd == NULL) {
  306.         return 0;
  307.     }
  308.  
  309.     ShowWindow(hwnd, nCmdShow);
  310.  
  311.     // Run the message loop.
  312.     MSG msg = { };
  313.     while (GetMessage(&msg, NULL, 0, 0)) {
  314.         TranslateMessage(&msg);
  315.         DispatchMessage(&msg);
  316.     }
  317.  
  318.     return 0;
  319. }
  320.  
  321. LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  322.     static HWND hEdit, hDisplay, hTreeViewRadio, hListViewRadio, hGenerateButton;
  323.     static Node* root = nullptr;
  324.  
  325.     switch (uMsg) {
  326.     case WM_CREATE: {
  327.         // Create Input Field
  328.         hEdit = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
  329.             WS_CHILD | WS_VISIBLE | WS_BORDER,
  330.             10, 10, 100, 20, hwnd, NULL, NULL, NULL);
  331.  
  332.         // Create multiline Edit control for display
  333.             // Create display Edit control with proper styles for newlines
  334.         hDisplay = CreateWindowEx(WS_EX_CLIENTEDGE, L"EDIT", L"",
  335.             WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_HSCROLL |
  336.             ES_MULTILINE | ES_AUTOVSCROLL | ES_AUTOHSCROLL | ES_READONLY | ES_LEFT,
  337.             10, 40, 510, 300, hwnd, NULL, NULL, NULL);
  338.  
  339.         // Radio Buttons
  340.         hTreeViewRadio = CreateWindowEx(0, L"BUTTON", L"Tree View",
  341.             WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON | WS_GROUP,
  342.             120, 10, 100, 20, hwnd, (HMENU)1, NULL, NULL);
  343.  
  344.         hListViewRadio = CreateWindowEx(0, L"BUTTON", L"List View",
  345.             WS_CHILD | WS_VISIBLE | BS_AUTORADIOBUTTON,
  346.             230, 10, 100, 20, hwnd, (HMENU)2, NULL, NULL);
  347.  
  348.         // Generate Button
  349.         hGenerateButton = CreateWindowEx(0, L"BUTTON", L"Generate Tree",
  350.             WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,
  351.             340, 10, 100, 20, hwnd, (HMENU)3, NULL, NULL);
  352.  
  353.         Button_SetCheck(hTreeViewRadio, BST_CHECKED);
  354.  
  355.         // Set monospace font
  356.             // Set monospace font for better tree display
  357.         HFONT hFont = CreateFont(16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
  358.             DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
  359.             DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, L"Consolas");
  360.  
  361.         SendMessage(hDisplay, WM_SETFONT, (WPARAM)hFont, TRUE);
  362.  
  363.         // Set tab stops for the display Edit control (optional)
  364.         DWORD tabStops = 16; // in dialog units
  365.         SendMessage(hDisplay, EM_SETTABSTOPS, 1, (LPARAM)&tabStops);
  366.  
  367.         // Set text alignment to center
  368.         //SendMessage(hDisplay, EM_SETALIGNMENT, ES_CENTER, 0);
  369.  
  370.         break;
  371.     }
  372.  
  373.     case WM_COMMAND:
  374.         if (LOWORD(wParam) == 3) { // Generate button clicked
  375.             wchar_t buffer[256];
  376.             GetWindowText(hEdit, buffer, 256);
  377.  
  378.             wchar_t* endptr;
  379.             long numNodes = std::wcstol(buffer, &endptr, 10);
  380.  
  381.             if (*endptr == L'\0' && numNodes > 0 && numNodes <= 100) {
  382.                 // Delete old tree
  383.                 if (root != nullptr) {
  384.                     deleteTree(root);
  385.                     root = nullptr;
  386.                 }
  387.  
  388.                 // Generate new tree
  389.                 try {
  390.                     std::vector<int> numbers(numNodes);
  391.                     for (int i = 0; i < numNodes; ++i) {
  392.                         numbers[i] = i + 1;
  393.                     }
  394.  
  395.                     std::random_device rd;
  396.                     std::mt19937 g(rd());
  397.                     std::shuffle(numbers.begin(), numbers.end(), g);
  398.  
  399.                     for (int num : numbers) {
  400.                         root = insert(root, num);
  401.                     }
  402.  
  403.                     // Generate tree string
  404.                     std::string treeString;
  405.                     if (Button_GetCheck(hTreeViewRadio) == BST_CHECKED) {
  406.                         treeString = getTreeString(root);
  407.                     }
  408.                     else {
  409.                         treeString = getListString(root);
  410.                     }
  411.  
  412.                     // Convert to wide string and set text
  413.                     int size_needed = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), -1, NULL, 0);
  414.                     if (size_needed > 0) {
  415.                         std::vector<wchar_t> wideStr(size_needed);
  416.                         MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), -1, &wideStr[0], size_needed);
  417.                         SetWindowText(hDisplay, &wideStr[0]);
  418.                     }
  419.  
  420.                     // Scroll to top
  421.                     SendMessage(hDisplay, WM_VSCROLL, SB_TOP, 0);
  422.                     SendMessage(hDisplay, EM_SETSEL, 0, 0);
  423.                     SendMessage(hDisplay, EM_SCROLLCARET, 0, 0);
  424.                 }
  425.                 catch (const std::exception& e) {
  426.                     MessageBoxA(hwnd, e.what(), "Error", MB_OK | MB_ICONERROR);
  427.                 }
  428.             }
  429.             else {
  430.                 MessageBox(hwnd, L"Please enter a number between 1 and 100.",
  431.                     L"Invalid Input", MB_OK | MB_ICONWARNING);
  432.             }
  433.             return 0;
  434.         }
  435.         else if (LOWORD(wParam) == 1 || LOWORD(wParam) == 2) {  // Radio button handling
  436.             if (root != nullptr) {
  437.                 std::string treeString;
  438.                 if (Button_GetCheck(hTreeViewRadio) == BST_CHECKED) {
  439.                     treeString = getTreeString(root);
  440.                     std::string::size_type pos = 0;
  441.                     while ((pos = treeString.find('\n', pos)) != std::string::npos) {
  442.                         treeString.replace(pos, 1, "\r\n");
  443.                         pos += 2;
  444.                     }
  445.                 }
  446.                 else {
  447.                     treeString = getListString(root);
  448.                 }
  449.  
  450.                 int size_needed = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), -1, NULL, 0);
  451.                 if (size_needed == 0) {
  452.                     OutputDebugString(L"MultiByteToWideChar failed (Radio)\n");
  453.                     break;
  454.                 }
  455.                 std::wstring wideStr(size_needed - 1, 0);
  456.                 int converted = MultiByteToWideChar(CP_UTF8, 0, treeString.c_str(), -1, &wideStr[0], size_needed);
  457.                 if (converted == 0) {
  458.                     OutputDebugString(L"MultiByteToWideChar failed (Radio)\n");
  459.                     break;
  460.                 }
  461.  
  462.                 SetWindowText(hDisplay, wideStr.c_str());
  463.  
  464.                 LONG_PTR style = GetWindowLongPtr(hDisplay, GWL_STYLE);
  465.                 style |= ES_MULTILINE | ES_AUTOVSCROLL;
  466.                 SetWindowLongPtr(hDisplay, GWL_STYLE, style);
  467.  
  468.                 SendMessage(hDisplay, WM_VSCROLL, SB_TOP, 0);
  469.                 SendMessage(hDisplay, EM_SETSEL, 0, 0);
  470.                 SendMessage(hDisplay, EM_SCROLLCARET, 0, 0);
  471.             }
  472.         }
  473.         break;
  474.  
  475.         case WM_KEYDOWN:
  476.             if (wParam == VK_ESCAPE) {
  477.                 PostQuitMessage(0);
  478.                 return 0;
  479.             }
  480.             // Add this new code block
  481.             else if (wParam == VK_F1) {
  482.                 MessageBox(hwnd, TEXT("Tree/ List Diagrams (incorporates robust GDI drawing techniques) Programmed in C++ Win32 API (479 lines of code) by Entisoft Software (c) Evans Thorpemorton"), TEXT("Information"), MB_OK | MB_ICONINFORMATION);
  483.                 return 0;
  484.             }
  485.             break;
  486.  
  487.     case WM_DESTROY:
  488.         delete root; // Clean up
  489.         PostQuitMessage(0);
  490.         return 0;
  491.     }
  492.     return DefWindowProc(hwnd, uMsg, wParam, lParam);
  493. }
Tags: #alldone!
Add Comment
Please, Sign In to add comment