/*--------------------------------------------------------- WinTree2.cpp Use classes for data functions for data handling. UNICODE Not fully supported in 98, so TCHAR will be used instead of char, windows will convert to char. If using fully supporting UNICODE OPSYS then convert all string calls to UNICODE ws*** string handlers. This is standard Charles Petzold windows api starter. "All hale Petzold!" ---------------------------------------------------------*/ #include #include "WinTree2.h" // Holds classes, function definitions, and const. // Standard Petzold window WinMain... LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow) { static TCHAR szAppName[] = TEXT ("WinTree2") ; HWND hwnd ; MSG msg ; WNDCLASS wndclass ; wndclass.style = CS_HREDRAW | CS_VREDRAW ; wndclass.lpfnWndProc = WndProc ; wndclass.cbClsExtra = 0 ; wndclass.cbWndExtra = 0 ; wndclass.hInstance = hInstance ; wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION) ; wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ; wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ; wndclass.lpszMenuName = NULL ; wndclass.lpszClassName = szAppName ; RegisterClass (&wndclass) ; hwnd = CreateWindow (szAppName, TEXT ("Windows Last Left Threaded Tree 2.0.1.0"), WS_OVERLAPPEDWINDOW | WS_VSCROLL | WS_HSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL) ; ShowWindow (hwnd, iCmdShow) ; UpdateWindow (hwnd) ; while (GetMessage (&msg, NULL, 0, 0)) { TranslateMessage (&msg) ; DispatchMessage (&msg) ; } return msg.wParam ; } // Petzold WndProc Modified... LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { static int cxChar, cxCaps, cyChar, cxClient, cyClient, iMaxWidth, xCaret, yCaret ; int i, x, y, iVertPos, iHorzPos, iPaintBeg, iPaintEnd, iInPut ; const int NUMLINES = 27 ; static TCHAR szBuffer_7[2] ; // To hold last node removed key value. static TCHAR szBuffer_6[2] ; static TCHAR szBuffer_5[2] ; static TCHAR szBuffer_4[99] ; static TCHAR szBuffer_3[2] ; // szBuffer_* used to hold output, and special messages. static TCHAR szBuffer_2[80] ; static TCHAR szBuffer_1[2] ; static TCHAR szBuffer[2] ; // szBuffer used in wsprintf TCHAR tC ; // Used in reading user input on node to remove. TCHAR* pC ; HDC hdc ; PAINTSTRUCT ps ; // Standard Windows structors. TEXTMETRIC tm ; RECT rect ; SCROLLINFO si ; rect.left = cxChar * 36 ; // Screen coordinates use in InvalidateRect (hwnd, &rect, TRUE) ; rect.top = 0 ; rect.right = cxChar * 160 ; rect.bottom = cyChar * 11 ; static TreeNode *pRoot = CreateTree(); // Tree is made up out of these classes. static TreeData *pTD = new TreeData(pRoot); // Holds Tree data, pointer to root... static bool fDoesTreeExist = FALSE ; // Use these flags in the WM_ messages below. static bool fTreeDataChanged ; static bool fDrawHeaders = TRUE ; static bool fRemoveLestSigNode = FALSE ; static bool fShowCaret = FALSE ; // If tree data shown then show caret. static bool fNodeNotCurrentTreeMember = FALSE ; // If user enters a key value of a node that is not current in tree. int stop ; stop = 1 ; // Debug stop. switch (message) { case WM_CREATE: // Petzold standard simple windows stuff. hdc = GetDC (hwnd) ; GetTextMetrics (hdc, &tm) ; cxChar = tm.tmAveCharWidth ; cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ; cyChar = tm.tmHeight + tm.tmExternalLeading ; ReleaseDC (hwnd, hdc) ; // Null out the szBuffer_*s at start up strcpy( szBuffer, "\0" ); strcpy( szBuffer_1, "\0" ); strcpy( szBuffer_2, "\0" ); strcpy( szBuffer_3, "\0" ); strcpy( szBuffer_4, "\0" ); strcpy( szBuffer_6, "\0" ); strcpy( szBuffer_7, "\0" ); // Save Max width needed for window. iMaxWidth = 26 * cxChar + 26 * cxCaps + 22 * cxCaps + strlen("Current Tree Data Members are..... : ") ; return 0 ; case WM_SIZE: cxClient = LOWORD (lParam) ; cyClient = HIWORD (lParam) ; // Set vertical scroll bar range and page size si.cbSize = sizeof (si) ; si.fMask = SIF_RANGE | SIF_PAGE ; si.nMin = 0 ; si.nMax = NUMLINES + 1 ; si.nPage = cyClient / cyChar ; SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ; // Set horizontal scroll bar range and page size si.cbSize = sizeof (si) ; si.fMask = SIF_RANGE | SIF_PAGE ; si.nMin = 0 ; si.nMax = 2 + iMaxWidth / cxChar ; si.nPage = cxClient / cxChar ; SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ; return 0 ; case WM_SETFOCUS: // Create and show the caret xCaret = cxChar * 47 ; yCaret = cyChar * 20 ; CreateCaret (hwnd, NULL, cxChar, cyChar); SetCaretPos (xCaret , yCaret ) ; ShowCaret (hwnd); return 0 ; case WM_KILLFOCUS: // hide and detroy the caret. HideCaret (hwnd) ; DestroyCaret () ; return 0 ; case WM_VSCROLL: // Get all the vertical scroll bar information si.cbSize = sizeof (si) ; si.fMask = SIF_ALL ; GetScrollInfo (hwnd, SB_VERT, &si) ; // Save the position for comparison later on iVertPos = si.nPos ; switch (LOWORD (wParam)) { case SB_TOP: si.nPos = si.nMin ; break ; case SB_BOTTOM: si.nPos = si.nMax ; break ; case SB_LINEUP: si.nPos -= 1 ; break ; case SB_LINEDOWN: si.nPos += 1 ; break ; case SB_PAGEUP: si.nPos -= si.nPage ; break ; case SB_PAGEDOWN: si.nPos += si.nPage ; break ; case SB_THUMBTRACK: si.nPos = si.nTrackPos ; break ; } // Set the position and then retrieve it. Due to adjustments // by Windows it might not be the same as the value set. si.fMask = SIF_POS ; SetScrollInfo (hwnd, SB_VERT, &si, TRUE) ; GetScrollInfo (hwnd, SB_VERT, &si) ; // If the position has changed, scroll the window and update it if (si.nPos != iVertPos) { ScrollWindow (hwnd, 0, cyChar * (iVertPos - si.nPos), NULL, NULL) ; UpdateWindow (hwnd) ; } return 0 ; case WM_HSCROLL: // Get all the vertical scroll bar information si.cbSize = sizeof (si) ; si.fMask = SIF_ALL ; // Save the position for comparison later on GetScrollInfo (hwnd, SB_HORZ, &si) ; iHorzPos = si.nPos ; switch (LOWORD (wParam)) { case SB_LINELEFT: si.nPos -= 1 ; break ; case SB_LINERIGHT: si.nPos += 1 ; break ; case SB_PAGELEFT: si.nPos -= si.nPage ; break ; case SB_PAGERIGHT: si.nPos += si.nPage ; break ; case SB_THUMBPOSITION: si.nPos = si.nTrackPos ; break ; default: break ; } // Set the position and then retrieve it. Due to adjustments // by Windows it might not be the same as the value set. si.fMask = SIF_POS ; SetScrollInfo (hwnd, SB_HORZ, &si, TRUE) ; GetScrollInfo (hwnd, SB_HORZ, &si) ; // If the position has changed, scroll the window if (si.nPos != iHorzPos) { ScrollWindow (hwnd, cxChar * (iHorzPos - si.nPos), 0, NULL, NULL) ; } return 0 ; case WM_RBUTTONUP: // For future use. break ; case WM_LBUTTONUP: // For future use. break ; // WM_KEYDOWN // nVirtKey = (int) wParam; // virtual-key code // lKeyData = lParam; // key data case WM_CHAR: // To read in user's input on which node to remove. if( (wParam >= 65 && wParam <= 90) || (wParam >= 97 && wParam <= 122) ) { tC = (TCHAR) wParam ; pC = &tC ; strncpy( szBuffer, pC, 1 ) ; if( fDoesTreeExist = DoesTreeExist(pTD) ) // Check does tree exist function, if it does not exist, then { pTD->SetNodeToBeRemoved( szBuffer ) ; if( FetchNodeData( pTD ) ) { PreRemoveNode(pRoot, pTD, szBuffer_1, szBuffer_2, szBuffer_3, szBuffer_5, szBuffer_6, szBuffer_7 ) ; if( pTD->FetchPointerToRoot() != pRoot ) // If root node was removed/replaced reset WinProc's root pointer. pRoot = pTD->FetchPointerToRoot() ; } // End 'if' on "FetchNodeData" else { strcpy( pTD->FetchCurrentTreeMembers(), "Node Key Value Not Current Data Tree Member." ); // Yes this does work. strcpy( szBuffer_2, pTD->FetchCurrentTreeMembers() ); HideCaret (hwnd) ; DestroyCaret () ; } // End 'else' }// End 'if' on "fDoesTreeExist" InvalidateRect (hwnd, &rect, TRUE) ; UpdateWindow(hwnd); break ; } // End top 'if' int stop ; stop = 1 ; if( wParam != 32 ) { if( fDoesTreeExist ) strcpy( pTD->FetchCurrentTreeMembers(), "Node Key Value Not Legitimate." ); // Yes this does work. else strcpy( pTD->FetchCurrentTreeMembers(), "No Tree Exist!" ); // Yes this does work. strcpy( szBuffer_2, pTD->FetchCurrentTreeMembers() ); HideCaret (hwnd) ; DestroyCaret () ; InvalidateRect (hwnd, &rect, TRUE) ; UpdateWindow(hwnd); } break ; case WM_KEYDOWN: switch (wParam) { case VK_HOME: SendMessage (hwnd, WM_VSCROLL, SB_TOP, 0) ; break ; case VK_END: SendMessage (hwnd, WM_VSCROLL, SB_BOTTOM, 0) ; break ; case VK_PRIOR: SendMessage (hwnd, WM_VSCROLL, SB_PAGEUP, 0) ; break ; case VK_NEXT: SendMessage (hwnd, WM_VSCROLL, SB_PAGEDOWN, 0) ; break ; case VK_LEFT: // Left arrow key if( fDoesTreeExist = DoesTreeExist(pTD) ) // Check does tree exist function, if it does not exist, then { FetchAllTreeData(pTD) ; // This will load the data members of class TreeData pTD->SetPointerNodeToBeRemoved(pTD->FetchPointerLestSignificantNode()) ; // Sets node to be removed. PreRemoveNode(pRoot, pTD, szBuffer_1, szBuffer_2, szBuffer_3, szBuffer_5, szBuffer_6, szBuffer_7 ) ; // PreRemoveNode will call RemoveNode. if( pTD->FetchPointerToRoot() != pRoot ) // If root node was removed/replaced reset WinProc's root pointer. pRoot = pTD->FetchPointerToRoot() ; } InvalidateRect (hwnd, &rect, TRUE) ; // Force windows to repaint WinTree2's window so new data will be shown. UpdateWindow(hwnd); break ; case VK_UP: // Up arrow key. if( fDoesTreeExist = DoesTreeExist(pTD) ) // Check does tree exist function, if it does not exist, then { FetchAllTreeData(pTD) ; pTD->SetPointerNodeToBeRemoved( pTD->FetchPointerToRoot() ) ; PreRemoveNode(pRoot, pTD, szBuffer_1, szBuffer_2, szBuffer_3, szBuffer_5, szBuffer_6, szBuffer_7 ) ; if( pTD->FetchPointerToRoot() != pRoot ) // If root node was removed/replaced reset WinProc's root pointer. pRoot = pTD->FetchPointerToRoot() ; } InvalidateRect (hwnd, &rect, TRUE) ; UpdateWindow(hwnd); break ; case VK_RIGHT: // Right arrow key. if( fDoesTreeExist = DoesTreeExist(pTD) ) // Check does tree exist function, if it does not exist, then { FetchAllTreeData(pTD) ; pTD->SetPointerNodeToBeRemoved(pTD->FetchPointerMostSignificantNode()) ; PreRemoveNode(pRoot, pTD, szBuffer_1, szBuffer_2, szBuffer_3, szBuffer_5, szBuffer_6, szBuffer_7 ) ; } InvalidateRect (hwnd, &rect, TRUE) ; UpdateWindow(hwnd); break ; case VK_DOWN: // Down arrow key. if( fDoesTreeExist = DoesTreeExist(pTD) ) // Check does tree exist function, if it does not exist, then { FetchAllTreeData(pTD) ; pTD->SetPointerNodeToBeRemoved(pTD->FetchPointerMedianNode()) ; PreRemoveNode(pRoot, pTD, szBuffer_1, szBuffer_2, szBuffer_3, szBuffer_5, szBuffer_6, szBuffer_7 ) ; } InvalidateRect (hwnd, &rect, TRUE) ; UpdateWindow(hwnd); break ; case VK_SPACE: // Space bar will fetch the current tree data. { strcpy( szBuffer_1, "\0" ); strcpy( szBuffer_2, "\0" ); strcpy( szBuffer_3, "\0" ); strcpy( szBuffer_5, "\0" ); strcpy( szBuffer_7, "\0" ); if( fDoesTreeExist = DoesTreeExist(pTD) ) // Check does tree exist function, if it does not exist, then { // no data to get. pTD->VoidOutCurrentTreeMembers() ; // pTD is pointer to class that is used to pick up all tree data. FetchAllTreeData(pTD) ; // null out the old tree data before you pick up the new. strcpy( szBuffer_1, ( ( pTD->FetchPointerToRoot() )->FetchTreeNodeData() ) ); // root data strcpy( szBuffer_2, pTD->FetchCurrentTreeMembers() ); // current tree data strcpy( szBuffer_3, ( (pTD->FetchPointerLestSignificantNode())->FetchTreeNodeData() ) ); // lest sig node strcpy( szBuffer_5, ( (pTD->FetchPointerMostSignificantNode())->FetchTreeNodeData() ) ); // most sig node strcpy( szBuffer_6, ( (pTD->FetchPointerMedianNode())->FetchTreeNodeData() ) ); // median node strcpy( szBuffer_7, ( (pTD->FetchLastNodeRemoved() ) ) ); // last node removed with this key value }else{ // Tree does not exist. strcpy( pTD->FetchCurrentTreeMembers(), "No Tree Exist!" ); // Yes this does work. strcpy( szBuffer_2, pTD->FetchCurrentTreeMembers() ); HideCaret (hwnd) ; DestroyCaret () ; }// End of if...else... fDrawHeaders = FALSE ; // SO only draw the new tree data... InvalidateRect (hwnd, &rect, TRUE) ; // This will force windows paint the output area of the client space. UpdateWindow(hwnd); break ; case VK_CONTROL : // Ctrl key will send to WinMain the WM_DESTROY message that will delete pTD and by that trip // TreeData's de-structor that will del out any remaining tree members. SendMessage (hwnd, WM_DESTROY, 0, 0 ) ; break ; } // End of VK_SPACE ... } // End of switch on wParam ... return 0 ; case WM_PAINT: hdc = BeginPaint (hwnd, &ps) ; // Get vertical scroll bar position si.cbSize = sizeof (si) ; si.fMask = SIF_POS ; GetScrollInfo (hwnd, SB_VERT, &si) ; iVertPos = si.nPos ; // Get horizontal scroll bar position GetScrollInfo (hwnd, SB_HORZ, &si) ; iHorzPos = si.nPos ; // Find painting limits iPaintBeg = max (0, iVertPos + ps.rcPaint.top / cyChar) ; iPaintEnd = min (NUMLINES - 1, iVertPos + ps.rcPaint.bottom / cyChar) ; // x = cxChar * (1 - iHorzPos) ; // y = cyChar * (i - iVertPos) ; // With the Headers in the 'if' app. only redraws them when the window is reformed, not when new data is displayed. // This save some time on redraw rate. TextOut (hdc, cxChar * 36, cyChar * (2 + iVertPos) , szBuffer_1, strlen( szBuffer_1 ) ) ; TextOut (hdc, cxChar * 36, cyChar * (4 + iVertPos) , szBuffer_2, strlen( szBuffer_2 ) ) ; TextOut (hdc, cxChar * 36, cyChar * (6 + iVertPos) , szBuffer_3, strlen( szBuffer_3 ) ) ; TextOut (hdc, cxChar * 36, cyChar * (7 + iVertPos) , szBuffer_5, strlen( szBuffer_5 ) ) ; TextOut (hdc, cxChar * 36, cyChar * (8 + iVertPos) , szBuffer_6, strlen( szBuffer_6 ) ) ; TextOut (hdc, cxChar * 36, cyChar * (10 + iVertPos) , szBuffer_7, strlen( szBuffer_7 ) ) ; //SetTextAlign (hdc, TA_RIGHT | TA_TOP) ; SetTextAlign (hdc, TA_LEFT | TA_TOP) ; if(pTD->FetchCurrentTreeMemberCount( ) > 0 ) // This way 0 value not shown. { TextOut (hdc, cxChar * 36, cyChar * 9 , szBuffer, wsprintf( szBuffer, TEXT("%2d"), pTD->FetchCurrentTreeMemberCount( ) ) ) ; SendMessage (hwnd, WM_SETFOCUS, 0, 0) ; // Show caret when tree data shown. } else { SendMessage (hwnd, WM_KILLFOCUS, 0, 0) ; // Kill caret when "No Tree Exist!" } if( fDrawHeaders ) { // fDrawHeaders Set to FALSE in the WM_RBUTTONUP: so headers not redrawn, any other window activity will redraw headers along with rest of window. TextOut (hdc, cxChar, cyChar * (2 + iVertPos), "Current Tree Root Data Member is. : ", strlen( "Current Tree Root Data Member is. : " ) ) ; TextOut (hdc, cxChar, cyChar * (4 + iVertPos), "Current Tree Data Members are..... : ", strlen( "Current Tree Data Members are..... : " ) ) ; TextOut (hdc, cxChar, cyChar * (6 + iVertPos), "Lest Significant Node is.................. : ", strlen( "Lest Significant Node is.................. : " ) ) ; TextOut (hdc, cxChar, cyChar * (7 + iVertPos), "Most Significant Node is................. : ", strlen( "Most Significant Node is................. : " ) ) ; TextOut (hdc, cxChar, cyChar * (8 + iVertPos), "Median Node is............................... : ", strlen( "Median Node is............................... : " ) ) ; TextOut (hdc, cxChar, cyChar * (9 + iVertPos), "Current Number of Tree Members... :", strlen( "Current Number of Tree Members... :" ) ) ; TextOut (hdc, cxChar, cyChar * (10 + iVertPos), "Last Node Removed.........................:", strlen( "Last Node Removed.........................:" ) ) ; TextOut (hdc, cxChar, cyChar * (12 + iVertPos), "Last Left Threaded Data Tree is created at application start.", strlen( "Last Left Threaded Data Tree is created at application start." ) ) ; TextOut (hdc, cxChar, cyChar * (14 + iVertPos), "Space Bar: display tree member information.", strlen("Space Bar: display tree member information." ) ) ; TextOut (hdc, cxChar, cyChar * (15 + iVertPos), "Left Arrow: remove lest significant tree member.", strlen("Left Arrow: remove lest significant tree member." ) ) ; TextOut (hdc, cxChar, cyChar * (16 + iVertPos), "Right Arrow: remove most significant tree member.", strlen("Right Arrow: remove most significant tree member." ) ) ; TextOut (hdc, cxChar, cyChar * (17 + iVertPos), "Up Arrow: remove root tree member.", strlen("Up Arrow: remove root tree member." ) ) ; TextOut (hdc, cxChar, cyChar * (18 + iVertPos), "Down Arrow: remove median tree member.", strlen("Down Arrow: remove median tree member." ) ) ; TextOut (hdc, cxChar, cyChar * (20 + iVertPos), "To remove a specific node enter it's key value. -->", strlen("To remove a specific node enter it's key value. -->" ) ) ; TextOut (hdc, cxChar, cyChar * (24 + iVertPos), "Once the last data member is removed the tree no longer exist.", strlen( "Once the last data member is removed the tree no longer exist." ) ) ; TextOut (hdc, cxChar, cyChar * (27 + iVertPos), "Ctrl: To exit aplication.", strlen("Ctrl: To exit aplication.") ) ; } fDrawHeaders = TRUE ; EndPaint (hwnd, &ps) ; return 0 ; case WM_DESTROY: delete pTD ; PostQuitMessage (0) ; return 0 ; } // End of switch on message return DefWindowProc (hwnd, message, wParam, lParam) ; } // End WinProc ...