/****************************************************************************/ /* */ /* WFTREE.C - */ /* */ /* Windows File System Tree Window Proc Routines */ /* */ /****************************************************************************/ #include "winfile.h" #include "winnet.h" #include "lfn.h" #include "wfcopy.h" HICON NEAR PASCAL GetTreeIcon(HWND hWnd); #ifdef LFN VOID APIENTRY CheckEscapes(LPSTR); #endif HICON NEAR PASCAL GetTreeIcon(HWND hWnd) { HWND hwndTree, hwndDir; hwndTree = HasTreeWindow(hWnd); hwndDir = HasDirWindow(hWnd); if (hwndTree && hwndDir) return hicoTreeDir; else if (hwndTree) return hicoTree; else return hicoDir; } VOID APIENTRY GetTreeWindows( HWND hwnd, PHWND phwndTree, PHWND phwndDir, PHWND phwndDrives) { if (phwndTree) { *phwndTree = GetDlgItem(hwnd, IDCW_TREECONTROL); } if (phwndDir) { *phwndDir = GetDlgItem(hwnd, IDCW_DIR); } if (phwndDrives) { *phwndDrives = GetDlgItem(hwnd, IDCW_DRIVES); } } // returns hwndTree, hwndDir or hwndDrives depending on the focus tracking // for the window. if none is found we return NULL HWND APIENTRY GetTreeFocus(HWND hwndTree) { HWND hwnd, hwndLast = NULL; hwndLast = hwnd = (HWND)GetWindowLong(hwndTree, GWL_LASTFOCUS); while (hwnd && hwnd != hwndTree) { hwndLast = hwnd; hwnd = GetParent(hwnd); } return hwndLast; } /*--------------------------------------------------------------------------*/ /* */ /* CompactPath() - */ /* */ /*--------------------------------------------------------------------------*/ BOOL APIENTRY CompactPath(HDC hDC, LPSTR lpszPath, WORD dx) { register INT len; INT dxFixed, dxT; LPSTR lpEnd; /* end of the unfixed string */ LPSTR lpFixed; /* start of text that we always display */ BOOL bEllipsesIn; CHAR szTemp[MAXPATHLEN]; /* Does it already fit? */ MGetTextExtent(hDC, lpszPath, lstrlen(lpszPath), &dxFixed, NULL); if (dxFixed <= (INT)dx) return(TRUE); /* Search backwards for the '\', and man, it better be there! */ #ifdef DBCS lpFixed = lpszPath + lstrlen(lpszPath); while (*lpFixed != '\\') lpFixed = AnsiPrev(lpszPath, lpFixed); #else lpFixed = lpszPath + lstrlen(lpszPath) - 1; while (*lpFixed != '\\') lpFixed--; #endif /* Save this guy to prevent overlap. */ lstrcpy(szTemp, lpFixed); lpEnd = lpFixed; bEllipsesIn = FALSE; MGetTextExtent(hDC, lpFixed, lstrlen(lpFixed), &dxFixed, NULL); while (TRUE) { MGetTextExtent(hDC, lpszPath, lpEnd - lpszPath, &dxT, NULL); len = dxFixed + dxT; if (bEllipsesIn) len += dxEllipses; if (len <= (INT)dx) break; bEllipsesIn = TRUE; if (lpEnd <= lpszPath) { /* Things didn't fit. */ lstrcpy(lpszPath, szEllipses); lstrcat(lpszPath, szTemp); return(FALSE); } /* Step back a character. */ #ifdef DBCS lpEnd = AnsiPrev(lpszPath, lpEnd); #else --lpEnd; #endif } if (bEllipsesIn) { lstrcpy(lpEnd, szEllipses); lstrcat(lpEnd, szTemp); } return(TRUE); } // // BOOL APIENTRY ResizeSplit(HWND hWnd, int dxSplit) // // creates/resizes children of the MDI child for the given path or resizes // (perhaps creating and destroying) these guys based on the dxSplit // parameter // // in: // hWnd window to fiddle with // dxSpit location of split between tree and dir panes // if less than size limit no tree is created // (current is destroyed) // if past limit on right margin the dir window // is destroyed (or not created) // // returns: // TRUE success, windows created // FALSE failure, windows failed creation, out of mem, or // the tree was in a state the couldn't be resized // BOOL APIENTRY ResizeSplit(HWND hWnd, INT dxSplit) { RECT rc; HWND hwndTree, hwndDir, hwndDrives, hwndLB; DWORD dwTemp; GetTreeWindows(hWnd, &hwndTree, &hwndDir, &hwndDrives); if (hwndTree && GetWindowLong(hwndTree, GWL_READLEVEL)) return FALSE; GetClientRect(hWnd, &rc); // create the drives if (!hwndDrives) { // make new drives window hwndDrives = CreateWindowEx(0, szDrivesClass, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, (HMENU)IDCW_DRIVES, hAppInstance, NULL); if (!hwndDrives) return FALSE; } if (dxSplit > dxDriveBitmap * 2) { if (!hwndTree) { // make new tree window hwndTree = CreateWindowEx(0, szTreeControlClass, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, (HMENU)IDCW_TREECONTROL, hAppInstance, NULL); if (!hwndTree) return FALSE; // only reset this if the dir window already // exists, that is we are creating the tree // by splitting open a dir window if (hwndDir) SendMessage(hwndTree, TC_SETDRIVE, MAKEWORD(FALSE, 0), 0L); } } else if (hwndTree) { // we are closing the tree window // If the directory window is empty, then set the focus to the // drives window. if (hwndDir) { hwndLB = GetDlgItem (hwndDir,IDCW_LISTBOX); if (hwndLB) { SendMessage (hwndLB,LB_GETTEXT,0,(LONG)(LPSTR) &dwTemp); if (!dwTemp) SetFocus (hwndDrives); } } DestroyWindow(hwndTree); dxSplit = 0; } if ((rc.right - dxSplit) > dxDriveBitmap * 2) { if (!hwndDir) { hwndDir = CreateWindowEx(0, szDirClass, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd,(HMENU)IDCW_DIR, hAppInstance, NULL); if (!hwndDir) return FALSE; } } else if (hwndDir) { DestroyWindow(hwndDir); dxSplit = rc.right; } UpdateStatus(hWnd); SetWindowLong(hWnd, GWL_SPLIT, dxSplit); return TRUE; } /*--------------------------------------------------------------------------*/ /* */ /* TreeWndProc() - */ /* */ /*--------------------------------------------------------------------------*/ /* WndProc for the MDI child window containing the drives, volume, and * directory tree child windows. */ LONG APIENTRY TreeWndProc(register HWND hWnd, UINT wMsg, register WPARAM wParam, LONG lParam) { HWND hwndTree, hwndDir, hwndDrives, hwndFocus; CHAR szDir[MAXPATHLEN]; RECT rc; HDC hdc; STKCHK(); switch (wMsg) { case WM_FILESYSCHANGE: MSG("TreeWndProc", "WM_FILESYSCHANGE"); if (hwndDir = HasDirWindow(hWnd)) SendMessage(hwndDir, wMsg, wParam, lParam); break; case FS_CHANGEDRIVES: MSG("TreeWndProc", "FS_CHANGEDRIVES"); { INT iNewDrive; if (!(hwndDrives = GetDlgItem(hWnd, IDCW_DRIVES))) break; DestroyWindow(hwndDrives); // see if this drive has gone, if so set this to the // last drive in the list iNewDrive = -1; if (!IsValidDisk((INT)GetWindowLong(hWnd, GWL_TYPE))) { iNewDrive = rgiDrive[cDrives - 1]; SetWindowLong(hWnd, GWL_TYPE, iNewDrive); } hwndDrives = CreateWindowEx(0, szDrivesClass, NULL, WS_CHILD | WS_VISIBLE, 0, 0, 0, 0, hWnd, (HMENU)IDCW_DRIVES, hAppInstance, NULL); if (!hwndDrives) return -1L; // Don't show the new stuff if the tree window is iconic if (IsIconic(hWnd)) break; /* HACK! Send SIZENOMDICRAP in the wParam of the size message. * This will re-compute the sizes of all three areas of * the tree window (in case the drive section grows or * shrinks) and not pass it the size message on to the * DefMDIChildProc() */ GetClientRect(hWnd, &rc); SendMessage(hWnd, WM_SIZE, SIZENOMDICRAP, MAKELONG(rc.right, rc.bottom)); // refresh the tree if necessary if (iNewDrive >= 0) { GetSelectedDirectory((WORD)(iNewDrive+1), szDir); SendMessage(GetDlgItem(hWnd, IDCW_TREECONTROL), TC_SETDRIVE, MAKEWORD(FALSE, 0), (LONG)szDir); } break; } case FS_GETSELECTION: { #define pfDir (BOOL *)lParam LPSTR p; MSG("TreeWndProc", "FS_GETSELECTION"); GetTreeWindows(hWnd, &hwndTree, &hwndDir, &hwndDrives); hwndFocus = GetTreeFocus(hWnd); if (hwndFocus == hwndDir || !hwndTree) { return SendMessage(hwndDir, FS_GETSELECTION, wParam, lParam); } else { p = (LPSTR)LocalAlloc(LPTR, MAXPATHLEN); if (p) { SendMessage(hWnd, FS_GETDIRECTORY, MAXPATHLEN, (DWORD)(LPSTR)p); StripBackslash(p); #ifdef LFN CheckEscapes(p); if (wParam == 2) { // BUG ??? wParam should be fMostRecentOnly if (pfDir) { *pfDir = IsLFN(p); } LocalFree((HANDLE)p); return (LONG)p; } #endif } if (pfDir) { *pfDir = TRUE; } return (LONG)p; } #undef pfDir } case FS_GETDIRECTORY: MSG("TreeWndProc", "FS_GETDIRECTORY"); // wParam is the length of the string pointed to by lParam // returns in lParam ANSI directory string with // a trailing backslash. if you want to do a SetCurrentDirecotor() // you must first StripBackslash() the thing! GetMDIWindowText(hWnd, (LPSTR)lParam, (INT)wParam); // get the string StripFilespec((LPSTR)lParam); // Remove the trailing extention AddBackslash((LPSTR)lParam); // terminate with a backslash break; case FS_GETFILESPEC: MSG("TreeWndProc", "FS_GETFILESPEC"); // returns the current filespec (from View.Include...). this is // an uppercase ANSI string GetMDIWindowText(hWnd, (LPSTR)lParam, (INT)wParam); StripPath((LPSTR)lParam); break; // redirect these messages to the drive icons to get the same result as // dropping on the active drive. // this is especially useful when we are minimized case WM_DRAGSELECT: case WM_QUERYDROPOBJECT: case WM_DROPOBJECT: MSG("TreeWndProc", "WM..OBJECT"); // Do nothing return(TRUE); if (hwndDrives = HasDrivesWindow(hWnd)) { return SendMessage(hwndDrives, wMsg, wParam, lParam); } if (hwndDir = HasDirWindow(hWnd)) { return SendMessage(hwndDir, wMsg, wParam, lParam); } break; case FS_GETDRIVE: MSG("TreeWndProc", "FS_GETDRIVE"); GetTreeWindows(hWnd, &hwndTree, &hwndDir, NULL); if (hwndTree) return SendMessage(hwndTree, wMsg, wParam, lParam); else return SendMessage(hwndDir, wMsg, wParam, lParam); break; case WM_CREATE: TRACE(BF_WM_CREATE, "TreeWndProc - WM_CREATE"); { INT dxSplit; WORD wDrive; // lpcs->lpszName is the path we are opening the // window for (has extension stuff "*.*") #define lpcs ((LPCREATESTRUCT)lParam) #define lpmdics ((LPMDICREATESTRUCT)(lpcs->lpCreateParams)) wDrive = lpcs->lpszName[0]; if (wDrive >= 'a') wDrive -= 'a'; else wDrive -= 'A'; SetWindowLong(hWnd, GWL_TYPE, wDrive); dxSplit = (SHORT)LOWORD(lpmdics->lParam); // if dxSplit is negative we split in the middle if (dxSplit < 0) dxSplit = lpcs->cx / 2; SetWindowLong(hWnd, GWL_SPLIT, dxSplit); SetWindowLong(hWnd, GWL_LASTFOCUS, 0); SetWindowLong(hWnd, GWL_FSCFLAG, FALSE); if (!ResizeSplit(hWnd, dxSplit)) return -1; GetTreeWindows(hWnd, &hwndTree, &hwndDir, NULL); SetWindowLong(hWnd, GWL_LASTFOCUS, (LONG)(hwndTree ? hwndTree : hwndDir)); break; } case WM_CLOSE: MSG("TreeWndProc", "WM_CLOSE"); // don't allow the last MDI child to be closed! if (hwndTree = HasTreeWindow(hWnd)) { // don't close if we are reading the tree if (GetWindowLong(hwndTree, GWL_READLEVEL)) break; } // don't leve current dir on floppies GetSystemDirectory(szDir, sizeof(szDir)); SheSetCurDrive(DRIVEID(szDir)); if (!IsLastWindow()) goto DEF_MDI_PROC; // this will close this window break; case WM_MDIACTIVATE: MSG("TreeWndProc", "WM_MDIACTIVATE"); if (GET_WM_MDIACTIVATE_FACTIVATE(hWnd, wParam, lParam)) { // we are receiving the activation lFreeSpace = -1L; UpdateStatus(hWnd); hwndFocus = (HWND)GetWindowLong(hWnd, GWL_LASTFOCUS); SetFocus(hwndFocus); } else if (hwndDrives = HasDrivesWindow(hWnd)) SendMessage(hwndDrives,wMsg,wParam,lParam); break; case WM_SETFOCUS: MSG("TreeWndProc", "WM_SETFOCUS"); hwndFocus = (HWND)GetWindowLong(hWnd, GWL_LASTFOCUS); SetFocus(hwndFocus); break; case WM_INITMENUPOPUP: MSG("TreeWndProc", "WM_INITMENUPOPUP"); if (HIWORD(lParam)) { EnableMenuItem((HMENU)wParam, SC_CLOSE, IsLastWindow() ? MF_BYCOMMAND | MF_DISABLED | MF_GRAYED : MF_ENABLED); } break; case WM_SYSCOMMAND: MSG("TreeWndProc", "WM_SYSCOMMAND"); if (wParam != SC_SPLIT) goto DEF_MDI_PROC; GetClientRect(hWnd, &rc); lParam = MAKELONG(rc.right / 2, 0); // fall through case WM_LBUTTONDOWN: MSG("TreeWndProc", "WM_LBUTTONDOWN"); { MSG msg; INT x, y, dx, dy; if (IsIconic(hWnd)) break; if (hwndDrives = GetDlgItem(hWnd, IDCW_DRIVES)) { GetClientRect(hwndDrives, &rc); y = rc.bottom; } else { y = 0; } x = LOWORD(lParam); GetClientRect(hWnd, &rc); dx = 4; dy = rc.bottom - y; // the height of the client less the drives window hdc = GetDC(hWnd); // split bar loop PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT); SetCapture(hWnd); while (GetMessage(&msg, NULL, 0, 0)) { if (msg.message == WM_KEYDOWN || msg.message == WM_SYSKEYDOWN || (msg.message >= WM_MOUSEFIRST && msg.message <= WM_MOUSELAST)) { if (msg.message == WM_LBUTTONUP || msg.message == WM_LBUTTONDOWN) break; if (msg.message == WM_KEYDOWN) { if (msg.wParam == VK_LEFT) { msg.message = WM_MOUSEMOVE; msg.pt.x -= 2; } else if (msg.wParam == VK_RIGHT) { msg.message = WM_MOUSEMOVE; msg.pt.x += 2; } else if (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE) { break; } SetCursorPos(msg.pt.x, msg.pt.y); } if (msg.message == WM_MOUSEMOVE) { // erase old PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT); ScreenToClient(hWnd, &msg.pt); x = msg.pt.x; // put down new PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT); } } else { DispatchMessage(&msg); } } ReleaseCapture(); // erase old PatBlt(hdc, x - dx / 2, y, dx, dy, PATINVERT); ReleaseDC(hWnd, hdc); if (msg.wParam != VK_ESCAPE) { if (ResizeSplit(hWnd, x)) SendMessage(hWnd, WM_SIZE, SIZENOMDICRAP, MAKELONG(rc.right, rc.bottom)); } break; } case WM_QUERYDRAGICON: MSG("TreeWndProc", "WM_QUERYDRAGICON"); return (LONG)GetTreeIcon(hWnd); break; case WM_ERASEBKGND: MSG("TreeWndProc", "WM_ERASEBKGND"); if (IsIconic(hWnd)) { // this paints the background of the icon properly, doing // brush allignment and other nasty stuff DefWindowProc(hWnd, WM_ICONERASEBKGND, wParam, 0L); } else { goto DEF_MDI_PROC; } break; case WM_PAINT: MSG("TreeWndProc", "WM_PAINT"); { PAINTSTRUCT ps; hdc = BeginPaint(hWnd, &ps); if (IsIconic(hWnd)) { DrawIcon(hdc, 0, 0, GetTreeIcon(hWnd)); } else { RECT rc2; GetClientRect(hWnd, &rc); rc.left = GetSplit(hWnd); if (rc.left >= rc.right) rc.left = 0; rc.right = rc.left + dxFrame; GetClientRect(HasDrivesWindow(hWnd), &rc2); rc2.top = rc2.bottom; rc2.bottom += dyBorder; rc2.left = rc.left; rc2.right = rc.right; FillRect(hdc, &rc2, GetStockObject(BLACK_BRUSH)); // draw the black pane handle rc.top = rc.bottom - GetSystemMetrics(SM_CYHSCROLL); FillRect(hdc, &rc, GetStockObject(BLACK_BRUSH)); } EndPaint(hWnd, &ps); break; } case WM_SIZE: if (wParam != SIZEICONIC) ResizeWindows(hWnd,LOWORD(lParam),HIWORD(lParam)); // if wParam is SIZENOMDICRAP this WM_SIZE was generated by us. // don't let this through to the DefMDIChildProc(). // that might change the min/max state, (show parameter) if (wParam == SIZENOMDICRAP) break; /*** FALL THRU ***/ default: DEF_MDI_PROC: return DefMDIChildProc(hWnd, wMsg, wParam, lParam); } return 0L; } VOID FAR PASCAL ResizeWindows(HWND hwndParent,WORD dxWindow, WORD dyWindow) { INT y, dy, split; INT cDriveRows, cDrivesPerRow; DWORD dw; HWND hwndTree,hwndDir,hwndDrives; GetTreeWindows(hwndParent, &hwndTree, &hwndDir, &hwndDrives); #ifdef OLD if (hwndDrives) #else if (FALSE) #endif { cDrivesPerRow = dxWindow / dxDrive; if (!cDrivesPerRow) cDrivesPerRow++; cDriveRows = (cDrives / cDrivesPerRow) + 1; y = dyDrive * cDriveRows + 1; // now see if there is enough space for that // silly volume/share label thing. if not // make more room! dw = GetVolShareExtent(hwndDrives); if (((int)dxWindow - (cDrives % cDrivesPerRow) * dxDrive) < (int)LOWORD(dw)) { y += dyText + 2*dyBorderx2; } MoveWindow(hwndDrives, 0, 0, dxWindow, y, TRUE); } else y = 0; split = GetSplit(hwndParent); // user has been fixed to do this right dy = dyWindow - y + dyBorder; if (hwndTree) { if (!hwndDir) MoveWindow(hwndTree, dxFrame, y, dxWindow - dxFrame + dyBorder, dy, TRUE); else MoveWindow(hwndTree, -dyBorder, y, split + dyBorder, dy, TRUE); } if (hwndDir) { if (!hwndTree) MoveWindow(hwndDir, dxFrame, y, dxWindow - dxFrame + dyBorder, dy, TRUE); else MoveWindow(hwndDir, split + dxFrame, y, dxWindow - split - dxFrame + dyBorder, dy, TRUE); } }