- Timestamp:
- May 22, 2000, 7:25:13 PM (25 years ago)
- Location:
- trunk/src/comctl32
- Files:
-
- 15 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/comctl32/animate.cpp
r3203 r3585 1 /* $Id: animate.cpp,v 1. 2 2000-03-23 17:14:33cbratschi Exp $ */1 /* $Id: animate.cpp,v 1.3 2000-05-22 17:25:06 cbratschi Exp $ */ 2 2 /* 3 3 * Animation control … … 8 8 * Copyright 1999 Christoph Bratschi 9 9 * 10 * Status: complete 10 * TODO: 11 * - check for the 'rec ' list in some AVI files 12 * - implement some missing flags (ACS_TRANSPARENT and ACS_CENTER) 13 * - protection between service thread and wndproc messages handling 14 * concurrent access to infoPtr 15 * 16 * Status: complete (read above) 11 17 * Version: 5.00 12 18 */ 19 20 /* 21 - Corel WINE 20000513 level 22 */ 13 23 14 24 #include "winbase.h" -
trunk/src/comctl32/comboex.cpp
r3182 r3585 1 /* $Id: comboex.cpp,v 1. 3 2000-03-21 17:30:40cbratschi Exp $ */1 /* $Id: comboex.cpp,v 1.4 2000-05-22 17:25:07 cbratschi Exp $ */ 2 2 /* 3 3 * ComboBoxEx control … … 19 19 */ 20 20 21 /* 22 - Corel WINE 20000513 level 23 */ 24 21 25 #include "winbase.h" 22 26 #include "commctrl.h" … … 176 180 { 177 181 COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd); 178 179 180 if (infoPtr->hwndCombo)181 DestroyWindow (infoPtr->hwndCombo);182 183 184 185 182 186 183 /* free comboex info data */ -
trunk/src/comctl32/comctl32.cpp
r3410 r3585 1 /* $Id: comctl32.cpp,v 1. 3 2000-04-16 18:52:38cbratschi Exp $ */1 /* $Id: comctl32.cpp,v 1.4 2000-05-22 17:25:07 cbratschi Exp $ */ 2 2 /* 3 3 * Win32 common controls implementation … … 13 13 14 14 /* 15 - Corel 20000 212level16 - WINE 20000130 level (commctrl.c)15 - Corel 20000513 level 16 - (WINE 20000130 level (commctrl.c)) 17 17 */ 18 18 -
trunk/src/comctl32/comctl32undoc.cpp
r3385 r3585 1 /* $Id: comctl32undoc.cpp,v 1. 3 2000-04-15 14:22:11cbratschi Exp $ */1 /* $Id: comctl32undoc.cpp,v 1.4 2000-05-22 17:25:07 cbratschi Exp $ */ 2 2 /* 3 3 * Undocumented functions from COMCTL32.DLL … … 13 13 14 14 /* 15 - Corel 20000 317level15 - Corel 20000513 level 16 16 - (WINE 20000130 level) 17 17 */ … … 1277 1277 hdpa->ptrs = 1278 1278 (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY, 1279 2 *hdpa->nGrow * sizeof(LPVOID));1279 hdpa->nGrow * sizeof(LPVOID)); 1280 1280 if (!hdpa->ptrs) 1281 1281 return -1; 1282 hdpa->nMaxCount = hdpa->nGrow * 2;1282 hdpa->nMaxCount = hdpa->nGrow; 1283 1283 nIndex = 0; 1284 1284 } 1285 1285 else { 1286 if (hdpa->nItemCount >= hdpa->nMaxCount) {1286 if (hdpa->nItemCount == hdpa->nMaxCount) { 1287 1287 // TRACE (commctrl, "-- resizing\n"); 1288 1288 nNewItems = hdpa->nMaxCount + hdpa->nGrow; … … 1350 1350 if (hdpa->nMaxCount > i) { 1351 1351 /* within the allocated space, set a new boundary */ 1352 hdpa->nItemCount = i ;1352 hdpa->nItemCount = i+1; 1353 1353 } 1354 1354 else { 1355 1355 /* resize the block of memory */ 1356 1356 INT nNewItems = 1357 hdpa->nGrow * (( INT)(((i+1) -1) / hdpa->nGrow) + 1);1357 hdpa->nGrow * (((i+1) / hdpa->nGrow) + 1); 1358 1358 INT nSize = nNewItems * sizeof(LPVOID); 1359 1359 … … 1413 1413 1414 1414 hdpa->nItemCount --; 1415 hdpa->ptrs[hdpa->nItemCount] = NULL; 1415 1416 1416 1417 /* free memory ?*/ 1417 if ((hdpa->nMaxCount - hdpa->nItemCount) > =hdpa->nGrow) {1418 INT nNewItems = MAX(hdpa->nGrow*2,hdpa->nItemCount);1418 if ((hdpa->nMaxCount - hdpa->nItemCount) > hdpa->nGrow) { 1419 INT nNewItems = hdpa->nMaxCount - hdpa->nGrow; 1419 1420 1420 1421 nSize = nNewItems * sizeof(LPVOID); … … 1705 1706 return hdpa; 1706 1707 } 1707 1708 #if 0 1709 /************************************************************************** 1710 * DPA_LoadStream [COMCTL32.9] 1711 * 1712 * Loads a dynamic pointer array from a stream 1713 * 1714 * PARAMS 1715 * phDpa [O] pointer to a handle to a dynamic pointer array 1716 * loadProc [I] pointer to a callback function 1717 * pStream [I] pointer to a stream 1718 * lParam [I] application specific value 1719 * 1720 * NOTES 1721 * No more information available yet! 1722 */ 1723 HRESULT WINAPI 1724 DPA_LoadStream (HDPA *phDpa, DPALOADPROC loadProc, IStream *pStream, LPARAM lParam) 1725 { 1726 HRESULT errCode; 1727 LARGE_INTEGER position; 1728 ULARGE_INTEGER newPosition; 1729 STREAMDATA streamData; 1730 LOADDATA loadData; 1731 ULONG ulRead; 1732 HDPA hDpa; 1733 PVOID *ptr; 1734 1735 //FIXME ("phDpa=3D%p loadProc=3D%p pStream=3D%p lParam=3D%lx\n",phDpa, loadProc, pStream, lParam); 1736 1737 if (!phDpa || !loadProc || !pStream) 1738 return E_INVALIDARG; 1739 1740 *phDpa = (HDPA)NULL; 1741 1742 position.s.LowPart = 0; 1743 position.s.HighPart = 0; 1744 1745 1746 1747 errCode = IStream_Seek (pStream, position, STREAM_SEEK_CUR, &newPosition); 1748 1749 if (errCode != S_OK) 1750 return errCode; 1751 1752 1753 errCode = IStream_Read (pStream, &streamData, sizeof(STREAMDATA), = &ulRead); 1754 1755 if (errCode != S_OK) 1756 return errCode; 1757 1758 //FIXME ("dwSize=3D%lu dwData2=3D%lu dwItems=3D%lu\n",streamData.dwSize, streamData.dwData2, streamData.dwItems); 1759 1760 if (lParam < sizeof(STREAMDATA) || 1761 streamData.dwSize < sizeof(STREAMDATA) || 1762 streamData.dwData2 < 1) { 1763 errCode = E_FAIL; 1764 } 1765 1766 /* create the dpa */ 1767 1768 hDpa = DPA_Create (streamData.dwItems); 1769 1770 if (!hDpa) 1771 return E_OUTOFMEMORY; 1772 1773 if (!DPA_Grow (hDpa, streamData.dwItems)) 1774 return E_OUTOFMEMORY; 1775 1776 /* load data from the stream into the dpa */ 1777 1778 ptr = hDpa->ptrs; 1779 for (loadData.nCount = 0; loadData.nCount < streamData.dwItems; loadData.nCount++) { 1780 errCode = (loadProc)(&loadData, pStream, lParam); 1781 1782 if (errCode != S_OK) { 1783 errCode = S_FALSE; 1784 break; 1785 } 1786 1787 *ptr = loadData.ptr; 1788 ptr++; 1789 } 1790 1791 /* set the number of items */ 1792 1793 hDpa->nItemCount = loadData.nCount; 1794 1795 /* store the handle to the dpa */ 1796 1797 *phDpa = hDpa; 1798 1799 //FIXME ("new hDpa=3D%p\n", hDpa); 1800 1801 return errCode; 1802 1803 } 1804 1805 /************************************************************************** 1806 * DPA_SaveStream [COMCTL32.10] 1807 * 1808 * Saves a dynamic pointer array to a stream 1809 * 1810 * PARAMS 1811 * hDpa [I] handle to a dynamic pointer array 1812 * loadProc [I] pointer to a callback function 1813 * pStream [I] pointer to a stream 1814 * lParam [I] application specific value 1815 * 1816 * NOTES 1817 * No more information available yet! 1818 */ 1819 HRESULT WINAPI 1820 DPA_SaveStream (const HDPA hDpa, DPALOADPROC loadProc, IStream *pStream,LPARAM lParam) 1821 { 1822 //FIXME ("hDpa=3D%p loadProc=3D%p pStream=3D%p lParam=3D%lx\n",hDpa, loadProc, pStream, lParam); 1823 1824 return E_FAIL; 1825 } 1826 #endif 1708 1827 /************************************************************************** 1709 1828 * Notification functions -
trunk/src/comctl32/datetime.cpp
r2895 r3585 1 /* $Id: datetime.cpp,v 1. 2 2000-02-25 17:00:15cbratschi Exp $ */1 /* $Id: datetime.cpp,v 1.3 2000-05-22 17:25:07 cbratschi Exp $ */ 2 2 /* 3 3 * Date and time picker control … … 15 15 */ 16 16 17 /* WINE 20000 130level */17 /* WINE 20000513 level */ 18 18 19 19 #include "winbase.h" … … 28 28 #define DATETIME_GetInfoPtr(hwnd) ((DATETIME_INFO*)getInfoPtr(hwnd)) 29 29 30 static c har *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",31 "Thursday", "Friday", "Saturday", NULL};32 33 static c har *monthtxt[] = {"January", "February", "March", "April", "May",34 "June", "July", "August", "September", "October",35 "November", "December"};30 static const char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday", 31 "Thursday", "Friday", "Saturday", NULL}; 32 33 static const char *monthtxt[] = {"January", "February", "March", "April", "May", 34 "June", "July", "August", "September", "October", 35 "November", "December"}; 36 36 37 37 static LRESULT -
trunk/src/comctl32/header.cpp
r3420 r3585 1 /* $Id: header.cpp,v 1.1 0 2000-04-18 16:02:37cbratschi Exp $ */1 /* $Id: header.cpp,v 1.11 2000-05-22 17:25:08 cbratschi Exp $ */ 2 2 /* 3 3 * Header control … … 17 17 /* 18 18 Most identical with: 19 - Corel 20000 317level19 - Corel 20000513 level 20 20 */ 21 21 -
trunk/src/comctl32/listview.cpp
r3520 r3585 1 /*$Id: listview.cpp,v 1.1 8 2000-05-10 19:50:32cbratschi Exp $*/1 /*$Id: listview.cpp,v 1.19 2000-05-22 17:25:08 cbratschi Exp $*/ 2 2 /* 3 3 * Listview control … … 50 50 /* 51 51 Most identical with: 52 - Corel 20000 317level52 - Corel 20000513 level 53 53 - (WINE 20000130 level) 54 54 */ … … 831 831 } 832 832 833 static BOOL LISTVIEW_IsItemSelected(LISTVIEW_INFO *infoPtr,INT nItem) 834 { 835 LISTVIEW_ITEM *lpItem; 836 INT pos = 0; 837 838 while ((lpItem = (LISTVIEW_ITEM*)DPA_GetPtr(infoPtr->hdpaSelItems,pos)) != NULL) 839 { 840 if (DPA_GetPtrIndex(infoPtr->hdpaItems,lpItem) == nItem) return TRUE; 841 pos++; 842 } 843 844 return FALSE; 845 } 846 833 847 /*** 834 848 * DESCRIPTION: … … 851 865 for (i = nFirst; i <= nLast; i++) 852 866 { 853 LISTVIEW_SetItemState(hwnd,i,LVIS_SELECTED,LVIS_SELECTED); 867 if (!LISTVIEW_IsItemSelected(infoPtr,nItem)) 868 { 869 LISTVIEW_SetItemState(hwnd,i,LVIS_SELECTED,LVIS_SELECTED); 870 } 854 871 } 855 872 856 873 LISTVIEW_SetItemFocus(hwnd, nItem); 857 infoPtr->nSelectionMark = nItem;858 874 } 859 875 … … 873 889 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)LISTVIEW_GetInfoPtr(hwnd); 874 890 875 LISTVIEW_SetItemState(hwnd,nItem,LVIS_SELECTED,LVIS_SELECTED); 891 if (!LISTVIEW_IsItemSelected(infoPtr,nItem)) 892 { 893 LISTVIEW_SetItemState(hwnd,nItem,LVIS_SELECTED,LVIS_SELECTED); 894 } 876 895 877 896 LISTVIEW_SetItemFocus(hwnd, nItem); 878 infoPtr->nSelectionMark = nItem;879 897 } 880 898 … … 894 912 { 895 913 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)LISTVIEW_GetInfoPtr(hwnd); 896 BOOL bResult; 897 898 if (LISTVIEW_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED) 899 { 900 LISTVIEW_SetItemState(hwnd,nItem,0,LVIS_SELECTED); 901 bResult = FALSE; 902 } 903 else 904 { 905 LISTVIEW_SetItemState(hwnd,nItem,LVIS_SELECTED,LVIS_SELECTED); 914 BOOL bResult = FALSE; 915 DWORD state = 0,stateMask = 0; 916 917 if (nItem != infoPtr->nFocusedItem) 918 { 919 stateMask = LVIS_FOCUSED; 920 LISTVIEW_SetItemState(hwnd,infoPtr->nFocusedItem,state,stateMask); 921 } 922 923 stateMask = LVIS_SELECTED; 924 if (!LISTVIEW_IsItemSelected(infoPtr,nItem)) 925 { 906 926 bResult = TRUE; 907 } 908 909 LISTVIEW_SetItemFocus(hwnd, nItem); 927 state = LVIS_SELECTED; 928 } 910 929 infoPtr->nSelectionMark = nItem; 930 LISTVIEW_SetItemState(hwnd,nItem,state,stateMask); 931 932 if (nItem != infoPtr->nFocusedItem) 933 { 934 state = LVIS_FOCUSED; 935 stateMask = LVIS_FOCUSED; 936 infoPtr->nFocusedItem = nItem; 937 LISTVIEW_SetItemState(hwnd,nItem,state,stateMask); 938 } 911 939 912 940 return bResult; … … 970 998 if ((i < nFirst) || (i > nLast)) 971 999 { 972 LISTVIEW_SetItemState(hwnd,i,0,LVIS_SELECTED); 1000 if (LISTVIEW_IsItemSelected(infoPtr,i)) 1001 { 1002 LISTVIEW_SetItemState(hwnd,i,0,LVIS_SELECTED); 1003 } 973 1004 } 974 1005 else 975 1006 { 976 LISTVIEW_SetItemState(hwnd,i,LVIS_SELECTED,LVIS_SELECTED); 977 } 978 } 1007 if (!LISTVIEW_IsItemSelected(infoPtr,i)) 1008 { 1009 LISTVIEW_SetItemState(hwnd,i,LVIS_SELECTED,LVIS_SELECTED); 1010 } 1011 } 1012 } 1013 LISTVIEW_SetItemState(hwnd,infoPtr->nFocusedItem,0,LVIS_FOCUSED); 1014 1015 infoPtr->nFocusedItem = nItem; 1016 LISTVIEW_SetItemState(hwnd,nItem,LVIS_SELECTED | LVIS_FOCUSED,LVIS_SELECTED | LVIS_FOCUSED); 1017 979 1018 } 980 1019 else … … 991 1030 rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight; 992 1031 LISTVIEW_SetSelectionRect(hwnd, rcSel); 993 } 994 995 LISTVIEW_SetItemFocus(hwnd, nItem); 1032 LISTVIEW_SetItemFocus(hwnd, nItem); 1033 } 996 1034 } 997 1035 … … 3639 3677 if (isUnicodeNotify(&infoPtr->header)) 3640 3678 { 3641 Str_SetPtrW(&lpItemData->pszText, dispInfo.item.pszText);3679 Str_SetPtrW(&lpItemData->pszText,(dispInfo.item.pszText == LPSTR_TEXTCALLBACKW) ? NULL:dispInfo.item.pszText); 3642 3680 } else 3643 3681 { 3644 INT len = dispInfo.item.pszText? lstrlenA((LPSTR)dispInfo.item.pszText):0;3682 INT len = (dispInfo.item.pszText && (dispInfo.item.pszText != LPSTR_TEXTCALLBACKW)) ? lstrlenA((LPSTR)dispInfo.item.pszText):0; 3645 3683 3646 3684 if (lpItemData->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(lpItemData->pszText); … … 3654 3692 } 3655 3693 /* Make sure the source string is valid */ 3656 if (!dispInfo.item.pszText )3694 if (!dispInfo.item.pszText || (dispInfo.item.pszText == LPSTR_TEXTCALLBACKW)) 3657 3695 { 3658 3696 if (!internal) … … 6486 6524 INT maxY = infoPtr->maxScroll.y-infoPtr->scrollPage.y,oldY = infoPtr->lefttop.y; 6487 6525 6526 if (infoPtr->hwndEdit) 6527 { 6528 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); 6529 } 6530 6488 6531 switch (nScrollCode) 6489 6532 { … … 6567 6610 LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)LISTVIEW_GetInfoPtr(hwnd); 6568 6611 INT maxX = infoPtr->maxScroll.x-infoPtr->scrollPage.x,oldX = infoPtr->lefttop.x; 6612 6613 if (infoPtr->hwndEdit) 6614 { 6615 SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0); 6616 } 6569 6617 6570 6618 switch (nScrollCode) … … 6743 6791 break; 6744 6792 6793 case VK_NEXT: 6794 if (infoPtr->uView == LVS_REPORT) 6795 { 6796 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd); 6797 } 6798 else 6799 { 6800 nItem = infoPtr->nFocusedItem + LISTVIEW_GetCountPerColumn(hwnd) * LISTVIEW_GetCountPerRow(hwnd); 6801 } 6802 if(nItem >= GETITEMCOUNT(infoPtr)) nItem = GETITEMCOUNT(infoPtr) - 1; 6803 break; 6804 6745 6805 case VK_PRIOR: 6746 /* TO DO */ 6747 break; 6748 6749 case VK_NEXT: 6750 /* TO DO */ 6806 if (infoPtr->uView == LVS_REPORT) 6807 { 6808 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd); 6809 } 6810 else 6811 { 6812 nItem = infoPtr->nFocusedItem - LISTVIEW_GetCountPerColumn(hwnd) * LISTVIEW_GetCountPerRow(hwnd); 6813 } 6814 if(nItem < 0) nItem = 0; 6751 6815 break; 6752 6816 } … … 7011 7075 sendNotify(hwnd,NM_RELEASEDCAPTURE); 7012 7076 7013 if ( infoPtr->bFocus == FALSE)7077 if (!infoPtr->bFocus) 7014 7078 SetFocus(hwnd); 7015 7079 … … 7024 7088 if (infoPtr->dwStyle & LVS_SINGLESEL) 7025 7089 { 7026 if ( (LISTVIEW_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED) && infoPtr->bDoEditLabel != TRUE)7090 if (LISTVIEW_IsItemSelected(infoPtr,nItem) && !infoPtr->bDoEditLabel) 7027 7091 infoPtr->bDoEditLabel = TRUE; 7028 7092 else … … 7033 7097 if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT)) 7034 7098 { 7035 if (bGroupSelect != FALSE)7099 if (bGroupSelect) 7036 7100 { 7037 7101 LISTVIEW_AddGroupSelection(hwnd, nItem); … … 7052 7116 else 7053 7117 { 7054 if ( (LISTVIEW_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED) && (infoPtr->bDoEditLabel != TRUE))7118 if (LISTVIEW_IsItemSelected(infoPtr,nItem) && !infoPtr->bDoEditLabel) 7055 7119 infoPtr->bDoEditLabel = TRUE; 7056 7120 else -
trunk/src/comctl32/monthcal.cpp
r3145 r3585 18 18 */ 19 19 20 /* WINE 20000130level */20 /* Corel WINE 20000513 level */ 21 21 22 22 #include "winbase.h" -
trunk/src/comctl32/propsheet.cpp
r3154 r3585 1 /* $Id: propsheet.cpp,v 1. 3 2000-03-18 16:17:26cbratschi Exp $ */1 /* $Id: propsheet.cpp,v 1.4 2000-05-22 17:25:10 cbratschi Exp $ */ 2 2 /* 3 3 * Property Sheets … … 14 14 15 15 /* 16 - Corel WINE 20000 317level16 - Corel WINE 20000513 level 17 17 - (WINE 991212 level) 18 18 */ … … 380 380 EnableWindow( owner, TRUE ); 381 381 } 382 retval = dlgInfo-> idResult;382 retval = dlgInfo->dlgExtra->idResult; 383 383 #endif 384 384 DestroyWindow( hwnd ); … … 1001 1001 DLGTEMPLATE* pTemplate; 1002 1002 HWND hwndPage; 1003 RECT rc; 1003 1004 1004 PropPageInfo* ppInfo = psInfo->proppage; 1005 PADDING_INFO padding;1006 1005 1007 1006 // TRACE("index %d\n", index); … … 1044 1043 else 1045 1044 { 1046 pTemplate->style |= WS_CHILD | DS_CONTROL;1045 pTemplate->style |= WS_CHILDWINDOW | DS_CONTROL; 1047 1046 pTemplate->style &= ~DS_MODALFRAME; 1048 1047 pTemplate->style &= ~WS_CAPTION; … … 1066 1065 ppInfo[index].hwndPage = hwndPage; 1067 1066 1068 rc.left = psInfo->x;1069 rc.top = psInfo->y;1070 rc.right = psInfo->width;1071 rc.bottom = psInfo->height;1072 1073 MapDialogRect(hwndParent, &rc);1074 1075 if (psInfo->ppshheader->dwFlags & PSH_WIZARD)1076 padding = PROPSHEET_GetPaddingInfoWizard(hwndParent);1077 else1078 {1079 /*1080 * Ask the Tab control to fit this page in.1081 */1082 1083 HWND hwndTabCtrl = GetDlgItem(hwndParent, IDC_TABCONTROL);1084 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc);1085 padding = PROPSHEET_GetPaddingInfo(hwndParent);1086 }1087 1088 SetWindowPos(hwndPage, HWND_TOP,1089 rc.left + padding.x,1090 rc.top + padding.y,1091 0, 0, SWP_NOSIZE);1092 1093 1067 return TRUE; 1094 1068 } … … 1101 1075 static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo) 1102 1076 { 1077 RECT rc; 1078 PADDING_INFO padding; 1079 UINT pageWidth,pageHeight; 1080 1103 1081 if (index == psInfo->active_page) 1104 1082 { … … 1133 1111 } 1134 1112 1135 ShowWindow(psInfo->proppage[index].hwndPage, SW_SHOW); 1113 if (psInfo->active_page != -1) 1114 { 1115 ShowWindow(psInfo->proppage[psInfo->active_page].hwndPage, SW_HIDE); 1116 } 1117 1118 /* HACK: Sometimes a property page doesn't get displayed at the right place inside the 1119 * property sheet. This will force the window to be placed at the proper location 1120 * before it is displayed. 1121 */ 1122 rc.left = psInfo->x; 1123 rc.top = psInfo->y; 1124 rc.right = psInfo->width; 1125 rc.bottom = psInfo->height; 1126 1127 MapDialogRect(hwndDlg, &rc); 1128 1129 pageWidth = rc.right - rc.left; 1130 pageHeight = rc.bottom - rc.top; 1131 1132 if (psInfo->ppshheader->dwFlags & PSH_WIZARD) 1133 padding = PROPSHEET_GetPaddingInfoWizard(hwndDlg); 1134 else 1135 { 1136 /* 1137 * Ask the Tab control to fit this page in. 1138 */ 1139 1140 HWND hwndTabCtrl = GetDlgItem(hwndDlg, IDC_TABCONTROL); 1141 SendMessageA(hwndTabCtrl, TCM_ADJUSTRECT, FALSE, (LPARAM)&rc); 1142 padding = PROPSHEET_GetPaddingInfo(hwndDlg); 1143 } 1144 1145 SetWindowPos(psInfo->proppage[index].hwndPage, HWND_TOP, 1146 rc.left + padding.x, 1147 rc.top + padding.y, 1148 pageWidth, pageHeight, SWP_SHOWWINDOW); 1136 1149 1137 1150 if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD)) … … 1305 1318 } 1306 1319 1320 EnableWindow(GetDlgItem(hwndDlg, IDC_APPLY_BUTTON), FALSE); 1321 1307 1322 if(lParam) 1308 1323 { 1324 int result = TRUE; 1325 1309 1326 psInfo->activeValid = FALSE; 1327 1328 if (psInfo->restartWindows) 1329 result = ID_PSRESTARTWINDOWS; 1330 1331 /* reboot system takes precedence over restart windows */ 1332 if (psInfo->rebootSystem) 1333 result = ID_PSREBOOTSYSTEM; 1334 1335 if (!psInfo->isModeless) 1336 EndDialog(hwndDlg, result); 1310 1337 } 1311 1338 else if(psInfo->active_page >= 0) … … 1451 1478 { 1452 1479 case PSBTN_APPLYNOW: 1453 SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);1480 PROPSHEET_Apply(hwndDlg, 0); 1454 1481 break; 1482 1455 1483 case PSBTN_BACK: 1456 1484 PROPSHEET_Back(hwndDlg); 1457 1485 break; 1486 1458 1487 case PSBTN_CANCEL: 1459 SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);1488 PROPSHEET_Cancel(hwndDlg, 0); 1460 1489 break; 1490 1461 1491 case PSBTN_FINISH: 1462 1492 PROPSHEET_Finish(hwndDlg); 1463 1493 break; 1494 1464 1495 case PSBTN_HELP: 1465 SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);1496 PROPSHEET_Help(hwndDlg); 1466 1497 break; 1498 1467 1499 case PSBTN_NEXT: 1468 1500 PROPSHEET_Next(hwndDlg); 1469 1501 break; 1502 1470 1503 case PSBTN_OK: 1471 SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);1504 PROPSHEET_Apply(hwndDlg, 1); 1472 1505 break; 1473 default: 1474 //FIXME(propsheet, "Invalid button index %d\n", buttonID);1475 break;1506 1507 //default: 1508 // FIXME("Invalid button index %d\n", buttonID); 1476 1509 } 1477 1510 } … … 2185 2218 { 2186 2219 WORD wID = LOWORD(wParam); 2220 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,PropSheetInfoStr); 2187 2221 2188 2222 switch (wID) … … 2190 2224 case IDOK: 2191 2225 case IDC_APPLY_BUTTON: 2192 { 2193 HWND hwndApplyBtn = GetDlgItem(hwnd, IDC_APPLY_BUTTON); 2194 2195 if (PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0) == FALSE) 2196 break; 2197 2198 if (wID == IDOK) 2199 { 2200 PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd, 2201 PropSheetInfoStr); 2202 int result = TRUE; 2203 2204 if (psInfo->restartWindows) 2205 result = ID_PSRESTARTWINDOWS; 2206 2207 /* reboot system takes precedence over restart windows */ 2208 if (psInfo->rebootSystem) 2209 result = ID_PSREBOOTSYSTEM; 2210 2211 if (psInfo->isModeless) 2212 psInfo->activeValid = FALSE; 2213 else 2214 EndDialog(hwnd, result); 2215 } 2216 else 2217 EnableWindow(hwndApplyBtn, FALSE); 2218 2226 PROPSHEET_Apply(hwnd, wID == IDOK ? 1: 0); 2219 2227 break; 2220 }2221 2228 2222 2229 case IDC_BACK_BUTTON: … … 2239 2246 PROPSHEET_Help(hwnd); 2240 2247 break; 2248 2249 default: 2250 if(psInfo->active_page != -1) 2251 { 2252 return SendMessageA(psInfo->proppage[psInfo->active_page].hwndPage, 2253 uMsg, wParam, lParam); 2254 } 2241 2255 } 2242 2256 -
trunk/src/comctl32/status.cpp
r3154 r3585 1 /* $Id: status.cpp,v 1. 2 2000-03-18 16:17:29cbratschi Exp $ */1 /* $Id: status.cpp,v 1.3 2000-05-22 17:25:11 cbratschi Exp $ */ 2 2 /* 3 3 * Interface code to StatusWindow widget/control … … 9 9 */ 10 10 11 /* WINE 990923 level */11 /* Corel WINE 20000513 level */ 12 12 13 13 #include "winbase.h" … … 918 918 DeleteObject (infoPtr->hDefaultFont); 919 919 920 /* delete tool tip control */921 destroyToolTip(infoPtr->hwndToolTip);922 923 920 doneControl(hwnd); 924 921 -
trunk/src/comctl32/tab.cpp
r3369 r3585 1 /* $Id: tab.cpp,v 1. 3 2000-04-12 16:38:59cbratschi Exp $ */1 /* $Id: tab.cpp,v 1.4 2000-05-22 17:25:11 cbratschi Exp $ */ 2 2 /* 3 3 * Tab control … … 12 12 * Image list support 13 13 * Multiline support 14 * Unicode support15 14 */ 16 15 17 16 /* inconsistent: report! */ 18 17 /* 19 - Corel WINE 20000 317level18 - Corel WINE 20000513 level 20 19 - (WINE 991212 level) 21 20 */ … … 49 48 50 49 /****************************************************************************** 50 * Hot-tracking timer constants 51 */ 52 #define TAB_HOTTRACK_TIMER 1 53 #define TAB_HOTTRACK_TIMER_INTERVAL 100 /* milliseconds */ 54 55 /****************************************************************************** 51 56 * Prototypes 52 57 */ … … 54 59 static void TAB_InvalidateTabArea(HWND hwnd, TAB_INFO* infoPtr); 55 60 static void TAB_EnsureSelectionVisible(HWND hwnd, TAB_INFO* infoPtr); 61 static void TAB_DrawItem(HWND hwnd, HDC hdc, INT iItem); 62 static void TAB_DrawItemInterior(HWND hwnd, HDC hdc, INT iItem, RECT* drawRect); 56 63 57 64 static VOID … … 123 130 if ((iItem < 0) || (iItem >= infoPtr->uNumItem)) return 0; 124 131 125 infoPtr->uFocus=iItem; 126 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BUTTONS) { 127 // FIXME (tab,"Should set input focus\n"); 128 } else { 129 if (infoPtr->iSelected != iItem) { 130 if (sendNotify(hwnd,TCN_SELCHANGING) != TRUE) { 132 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BUTTONS) 133 { 134 //FIXME (tab,"Should set input focus\n"); 135 } else 136 { 137 if (infoPtr->iSelected != iItem || infoPtr->uFocus == -1) 138 { 139 infoPtr->uFocus = iItem; 140 if (sendNotify(hwnd,TCN_SELCHANGING) != TRUE) 141 { 131 142 infoPtr->iSelected = iItem; 132 143 sendNotify(hwnd,TCN_SELCHANGE); … … 166 177 RECT* selectedRect) 167 178 { 168 RECT tmpItemRect; 179 RECT tmpItemRect,clientRect; 180 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); 169 181 170 182 /* 171 183 * Perform a sanity check and a trivial visibility check. 172 184 */ 173 if ( (infoPtr->uNumItem == 0) ||185 if ( (infoPtr->uNumItem <= 0) || 174 186 (itemIndex >= infoPtr->uNumItem) || 175 ( itemIndex < infoPtr->leftmostVisible) )187 (!(lStyle &TCS_MULTILINE) && (itemIndex < infoPtr->leftmostVisible)) ) 176 188 return FALSE; 177 189 … … 187 199 */ 188 200 *itemRect = infoPtr->items[itemIndex].rect; 201 202 /* 203 * calculate the times bottom and top based on the row 204 */ 205 GetClientRect(hwnd, &clientRect); 206 207 if (lStyle & TCS_BOTTOM) 208 { 209 itemRect->bottom = clientRect.bottom - 210 SELECTED_TAB_OFFSET - 211 itemRect->top * (infoPtr->tabHeight - 2); 212 213 itemRect->top = clientRect.bottom - 214 infoPtr->tabHeight - 215 itemRect->top * ( infoPtr->tabHeight - 2); 216 } 217 else 218 { 219 itemRect->bottom = clientRect.top + 220 infoPtr->tabHeight + 221 itemRect->top * (infoPtr->tabHeight - 2); 222 itemRect->top = clientRect.top + 223 SELECTED_TAB_OFFSET+ 224 itemRect->top * (infoPtr->tabHeight - 2); 225 } 189 226 190 227 /* … … 409 446 TAB_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) 410 447 { 448 sendNotify(hwnd,NM_CLICK); 449 450 return 0; 451 } 452 453 static LRESULT 454 TAB_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 455 { 456 sendNotify(hwnd,NM_RCLICK); 457 458 return 0; 459 } 460 461 /****************************************************************************** 462 * TAB_DrawLoneItemInterior 463 * 464 * This calls TAB_DrawItemInterior. However, TAB_DrawItemInterior is normally 465 * called by TAB_DrawItem which is normally called by TAB_Refresh which sets 466 * up the device context and font. This routine does the same setup but 467 * only calls TAB_DrawItemInterior for the single specified item. 468 */ 469 static void 470 TAB_DrawLoneItemInterior(HWND hwnd, TAB_INFO* infoPtr, int iItem) 471 { 472 HDC hdc = GetDC(hwnd); 473 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont); 474 TAB_DrawItemInterior(hwnd, hdc, iItem, NULL); 475 SelectObject(hdc, hOldFont); 476 ReleaseDC(hwnd, hdc); 477 } 478 479 /****************************************************************************** 480 * TAB_HotTrackTimerProc 481 * 482 * When a mouse-move event causes a tab to be highlighted (hot-tracking), a 483 * timer is setup so we can check if the mouse is moved out of our window. 484 * (We don't get an event when the mouse leaves, the mouse-move events just 485 * stop being delivered to our window and just start being delivered to 486 * another window.) This function is called when the timer triggers so 487 * we can check if the mouse has left our window. If so, we un-highlight 488 * the hot-tracked tab. 489 */ 490 static VOID CALLBACK 491 TAB_HotTrackTimerProc 492 ( 493 HWND hwnd, // handle of window for timer messages 494 UINT uMsg, // WM_TIMER message 495 UINT idEvent, // timer identifier 496 DWORD dwTime // current system time 497 ) 498 { 499 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd); 500 501 if (infoPtr != NULL && infoPtr->iHotTracked >= 0) 502 { 503 POINT pt; 504 505 /* 506 ** If we can't get the cursor position, or if the cursor is outside our 507 ** window, we un-highlight the hot-tracked tab. Note that the cursor is 508 ** "outside" even if it is within our bounding rect if another window 509 ** overlaps. Note also that the case where the cursor stayed within our 510 ** window but has moved off the hot-tracked tab will be handled by the 511 ** WM_MOUSEMOVE event. 512 */ 513 if (!GetCursorPos(&pt) || WindowFromPoint(pt) != hwnd) 514 { 515 // Redraw iHotTracked to look normal 516 INT iRedraw = infoPtr->iHotTracked; 517 infoPtr->iHotTracked = -1; 518 TAB_DrawLoneItemInterior(hwnd, infoPtr, iRedraw); 519 520 // Kill this timer 521 KillTimer(hwnd, TAB_HOTTRACK_TIMER); 522 } 523 } 524 } 525 526 /****************************************************************************** 527 * TAB_RecalcHotTrack 528 * 529 * If a tab control has the TCS_HOTTRACK style, then the tab under the mouse 530 * should be highlighted. This function determines which tab in a tab control, 531 * if any, is under the mouse and records that information. The caller may 532 * supply output parameters to receive the item number of the tab item which 533 * was highlighted but isn't any longer and of the tab item which is now 534 * highlighted but wasn't previously. The caller can use this information to 535 * selectively redraw those tab items. 536 * 537 * If the caller has a mouse position, it can supply it through the pos 538 * parameter. For example, TAB_MouseMove does this. Otherwise, the caller 539 * supplies NULL and this function determines the current mouse position 540 * itself. 541 */ 542 static void 543 TAB_RecalcHotTrack 544 ( 545 HWND hwnd, 546 const LPARAM* pos, 547 int* out_redrawLeave, 548 int* out_redrawEnter 549 ) 550 { 551 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd); 552 553 int item = -1; 554 555 556 if (out_redrawLeave != NULL) 557 *out_redrawLeave = -1; 558 if (out_redrawEnter != NULL) 559 *out_redrawEnter = -1; 560 561 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_HOTTRACK) 562 { 563 POINT pt; 564 UINT flags; 565 566 if (pos == NULL) 567 { 568 GetCursorPos(&pt); 569 ScreenToClient(hwnd, &pt); 570 } 571 else 572 { 573 pt.x = LOWORD(*pos); 574 pt.y = HIWORD(*pos); 575 } 576 577 item = TAB_InternalHitTest(hwnd, infoPtr, pt, &flags); 578 } 579 580 if (item != infoPtr->iHotTracked) 581 { 582 if (infoPtr->iHotTracked >= 0) 583 { 584 // Mark currently hot-tracked to be redrawn to look normal 585 if (out_redrawLeave != NULL) 586 *out_redrawLeave = infoPtr->iHotTracked; 587 588 if (item < 0) 589 { 590 // Kill timer which forces recheck of mouse pos 591 KillTimer(hwnd, TAB_HOTTRACK_TIMER); 592 } 593 } 594 else 595 { 596 // Start timer so we recheck mouse pos 597 UINT timerID = SetTimer 598 ( 599 hwnd, 600 TAB_HOTTRACK_TIMER, 601 TAB_HOTTRACK_TIMER_INTERVAL, 602 TAB_HotTrackTimerProc 603 ); 604 605 if (timerID == 0) 606 return; /* Hot tracking not available */ 607 } 608 609 infoPtr->iHotTracked = item; 610 611 if (item >= 0) 612 { 613 // Mark new hot-tracked to be redrawn to look highlighted 614 if (out_redrawEnter != NULL) 615 *out_redrawEnter = item; 616 } 617 } 618 } 619 620 /****************************************************************************** 621 * TAB_MouseMove 622 * 623 * Handles the mouse-move event. Updates tooltips. Updates hot-tracking. 624 */ 625 static LRESULT 626 TAB_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) 627 { 628 int redrawLeave; 629 int redrawEnter; 630 411 631 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd); 412 POINT pt;413 INT newItem;414 UINT dummy;415 632 416 633 if (infoPtr->hwndToolTip) … … 418 635 WM_LBUTTONDOWN, wParam, lParam); 419 636 420 pt.x = (INT)LOWORD(lParam); 421 pt.y = (INT)HIWORD(lParam); 422 423 newItem=TAB_InternalHitTest (hwnd, infoPtr,pt,&dummy); 424 425 // TRACE(tab, "On Tab, item %d\n", newItem); 426 427 if ( (newItem!=-1) && 428 (infoPtr->iSelected != newItem) ) 429 { 430 if (sendNotify(hwnd,TCN_SELCHANGING) != TRUE) 431 { 432 infoPtr->iSelected = newItem; 433 infoPtr->uFocus = newItem; 434 sendNotify(hwnd,TCN_SELCHANGE); 435 436 TAB_EnsureSelectionVisible(hwnd, infoPtr); 437 438 TAB_InvalidateTabArea(hwnd, infoPtr); 439 } 440 } 441 sendNotify(hwnd,NM_CLICK); 442 443 return 0; 444 } 445 446 static LRESULT 447 TAB_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 448 { 449 sendNotify(hwnd,NM_RCLICK); 450 451 return 0; 452 } 453 454 static LRESULT 455 TAB_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) 456 { 457 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd); 458 459 if (infoPtr->hwndToolTip) 460 TAB_RelayEvent (infoPtr->hwndToolTip, hwnd, 461 WM_LBUTTONDOWN, wParam, lParam); 637 /* Determine which tab to highlight. Redraw tabs which change highlight 638 ** status. */ 639 TAB_RecalcHotTrack(hwnd, &lParam, &redrawLeave, &redrawEnter); 640 641 if (redrawLeave != -1) 642 TAB_DrawLoneItemInterior(hwnd, infoPtr, redrawLeave); 643 if (redrawEnter != -1) 644 TAB_DrawLoneItemInterior(hwnd, infoPtr, redrawEnter); 645 462 646 return 0; 463 647 } … … 486 670 */ 487 671 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM) 488 prc->bottom += infoPtr->tabHeight;672 prc->bottom += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 489 673 else 490 prc->top -= infoPtr->tabHeight;674 prc->top -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 491 675 492 676 /* … … 520 704 */ 521 705 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM) 522 prc->bottom -= infoPtr->tabHeight;706 prc->bottom -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 523 707 else 524 prc->top += infoPtr->tabHeight;708 prc->top += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 525 709 526 710 } … … 543 727 TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd); 544 728 545 if (nScrollCode == SB_LINELEFT) 546 { 547 if (infoPtr->leftmostVisible>0) 548 { 549 infoPtr->leftmostVisible--; 550 551 TAB_InvalidateTabArea(hwnd, infoPtr); 552 } 553 } 554 else if (nScrollCode == SB_LINERIGHT) 555 { 556 if (infoPtr->leftmostVisible< (infoPtr->uNumItem-1)) 557 { 558 infoPtr->leftmostVisible++; 559 560 TAB_InvalidateTabArea(hwnd, infoPtr); 561 } 562 } 563 564 return 0; 729 if(nScrollCode == SB_THUMBPOSITION && nPos != infoPtr->leftmostVisible) 730 { 731 if(nPos < infoPtr->leftmostVisible) 732 infoPtr->leftmostVisible--; 733 else 734 infoPtr->leftmostVisible++; 735 736 TAB_RecalcHotTrack(hwnd, NULL, NULL, NULL); 737 TAB_InvalidateTabArea(hwnd, infoPtr); 738 SendMessageA(infoPtr->hwndUpDown, UDM_SETPOS, 0, 739 MAKELONG(infoPtr->leftmostVisible, 0)); 740 } 741 742 return 0; 565 743 } 566 744 … … 576 754 const RECT* clientRect) 577 755 { 756 INT maxRange = 0; 757 578 758 if (infoPtr->needsScrolling) 579 759 { 580 760 RECT controlPos; 761 INT vsize, tabwidth; 581 762 582 763 /* … … 607 788 * control. 608 789 */ 609 infoPtr->hwndUpDown = CreateWindowA(" ScrollBar",610 611 WS_VISIBLE | WS_CHILD | WS_OVERLAPPED | SBS_HORZ,790 infoPtr->hwndUpDown = CreateWindowA("msctls_updown32", 791 "", 792 WS_VISIBLE | WS_CHILD | UDS_HORZ, 612 793 controlPos.left, controlPos.top, 613 794 controlPos.right - controlPos.left, … … 627 808 SWP_SHOWWINDOW | SWP_NOZORDER); 628 809 } 810 811 /* Now calculate upper limit of the updown control range. 812 * We do this by calculating how many tabs will be offscreen when the 813 * last tab is visible. 814 */ 815 if(infoPtr->uNumItem) 816 { 817 vsize = clientRect->right - (controlPos.right - controlPos.left + 1); 818 maxRange = infoPtr->uNumItem; 819 tabwidth = infoPtr->items[maxRange-1].rect.right; 820 821 for(; maxRange > 0; maxRange--) 822 { 823 if(tabwidth - infoPtr->items[maxRange - 1].rect.left > vsize) 824 break; 825 } 826 827 if(maxRange == infoPtr->uNumItem) 828 maxRange--; 829 } 629 830 } 630 831 else … … 638 839 } 639 840 } 841 842 if (infoPtr->hwndUpDown) 843 SendMessageA(infoPtr->hwndUpDown, UDM_SETRANGE32, 0, maxRange); 640 844 } 641 845 … … 657 861 INT curItem; 658 862 INT curItemLeftPos; 863 INT curItemRowCount; 659 864 HFONT hFont, hOldFont; 660 865 HDC hdc; … … 681 886 */ 682 887 curItemLeftPos = 0; 683 684 if (!((lStyle & TCS_FIXEDWIDTH) || (lStyle & TCS_OWNERDRAWFIXED))) 888 curItemRowCount = 0; 889 890 if (!(lStyle & TCS_FIXEDWIDTH) && !((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet)) 685 891 { 686 892 int item_height; … … 717 923 { 718 924 /* 719 * Calculate the vertical position of the tab720 */721 if (lStyle & TCS_BOTTOM)722 {723 infoPtr->items[curItem].rect.bottom = clientRect.bottom -724 SELECTED_TAB_OFFSET;725 infoPtr->items[curItem].rect.top = clientRect.bottom -726 infoPtr->tabHeight;727 }728 else729 {730 infoPtr->items[curItem].rect.top = clientRect.top +731 SELECTED_TAB_OFFSET;732 infoPtr->items[curItem].rect.bottom = clientRect.top +733 infoPtr->tabHeight;734 }735 736 /*737 925 * Set the leftmost position of the tab. 738 926 */ 739 927 infoPtr->items[curItem].rect.left = curItemLeftPos; 740 928 741 if ((lStyle & TCS_FIXEDWIDTH) || ( lStyle & TCS_OWNERDRAWFIXED))929 if ((lStyle & TCS_FIXEDWIDTH) || ((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet)) 742 930 { 743 931 infoPtr->items[curItem].rect.right = infoPtr->items[curItem].rect.left + … … 753 941 * Calculate how wide the tab is depending on the text it contains 754 942 */ 755 //SvL: Bugfix: text is unicode, not ascii756 943 GetTextExtentPoint32W(hdc, infoPtr->items[curItem].pszText, 757 944 lstrlenW(infoPtr->items[curItem].pszText), &size); … … 771 958 } 772 959 960 /* 961 * Check if this is a multiline tab control and if so 962 * check to see if we should wrap the tabs 963 * 964 * Because we are going to arange all these tabs evenly 965 * really we are basically just counting rows at this point 966 * 967 */ 968 969 if ((lStyle & TCS_MULTILINE)&& 970 (infoPtr->items[curItem].rect.right > clientRect.right)) 971 { 972 infoPtr->items[curItem].rect.right -= 973 infoPtr->items[curItem].rect.left; 974 infoPtr->items[curItem].rect.left = 0; 975 curItemRowCount ++; 976 } 977 978 infoPtr->items[curItem].rect.bottom = 0; 979 infoPtr->items[curItem].rect.top = curItemRowCount; 980 773 981 // TRACE("TextSize: %i\n ", size.cx); 774 982 // TRACE("Rect: T %i, L %i, B %i, R %i\n", … … 788 996 } 789 997 790 /* 791 * Check if we need a scrolling control. 792 */ 793 infoPtr->needsScrolling = (curItemLeftPos + (2*SELECTED_TAB_OFFSET) > 794 clientRect.right); 795 796 /* Don't need scrolling, then update infoPtr->leftmostVisible */ 797 if(!infoPtr->needsScrolling) 798 infoPtr->leftmostVisible = 0; 799 800 TAB_SetupScrolling(hwnd, infoPtr, &clientRect); 998 if (!(lStyle & TCS_MULTILINE)) 999 { 1000 /* 1001 * Check if we need a scrolling control. 1002 */ 1003 infoPtr->needsScrolling = (curItemLeftPos + (2*SELECTED_TAB_OFFSET) > 1004 clientRect.right); 1005 1006 /* Don't need scrolling, then update infoPtr->leftmostVisible */ 1007 if(!infoPtr->needsScrolling) 1008 infoPtr->leftmostVisible = 0; 1009 1010 TAB_SetupScrolling(hwnd, infoPtr, &clientRect); 1011 } 1012 1013 /* 1014 * Set the number of rows 1015 */ 1016 1017 infoPtr->uNumRows = curItemRowCount; 1018 1019 if ((lStyle & TCS_MULTILINE)&&(infoPtr->uNumItem > 0)) 1020 { 1021 INT widthDiff,remainder; 1022 INT tabPerRow,remTab; 1023 INT iRow,iItm; 1024 INT iIndexStart=0,iIndexEnd=0, iCount=0; 1025 1026 /* 1027 * Ok Microsoft trys to even out the rows. place the same 1028 * number of tabs in each row. So lets give that a shot 1029 * 1030 */ 1031 1032 tabPerRow = infoPtr->uNumItem / (infoPtr->uNumRows + 1); 1033 remTab = infoPtr->uNumItem % (infoPtr->uNumRows + 1); 1034 1035 for (iItm=0,iRow=0,iCount=0,curItemLeftPos=0; 1036 iItm<infoPtr->uNumItem; 1037 iItm++,iCount++) 1038 { 1039 if (iCount >= ((iRow<remTab)?tabPerRow+1:tabPerRow)) 1040 { 1041 iRow++; 1042 curItemLeftPos = 0; 1043 iCount = 0; 1044 } 1045 /* 1046 * normalize the current rect 1047 */ 1048 infoPtr->items[iItm].rect.right -= 1049 infoPtr->items[iItm].rect.left; 1050 infoPtr->items[iItm].rect.left = 0; 1051 1052 infoPtr->items[iItm].rect.top = iRow; 1053 infoPtr->items[iItm].rect.left +=curItemLeftPos; 1054 infoPtr->items[iItm].rect.right +=curItemLeftPos; 1055 if (lStyle & TCS_BUTTONS) 1056 curItemLeftPos = infoPtr->items[iItm].rect.right + 1057 BUTTON_SPACINGX; 1058 else 1059 curItemLeftPos = infoPtr->items[iItm].rect.right; 1060 } 1061 1062 /* 1063 * Justify the rows 1064 * 1065 */ 1066 { 1067 while(iIndexStart < infoPtr->uNumItem) 1068 { 1069 /* 1070 * find the indexs of the row 1071 */ 1072 for (iIndexEnd=iIndexStart; 1073 (iIndexEnd < infoPtr->uNumItem) && 1074 (infoPtr->items[iIndexEnd].rect.top == 1075 infoPtr->items[iIndexStart].rect.top) ; 1076 iIndexEnd++) 1077 /* intentionaly blank */; 1078 1079 /* 1080 * we need to justify these tabs so they fill the whole given 1081 * client area 1082 * 1083 */ 1084 widthDiff = clientRect.right - (2*SELECTED_TAB_OFFSET) - 1085 infoPtr->items[iIndexEnd-1].rect.right; 1086 1087 iCount = iIndexEnd-iIndexStart; 1088 1089 if (iCount) 1090 { 1091 INT iIndex; 1092 remainder = widthDiff % iCount; 1093 widthDiff = widthDiff / iCount; 1094 for (iIndex=iIndexStart,iCount=0; iIndex < iIndexEnd; 1095 iIndex++,iCount++) 1096 { 1097 infoPtr->items[iIndex].rect.left +=iCount*widthDiff; 1098 infoPtr->items[iIndex].rect.right +=(iCount+1)*widthDiff; 1099 } 1100 infoPtr->items[iIndex-1].rect.right += remainder; 1101 } 1102 1103 iIndexStart=iIndexEnd; 1104 } 1105 } 1106 } 1107 1108 TAB_EnsureSelectionVisible(hwnd,infoPtr); 1109 TAB_RecalcHotTrack(hwnd, NULL, NULL, NULL); 801 1110 802 1111 /* … … 805 1114 SelectObject (hdc, hOldFont); 806 1115 ReleaseDC (hwnd, hdc); 1116 } 1117 1118 /****************************************************************************** 1119 * TAB_DrawItemInterior 1120 * 1121 * This method is used to draw the interior (text and icon) of a single tab 1122 * into the tab control. 1123 */ 1124 static void 1125 TAB_DrawItemInterior 1126 ( 1127 HWND hwnd, 1128 HDC hdc, 1129 INT iItem, 1130 RECT* drawRect 1131 ) 1132 { 1133 TAB_INFO* infoPtr = TAB_GetInfoPtr(hwnd); 1134 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); 1135 1136 RECT localRect; 1137 1138 HPEN htextPen = GetSysColorPen (COLOR_BTNTEXT); 1139 HPEN holdPen; 1140 INT oldBkMode; 1141 1142 if (drawRect == NULL) 1143 { 1144 BOOL isVisible; 1145 RECT itemRect; 1146 RECT selectedRect; 1147 1148 /* 1149 * Get the rectangle for the item. 1150 */ 1151 isVisible = TAB_InternalGetItemRect 1152 ( 1153 hwnd, 1154 infoPtr, 1155 iItem, 1156 &itemRect, 1157 &selectedRect 1158 ); 1159 if (!isVisible) 1160 return; 1161 1162 /* 1163 * Make sure drawRect points to something valid; simplifies code. 1164 */ 1165 drawRect = &localRect; 1166 1167 /* 1168 * This logic copied from the part of TAB_DrawItem which draws 1169 * the tab background. It's important to keep it in sync. I 1170 * would have liked to avoid code duplication, but couldn't figure 1171 * out how without making spaghetti of TAB_DrawItem. 1172 */ 1173 if (lStyle & TCS_BUTTONS) 1174 { 1175 *drawRect = itemRect; 1176 if (iItem == infoPtr->iSelected) 1177 { 1178 drawRect->right--; 1179 drawRect->bottom--; 1180 } 1181 } 1182 else 1183 { 1184 if (iItem == infoPtr->iSelected) 1185 *drawRect = selectedRect; 1186 else 1187 *drawRect = itemRect; 1188 drawRect->right--; 1189 drawRect->bottom--; 1190 } 1191 } 1192 1193 /* 1194 * Text pen 1195 */ 1196 holdPen = SelectObject(hdc, htextPen); 1197 1198 oldBkMode = SetBkMode(hdc, TRANSPARENT); 1199 SetTextColor 1200 ( 1201 hdc, 1202 GetSysColor 1203 ( 1204 (iItem == infoPtr->iHotTracked) ? COLOR_HIGHLIGHT : COLOR_BTNTEXT 1205 ) 1206 ); 1207 1208 /* 1209 * Deflate the rectangle to acount for the padding 1210 */ 1211 InflateRect(drawRect, -HORIZONTAL_ITEM_PADDING, -VERTICAL_ITEM_PADDING); 1212 1213 /* 1214 * if owner draw, tell the owner to draw 1215 */ 1216 if ( (lStyle & TCS_OWNERDRAWFIXED) && GetParent(hwnd) ) 1217 { 1218 DRAWITEMSTRUCT dis; 1219 UINT id; 1220 1221 /* 1222 * get the control id 1223 */ 1224 id = GetWindowLongA(hwnd,GWL_ID); 1225 1226 /* 1227 * put together the DRAWITEMSTRUCT 1228 */ 1229 dis.CtlType = ODT_TAB; 1230 dis.CtlID = id; 1231 dis.itemID = iItem; 1232 dis.itemAction = ODA_DRAWENTIRE; 1233 if ( iItem == infoPtr->iSelected ) 1234 dis.itemState = ODS_SELECTED; 1235 else 1236 dis.itemState = 0; 1237 dis.hwndItem = hwnd; /* */ 1238 dis.hDC = hdc; 1239 dis.rcItem = *drawRect; /* */ 1240 dis.itemData = infoPtr->items[iItem].lParam; 1241 1242 /* 1243 * send the draw message 1244 */ 1245 SendMessageA( GetParent(hwnd), WM_DRAWITEM, (WPARAM)id, (LPARAM)&dis ); 1246 } 1247 else 1248 { 1249 UINT uHorizAlign; 1250 1251 /* 1252 * If not owner draw, then do the drawing ourselves. 1253 * 1254 * Draw the icon. 1255 */ 1256 if (infoPtr->himl && (infoPtr->items[iItem].mask & TCIF_IMAGE)) 1257 { 1258 INT cx; 1259 INT cy; 1260 1261 ImageList_Draw 1262 ( 1263 infoPtr->himl, 1264 infoPtr->items[iItem].iImage, 1265 hdc, 1266 drawRect->left, 1267 drawRect->top + 1, 1268 ILD_NORMAL 1269 ); 1270 ImageList_GetIconSize(infoPtr->himl, &cx, &cy); 1271 drawRect->left += (cx + HORIZONTAL_ITEM_PADDING); 1272 } 1273 1274 /* 1275 * Draw the text; 1276 */ 1277 if (lStyle & TCS_RIGHTJUSTIFY) 1278 uHorizAlign = DT_CENTER; 1279 else 1280 uHorizAlign = DT_LEFT; 1281 1282 DrawTextW 1283 ( 1284 hdc, 1285 infoPtr->items[iItem].pszText, 1286 lstrlenW(infoPtr->items[iItem].pszText), 1287 drawRect, 1288 uHorizAlign | DT_SINGLELINE | DT_VCENTER 1289 ); 1290 } 1291 1292 /* 1293 * Cleanup 1294 */ 1295 SetBkMode(hdc, oldBkMode); 1296 SelectObject(hdc, holdPen); 807 1297 } 808 1298 … … 838 1328 HPEN hwPen = GetSysColorPen (COLOR_3DHILIGHT); 839 1329 HPEN hbPen = GetSysColorPen (COLOR_BTNSHADOW); 840 HPEN hsdPen = GetSysColorPen (COLOR_BTNTEXT);841 1330 HPEN hfocusPen = CreatePen(PS_DOT, 1, GetSysColor(COLOR_BTNTEXT)); 842 1331 HPEN holdPen; 843 1332 INT oldBkMode; 844 INT cx,cy;845 1333 BOOL deleteBrush = TRUE; 846 1334 … … 859 1347 * Background color. 860 1348 */ 861 if (!( lStyle & TCS_OWNERDRAWFIXED))1349 if (!((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet)) 862 1350 { 863 1351 COLORREF bk = GetSysColor(COLOR_3DHILIGHT); … … 867 1355 SetBkColor(hdc, bk); 868 1356 1357 /* if COLOR_WINDOW happens to be the same as COLOR_3DHILIGHT 1358 * we better use 0x55aa bitmap brush to make scrollbar's background 1359 * look different from the window background. 1360 */ 1361 if (bk == GetSysColor(COLOR_WINDOW)) 1362 hbr = GetPattern55AABrush(); 1363 1364 deleteBrush = FALSE; 869 1365 } 870 1366 … … 975 1471 } 976 1472 977 /*978 * Text pen979 */980 SelectObject(hdc, hsdPen);981 982 1473 oldBkMode = SetBkMode(hdc, TRANSPARENT); 983 SetTextColor (hdc, COLOR_BTNTEXT); 984 985 /* 986 * Deflate the rectangle to acount for the padding 987 */ 988 InflateRect(&r, -HORIZONTAL_ITEM_PADDING, -VERTICAL_ITEM_PADDING); 989 990 /* 991 * Draw the icon. 992 */ 993 if (infoPtr->himl) 994 { 995 ImageList_Draw (infoPtr->himl, iItem, hdc, 996 r.left, r.top+1, ILD_NORMAL); 997 ImageList_GetIconSize (infoPtr->himl, &cx, &cy); 998 r.left+=(cx + HORIZONTAL_ITEM_PADDING); 999 } 1000 1001 /* 1002 * Draw the text; 1003 */ 1004 DrawTextW(hdc, 1005 infoPtr->items[iItem].pszText, 1006 lstrlenW(infoPtr->items[iItem].pszText), 1007 &r, 1008 DT_LEFT|DT_SINGLELINE|DT_VCENTER); 1474 1475 /* This modifies r to be the text rectangle. */ 1476 TAB_DrawItemInterior(hwnd, hdc, iItem, &r); 1009 1477 1010 1478 /* … … 1032 1500 SelectObject(hdc, holdPen); 1033 1501 DeleteObject(hfocusPen); 1034 DeleteObject(hbr);1502 if (deleteBrush) DeleteObject(hbr); 1035 1503 } 1036 1504 } … … 1058 1526 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM) 1059 1527 { 1060 rect.bottom -= infoPtr->tabHeight;1528 rect.bottom -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 1061 1529 } 1062 1530 else 1063 1531 { 1064 rect.top += infoPtr->tabHeight;1532 rect.top += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2; 1065 1533 } 1066 1534 … … 1137 1605 */ 1138 1606 TAB_DrawItem (hwnd, hdc, infoPtr->iSelected); 1607 1608 /* 1609 * If we haven't set the current focus yet, set it now. 1610 * Only happens when we first paint the tab controls. 1611 */ 1612 if (infoPtr->uFocus == -1) 1613 TAB_SetCurFocus(hwnd, infoPtr->iSelected); 1139 1614 } 1140 1615 … … 1184 1659 TAB_INFO* infoPtr) 1185 1660 { 1186 RECT selectedRect; 1187 RECT visibleRect; 1188 RECT scrollerRect; 1189 BOOL isVisible; 1661 INT iSelected = infoPtr->iSelected; 1662 1663 INT iOrigLeftmostVisible = infoPtr->leftmostVisible; 1664 1665 /* 1666 * set the items row to the bottommost row or topmost row depending on 1667 * style 1668 */ 1669 1670 if (infoPtr->uNumRows > 0) 1671 { 1672 INT newselected=infoPtr->items[iSelected].rect.top; 1673 INT iTargetRow; 1674 LONG lStyle = GetWindowLongA(hwnd, GWL_STYLE); 1675 1676 if (lStyle & TCS_BOTTOM) 1677 iTargetRow = 0; 1678 else 1679 iTargetRow = infoPtr->uNumRows; 1680 1681 if (newselected != iTargetRow) 1682 { 1683 INT i; 1684 for (i=0; i < infoPtr->uNumItem; i++) 1685 if (infoPtr->items[i].rect.top == newselected ) 1686 infoPtr->items[i].rect.top = iTargetRow; 1687 else if (lStyle&TCS_BOTTOM) 1688 { 1689 if (infoPtr->items[i].rect.top < newselected) 1690 infoPtr->items[i].rect.top+=1; 1691 } 1692 else 1693 { 1694 if (infoPtr->items[i].rect.top > newselected) 1695 infoPtr->items[i].rect.top-=1; 1696 } 1697 1698 TAB_RecalcHotTrack(hwnd, NULL, NULL, NULL); 1699 } 1700 } 1190 1701 1191 1702 /* … … 1196 1707 return; 1197 1708 1198 if (infoPtr->leftmostVisible > infoPtr->iSelected) 1199 { 1200 infoPtr->leftmostVisible = infoPtr->iSelected; 1201 return; 1202 } 1203 1204 /* 1205 * Calculate the part of the client area that is visible. 1206 */ 1207 GetClientRect(hwnd, &visibleRect); 1208 GetClientRect(infoPtr->hwndUpDown, &scrollerRect); 1209 visibleRect.right -= scrollerRect.right; 1210 1211 /* 1212 * Get the rectangle for the item 1213 */ 1214 isVisible = TAB_InternalGetItemRect(hwnd, 1215 infoPtr, 1216 infoPtr->iSelected, 1217 NULL, 1218 &selectedRect); 1219 1220 /* 1221 * If this function can't say it's completely invisible, maybe it 1222 * is partially visible. Let's check. 1223 */ 1224 if (isVisible) 1225 { 1226 POINT pt1; 1227 POINT pt2; 1228 1229 pt1.x = selectedRect.left; 1230 pt1.y = selectedRect.top; 1231 pt2.x = selectedRect.right - 1; 1232 pt2.y = selectedRect.bottom - 1; 1233 1234 isVisible = PtInRect(&visibleRect, pt1) && PtInRect(&visibleRect, pt2); 1235 } 1236 1237 while ( (infoPtr->leftmostVisible < infoPtr->iSelected) && 1238 !isVisible) 1239 { 1240 infoPtr->leftmostVisible++; 1241 1242 /* 1243 * Get the rectangle for the item 1244 */ 1245 isVisible = TAB_InternalGetItemRect(hwnd, 1246 infoPtr, 1247 infoPtr->iSelected, 1248 NULL, 1249 &selectedRect); 1250 1251 /* 1252 * If this function can't say it's completely invisible, maybe it 1253 * is partially visible. Let's check. 1254 */ 1255 if (isVisible) 1256 { 1257 POINT pt1; 1258 POINT pt2; 1259 1260 pt1.x = selectedRect.left; 1261 pt1.y = selectedRect.top; 1262 pt2.x = selectedRect.right - 1; 1263 pt2.y = selectedRect.bottom - 1; 1264 1265 isVisible = PtInRect(&visibleRect, pt1) && PtInRect(&visibleRect, pt2); 1266 } 1267 } 1709 if (infoPtr->leftmostVisible >= iSelected) 1710 { 1711 infoPtr->leftmostVisible = iSelected; 1712 } 1713 else 1714 { 1715 RECT r; 1716 INT width, i; 1717 /* 1718 * Calculate the part of the client area that is visible. 1719 */ 1720 GetClientRect(hwnd, &r); 1721 width = r.right; 1722 1723 GetClientRect(infoPtr->hwndUpDown, &r); 1724 width -= r.right; 1725 1726 if ((infoPtr->items[iSelected].rect.right - 1727 infoPtr->items[iSelected].rect.left) >= width ) 1728 { 1729 /* Special case: width of selected item is greater than visible 1730 * part of control. 1731 */ 1732 infoPtr->leftmostVisible = iSelected; 1733 } 1734 else 1735 { 1736 for (i = infoPtr->leftmostVisible; i < infoPtr->uNumItem; i++) 1737 { 1738 if ((infoPtr->items[iSelected].rect.right - 1739 infoPtr->items[i].rect.left) < width) 1740 break; 1741 } 1742 infoPtr->leftmostVisible = i; 1743 } 1744 } 1745 1746 if (infoPtr->leftmostVisible != iOrigLeftmostVisible) 1747 TAB_RecalcHotTrack(hwnd, NULL, NULL, NULL); 1748 1749 SendMessageA(infoPtr->hwndUpDown, UDM_SETPOS, 0, 1750 MAKELONG(infoPtr->leftmostVisible, 0)); 1268 1751 } 1269 1752 … … 1285 1768 if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM) 1286 1769 { 1287 clientRect.top = clientRect.bottom - (infoPtr->tabHeight + 1); 1770 clientRect.top = clientRect.bottom - (infoPtr->tabHeight * 1771 (infoPtr->uNumRows + 1) + 3); 1288 1772 } 1289 1773 else 1290 1774 { 1291 clientRect.bottom = clientRect.top + (infoPtr->tabHeight + 1); 1775 clientRect.bottom = clientRect.top + (infoPtr->tabHeight * 1776 (infoPtr->uNumRows + 1) + 1); 1292 1777 } 1293 1778 … … 1462 1947 } 1463 1948 1949 infoPtr->fSizeSet = TRUE; 1950 1464 1951 return lResult; 1465 1952 } … … 1494 1981 if (tabItem->mask & TCIF_TEXT) { 1495 1982 len=lstrlenA (tabItem->pszText); 1496 if (len >wineItem->cchTextMax)1497 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc (wineItem->pszText, len+1);1498 lstrcpyA ((LPSTR)wineItem->pszText,tabItem->pszText);1983 if (len > wineItem->cchTextMax) 1984 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,(len+1)*sizeof(WCHAR)); 1985 lstrcpyAtoW(wineItem->pszText,tabItem->pszText); 1499 1986 } 1500 1987 … … 1673 2160 infoPtr->uNumItem = 0; 1674 2161 infoPtr->iSelected = -1; 2162 if (infoPtr->iHotTracked >= 0) 2163 KillTimer(hwnd, TAB_HOTTRACK_TIMER); 2164 infoPtr->iHotTracked = -1; 2165 2166 TAB_SetItemBounds(hwnd); 2167 TAB_InvalidateTabArea(hwnd,infoPtr); 1675 2168 1676 2169 return TRUE; … … 1781 2274 1782 2275 infoPtr->uNumItem = 0; 2276 infoPtr->uNumRows = 0; 1783 2277 infoPtr->hFont = 0; 1784 2278 infoPtr->items = 0; 1785 2279 infoPtr->hcurArrow = LoadCursorA (0, IDC_ARROWA); 1786 2280 infoPtr->iSelected = -1; 1787 infoPtr->uFocus = 0; 2281 infoPtr->iHotTracked = -1; 2282 infoPtr->uFocus = -1; 1788 2283 infoPtr->hwndToolTip = 0; 1789 2284 infoPtr->DoRedraw = TRUE; … … 1791 2286 infoPtr->hwndUpDown = 0; 1792 2287 infoPtr->leftmostVisible = 0; 2288 infoPtr->fSizeSet = FALSE; 1793 2289 1794 2290 /* The tab control always has the WS_CLIPSIBLINGS style. Even … … 1847 2343 } 1848 2344 1849 if (infoPtr->hwndToolTip) 1850 DestroyWindow (infoPtr->hwndToolTip); 1851 1852 if (infoPtr->hwndUpDown) 1853 DestroyWindow(infoPtr->hwndUpDown); 2345 if (infoPtr->iHotTracked >= 0) 2346 KillTimer(hwnd, TAB_HOTTRACK_TIMER); 1854 2347 1855 2348 doneControl(hwnd); 2349 2350 return 0; 2351 } 2352 2353 static LRESULT TAB_StyleChanged(HWND hwnd,WPARAM wParam,LPARAM lParam) 2354 { 2355 TAB_SetItemBounds (hwnd); 2356 InvalidateRect(hwnd, NULL, TRUE); 1856 2357 1857 2358 return 0; … … 1930 2431 return 0; 1931 2432 1932 case TCM_GETUNICODEFORMAT:1933 // FIXME (tab, "Unimplemented msg TCM_GETUNICODEFORMAT\n");1934 return 0;1935 1936 case TCM_SETUNICODEFORMAT:1937 // FIXME (tab, "Unimplemented msg TCM_SETUNICODEFORMAT\n");1938 return 0;1939 1940 2433 case TCM_HIGHLIGHTITEM: 1941 2434 // FIXME (tab, "Unimplemented msg TCM_HIGHLIGHTITEM\n"); … … 2011 2504 case WM_HSCROLL: 2012 2505 return TAB_OnHScroll(hwnd, (int)LOWORD(wParam), (int)HIWORD(wParam), (HWND)lParam); 2506 2507 case WM_STYLECHANGED: 2508 return TAB_StyleChanged(hwnd,wParam,lParam); 2013 2509 2014 2510 case WM_KILLFOCUS: … … 2035 2531 2036 2532 ZeroMemory (&wndClass, sizeof(WNDCLASSA)); 2037 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_ SAVEBITS;2533 wndClass.style = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; 2038 2534 wndClass.lpfnWndProc = (WNDPROC)TAB_WindowProc; 2039 2535 wndClass.cbClsExtra = 0; -
trunk/src/comctl32/toolbar.cpp
r3428 r3585 1 /* $Id: toolbar.cpp,v 1. 5 2000-04-19 14:47:24 sandervlExp $ */1 /* $Id: toolbar.cpp,v 1.6 2000-05-22 17:25:12 cbratschi Exp $ */ 2 2 /* 3 3 * Toolbar control … … 29 29 30 30 /* 31 - Corel 20000317 level 32 - WINE 991212 level 33 */ 34 35 /* CB: Odin32/WINE bugs 36 - IMAGELIST_Draw draws a line too at the bottom of the bitmap (toolbar.exe) 37 imagelist uses default size values instead of real bitmap values 31 - Corel 20000513 level 32 - (WINE 991212 level) 38 33 */ 39 34 … … 1600 1595 return -1; 1601 1596 1602 //TRACE ("adding %d bitmaps!\n", nButtons);1597 //TRACE ("adding %d bitmaps!\n", nButtons); 1603 1598 } 1604 1599 1605 1600 if (!(infoPtr->himlDef)) { 1606 1601 /* create new default image list */ 1607 // TRACE ("creating default image list!\n"); 1608 1609 infoPtr->himlDef = 1610 ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight, 1611 ILC_COLOR | ILC_MASK, nButtons, 2); 1602 //TRACE ("creating default image list!\n"); 1603 /* It seems that the image list created is 1 pixel taller than the bitmap height */ 1604 //CB: nope, it's otherwise 1605 infoPtr->himlDef = 1606 ImageList_Create (infoPtr->nBitmapWidth, infoPtr->nBitmapHeight-1, 1607 ILC_COLOR | ILC_MASK, nButtons, 2); 1612 1608 infoPtr->himlInt = infoPtr->himlDef; 1613 1609 } … … 3462 3458 TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd); 3463 3459 3464 /* delete tooltip control */3465 if (infoPtr->hwndToolTip)3466 DestroyWindow (infoPtr->hwndToolTip);3467 3468 3460 /* delete button data */ 3469 3461 if (infoPtr->buttons) … … 3472 3464 3473 3465 //SvL: Check pointers 3474 for (x = 0;x < infoPtr->nNumButtons;x++) 3475 3476 3466 for (x = 0;x < infoPtr->nNumButtons;x++) 3467 if(infoPtr->buttons[x].pszName) 3468 COMCTL32_Free(infoPtr->buttons[x].pszName); 3477 3469 3478 3470 COMCTL32_Free(infoPtr->buttons); -
trunk/src/comctl32/tooltips.cpp
r3285 r3585 1 /* $Id: tooltips.cpp,v 1. 7 2000-03-31 14:44:23cbratschi Exp $ */1 /* $Id: tooltips.cpp,v 1.8 2000-05-22 17:25:12 cbratschi Exp $ */ 2 2 /* 3 3 * Tool tip control … … 18 18 19 19 /* 20 - Corel WINE 20000 317level20 - Corel WINE 20000513 level 21 21 - (WINE 20000130 level) 22 22 */ … … 1512 1512 TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd); 1513 1513 1514 /* 1515 * Need to set nCurrentTool to nOldTool so we hide the tool. 1516 * nTool and nOldTool values change when the mouse leaves the window. 1517 * If using TTM_UPDATETIPTEXT we can end up with an nCurrentTool = -1 if the 1518 * text can't be found, thus the tooltip would never be hidden. 1519 */ 1520 if (infoPtr->nTool != infoPtr->nOldTool) 1521 infoPtr->nCurrentTool = infoPtr->nOldTool; 1522 1514 1523 TOOLTIPS_Hide (hwnd, infoPtr); 1515 1524 … … 1553 1562 infoPtr->nOldTool = infoPtr->nTool; 1554 1563 infoPtr->nTool = TOOLTIPS_GetToolFromPoint(infoPtr,lpMsg->hwnd,&pt); 1555 //TRACE (tooltips, "tool (%x) %d %d\n",1556 //hwnd, infoPtr->nOldTool, infoPtr->nTool);1557 //TRACE (tooltips, "WM_MOUSEMOVE (%04x %ld %ld)\n",1558 //hwnd, pt.x, pt.y);1564 //TRACE (tooltips, "tool (%x) %d %d\n", 1565 // hwnd, infoPtr->nOldTool, infoPtr->nTool); 1566 //TRACE (tooltips, "WM_MOUSEMOVE (%04x %ld %ld)\n", 1567 // hwnd, pt.x, pt.y); 1559 1568 1560 1569 if (infoPtr->bActive && (infoPtr->nTool != infoPtr->nOldTool)) … … 1563 1572 { 1564 1573 SetTimer(hwnd,ID_TIMERSHOW,infoPtr->nInitialTime,0); 1565 //TRACE (tooltips, "timer 1 started!\n");1574 //TRACE (tooltips, "timer 1 started!\n"); 1566 1575 } else 1567 1576 { 1577 /* 1578 * Need to set nCurrentTool to nOldTool so we hide the tool. 1579 * nTool and nOldTool values change when the mouse leaves the window. 1580 * If using TTM_UPDATETIPTEXT we can end up with an nCurrentTool = -1 if the 1581 * text can't be found, thus the tooltip would never be hidden. 1582 */ 1583 if (infoPtr->nTool != infoPtr->nOldTool) 1584 infoPtr->nCurrentTool = infoPtr->nOldTool; 1585 1568 1586 TOOLTIPS_Hide(hwnd,infoPtr); 1569 1587 SetTimer (hwnd,ID_TIMERSHOW,infoPtr->nReshowTime,0); 1570 //TRACE (tooltips, "timer 2 started!\n");1588 //TRACE (tooltips, "timer 2 started!\n"); 1571 1589 } 1572 1590 } … … 1574 1592 { 1575 1593 SetTimer(hwnd,ID_TIMERLEAVE,100,0); 1576 //TRACE (tooltips, "timer 3 started!\n");1594 //TRACE (tooltips, "timer 3 started!\n"); 1577 1595 } 1578 1596 break; -
trunk/src/comctl32/trackbar.cpp
r3154 r3585 1 /* $Id: trackbar.cpp,v 1. 3 2000-03-18 16:17:33 cbratschi Exp $ */1 /* $Id: trackbar.cpp,v 1.4 2000-05-22 17:25:13 cbratschi Exp $ */ 2 2 /* 3 3 * Trackbar control … … 52 52 #define SCALE_SPACE 1 53 53 54 #define THUMB_LEN 23 55 #define THUMB_MINLEN 4 54 #define THUMB_LEN_SEL 23 55 #define THUMB_LEN 21 56 #define THUMB_MINLEN 4 56 57 57 58 #define CHANNEL_NOSEL_HEIGHT 4 //min no sel height … … 74 75 #define TOOLTIP_YSPACE 5 75 76 76 static BOOL TRACKBAR_SendNotify (HWND hwnd, UINT code); 77 78 static void TRACKBAR_RecalculateTics (HWND hwnd,TRACKBAR_INFO *infoPtr,BOOL restoreOld) 77 static const WORD pattern[8] = 78 {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA}; 79 80 static BOOL TRACKBAR_SendNotify(TRACKBAR_INFO *infoPtr,UINT code); 81 82 static void TRACKBAR_RecalculateTics(TRACKBAR_INFO *infoPtr,BOOL restoreOld) 79 83 { 80 84 INT i,tic,nrTics; 81 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 82 83 if (dwStyle & TBS_NOTICKS) //no ticks 85 86 if (infoPtr->dwStyle & TBS_NOTICKS) //no ticks 84 87 { 85 88 COMCTL32_Free(infoPtr->tics); … … 90 93 } 91 94 92 if (restoreOld && !( dwStyle & TBS_AUTOTICKS) && infoPtr->tics != NULL)95 if (restoreOld && !(infoPtr->dwStyle & TBS_AUTOTICKS) && infoPtr->tics) 93 96 { //check old ticks 94 97 LPLONG oldTics = (LONG*)COMCTL32_Alloc(infoPtr->uNumTics*sizeof(DWORD)); … … 111 114 } 112 115 113 if (infoPtr->uTicFreq && (infoPtr->nRangeMax > infoPtr->nRangeMin) && ( dwStyle & TBS_AUTOTICKS))116 if (infoPtr->uTicFreq && (infoPtr->nRangeMax > infoPtr->nRangeMin) && (infoPtr->dwStyle & TBS_AUTOTICKS)) 114 117 { 115 118 //Tics without start and end tic … … 168 171 else if (pos < infoPtr->nRangeMin) pos = infoPtr->nRangeMin; 169 172 170 // TRACE (trackbar,"%.2f\n",pos);171 173 return pos; 172 174 } … … 174 176 175 177 static VOID 176 TRACKBAR_CalcChannel (HWND hwnd,TRACKBAR_INFO *infoPtr) 177 { 178 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 178 TRACKBAR_CalcChannel(TRACKBAR_INFO *infoPtr) 179 { 179 180 INT channelSize; 180 181 RECT lpRect,*channel = &infoPtr->rcChannel; 181 182 INT thumbDiff; 182 183 183 GetClientRect( hwnd,&lpRect);184 185 if ( dwStyle & TBS_ENABLESELRANGE) channelSize = MAX(infoPtr->uThumbLen-CHANNEL_THUMB_DIFF,CHANNEL_MIN_HEIGHT);184 GetClientRect(infoPtr->hwnd,&lpRect); 185 186 if (infoPtr->dwStyle & TBS_ENABLESELRANGE) channelSize = MAX(infoPtr->uThumbLen-CHANNEL_THUMB_DIFF,CHANNEL_MIN_HEIGHT); 186 187 else channelSize = CHANNEL_NOSEL_HEIGHT; 187 188 188 189 thumbDiff = (infoPtr->uThumbLen-channelSize)/2; 189 190 190 if ( dwStyle & TBS_VERT)191 if (infoPtr->dwStyle & TBS_VERT) 191 192 { 192 193 channel->top = lpRect.top+CHANNEL_SPACE; 193 194 channel->bottom = lpRect.bottom-CHANNEL_SPACE; 194 195 195 if (( dwStyle & TBS_BOTH) || (dwStyle & TBS_NOTICKS))196 if ((infoPtr->dwStyle & TBS_BOTH) || (infoPtr->dwStyle & TBS_NOTICKS)) 196 197 { //center 197 198 channel->left = (lpRect.right-channelSize)/2; 198 199 channel->right = (lpRect.right+channelSize)/2; 199 } else if ( dwStyle & TBS_LEFT)200 } else if (infoPtr->dwStyle & TBS_LEFT) 200 201 { 201 202 channel->left = lpRect.left+thumbDiff+CHANNEL_SCALE_SPACE; … … 210 211 channel->left = lpRect.left+CHANNEL_SPACE; 211 212 channel->right = lpRect.right-CHANNEL_SPACE; 212 if (( dwStyle & TBS_BOTH) || (dwStyle & TBS_NOTICKS))213 if ((infoPtr->dwStyle & TBS_BOTH) || (infoPtr->dwStyle & TBS_NOTICKS)) 213 214 { //center 214 215 channel->top = (lpRect.bottom-channelSize)/2; 215 216 channel->bottom = (lpRect.bottom+channelSize)/2; 216 } else if ( dwStyle & TBS_TOP)217 } else if (infoPtr->dwStyle & TBS_TOP) 217 218 { 218 219 channel->top = lpRect.top+thumbDiff+CHANNEL_SCALE_SPACE; … … 226 227 } 227 228 228 //Calculate thumb size229 230 229 static VOID 231 TRACKBAR_CalcThumb( HWND hwnd,TRACKBAR_INFO *infoPtr)230 TRACKBAR_CalcThumb(TRACKBAR_INFO *infoPtr) 232 231 { 233 232 RECT *thumb; … … 235 234 int range, width; 236 235 int x,y; 237 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);238 236 int thumbFactor = 2; 239 237 … … 241 239 fullThumb = &infoPtr->rcFullThumb; 242 240 range = infoPtr->nRangeMax-infoPtr->nRangeMin; 243 if ( dwStyle & TBS_VERT)241 if (infoPtr->dwStyle & TBS_VERT) 244 242 { 245 243 width = infoPtr->rcChannel.bottom-infoPtr->rcChannel.top; … … 252 250 thumb->right = thumb->left+infoPtr->uThumbLen; 253 251 CopyRect(fullThumb,thumb); 254 if ( dwStyle & TBS_BOTH) return;252 if (infoPtr->dwStyle & TBS_BOTH) return; 255 253 x = y/2; //arrow width 256 if ( dwStyle & TBS_LEFT) thumb->left += x; else thumb->right -= x;254 if (infoPtr->dwStyle & TBS_LEFT) thumb->left += x; else thumb->right -= x; 257 255 } else 258 256 { … … 266 264 thumb->bottom = thumb->top+infoPtr->uThumbLen; 267 265 CopyRect(fullThumb,thumb); 268 if ( dwStyle & TBS_BOTH) return;266 if (infoPtr->dwStyle & TBS_BOTH) return; 269 267 y = x/2; //arrow height 270 if ( dwStyle & TBS_TOP) thumb->top += y; else thumb->bottom -= y;268 if (infoPtr->dwStyle & TBS_TOP) thumb->top += y; else thumb->bottom -= y; 271 269 } 272 270 } 273 271 274 272 static VOID 275 TRACKBAR_CalcSelection (HWND hwnd,TRACKBAR_INFO *infoPtr)273 TRACKBAR_CalcSelection(TRACKBAR_INFO *infoPtr) 276 274 { 277 275 RECT *selection; … … 285 283 if ((range <= 0) || (selMin == selMax)) SetRectEmpty(selection); 286 284 else 287 if (!( GetWindowLongA(hwnd, GWL_STYLE)& TBS_VERT))285 if (!(infoPtr->dwStyle & TBS_VERT)) 288 286 { //Horizontal 289 287 width = infoPtr->rcChannel.right-infoPtr->rcChannel.left; … … 307 305 308 306 static VOID 309 TRACKBAR_DrawHorizTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, 310 int flags, COLORREF clrTic) 307 TRACKBAR_DrawHorizTic(TRACKBAR_INFO *infoPtr,HDC hdc,LONG ticPos,int flags,COLORREF clrTic) 311 308 { 312 309 RECT rcChannel = infoPtr->rcChannel; … … 386 383 387 384 static VOID 388 TRACKBAR_DrawVertTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, 389 int flags, COLORREF clrTic) 385 TRACKBAR_DrawVertTic(TRACKBAR_INFO *infoPtr,HDC hdc,LONG ticPos,int flags,COLORREF clrTic) 390 386 { 391 387 RECT rcChannel = infoPtr->rcChannel; … … 467 463 468 464 static VOID 469 TRACKBAR_DrawTics (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos, 470 int flags, COLORREF clrTic) 465 TRACKBAR_DrawTics(TRACKBAR_INFO *infoPtr,HDC hdc,LONG ticPos,int flags,COLORREF clrTic) 471 466 { 472 467 if (flags & TBS_VERT) … … 489 484 //draw thumb, call only from draw! 490 485 491 static VOID TRACKBAR_DrawThumb(TRACKBAR_INFO *infoPtr,H WND hwnd,HDC hdc,DWORD dwStyle)492 { 493 if (!( dwStyle & TBS_NOTHUMB))486 static VOID TRACKBAR_DrawThumb(TRACKBAR_INFO *infoPtr,HDC hdc) 487 { 488 if (!(infoPtr->dwStyle & TBS_NOTHUMB)) 494 489 { 495 490 HBRUSH hbr,hbrOld; 496 491 RECT thumb = infoPtr->rcThumb; 497 492 498 if ((infoPtr->flags & TB_DRAG_MODE) || !IsWindowEnabled( hwnd)) hbr = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));499 else hbr = CreateSolidBrush(GetSysColor(COLOR_3DFACE));493 if ((infoPtr->flags & TB_DRAG_MODE) || !IsWindowEnabled(infoPtr->hwnd)) hbr = CreateSolidBrush(infoPtr->clrHighlightedThumb); 494 else hbr = infoPtr->hbrThumb; 500 495 hbrOld = SelectObject(hdc,hbr); 501 496 502 if ( dwStyle & TBS_BOTH)497 if (infoPtr->dwStyle & TBS_BOTH) 503 498 { 504 499 DrawEdge(hdc,&thumb,EDGE_RAISED,BF_RECT | BF_ADJUST); … … 509 504 RECT triangle; /* for correct shadows of thumb */ 510 505 511 if ( dwStyle & TBS_VERT)506 if (infoPtr->dwStyle & TBS_VERT) 512 507 { //Vertical 513 508 514 if ( dwStyle & TBS_LEFT)509 if (infoPtr->dwStyle & TBS_LEFT) 515 510 { 516 511 HPEN oldPen,pen; … … 606 601 { //Horizontal 607 602 608 if ( dwStyle & TBS_TOP)603 if (infoPtr->dwStyle & TBS_TOP) 609 604 { 610 605 //Outline … … 689 684 } 690 685 SelectObject(hdc,hbrOld); 691 DeleteObject(hbr);686 if (hbr != infoPtr->hbrThumb) DeleteObject(hbr); 692 687 } 693 688 } … … 695 690 //draw the trackbar 696 691 697 static VOID TRACKBAR_Draw(HWND hwnd,HDC hdc) 698 { 699 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 700 DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE); 692 static VOID TRACKBAR_Draw(TRACKBAR_INFO *infoPtr,HDC hdc) 693 { 701 694 RECT rcClient,rcChannel,rcSelection; 702 695 HBRUSH hBrush; … … 705 698 LRESULT cdctlres,cdres; 706 699 707 GetClientRect( hwnd,&rcClient);700 GetClientRect(infoPtr->hwnd,&rcClient); 708 701 709 702 //Custom draw … … 711 704 cdraw.hdc = hdc; 712 705 cdraw.dwItemSpec = 0; 713 cdraw.uItemState = CDIS_DEFAULT;706 cdraw.uItemState = infoPtr->bFocus ? CDIS_FOCUS:CDIS_DEFAULT; 714 707 cdraw.rc = rcClient; 715 708 cdraw.lItemlParam = 0; 716 709 717 cdctlres = sendNotify( hwnd,NM_CUSTOMDRAW,&cdraw.hdr);710 cdctlres = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr); 718 711 719 712 if (cdctlres & CDRF_SKIPDEFAULT) return; … … 734 727 if (infoPtr->flags & TB_THUMBSIZECHANGED) 735 728 { 736 TRACKBAR_CalcChannel( hwnd,infoPtr);737 TRACKBAR_CalcSelection( hwnd,infoPtr);729 TRACKBAR_CalcChannel(infoPtr); 730 TRACKBAR_CalcSelection(infoPtr); 738 731 } 739 TRACKBAR_CalcThumb( hwnd,infoPtr);740 } 741 if (infoPtr->flags & TB_SELECTIONCHANGED) TRACKBAR_CalcSelection( hwnd,infoPtr);732 TRACKBAR_CalcThumb(infoPtr); 733 } 734 if (infoPtr->flags & TB_SELECTIONCHANGED) TRACKBAR_CalcSelection(infoPtr); 742 735 infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED | TB_DRAGPOSVALID); 743 736 … … 750 743 cdraw.rc = infoPtr->rcChannel; 751 744 752 cdres = sendNotify( hwnd,NM_CUSTOMDRAW,&cdraw.hdr);745 cdres = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr); 753 746 } else cdres = 0; 754 747 … … 759 752 DrawEdge(hdc,&rcChannel,EDGE_SUNKEN,BF_RECT | BF_ADJUST); 760 753 761 if ( dwStyle & TBS_ENABLESELRANGE) /* fill the channel */754 if (infoPtr->dwStyle & TBS_ENABLESELRANGE) /* fill the channel */ 762 755 { 763 756 HBRUSH hbr = CreateSolidBrush(RGB(255,255,255)); 764 757 FillRect(hdc,&rcChannel,hbr); 765 758 DeleteObject(hbr); 766 if ((( dwStyle & TBS_VERT) && (rcSelection.top != rcSelection.bottom)) ||767 ((!( dwStyle & TBS_VERT)) && (rcSelection.left != rcSelection.right)))759 if (((infoPtr->dwStyle & TBS_VERT) && (rcSelection.top != rcSelection.bottom)) || 760 ((!(infoPtr->dwStyle & TBS_VERT)) && (rcSelection.left != rcSelection.right))) 768 761 { 769 762 hbr = CreateSolidBrush (COLOR_HIGHLIGHT); … … 777 770 cdraw.dwDrawStage = CDDS_ITEMPOSTPAINT; 778 771 779 sendNotify( hwnd,NM_CUSTOMDRAW,&cdraw.hdr);772 sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr); 780 773 } 781 774 } … … 789 782 SetRectEmpty(&cdraw.rc); 790 783 791 cdres = sendNotify( hwnd,NM_CUSTOMDRAW,&cdraw.hdr);784 cdres = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr); 792 785 } else cdres = 0; 793 786 794 787 if (!(cdres & CDRF_SKIPDEFAULT)) 795 788 { 796 if (!( dwStyle & TBS_NOTICKS))789 if (!(infoPtr->dwStyle & TBS_NOTICKS)) 797 790 { 798 int ticFlags = dwStyle & 0x0f;791 int ticFlags = infoPtr->dwStyle & 0x0f; 799 792 COLORREF clrTic = GetSysColor(COLOR_3DDKSHADOW); 800 793 INT range = infoPtr->nRangeMax-infoPtr->nRangeMin; 801 INT width = ( dwStyle & TBS_VERT) ? rcChannel.bottom-rcChannel.top:rcChannel.right-rcChannel.left;794 INT width = (infoPtr->dwStyle & TBS_VERT) ? rcChannel.bottom-rcChannel.top:rcChannel.right-rcChannel.left; 802 795 803 796 //check if maximum of visible marks is reached 804 if (( dwStyle & TBS_AUTOTICKS) && (infoPtr->uNumTics > 1) && ((INT)(width*infoPtr->tics[0]/range) == (INT)(width*infoPtr->tics[1]/range)))797 if ((infoPtr->dwStyle & TBS_AUTOTICKS) && (infoPtr->uNumTics > 1) && ((INT)(width*infoPtr->tics[0]/range) == (INT)(width*infoPtr->tics[1]/range))) 805 798 { 806 799 //draw all pixels at once -> much faster 807 if ( dwStyle & TBS_VERT)800 if (infoPtr->dwStyle & TBS_VERT) 808 801 { 809 802 if ((ticFlags & TBS_LEFT) || (ticFlags & TBS_BOTH)) … … 827 820 TRACKBAR_DrawTics(infoPtr,hdc,0,ticFlags | TIC_RIGHTEDGE,clrTic); 828 821 829 if (( dwStyle & TBS_ENABLESELRANGE) &&830 (( dwStyle & TBS_VERT && rcSelection.bottom != rcSelection.top) ||831 (!( dwStyle & TBS_VERT) && rcSelection.left != rcSelection.right)))822 if ((infoPtr->dwStyle & TBS_ENABLESELRANGE) && 823 ((infoPtr->dwStyle & TBS_VERT && rcSelection.bottom != rcSelection.top) || 824 (!(infoPtr->dwStyle & TBS_VERT) && rcSelection.left != rcSelection.right))) 832 825 { 833 826 TRACKBAR_DrawTics(infoPtr,hdc,infoPtr->nSelMin,ticFlags | TIC_SELECTIONMARKMIN,clrTic); … … 840 833 cdraw.dwDrawStage = CDDS_ITEMPOSTPAINT; 841 834 842 sendNotify( hwnd,NM_CUSTOMDRAW,&cdraw.hdr);835 sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr); 843 836 } 844 837 } … … 852 845 cdraw.rc = infoPtr->rcFullThumb; 853 846 854 cdres = sendNotify( hwnd,NM_CUSTOMDRAW,&cdraw.hdr);847 cdres = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr); 855 848 } else cdres = 0; 856 849 857 850 if (!(cdres & CDRF_SKIPDEFAULT)) 858 851 { 859 TRACKBAR_DrawThumb(infoPtr,h wnd,hdc,dwStyle);852 TRACKBAR_DrawThumb(infoPtr,hdc); 860 853 861 854 if (cdctlres & CDRF_NOTIFYITEMDRAW) … … 863 856 cdraw.dwDrawStage = CDDS_ITEMPOSTPAINT; 864 857 865 sendNotify( hwnd,NM_CUSTOMDRAW,&cdraw.hdr);858 sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr); 866 859 } 867 860 868 861 } 869 862 870 if (infoPtr->bFocus && IsWindowEnabled( hwnd)) DrawFocusRect(hdc,&rcClient);863 if (infoPtr->bFocus && IsWindowEnabled(infoPtr->hwnd)) DrawFocusRect(hdc,&rcClient); 871 864 872 865 if (cdctlres & CDRF_NOTIFYPOSTPAINT) … … 874 867 cdraw.dwDrawStage = CDDS_POSTPAINT; 875 868 cdraw.dwItemSpec = 0; 876 GetClientRect( hwnd,&cdraw.rc);877 878 sendNotify( hwnd,NM_CUSTOMDRAW,&cdraw.hdr);869 GetClientRect(infoPtr->hwnd,&cdraw.rc); 870 871 sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr); 879 872 } 880 873 … … 883 876 //update thumb position 884 877 885 static VOID TRACKBAR_UpdateThumbPosition( HWND hwnd,INT lastPos,BOOL mustRedraw)878 static VOID TRACKBAR_UpdateThumbPosition(TRACKBAR_INFO *infoPtr,INT lastPos,BOOL mustRedraw) 886 879 { 887 880 HDC hdc; 888 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd);889 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);890 881 RECT lastRect,newRect,updateRect; 891 882 HDC hdcCompatible; … … 903 894 if (!mustRedraw && (infoPtr->nPos == lastPos)) return; 904 895 905 if ( dwStyle & TBS_NOTHUMB) return;906 907 TRACKBAR_CalcThumb( hwnd,infoPtr);896 if (infoPtr->dwStyle & TBS_NOTHUMB) return; 897 898 TRACKBAR_CalcThumb(infoPtr); 908 899 infoPtr->flags &= ~TB_THUMBCHANGED; 909 900 newRect = infoPtr->rcFullThumb; … … 923 914 updateRect.top = MIN(lastRect.top,newRect.top); 924 915 updateRect.bottom = MAX(lastRect.bottom,newRect.bottom); 925 hdc = GetDC( hwnd);916 hdc = GetDC(infoPtr->hwnd); 926 917 hdcCompatible = CreateCompatibleDC(hdc); 927 918 bitmap = CreateCompatibleBitmap(hdc,updateRect.right,updateRect.bottom); 928 919 oldbmp = SelectObject(hdcCompatible,bitmap); 929 TRACKBAR_Draw( hwnd,hdcCompatible);930 if ( dwStyle & TBS_VERT)920 TRACKBAR_Draw(infoPtr,hdcCompatible); 921 if (infoPtr->dwStyle & TBS_VERT) 931 922 { 932 923 if ((lastRect.top > newRect.top) && (lastRect.top < newRect.bottom)) … … 954 945 DeleteObject(bitmap); 955 946 DeleteDC(hdcCompatible); 956 ReleaseDC( hwnd,hdc);947 ReleaseDC(infoPtr->hwnd,hdc); 957 948 } 958 949 959 950 //redraw everything 960 951 961 static VOID TRACKBAR_Refresh (HWND hwnd)952 static VOID TRACKBAR_Refresh(TRACKBAR_INFO *infoPtr) 962 953 { 963 954 HDC hdc; 964 955 965 hdc = GetDC (hwnd);966 TRACKBAR_Draw( hwnd,hdc);967 ReleaseDC( hwnd,hdc);956 hdc = GetDC(infoPtr->hwnd); 957 TRACKBAR_Draw(infoPtr,hdc); 958 ReleaseDC(infoPtr->hwnd,hdc); 968 959 } 969 960 970 961 static VOID 971 TRACKBAR_AlignBuddies (HWND hwnd, TRACKBAR_INFO *infoPtr) 972 { 973 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 974 HWND hwndParent = GetParent(hwnd); 962 TRACKBAR_AlignBuddies(TRACKBAR_INFO *infoPtr) 963 { 964 HWND hwndParent = GetParent(infoPtr->hwnd); 975 965 RECT rcSelf,rcBuddy; 976 966 INT x, y; 977 967 978 GetWindowRect( hwnd,&rcSelf);968 GetWindowRect(infoPtr->hwnd,&rcSelf); 979 969 MapWindowPoints(HWND_DESKTOP,hwndParent,(LPPOINT)&rcSelf,2); 980 970 … … 984 974 GetWindowRect(infoPtr->hwndBuddyLA,&rcBuddy); 985 975 986 if ( dwStyle & TBS_VERT)976 if (infoPtr->dwStyle & TBS_VERT) 987 977 { //above 988 978 x = (infoPtr->rcChannel.right+infoPtr->rcChannel.left)/2-(rcBuddy.right-rcBuddy.left)/2+rcSelf.left; … … 1003 993 GetWindowRect(infoPtr->hwndBuddyRB,&rcBuddy); 1004 994 1005 if ( dwStyle & TBS_VERT)995 if (infoPtr->dwStyle & TBS_VERT) 1006 996 { //below 1007 997 x = (infoPtr->rcChannel.right+infoPtr->rcChannel.left)/2-(rcBuddy.right-rcBuddy.left)/2+rcSelf.left; … … 1017 1007 } 1018 1008 1019 1020 static LRESULT 1021 TRACKBAR_ClearSel (HWND hwnd, WPARAM wParam, LPARAM lParam) 1022 { 1023 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1024 1009 static LRESULT 1010 TRACKBAR_ClearSel(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1011 { 1025 1012 if (infoPtr->nSelMin != infoPtr->nSelMax) 1026 1013 { … … 1029 1016 infoPtr->flags |= TB_SELECTIONCHANGED; 1030 1017 1031 if ((BOOL)wParam) TRACKBAR_Refresh(hwnd); 1032 } 1033 1034 return 0; 1035 } 1036 1037 1038 static LRESULT 1039 TRACKBAR_ClearTics (HWND hwnd, WPARAM wParam, LPARAM lParam) 1040 { 1041 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1042 1043 if (!(GetWindowLongA(hwnd, GWL_STYLE) & (TBS_AUTOTICKS | TBS_NOTICKS))) return 0; 1018 if ((BOOL)wParam) TRACKBAR_Refresh(infoPtr); 1019 } 1020 1021 return 0; 1022 } 1023 1024 static LRESULT 1025 TRACKBAR_ClearTics(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1026 { 1027 if (!(infoPtr->dwStyle & (TBS_AUTOTICKS | TBS_NOTICKS))) return 0; 1044 1028 1045 1029 if (infoPtr->tics) … … 1049 1033 infoPtr->uNumTics = 0; 1050 1034 1051 if (wParam) TRACKBAR_Refresh(hwnd); 1052 } 1053 1054 return 0; 1055 } 1056 1057 1058 static LRESULT 1059 TRACKBAR_GetBuddy (HWND hwnd, WPARAM wParam, LPARAM lParam) 1060 { 1061 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd); 1062 1035 if (wParam) TRACKBAR_Refresh(infoPtr); 1036 } 1037 1038 return 0; 1039 } 1040 1041 1042 static LRESULT 1043 TRACKBAR_GetBuddy(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1044 { 1063 1045 if (wParam) 1064 1046 return (LRESULT)infoPtr->hwndBuddyLA; //left or above … … 1067 1049 } 1068 1050 1069 1070 static LRESULT 1071 TRACKBAR_GetChannelRect (HWND hwnd, WPARAM wParam, LPARAM lParam) 1072 { 1073 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1051 static LRESULT 1052 TRACKBAR_GetChannelRect(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1053 { 1074 1054 LPRECT lprc = (LPRECT)lParam; 1075 1055 … … 1081 1061 } 1082 1062 1083 1084 static LRESULT 1085 TRACKBAR_GetLineSize (HWND hwnd, WPARAM wParam, LPARAM lParam) 1086 { 1087 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1088 1063 static LRESULT 1064 TRACKBAR_GetLineSize(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1065 { 1089 1066 return infoPtr->nLineSize; 1090 1067 } … … 1092 1069 1093 1070 static LRESULT 1094 TRACKBAR_GetNumTics (HWND hwnd, WPARAM wParam, LPARAM lParam) 1095 { 1096 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1097 1098 if (GetWindowLongA(hwnd, GWL_STYLE) & TBS_NOTICKS) return 0; 1071 TRACKBAR_GetNumTics(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1072 { 1073 if (infoPtr->dwStyle & TBS_NOTICKS) return 0; 1099 1074 1100 1075 return infoPtr->uNumTics+2; //includes last and first tick 1101 1076 } 1102 1077 1103 1104 static LRESULT 1105 TRACKBAR_GetPageSize (HWND hwnd, WPARAM wParam, LPARAM lParam) 1106 { 1107 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1108 1078 static LRESULT 1079 TRACKBAR_GetPageSize(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1080 { 1109 1081 return infoPtr->nPageSize; 1110 1082 } … … 1112 1084 1113 1085 static LRESULT 1114 TRACKBAR_GetPos (HWND hwnd, WPARAM wParam, LPARAM lParam) 1115 { 1116 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1117 1086 TRACKBAR_GetPos(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1087 { 1118 1088 return infoPtr->nPos; 1119 1089 } … … 1121 1091 1122 1092 static LRESULT 1123 TRACKBAR_GetRangeMax (HWND hwnd, WPARAM wParam, LPARAM lParam) 1124 { 1125 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1126 1093 TRACKBAR_GetRangeMax(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1094 { 1127 1095 return infoPtr->nRangeMax; 1128 1096 } … … 1130 1098 1131 1099 static LRESULT 1132 TRACKBAR_GetRangeMin (HWND hwnd, WPARAM wParam, LPARAM lParam) 1133 { 1134 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1135 1100 TRACKBAR_GetRangeMin(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1101 { 1136 1102 return infoPtr->nRangeMin; 1137 1103 } … … 1139 1105 1140 1106 static LRESULT 1141 TRACKBAR_GetSelEnd (HWND hwnd, WPARAM wParam, LPARAM lParam) 1142 { 1143 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1144 1107 TRACKBAR_GetSelEnd(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1108 { 1145 1109 return infoPtr->nSelMax; 1146 1110 } … … 1148 1112 1149 1113 static LRESULT 1150 TRACKBAR_GetSelStart (HWND hwnd, WPARAM wParam, LPARAM lParam) 1151 { 1152 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1153 1114 TRACKBAR_GetSelStart(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1115 { 1154 1116 return infoPtr->nSelMin; 1155 1117 } … … 1157 1119 1158 1120 static LRESULT 1159 TRACKBAR_GetThumbLength (HWND hwnd, WPARAM wParam, LPARAM lParam) 1160 { 1161 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1162 1121 TRACKBAR_GetThumbLength(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1122 { 1163 1123 return infoPtr->uThumbLen; 1164 1124 } 1165 1125 1166 1126 static LRESULT 1167 TRACKBAR_GetPTics (HWND hwnd) 1168 { 1169 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1170 1127 TRACKBAR_GetPTics(TRACKBAR_INFO *infoPtr) 1128 { 1171 1129 return (LRESULT)infoPtr->tics; 1172 1130 } 1173 1131 1174 1132 static LRESULT 1175 TRACKBAR_GetThumbRect (HWND hwnd, WPARAM wParam, LPARAM lParam) 1176 { 1177 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1133 TRACKBAR_GetThumbRect(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1134 { 1178 1135 LPRECT lprc = (LPRECT)lParam; 1179 1136 … … 1187 1144 1188 1145 static LRESULT 1189 TRACKBAR_GetTic (HWND hwnd, WPARAM wParam, LPARAM lParam) 1190 { 1191 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1146 TRACKBAR_GetTic(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1147 { 1192 1148 INT iTic; 1193 1149 … … 1201 1157 1202 1158 static LRESULT 1203 TRACKBAR_GetTicPos (HWND hwnd, WPARAM wParam, LPARAM lParam) 1204 { 1205 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1159 TRACKBAR_GetTicPos(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1160 { 1206 1161 INT iTic, range, width, pos; 1207 1162 … … 1219 1174 1220 1175 static LRESULT 1221 TRACKBAR_GetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam) 1222 { 1223 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1224 1225 if (GetWindowLongA (hwnd, GWL_STYLE) & TBS_TOOLTIPS) 1176 TRACKBAR_GetToolTips(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1177 { 1178 if (infoPtr->dwStyle & TBS_TOOLTIPS) 1226 1179 return (LRESULT)infoPtr->hwndToolTip; 1227 1180 return 0; … … 1230 1183 1231 1184 static LRESULT 1232 TRACKBAR_SetBuddy (HWND hwnd, WPARAM wParam, LPARAM lParam) 1233 { 1234 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd); 1185 TRACKBAR_SetBuddy(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1186 { 1235 1187 HWND hwndTemp; 1236 1188 1237 if (!(GetParent(lParam) == GetParent( hwnd))) return wParam ? infoPtr->hwndBuddyLA:infoPtr->hwndBuddyRB;1189 if (!(GetParent(lParam) == GetParent(infoPtr->hwnd))) return wParam ? infoPtr->hwndBuddyLA:infoPtr->hwndBuddyRB; 1238 1190 1239 1191 if (wParam) … … 1249 1201 } 1250 1202 1251 TRACKBAR_AlignBuddies( hwnd,infoPtr);1203 TRACKBAR_AlignBuddies(infoPtr); 1252 1204 1253 1205 return (LRESULT)hwndTemp; … … 1256 1208 1257 1209 static LRESULT 1258 TRACKBAR_SetLineSize (HWND hwnd, WPARAM wParam, LPARAM lParam) 1259 { 1260 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1210 TRACKBAR_SetLineSize(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1211 { 1261 1212 INT nTemp = infoPtr->nLineSize; 1262 1213 … … 1268 1219 1269 1220 static LRESULT 1270 TRACKBAR_SetPageSize (HWND hwnd, WPARAM wParam, LPARAM lParam) 1271 { 1272 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1221 TRACKBAR_SetPageSize(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1222 { 1273 1223 INT nTemp = infoPtr->nPageSize; 1274 1224 … … 1280 1230 1281 1231 static LRESULT 1282 TRACKBAR_SetPos (HWND hwnd, WPARAM wParam, LPARAM lParam) 1283 { 1284 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1232 TRACKBAR_SetPos(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1233 { 1285 1234 INT lastPos = infoPtr->nPos; 1286 1235 … … 1296 1245 infoPtr->flags |= TB_THUMBPOSCHANGED; 1297 1246 1298 if (wParam) TRACKBAR_UpdateThumbPosition(hwnd,lastPos,FALSE); 1299 1300 return 0; 1301 } 1302 1303 1304 static LRESULT 1305 TRACKBAR_SetRange (HWND hwnd, WPARAM wParam, LPARAM lParam) 1306 { 1307 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1247 if (wParam) TRACKBAR_UpdateThumbPosition(infoPtr,lastPos,FALSE); 1248 1249 return 0; 1250 } 1251 1252 1253 static LRESULT 1254 TRACKBAR_SetRange(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1255 { 1308 1256 int newMin,newMax; 1309 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);1310 1257 1311 1258 newMin = (INT)LOWORD(lParam); … … 1360 1307 infoPtr->nPageSize = (infoPtr->nRangeMax-infoPtr->nRangeMin)/5; 1361 1308 if (infoPtr->nPageSize == 0) infoPtr->nPageSize = 1; 1362 TRACKBAR_RecalculateTics(hwnd,infoPtr,TRUE); 1363 1364 if (wParam) TRACKBAR_Refresh(hwnd); 1365 1366 return 0; 1367 } 1368 1369 1370 static LRESULT 1371 TRACKBAR_SetRangeMax (HWND hwnd, WPARAM wParam, LPARAM lParam) 1372 { 1373 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1374 1309 TRACKBAR_RecalculateTics(infoPtr,TRUE); 1310 1311 if (wParam) TRACKBAR_Refresh(infoPtr); 1312 1313 return 0; 1314 } 1315 1316 1317 static LRESULT 1318 TRACKBAR_SetRangeMax(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1319 { 1375 1320 if ((INT)lParam <= infoPtr->nRangeMin) return 0; 1376 1321 if (infoPtr->nRangeMax == (INT)lParam) return 0; … … 1385 1330 infoPtr->nPageSize = (infoPtr->nRangeMax-infoPtr->nRangeMin)/5; 1386 1331 if (infoPtr->nPageSize == 0) infoPtr->nPageSize = 1; 1387 TRACKBAR_RecalculateTics(hwnd,infoPtr,TRUE); 1388 1389 if (wParam) TRACKBAR_Refresh(hwnd); 1390 1391 return 0; 1392 } 1393 1394 1395 static LRESULT 1396 TRACKBAR_SetRangeMin (HWND hwnd, WPARAM wParam, LPARAM lParam) 1397 { 1398 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1399 1332 TRACKBAR_RecalculateTics(infoPtr,TRUE); 1333 1334 if (wParam) TRACKBAR_Refresh(infoPtr); 1335 1336 return 0; 1337 } 1338 1339 1340 static LRESULT 1341 TRACKBAR_SetRangeMin(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1342 { 1400 1343 if ((INT)lParam >= infoPtr->nRangeMax) return 0; 1401 1344 if (infoPtr->nRangeMin == (INT)lParam) return 0; … … 1410 1353 infoPtr->nPageSize = (infoPtr->nRangeMax-infoPtr->nRangeMin)/5; 1411 1354 if (infoPtr->nPageSize == 0) infoPtr->nPageSize = 1; 1412 TRACKBAR_RecalculateTics(hwnd,infoPtr,TRUE); 1413 1414 if (wParam) TRACKBAR_Refresh(hwnd); 1415 1416 return 0; 1417 } 1418 1419 1420 static LRESULT 1421 TRACKBAR_SetTicFreq (HWND hwnd, WPARAM wParam) 1422 { 1423 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1424 1355 TRACKBAR_RecalculateTics(infoPtr,TRUE); 1356 1357 if (wParam) TRACKBAR_Refresh(infoPtr); 1358 1359 return 0; 1360 } 1361 1362 1363 static LRESULT 1364 TRACKBAR_SetTicFreq(TRACKBAR_INFO *infoPtr,WPARAM wParam) 1365 { 1425 1366 if (infoPtr->uTicFreq == (UINT)wParam) return 0; 1426 1367 1427 if (!( GetWindowLongA(hwnd,GWL_STYLE)& TBS_AUTOTICKS)) return 0;1368 if (!(infoPtr->dwStyle & TBS_AUTOTICKS)) return 0; 1428 1369 1429 1370 infoPtr->uTicFreq = (UINT)wParam; 1430 1371 1431 TRACKBAR_RecalculateTics(hwnd,infoPtr,FALSE); 1432 1433 TRACKBAR_Refresh(hwnd); 1434 1435 return 0; 1436 } 1437 1438 1439 static LRESULT 1440 TRACKBAR_SetSel(HWND hwnd,WPARAM wParam,LPARAM lParam) 1441 { 1442 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1372 TRACKBAR_RecalculateTics(infoPtr,FALSE); 1373 1374 TRACKBAR_Refresh(infoPtr); 1375 1376 return 0; 1377 } 1378 1379 static LRESULT 1380 TRACKBAR_SetSel(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1381 { 1443 1382 INT newMin,newMax,oldMin,oldMax; 1444 1383 … … 1459 1398 if (infoPtr->nSelMin > infoPtr->nSelMax) infoPtr->nSelMin = infoPtr->nSelMax; 1460 1399 1461 if (! GetWindowLongA(hwnd, GWL_STYLE) & TBS_ENABLESELRANGE) return 0;1400 if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)) return 0; 1462 1401 1463 1402 if ((oldMin != newMin) || (oldMax != newMax)) 1464 1403 { 1465 1404 infoPtr->flags |= TB_SELECTIONCHANGED; 1466 if (wParam) TRACKBAR_Refresh(hwnd); 1467 } 1468 1469 return 0; 1470 } 1471 1472 1473 static LRESULT 1474 TRACKBAR_SetSelEnd (HWND hwnd, WPARAM wParam, LPARAM lParam) 1475 { 1476 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1405 if (wParam) TRACKBAR_Refresh(infoPtr); 1406 } 1407 1408 return 0; 1409 } 1410 1411 static LRESULT 1412 TRACKBAR_SetSelEnd(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1413 { 1477 1414 INT oldMax; 1478 1415 … … 1487 1424 if (infoPtr->nSelMin > infoPtr->nSelMax) infoPtr->nSelMin = infoPtr->nSelMax; 1488 1425 1489 if (! GetWindowLongA(hwnd,GWL_STYLE) & TBS_ENABLESELRANGE) return 0;1426 if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)) return 0; 1490 1427 1491 1428 if (oldMax != infoPtr->nSelMax) 1492 1429 { 1493 1430 infoPtr->flags |= TB_SELECTIONCHANGED; 1494 if (wParam) TRACKBAR_Refresh(hwnd); 1495 } 1496 1497 return 0; 1498 } 1499 1500 1501 static LRESULT 1502 TRACKBAR_SetSelStart (HWND hwnd, WPARAM wParam, LPARAM lParam) 1503 { 1504 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1431 if (wParam) TRACKBAR_Refresh(infoPtr); 1432 } 1433 1434 return 0; 1435 } 1436 1437 static LRESULT 1438 TRACKBAR_SetSelStart(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1439 { 1505 1440 INT oldMin; 1506 1441 … … 1515 1450 if (infoPtr->nSelMin > infoPtr->nSelMax) infoPtr->nSelMin = infoPtr->nSelMax; 1516 1451 1517 if (! GetWindowLongA(hwnd,GWL_STYLE) & TBS_ENABLESELRANGE) return 0;1452 if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)) return 0; 1518 1453 1519 1454 if (oldMin != infoPtr->nSelMin) 1520 1455 { 1521 1456 infoPtr->flags |= TB_SELECTIONCHANGED; 1522 if (wParam) TRACKBAR_Refresh(hwnd); 1523 } 1524 1525 return 0; 1526 } 1527 1528 1529 static LRESULT 1530 TRACKBAR_SetThumbLength (HWND hwnd, WPARAM wParam, LPARAM lParam) 1531 { 1532 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd); 1533 1457 if (wParam) TRACKBAR_Refresh(infoPtr); 1458 } 1459 1460 return 0; 1461 } 1462 1463 static LRESULT 1464 TRACKBAR_SetThumbLength(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1465 { 1534 1466 if (infoPtr->uThumbLen == (UINT)wParam) return 0; 1535 1467 1536 if ( GetWindowLongA(hwnd,GWL_STYLE)& TBS_FIXEDLENGTH) return 0;1468 if (infoPtr->dwStyle & TBS_FIXEDLENGTH) return 0; 1537 1469 1538 1470 infoPtr->uThumbLen = MAX((UINT)wParam,THUMB_MINLEN); 1539 1471 infoPtr->flags |= TB_THUMBSIZECHANGED | TB_THUMBCHANGED; 1540 1472 1541 TRACKBAR_Refresh( hwnd);1473 TRACKBAR_Refresh(infoPtr); 1542 1474 1543 1475 return 0; … … 1569 1501 1570 1502 static LRESULT 1571 TRACKBAR_SetTic (HWND hwnd, WPARAM wParam, LPARAM lParam) 1572 { 1573 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1503 TRACKBAR_SetTic(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1504 { 1574 1505 INT nPos = (INT)lParam; 1575 1506 INT x; 1576 1507 1577 if (!( GetWindowLongA(hwnd, GWL_STYLE)& (TBS_AUTOTICKS | TBS_NOTICKS))) return 0;1508 if (!(infoPtr->dwStyle & (TBS_AUTOTICKS | TBS_NOTICKS))) return 0; 1578 1509 1579 1510 if ((nPos < infoPtr->nRangeMin) || (nPos > infoPtr->nRangeMax)) return FALSE; … … 1592 1523 TRACKBAR_QuickSort(infoPtr->tics,0,infoPtr->uNumTics-1); 1593 1524 1594 TRACKBAR_Refresh( hwnd);1525 TRACKBAR_Refresh(infoPtr); 1595 1526 1596 1527 return TRUE; 1597 1528 } 1598 1529 1599 1600 static LRESULT 1601 TRACKBAR_SetTipSide (HWND hwnd, WPARAM wParam, LPARAM lParam) 1602 { 1603 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd); 1604 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 1530 static LRESULT 1531 TRACKBAR_SetTipSide(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1532 { 1605 1533 INT fTemp = infoPtr->fLocation; 1606 1534 1607 if ( dwStyle & TBS_VERT)1535 if (infoPtr->dwStyle & TBS_VERT) 1608 1536 { 1609 1537 if ((wParam == TBTS_LEFT) || (wParam == TBTS_RIGHT)) infoPtr->fLocation = (INT)wParam; … … 1616 1544 } 1617 1545 1618 1619 static LRESULT 1620 TRACKBAR_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam) 1621 { 1622 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1623 1546 static LRESULT 1547 TRACKBAR_SetToolTips(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1548 { 1624 1549 infoPtr->hwndToolTip = (HWND)wParam; 1625 1550 … … 1628 1553 1629 1554 static LRESULT 1630 TRACKBAR_InitializeThumb (HWND hwnd) 1631 { 1632 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1555 TRACKBAR_InitializeThumb(TRACKBAR_INFO *infoPtr) 1556 { 1633 1557 RECT clientRect; 1634 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);1635 1558 INT scaleSize; 1636 1559 1637 GetClientRect( hwnd,&clientRect);1638 infoPtr->uThumbLen = THUMB_LEN; /* initial thumb length */1560 GetClientRect(infoPtr->hwnd,&clientRect); 1561 infoPtr->uThumbLen = (infoPtr->dwStyle & TBS_ENABLESELRANGE) ? THUMB_LEN_SEL:THUMB_LEN; /* initial thumb length */ 1639 1562 1640 1563 scaleSize = 2*BORDER_SIZE; 1641 if ( dwStyle & TBS_NOTICKS) scaleSize += 0;1642 else if ( dwStyle & TBS_BOTH) scaleSize += 2*(SCALE_SIZE+SCALE_SPACE);1564 if (infoPtr->dwStyle & TBS_NOTICKS) scaleSize += 0; 1565 else if (infoPtr->dwStyle & TBS_BOTH) scaleSize += 2*(SCALE_SIZE+SCALE_SPACE); 1643 1566 else scaleSize += SCALE_SIZE+SCALE_SPACE; 1644 1567 1645 if ( dwStyle & TBS_VERT)1568 if (infoPtr->dwStyle & TBS_VERT) 1646 1569 { 1647 1570 INT width = clientRect.right-clientRect.left; … … 1655 1578 } 1656 1579 1657 TRACKBAR_CalcChannel( hwnd,infoPtr);1658 TRACKBAR_CalcThumb( hwnd,infoPtr);1580 TRACKBAR_CalcChannel(infoPtr); 1581 TRACKBAR_CalcThumb(infoPtr); 1659 1582 1660 1583 infoPtr->flags &= ~TB_SELECTIONCHANGED; … … 1663 1586 } 1664 1587 1665 1666 static LRESULT 1667 TRACKBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) 1588 static LRESULT 1589 TRACKBAR_InitColors(TRACKBAR_INFO *infoPtr,BOOL redraw) 1590 { 1591 infoPtr->clrBk = GetSysColor(COLOR_3DFACE); 1592 infoPtr->clrHighlightedThumb = GetSysColor(COLOR_3DHILIGHT); 1593 1594 if (redraw) TRACKBAR_Refresh(infoPtr); 1595 1596 return 0; 1597 } 1598 1599 static LRESULT 1600 TRACKBAR_Create(HWND hwnd,WPARAM wParam,LPARAM lParam) 1668 1601 { 1669 1602 TRACKBAR_INFO *infoPtr; 1670 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);1603 LOGBRUSH lb; 1671 1604 1672 1605 infoPtr = (TRACKBAR_INFO*)initControl(hwnd,sizeof(TRACKBAR_INFO)); 1673 1606 1674 1607 /* set default values */ 1608 infoPtr->hwnd = hwnd; 1609 infoPtr->dwStyle = GetWindowLongA(hwnd,GWL_STYLE);; 1610 1675 1611 infoPtr->nRangeMin = 0; 1676 1612 infoPtr->nRangeMax = 100; … … 1684 1620 infoPtr->uTicFreq = 1; 1685 1621 infoPtr->tics = NULL; 1686 infoPtr->clrBk = GetSysColor(COLOR_3DFACE); 1622 1623 /* Create dotted brush */ 1624 lb.lbStyle = BS_PATTERN; 1625 lb.lbHatch = (INT)CreateBitmap(8, 8, 1, 1, pattern); 1626 infoPtr->hbrThumb = CreateBrushIndirect(&lb); 1627 DeleteObject((HGDIOBJ)lb.lbHatch); 1628 1629 TRACKBAR_InitColors(infoPtr,FALSE); 1687 1630 1688 1631 infoPtr->hwndBuddyLA = 0; … … 1691 1634 infoPtr->bFocus = FALSE; 1692 1635 1693 if ( dwStyle & TBS_VERT)1694 { 1695 infoPtr->fLocation = ( dwStyle & TBS_LEFT) ? TBTS_RIGHT : TBTS_LEFT;1636 if (infoPtr->dwStyle & TBS_VERT) 1637 { 1638 infoPtr->fLocation = (infoPtr->dwStyle & TBS_LEFT) ? TBTS_RIGHT : TBTS_LEFT; 1696 1639 } else 1697 1640 { 1698 infoPtr->fLocation = ( dwStyle & TBS_TOP) ? TBTS_BOTTOM : TBTS_TOP;1699 } 1700 1701 TRACKBAR_InitializeThumb (hwnd);1641 infoPtr->fLocation = (infoPtr->dwStyle & TBS_TOP) ? TBTS_BOTTOM : TBTS_TOP; 1642 } 1643 1644 TRACKBAR_InitializeThumb(infoPtr); 1702 1645 1703 1646 /* Create tooltip control */ 1704 if ( dwStyle & TBS_TOOLTIPS)1647 if (infoPtr->dwStyle & TBS_TOOLTIPS) 1705 1648 { 1706 1649 UINT uFlags = TTF_TRACK | TTF_ABSOLUTE; 1707 1650 1708 if ( dwStyle & TBS_VERT)1651 if (infoPtr->dwStyle & TBS_VERT) 1709 1652 if (infoPtr->fLocation == TBTS_RIGHT) 1710 1653 uFlags |= TTF_ALIGNRIGHT | TTF_VCENTER; … … 1723 1666 } 1724 1667 1725 1726 static LRESULT 1727 TRACKBAR_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam) 1728 { 1729 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);1668 static LRESULT 1669 TRACKBAR_Destroy(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1670 { 1671 if (infoPtr->hbrThumb) 1672 DeleteObject((HGDIOBJ)infoPtr->hbrThumb); 1730 1673 1731 1674 /* delete tooltip control */ … … 1733 1676 1734 1677 COMCTL32_Free(infoPtr->tics); 1735 doneControl( hwnd);1736 1737 return 0; 1738 } 1739 1740 static VOID TRACKBAR_CalcToolTipPos( HWND hwnd,DWORD dwStyle,TRACKBAR_INFO *infoPtr,POINT *pt)1741 { 1742 if ( dwStyle & TBS_VERT)1678 doneControl(infoPtr->hwnd); 1679 1680 return 0; 1681 } 1682 1683 static VOID TRACKBAR_CalcToolTipPos(TRACKBAR_INFO *infoPtr,POINT *pt) 1684 { 1685 if (infoPtr->dwStyle & TBS_VERT) 1743 1686 { 1744 1687 if (infoPtr->fLocation == TBTS_RIGHT) … … 1764 1707 } 1765 1708 } 1766 ClientToScreen(hwnd,pt); 1767 } 1768 1769 static LRESULT 1770 TRACKBAR_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 1771 { 1772 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1773 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE); 1709 ClientToScreen(infoPtr->hwnd,pt); 1710 } 1711 1712 static LRESULT 1713 TRACKBAR_LButtonDown(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1714 { 1774 1715 int clickPlace,prevPos,vertical; 1775 1716 DOUBLE clickPos; … … 1777 1718 POINT clickPoint; 1778 1719 1779 SetFocus (hwnd);1780 1781 vertical = dwStyle & TBS_VERT;1720 SetFocus(infoPtr->hwnd); 1721 1722 vertical = infoPtr->dwStyle & TBS_VERT; 1782 1723 clickPoint.x = (INT)LOWORD(lParam); 1783 1724 clickPoint.y = (INT)HIWORD(lParam); … … 1793 1734 (clickPoint.y >= thumb.top) && 1794 1735 (clickPoint.y <= thumb.bottom) && 1795 ((( dwStyle & TBS_BOTH) &&1736 (((infoPtr->dwStyle & TBS_BOTH) && 1796 1737 (clickPoint.x >= thumb.left) && 1797 1738 (clickPoint.x <= thumb.right) 1798 1739 ) || 1799 (( dwStyle & TBS_LEFT) &&1740 ((infoPtr->dwStyle & TBS_LEFT) && 1800 1741 (clickPoint.x <= thumb.right) && 1801 1742 ((clickPoint.x >= thumb.left) || … … 1807 1748 ) 1808 1749 ) || 1809 (!( dwStyle & (TBS_BOTH | TBS_LEFT)) &&1750 (!(infoPtr->dwStyle & (TBS_BOTH | TBS_LEFT)) && 1810 1751 (clickPoint.x >= thumb.left) && 1811 1752 ((clickPoint.x <= thumb.right) || … … 1821 1762 (clickPoint.x >= thumb.left) && 1822 1763 (clickPoint.x <= thumb.right) && 1823 ((( dwStyle & TBS_BOTH) &&1764 (((infoPtr->dwStyle & TBS_BOTH) && 1824 1765 (clickPoint.y >= thumb.top) && 1825 1766 (clickPoint.y <= thumb.bottom) 1826 1767 ) || 1827 (( dwStyle & TBS_TOP) &&1768 ((infoPtr->dwStyle & TBS_TOP) && 1828 1769 (clickPoint.y <= thumb.bottom) && 1829 1770 ((clickPoint.y >= thumb.top) || … … 1835 1776 ) 1836 1777 ) || 1837 (!( dwStyle & (TBS_BOTH | TBS_TOP)) &&1778 (!(infoPtr->dwStyle & (TBS_BOTH | TBS_TOP)) && 1838 1779 (clickPoint.y >= thumb.top) && 1839 1780 ((clickPoint.y <= thumb.bottom) || … … 1848 1789 { 1849 1790 infoPtr->flags |= TB_DRAG_MODE; 1850 if ( dwStyle & TBS_TOOLTIPS)1791 if (infoPtr->dwStyle & TBS_TOOLTIPS) 1851 1792 { /* enable tooltip */ 1852 1793 TTTOOLINFOA ti; … … 1856 1797 ti.cbSize = sizeof(TTTOOLINFOA); 1857 1798 ti.uId = 0; 1858 ti.hwnd = (UINT) hwnd;1799 ti.hwnd = (UINT)infoPtr->hwnd; 1859 1800 ti.hinst = 0; 1860 sprintf (buf,"% d",infoPtr->nPos);1801 sprintf (buf,"%ld",infoPtr->nPos); 1861 1802 ti.lpszText = (LPSTR)buf; 1862 1803 1863 1804 infoPtr->flags |= TB_SHOW_TOOLTIP; 1864 SetCapture( hwnd);1805 SetCapture(infoPtr->hwnd); 1865 1806 1866 1807 SendMessageA(infoPtr->hwndToolTip,TTM_UPDATETIPTEXTA,0,(LPARAM)&ti); 1867 TRACKBAR_CalcToolTipPos( hwnd,dwStyle,infoPtr,&pt);1808 TRACKBAR_CalcToolTipPos(infoPtr,&pt); 1868 1809 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKPOSITION,0,(LPARAM)MAKELPARAM(pt.x,pt.y)); 1869 1810 1870 1811 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti); 1871 1812 } 1872 SetCapture( hwnd);1873 TRACKBAR_UpdateThumbPosition( hwnd,infoPtr->nPos,TRUE); //change arrow color1813 SetCapture(infoPtr->hwnd); 1814 TRACKBAR_UpdateThumbPosition(infoPtr,infoPtr->nPos,TRUE); //change arrow color 1874 1815 return 0; 1875 1816 } … … 1883 1824 //ScrollMode 1884 1825 infoPtr->flags |= TB_SCROLL_MODE; 1885 SetCapture( hwnd);1886 SetTimer( hwnd,SCROLL_TIMER_ID,SCROLL_TIME,NULL);1826 SetCapture(infoPtr->hwnd); 1827 SetTimer(infoPtr->hwnd,SCROLL_TIMER_ID,SCROLL_TIME,NULL); 1887 1828 1888 1829 return 0; … … 1896 1837 infoPtr->nPos += infoPtr->nPageSize; 1897 1838 if (infoPtr->nPos > infoPtr->nRangeMax) infoPtr->nPos = infoPtr->nRangeMax; 1898 if (prevPos != infoPtr->nPos) TRACKBAR_SendNotify( hwnd,TB_PAGEUP);1839 if (prevPos != infoPtr->nPos) TRACKBAR_SendNotify(infoPtr,TB_PAGEUP); 1899 1840 } else 1900 1841 { /* similar to VK_PRIOR */ 1901 1842 infoPtr->nPos -= infoPtr->nPageSize; 1902 1843 if (infoPtr->nPos < infoPtr->nRangeMin) infoPtr->nPos = infoPtr->nRangeMin; 1903 if (prevPos != infoPtr->nPos) TRACKBAR_SendNotify( hwnd,TB_PAGEDOWN);1844 if (prevPos != infoPtr->nPos) TRACKBAR_SendNotify(infoPtr,TB_PAGEDOWN); 1904 1845 } 1905 1846 … … 1907 1848 { 1908 1849 infoPtr->flags |= TB_THUMBPOSCHANGED; 1909 TRACKBAR_UpdateThumbPosition( hwnd,prevPos,TRUE);1850 TRACKBAR_UpdateThumbPosition(infoPtr,prevPos,TRUE); 1910 1851 } 1911 1852 1912 1853 //ScrollMode 1913 1854 infoPtr->flags |= TB_SCROLL_MODE; 1914 SetCapture(hwnd); 1915 SetTimer(hwnd,SCROLL_TIMER_ID,SCROLL_TIME,NULL); 1916 1917 return 0; 1918 } 1919 1920 1921 static LRESULT 1922 TRACKBAR_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam) 1923 { 1924 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1925 1855 SetCapture(infoPtr->hwnd); 1856 SetTimer(infoPtr->hwnd,SCROLL_TIMER_ID,SCROLL_TIME,NULL); 1857 1858 return 0; 1859 } 1860 1861 1862 static LRESULT 1863 TRACKBAR_LButtonUp(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1864 { 1926 1865 if (infoPtr->flags & TB_DRAG_MODE) 1927 1866 { 1928 TRACKBAR_SendNotify( hwnd,TB_ENDTRACK);1867 TRACKBAR_SendNotify(infoPtr,TB_ENDTRACK); 1929 1868 1930 1869 infoPtr->flags &= ~TB_DRAG_MODE; 1931 1870 1932 if (GetCapture() == hwnd)1871 if (GetCapture() == infoPtr->hwnd) 1933 1872 { 1934 sendNotify( hwnd,NM_RELEASEDCAPTURE);1873 sendNotify(infoPtr->hwnd,NM_RELEASEDCAPTURE); 1935 1874 1936 1875 ReleaseCapture(); 1937 1876 } 1938 1877 1939 TRACKBAR_UpdateThumbPosition( hwnd,infoPtr->nPos,TRUE); //change arrow color1878 TRACKBAR_UpdateThumbPosition(infoPtr,infoPtr->nPos,TRUE); //change arrow color 1940 1879 } 1941 1880 … … 1944 1883 infoPtr->flags &= ~TB_SCROLL_MODE; 1945 1884 1946 if (GetCapture() == hwnd)1885 if (GetCapture() == infoPtr->hwnd) 1947 1886 { 1948 sendNotify( hwnd,NM_RELEASEDCAPTURE);1887 sendNotify(infoPtr->hwnd,NM_RELEASEDCAPTURE); 1949 1888 1950 1889 ReleaseCapture(); 1951 1890 } 1952 1891 1953 KillTimer( hwnd,SCROLL_TIMER_ID);1954 } 1955 1956 if ( GetWindowLongA (hwnd, GWL_STYLE)& TBS_TOOLTIPS)1892 KillTimer(infoPtr->hwnd,SCROLL_TIMER_ID); 1893 } 1894 1895 if (infoPtr->dwStyle & TBS_TOOLTIPS) 1957 1896 { /* disable tooltip */ 1958 1897 TTTOOLINFOA ti; … … 1960 1899 ti.cbSize = sizeof(TTTOOLINFOA); 1961 1900 ti.uId = 0; 1962 ti.hwnd = (UINT) hwnd;1901 ti.hwnd = (UINT)infoPtr->hwnd; 1963 1902 1964 1903 infoPtr->flags &= ~TB_SHOW_TOOLTIP; 1965 SendMessageA (infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 1966 } 1967 1968 return 0; 1969 } 1970 1971 1972 static LRESULT TRACKBAR_Timer(HWND hwnd,WPARAM wParam,LPARAM lParam) 1973 { 1974 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd); 1975 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 1904 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 1905 } 1906 1907 return 0; 1908 } 1909 1910 static LRESULT TRACKBAR_Timer(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1911 { 1976 1912 POINT mousePoint; 1977 1913 INT mousePlace,prevPos,newPos,vertical; … … 1979 1915 1980 1916 GetCursorPos(&mousePoint); 1981 ScreenToClient( hwnd,&mousePoint);1982 1983 vertical = dwStyle & TBS_VERT;1917 ScreenToClient(infoPtr->hwnd,&mousePoint); 1918 1919 vertical = infoPtr->dwStyle & TBS_VERT; 1984 1920 if (vertical) mousePlace = mousePoint.y; 1985 1921 else mousePlace = mousePoint.x; … … 1996 1932 infoPtr->nPos += infoPtr->nPageSize; 1997 1933 if (infoPtr->nPos > infoPtr->nRangeMax) infoPtr->nPos = infoPtr->nRangeMax; 1998 if (prevPos != infoPtr->nPos) TRACKBAR_SendNotify( hwnd,TB_PAGEUP);1934 if (prevPos != infoPtr->nPos) TRACKBAR_SendNotify(infoPtr,TB_PAGEUP); 1999 1935 } else 2000 1936 { /* similar to VK_PRIOR */ 2001 1937 infoPtr->nPos -= infoPtr->nPageSize; 2002 1938 if (infoPtr->nPos < infoPtr->nRangeMin) infoPtr->nPos = infoPtr->nRangeMin; 2003 if (prevPos != infoPtr->nPos) TRACKBAR_SendNotify( hwnd,TB_PAGEDOWN);1939 if (prevPos != infoPtr->nPos) TRACKBAR_SendNotify(infoPtr,TB_PAGEDOWN); 2004 1940 } 2005 1941 … … 2007 1943 { 2008 1944 infoPtr->flags |= TB_THUMBPOSCHANGED; 2009 TRACKBAR_UpdateThumbPosition( hwnd,prevPos,FALSE);1945 TRACKBAR_UpdateThumbPosition(infoPtr,prevPos,FALSE); 2010 1946 } 2011 1947 … … 2014 1950 2015 1951 static LRESULT 2016 TRACKBAR_SetUnicodeFormat(HWND hwnd,WPARAM wParam,LPARAM lParam) 2017 { 2018 //wParam = new format 2019 2020 return FALSE; //previous was no Unicode 2021 } 2022 2023 static LRESULT 2024 TRACKBAR_CaptureChanged (HWND hwnd, WPARAM wParam, LPARAM lParam) 2025 { 2026 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1952 TRACKBAR_CaptureChanged(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1953 { 1954 sendNotify(infoPtr->hwnd,NM_RELEASEDCAPTURE); 2027 1955 2028 1956 if (infoPtr->flags & TB_DRAGPOSVALID) … … 2030 1958 int lastPos = infoPtr->nPos; 2031 1959 infoPtr->nPos = infoPtr->dragPos; 2032 if (lastPos != infoPtr->nPos) TRACKBAR_UpdateThumbPosition( hwnd,lastPos,TRUE);1960 if (lastPos != infoPtr->nPos) TRACKBAR_UpdateThumbPosition(infoPtr,lastPos,TRUE); 2033 1961 } 2034 1962 … … 2038 1966 { 2039 1967 infoPtr->flags &= ~TB_SCROLL_MODE; 2040 KillTimer( hwnd,SCROLL_TIMER_ID);2041 } 2042 2043 TRACKBAR_SendNotify( hwnd,TB_ENDTRACK);2044 return 0; 2045 } 2046 2047 2048 static LRESULT 2049 TRACKBAR_Paint (HWND hwnd,WPARAM wParam)1968 KillTimer(infoPtr->hwnd,SCROLL_TIMER_ID); 1969 } 1970 1971 TRACKBAR_SendNotify(infoPtr,TB_ENDTRACK); 1972 return 0; 1973 } 1974 1975 1976 static LRESULT 1977 TRACKBAR_Paint(TRACKBAR_INFO *infoPtr,WPARAM wParam) 2050 1978 { 2051 1979 HDC hdc; 2052 1980 PAINTSTRUCT ps; 2053 1981 2054 hdc = wParam == 0 ? BeginPaint(hwnd,&ps) : (HDC)wParam; 2055 TRACKBAR_Draw(hwnd,hdc); 2056 if (!wParam) EndPaint(hwnd,&ps); 2057 return 0; 2058 } 2059 2060 2061 static LRESULT 2062 TRACKBAR_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) 2063 { 2064 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1982 hdc = wParam == 0 ? BeginPaint(infoPtr->hwnd,&ps):(HDC)wParam; 1983 TRACKBAR_Draw(infoPtr,hdc); 1984 if (!wParam) EndPaint(infoPtr->hwnd,&ps); 1985 return 0; 1986 } 1987 1988 1989 static LRESULT 1990 TRACKBAR_SetFocus(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 1991 { 2065 1992 HDC hdc; 2066 1993 RECT rcClient; 2067 1994 2068 // TRACE (trackbar,"\n"); 2069 if (!infoPtr->bFocus && IsWindowEnabled(hwnd)) 1995 if (!infoPtr->bFocus && IsWindowEnabled(infoPtr->hwnd)) 2070 1996 { 2071 1997 infoPtr->bFocus = TRUE; 2072 1998 2073 GetClientRect (hwnd,&rcClient); 2074 hdc = GetDC (hwnd); 2075 DrawFocusRect (hdc,&rcClient); 2076 ReleaseDC(hwnd,hdc); 2077 2078 } 2079 return 0; 2080 } 2081 2082 static LRESULT 2083 TRACKBAR_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) 2084 { 2085 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 1999 GetClientRect(infoPtr->hwnd,&rcClient); 2000 hdc = GetDC (infoPtr->hwnd); 2001 DrawFocusRect(hdc,&rcClient); 2002 ReleaseDC(infoPtr->hwnd,hdc); 2003 } 2004 return 0; 2005 } 2006 2007 static LRESULT 2008 TRACKBAR_KillFocus(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 2009 { 2086 2010 HDC hdc; 2087 2011 RECT rcClient; 2088 2012 2089 // TRACE (trackbar,"\n");2090 2013 2091 2014 infoPtr->flags &= ~TB_DRAG_MODE; 2092 if (infoPtr->bFocus && IsWindowEnabled( hwnd))2015 if (infoPtr->bFocus && IsWindowEnabled(infoPtr->hwnd)) 2093 2016 { 2094 2017 infoPtr->bFocus = FALSE; 2095 2018 2096 GetClientRect( hwnd,&rcClient);2097 hdc = GetDC (hwnd);2019 GetClientRect(infoPtr->hwnd,&rcClient); 2020 hdc = GetDC(infoPtr->hwnd); 2098 2021 DrawFocusRect(hdc,&rcClient); //XOR removes 2099 ReleaseDC(hwnd,hdc); 2100 } 2101 2102 return 0; 2103 } 2104 2105 static LRESULT 2106 TRACKBAR_Size (HWND hwnd, WPARAM wParam, LPARAM lParam) 2107 { 2108 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 2109 2110 TRACKBAR_CalcChannel (hwnd, infoPtr); 2111 TRACKBAR_AlignBuddies (hwnd, infoPtr); 2112 2113 return 0; 2114 } 2115 2116 2117 static BOOL TRACKBAR_SendNotify (HWND hwnd, UINT code) 2118 { 2119 if (GetWindowLongA(hwnd, GWL_STYLE) & TBS_VERT) 2120 return sendVScroll(hwnd,code); 2022 ReleaseDC(infoPtr->hwnd,hdc); 2023 } 2024 2025 return 0; 2026 } 2027 2028 static LRESULT 2029 TRACKBAR_Size(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 2030 { 2031 if (!(infoPtr->dwStyle & TBS_FIXEDLENGTH)) 2032 { 2033 /* If trackbar doesn't have TBS_FIXEDLENGTH style 2034 * it sets thumb length according to new width / height. 2035 */ 2036 LONG h; 2037 LONG hmin = (infoPtr->dwStyle & TBS_ENABLESELRANGE) ? THUMB_LEN_SEL:THUMB_LEN; 2038 2039 if (infoPtr->dwStyle & TBS_VERT) 2040 h = (LONG)(INT16)LOWORD(lParam); /* width */ 2041 else 2042 h = (LONG)(INT16)HIWORD(lParam); /* height */ 2043 2044 if (h < hmin) 2045 { 2046 /* focus rect + tic size + thumb offset */ 2047 2048 h -= (BORDER_SIZE+SCALE_SPACE)*2; 2049 } 2050 2051 h = MAX(h,THUMB_MINLEN); 2052 h = MIN(h,hmin); 2053 2054 infoPtr->uThumbLen = h; 2055 } 2056 2057 TRACKBAR_CalcChannel(infoPtr); 2058 TRACKBAR_AlignBuddies(infoPtr); 2059 2060 return 0; 2061 } 2062 2063 static BOOL TRACKBAR_SendNotify(TRACKBAR_INFO *infoPtr,UINT code) 2064 { 2065 if (infoPtr->dwStyle & TBS_VERT) 2066 return sendVScroll(infoPtr->hwnd,code); 2121 2067 else 2122 return sendHScroll(hwnd,code); 2123 } 2124 2125 2126 static LRESULT 2127 TRACKBAR_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam) 2128 { 2129 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd); 2130 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 2068 return sendHScroll(infoPtr->hwnd,code); 2069 } 2070 2071 static LRESULT 2072 TRACKBAR_MouseMove(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 2073 { 2131 2074 SHORT clickPlace; 2132 2075 DOUBLE dragPos; … … 2134 2077 if (!(infoPtr->flags & TB_DRAG_MODE)) return TRUE; 2135 2078 2136 if ( dwStyle & TBS_VERT) clickPlace = (SHORT)HIWORD(lParam);2079 if (infoPtr->dwStyle & TBS_VERT) clickPlace = (SHORT)HIWORD(lParam); 2137 2080 else clickPlace = (SHORT)LOWORD(lParam); 2138 2081 2139 dragPos = TRACKBAR_ConvertPlaceToPosition(infoPtr,clickPlace, dwStyle & TBS_VERT);2082 dragPos = TRACKBAR_ConvertPlaceToPosition(infoPtr,clickPlace,infoPtr->dwStyle & TBS_VERT); 2140 2083 if (dragPos > ((INT)dragPos)+0.5) infoPtr->dragPos = dragPos + 1; 2141 2084 else infoPtr->dragPos = dragPos; … … 2145 2088 infoPtr->flags |= TB_DRAGPOSVALID; 2146 2089 2147 TRACKBAR_UpdateThumbPosition( hwnd,infoPtr->nPos,FALSE); //infoPtr->nPos now set2148 2149 TRACKBAR_SendNotify( hwnd,TB_THUMBTRACK | (infoPtr->nPos << 16));2090 TRACKBAR_UpdateThumbPosition(infoPtr,infoPtr->nPos,FALSE); //infoPtr->nPos now set 2091 2092 TRACKBAR_SendNotify(infoPtr,TB_THUMBTRACK | (infoPtr->nPos << 16)); 2150 2093 2151 2094 if (infoPtr->flags & TB_SHOW_TOOLTIP) … … 2156 2099 2157 2100 ti.cbSize = sizeof(TTTOOLINFOA); 2158 ti.hwnd = hwnd;2101 ti.hwnd = infoPtr->hwnd; 2159 2102 ti.uId = 0; 2160 2103 ti.hinst = 0; … … 2163 2106 2164 2107 SendMessageA(infoPtr->hwndToolTip,TTM_UPDATETIPTEXTA,0,(LPARAM)&ti); 2165 TRACKBAR_CalcToolTipPos( hwnd,dwStyle,infoPtr,&pt);2108 TRACKBAR_CalcToolTipPos(infoPtr,&pt); 2166 2109 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKPOSITION,0,(LPARAM)MAKELPARAM(pt.x,pt.y)); 2167 2110 } … … 2171 2114 2172 2115 static LRESULT 2173 TRACKBAR_Enable(HWND hwnd,WPARAM wParam,LPARAM lParam) 2174 { 2175 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd); 2116 TRACKBAR_Enable(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 2117 { 2176 2118 BOOL oldFocus = infoPtr->bFocus; 2177 2119 2178 if (wParam) infoPtr->bFocus = (GetFocus() == hwnd);2120 if (wParam) infoPtr->bFocus = (GetFocus() == infoPtr->hwnd); 2179 2121 else infoPtr->bFocus = FALSE; 2180 2122 2181 if (oldFocus != infoPtr->bFocus) TRACKBAR_Refresh( hwnd);2182 else TRACKBAR_UpdateThumbPosition( hwnd,infoPtr->nPos,TRUE);2123 if (oldFocus != infoPtr->bFocus) TRACKBAR_Refresh(infoPtr); 2124 else TRACKBAR_UpdateThumbPosition(infoPtr,infoPtr->nPos,TRUE); 2183 2125 2184 2126 return 0; … … 2186 2128 2187 2129 static LRESULT 2188 TRACKBAR_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 2189 { 2190 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd); 2130 TRACKBAR_KeyDown(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 2131 { 2191 2132 INT pos; 2192 2193 // TRACE (trackbar, "%x\n",wParam);2194 2133 2195 2134 if (infoPtr->flags & TB_DRAG_MODE) return TRUE; … … 2203 2142 if (infoPtr->nPos < infoPtr->nRangeMin) 2204 2143 infoPtr->nPos = infoPtr->nRangeMin; 2205 TRACKBAR_SendNotify( hwnd,TB_LINEUP);2144 TRACKBAR_SendNotify(infoPtr,TB_LINEUP); 2206 2145 break; 2207 2146 case VK_RIGHT: … … 2211 2150 if (infoPtr->nPos > infoPtr->nRangeMax) 2212 2151 infoPtr->nPos = infoPtr->nRangeMax; 2213 TRACKBAR_SendNotify (hwnd,TB_LINEDOWN);2152 TRACKBAR_SendNotify(infoPtr,TB_LINEDOWN); 2214 2153 break; 2215 2154 case VK_NEXT: … … 2218 2157 if (infoPtr->nPos > infoPtr->nRangeMax) 2219 2158 infoPtr->nPos = infoPtr->nRangeMax; 2220 TRACKBAR_SendNotify (hwnd,TB_PAGEUP);2159 TRACKBAR_SendNotify(infoPtr,TB_PAGEUP); 2221 2160 break; 2222 2161 case VK_PRIOR: … … 2225 2164 if (infoPtr->nPos < infoPtr->nRangeMin) 2226 2165 infoPtr->nPos = infoPtr->nRangeMin; 2227 TRACKBAR_SendNotify (hwnd,TB_PAGEDOWN);2166 TRACKBAR_SendNotify(infoPtr,TB_PAGEDOWN); 2228 2167 break; 2229 2168 case VK_HOME: 2230 2169 if (infoPtr->nPos == infoPtr->nRangeMin) return FALSE; 2231 2170 infoPtr->nPos = infoPtr->nRangeMin; 2232 TRACKBAR_SendNotify (hwnd,TB_TOP);2171 TRACKBAR_SendNotify(infoPtr,TB_TOP); 2233 2172 break; 2234 2173 case VK_END: 2235 2174 if (infoPtr->nPos == infoPtr->nRangeMax) return FALSE; 2236 2175 infoPtr->nPos = infoPtr->nRangeMax; 2237 TRACKBAR_SendNotify (hwnd,TB_BOTTOM);2176 TRACKBAR_SendNotify(infoPtr,TB_BOTTOM); 2238 2177 break; 2178 2179 default: 2180 return FALSE; 2239 2181 } 2240 2182 … … 2242 2184 { 2243 2185 infoPtr->flags |= TB_THUMBPOSCHANGED; 2244 TRACKBAR_UpdateThumbPosition( hwnd,pos,FALSE);2186 TRACKBAR_UpdateThumbPosition(infoPtr,pos,FALSE); 2245 2187 } 2246 2188 … … 2250 2192 2251 2193 static LRESULT 2252 TRACKBAR_KeyUp (HWND hwnd, WPARAM wParam) 2253 { 2254 TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd); 2255 2194 TRACKBAR_KeyUp(TRACKBAR_INFO *infoPtr,WPARAM wParam) 2195 { 2256 2196 if (infoPtr->flags & TB_DRAG_MODE) return TRUE; 2257 2197 … … 2265 2205 case VK_HOME: 2266 2206 case VK_END: 2267 TRACKBAR_SendNotify (hwnd,TB_ENDTRACK);2207 TRACKBAR_SendNotify(infoPtr,TB_ENDTRACK); 2268 2208 } 2269 2209 return TRUE; 2270 2210 } 2271 2211 2212 static LRESULT 2213 TRACKBAR_StyleChanged(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPSTYLESTRUCT lParam) 2214 { 2215 TRACKBAR_CalcChannel(infoPtr); 2216 2217 return 0; 2218 } 2272 2219 2273 2220 static LRESULT WINAPI 2274 TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 2275 { 2276 switch (uMsg) 2277 { 2221 TRACKBAR_WindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) 2222 { 2223 TRACKBAR_INFO *infoPtr; 2224 2225 if (uMsg == WM_CREATE) 2226 return TRACKBAR_Create(hwnd,wParam,lParam); 2227 2228 infoPtr = TRACKBAR_GetInfoPtr(hwnd); 2229 2230 if (!infoPtr) 2231 goto defproc; 2232 2233 switch (uMsg) 2234 { 2278 2235 case TBM_CLEARSEL: 2279 return TRACKBAR_ClearSel (hwnd, wParam,lParam);2236 return TRACKBAR_ClearSel(infoPtr,wParam,lParam); 2280 2237 2281 2238 case TBM_CLEARTICS: 2282 return TRACKBAR_ClearTics (hwnd, wParam,lParam);2239 return TRACKBAR_ClearTics(infoPtr,wParam,lParam); 2283 2240 2284 2241 case TBM_GETBUDDY: 2285 return TRACKBAR_GetBuddy (hwnd, wParam,lParam);2242 return TRACKBAR_GetBuddy(infoPtr,wParam,lParam); 2286 2243 2287 2244 case TBM_GETCHANNELRECT: 2288 return TRACKBAR_GetChannelRect (hwnd, wParam,lParam);2245 return TRACKBAR_GetChannelRect(infoPtr,wParam,lParam); 2289 2246 2290 2247 case TBM_GETLINESIZE: 2291 return TRACKBAR_GetLineSize (hwnd, wParam,lParam);2248 return TRACKBAR_GetLineSize(infoPtr,wParam,lParam); 2292 2249 2293 2250 case TBM_GETNUMTICS: 2294 return TRACKBAR_GetNumTics (hwnd, wParam,lParam);2251 return TRACKBAR_GetNumTics(infoPtr,wParam,lParam); 2295 2252 2296 2253 case TBM_GETPAGESIZE: 2297 return TRACKBAR_GetPageSize (hwnd, wParam,lParam);2254 return TRACKBAR_GetPageSize(infoPtr,wParam,lParam); 2298 2255 2299 2256 case TBM_GETPOS: 2300 return TRACKBAR_GetPos (hwnd, wParam,lParam);2257 return TRACKBAR_GetPos(infoPtr,wParam,lParam); 2301 2258 2302 2259 case TBM_GETPTICS: 2303 return TRACKBAR_GetPTics (hwnd);2260 return TRACKBAR_GetPTics(infoPtr); 2304 2261 2305 2262 case TBM_GETRANGEMAX: 2306 return TRACKBAR_GetRangeMax (hwnd, wParam,lParam);2263 return TRACKBAR_GetRangeMax(infoPtr,wParam,lParam); 2307 2264 2308 2265 case TBM_GETRANGEMIN: 2309 return TRACKBAR_GetRangeMin (hwnd, wParam,lParam);2266 return TRACKBAR_GetRangeMin(infoPtr,wParam,lParam); 2310 2267 2311 2268 case TBM_GETSELEND: 2312 return TRACKBAR_GetSelEnd (hwnd, wParam,lParam);2269 return TRACKBAR_GetSelEnd(infoPtr,wParam,lParam); 2313 2270 2314 2271 case TBM_GETSELSTART: 2315 return TRACKBAR_GetSelStart (hwnd, wParam,lParam);2272 return TRACKBAR_GetSelStart(infoPtr,wParam,lParam); 2316 2273 2317 2274 case TBM_GETTHUMBLENGTH: 2318 return TRACKBAR_GetThumbLength (hwnd, wParam,lParam);2275 return TRACKBAR_GetThumbLength(infoPtr,wParam,lParam); 2319 2276 2320 2277 case TBM_GETTHUMBRECT: 2321 return TRACKBAR_GetThumbRect (hwnd, wParam,lParam);2278 return TRACKBAR_GetThumbRect(infoPtr,wParam,lParam); 2322 2279 2323 2280 case TBM_GETTIC: 2324 return TRACKBAR_GetTic (hwnd, wParam,lParam);2281 return TRACKBAR_GetTic(infoPtr,wParam,lParam); 2325 2282 2326 2283 case TBM_GETTICPOS: 2327 return TRACKBAR_GetTicPos (hwnd, wParam,lParam);2284 return TRACKBAR_GetTicPos(infoPtr,wParam,lParam); 2328 2285 2329 2286 case TBM_GETTOOLTIPS: 2330 return TRACKBAR_GetToolTips (hwnd, wParam,lParam);2287 return TRACKBAR_GetToolTips(infoPtr,wParam,lParam); 2331 2288 2332 2289 case TBM_SETBUDDY: 2333 return TRACKBAR_SetBuddy (hwnd, wParam,lParam);2290 return TRACKBAR_SetBuddy(infoPtr,wParam,lParam); 2334 2291 2335 2292 case TBM_SETLINESIZE: 2336 return TRACKBAR_SetLineSize (hwnd, wParam,lParam);2293 return TRACKBAR_SetLineSize(infoPtr,wParam,lParam); 2337 2294 2338 2295 case TBM_SETPAGESIZE: 2339 return TRACKBAR_SetPageSize (hwnd, wParam,lParam);2296 return TRACKBAR_SetPageSize(infoPtr,wParam,lParam); 2340 2297 2341 2298 case TBM_SETPOS: 2342 return TRACKBAR_SetPos (hwnd, wParam,lParam);2299 return TRACKBAR_SetPos(infoPtr,wParam,lParam); 2343 2300 2344 2301 case TBM_SETRANGE: 2345 return TRACKBAR_SetRange (hwnd, wParam,lParam);2302 return TRACKBAR_SetRange(infoPtr,wParam,lParam); 2346 2303 2347 2304 case TBM_SETRANGEMAX: 2348 return TRACKBAR_SetRangeMax (hwnd, wParam,lParam);2305 return TRACKBAR_SetRangeMax(infoPtr,wParam,lParam); 2349 2306 2350 2307 case TBM_SETRANGEMIN: 2351 return TRACKBAR_SetRangeMin (hwnd, wParam,lParam);2308 return TRACKBAR_SetRangeMin(infoPtr,wParam,lParam); 2352 2309 2353 2310 case TBM_SETSEL: 2354 return TRACKBAR_SetSel (hwnd, wParam,lParam);2311 return TRACKBAR_SetSel(infoPtr,wParam,lParam); 2355 2312 2356 2313 case TBM_SETSELEND: 2357 return TRACKBAR_SetSelEnd (hwnd, wParam,lParam);2314 return TRACKBAR_SetSelEnd(infoPtr,wParam,lParam); 2358 2315 2359 2316 case TBM_SETSELSTART: 2360 return TRACKBAR_SetSelStart (hwnd, wParam,lParam);2317 return TRACKBAR_SetSelStart(infoPtr,wParam,lParam); 2361 2318 2362 2319 case TBM_SETTHUMBLENGTH: 2363 return TRACKBAR_SetThumbLength (hwnd, wParam,lParam);2320 return TRACKBAR_SetThumbLength(infoPtr,wParam,lParam); 2364 2321 2365 2322 case TBM_SETTIC: 2366 return TRACKBAR_SetTic (hwnd, wParam,lParam);2323 return TRACKBAR_SetTic(infoPtr,wParam,lParam); 2367 2324 2368 2325 case TBM_SETTICFREQ: 2369 return TRACKBAR_SetTicFreq (hwnd,wParam);2326 return TRACKBAR_SetTicFreq(infoPtr,wParam); 2370 2327 2371 2328 case TBM_SETTIPSIDE: 2372 return TRACKBAR_SetTipSide (hwnd, wParam,lParam);2329 return TRACKBAR_SetTipSide(infoPtr,wParam,lParam); 2373 2330 2374 2331 case TBM_SETTOOLTIPS: 2375 return TRACKBAR_SetToolTips (hwnd, wParam, lParam); 2376 2377 case TBM_SETUNICODEFORMAT: 2378 return TRACKBAR_SetUnicodeFormat(hwnd,wParam,lParam); 2332 return TRACKBAR_SetToolTips(infoPtr,wParam,lParam); 2379 2333 2380 2334 case WM_CAPTURECHANGED: 2381 return TRACKBAR_CaptureChanged (hwnd, wParam, lParam); 2382 2383 case WM_CREATE: 2384 return TRACKBAR_Create (hwnd, wParam, lParam); 2335 return TRACKBAR_CaptureChanged(infoPtr,wParam,lParam); 2385 2336 2386 2337 case WM_DESTROY: 2387 return TRACKBAR_Destroy (hwnd, wParam,lParam);2338 return TRACKBAR_Destroy(infoPtr,wParam,lParam); 2388 2339 2389 2340 case WM_ENABLE: 2390 return TRACKBAR_Enable( hwnd,wParam,lParam);2341 return TRACKBAR_Enable(infoPtr,wParam,lParam); 2391 2342 2392 2343 case WM_ERASEBKGND: … … 2397 2348 2398 2349 case WM_KEYDOWN: 2399 return TRACKBAR_KeyDown (hwnd, wParam,lParam);2350 return TRACKBAR_KeyDown(infoPtr,wParam,lParam); 2400 2351 2401 2352 case WM_KEYUP: 2402 return TRACKBAR_KeyUp (hwnd,wParam);2353 return TRACKBAR_KeyUp(infoPtr,wParam); 2403 2354 2404 2355 case WM_LBUTTONDOWN: 2405 return TRACKBAR_LButtonDown (hwnd, wParam,lParam);2356 return TRACKBAR_LButtonDown(infoPtr,wParam,lParam); 2406 2357 2407 2358 case WM_LBUTTONUP: 2408 return TRACKBAR_LButtonUp (hwnd, wParam,lParam);2359 return TRACKBAR_LButtonUp(infoPtr,wParam,lParam); 2409 2360 2410 2361 case WM_TIMER: 2411 return TRACKBAR_Timer( hwnd,wParam,lParam);2362 return TRACKBAR_Timer(infoPtr,wParam,lParam); 2412 2363 2413 2364 case WM_MOUSEMOVE: 2414 return TRACKBAR_MouseMove (hwnd, wParam,lParam);2365 return TRACKBAR_MouseMove(infoPtr,wParam,lParam); 2415 2366 2416 2367 case WM_PAINT: 2417 return TRACKBAR_Paint (hwnd,wParam);2368 return TRACKBAR_Paint(infoPtr,wParam); 2418 2369 2419 2370 case WM_SETFOCUS: 2420 return TRACKBAR_SetFocus (hwnd, wParam,lParam);2371 return TRACKBAR_SetFocus(infoPtr,wParam,lParam); 2421 2372 2422 2373 case WM_KILLFOCUS: 2423 return TRACKBAR_KillFocus (hwnd, wParam, lParam); 2374 return TRACKBAR_KillFocus(infoPtr,wParam,lParam); 2375 2376 case WM_STYLECHANGED: 2377 return TRACKBAR_StyleChanged(infoPtr,wParam,(LPSTYLESTRUCT)lParam); 2424 2378 2425 2379 case WM_SIZE: 2426 return TRACKBAR_Size (hwnd, wParam,lParam);2380 return TRACKBAR_Size(infoPtr,wParam,lParam); 2427 2381 2428 2382 case WM_WININICHANGE: 2429 return TRACKBAR_InitializeThumb (hwnd); 2383 return TRACKBAR_InitializeThumb(infoPtr); 2384 2385 case WM_SYSCOLORCHANGE: 2386 return TRACKBAR_InitColors(infoPtr,TRUE); 2430 2387 2431 2388 default: 2432 // if (uMsg >= WM_USER) 2433 // ERR (trackbar, "unknown msg %04x wp=%08x lp=%08lx\n", 2434 // uMsg, wParam, lParam); 2435 return defComCtl32ProcA (hwnd, uMsg, wParam, lParam); 2389 //if (uMsg >= WM_USER) 2390 // ERR (trackbar, "unknown msg %04x wp=%08x lp=%08lx\n", 2391 // uMsg, wParam, lParam); 2392 defproc: 2393 return defComCtl32ProcA(hwnd,uMsg,wParam,lParam); 2436 2394 } 2437 2395 return 0; … … 2442 2400 TRACKBAR_Register (VOID) 2443 2401 { 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 RegisterClassA(&wndClass);2402 WNDCLASSA wndClass; 2403 2404 ZeroMemory (&wndClass, sizeof(WNDCLASSA)); 2405 wndClass.style = CS_GLOBALCLASS; 2406 wndClass.lpfnWndProc = (WNDPROC)TRACKBAR_WindowProc; 2407 wndClass.cbClsExtra = 0; 2408 wndClass.cbWndExtra = sizeof(TRACKBAR_INFO *); 2409 wndClass.hCursor = LoadCursorA (0, IDC_ARROWA); 2410 wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1); 2411 wndClass.lpszClassName = TRACKBAR_CLASSA; 2412 2413 RegisterClassA(&wndClass); 2456 2414 } 2457 2415 … … 2460 2418 TRACKBAR_Unregister (VOID) 2461 2419 { 2462 2463 } 2464 2420 UnregisterClassA (TRACKBAR_CLASSA, (HINSTANCE)NULL); 2421 } 2422 -
trunk/src/comctl32/treeview.cpp
r3520 r3585 1 /* $Id: treeview.cpp,v 1.1 3 2000-05-10 19:50:33 cbratschi Exp $ */1 /* $Id: treeview.cpp,v 1.14 2000-05-22 17:25:13 cbratschi Exp $ */ 2 2 /* Treeview control 3 3 * … … 8 8 * Copyright 1999-2000 Christoph Bratschi (cbratschi@datacomm.ch) 9 9 * 10 * Note that TREEVIEW_INFO * and HTREEITEM are the same thing. 10 11 * 11 * FIXMEs (for personal use)12 Expand: -ctlmacro expands twice ->toggle.13 -DblClick: ctlmacro.exe's NM_DBLCLK seems to go wrong (returns FALSE).14 -treehelper: stack corruption makes big window.15 12 * 16 13 * Status: complete (many things untested) … … 30 27 - expand not finished 31 28 - WM_ENABLE: draw disabled control 29 - AMD cpuid: text not drawn (> treeview.cpp,v 1.13 2000/05/10 19:50:33) 30 t1: GDI32: SetBkColor to FFFFFF 31 t1: GDI32: GetTextMetricsA returned 1 32 t1: GDI32: SetTextAlign 33 --> 34 t1: GDI32: RestoreDC 35 t1: SendInternalMessageA WM_NOTIFY for 68000003 65 1312e4 36 t1: USER32: GetDlgCtrlID 37 38 missing lines at -->: 39 t1: GDI32: GetTextExtentPoint32A 10001a1 Processor Speed Test 20 returned 1 (93,14) 40 t1: GDI32: ExtTextOutA 10001a1 Processor Speed Test 41 t1: GDI32: GetTextAlign 42 t1: GDI32: GetTextExtentPoint32A 10001a1 454 Mhz 7 returned 1 (37,14) 43 t1: GDI32: ExtTextOutA 10001a1 454 Mhz 44 t1: GDI32: GetTextAlign 45 46 don't know why it fails 32 47 */ 33 48 49 #include <assert.h> 34 50 #include <stdlib.h> 35 51 #include <string.h> 36 52 #include <math.h> 53 #include <limits.h> 37 54 #include "winbase.h" 38 55 #include "wingdi.h" … … 45 62 /* ffs should be in <string.h>. */ 46 63 47 //#define OS2LINEHACK //CB: too slow, but looks good 48 49 /* Defines, since they do not need to return previous state, and nr 50 * has no side effects in this file. 64 //#define NDEBUG 65 #define NDEBUG_TEXT 66 67 #define TEXT_CALLBACK_SIZE 260 68 69 #define TREEVIEW_LEFT_MARGIN 8 70 71 #define MINIMUM_INDENT 19 72 73 #define CALLBACK_MASK_ALL (TVIF_TEXT|TVIF_CHILDREN|TVIF_IMAGE|TVIF_SELECTEDIMAGE) 74 75 #define STATEIMAGEINDEX(x) (((x) >> 12) & 0x0f) 76 #define OVERLAYIMAGEINDEX(x) (((x) >> 8) & 0x0f) 77 78 typedef VOID (*TREEVIEW_ItemEnumFunc)(TREEVIEW_INFO *, TREEVIEW_ITEM *,LPVOID); 79 80 static BOOL TREEVIEW_UnqueueRefresh(TREEVIEW_INFO *,BOOL calc,BOOL refresh); 81 static void TREEVIEW_QueueRefresh(TREEVIEW_INFO *); 82 static void TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr); 83 static void TREEVIEW_RefreshItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,DWORD changed); 84 85 static VOID TREEVIEW_HideInfoTip(TREEVIEW_INFO *infoPtr); 86 static LRESULT TREEVIEW_DoSelectItem(TREEVIEW_INFO *, INT, HTREEITEM, INT); 87 static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *, HTREEITEM); 88 static LRESULT TREEVIEW_RButtonUp(TREEVIEW_INFO *, LPPOINT); 89 static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel); 90 static VOID TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr, BOOL); 91 static VOID TREEVIEW_CheckInfoTip(TREEVIEW_INFO *infoPtr); 92 static VOID TREEVIEW_ISearch(TREEVIEW_INFO *infoPtr,CHAR ch); 93 94 /* Random Utilities *****************************************************/ 95 96 #ifdef NDEBUG 97 static inline void 98 TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr) 99 { 100 (void)infoPtr; 101 } 102 103 #else 104 /* The definition is at the end of the file. */ 105 static void TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr); 106 #ifndef NDEBUG_TEXT 107 static void TREEVIEW_WriteVerify(CHAR *text) 108 { 109 dprintf((text)); 110 } 111 #else 112 static inline void TREEVIEW_WriteVerify(CHAR * text) {} 113 #endif 114 #endif 115 116 /* Returns the treeview private data if hwnd is a treeview. 117 * Otherwise returns an undefined value. */ 118 #define TREEVIEW_GetInfoPtr(hwnd) ((TREEVIEW_INFO *)getInfoPtr(hwnd)) 119 120 /* Don't call this. Nothing wants an item index. */ 121 static inline int 122 TREEVIEW_GetItemIndex(TREEVIEW_INFO *infoPtr, HTREEITEM handle) 123 { 124 assert(infoPtr != NULL); 125 126 return DPA_GetPtrIndex(infoPtr->items,handle); 127 } 128 129 /*************************************************************************** 130 * This method checks that handle is an item for this tree. 51 131 */ 52 #define tv_test_bit(nr,bf) (((LPBYTE)bf)[nr>>3]&(1<<(nr&7))) 53 #define tv_set_bit(nr,bf) ((LPBYTE)bf)[nr>>3]|=(1<<(nr&7)) 54 #define tv_clear_bit(nr,bf) ((LPBYTE)bf)[nr>>3]&=~(1<<(nr&7)) 55 56 #define TREEVIEW_GetInfoPtr(hwnd) ((TREEVIEW_INFO *)getInfoPtr(hwnd)) 57 58 static BOOL TREEVIEW_SendTreeviewNotify (HWND hwnd, UINT code, UINT action, HTREEITEM oldItem, HTREEITEM newItem); 59 static BOOL TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem, POINT pt); 60 static INT TREEVIEW_CallbackChildren(HWND hwnd,TREEVIEW_ITEM *wineItem); 61 static INT TREEVIEW_CallbackImage(HWND hwnd,TREEVIEW_ITEM *wineItem); 62 static INT TREEVIEW_CallbackSelectedImage(HWND hwnd,TREEVIEW_ITEM *wineItem); 63 static WCHAR* TREEVIEW_CallbackText(HWND hwnd,TREEVIEW_ITEM *wineItem,BOOL *mustFree); 64 static BOOL TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc, RECT rc); 65 static BOOL TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc, TREEVIEW_ITEM *tvItem, UINT uItemDrawState); 66 static LRESULT TREEVIEW_RButtonUp (HWND hwnd, LPPOINT pPt); 67 static LRESULT TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam); 68 static LRESULT TREEVIEW_DoSelectItem(HWND hwnd,INT action,HTREEITEM newSelect,INT cause); 69 static void TREEVIEW_Refresh(HWND hwnd); 70 static void TREEVIEW_RefreshItem(HWND hwnd,TREEVIEW_ITEM *item,BOOL wholeLine); 71 static void TREEVIEW_Draw(HWND hwnd,HDC hdc,RECT *updateRect); 72 static BOOL TREEVIEW_UnqueueRefresh(HWND hwnd,BOOL calc,BOOL refresh); 73 static void TREEVIEW_QueueRefresh(HWND hwnd); 74 static void TREEVIEW_CalcItem(HWND hwnd,HDC hdc,DWORD dwStyle,TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item); 75 static BOOL TREEVIEW_CalcItems(HWND hwnd,HDC hdc,TREEVIEW_INFO *infoPtr); 76 static LRESULT TREEVIEW_EnsureVisible(HWND hwnd,HTREEITEM hItem); 77 static VOID TREEVIEW_ISearch(HWND hwnd,CHAR ch); 78 static VOID TREEVIEW_CheckInfoTip(HWND hwnd); 79 static VOID TREEVIEW_HideInfoTip(HWND hwnd,TREEVIEW_INFO *infoPtr); 80 81 static LRESULT CALLBACK TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); 82 83 LRESULT WINAPI TREEVIEW_EndEditLabelNow (HWND hwnd, BOOL bCancel); 84 85 HWND TREEVIEW_EditLabel(HWND hwnd, HTREEITEM hItem,BOOL unicode); 86 87 /* helper functions. Work with the assumption that validity of operands 88 is checked beforehand, and that tree state is valid. */ 89 90 /* FIXME: MS documentation says `GetNextVisibleItem' returns NULL 91 if not succesfull'. Probably only applies to derefencing infoPtr 92 (ie we are offered a valid treeview structure) 93 and not whether there is a next `visible' child. 94 FIXME: check other failures. 132 static BOOL 133 TREEVIEW_ValidItem(TREEVIEW_INFO *infoPtr,HTREEITEM handle) 134 { 135 if (TREEVIEW_GetItemIndex(infoPtr, handle) == -1) 136 { 137 //TRACE("invalid item %p\n", handle); 138 return FALSE; 139 } 140 else 141 return TRUE; 142 } 143 144 static HFONT 145 TREEVIEW_CreateBoldFont(HFONT hOrigFont) 146 { 147 LOGFONTA font; 148 149 GetObjectA(hOrigFont, sizeof(font), &font); 150 font.lfWeight = FW_BOLD; 151 152 return CreateFontIndirectA(&font); 153 } 154 155 static inline HFONT 156 TREEVIEW_FontForItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 157 { 158 return (item->state & TVIS_BOLD) ? infoPtr->hBoldFont : infoPtr->hFont; 159 } 160 161 /* for trace/debugging purposes only */ 162 static const WCHAR * 163 TREEVIEW_ItemName(TREEVIEW_ITEM *item) 164 { 165 if (item == NULL) return (WCHAR*)L"<null item>"; 166 if (item->pszText == LPSTR_TEXTCALLBACKW) return (WCHAR*)L"<callback>"; 167 if (item->pszText == NULL) return (WCHAR*)L"<null>"; 168 /* It would be nice to check item->callbackMask & TVIF_TEXT here, 169 * and indicate that this is a callback string, but there is nowhere 170 * to put that indication. (Or we could be clever, and put it before 171 * pszText, but that is just too hacky.) */ 172 return item->pszText; 173 } 174 175 /* An item is not a child of itself. */ 176 static BOOL 177 TREEVIEW_IsChildOf(TREEVIEW_ITEM *parent, TREEVIEW_ITEM *child) 178 { 179 do 180 { 181 child = child->parent; 182 if (child == parent) return TRUE; 183 } while (child != NULL); 184 185 return FALSE; 186 } 187 188 /* Tree Traversal *******************************************************/ 189 190 /*************************************************************************** 191 * This method returns the last expanded sibling or child child item 192 * of a tree node 95 193 */ 194 static TREEVIEW_ITEM * 195 TREEVIEW_GetLastListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) 196 { 197 /* 198 * Get this item's last sibling 199 */ 200 while (wineItem->nextSibling) 201 wineItem = wineItem->nextSibling; 202 203 /* 204 * If the last sibling has expanded children, restart. 205 */ 206 if ((wineItem->state & TVIS_EXPANDED) && wineItem->firstChild != NULL) 207 { 208 return TREEVIEW_GetLastListItem(infoPtr, wineItem->firstChild); 209 } 210 211 return wineItem; 212 } 96 213 97 214 /*************************************************************************** 98 * This method returns the TREEVIEW_ITEM object given the handle 99 */ 100 static TREEVIEW_ITEM* TREEVIEW_ValidItem( 101 TREEVIEW_INFO *infoPtr, 102 HTREEITEM handle) 103 { 104 if ((!handle) || (handle>infoPtr->uMaxHandle)) 105 return NULL; 106 107 if (tv_test_bit ((INT)handle, infoPtr->freeList)) 108 return NULL; 109 110 return &infoPtr->items[(INT)handle]; 111 } 112 113 /*************************************************************************** 114 * This function uses cChildren field to decide whether item has children 115 * or not. 116 * Note: return value doesn't reflect physical presence of children. 117 */ 118 static INT TREEVIEW_HasChildren( 119 HWND hwnd, 120 TREEVIEW_ITEM *wineItem) 121 { 122 INT cChildren = 0; 123 124 if ( wineItem->mask & TVIF_CHILDREN ) 125 { 126 if (wineItem->cChildren == I_CHILDRENCALLBACK) 127 cChildren = TREEVIEW_CallbackChildren(hwnd,wineItem); 128 else 129 cChildren = wineItem->cChildren; 130 } 131 else if ( wineItem->firstChild ) 132 cChildren = 1; 133 134 return cChildren; 135 } 136 137 /*************************************************************************** 138 * This method returns the last expanded child item of a tree node 139 */ 140 static TREEVIEW_ITEM *TREEVIEW_GetLastListItem( 141 HWND hwnd, 142 TREEVIEW_INFO *infoPtr, 143 TREEVIEW_ITEM *tvItem) 144 { 145 TREEVIEW_ITEM *wineItem = tvItem; 146 147 /* 148 * Get this item last sibling 149 */ 150 while (wineItem->sibling) 151 wineItem=& infoPtr->items [(INT)wineItem->sibling]; 152 153 /* 154 * If the last sibling has expanded children, restart. 155 */ 156 if ((wineItem->state & TVIS_EXPANDED) && 157 TREEVIEW_HasChildren(hwnd, wineItem)) 158 { 159 return TREEVIEW_GetLastListItem( 160 hwnd, 161 infoPtr, 162 &(infoPtr->items[(INT)wineItem->firstChild])); 163 } 164 165 return wineItem; 166 } 167 168 /*************************************************************************** 169 * This method returns the previous physical item in the list not 215 * This method returns the previous non-hidden item in the list not 170 216 * considering the tree hierarchy. 171 217 */ 172 static TREEVIEW_ITEM *TREEVIEW_GetPrevListItem( 173 HWND hwnd, 174 TREEVIEW_INFO *infoPtr, 175 TREEVIEW_ITEM *tvItem) 176 { 177 if (tvItem->upsibling) 178 { 179 /* 180 * This item has a upsibling, get the last item. Since, GetLastListItem 181 * first looks at siblings, we must feed it with the first child. 182 */ 183 TREEVIEW_ITEM *upItem = &infoPtr->items[(INT)tvItem->upsibling]; 184 185 if ( (upItem->state & TVIS_EXPANDED) && 186 TREEVIEW_HasChildren(hwnd, upItem) ) 187 { 188 return TREEVIEW_GetLastListItem( 189 hwnd, 190 infoPtr, 191 &infoPtr->items[(INT)upItem->firstChild]); 218 static TREEVIEW_ITEM * 219 TREEVIEW_GetPrevListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem) 220 { 221 if (tvItem->prevSibling) 222 { 223 /* 224 * This item has a prevSibling, get the last item. Since 225 * GetLastListItem first looks at siblings, we must feed it with the 226 * first child. 227 */ 228 TREEVIEW_ITEM *upItem = tvItem->prevSibling; 229 230 if ((upItem->state & TVIS_EXPANDED) && upItem->firstChild != NULL) 231 return TREEVIEW_GetLastListItem(infoPtr, upItem->firstChild); 232 else 233 return upItem; 192 234 } 193 235 else 194 return upItem; 195 } 196 else 197 { 198 /* 199 * this item does not have a upsibling, get the parent 200 */ 201 if (tvItem->parent) 202 return &infoPtr->items[(INT)tvItem->parent]; 203 } 204 205 return NULL; 236 { 237 /* 238 * this item does not have a prevSibling, get the parent 239 */ 240 return (tvItem->parent != infoPtr->root) ? tvItem->parent : NULL; 241 } 206 242 } 207 243 … … 211 247 * considering the tree hierarchy. 212 248 */ 213 static TREEVIEW_ITEM *TREEVIEW_GetNextListItem( 214 HWND hwnd, 215 TREEVIEW_INFO *infoPtr, 216 TREEVIEW_ITEM *tvItem) 217 { 218 TREEVIEW_ITEM *wineItem = NULL; 219 220 /* 221 * If this item has children and is expanded, return the first child 222 */ 223 if ( (tvItem->state & TVIS_EXPANDED) && 224 TREEVIEW_HasChildren(hwnd, tvItem) ) 225 { 226 return (& infoPtr->items[(INT)tvItem->firstChild]); 227 } 228 229 230 /* 231 * try to get the sibling 232 */ 233 if (tvItem->sibling) 234 return (& infoPtr->items[(INT)tvItem->sibling]); 235 236 /* 237 * Otherwise, get the parent's sibling. 238 */ 239 wineItem=tvItem; 240 while (wineItem->parent) { 241 wineItem=& infoPtr->items [(INT)wineItem->parent]; 242 if (wineItem->sibling) 243 return (& infoPtr->items [(INT)wineItem->sibling]); 244 } 245 246 return NULL; 249 static TREEVIEW_ITEM * 250 TREEVIEW_GetNextListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *tvItem) 251 { 252 assert(infoPtr != NULL); 253 assert(tvItem != NULL); 254 255 /* 256 * If this item has children and is expanded, return the first child 257 */ 258 if ((tvItem->state & TVIS_EXPANDED) && tvItem->firstChild != NULL) 259 { 260 return tvItem->firstChild; 261 } 262 263 264 /* 265 * try to get the sibling 266 */ 267 if (tvItem->nextSibling) 268 return tvItem->nextSibling; 269 270 /* 271 * Otherwise, get the parent's sibling. 272 */ 273 while (tvItem->parent) 274 { 275 tvItem = tvItem->parent; 276 277 if (tvItem->nextSibling) 278 return tvItem->nextSibling; 279 } 280 281 return NULL; 247 282 } 248 283 … … 254 289 * forward if count is >0. 255 290 */ 256 static TREEVIEW_ITEM *TREEVIEW_GetListItem( 257 HWND hwnd, 258 TREEVIEW_INFO *infoPtr, 259 TREEVIEW_ITEM *tvItem, 260 LONG count) 261 { 262 TREEVIEW_ITEM *previousItem = NULL; 263 TREEVIEW_ITEM *wineItem = tvItem; 264 LONG iter = 0; 265 266 if (count > 0) 267 { 268 /* Find count item downward */ 269 while ((iter++ < count) && (wineItem != NULL)) 270 { 271 /* Keep a pointer to the previous in case we ask for more than we got */ 272 previousItem = wineItem; 273 wineItem = TREEVIEW_GetNextListItem(hwnd,infoPtr,wineItem); 274 } 275 276 if (wineItem == NULL) 277 wineItem = previousItem; 278 } 279 else if (count < 0) 280 { 281 /* Find count item upward */ 282 while ((iter-- > count) && (wineItem != NULL)) 283 { 284 /* Keep a pointer to the previous in case we ask for more than we got */ 285 previousItem = wineItem; 286 wineItem = TREEVIEW_GetPrevListItem(hwnd,infoPtr,wineItem); 287 } 288 289 if (wineItem == NULL) 290 wineItem = previousItem; 291 } 292 else 293 wineItem = NULL; 294 295 return wineItem; 296 } 297 291 static TREEVIEW_ITEM * 292 TREEVIEW_GetListItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 293 LONG count) 294 { 295 TREEVIEW_ITEM *(*next_item)(TREEVIEW_INFO *, TREEVIEW_ITEM *); 296 TREEVIEW_ITEM *previousItem; 297 298 assert(wineItem != NULL); 299 300 if (count > 0) 301 { 302 next_item = TREEVIEW_GetNextListItem; 303 } 304 else if (count < 0) 305 { 306 count = -count; 307 next_item = TREEVIEW_GetPrevListItem; 308 } 309 else 310 return wineItem; 311 312 do 313 { 314 previousItem = wineItem; 315 wineItem = next_item(infoPtr, wineItem); 316 317 } while (--count && wineItem != NULL); 318 319 320 return wineItem ? wineItem : previousItem; 321 } 322 323 static VOID 324 TREEVIEW_ForEachDisplayed(TREEVIEW_INFO *infoPtr,TREEVIEW_ItemEnumFunc func,LPVOID data) 325 { 326 TREEVIEW_ITEM *item; 327 328 for (item = infoPtr->root->firstChild; item != NULL; 329 item = TREEVIEW_GetNextListItem(infoPtr, item)) 330 { 331 func(infoPtr, item, data); 332 } 333 } 334 335 /* Notifications */ 336 337 static VOID 338 TREEVIEW_TVItemFromItem(UINT mask,TVITEMW *tvItem,TREEVIEW_ITEM *item) 339 { 340 tvItem->mask = mask; 341 tvItem->hItem = item; 342 tvItem->state = item->state; 343 tvItem->stateMask = 0; 344 tvItem->iImage = item->iImage; 345 tvItem->pszText = item->pszText; 346 tvItem->cchTextMax = item->cchTextMax; 347 tvItem->iImage = item->iImage; 348 tvItem->iSelectedImage = item->iSelectedImage; 349 tvItem->cChildren = item->cChildren; 350 tvItem->lParam = item->lParam; 351 } 352 353 static BOOL TREEVIEW_SendTreeviewNotify(TREEVIEW_INFO *infoPtr,UINT code,UINT action,UINT mask,HTREEITEM oldItem,HTREEITEM newItem) 354 { 355 NMTREEVIEWW nmhdr; 356 CHAR *oldText = NULL,*newText = NULL; 357 BOOL rc; 358 359 ZeroMemory(&nmhdr,sizeof(NMTREEVIEWW)); 360 361 nmhdr.action = action; 362 if (oldItem) 363 { 364 TREEVIEW_TVItemFromItem(mask, &nmhdr.itemOld, oldItem); 365 if (!isUnicodeNotify(&infoPtr->header)) 366 { 367 if (!oldItem->pszText || (oldItem->pszText == LPSTR_TEXTCALLBACKW)) nmhdr.itemOld.pszText = NULL; else 368 { 369 INT len = lstrlenW(oldItem->pszText)+1; 370 371 oldText = (CHAR*)COMCTL32_Alloc(len); 372 lstrcpyWtoA(oldText,oldItem->pszText); 373 nmhdr.itemOld.pszText = (WCHAR*)oldText; 374 nmhdr.itemOld.cchTextMax = len; 375 } 376 } 377 } 378 379 if (newItem) 380 { 381 TREEVIEW_TVItemFromItem(mask, &nmhdr.itemNew, newItem); 382 if (!isUnicodeNotify(&infoPtr->header)) 383 { 384 if (!newItem->pszText || (newItem->pszText == LPSTR_TEXTCALLBACKW)) nmhdr.itemNew.pszText = NULL; else 385 { 386 INT len = lstrlenW(newItem->pszText)+1; 387 388 newText = (CHAR*)COMCTL32_Alloc(len); 389 lstrcpyWtoA(newText,newItem->pszText); 390 nmhdr.itemNew.pszText = (WCHAR*)newText; 391 nmhdr.itemNew.cchTextMax = len; 392 } 393 } 394 } 395 396 nmhdr.ptDrag.x = 0; 397 nmhdr.ptDrag.y = 0; 398 399 rc = (BOOL)sendNotify(infoPtr->hwnd,code,&nmhdr.hdr); 400 401 if (oldText) COMCTL32_Free(oldText); 402 if (newText) COMCTL32_Free(newText); 403 404 return rc; 405 } 406 407 static BOOL 408 TREEVIEW_SendTreeviewDnDNotify (TREEVIEW_INFO *infoPtr,UINT code,HTREEITEM dragItem,POINT pt) 409 { 410 NMTREEVIEWA nmhdr; 411 412 nmhdr.action = 0; 413 nmhdr.itemNew.mask = TVIF_STATE | TVIF_PARAM | TVIF_HANDLE; 414 nmhdr.itemNew.hItem = dragItem; 415 nmhdr.itemNew.state = dragItem->state; 416 nmhdr.itemNew.lParam = dragItem->lParam; 417 418 nmhdr.ptDrag.x = pt.x; 419 nmhdr.ptDrag.y = pt.y; 420 421 return (BOOL)sendNotify(infoPtr->hwnd,code,&nmhdr.hdr); 422 } 423 424 static BOOL 425 TREEVIEW_SendCustomDrawNotify(TREEVIEW_INFO *infoPtr,DWORD dwDrawStage,HDC hdc,RECT rc) 426 { 427 NMTVCUSTOMDRAW nmcdhdr; 428 LPNMCUSTOMDRAW nmcd; 429 430 nmcd = &nmcdhdr.nmcd; 431 nmcd->dwDrawStage = dwDrawStage; 432 nmcd->hdc = hdc; 433 nmcd->rc = rc; 434 nmcd->dwItemSpec = 0; 435 nmcd->uItemState = 0; 436 nmcd->lItemlParam = 0; 437 nmcdhdr.clrText = infoPtr->clrText; 438 nmcdhdr.clrTextBk = infoPtr->clrBk; 439 nmcdhdr.iLevel = 0; 440 441 return (BOOL)sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&nmcdhdr.nmcd.hdr); 442 } 443 444 /* FIXME: need to find out when the flags in uItemState need to be set */ 445 static BOOL 446 TREEVIEW_SendCustomDrawItemNotify(TREEVIEW_INFO *infoPtr,HDC hdc,TREEVIEW_ITEM *wineItem,UINT uItemDrawState) 447 { 448 NMTVCUSTOMDRAW nmcdhdr; 449 LPNMCUSTOMDRAW nmcd; 450 DWORD dwDrawStage,dwItemSpec; 451 UINT uItemState; 452 INT retval; 453 454 dwDrawStage = CDDS_ITEM | uItemDrawState; 455 dwItemSpec = (DWORD)wineItem; 456 uItemState = 0; 457 if (wineItem == infoPtr->selectedItem) 458 { 459 uItemState |= CDIS_SELECTED; 460 if (GetFocus() == infoPtr->hwnd) uItemState |= CDIS_FOCUS; 461 } 462 if (wineItem == infoPtr->focusItem) 463 uItemState |= CDIS_FOCUS; 464 if (wineItem == infoPtr->hotItem) 465 uItemState |= CDIS_HOT; 466 467 nmcd = &nmcdhdr.nmcd; 468 nmcd->dwDrawStage = dwDrawStage; 469 nmcd->hdc = hdc; 470 nmcd->rc = wineItem->rect; 471 nmcd->dwItemSpec = dwItemSpec; 472 nmcd->uItemState = uItemState; 473 nmcd->lItemlParam = wineItem->lParam; 474 nmcdhdr.clrText = infoPtr->clrText; 475 nmcdhdr.clrTextBk = infoPtr->clrBk; 476 nmcdhdr.iLevel = wineItem->iLevel; 477 478 retval = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&nmcdhdr.nmcd.hdr); 479 480 infoPtr->clrText = nmcdhdr.clrText; 481 infoPtr->clrBk = nmcdhdr.clrTextBk; 482 483 return (BOOL)retval; 484 } 485 486 static void 487 TREEVIEW_GetDispInfo(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *wineItem,NMTVDISPINFOW* info,UINT mask) 488 { 489 info->item.mask = mask; 490 info->item.hItem = wineItem; 491 info->item.state = wineItem->state; 492 info->item.stateMask = 0; 493 info->item.lParam = wineItem->lParam; 494 495 sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&info->hdr); 496 } 497 498 static void 499 TREEVIEW_UpdateDispInfo(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *wineItem,UINT mask) 500 { 501 NMTVDISPINFOW callback; 502 503 mask &= wineItem->callbackMask; 504 505 if (mask == 0) return; 506 507 if ((mask & TVIF_TEXT) /*&& (wineItem->cchTextMax < TEXT_CALLBACK_SIZE)*/) 508 { 509 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,TEXT_CALLBACK_SIZE*sizeof(WCHAR)); 510 wineItem->cchTextMax = TEXT_CALLBACK_SIZE; 511 } 512 513 callback.item.pszText = wineItem->pszText; 514 callback.item.cchTextMax = wineItem->cchTextMax; 515 callback.item.iImage = wineItem->iImage; 516 callback.item.iSelectedImage = wineItem->iSelectedImage; 517 callback.item.cChildren = wineItem->cChildren; 518 519 TREEVIEW_GetDispInfo(infoPtr,wineItem,&callback,mask); 520 521 /* It may have changed due to a call to SetItem. */ 522 mask &= wineItem->callbackMask; 523 524 if (mask & TVIF_TEXT) 525 { 526 if (callback.item.pszText != wineItem->pszText) 527 { 528 INT len = MAX((isUnicodeNotify(&infoPtr->header) ? lstrlenW(callback.item.pszText):lstrlenA((CHAR*)callback.item.pszText))+1,TEXT_CALLBACK_SIZE); 529 530 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,len*sizeof(WCHAR)); 531 if (isUnicodeNotify(&infoPtr->header)) 532 lstrcpyW(wineItem->pszText,callback.item.pszText); 533 else 534 lstrcpyAtoW(wineItem->pszText,(CHAR*)callback.item.pszText); 535 wineItem->cchTextMax = len; 536 } else if (!isUnicodeNotify(&infoPtr->header)) 537 { 538 WCHAR *newText; 539 INT len = MAX(lstrlenA((CHAR*)callback.item.pszText)+1,TEXT_CALLBACK_SIZE); 540 541 newText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 542 lstrcpyAtoW(newText,(LPSTR)callback.item.pszText); 543 COMCTL32_Free(wineItem->pszText); 544 wineItem->pszText = newText; 545 wineItem->cchTextMax = len; 546 } 547 } 548 549 if (mask & TVIF_IMAGE) 550 wineItem->iImage = callback.item.iImage; 551 552 if (mask & TVIF_SELECTEDIMAGE) 553 wineItem->iSelectedImage = callback.item.iSelectedImage; 554 555 if (mask & TVIF_CHILDREN) 556 wineItem->cChildren = callback.item.cChildren; 557 558 /* These members are now permanently set. */ 559 if (callback.item.mask & TVIF_DI_SETITEM) 560 wineItem->callbackMask &= ~callback.item.mask; 561 } 562 563 static VOID TREEVIEW_SendKeyDownNotify(TREEVIEW_INFO *infoPtr,UINT code,WORD wVKey) 564 { 565 NMTVKEYDOWN nmkdhdr; 566 567 nmkdhdr.wVKey = wVKey; 568 nmkdhdr.flags = 0; 569 570 sendNotify(infoPtr->hwnd,code,&nmkdhdr.hdr); 571 } 298 572 299 573 /*************************************************************************** 300 * This method 574 * This function uses cChildren field to decide whether the item has 575 * children or not. 576 * Note: if this returns TRUE, the child items may not actually exist, 577 * they could be virtual. 578 * 579 * Just use wineItem->firstChild to check for physical children. 301 580 */ 302 static void TREEVIEW_RemoveAllChildren( 303 HWND hwnd, 304 TREEVIEW_ITEM *parentItem) 305 { 306 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 307 TREEVIEW_ITEM *killItem; 308 INT kill; 309 310 kill=(INT)parentItem->firstChild; 311 while (kill) 312 { 313 tv_set_bit ( kill, infoPtr->freeList); 314 infoPtr->uNumItems--; 315 killItem=& infoPtr->items[kill]; 316 if (killItem->pszText != LPSTR_TEXTCALLBACKW) 317 COMCTL32_Free (killItem->pszText); 318 killItem->pszText = NULL; 319 TREEVIEW_SendTreeviewNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_DELETEITEMW:TVN_DELETEITEMA, 0, (HTREEITEM)kill, 0); 320 if (killItem->firstChild) 321 TREEVIEW_RemoveAllChildren (hwnd, killItem); 322 kill=(INT)killItem->sibling; 323 } 324 325 parentItem->firstChild = 0; 326 } 327 328 329 static void 330 TREEVIEW_RemoveItem (HWND hwnd, TREEVIEW_ITEM *wineItem) 331 332 { 333 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 334 TREEVIEW_ITEM *parentItem, *upsiblingItem, *siblingItem; 335 INT iItem; 336 337 if (infoPtr->hwndEdit) SetFocus(hwnd); 338 339 iItem=(INT)wineItem->hItem; 340 tv_set_bit(iItem,infoPtr->freeList); 341 infoPtr->uNumItems--; 342 parentItem=NULL; 343 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) 344 COMCTL32_Free (wineItem->pszText); 345 wineItem->pszText = NULL; 346 347 TREEVIEW_SendTreeviewNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_DELETEITEMW:TVN_DELETEITEMA, 0, (HTREEITEM)iItem, 0); 348 349 if (wineItem->firstChild) 350 TREEVIEW_RemoveAllChildren (hwnd,wineItem); 351 352 if (wineItem->parent) { 353 parentItem=& infoPtr->items [(INT)wineItem->parent]; 354 if ((INT)parentItem->firstChild==iItem) 355 parentItem->firstChild=wineItem->sibling; 356 } 357 358 if (iItem==(INT)infoPtr->TopRootItem) 359 infoPtr->TopRootItem=(HTREEITEM)wineItem->sibling; 360 if (wineItem->upsibling) { 361 upsiblingItem=& infoPtr->items [(INT)wineItem->upsibling]; 362 upsiblingItem->sibling=wineItem->sibling; 363 } 364 if (wineItem->sibling) { 365 siblingItem=& infoPtr->items [(INT)wineItem->sibling]; 366 siblingItem->upsibling=wineItem->upsibling; 367 } 368 369 if (iItem==(INT)infoPtr->selectedItem) { 370 if (!wineItem->upsibling) 371 infoPtr->selectedItem = 0; 372 else 373 TREEVIEW_DoSelectItem(hwnd, TVGN_CARET, wineItem->upsibling, TVC_UNKNOWN); 374 } 375 } 376 377 /* Note:TREEVIEW_RemoveTree doesn't remove infoPtr itself */ 378 379 static void TREEVIEW_RemoveTree (HWND hwnd) 380 { 381 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 382 TREEVIEW_ITEM *killItem; 383 int i; 384 385 TREEVIEW_EndEditLabelNow(hwnd,TRUE); 386 387 for (i=1; i<=(INT)infoPtr->uMaxHandle; i++) 388 if (!tv_test_bit (i, infoPtr->freeList)) { 389 killItem=& infoPtr->items [i]; 390 if (killItem->pszText != LPSTR_TEXTCALLBACKW) 391 COMCTL32_Free (killItem->pszText); 392 killItem->pszText = NULL; 393 394 TREEVIEW_SendTreeviewNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_DELETEITEMW:TVN_DELETEITEMA, 0, killItem->hItem, 0); 395 } 396 397 if (infoPtr->uNumPtrsAlloced) { 398 COMCTL32_Free (infoPtr->items); 399 COMCTL32_Free (infoPtr->freeList); 400 infoPtr->uNumItems=0; 401 infoPtr->uNumPtrsAlloced=0; 402 infoPtr->uMaxHandle=0; 403 infoPtr->lefttop.x = infoPtr->lefttop.y = 0; 404 } 405 } 406 407 408 static LRESULT 409 TREEVIEW_GetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) 410 { 411 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 412 413 if ((INT)wParam == TVSIL_NORMAL) 414 return (LRESULT) infoPtr->himlNormal; 415 if ((INT)wParam == TVSIL_STATE) 416 return (LRESULT) infoPtr->himlState; 417 418 return 0; 419 } 420 421 static LRESULT 422 TREEVIEW_SetImageList (HWND hwnd, WPARAM wParam, LPARAM lParam) 423 { 424 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 425 HIMAGELIST himlTemp; 426 427 switch ((INT)wParam) { 428 case TVSIL_NORMAL: 429 himlTemp = infoPtr->himlNormal; 430 infoPtr->himlNormal = (HIMAGELIST)lParam; 431 return (LRESULT)himlTemp; 432 433 case TVSIL_STATE: 434 himlTemp = infoPtr->himlState; 435 infoPtr->himlState = (HIMAGELIST)lParam; 436 return (LRESULT)himlTemp; 437 } 438 439 return (LRESULT)NULL; 440 } 441 442 443 444 static LRESULT 445 TREEVIEW_SetItemHeight (HWND hwnd, WPARAM wParam) 446 { 447 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 448 INT cx,cy,prevHeight = infoPtr->uItemHeight; 449 450 if (wParam == -1) 451 { 452 infoPtr->uItemHeight = -1; 453 454 return prevHeight; 455 } 456 457 ImageList_GetIconSize (infoPtr->himlNormal, &cx, &cy); 458 459 if (wParam > cy) cy = wParam; 460 infoPtr->uItemHeight = cy; 461 462 if (!(GetWindowLongA(hwnd, GWL_STYLE) & TVS_NONEVENHEIGHT)) 463 if (infoPtr->uItemHeight & 0x1) infoPtr->uItemHeight++; 464 465 if (prevHeight != infoPtr->uItemHeight) 466 { 467 infoPtr->uInternalStatus |= TV_CALCALL; 468 TREEVIEW_QueueRefresh(hwnd); 469 } 470 471 return prevHeight; 472 } 473 474 static LRESULT 475 TREEVIEW_GetItemHeight (HWND hwnd) 476 { 477 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 478 479 return infoPtr->uItemHeight; 480 } 481 482 static LRESULT 483 TREEVIEW_GetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 484 { 485 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 486 487 //TRACE("\n"); 488 return (LRESULT) infoPtr->clrLine; 489 } 490 491 static LRESULT 492 TREEVIEW_SetLineColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 493 { 494 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 495 COLORREF prevColor=infoPtr->clrLine; 496 497 //TRACE("\n"); 498 infoPtr->clrLine=(COLORREF) lParam; 499 return (LRESULT) prevColor; 500 } 501 502 static LRESULT 503 TREEVIEW_GetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 504 { 505 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 506 507 //TRACE("\n"); 508 return (LRESULT) infoPtr->clrInsertMark; 509 } 510 511 static LRESULT 512 TREEVIEW_SetInsertMarkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 513 { 514 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 515 COLORREF prevColor=infoPtr->clrInsertMark; 516 517 //TRACE("%d %ld\n",wParam,lParam); 518 infoPtr->clrInsertMark=(COLORREF) lParam; 519 return (LRESULT) prevColor; 520 } 521 522 static LRESULT 523 TREEVIEW_SetInsertMark (HWND hwnd, WPARAM wParam, LPARAM lParam) 524 { 525 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 526 527 //FIXME("%d %ld\n",wParam,lParam); 528 if (!TREEVIEW_ValidItem (infoPtr, (HTREEITEM)lParam)) return 0; 529 //FIXME("%d %ld\n",wParam,lParam); 530 531 infoPtr->insertBeforeorAfter=(BOOL) wParam; 532 infoPtr->insertMarkItem=(HTREEITEM) lParam; 533 534 TREEVIEW_Refresh(hwnd); 535 536 return 1; 537 } 538 539 static LRESULT 540 TREEVIEW_SetTextColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 541 { 542 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 543 COLORREF prevColor=infoPtr->clrText; 544 545 infoPtr->clrText=(COLORREF) lParam; 546 if (infoPtr->clrText != prevColor) 547 TREEVIEW_Refresh(hwnd); 548 549 return (LRESULT) prevColor; 550 } 551 552 static LRESULT 553 TREEVIEW_GetBkColor (HWND hwnd) 554 { 555 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 556 557 return (LRESULT) infoPtr->clrBk; 558 } 559 560 static LRESULT 561 TREEVIEW_SetBkColor (HWND hwnd, WPARAM wParam, LPARAM lParam) 562 { 563 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 564 COLORREF prevColor=infoPtr->clrBk; 565 566 infoPtr->clrBk=(COLORREF) lParam; 567 if (infoPtr->clrBk != prevColor) 568 TREEVIEW_Refresh(hwnd); 569 570 571 return (LRESULT) prevColor; 572 } 573 574 static LRESULT 575 TREEVIEW_GetTextColor (HWND hwnd) 576 { 577 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 578 579 return (LRESULT) infoPtr->clrText; 580 } 581 582 583 /* cdmode: custom draw mode as received from app. in first NMCUSTOMDRAW 584 notification */ 585 586 #define TREEVIEW_LEFT_MARGIN 8 587 588 #ifdef OS2LINEHACK 589 //CB: hack for PS_DOT bug in Open32 pen handling 590 591 BOOL drawPixel; 592 HDC drawDC; 593 594 VOID CALLBACK TREEVIEW_DDAProc(int x,int y,LPARAM lpData) 595 { 596 if (drawPixel) SetPixel(drawDC,x,y,(COLORREF)lpData); 597 drawPixel = !drawPixel; 598 } 599 600 static void TREEVIEW_Polyline(HDC hdc,const POINT *lppt,int cPoints,COLORREF color) 601 { 602 INT x; 603 604 drawPixel = TRUE; 605 drawDC = hdc; 606 for (x = 0;x < cPoints-1;x++) 607 LineDDA(lppt[x].x,lppt[x].y,lppt[x+1].x,lppt[x+1].y,TREEVIEW_DDAProc,color); 608 } 609 #endif 610 611 //pen must be selected! 612 613 static void TREEVIEW_DrawVLines(HDC hdc,TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item) 614 { 615 POINT points[2]; 616 INT center; 617 618 center = (item->rect.top+item->rect.bottom)/2; 619 //INT cChildren = TREEVIEW_HasChildren(hwnd,wineItem); 620 if ((item->iLevel == 0) && !item->upsibling && item->sibling) 621 { 622 TREEVIEW_ITEM *lastItem = &infoPtr->items[(INT)item->sibling]; 623 624 while (lastItem->sibling) lastItem = &infoPtr->items[(INT)lastItem->sibling]; 625 626 points[0].y = center; 627 points[1].x = points[0].x = 8; 628 points[1].y = (lastItem->rect.top+lastItem->rect.bottom)/2; 629 #ifdef OS2LINEHACK 630 TREEVIEW_Polyline(hdc,points,2,infoPtr->clrLine); 631 #else 632 Polyline(hdc,points,2); 633 #endif 634 } 635 636 if (item->firstChild && (item->state & TVIS_EXPANDED)) 637 { 638 TREEVIEW_ITEM *lastItem = &infoPtr->items[(INT)item->firstChild]; 639 640 while (lastItem->sibling) lastItem = &infoPtr->items[(INT)lastItem->sibling]; 641 642 points[0].y = (lastItem->upsibling != NULL) ? 643 item->rect.bottom-3: /* is linked to an icon */ 644 item->rect.bottom+1; /* is linked to a +/- box */ 645 points[1].x = points[0].x = 28+20*item->iLevel-infoPtr->lefttop.x; 646 points[1].y = (lastItem->rect.top+lastItem->rect.bottom)/2; /* is linked to a +/- box */ 647 #ifdef OS2LINEHACK 648 TREEVIEW_Polyline(hdc,points,2,infoPtr->clrLine); 649 #else 650 Polyline(hdc,points,2); 651 #endif 652 } 653 } 654 655 static VOID TREEVIEW_DrawHottrackLine(HDC hdc,TREEVIEW_ITEM *item) 656 { 657 HPEN hPen,hOldPen; 658 INT rop; 659 660 if (!item->visible) return; 661 662 rop = SetROP2(hdc,R2_XORPEN); 663 hPen = CreatePen(PS_SOLID,2,RGB(0,0,0)); 664 hOldPen = SelectObject(hdc,hPen); 665 666 MoveToEx(hdc,item->text.left,item->text.bottom-1,NULL); 667 LineTo(hdc,item->text.right,item->text.bottom-1); 668 669 DeleteObject(hPen); 670 SelectObject(hdc,hOldPen); 671 SetROP2(hdc,rop); 672 } 673 674 static void 675 TREEVIEW_DrawItem(HWND hwnd,HDC hdc,TREEVIEW_ITEM *item,DWORD dwStyle,TREEVIEW_INFO *infoPtr) 676 { 677 INT center,cditem; 678 HFONT hOldFont; 679 680 if (!item->calculated) TREEVIEW_CalcItem(hwnd,hdc,dwStyle,infoPtr,item); 681 682 if (item->state & TVIS_BOLD) 683 hOldFont = SelectObject(hdc,infoPtr->hBoldFont); 684 else 685 hOldFont = SelectObject(hdc,infoPtr->hFont); 686 687 cditem = 0; 688 689 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) 690 { 691 cditem = TREEVIEW_SendCustomDrawItemNotify(hwnd, hdc, item, CDDS_ITEMPREPAINT); 692 693 if (cditem & CDRF_SKIPDEFAULT) return; 694 } 695 696 //CDRF_NEWFONT: CCM_SETVERSION < 5 clips text (what we do now) 697 // > 5 ??? recalc? 698 699 /* 700 * Set drawing starting points 701 */ 702 center = (item->rect.top+item->rect.bottom)/2; /* this item vertical center */ 703 704 /* 705 * Display the tree hierarchy 706 */ 707 if (dwStyle & TVS_HASLINES) 708 { 709 /* 710 * Write links to parent node 711 * we draw the L starting from the child to the parent 712 * 713 * points[0] is attached to the current item 714 * points[1] is the L corner 715 * points[2] is attached to the parent or the up sibling 716 */ 717 if (dwStyle & TVS_LINESATROOT) 718 { 719 TREEVIEW_ITEM *upNode = NULL; 720 RECT upRect = {0,0,0,0}; 721 HPEN hOldPen, hnewPen; 722 POINT points[2]; 723 724 hnewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine); 725 hOldPen = SelectObject(hdc,hnewPen); 726 727 TREEVIEW_DrawVLines(hdc,infoPtr,item); 728 729 /* 730 * determine the target location of the line at root, either be linked 731 * to the up sibling or to the parent node. 732 */ 733 if (item->upsibling) 734 upNode = TREEVIEW_ValidItem (infoPtr, item->upsibling); 735 else if (item->parent) 736 upNode = TREEVIEW_ValidItem (infoPtr, item->parent); 737 738 if (upNode) upRect = upNode->rect; 739 740 if (item->iLevel == 0) 741 { 742 points[1].x = upRect.left+8; 743 points[0].x = points[1].x + 10; 744 points[1].y = points[0].y = center; 745 } else 746 { 747 points[1].x = 8+(20*item->iLevel)-infoPtr->lefttop.x; 748 points[1].y = points[0].y = center; 749 points[0].x = points[1].x + 10; 750 } 751 752 /* 753 * Get a dotted pen 754 */ 755 #ifdef OS2LINEHACK 756 TREEVIEW_Polyline(hdc,points,2,infoPtr->clrLine); 757 #else 758 Polyline(hdc,points,2); 759 #endif 760 DeleteObject(hnewPen); 761 SelectObject(hdc, hOldPen); 762 } 763 } 764 765 /* 766 * Display the (+/-) signs 767 */ 768 if ((dwStyle & TVS_HASBUTTONS) && (dwStyle & TVS_HASLINES)) 769 { 770 if (TREEVIEW_HasChildren(hwnd,item)) 771 { 772 INT vCenter = (item->expandBox.top+item->expandBox.bottom)/2; 773 INT hCenter = (item->expandBox.right+item->expandBox.left)/2; 774 775 Rectangle(hdc,item->expandBox.left,item->expandBox.top,item->expandBox.right,item->expandBox.bottom); 776 777 MoveToEx(hdc,item->expandBox.left+2,vCenter,NULL); 778 LineTo(hdc,item->expandBox.right-2,vCenter); 779 780 if (!(item->state & TVIS_EXPANDED)) 781 { 782 MoveToEx(hdc,hCenter,item->expandBox.top+2,NULL); 783 LineTo(hdc,hCenter,item->expandBox.bottom-2); 784 } 785 } 786 } 787 788 /* 789 * Display the image associated with this item 790 */ 791 if ((item->mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) || (dwStyle & TVS_CHECKBOXES)) 792 { 793 INT imageIndex; 794 HIMAGELIST *himlp = NULL; 795 796 /* State images are displayed to the left of the Normal image 797 * image number is in state; zero should be `display no image'. 798 * FIXME: that last sentence looks like it needs some checking. 799 */ 800 if (infoPtr->himlState) 801 himlp =& infoPtr->himlState; 802 imageIndex = item->state >> 12; 803 804 if (himlp && imageIndex) 805 { 806 imageIndex--; /* see FIXME */ 807 ImageList_Draw(*himlp,imageIndex,hdc,item->statebitmap.left,item->statebitmap.top,ILD_NORMAL); 808 } 809 810 /* Now, draw the normal image; can be either selected or 811 * non-selected image. 812 */ 813 814 himlp = NULL; 815 if (infoPtr->himlNormal) 816 himlp = &infoPtr->himlNormal; /* get the image list */ 817 818 imageIndex = item->iImage; 819 if ((item->state & TVIS_SELECTED) && item->iSelectedImage) 820 { 821 /* The item is curently selected */ 822 if (item->iSelectedImage == I_IMAGECALLBACK) 823 imageIndex = TREEVIEW_CallbackSelectedImage(hwnd,item); 824 else 825 imageIndex = item->iSelectedImage; 826 } else 827 { 828 /* The item is not selected */ 829 if (item->iImage == I_IMAGECALLBACK) 830 imageIndex = TREEVIEW_CallbackImage(hwnd,item); 831 else 832 imageIndex = item->iImage; 833 } 834 835 if (himlp && (imageIndex != I_IMAGENONE)) 836 { 837 int ovlIdx = 0; 838 839 if(item->stateMask & TVIS_OVERLAYMASK) 840 ovlIdx = item->state & TVIS_OVERLAYMASK; 841 842 ImageList_Draw(*himlp,imageIndex,hdc,item->bitmap.left,item->bitmap.top,ILD_NORMAL | ovlIdx); 843 } 844 } 845 846 /* 847 * Display the text associated with this item 848 */ 849 /* Don't paint item's text if it's being edited */ 850 if (!infoPtr->hwndEdit || (infoPtr->editItem != item->hItem)) 851 { 852 if ((item->mask & TVIF_TEXT) && (item->pszText)) 853 { 854 UINT uTextJustify = DT_LEFT; 855 COLORREF oldTextColor = 0; 856 INT oldBkMode; 857 HBRUSH hbrBk = 0; 858 BOOL inFocus = GetFocus() == hwnd; 859 WCHAR* text; 860 BOOL mustFree = FALSE; 861 862 oldBkMode = SetBkMode(hdc, TRANSPARENT); 863 864 /* - If item is drop target or it is selected and window is in focus - 865 * use blue background (COLOR_HIGHLIGHT). 866 * - If item is selected, window is not in focus, but it has style 867 * TVS_SHOWSELALWAYS - use grey background (COLOR_BTNFACE) 868 * - Otherwise - don't fill background 869 */ 870 if ((item->state & TVIS_DROPHILITED) || 871 ((item->state & TVIS_SELECTED) && 872 (inFocus || (GetWindowLongA( hwnd, GWL_STYLE) & TVS_SHOWSELALWAYS)))) 873 { 874 if ((item->state & TVIS_DROPHILITED) || inFocus) 875 { 876 hbrBk = CreateSolidBrush(GetSysColor( COLOR_HIGHLIGHT)); 877 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_HIGHLIGHTTEXT)); 878 } else 879 { 880 hbrBk = CreateSolidBrush(GetSysColor( COLOR_BTNFACE)); 881 882 if (infoPtr->clrText == -1) 883 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT)); 884 else 885 oldTextColor = SetTextColor(hdc, infoPtr->clrText); 886 } 887 } else 888 { 889 if (infoPtr->clrText == -1) 890 oldTextColor = SetTextColor(hdc, GetSysColor( COLOR_WINDOWTEXT)); 891 else 892 oldTextColor = SetTextColor(hdc, infoPtr->clrText); 893 } 894 895 if (item->pszText == LPSTR_TEXTCALLBACKW) 896 text = TREEVIEW_CallbackText(hwnd,item,&mustFree); 897 else 898 text = item->pszText; 899 900 if (hbrBk) 901 { 902 FillRect(hdc, &item->text, hbrBk); 903 DeleteObject(hbrBk); 904 } 905 906 item->text.left += 2; 907 908 /* Draw it */ 909 DrawTextW(hdc,text,lstrlenW(text),&item->text,uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); 910 if (mustFree) COMCTL32_Free(text); 911 912 item->text.left -= 2; 913 914 /* Restore the hdc state */ 915 SetTextColor( hdc, oldTextColor); 916 917 /* Draw the box arround the selected item */ 918 if (item->state & TVIS_SELECTED) 919 { 920 HPEN hNewPen = CreatePen(PS_DOT, 0, GetSysColor(COLOR_WINDOWTEXT) ); 921 HPEN hOldPen = SelectObject( hdc, hNewPen ); 922 INT rop = SetROP2(hdc, R2_XORPEN); 923 POINT points[5]; 924 925 points[4].x = points[0].x = item->text.left; 926 points[4].y = points[0].y = item->text.top; 927 points[1].x = item->text.right-1 ; 928 points[1].y = item->text.top; 929 points[2].x = item->text.right-1; 930 points[2].y = item->text.bottom-1; 931 points[3].x = item->text.left; 932 points[3].y = item->text.bottom-1; 933 934 Polyline (hdc,points,5); 935 936 SetROP2(hdc, rop); 937 DeleteObject(hNewPen); 938 SelectObject(hdc, hOldPen); 939 } 940 941 if (oldBkMode != TRANSPARENT) 942 SetBkMode(hdc, oldBkMode); 943 } 944 } 945 946 /* Draw insertion mark if necessary */ 947 948 if (item->hItem == infoPtr->insertMarkItem) 949 { 950 HPEN hNewPen, hOldPen; 951 int offset; 952 953 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark); 954 hOldPen = SelectObject( hdc, hNewPen ); 955 956 if (infoPtr->insertBeforeorAfter) 957 offset = item->text.top+1; 958 else 959 offset = item->text.bottom-1; 960 961 MoveToEx(hdc,item->text.left, offset-3, NULL); 962 LineTo(hdc,item->text.left, offset+3); 963 964 MoveToEx(hdc,item->text.left,offset,NULL); 965 LineTo(hdc,item->text.right-2,offset); 966 967 MoveToEx(hdc,item->text.right-2, offset+3, NULL); 968 LineTo(hdc,item->text.right-2, offset-3); 969 970 DeleteObject(hNewPen); 971 972 SelectObject(hdc, hOldPen); 973 } 974 975 //draw hot item if necessary 976 if (item->hItem == infoPtr->hotItem) 977 TREEVIEW_DrawHottrackLine(hdc,item); 978 979 if (cditem & CDRF_NOTIFYPOSTPAINT) 980 cditem = TREEVIEW_SendCustomDrawItemNotify(hwnd, hdc, item, CDDS_ITEMPOSTPAINT); 981 982 SelectObject (hdc, hOldFont); 983 } 984 985 static LRESULT 986 TREEVIEW_GetItemRect (HWND hwnd, WPARAM wParam, LPARAM lParam) 987 { 988 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 989 TREEVIEW_ITEM *wineItem; 990 HTREEITEM *iItem; 991 LPRECT lpRect = (LPRECT)lParam; 992 993 /* 994 * validate parameters 995 */ 996 if ((infoPtr == NULL) || (lpRect == NULL)) 997 return FALSE; 998 999 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 1000 1001 /* 1002 * retrieve the item ptr 1003 */ 1004 iItem = (HTREEITEM *) lParam; 1005 wineItem = TREEVIEW_ValidItem (infoPtr, *iItem); 1006 if (!wineItem || !wineItem->visible) 1007 return FALSE; 1008 1009 /* 1010 * If wParam is TRUE return the text size otherwise return 1011 * the whole item size 1012 */ 1013 if (wParam) 1014 { 1015 lpRect->left = wineItem->text.left; 1016 lpRect->right = wineItem->text.right; 1017 lpRect->bottom = wineItem->text.bottom; 1018 lpRect->top = wineItem->text.top; 1019 } else 1020 { 1021 lpRect->left = wineItem->rect.left; 1022 lpRect->right = wineItem->rect.right; 1023 lpRect->bottom = wineItem->rect.bottom; 1024 lpRect->top = wineItem->rect.top; 1025 } 1026 1027 return TRUE; 1028 } 1029 1030 static LRESULT 1031 TREEVIEW_GetVisibleCount (HWND hwnd, WPARAM wParam, LPARAM lParam) 1032 1033 { 1034 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1035 1036 return (LRESULT)infoPtr->uVisibleHeight/infoPtr->uRealItemHeight; 1037 } 1038 1039 static LRESULT TREEVIEW_SetItem(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode) 1040 { 1041 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1042 TREEVIEW_ITEM *wineItem; 1043 TVITEMEXW *tvItem; 1044 INT iItem,len; 1045 BOOL mustRefresh = FALSE; 1046 BOOL mustRepaintItem = FALSE; 1047 BOOL refreshFullLine = FALSE; 1048 1049 if (infoPtr->hwndEdit) SetFocus(hwnd); 1050 1051 tvItem = (LPTVITEMEXW)lParam; 1052 iItem = (INT)tvItem->hItem; 1053 1054 wineItem = TREEVIEW_ValidItem(infoPtr,(HTREEITEM)iItem); 1055 if (!wineItem) return FALSE; 1056 1057 if ((tvItem->mask & TVIF_CHILDREN) && (wineItem->cChildren != tvItem->cChildren)) 1058 { 1059 wineItem->cChildren = tvItem->cChildren; 1060 mustRefresh = TRUE; 1061 } 1062 1063 if ((tvItem->mask & TVIF_IMAGE) && (wineItem->iImage != tvItem->iImage)) 1064 { 1065 wineItem->iImage = tvItem->iImage; 1066 mustRepaintItem = TRUE; 1067 } 1068 1069 if ((tvItem->mask & TVIF_INTEGRAL) && (wineItem->iIntegral != tvItem->iIntegral)) 1070 { 1071 wineItem->iIntegral = tvItem->iIntegral; 1072 mustRefresh = TRUE; 1073 } 1074 1075 if (tvItem->mask & TVIF_PARAM) 1076 wineItem->lParam = tvItem->lParam; 1077 1078 if ((tvItem->mask & TVIF_SELECTEDIMAGE) && (wineItem->iSelectedImage != tvItem->iSelectedImage)) 1079 { 1080 wineItem->iSelectedImage = tvItem->iSelectedImage; 1081 mustRepaintItem = TRUE; 1082 } 1083 1084 if (tvItem->mask & TVIF_STATE) 1085 { 1086 DWORD oldState = wineItem->state,oldMask = wineItem->stateMask; 1087 1088 wineItem->state &= ~tvItem->stateMask; 1089 wineItem->state |= (tvItem->state & tvItem->stateMask); 1090 wineItem->stateMask |= tvItem->stateMask; 1091 mustRepaintItem = (oldState != wineItem->state) || (oldMask != wineItem->stateMask); 1092 } 1093 1094 if (tvItem->mask & TVIF_TEXT) 1095 { 1096 if (unicode) 1097 { 1098 if (tvItem->pszText != LPSTR_TEXTCALLBACKW) 1099 { 1100 len = lstrlenW(tvItem->pszText)+1; 1101 1102 mustRepaintItem = ((wineItem->pszText == LPSTR_TEXTCALLBACKW) || (lstrcmpW(wineItem->pszText,tvItem->pszText) != 0)); 1103 if (len > wineItem->cchTextMax) 1104 { 1105 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(wineItem->pszText); 1106 wineItem->pszText= (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 1107 wineItem->cchTextMax = len; 1108 } 1109 lstrcpyW(wineItem->pszText,tvItem->pszText); 1110 } else 1111 { 1112 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(wineItem->pszText); 1113 wineItem->cchTextMax = 0; 1114 wineItem->pszText = LPSTR_TEXTCALLBACKW; 1115 mustRepaintItem = TRUE; 1116 } 1117 } else 1118 { 1119 if ((LPSTR)tvItem->pszText != LPSTR_TEXTCALLBACKA) 1120 { 1121 mustRepaintItem = ((wineItem->pszText == LPSTR_TEXTCALLBACKW) || (lstrcmpAtoW((CHAR*)tvItem->pszText,wineItem->pszText) != 0)); 1122 len = lstrlenA((LPSTR)tvItem->pszText)+1; 1123 if (len > wineItem->cchTextMax) 1124 { 1125 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(wineItem->pszText); 1126 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 1127 wineItem->cchTextMax = len; 1128 } 1129 lstrcpyAtoW(wineItem->pszText,(LPSTR)tvItem->pszText); 1130 } else 1131 { 1132 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(wineItem->pszText); 1133 wineItem->cchTextMax = 0; 1134 wineItem->pszText = LPSTR_TEXTCALLBACKW; 1135 mustRepaintItem = TRUE; 1136 } 1137 } 1138 refreshFullLine = TRUE; 1139 } 1140 1141 if (wineItem->mask != (wineItem->mask | tvItem->mask)) 1142 { 1143 wineItem->mask |= tvItem->mask; 1144 mustRepaintItem = TRUE; 1145 } 1146 1147 if (mustRepaintItem || mustRefresh) 1148 { 1149 wineItem->calculated = FALSE; 1150 if (mustRefresh) 1151 TREEVIEW_QueueRefresh(hwnd); 1152 else 1153 TREEVIEW_RefreshItem(hwnd,wineItem,refreshFullLine); 1154 } 1155 1156 return TRUE; 1157 } 1158 1159 static LRESULT 1160 TREEVIEW_GetItemState (HWND hwnd, WPARAM wParam, LPARAM lParam) 1161 1162 { 1163 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1164 TREEVIEW_ITEM *wineItem; 1165 1166 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)wParam); 1167 if (!wineItem) return 0; 1168 1169 return (wineItem->state & lParam); 1170 } 1171 1172 static void TREEVIEW_Refresh(HWND hwnd) 1173 { 1174 TREEVIEW_UnqueueRefresh(hwnd,TRUE,FALSE); 1175 1176 InvalidateRect(hwnd,NULL,TRUE); 1177 } 1178 1179 static void TREEVIEW_RefreshItem(HWND hwnd,TREEVIEW_ITEM *item,BOOL wholeLine) 1180 { 1181 if (item && item->visible) 1182 { 1183 RECT rect = item->rect; 1184 1185 if (wholeLine) 1186 { 1187 RECT client; 1188 1189 GetClientRect(hwnd,&client); 1190 rect.left = 0; 1191 rect.right = client.right; 1192 } else 1193 { 1194 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 1195 1196 //redraw text and image 1197 if ((((item->mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) == (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) || (dwStyle & TVS_CHECKBOXES)) && (item->iSelectedImage != item->iImage)) 1198 { 1199 rect.left += TREEVIEW_LEFT_MARGIN; 1200 if (item->iLevel != 0) rect.left += (5*item->iLevel); 1201 rect.left += 15; 1202 } else rect = item->text; 1203 } 1204 1205 InvalidateRect(hwnd,&rect,TRUE); 1206 } 1207 } 1208 1209 //HDC parameter is optional 1210 1211 static void TREEVIEW_CalcItem(HWND hwnd,HDC hdc,DWORD dwStyle,TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item) 1212 { 1213 RECT r; 1214 INT center,xpos; 1215 BOOL ownDC = FALSE; 1216 581 static INT 582 TREEVIEW_HasChildren(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *wineItem) 583 { 584 TREEVIEW_UpdateDispInfo(infoPtr, wineItem, TVIF_CHILDREN); 585 586 return wineItem->cChildren > 0; 587 } 588 589 /* Item Position ********************************************************/ 590 591 static VOID 592 TREEVIEW_ComputeTextWidth(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,HDC hDC,BOOL useFont) 593 { 594 HDC hdc; 595 HFONT hOldFont; 596 RECT rect; 597 598 /* DRAW's OM docker creates items like this */ 599 if (item->pszText == NULL) 600 { 601 item->textWidth = 0; 602 return; 603 } 604 605 hdc = hDC ? hDC:GetDC(infoPtr->hwnd); 606 if (!hDC || !useFont) hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, item)); 607 608 SetRectEmpty(&rect); 609 DrawTextW (hdc,item->pszText,lstrlenW(item->pszText),&rect,DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX); 610 item->textWidth = rect.right-rect.left; 611 item->textHeight = rect.bottom-rect.top; 612 item->rect.right = item->textOffset+item->textWidth+4; 613 614 if (!hDC || !useFont) SelectObject(hdc, hOldFont); 615 if (!hDC) ReleaseDC(infoPtr->hwnd,hdc); 616 } 617 618 static INT CALLBACK 619 TREEVIEW_ResetItemOrderVisible(LPVOID pItem, DWORD unused) 620 { 621 TREEVIEW_ITEM *item = (TREEVIEW_ITEM *)pItem; 622 (void)unused; 623 624 item->displayOrder = -1; 625 item->displayed = FALSE; 626 item->inclient = FALSE; 627 628 return 1; 629 } 630 631 static VOID TREEVIEW_CalcItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,HDC hdc) 632 { 633 TREEVIEW_UpdateDispInfo(infoPtr,item,TVIF_TEXT); 634 TREEVIEW_ComputeTextWidth(infoPtr,item,hdc,FALSE); 1217 635 item->calculated = TRUE; 1218 1219 r = item->rect; /* this item rectangle */ 1220 center = (r.top+r.bottom)/2; /* this item vertical center */ 1221 xpos = r.left + TREEVIEW_LEFT_MARGIN;/* horizontal starting point */ 1222 1223 if (item->iLevel != 0)/* update position only for non root node */ 1224 xpos += 5*item->iLevel; 1225 1226 if ((dwStyle & TVS_HASBUTTONS) && (dwStyle & TVS_HASLINES)) 1227 { 1228 if (TREEVIEW_HasChildren(hwnd,item)) 1229 { 1230 /* Setup expand box coordinate to facilitate the LMBClick handling */ 1231 item->expandBox.left = xpos-4; 1232 item->expandBox.top = center-4; 1233 item->expandBox.right = xpos+5; 1234 item->expandBox.bottom = center+5; 1235 } else SetRectEmpty(&item->expandBox); 1236 } else SetRectEmpty(&item->expandBox); 1237 1238 xpos += 13; /* update position */ 1239 1240 if ((item->mask & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) || (dwStyle & TVS_CHECKBOXES)) 1241 { 1242 INT imageIndex,cx,cy; 1243 HIMAGELIST *himlp = NULL; 1244 1245 /* State images are displayed to the left of the Normal image 1246 * image number is in state; zero should be `display no image'. 1247 * FIXME: that last sentence looks like it needs some checking. 1248 */ 1249 if (infoPtr->himlState) 1250 himlp = &infoPtr->himlState; 1251 imageIndex = item->state >> 12; 1252 1253 if (himlp && imageIndex) 1254 { 1255 if (!hdc) 1256 { 1257 ownDC = TRUE; 1258 hdc = GetDC(hwnd); 1259 } 1260 1261 imageIndex--; /* see FIXME */ 1262 ImageList_GetIconSize(*himlp,&cx,&cy); 1263 item->statebitmap.left = xpos-2; 1264 item->statebitmap.right = xpos-2+cx; 1265 item->statebitmap.top = r.top+1; 1266 item->statebitmap.bottom = r.top+1+cy; 1267 xpos += cx; 1268 } else SetRectEmpty(&item->statebitmap); 1269 1270 /* Now, draw the normal image; can be either selected or 1271 * non-selected image. 1272 */ 1273 1274 himlp = NULL; 1275 if (infoPtr->himlNormal) 1276 himlp = &infoPtr->himlNormal; /* get the image list */ 1277 1278 if (himlp) 1279 { 1280 int ovlIdx = 0; 1281 1282 if(item->stateMask & TVIS_OVERLAYMASK) 1283 ovlIdx = item->state & TVIS_OVERLAYMASK; 1284 1285 if (!hdc) 1286 { 1287 ownDC = TRUE; 1288 hdc = GetDC(hwnd); 1289 } 1290 1291 ImageList_GetIconSize(*himlp,&cx,&cy); 1292 item->bitmap.left = xpos-2; 1293 item->bitmap.right = xpos-2+cx; 1294 item->bitmap.top = r.top+1; 1295 item->bitmap.bottom = r.top+1+cy; 1296 xpos += cx; 1297 } else SetRectEmpty(&item->bitmap); 1298 } else 1299 { 1300 SetRectEmpty(&item->statebitmap); 1301 SetRectEmpty(&item->bitmap); 1302 } 1303 1304 r.left = xpos; 1305 if ((item->mask & TVIF_TEXT) && item->pszText) 1306 { 1307 UINT uTextJustify = DT_LEFT; 1308 HFONT hOldFont; 1309 WCHAR* text; 1310 BOOL mustFree = FALSE; 1311 1312 r.left += 3; 1313 r.right -= 3; 1314 1315 item->text.left = r.left; 1316 item->text.right = r.right; 1317 item->text.top = r.top; 1318 item->text.bottom= r.bottom; 1319 1320 if (item->pszText == LPSTR_TEXTCALLBACKW) 1321 text = TREEVIEW_CallbackText(hwnd,item,&mustFree); 1322 else 1323 text = item->pszText; 1324 1325 if (!hdc) 1326 { 1327 ownDC = TRUE; 1328 hdc = GetDC(hwnd); 1329 } 1330 1331 if (item->state & TVIS_BOLD) 1332 hOldFont = SelectObject (hdc, infoPtr->hBoldFont); 1333 else 1334 hOldFont = SelectObject (hdc, infoPtr->hFont); 1335 1336 /* Obtain the text coordinate */ 1337 DrawTextW (hdc,text,lstrlenW(text),&item->text,uTextJustify | DT_VCENTER | DT_SINGLELINE | DT_CALCRECT | DT_NOPREFIX); 1338 if (mustFree) COMCTL32_Free(text); 1339 1340 SelectObject(hdc,hOldFont); 1341 1342 /* We need to reset it to items height */ 1343 item->text.top = r.top; 1344 item->text.bottom = r.bottom; 1345 item->text.right += 4; /* This is extra for focus rectangle */ 1346 1347 xpos = item->text.right; 1348 } else SetRectEmpty(&item->text); 1349 1350 item->rect.right = xpos; 1351 1352 if (ownDC) ReleaseDC(hwnd,hdc); 1353 } 1354 1355 //HDC parameter is optional 1356 1357 static BOOL TREEVIEW_CalcItems(HWND hwnd,HDC hdc,TREEVIEW_INFO *infoPtr) 636 } 637 638 static BOOL TREEVIEW_CalcItems(TREEVIEW_INFO *infoPtr) 1358 639 { 1359 640 TREEVIEW_ITEM *item; 1360 INT iItem, indent,x,y,height,itemHeight; 1361 TEXTMETRICA tm; 1362 RECT rect,view; 1363 BOOL ownDC = FALSE,changedLeftTop = FALSE; 1364 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 641 int order = 0; 642 BOOL lar = ((infoPtr->dwStyle & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) > TVS_LINESATROOT); 643 HDC hdc = 0; 1365 644 INT maxXScroll,maxYScroll; 1366 645 INT xDiff,yDiff; 1367 HFONT oldFont; 1368 1369 GetClientRect(hwnd,&rect); 1370 infoPtr->uVisibleHeight = rect.bottom-rect.top; 1371 infoPtr->uVisibleWidth = rect.right-rect.left; 1372 1373 if (infoPtr->uInternalStatus & TV_CALCALL) 1374 { 1375 TREEVIEW_HideInfoTip(hwnd,infoPtr); 1376 itemHeight = 0; 1377 ImageList_GetIconSize(infoPtr->himlNormal,&x,&itemHeight); 1378 if (infoPtr->uItemHeight != -1) itemHeight = MAX(infoPtr->uItemHeight,itemHeight); 1379 1380 if (!hdc) 1381 { 1382 ownDC = TRUE; 1383 hdc = GetDC(hwnd); 1384 } 1385 1386 oldFont = SelectObject(hdc,infoPtr->hFont); 1387 GetTextMetricsA(hdc,&tm); 1388 itemHeight = MAX(tm.tmHeight+tm.tmExternalLeading,itemHeight); 1389 SelectObject(hdc,infoPtr->hBoldFont); 1390 GetTextMetricsA(hdc,&tm); 1391 itemHeight = MAX(tm.tmHeight+tm.tmExternalLeading,itemHeight); 1392 SelectObject(hdc,oldFont); 1393 if (!(dwStyle & TVS_NONEVENHEIGHT)) 1394 if (itemHeight & 0x1) itemHeight++; //important for PS_DOT pen! 1395 infoPtr->uRealItemHeight = itemHeight; 1396 infoPtr->uVScrollStep = itemHeight+ITEM_VSPACE; 1397 } else 1398 { 1399 itemHeight = infoPtr->uRealItemHeight; 1400 } 1401 infoPtr->uTotalWidth = 0; 1402 1403 view = rect; 1404 OffsetRect(&view,infoPtr->lefttop.x,infoPtr->lefttop.y); 1405 1406 iItem = (INT)infoPtr->TopRootItem; 1407 infoPtr->firstVisible = 0; 1408 item = NULL; 1409 indent = x = y = 0; 1410 1411 while (iItem) 1412 { 1413 item = &infoPtr->items[iItem]; 1414 item->iLevel = indent; 1415 1416 height = itemHeight*item->iIntegral+ITEM_VSPACE; 1417 1418 //calculate size and fill rects 646 BOOL changedLeftTop = FALSE; 647 RECT rc; 648 649 TREEVIEW_HideInfoTip(infoPtr); 650 651 // 1) reset 652 infoPtr->treeWidth = 0; 653 infoPtr->treeHeight = 0; 654 GetClientRect(infoPtr->hwnd,&rc); 655 infoPtr->clientWidth = rc.right; 656 infoPtr->clientHeight = rc.bottom; 657 DPA_EnumCallback(infoPtr->items,TREEVIEW_ResetItemOrderVisible,(LPARAM)NULL); 658 659 // 2) get order and tree height 660 infoPtr->firstVisible = NULL; 661 for (item = infoPtr->root->firstChild;item != NULL;item = TREEVIEW_GetNextListItem(infoPtr, item)) 662 { 663 INT itemW; 664 665 item->displayOrder = order; 666 1419 667 if ((infoPtr->uInternalStatus & TV_CALCALL) || !item->calculated) 1420 668 { 1421 item->rect.top = y-view.top; 1422 item->rect.bottom = item->rect.top+height; 1423 item->rect.left = x-view.left; 1424 item->rect.right = rect.right; //dummy 1425 if (!hdc) 1426 { 1427 ownDC = TRUE; 1428 hdc = GetDC(hwnd); 1429 } 1430 TREEVIEW_CalcItem(hwnd,hdc,dwStyle,infoPtr,item); 1431 } else 1432 { 1433 INT xOffset,yOffset; 1434 1435 xOffset = (x-view.left)-item->rect.left; 1436 yOffset = (y-view.top)-item->rect.top; 1437 OffsetRect(&item->rect,xOffset,yOffset); 1438 OffsetRect(&item->text,xOffset,yOffset); 1439 OffsetRect(&item->expandBox,xOffset,yOffset); 1440 OffsetRect(&item->bitmap,xOffset,yOffset); 1441 OffsetRect(&item->statebitmap,xOffset,yOffset); 1442 } 1443 infoPtr->uTotalWidth = MAX(infoPtr->uTotalWidth,item->rect.right+infoPtr->lefttop.x); 1444 1445 if (((y >= view.top) && (y < view.bottom)) || ((y+height > view.top) && (y+height <= view.bottom))) 1446 { 1447 item->visible = TRUE; 1448 if (!infoPtr->firstVisible) 1449 infoPtr->firstVisible = item->hItem; 1450 } else item->visible = FALSE; 1451 1452 /* look up next item */ 1453 1454 if ((item->firstChild) && (item->state & TVIS_EXPANDED)) 1455 { 1456 iItem = (INT)item->firstChild; 1457 indent++; 1458 x += infoPtr->uIndent; 1459 } else 1460 { 1461 iItem = (INT)item->sibling; 1462 while ((!iItem) && (indent > 0)) 1463 { 1464 indent--; 1465 x -= infoPtr->uIndent; 1466 item = &infoPtr->items[(INT)item->parent]; 1467 iItem = (INT)item->sibling; 1468 } 1469 } 1470 y += height; 1471 } /* while */ 1472 1473 if (ownDC) ReleaseDC(hwnd,hdc); 1474 669 if (!hdc) hdc = GetDC(infoPtr->hwnd); 670 TREEVIEW_CalcItem(infoPtr,item,hdc); 671 } 672 673 //set internal metrics 674 item->linesOffset = infoPtr->uIndent * (item->iLevel + lar - 1) - infoPtr->lefttop.x; 675 item->stateOffset = item->linesOffset + infoPtr->uIndent; 676 item->imageOffset = item->stateOffset + (STATEIMAGEINDEX(item->state) ? infoPtr->stateImageWidth : 0); 677 item->textOffset = item->imageOffset + infoPtr->normalImageWidth; 678 679 //set item rect 680 item->rect.top = infoPtr->uItemHeight*item->displayOrder-infoPtr->lefttop.y; 681 item->rect.bottom = item->rect.top+infoPtr->uItemHeight*item->iIntegral; 682 item->rect.left = item->stateOffset; 683 item->rect.right = item->textOffset+item->textWidth+4; 684 item->displayed = TRUE; 685 item->inclient = (((item->rect.top >= 0) || (item->rect.bottom >= 0)) && (item->rect.top < infoPtr->clientHeight)); 686 if (!infoPtr->firstVisible && item->inclient) infoPtr->firstVisible = item; 687 688 itemW = item->textOffset+item->textWidth+4+infoPtr->lefttop.x; 689 if (itemW > infoPtr->treeWidth) 690 infoPtr->treeWidth = itemW; 691 692 infoPtr->treeHeight += item->rect.bottom-item->rect.top; 693 694 order += item->iIntegral; 695 } 696 infoPtr->maxDisplayOrder = order; 697 698 if (hdc) ReleaseDC(infoPtr->hwnd,hdc); 1475 699 infoPtr->uInternalStatus &= ~TV_CALCALL; 1476 infoPtr->uTotalHeight = y; 1477 1478 //check cx and cy 700 701 // 3) check lefttop 1479 702 yDiff = xDiff = 0; 1480 703 1481 maxYScroll = infoPtr-> uTotalHeight-infoPtr->uVisibleHeight;704 maxYScroll = infoPtr->treeHeight-infoPtr->clientHeight; 1482 705 if (maxYScroll < 0) maxYScroll = 0; 1483 706 if (infoPtr->lefttop.y > maxYScroll) 1484 707 { 1485 INT mod = maxYScroll % infoPtr->u VScrollStep;1486 1487 if (mod > 0) maxYScroll += infoPtr->u VScrollStep-mod;708 INT mod = maxYScroll % infoPtr->uItemHeight; 709 710 if (mod > 0) maxYScroll += infoPtr->uItemHeight-mod; 1488 711 yDiff = infoPtr->lefttop.y-maxYScroll; 1489 712 infoPtr->lefttop.y = maxYScroll; 1490 713 } 1491 714 1492 maxXScroll = infoPtr-> uTotalWidth-infoPtr->uVisibleWidth;715 maxXScroll = infoPtr->treeWidth-infoPtr->clientWidth; 1493 716 if (maxXScroll < 0) maxXScroll = 0; 1494 717 if (infoPtr->lefttop.x > maxXScroll) … … 1501 724 if (changedLeftTop) 1502 725 { 1503 iItem = (INT)infoPtr->TopRootItem; 1504 item = NULL; 1505 indent = 0; 1506 infoPtr->firstVisible = 0; 1507 1508 while (iItem) 1509 { 1510 item = &infoPtr->items[iItem]; 1511 OffsetRect(&item->rect,xDiff,yDiff); 1512 OffsetRect(&item->text,xDiff,yDiff); 1513 OffsetRect(&item->expandBox,xDiff,yDiff); 1514 OffsetRect(&item->bitmap,xDiff,yDiff); 1515 OffsetRect(&item->statebitmap,xDiff,yDiff); 1516 1517 y = view.top+item->rect.top; 1518 if (((y >= view.top) && (y < view.bottom)) || ((y+height > view.top) && (y+height <= view.bottom))) 1519 { 1520 item->visible = TRUE; 1521 if (!infoPtr->firstVisible) 1522 infoPtr->firstVisible = item->hItem; 1523 } else item->visible = FALSE; 1524 1525 if ((item->firstChild) && (item->state & TVIS_EXPANDED)) 1526 { 1527 iItem = (INT)item->firstChild; 1528 indent++; 1529 } else 1530 { 1531 iItem = (INT)item->sibling; 1532 while ((!iItem) && (indent > 0)) 1533 { 1534 indent--; 1535 item = &infoPtr->items[(INT)item->parent]; 1536 iItem = (INT)item->sibling; 1537 } 1538 } 1539 } /* while */ 1540 } 1541 1542 if (!(dwStyle & TVS_NOSCROLL) && (infoPtr->uVisibleHeight > 0) && (infoPtr->uVisibleWidth > 0)) 1543 { 1544 if (infoPtr->uTotalHeight > infoPtr->uVisibleHeight) 726 //update visible flag and position 727 infoPtr->firstVisible = NULL; 728 for (item = infoPtr->root->firstChild;item != NULL;item = TREEVIEW_GetNextListItem(infoPtr, item)) 729 { 730 item->rect.top += yDiff; 731 item->rect.bottom += yDiff; 732 item->rect.left += xDiff; 733 item->rect.right += xDiff; 734 item->inclient = (((item->rect.top >= 0) || (item->rect.bottom >= 0)) && (item->rect.top < infoPtr->clientHeight)); 735 if (!infoPtr->firstVisible && item->inclient) infoPtr->firstVisible = item; 736 item->linesOffset += xDiff; 737 item->stateOffset += xDiff; 738 item->imageOffset += xDiff; 739 item->textOffset += xDiff; 740 } 741 } 742 743 // 4) set scrollbars 744 if (!(infoPtr->dwStyle & TVS_NOSCROLL) && (infoPtr->clientHeight > 0) && (infoPtr->clientWidth > 0)) 745 { 746 if (infoPtr->treeHeight > infoPtr->clientHeight) 1545 747 { 1546 748 SCROLLINFO info; 1547 INT visH = ((INT)(infoPtr-> uVisibleHeight/infoPtr->uVScrollStep))*infoPtr->uVScrollStep;749 INT visH = ((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight; 1548 750 1549 751 info.cbSize = sizeof(info); 1550 752 info.nMin = 0; 1551 info.nMax = infoPtr-> uTotalHeight-1;753 info.nMax = infoPtr->treeHeight-1; 1552 754 info.nPos = infoPtr->lefttop.y; 1553 755 info.nPage = visH; 1554 756 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; 1555 757 infoPtr->uInternalStatus |= TV_VSCROLL; 1556 SetScrollInfo( hwnd,SB_VERT,&info,TRUE);758 SetScrollInfo(infoPtr->hwnd,SB_VERT,&info,TRUE); 1557 759 } else 1558 760 { 1559 761 if (infoPtr->uInternalStatus & TV_VSCROLL) 1560 ShowScrollBar( hwnd,SB_VERT,FALSE);762 ShowScrollBar(infoPtr->hwnd,SB_VERT,FALSE); 1561 763 infoPtr->uInternalStatus &= ~TV_VSCROLL; 1562 764 } 1563 if (!( dwStyle & TVS_NOHSCROLL) && (infoPtr->uTotalWidth > infoPtr->uVisibleWidth))765 if (!(infoPtr->dwStyle & TVS_NOHSCROLL) && (infoPtr->treeWidth > infoPtr->clientWidth)) 1564 766 { 1565 767 SCROLLINFO info; … … 1567 769 info.cbSize = sizeof(info); 1568 770 info.nMin = 0; 1569 info.nMax = infoPtr-> uTotalWidth-1;771 info.nMax = infoPtr->treeWidth-1; 1570 772 info.nPos = infoPtr->lefttop.x; 1571 info.nPage = MAX(infoPtr-> uVisibleWidth,1);773 info.nPage = MAX(infoPtr->clientWidth,1); 1572 774 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE; 1573 775 infoPtr->uInternalStatus |= TV_HSCROLL; 1574 SetScrollInfo( hwnd,SB_HORZ,&info,TRUE);776 SetScrollInfo(infoPtr->hwnd,SB_HORZ,&info,TRUE); 1575 777 } else 1576 778 { 1577 779 if (infoPtr->uInternalStatus & TV_HSCROLL) 1578 ShowScrollBar( hwnd,SB_HORZ,FALSE);780 ShowScrollBar(infoPtr->hwnd,SB_HORZ,FALSE); 1579 781 infoPtr->uInternalStatus &= ~TV_HSCROLL; 1580 782 } … … 1582 784 { 1583 785 if (infoPtr->uInternalStatus & (TV_VSCROLL | TV_HSCROLL)) 1584 ShowScrollBar( hwnd,SB_BOTH,FALSE);786 ShowScrollBar(infoPtr->hwnd,SB_BOTH,FALSE); 1585 787 infoPtr->uInternalStatus &= ~(TV_VSCROLL | TV_HSCROLL); 1586 788 } 1587 789 790 infoPtr->dwStyle = GetWindowLongA(infoPtr->hwnd,GWL_STYLE); 791 1588 792 return changedLeftTop; 1589 793 } 1590 794 795 static VOID TREEVIEW_MoveItems(TREEVIEW_INFO *infoPtr,INT xScroll,INT yScroll) 796 { 797 TREEVIEW_ITEM *item; 798 799 infoPtr->firstVisible = NULL; 800 for (item = infoPtr->root->firstChild;item;item = TREEVIEW_GetNextListItem(infoPtr,item)) 801 { 802 item->rect.top += yScroll; 803 item->rect.bottom += yScroll; 804 item->rect.left += xScroll; 805 item->rect.right += xScroll; 806 item->inclient = (((item->rect.top >= 0) || (item->rect.bottom >= 0)) && (item->rect.top < infoPtr->clientHeight)); 807 if (!infoPtr->firstVisible && item->inclient) infoPtr->firstVisible = item; 808 809 //set internal metrics 810 item->linesOffset += xScroll; 811 item->stateOffset += xScroll; 812 item->imageOffset += xScroll; 813 item->textOffset += xScroll; 814 } 815 } 816 817 /* Item Allocation **********************************************************/ 818 819 static TREEVIEW_ITEM * 820 TREEVIEW_AllocateItem(TREEVIEW_INFO *infoPtr) 821 { 822 TREEVIEW_ITEM *newItem = (TREEVIEW_ITEM*)COMCTL32_Alloc(sizeof(TREEVIEW_ITEM)); 823 824 if (!newItem) 825 return NULL; 826 827 ZeroMemory(newItem,sizeof(TREEVIEW_ITEM)); 828 if (DPA_InsertPtr(infoPtr->items, INT_MAX, newItem) == -1) 829 { 830 COMCTL32_Free(newItem); 831 return NULL; 832 } 833 834 return newItem; 835 } 836 837 /* Exact opposite of TREEVIEW_AllocateItem. In particular, it does not 838 * free item->pszText. */ 1591 839 static void 1592 TREEVIEW_Draw(HWND hwnd,HDC hdc,RECT *updateRect) 1593 { 1594 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1595 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 1596 HBRUSH hbrBk; 840 TREEVIEW_FreeItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 841 { 842 DPA_DeletePtr(infoPtr->items, DPA_GetPtrIndex(infoPtr->items, item)); 843 COMCTL32_Free(item); 844 } 845 846 847 /* Item Insertion *******************************************************/ 848 849 /*************************************************************************** 850 * This method inserts newItem before sibling as a child of parent. 851 * sibling can be NULL, but only if parent has no children. 852 */ 853 static void 854 TREEVIEW_InsertBefore(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling, 855 TREEVIEW_ITEM *parent) 856 { 857 assert(newItem != NULL); 858 assert(parent != NULL); 859 860 if (sibling != NULL) 861 { 862 assert(sibling->parent == parent); 863 864 if (sibling->prevSibling != NULL) 865 sibling->prevSibling->nextSibling = newItem; 866 867 newItem->prevSibling = sibling->prevSibling; 868 sibling->prevSibling = newItem; 869 } 870 871 newItem->nextSibling = sibling; 872 873 if (parent->firstChild == sibling) 874 { 875 newItem->nextSibling = parent->firstChild; 876 parent->firstChild = newItem; 877 } 878 879 if (parent->lastChild == NULL) 880 parent->lastChild = newItem; 881 } 882 883 /*************************************************************************** 884 * This method inserts newItem after sibling as a child of parent. 885 * sibling can be NULL, but only if parent has no children. 886 */ 887 static void 888 TREEVIEW_InsertAfter(TREEVIEW_ITEM *newItem, TREEVIEW_ITEM *sibling, 889 TREEVIEW_ITEM *parent) 890 { 891 assert(newItem != NULL); 892 assert(parent != NULL); 893 894 if (sibling != NULL) 895 { 896 assert(sibling->parent == parent); 897 898 if (sibling->nextSibling != NULL) 899 sibling->nextSibling->prevSibling = newItem; 900 901 newItem->nextSibling = sibling->nextSibling; 902 sibling->nextSibling = newItem; 903 } 904 905 newItem->prevSibling = sibling; 906 907 if (parent->lastChild == sibling) 908 { 909 newItem->prevSibling = parent->lastChild; 910 parent->lastChild = newItem; 911 } 912 913 if (parent->firstChild == NULL) 914 parent->firstChild = newItem; 915 } 916 917 static BOOL 918 TREEVIEW_DoSetItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *wineItem,const TVITEMEXW *tvItem,BOOL unicode,DWORD *changed = NULL) 919 { 920 UINT callbackClear = 0; 921 UINT callbackSet = 0; 922 923 if (changed) *changed = 0; 924 925 /* Do this first in case it fails. */ 926 927 if (tvItem->mask & TVIF_TEXT) 928 { 929 /* 930 * Setup the item text stuff here since it's required by the Sort method 931 * when the insertion are ordered 932 */ 933 if (unicode) 934 { 935 if (tvItem->pszText != LPSTR_TEXTCALLBACKW) 936 { 937 INT len = lstrlenW(tvItem->pszText)+1; 938 939 callbackClear |= TVIF_TEXT; 940 941 if (changed && ((wineItem->callbackMask & LVIF_TEXT) || (lstrcmpW(wineItem->pszText,tvItem->pszText) != 0))) *changed |= TVIF_TEXT; 942 if (len > wineItem->cchTextMax) 943 { 944 LPWSTR newText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,len*sizeof(WCHAR)); 945 if (newText == NULL) return FALSE; 946 947 wineItem->pszText = newText; 948 wineItem->cchTextMax = len; 949 } 950 lstrcpyW (wineItem->pszText,tvItem->pszText); 951 } else 952 { 953 callbackSet |= TVIF_TEXT; 954 955 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,TEXT_CALLBACK_SIZE*sizeof(WCHAR)); 956 wineItem->cchTextMax = TEXT_CALLBACK_SIZE; 957 if (changed) *changed |= TVIF_TEXT; 958 } 959 } else 960 { 961 if ((LPSTR)tvItem->pszText != LPSTR_TEXTCALLBACKA) 962 { 963 INT len = lstrlenA((LPSTR)tvItem->pszText)+1; 964 965 callbackClear |= TVIF_TEXT; 966 967 if (changed && ((wineItem->callbackMask & LVIF_TEXT) || (lstrcmpAtoW((CHAR*)tvItem->pszText,wineItem->pszText) != 0))) *changed |= TVIF_TEXT; 968 if (len > wineItem->cchTextMax) 969 { 970 LPWSTR newText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,len*sizeof(WCHAR)); 971 if (newText == NULL) return FALSE; 972 973 wineItem->pszText = newText; 974 wineItem->cchTextMax = len; 975 } 976 lstrcpyAtoW (wineItem->pszText,(LPSTR)tvItem->pszText); 977 } else 978 { 979 callbackSet |= TVIF_TEXT; 980 981 wineItem->pszText = (WCHAR*)COMCTL32_ReAlloc(wineItem->pszText,TEXT_CALLBACK_SIZE*sizeof(WCHAR)); 982 wineItem->cchTextMax = TEXT_CALLBACK_SIZE; 983 if (changed) *changed |= TVIF_TEXT; 984 } 985 } 986 } 987 988 if (tvItem->mask & TVIF_CHILDREN) 989 { 990 if (changed && (wineItem->cChildren != tvItem->cChildren)) *changed |= TVIF_CHILDREN; 991 wineItem->cChildren = tvItem->cChildren; 992 993 if (wineItem->cChildren == I_CHILDRENCALLBACK) 994 callbackSet |= TVIF_CHILDREN; 995 else 996 callbackClear |= TVIF_CHILDREN; 997 } 998 999 if (tvItem->mask & TVIF_IMAGE) 1000 { 1001 if (changed && (wineItem->iImage != tvItem->iImage)) *changed |= TVIF_IMAGE; 1002 wineItem->iImage = tvItem->iImage; 1003 1004 if (wineItem->iImage == I_IMAGECALLBACK) 1005 callbackSet |= TVIF_IMAGE; 1006 else 1007 callbackClear |= TVIF_IMAGE; 1008 } 1009 1010 if (tvItem->mask & TVIF_SELECTEDIMAGE) 1011 { 1012 if (changed && (wineItem->iSelectedImage != tvItem->iSelectedImage)) *changed |= TVIF_SELECTEDIMAGE; 1013 wineItem->iSelectedImage = tvItem->iSelectedImage; 1014 1015 if (wineItem->iImage == I_IMAGECALLBACK) 1016 callbackSet |= TVIF_SELECTEDIMAGE; 1017 else 1018 callbackClear |= TVIF_SELECTEDIMAGE; 1019 } 1020 1021 if (tvItem->mask & TVIF_PARAM) 1022 { 1023 if (changed && (wineItem->lParam != tvItem->lParam)) *changed |= TVIF_PARAM; 1024 wineItem->lParam = tvItem->lParam; 1025 } 1026 1027 /* If the application sets TVIF_INTEGRAL without 1028 * supplying a TVITEMEX structure, it's toast. */ 1029 if (tvItem->mask & TVIF_INTEGRAL) 1030 { 1031 if (changed && (wineItem->iIntegral != tvItem->iIntegral)) *changed |= TVIF_INTEGRAL; 1032 wineItem->iIntegral = tvItem->iIntegral; 1033 } 1034 1035 if (tvItem->mask & TVIF_STATE) 1036 { 1037 DWORD oldState = wineItem->state; 1038 1039 wineItem->state &= ~tvItem->stateMask; 1040 wineItem->state |= (tvItem->state & tvItem->stateMask); 1041 if (changed && (wineItem->state != oldState)) *changed |= TVIF_STATE; 1042 } 1043 1044 wineItem->callbackMask |= callbackSet; 1045 wineItem->callbackMask &= ~callbackClear; 1046 1047 return TRUE; 1048 } 1049 1050 /* Note that the new item is pre-zeroed. */ 1051 static LRESULT 1052 TREEVIEW_InsertItem(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam,BOOL unicode) 1053 { 1054 TVINSERTSTRUCTW *ptdi = (LPTVINSERTSTRUCTW)lParam; 1055 TVITEMEXW *tvItem; 1056 HTREEITEM insertAfter; 1057 INT x; 1058 TREEVIEW_ITEM *newItem, *parentItem; 1059 1060 if (!ptdi) return NULL; 1061 tvItem = &ptdi->itemex; 1062 1063 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwnd); 1064 1065 if ((ptdi->hParent == TVI_ROOT) || (ptdi->hParent == 0)) 1066 { 1067 parentItem = infoPtr->root; 1068 } else 1069 { 1070 parentItem = ptdi->hParent; 1071 1072 if (!TREEVIEW_ValidItem(infoPtr,parentItem)) 1073 { 1074 //dprintf(("invalid parent %p\n",parentItem)); 1075 1076 return (LRESULT)(HTREEITEM)NULL; 1077 } 1078 } 1079 1080 insertAfter = ptdi->hInsertAfter; 1081 1082 /* Validate this now for convenience. */ 1083 if ((insertAfter != TVI_FIRST) && (insertAfter != TVI_LAST) && (insertAfter != TVI_SORT)) 1084 { 1085 if (!TREEVIEW_ValidItem(infoPtr,insertAfter)) 1086 { 1087 //dprintf(("invalid insert after %p\n",insertAfter)); 1088 insertAfter = TVI_LAST; 1089 } else if (parentItem != insertAfter->parent) 1090 { 1091 //dprintf(("invalid insert after parent %p %p %p",insertAfter,insertAfter->parent,parentItem)); 1092 //CB: Verified with AMD cpuid 2.04 (there are other strange things...) 1093 insertAfter = parentItem->lastChild; 1094 } 1095 } 1096 1097 //TRACE("parent %p position %p: %s\n", parentItem, insertAfter, 1098 // (tvItem->mask & TVIF_TEXT) 1099 // ? ((tvItem->pszText == LPSTR_TEXTCALLBACKA) ? "<callback>" 1100 // : tvItem->pszText) 1101 // : "<no label>"); 1102 1103 newItem = TREEVIEW_AllocateItem(infoPtr); 1104 if (newItem == NULL) 1105 return (LRESULT)(HTREEITEM)NULL; 1106 1107 newItem->parent = parentItem; 1108 newItem->iIntegral = 1; 1109 1110 if (!TREEVIEW_DoSetItem(infoPtr,newItem,tvItem,unicode)) 1111 return (LRESULT)(HTREEITEM)NULL; 1112 1113 /* After this point, nothing can fail. (Except for TVI_SORT.) */ 1114 1115 infoPtr->uNumItems++; 1116 1117 if (insertAfter == TVI_FIRST) 1118 { 1119 TREEVIEW_InsertBefore(newItem, parentItem->firstChild, parentItem); 1120 } else if (insertAfter == TVI_LAST) 1121 { 1122 TREEVIEW_InsertAfter(newItem, parentItem->lastChild, parentItem); 1123 } else if (insertAfter == TVI_SORT) 1124 { 1125 TREEVIEW_ITEM *aChild; 1126 TREEVIEW_ITEM *previousChild = NULL; 1127 BOOL bItemInserted = FALSE; 1128 1129 aChild = parentItem->firstChild; 1130 1131 TREEVIEW_UpdateDispInfo(infoPtr, newItem, TVIF_TEXT); 1132 1133 /* Iterate the parent children to see where we fit in */ 1134 while (aChild) 1135 { 1136 INT comp; 1137 1138 TREEVIEW_UpdateDispInfo(infoPtr,aChild,TVIF_TEXT); 1139 comp = lstrcmpW(newItem->pszText,aChild->pszText); 1140 1141 if (comp < 0) /* we are smaller than the current one */ 1142 { 1143 TREEVIEW_InsertBefore(newItem, aChild, parentItem); 1144 bItemInserted = TRUE; 1145 break; 1146 } 1147 else if (comp > 0) /* we are bigger than the current one */ 1148 { 1149 previousChild = aChild; 1150 aChild = (aChild->nextSibling == 0) /* This will help us to exit */ 1151 ? NULL /* if there is no more sibling */ 1152 : aChild->nextSibling; 1153 1154 /* Look at the next item */ 1155 continue; 1156 } 1157 else if (comp == 0) 1158 { 1159 /* 1160 * An item with this name is already existing, therefore, 1161 * we add after the one we found 1162 */ 1163 TREEVIEW_InsertAfter(newItem, aChild, parentItem); 1164 bItemInserted = TRUE; 1165 break; 1166 } 1167 } 1168 1169 /* 1170 * we reach the end of the child list and the item as not 1171 * yet been inserted, therefore, insert it after the last child. 1172 */ 1173 if ((!bItemInserted) && (aChild == NULL)) 1174 TREEVIEW_InsertAfter(newItem, previousChild, parentItem); 1175 } else 1176 { 1177 /* hInsertAfter names a specific item we want to insert after */ 1178 TREEVIEW_InsertAfter(newItem,insertAfter,parentItem); 1179 } 1180 1181 //TRACE("new item %p; parent %p, mask %x\n", newItem, 1182 // newItem->parent, tvItem->mask); 1183 1184 newItem->iLevel = newItem->parent->iLevel + 1; 1185 1186 if (newItem->parent->cChildren == 0) 1187 newItem->parent->cChildren = 1; 1188 1189 if (infoPtr->dwStyle & TVS_CHECKBOXES) 1190 { 1191 if (STATEIMAGEINDEX(newItem->state) == 0) 1192 newItem->state |= INDEXTOSTATEIMAGEMASK(1); 1193 } 1194 1195 TREEVIEW_VerifyTree(infoPtr); 1196 1197 newItem->calculated = FALSE; 1198 TREEVIEW_QueueRefresh(infoPtr); 1199 1200 return (LRESULT)newItem; 1201 } 1202 1203 /* Item Deletion ************************************************************/ 1204 static void 1205 TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem); 1206 1207 static void 1208 TREEVIEW_RemoveAllChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *parentItem) 1209 { 1210 TREEVIEW_ITEM *kill = parentItem->firstChild; 1211 1212 while (kill != NULL) 1213 { 1214 TREEVIEW_ITEM *next = kill->nextSibling; 1215 1216 TREEVIEW_RemoveItem(infoPtr, kill); 1217 1218 kill = next; 1219 } 1220 1221 assert(parentItem->cChildren <= 0); /* I_CHILDRENCALLBACK or 0 */ 1222 assert(parentItem->firstChild == NULL); 1223 assert(parentItem->lastChild == NULL); 1224 } 1225 1226 static void 1227 TREEVIEW_UnlinkItem(TREEVIEW_ITEM *item) 1228 { 1229 TREEVIEW_ITEM *parentItem = item->parent; 1230 1231 assert(item != NULL); 1232 assert(item->parent != NULL); /* i.e. it must not be the root */ 1233 1234 if (parentItem->firstChild == item) 1235 parentItem->firstChild = item->nextSibling; 1236 1237 if (parentItem->lastChild == item) 1238 parentItem->lastChild = item->prevSibling; 1239 1240 if (parentItem->firstChild == NULL && parentItem->lastChild == NULL 1241 && parentItem->cChildren > 0) 1242 parentItem->cChildren = 0; 1243 1244 if (item->prevSibling) 1245 item->prevSibling->nextSibling = item->nextSibling; 1246 1247 if (item->nextSibling) 1248 item->nextSibling->prevSibling = item->prevSibling; 1249 } 1250 1251 static void 1252 TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem) 1253 { 1254 TREEVIEW_ITEM *newFirstVisible; 1255 1256 //TRACE("%p, (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); 1257 1258 TREEVIEW_SendTreeviewNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_DELETEITEMW:TVN_DELETEITEMA,TVIF_HANDLE | TVIF_PARAM,0,wineItem,0); 1259 1260 if (wineItem->firstChild) 1261 TREEVIEW_RemoveAllChildren(infoPtr, wineItem); 1262 1263 /* Selection is handled in TREEVIEW_DeleteItem. */ 1264 1265 if (infoPtr->insertMarkItem == wineItem) 1266 infoPtr->insertMarkItem = NULL; 1267 1268 /* XXX focusItem, hotItem, dropItem */ 1269 1270 TREEVIEW_UnlinkItem(wineItem); 1271 1272 infoPtr->uNumItems--; 1273 1274 if (wineItem->pszText != LPSTR_TEXTCALLBACKW) 1275 COMCTL32_Free(wineItem->pszText); 1276 1277 TREEVIEW_FreeItem(infoPtr, wineItem); 1278 } 1279 1280 1281 /* Empty out the tree. */ 1282 static void 1283 TREEVIEW_RemoveTree(TREEVIEW_INFO *infoPtr) 1284 { 1285 TREEVIEW_RemoveAllChildren(infoPtr, infoPtr->root); 1286 1287 assert(infoPtr->uNumItems == 0); /* root isn't counted in uNumItems */ 1288 } 1289 1290 static LRESULT 1291 TREEVIEW_DeleteItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1292 { 1293 TREEVIEW_ITEM *oldSelection = infoPtr->selectedItem; 1294 TREEVIEW_ITEM *newSelection = NULL; 1295 1296 if (lParam == (LPARAM)TVI_ROOT) 1297 { 1298 newSelection = NULL; 1299 TREEVIEW_RemoveTree(infoPtr); 1300 } 1301 else 1302 { 1303 TREEVIEW_ITEM *wineItem = (TREEVIEW_ITEM *)lParam; 1304 1305 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 1306 return FALSE; 1307 1308 //TRACE("%p (%s)\n", wineItem, TREEVIEW_ItemName(wineItem)); 1309 1310 if (infoPtr->selectedItem != NULL 1311 && (wineItem == infoPtr->selectedItem 1312 || TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem))) 1313 { 1314 if (wineItem->nextSibling) 1315 newSelection = wineItem->nextSibling; 1316 else if (wineItem->parent != infoPtr->root) 1317 newSelection = wineItem->parent; 1318 } 1319 1320 TREEVIEW_RemoveItem(infoPtr, wineItem); 1321 } 1322 1323 /* Don't change if somebody else already has. */ 1324 if (oldSelection == infoPtr->selectedItem 1325 && TREEVIEW_ValidItem(infoPtr, newSelection)) 1326 { 1327 TREEVIEW_DoSelectItem(infoPtr, TVGN_CARET, newSelection, TVC_UNKNOWN); 1328 } 1329 1330 TREEVIEW_VerifyTree(infoPtr); 1331 1332 TREEVIEW_QueueRefresh(infoPtr); 1333 1334 return TRUE; 1335 } 1336 1337 /* Get/Set Messages *********************************************************/ 1338 1339 static LRESULT 1340 TREEVIEW_GetIndent(TREEVIEW_INFO *infoPtr) 1341 { 1342 return infoPtr->uIndent; 1343 } 1344 1345 static LRESULT 1346 TREEVIEW_SetIndent(TREEVIEW_INFO *infoPtr, WPARAM wParam) 1347 { 1348 INT newIndent; 1349 1350 newIndent = (INT)wParam; 1351 if (newIndent < MINIMUM_INDENT) 1352 newIndent = MINIMUM_INDENT; 1353 1354 if (infoPtr->uIndent != newIndent) 1355 { 1356 infoPtr->uIndent = newIndent; 1357 1358 infoPtr->uInternalStatus |= TV_CALCALL; 1359 TREEVIEW_QueueRefresh(infoPtr); 1360 } 1361 1362 return 0; 1363 } 1364 1365 static LRESULT 1366 TREEVIEW_GetToolTips(TREEVIEW_INFO *infoPtr) 1367 { 1368 return infoPtr->hwndToolTip; 1369 } 1370 1371 static LRESULT 1372 TREEVIEW_SetToolTips(TREEVIEW_INFO *infoPtr, WPARAM wParam) 1373 { 1374 HWND prevToolTip; 1375 1376 prevToolTip = infoPtr->hwndToolTip; 1377 infoPtr->hwndToolTip = (HWND)wParam; 1378 1379 return prevToolTip; 1380 } 1381 1382 static LRESULT 1383 TREEVIEW_GetScrollTime(TREEVIEW_INFO *infoPtr) 1384 { 1385 return infoPtr->uScrollTime; 1386 } 1387 1388 static LRESULT 1389 TREEVIEW_SetScrollTime(TREEVIEW_INFO *infoPtr, UINT uScrollTime) 1390 { 1391 UINT uOldScrollTime = infoPtr->uScrollTime; 1392 1393 infoPtr->uScrollTime = min(uScrollTime, 100); 1394 1395 return uOldScrollTime; 1396 } 1397 1398 1399 static LRESULT 1400 TREEVIEW_GetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1401 { 1402 switch (wParam) 1403 { 1404 case (WPARAM)TVSIL_NORMAL: 1405 return (LRESULT)infoPtr->himlNormal; 1406 1407 case (WPARAM)TVSIL_STATE: 1408 return (LRESULT)infoPtr->himlState; 1409 1410 default: 1411 return 0; 1412 } 1413 } 1414 1415 static LRESULT 1416 TREEVIEW_SetImageList(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1417 { 1418 HIMAGELIST himlNew = (HIMAGELIST)lParam; 1419 HIMAGELIST himlOld = 0; 1420 1421 switch (wParam) 1422 { 1423 case (WPARAM)TVSIL_NORMAL: 1424 himlOld = infoPtr->himlNormal; 1425 infoPtr->himlNormal = himlNew; 1426 1427 if (himlNew != NULL) 1428 ImageList_GetIconSize(himlNew, &infoPtr->normalImageWidth, 1429 &infoPtr->normalImageHeight); 1430 else 1431 { 1432 infoPtr->normalImageWidth = 0; 1433 infoPtr->normalImageHeight = 0; 1434 } 1435 1436 break; 1437 1438 case (WPARAM)TVSIL_STATE: 1439 himlOld = infoPtr->himlState; 1440 infoPtr->himlState = himlNew; 1441 1442 if (himlNew != NULL) 1443 ImageList_GetIconSize(himlNew, &infoPtr->stateImageWidth, 1444 &infoPtr->stateImageHeight); 1445 else 1446 { 1447 infoPtr->stateImageWidth = 0; 1448 infoPtr->stateImageHeight = 0; 1449 } 1450 1451 break; 1452 } 1453 1454 infoPtr->uInternalStatus |= TV_CALCALL; 1455 TREEVIEW_QueueRefresh(infoPtr); 1456 1457 return (LRESULT)himlOld; 1458 } 1459 1460 /* Compute the natural height (based on the font size) for items. */ 1461 static UINT 1462 TREEVIEW_NaturalHeight(TREEVIEW_INFO *infoPtr) 1463 { 1464 TEXTMETRICA tm; 1465 HDC hdc = GetDC(infoPtr->hwnd); 1466 HFONT hOldFont = SelectObject(hdc, infoPtr->hFont); 1467 INT height; 1468 1469 GetTextMetricsA(hdc, &tm); 1470 1471 SelectObject(hdc, hOldFont); 1472 ReleaseDC(infoPtr->hwnd, hdc); 1473 1474 /* The 16 is a hack because our fonts are tiny. */ 1475 height = MAX(16, tm.tmHeight + tm.tmExternalLeading); 1476 if (!(infoPtr->dwStyle & TVS_NONEVENHEIGHT)) 1477 if (height & 0x1) height++; //important for PS_DOT pen! 1478 1479 return height; 1480 } 1481 1482 static LRESULT 1483 TREEVIEW_SetItemHeight(TREEVIEW_INFO *infoPtr, WPARAM wParam) 1484 { 1485 INT prevHeight = infoPtr->uItemHeight; 1486 1487 if (wParam == (WPARAM)(SHORT)-1) 1488 { 1489 infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); 1490 infoPtr->bHeightSet = FALSE; 1491 } 1492 else 1493 { 1494 infoPtr->uItemHeight = wParam; 1495 infoPtr->bHeightSet = TRUE; 1496 } 1497 1498 if (!(infoPtr->dwStyle & TVS_NONEVENHEIGHT)) 1499 if (infoPtr->uItemHeight & 0x1) infoPtr->uItemHeight++; 1500 1501 if (infoPtr->uItemHeight != prevHeight) 1502 { 1503 infoPtr->uInternalStatus |= TV_CALCALL; 1504 TREEVIEW_QueueRefresh(infoPtr); 1505 } 1506 1507 return prevHeight; 1508 } 1509 1510 static LRESULT 1511 TREEVIEW_GetItemHeight(TREEVIEW_INFO *infoPtr) 1512 { 1513 return infoPtr->uItemHeight; 1514 } 1515 1516 1517 static LRESULT 1518 TREEVIEW_GetFont(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1519 { 1520 return infoPtr->hFont; 1521 } 1522 1523 static LRESULT 1524 TREEVIEW_SetFont(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1525 { 1526 infoPtr->hFont = wParam ? (HFONT)wParam : GetStockObject(SYSTEM_FONT); 1527 1528 DeleteObject(infoPtr->hBoldFont); 1529 infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); 1530 1531 if (!infoPtr->bHeightSet) 1532 infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); 1533 1534 SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,1); 1535 infoPtr->uInternalStatus |= TV_CALCALL; 1536 TREEVIEW_CalcItems(infoPtr); 1537 1538 if (lParam) 1539 { 1540 TREEVIEW_UnqueueRefresh(infoPtr,FALSE,FALSE); 1541 TREEVIEW_Refresh(infoPtr); 1542 } 1543 1544 return 0; 1545 } 1546 1547 1548 static LRESULT 1549 TREEVIEW_GetLineColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1550 { 1551 return (LRESULT)infoPtr->clrLine; 1552 } 1553 1554 static LRESULT 1555 TREEVIEW_SetLineColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1556 { 1557 COLORREF prevColor = infoPtr->clrLine; 1558 1559 infoPtr->clrLine = (COLORREF)lParam; 1560 1561 return (LRESULT)prevColor; 1562 } 1563 1564 1565 static LRESULT 1566 TREEVIEW_GetTextColor(TREEVIEW_INFO *infoPtr) 1567 { 1568 return (LRESULT)infoPtr->clrText; 1569 } 1570 1571 static LRESULT 1572 TREEVIEW_SetTextColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1573 { 1574 COLORREF prevColor = infoPtr->clrText; 1575 1576 infoPtr->clrText = (COLORREF)lParam; 1577 1578 if (infoPtr->clrText != prevColor) 1579 TREEVIEW_QueueRefresh(infoPtr); 1580 1581 return (LRESULT)prevColor; 1582 } 1583 1584 1585 static LRESULT 1586 TREEVIEW_GetBkColor(TREEVIEW_INFO *infoPtr) 1587 { 1588 return (LRESULT)infoPtr->clrBk; 1589 } 1590 1591 static LRESULT 1592 TREEVIEW_SetBkColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1593 { 1594 COLORREF prevColor = infoPtr->clrBk; 1595 1596 infoPtr->clrBk = (COLORREF)lParam; 1597 1598 if (infoPtr->clrBk != prevColor) 1599 TREEVIEW_QueueRefresh(infoPtr); 1600 1601 return (LRESULT)prevColor; 1602 } 1603 1604 1605 static LRESULT 1606 TREEVIEW_GetInsertMarkColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, 1607 LPARAM lParam) 1608 { 1609 return (LRESULT)infoPtr->clrInsertMark; 1610 } 1611 1612 static LRESULT 1613 TREEVIEW_SetInsertMarkColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, 1614 LPARAM lParam) 1615 { 1616 COLORREF prevColor = infoPtr->clrInsertMark; 1617 1618 infoPtr->clrInsertMark = (COLORREF)lParam; 1619 1620 return (LRESULT)prevColor; 1621 } 1622 1623 1624 static LRESULT 1625 TREEVIEW_SetInsertMark(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1626 { 1627 if (!TREEVIEW_ValidItem(infoPtr, (HTREEITEM)lParam)) 1628 return 0; 1629 1630 infoPtr->insertBeforeorAfter = (BOOL)wParam; 1631 infoPtr->insertMarkItem = (HTREEITEM)lParam; 1632 1633 TREEVIEW_QueueRefresh(infoPtr); 1634 1635 return 1; 1636 } 1637 1638 /************************************************************************ 1639 * Some serious braindamage here. lParam is a pointer to both the 1640 * input HTREEITEM and the output RECT. 1641 */ 1642 static LRESULT 1643 TREEVIEW_GetItemRect(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1644 { 1645 TREEVIEW_ITEM *wineItem; 1646 const HTREEITEM *pItem = (HTREEITEM *)lParam; 1647 LPRECT lpRect = (LPRECT)lParam; 1648 1649 /* 1650 * validate parameters 1651 */ 1652 if ((pItem == NULL) || (lpRect == NULL)) 1653 return FALSE; 1654 1655 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 1656 1657 wineItem = *pItem; 1658 if (!TREEVIEW_ValidItem(infoPtr, *pItem) || !wineItem->displayed) 1659 return FALSE; 1660 1661 if (!wineItem->calculated) 1662 TREEVIEW_CalcItem(infoPtr,wineItem,(HDC)0); 1663 1664 /* 1665 * If wParam is TRUE return the text size otherwise return 1666 * the whole item size 1667 */ 1668 if (wParam) 1669 { 1670 /* Windows does not send TVN_GETDISPINFO here. */ 1671 1672 lpRect->top = wineItem->rect.top; 1673 lpRect->bottom = wineItem->rect.bottom; 1674 1675 lpRect->left = wineItem->textOffset; 1676 lpRect->right = wineItem->textOffset+wineItem->textWidth+4; 1677 } 1678 else 1679 { 1680 *lpRect = wineItem->rect; 1681 } 1682 1683 return TRUE; 1684 } 1685 1686 static inline LRESULT 1687 TREEVIEW_GetVisibleCount(TREEVIEW_INFO *infoPtr) 1688 { 1689 /* Suprise! This does not take integral height into account. */ 1690 return infoPtr->clientHeight / infoPtr->uItemHeight; 1691 } 1692 1693 static LRESULT 1694 TREEVIEW_GetItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam,BOOL unicode) 1695 { 1696 LPTVITEMEXW tvItem; 1697 TREEVIEW_ITEM *wineItem; 1698 1699 tvItem = (LPTVITEMEXW)lParam; 1700 1701 wineItem = tvItem->hItem; 1702 1703 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 1704 return FALSE; 1705 1706 TREEVIEW_UpdateDispInfo(infoPtr, wineItem, tvItem->mask); 1707 1708 if (tvItem->mask & TVIF_CHILDREN) 1709 tvItem->cChildren = wineItem->cChildren; 1710 1711 if (tvItem->mask & TVIF_HANDLE) 1712 tvItem->hItem = wineItem; 1713 1714 if (tvItem->mask & TVIF_IMAGE) 1715 tvItem->iImage = wineItem->iImage; 1716 1717 if (tvItem->mask & TVIF_INTEGRAL) 1718 tvItem->iIntegral = wineItem->iIntegral; 1719 1720 /* undocumented: windows ignores TVIF_PARAM and 1721 * * always sets lParam 1722 */ 1723 tvItem->lParam = wineItem->lParam; 1724 1725 if (tvItem->mask & TVIF_SELECTEDIMAGE) 1726 tvItem->iSelectedImage = wineItem->iSelectedImage; 1727 1728 if (tvItem->mask & TVIF_STATE) 1729 tvItem->state = wineItem->state & tvItem->stateMask; 1730 1731 if (tvItem->mask & TVIF_TEXT) 1732 { 1733 if (unicode) 1734 lstrcpynW(tvItem->pszText,wineItem->pszText,tvItem->cchTextMax); 1735 else 1736 lstrcpynWtoA((CHAR*)tvItem->pszText,wineItem->pszText,tvItem->cchTextMax); 1737 } 1738 1739 return TRUE; 1740 } 1741 1742 /* Beware MSDN Library Visual Studio 6.0. It says -1 on failure, 0 on success, 1743 * which is wrong. */ 1744 static LRESULT 1745 TREEVIEW_SetItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam,BOOL unicode) 1746 { 1747 TREEVIEW_ITEM *wineItem; 1748 TVITEMEXW *tvItem; 1749 DWORD changed = 0; 1750 1751 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwnd); 1752 1753 tvItem = (LPTVITEMEXW)lParam; 1754 wineItem = tvItem->hItem; 1755 1756 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 1757 return FALSE; 1758 1759 if (!TREEVIEW_DoSetItem(infoPtr,wineItem,tvItem,unicode,&changed)) 1760 return FALSE; 1761 1762 /* If the text or TVIS_BOLD was changed, and it is displayed, recalculate. */ 1763 if (((changed & TVIF_TEXT) || ((tvItem->mask & TVIF_STATE) && (tvItem->stateMask & TVIS_BOLD))) && wineItem->displayed) 1764 { 1765 TREEVIEW_ComputeTextWidth(infoPtr,wineItem,0,FALSE); 1766 } 1767 1768 if (changed & (TVIF_INTEGRAL | TVIF_CHILDREN)) 1769 TREEVIEW_QueueRefresh(infoPtr); 1770 else 1771 TREEVIEW_RefreshItem(infoPtr,wineItem,changed); 1772 1773 return TRUE; 1774 } 1775 1776 static LRESULT 1777 TREEVIEW_GetItemState(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1778 { 1779 TREEVIEW_ITEM *wineItem = (HTREEITEM)wParam; 1780 1781 if (!wineItem || !TREEVIEW_ValidItem(infoPtr, wineItem)) 1782 return 0; 1783 1784 return (wineItem->state & lParam); 1785 } 1786 1787 static LRESULT 1788 TREEVIEW_GetNextItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1789 { 1790 TREEVIEW_ITEM *wineItem; 1791 TREEVIEW_ITEM *retval; 1792 WPARAM which; 1793 1794 which = (INT)wParam; 1795 wineItem = (TREEVIEW_ITEM *)lParam; 1796 retval = 0; 1797 1798 /* handle all the global data here */ 1799 switch (which) 1800 { 1801 case TVGN_CHILD: /* Special case: child of 0 is root */ 1802 if (wineItem) 1803 break; 1804 /* fall through */ 1805 case TVGN_ROOT: 1806 retval = infoPtr->root->firstChild; 1807 break; 1808 1809 case TVGN_CARET: 1810 retval = infoPtr->selectedItem; 1811 break; 1812 1813 case TVGN_FIRSTVISIBLE: 1814 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 1815 retval = infoPtr->firstVisible; 1816 break; 1817 1818 case TVGN_DROPHILITE: 1819 retval = infoPtr->dropItem; 1820 break; 1821 } 1822 1823 if (retval) 1824 { 1825 //TRACE("flags:%x, returns %p\n", which, retval); 1826 return (LRESULT)retval; 1827 } 1828 1829 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 1830 return FALSE; 1831 1832 switch (which) 1833 { 1834 case TVGN_NEXT: 1835 retval = wineItem->nextSibling; 1836 break; 1837 1838 case TVGN_PREVIOUS: 1839 retval = wineItem->prevSibling; 1840 break; 1841 1842 case TVGN_PARENT: 1843 retval = (wineItem->parent != infoPtr->root) ? wineItem->parent : NULL; 1844 break; 1845 1846 case TVGN_CHILD: 1847 retval = wineItem->firstChild; 1848 break; 1849 1850 case TVGN_LASTVISIBLE: 1851 retval = TREEVIEW_GetLastListItem(infoPtr, wineItem); 1852 break; 1853 1854 case TVGN_NEXTVISIBLE: 1855 retval = TREEVIEW_GetNextListItem(infoPtr, wineItem); 1856 break; 1857 1858 case TVGN_PREVIOUSVISIBLE: 1859 retval = TREEVIEW_GetPrevListItem(infoPtr, wineItem); 1860 break; 1861 1862 default: 1863 //TRACE("Unknown msg %x,item %p\n", which, wineItem); 1864 break; 1865 } 1866 1867 //TRACE("flags:%x, item %p;returns %p\n", which, wineItem, retval); 1868 return (LRESULT)retval; 1869 } 1870 1871 1872 static LRESULT 1873 TREEVIEW_GetCount(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 1874 { 1875 return (LRESULT)infoPtr->uNumItems; 1876 } 1877 1878 static VOID 1879 TREEVIEW_ToggleItemState(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 1880 { 1881 if (infoPtr->dwStyle & TVS_CHECKBOXES) 1882 { 1883 static const unsigned int state_table[] = { 0, 2, 1 }; 1884 1885 unsigned int state; 1886 1887 state = STATEIMAGEINDEX(item->state); 1888 //TRACE("state:%x\n", state); 1889 item->state &= ~TVIS_STATEIMAGEMASK; 1890 1891 if (state < 3) 1892 state = state_table[state]; 1893 1894 item->state |= INDEXTOSTATEIMAGEMASK(state); 1895 1896 //TRACE("state:%x\n", state); 1897 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE); 1898 } 1899 } 1900 1901 1902 /* Painting *************************************************************/ 1903 1904 /* Draw the lines and expand button for an item. Also draws one section 1905 * of the line from item's parent to item's parent's next sibling. */ 1906 static void 1907 TREEVIEW_DrawItemLines(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *item) 1908 { 1909 LONG centerx, centery; 1910 BOOL lar = ((infoPtr->dwStyle 1911 & (TVS_LINESATROOT|TVS_HASLINES|TVS_HASBUTTONS)) 1912 > TVS_LINESATROOT); 1913 1914 if (!lar && item->iLevel == 0) 1915 return; 1916 1917 centerx = (item->linesOffset + item->stateOffset) / 2; 1918 centery = (item->rect.top + item->rect.bottom) / 2; 1919 1920 if (infoPtr->dwStyle & TVS_HASLINES) 1921 { 1922 HPEN hOldPen, hNewPen; 1923 HTREEITEM parent; 1924 1925 /* 1926 * Get a dotted grey pen 1927 */ 1928 hNewPen = CreatePen(PS_DOT, 0, infoPtr->clrLine); 1929 hOldPen = SelectObject(hdc, hNewPen); 1930 1931 MoveToEx(hdc, item->stateOffset, centery, NULL); 1932 LineTo(hdc, centerx - 1, centery); 1933 1934 if (item->prevSibling || item->parent != infoPtr->root) 1935 { 1936 MoveToEx(hdc, centerx, item->rect.top, NULL); 1937 LineTo(hdc, centerx, centery); 1938 } 1939 1940 if (item->nextSibling) 1941 { 1942 MoveToEx(hdc, centerx, centery, NULL); 1943 LineTo(hdc, centerx, item->rect.bottom + 1); 1944 } 1945 1946 /* Draw the line from our parent to its next sibling. */ 1947 parent = item->parent; 1948 while (parent != infoPtr->root) 1949 { 1950 int pcenterx = (parent->linesOffset + parent->stateOffset) / 2; 1951 1952 if (parent->nextSibling 1953 /* skip top-levels unless TVS_LINESATROOT */ 1954 && parent->stateOffset > parent->linesOffset) 1955 { 1956 MoveToEx(hdc, pcenterx, item->rect.top, NULL); 1957 LineTo(hdc, pcenterx, item->rect.bottom + 1); 1958 } 1959 1960 parent = parent->parent; 1961 } 1962 1963 SelectObject(hdc, hOldPen); 1964 DeleteObject(hNewPen); 1965 } 1966 1967 /* 1968 * Display the (+/-) signs 1969 */ 1970 1971 if (infoPtr->dwStyle & TVS_HASBUTTONS) 1972 { 1973 if (item->cChildren) 1974 { 1975 LONG height = item->rect.bottom - item->rect.top; 1976 LONG width = item->stateOffset - item->linesOffset; 1977 LONG rectsize = MIN(height, width) / 4; 1978 /* plussize = ceil(rectsize * 3/4) */ 1979 LONG plussize = (rectsize + 1) * 3 / 4; 1980 1981 HPEN hNewPen = CreatePen(PS_SOLID, 0, infoPtr->clrLine); 1982 HPEN hOldPen = SelectObject(hdc, hNewPen); 1983 1984 Rectangle(hdc, centerx - rectsize, centery - rectsize, 1985 centerx + rectsize + 1, centery + rectsize + 1); 1986 1987 SelectObject(hdc, hOldPen); 1988 DeleteObject(hNewPen); 1989 1990 MoveToEx(hdc, centerx - plussize + 1, centery, NULL); 1991 LineTo(hdc, centerx + plussize, centery); 1992 1993 if (!(item->state & TVIS_EXPANDED)) 1994 { 1995 MoveToEx(hdc, centerx, centery - plussize + 1, NULL); 1996 LineTo(hdc, centerx, centery + plussize); 1997 } 1998 } 1999 } 2000 } 2001 2002 static VOID TREEVIEW_DrawHottrackLine(HDC hdc,TREEVIEW_ITEM *item) 2003 { 2004 HPEN hPen,hOldPen; 2005 INT rop; 2006 2007 if (!item->inclient) return; 2008 2009 rop = SetROP2(hdc,R2_XORPEN); 2010 hPen = CreatePen(PS_SOLID,2,RGB(0,0,0)); 2011 hOldPen = SelectObject(hdc,hPen); 2012 2013 MoveToEx(hdc,item->textOffset,item->rect.bottom-1,NULL); 2014 LineTo(hdc,item->textOffset+item->textWidth,item->rect.bottom-1); 2015 2016 DeleteObject(hPen); 2017 SelectObject(hdc,hOldPen); 2018 SetROP2(hdc,rop); 2019 } 2020 2021 static void 2022 TREEVIEW_DrawItem(TREEVIEW_INFO *infoPtr, HDC hdc, TREEVIEW_ITEM *wineItem) 2023 { 2024 INT cditem; 2025 HFONT hOldFont; 2026 int centery; 2027 2028 if (!wineItem->calculated) TREEVIEW_CalcItem(infoPtr,wineItem,hdc); 2029 2030 hOldFont = SelectObject(hdc, TREEVIEW_FontForItem(infoPtr, wineItem)); 2031 2032 TREEVIEW_UpdateDispInfo(infoPtr, wineItem, CALLBACK_MASK_ALL); 2033 2034 /* The custom draw handler can query the text rectangle, 2035 * so get ready. */ 2036 TREEVIEW_ComputeTextWidth(infoPtr,wineItem,hdc,TRUE); 2037 2038 cditem = 0; 2039 2040 if (infoPtr->cdmode & CDRF_NOTIFYITEMDRAW) 2041 { 2042 cditem = TREEVIEW_SendCustomDrawItemNotify(infoPtr, hdc, wineItem, CDDS_ITEMPREPAINT); 2043 2044 if (cditem & CDRF_SKIPDEFAULT) 2045 { 2046 SelectObject(hdc, hOldFont); 2047 return; 2048 } 2049 } 2050 2051 if (cditem & CDRF_NEWFONT) 2052 TREEVIEW_ComputeTextWidth(infoPtr,wineItem,hdc,TRUE); 2053 2054 TREEVIEW_DrawItemLines(infoPtr, hdc, wineItem); 2055 2056 centery = (wineItem->rect.top + wineItem->rect.bottom) / 2; 2057 2058 /* 2059 * Display the images associated with this item 2060 */ 2061 { 2062 INT imageIndex; 2063 2064 /* State images are displayed to the left of the Normal image 2065 * image number is in state; zero should be `display no image'. 2066 */ 2067 imageIndex = STATEIMAGEINDEX(wineItem->state); 2068 2069 if (infoPtr->himlState && imageIndex) 2070 { 2071 ImageList_Draw(infoPtr->himlState, imageIndex - 1, hdc, 2072 wineItem->stateOffset, 2073 centery - infoPtr->stateImageHeight / 2, 2074 ILD_NORMAL); 2075 } 2076 2077 /* Now, draw the normal image; can be either selected or 2078 * non-selected image. 2079 */ 2080 2081 if ((wineItem->state & TVIS_SELECTED) && wineItem->iSelectedImage) 2082 { 2083 /* The item is curently selected */ 2084 imageIndex = wineItem->iSelectedImage; 2085 } 2086 else 2087 { 2088 /* The item is not selected */ 2089 imageIndex = wineItem->iImage; 2090 } 2091 2092 if (infoPtr->himlNormal && (imageIndex != I_IMAGENONE)) 2093 { 2094 int ovlIdx = wineItem->state & TVIS_OVERLAYMASK; 2095 2096 ImageList_Draw(infoPtr->himlNormal, imageIndex, hdc, 2097 wineItem->imageOffset, 2098 centery - infoPtr->normalImageHeight / 2, 2099 ILD_NORMAL | ovlIdx); 2100 } 2101 } 2102 2103 2104 /* 2105 * Display the text associated with this item 2106 */ 2107 2108 /* Don't paint item's text if it's being edited */ 2109 if (!infoPtr->hwndEdit) 2110 { 2111 if (wineItem->pszText && (wineItem->pszText[0] != 0)) 2112 { 2113 COLORREF oldTextColor = 0; 2114 INT oldBkMode; 2115 HBRUSH hbrBk = 0; 2116 BOOL inFocus = (GetFocus() == infoPtr->hwnd); 2117 RECT rcText; 2118 2119 oldBkMode = SetBkMode(hdc, TRANSPARENT); 2120 2121 /* - If item is drop target or it is selected and window is in focus - 2122 * use blue background (COLOR_HIGHLIGHT). 2123 * - If item is selected, window is not in focus, but it has style 2124 * TVS_SHOWSELALWAYS - use grey background (COLOR_BTNFACE) 2125 * - Otherwise - don't fill background 2126 */ 2127 if ((wineItem->state & TVIS_DROPHILITED) || 2128 ((wineItem->state & TVIS_SELECTED) && 2129 (inFocus || (infoPtr->dwStyle & TVS_SHOWSELALWAYS)))) 2130 { 2131 if ((wineItem->state & TVIS_DROPHILITED) || inFocus) 2132 { 2133 hbrBk = CreateSolidBrush(GetSysColor(COLOR_HIGHLIGHT)); 2134 oldTextColor = 2135 SetTextColor(hdc, GetSysColor(COLOR_HIGHLIGHTTEXT)); 2136 } 2137 else 2138 { 2139 hbrBk = CreateSolidBrush(GetSysColor(COLOR_BTNFACE)); 2140 2141 if (infoPtr->clrText == -1) 2142 oldTextColor = 2143 SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); 2144 else 2145 oldTextColor = SetTextColor(hdc, infoPtr->clrText); 2146 } 2147 } 2148 else 2149 { 2150 if (infoPtr->clrText == -1) 2151 oldTextColor = 2152 SetTextColor(hdc, GetSysColor(COLOR_WINDOWTEXT)); 2153 else 2154 oldTextColor = SetTextColor(hdc, infoPtr->clrText); 2155 } 2156 2157 rcText.top = wineItem->rect.top; 2158 rcText.bottom = wineItem->rect.bottom; 2159 rcText.left = wineItem->textOffset; 2160 rcText.right = rcText.left + wineItem->textWidth + 4; 2161 2162 if (hbrBk) 2163 { 2164 FillRect(hdc, &rcText, hbrBk); 2165 DeleteObject(hbrBk); 2166 } 2167 2168 /* Draw the box arround the selected item */ 2169 if ((wineItem->state & TVIS_SELECTED) && inFocus) 2170 { 2171 HPEN hNewPen = CreatePen(PS_DOT, 0, 2172 GetSysColor(COLOR_WINDOWTEXT)); 2173 HPEN hOldPen = SelectObject(hdc, hNewPen); 2174 INT rop = SetROP2(hdc, R2_XORPEN); 2175 POINT points[5]; 2176 2177 points[4].x = points[0].x = rcText.left; 2178 points[4].y = points[0].y = rcText.top; 2179 points[1].x = rcText.right - 1; 2180 points[1].y = rcText.top; 2181 points[2].x = rcText.right - 1; 2182 points[2].y = rcText.bottom - 1; 2183 points[3].x = rcText.left; 2184 points[3].y = rcText.bottom - 1; 2185 2186 Polyline(hdc, points, 5); 2187 2188 SetROP2(hdc, rop); 2189 SelectObject(hdc, hOldPen); 2190 DeleteObject(hNewPen); 2191 } 2192 2193 rcText.left += 2; 2194 rcText.right -= 2; 2195 2196 /* Draw it */ 2197 DrawTextW(hdc, 2198 wineItem->pszText, 2199 lstrlenW(wineItem->pszText), 2200 &rcText, 2201 DT_LEFT | DT_VCENTER | DT_SINGLELINE | DT_NOPREFIX); 2202 2203 /* Restore the hdc state */ 2204 SetTextColor(hdc, oldTextColor); 2205 2206 if (oldBkMode != TRANSPARENT) 2207 SetBkMode(hdc, oldBkMode); 2208 } 2209 } 2210 2211 /* Draw insertion mark if necessary */ 2212 2213 if (wineItem == infoPtr->insertMarkItem) 2214 { 2215 HPEN hNewPen, hOldPen; 2216 int offset; 2217 int left, right; 2218 2219 hNewPen = CreatePen(PS_SOLID, 2, infoPtr->clrInsertMark); 2220 hOldPen = SelectObject(hdc, hNewPen); 2221 2222 if (infoPtr->insertBeforeorAfter) 2223 offset = wineItem->rect.bottom - 1; 2224 else 2225 offset = wineItem->rect.top + 1; 2226 2227 left = wineItem->textOffset - 2; 2228 right = wineItem->textOffset + wineItem->textWidth + 2; 2229 2230 MoveToEx(hdc, left, offset - 3, NULL); 2231 LineTo(hdc, left, offset + 4); 2232 2233 MoveToEx(hdc, left, offset, NULL); 2234 LineTo(hdc, right + 1, offset); 2235 2236 MoveToEx(hdc, right, offset + 3, NULL); 2237 LineTo(hdc, right, offset - 4); 2238 2239 SelectObject(hdc, hOldPen); 2240 DeleteObject(hNewPen); 2241 } 2242 2243 //draw hot item if necessary 2244 if (wineItem == infoPtr->hotItem) 2245 TREEVIEW_DrawHottrackLine(hdc,wineItem); 2246 2247 if (cditem & CDRF_NOTIFYPOSTPAINT) 2248 { 2249 cditem = TREEVIEW_SendCustomDrawItemNotify(infoPtr, hdc, wineItem, CDDS_ITEMPOSTPAINT); 2250 } 2251 2252 SelectObject(hdc, hOldFont); 2253 } 2254 2255 static void TREEVIEW_QueueRefresh(TREEVIEW_INFO *infoPtr) 2256 { 2257 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 2258 KillTimer(infoPtr->hwnd,TV_REFRESH_TIMER); 2259 2260 if (infoPtr->uInternalStatus & TV_NOREDRAW) 2261 { 2262 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 2263 2264 return; 2265 } 2266 2267 SetTimer(infoPtr->hwnd,TV_REFRESH_TIMER,TV_REFRESH_DELAY,0); 2268 infoPtr->Timer |= TV_REFRESH_TIMER_SET; 2269 } 2270 2271 static BOOL TREEVIEW_UnqueueRefresh(TREEVIEW_INFO *infoPtr,BOOL calc,BOOL refresh) 2272 { 2273 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 2274 { 2275 KillTimer(infoPtr->hwnd,TV_REFRESH_TIMER); 2276 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 2277 2278 if (calc) TREEVIEW_CalcItems(infoPtr); 2279 if (refresh) 2280 { 2281 TREEVIEW_Refresh(infoPtr); 2282 UpdateWindow(infoPtr->hwnd); 2283 } 2284 2285 return TRUE; 2286 } 2287 2288 return FALSE; 2289 } 2290 2291 static void 2292 TREEVIEW_Draw(TREEVIEW_INFO *infoPtr,HDC hdc,RECT *updateRect) 2293 { 1597 2294 RECT rect; 1598 2295 TREEVIEW_ITEM *item; 1599 INT iItem,indent; 1600 BOOL visFound = FALSE; 1601 HPEN hNewPen,hOldPen; 1602 1603 TREEVIEW_UnqueueRefresh(hwnd,TRUE,FALSE); 1604 1605 GetClientRect (hwnd, &rect); 2296 INT iItem; 2297 2298 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,FALSE); 2299 2300 GetClientRect(infoPtr->hwnd,&rect); 1606 2301 if ((rect.left == rect.right) || (rect.top == rect.bottom)) return; 1607 2302 1608 infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify( hwnd, CDDS_PREPAINT, hdc,rect);2303 infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(infoPtr,CDDS_PREPAINT,hdc,rect); 1609 2304 1610 2305 if (infoPtr->cdmode == CDRF_SKIPDEFAULT) return; 1611 2306 1612 / /draw items1613 1614 hNewPen = CreatePen(PS_DOT,0,infoPtr->clrLine); 1615 1616 iItem = (INT)infoPtr->TopRootItem;1617 indent = 0;1618 1619 while (iItem)1620 {1621 item = &infoPtr->items[iItem];1622 if (item->visible)2307 /* We iterate through all visible items in order */ 2308 item = infoPtr->firstVisible; 2309 2310 while ((item != NULL) && item->inclient) 2311 { 2312 RECT itemRect = item->rect; 2313 2314 if (!item->calculated) TREEVIEW_CalcItem(infoPtr,item,hdc); 2315 if (updateRect && IntersectRect(NULL,&itemRect,updateRect)) 2316 TREEVIEW_DrawItem(infoPtr,hdc,item); 2317 else 1623 2318 { 1624 if (updateRect && IntersectRect(NULL,&item->rect,updateRect)) 1625 { 1626 TREEVIEW_DrawItem(hwnd,hdc,item,dwStyle,infoPtr); 1627 visFound = TRUE; 1628 } else if (updateRect && (item->rect.top >= updateRect->bottom)) break; 1629 } else if (visFound) break; 1630 if (!visFound && (dwStyle & TVS_HASLINES) && (dwStyle & TVS_LINESATROOT)) 1631 { 1632 //draw vertical connections 1633 hOldPen = SelectObject(hdc,hNewPen); 1634 TREEVIEW_DrawVLines(hdc,infoPtr,item); 1635 SelectObject(hdc,hOldPen); 2319 if (updateRect && (item->rect.top >= updateRect->bottom)) break; 2320 itemRect.left = 0; 2321 if (updateRect && IntersectRect(NULL,&itemRect,updateRect)) 2322 TREEVIEW_DrawItemLines(infoPtr,hdc,item); 1636 2323 } 1637 if (item->firstChild && (item->state & TVIS_EXPANDED)) 1638 { 1639 iItem = (INT)item->firstChild; 1640 indent++; 1641 } else 1642 { 1643 iItem = (INT)item->sibling; 1644 while (!iItem && (indent > 0)) 1645 { 1646 item = &infoPtr->items[(INT)item->parent]; 1647 iItem = (INT)item->sibling; 1648 indent--; 1649 } 1650 } 1651 } 1652 1653 DeleteObject(hNewPen); 2324 item = TREEVIEW_GetNextListItem(infoPtr,item); 2325 } 1654 2326 1655 2327 if (infoPtr->cdmode & CDRF_NOTIFYPOSTPAINT) 1656 infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(hwnd, CDDS_POSTPAINT, hdc, rect); 1657 } 1658 1659 static LRESULT TREEVIEW_SetRedraw(HWND hwnd,WPARAM wParam,LPARAM lParam) 1660 { 1661 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1662 1663 if (wParam) 1664 { 1665 if (!(infoPtr->uInternalStatus & TV_NOREDRAW)) return 0; 1666 infoPtr->uInternalStatus &= ~TV_NOREDRAW; 1667 TREEVIEW_CalcItems(hwnd,0,infoPtr); 1668 TREEVIEW_Refresh(hwnd); 2328 infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(infoPtr, CDDS_POSTPAINT, hdc, rect); 2329 } 2330 2331 static void TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr) 2332 { 2333 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,FALSE); 2334 2335 InvalidateRect(infoPtr->hwnd,NULL,TRUE); 2336 } 2337 2338 static void TREEVIEW_RefreshItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,DWORD changed) 2339 { 2340 if (item && item->inclient) 2341 { 2342 RECT rect = item->rect; 2343 2344 //left 2345 if (changed & TVIF_STATE) rect.left = item->stateOffset; 2346 else if (changed & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) rect.left = item->imageOffset; 2347 else if (changed & TVIF_TEXT) rect.left = item->textOffset; 2348 2349 //right 2350 if (changed & TVIF_TEXT); 2351 else if (changed & (TVIF_IMAGE | TVIF_SELECTEDIMAGE)) rect.right = item->imageOffset-infoPtr->normalImageWidth; 2352 else if (changed & TVIF_STATE) rect.right = item->stateOffset-infoPtr->stateImageWidth; 2353 2354 InvalidateRect(infoPtr->hwnd,&rect,TRUE); 2355 } 2356 } 2357 2358 static LRESULT 2359 TREEVIEW_Paint(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 2360 { 2361 HDC hdc = (HDC)wParam; 2362 2363 if (!hdc) 2364 { 2365 PAINTSTRUCT ps; 2366 2367 hdc = BeginPaint(infoPtr->hwnd,&ps); 2368 TREEVIEW_Draw(infoPtr,hdc,&ps.rcPaint); 2369 EndPaint(infoPtr->hwnd,&ps); 1669 2370 } else 1670 { 1671 infoPtr->uInternalStatus |= TV_NOREDRAW; 1672 } 2371 TREEVIEW_Draw(infoPtr,hdc,NULL); 1673 2372 1674 2373 return 0; 1675 2374 } 1676 2375 1677 1678 static LRESULT 1679 TREEVIEW_HandleTimer (HWND hwnd, WPARAM wParam, LPARAM lParam) 1680 { 1681 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1682 1683 switch (wParam) 1684 { 1685 case TV_REFRESH_TIMER: 1686 KillTimer (hwnd, TV_REFRESH_TIMER); 1687 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 1688 TREEVIEW_CalcItems(hwnd,0,infoPtr); 1689 TREEVIEW_Refresh(hwnd); 1690 return 0; 1691 1692 case TV_EDIT_TIMER: 1693 KillTimer (hwnd, TV_EDIT_TIMER); 1694 infoPtr->Timer &= ~TV_EDIT_TIMER_SET; 1695 if (infoPtr->editItem) 1696 TREEVIEW_EditLabel(hwnd,infoPtr->editItem,TRUE); 1697 return 0; 1698 1699 case TV_INFOTIP_TIMER: 1700 TREEVIEW_CheckInfoTip(hwnd); 1701 return 0; 1702 } 1703 1704 return 1; 1705 } 1706 1707 static void TREEVIEW_QueueRefresh(HWND hwnd) 1708 1709 { 1710 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1711 1712 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 1713 KillTimer (hwnd, TV_REFRESH_TIMER); 1714 1715 if (infoPtr->uInternalStatus & TV_NOREDRAW) 1716 { 1717 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 1718 1719 return; 1720 } 1721 1722 SetTimer (hwnd, TV_REFRESH_TIMER, TV_REFRESH_DELAY, 0); 1723 infoPtr->Timer |= TV_REFRESH_TIMER_SET; 1724 } 1725 1726 static BOOL TREEVIEW_UnqueueRefresh(HWND hwnd,BOOL calc,BOOL refresh) 1727 { 1728 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1729 1730 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 1731 { 1732 KillTimer (hwnd, TV_REFRESH_TIMER); 1733 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 1734 if (calc) TREEVIEW_CalcItems(hwnd,0,infoPtr); 1735 if (refresh) 1736 { 1737 TREEVIEW_Refresh(hwnd); 1738 UpdateWindow(hwnd); 1739 } 1740 1741 return TRUE; 1742 } 1743 1744 return FALSE; 1745 } 1746 1747 static LRESULT 1748 TREEVIEW_GetItem(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode) 1749 { 1750 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1751 LPTVITEMEXW tvItem; 1752 TREEVIEW_ITEM *wineItem; 1753 INT iItem; 1754 1755 tvItem = (LPTVITEMEXW)lParam; 1756 iItem = (INT)tvItem->hItem; 1757 1758 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem); 1759 if (!wineItem) return FALSE; 1760 1761 if (tvItem->mask & TVIF_CHILDREN) 1762 tvItem->cChildren = TREEVIEW_HasChildren(hwnd, wineItem); 1763 1764 if (tvItem->mask & TVIF_HANDLE) 1765 tvItem->hItem = wineItem->hItem; 1766 1767 if (tvItem->mask & TVIF_IMAGE) 1768 { 1769 if (wineItem->iImage == I_IMAGECALLBACK) 1770 tvItem->iImage = TREEVIEW_CallbackImage(hwnd,wineItem); 1771 else 1772 tvItem->iImage = wineItem->iImage; 1773 } 1774 1775 if (tvItem->mask & TVIF_INTEGRAL) 1776 tvItem->iIntegral = wineItem->iIntegral; 1777 1778 // undocumented: windows ignores TVIF_PARAM and 1779 // always sets lParam 1780 tvItem->lParam = wineItem->lParam; 1781 1782 if (tvItem->mask & TVIF_SELECTEDIMAGE) 1783 { 1784 if (wineItem->iSelectedImage == I_IMAGECALLBACK) 1785 tvItem->iSelectedImage = TREEVIEW_CallbackSelectedImage(hwnd,wineItem); 1786 else 1787 tvItem->iSelectedImage = wineItem->iSelectedImage; 1788 } 1789 1790 if (tvItem->mask & TVIF_STATE) 1791 tvItem->state = wineItem->state & tvItem->stateMask; 1792 1793 if (tvItem->mask & TVIF_TEXT) 1794 { 1795 WCHAR* text; 1796 BOOL mustFree = FALSE; 1797 1798 if (wineItem->pszText == LPSTR_TEXTCALLBACKW) 1799 text = TREEVIEW_CallbackText(hwnd,wineItem,&mustFree); 1800 else 1801 text = wineItem->pszText; 1802 1803 if (unicode) 1804 lstrcpynW(tvItem->pszText,text,tvItem->cchTextMax); 1805 else 1806 lstrcpynWtoA((LPSTR)tvItem->pszText,text,tvItem->cchTextMax); 1807 if (mustFree) COMCTL32_Free(text); 1808 } 1809 1810 return TRUE; 1811 } 1812 1813 1814 1815 /* FIXME: check implementation of TVGN_NEXT/TVGN_NEXTVISIBLE */ 1816 1817 static LRESULT 1818 TREEVIEW_GetNextItem (HWND hwnd, WPARAM wParam, LPARAM lParam) 1819 1820 { 1821 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1822 TREEVIEW_ITEM *wineItem, *returnItem; 1823 INT iItem, retval, flag; 1824 1825 flag = (INT) wParam; 1826 iItem = (INT) lParam; 1827 retval = 0; 1828 switch (flag) 1829 { 1830 case TVGN_CHILD: /* Special case: child of 0 is root */ 1831 if (iItem) break; 1832 1833 case TVGN_ROOT: 1834 retval = (INT)infoPtr->TopRootItem; 1835 break; 1836 1837 case TVGN_CARET: 1838 retval = (INT)infoPtr->selectedItem; 1839 break; 1840 1841 case TVGN_FIRSTVISIBLE: 1842 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 1843 retval = (INT)infoPtr->firstVisible; 1844 break; 1845 1846 case TVGN_DROPHILITE: 1847 retval = (INT)infoPtr->dropItem; 1848 break; 1849 } 1850 1851 if (retval) return retval; 1852 1853 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem); 1854 returnItem = NULL; 1855 if (!wineItem) return FALSE; 1856 1857 switch (flag) 1858 { 1859 case TVGN_NEXT: 1860 retval = (INT)wineItem->sibling; 1861 break; 1862 1863 case TVGN_PREVIOUS: 1864 retval = (INT)wineItem->upsibling; 1865 break; 1866 1867 case TVGN_PARENT: 1868 retval = (INT)wineItem->parent; 1869 break; 1870 1871 case TVGN_CHILD: 1872 retval = (INT)wineItem->firstChild; 1873 break; 1874 1875 case TVGN_LASTVISIBLE: 1876 returnItem = TREEVIEW_GetLastListItem (hwnd,infoPtr,wineItem); 1877 break; 1878 1879 case TVGN_NEXTVISIBLE: 1880 returnItem = TREEVIEW_GetNextListItem (hwnd,infoPtr,wineItem); 1881 break; 1882 1883 case TVGN_PREVIOUSVISIBLE: 1884 returnItem = TREEVIEW_GetPrevListItem (hwnd,infoPtr, wineItem); 1885 break; 1886 1887 default: 1888 break; 1889 } 1890 1891 if (returnItem) return (INT)returnItem->hItem; 1892 1893 return retval; 1894 } 1895 1896 1897 static LRESULT 1898 TREEVIEW_GetCount (HWND hwnd, WPARAM wParam, LPARAM lParam) 1899 { 1900 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 1901 1902 return (LRESULT) infoPtr->uNumItems; 1903 } 1904 1905 /*************************************************************************** 1906 * This method does the chaining of the insertion of a treeview item 1907 * before an item. 1908 * If parent is NULL, we're inserting at the root of the list. 1909 */ 1910 static void TREEVIEW_InsertBefore( 1911 TREEVIEW_INFO *infoPtr, 1912 TREEVIEW_ITEM *newItem, 1913 TREEVIEW_ITEM *sibling, 1914 TREEVIEW_ITEM *parent) 1915 { 1916 HTREEITEM siblingHandle = 0; 1917 HTREEITEM upSiblingHandle = 0; 1918 TREEVIEW_ITEM *upSibling = NULL; 1919 1920 // if (newItem == NULL) 1921 // ERR(treeview, "NULL newItem, impossible condition\n"); 1922 1923 // if (parent == NULL) 1924 // ERR(treeview, "NULL parent, impossible condition\n"); 1925 1926 if (sibling != NULL) /* Insert before this sibling for this parent */ 1927 { 1928 /* Store the new item sibling up sibling and sibling tem handle */ 1929 siblingHandle = sibling->hItem; 1930 upSiblingHandle = sibling->upsibling; 1931 /* As well as a pointer to the upsibling sibling object */ 1932 if ( (INT)sibling->upsibling != 0 ) 1933 upSibling = &infoPtr->items[(INT)sibling->upsibling]; 1934 1935 /* Adjust the sibling pointer */ 1936 sibling->upsibling = newItem->hItem; 1937 1938 /* Adjust the new item pointers */ 1939 newItem->upsibling = upSiblingHandle; 1940 newItem->sibling = siblingHandle; 1941 1942 /* Adjust the up sibling pointer */ 1943 if ( upSibling != NULL ) 1944 upSibling->sibling = newItem->hItem; 1945 else 1946 if (parent) 1947 /* this item is the first child of this parent, adjust parent pointers */ 1948 parent->firstChild = newItem->hItem; 1949 else infoPtr->TopRootItem = newItem->hItem; 1950 } 1951 else /* Insert as first child of this parent */ 1952 if (parent) 1953 parent->firstChild = newItem->hItem; 1954 } 1955 1956 /*************************************************************************** 1957 * This method does the chaining of the insertion of a treeview item 1958 * If parent is NULL, we're inserting at the root of the list. 1959 * after an item. 1960 */ 1961 static void TREEVIEW_InsertAfter( 1962 TREEVIEW_INFO *infoPtr, 1963 TREEVIEW_ITEM *newItem, 1964 TREEVIEW_ITEM *upSibling, 1965 TREEVIEW_ITEM *parent) 1966 { 1967 HTREEITEM upSiblingHandle = 0; 1968 HTREEITEM siblingHandle = 0; 1969 TREEVIEW_ITEM *sibling = NULL; 1970 1971 // if (newItem == NULL) 1972 // ERR(treeview, "NULL newItem, impossible condition\n"); 1973 1974 // if (parent == NULL) 1975 // ERR(treeview, "NULL parent, impossible condition\n"); 1976 1977 if (upSibling != NULL) /* Insert after this upsibling for this parent */ 1978 { 1979 /* Store the new item up sibling and sibling item handle */ 1980 upSiblingHandle = upSibling->hItem; 1981 siblingHandle = upSibling->sibling; 1982 /* As well as a pointer to the upsibling sibling object */ 1983 if ( (INT)upSibling->sibling != 0 ) 1984 sibling = &infoPtr->items[(INT)upSibling->sibling]; 1985 1986 /* Adjust the up sibling pointer */ 1987 upSibling->sibling = newItem->hItem; 1988 1989 /* Adjust the new item pointers */ 1990 newItem->upsibling = upSiblingHandle; 1991 newItem->sibling = siblingHandle; 1992 1993 /* Adjust the sibling pointer */ 1994 if ( sibling != NULL ) 1995 sibling->upsibling = newItem->hItem; 1996 /* 1997 else 1998 newItem is the last of the level, nothing else to do 1999 */ 2000 } 2001 else /* Insert as first child of this parent */ 2002 if (parent) 2003 parent->firstChild = newItem->hItem; 2004 } 2376 /* Sorting **************************************************************/ 2005 2377 2006 2378 /*************************************************************************** 2007 2379 * Forward the DPA local callback to the treeview owner callback 2008 2380 */ 2009 static INT WINAPI TREEVIEW_CallBackCompare(LPVOID first,LPVOID second,LPARAM tvInfoPtr) 2010 { 2011 /* Forward the call to the client define callback */ 2012 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr((HWND)tvInfoPtr); 2013 2014 return (infoPtr->pCallBackSort->lpfnCompare)( 2015 ((TREEVIEW_ITEM*)first)->lParam, 2016 ((TREEVIEW_ITEM*)second)->lParam, 2017 infoPtr->pCallBackSort->lParam); 2381 static INT WINAPI 2382 TREEVIEW_CallBackCompare(LPVOID pvFirst, LPVOID pvSecond, LPARAM callback) 2383 { 2384 LPTVSORTCB pCallBackSort = (LPTVSORTCB)callback; 2385 2386 TREEVIEW_ITEM *first = (TREEVIEW_ITEM *)pvFirst; 2387 TREEVIEW_ITEM *second = (TREEVIEW_ITEM *)pvSecond; 2388 2389 /* Forward the call to the client-defined callback */ 2390 return pCallBackSort->lpfnCompare(first->lParam, 2391 second->lParam, 2392 pCallBackSort->lParam); 2018 2393 } 2019 2394 … … 2021 2396 * Treeview native sort routine: sort on item text. 2022 2397 */ 2023 static INT WINAPI TREEVIEW_SortOnName(LPVOID first,LPVOID second,LPARAM tvInfoPtr) 2024 { 2025 HWND hwnd = (HWND)tvInfoPtr; 2026 WCHAR *txt1,*txt2; 2027 TREEVIEW_ITEM *item; 2028 INT res; 2029 BOOL mustFree1 = FALSE,mustFree2 = FALSE; 2030 2031 item = (TREEVIEW_ITEM*)first; 2032 if (item->pszText == LPSTR_TEXTCALLBACKW) 2033 txt1 = TREEVIEW_CallbackText(hwnd,item,&mustFree1); 2034 else 2035 txt1 = item->pszText; 2036 2037 item = (TREEVIEW_ITEM*)second; 2038 if (item->pszText == LPSTR_TEXTCALLBACKW) 2039 txt2 = TREEVIEW_CallbackText(hwnd,item,&mustFree2); 2040 else 2041 txt2 = item->pszText; 2042 2043 res = lstrcmpiW(txt1,txt2); //CB: or lstrcmpW? 2044 if (mustFree1) COMCTL32_Free(txt1); 2045 if (mustFree2) COMCTL32_Free(txt2); 2046 2047 return res; 2398 static INT WINAPI 2399 TREEVIEW_SortOnName(LPVOID pvFirst, LPVOID pvSecond, LPARAM tvInfoPtr) 2400 { 2401 TREEVIEW_INFO *infoPtr = (TREEVIEW_INFO *)tvInfoPtr; 2402 2403 TREEVIEW_ITEM *first = (TREEVIEW_ITEM *)pvFirst; 2404 TREEVIEW_ITEM *second = (TREEVIEW_ITEM *)pvSecond; 2405 2406 TREEVIEW_UpdateDispInfo(infoPtr, first, TVIF_TEXT); 2407 TREEVIEW_UpdateDispInfo(infoPtr, second, TVIF_TEXT); 2408 2409 return lstrcmpiW(first->pszText, second->pszText); 2410 } 2411 2412 /* Returns the number of physical children belonging to item. */ 2413 static INT 2414 TREEVIEW_CountChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 2415 { 2416 INT cChildren = 0; 2417 HTREEITEM hti; 2418 2419 for (hti = item->firstChild; hti != NULL; hti = hti->nextSibling) 2420 cChildren++; 2421 2422 return cChildren; 2423 } 2424 2425 /* Returns a DPA containing a pointer to each physical child of item in 2426 * sibling order. If item has no children, an empty DPA is returned. */ 2427 static HDPA 2428 TREEVIEW_BuildChildDPA(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 2429 { 2430 HTREEITEM child = item->firstChild; 2431 2432 HDPA list = DPA_Create(8); 2433 if (list == 0) return NULL; 2434 2435 for (child = item->firstChild; child != NULL; child = child->nextSibling) 2436 { 2437 if (DPA_InsertPtr(list, INT_MAX, child) == -1) 2438 { 2439 DPA_Destroy(list); 2440 return NULL; 2441 } 2442 } 2443 2444 return list; 2048 2445 } 2049 2446 … … 2059 2456 */ 2060 2457 2061 static LRESULT WINAPI TREEVIEW_Sort(HWND hwnd,BOOL fRecurse,HTREEITEM parent,LPTVSORTCB pSort) 2062 { 2063 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2064 TREEVIEW_ITEM *sortMe = NULL; /* Node for which we sort the children */ 2065 INT cChildren; 2066 HTREEITEM hti; 2067 BOOL root = FALSE; 2068 2069 /* Obtain the TVSORTBC struct */ 2070 infoPtr->pCallBackSort = pSort; 2071 2072 /* undocumented feature: TVI_ROOT means `sort the whole tree' */ 2073 2074 if ((parent == TVI_ROOT) || (parent == 0)) 2075 { 2076 root = TRUE; 2077 parent = infoPtr->TopRootItem; 2078 } 2079 2080 /* Check for a valid handle to the parent item */ 2081 sortMe = TREEVIEW_ValidItem(infoPtr,parent); 2082 if (!sortMe) 2458 static LRESULT 2459 TREEVIEW_Sort(TREEVIEW_INFO *infoPtr, BOOL fRecurse, HTREEITEM parent, 2460 LPTVSORTCB pSort) 2461 { 2462 INT cChildren; 2463 PFNDPACOMPARE pfnCompare; 2464 LPARAM lpCompare; 2465 BOOL root = FALSE; 2466 2467 /* undocumented feature: TVI_ROOT means `sort the whole tree' */ 2468 if ((parent == TVI_ROOT) || (parent == 0)) 2469 { 2470 root = TRUE; 2471 parent = infoPtr->root; 2472 } 2473 2474 /* Check for a valid handle to the parent item */ 2475 if (!TREEVIEW_ValidItem(infoPtr, parent)) 2476 { 2477 //ERR("invalid item hParent=%x\n", (INT)parent); 2478 return FALSE; 2479 } 2480 2481 if (pSort) 2482 { 2483 pfnCompare = TREEVIEW_CallBackCompare; 2484 lpCompare = (LPARAM)pSort; 2485 } 2486 else 2487 { 2488 pfnCompare = TREEVIEW_SortOnName; 2489 lpCompare = (LPARAM)infoPtr; 2490 } 2491 2492 cChildren = TREEVIEW_CountChildren(infoPtr,parent); 2493 2494 /* Make sure there is something to sort */ 2495 if (cChildren > 1) 2496 { 2497 /* TREEVIEW_ITEM rechaining */ 2498 INT count = 0; 2499 HTREEITEM item = 0; 2500 HTREEITEM nextItem = 0; 2501 HTREEITEM prevItem = 0; 2502 2503 HDPA sortList = TREEVIEW_BuildChildDPA(infoPtr, parent); 2504 2505 if (sortList == NULL) 2506 return FALSE; 2507 2508 /* let DPA sort the list */ 2509 DPA_Sort(sortList, pfnCompare, lpCompare); 2510 2511 /* The order of DPA entries has been changed, so fixup the 2512 * nextSibling and prevSibling pointers. */ 2513 2514 item = (HTREEITEM)DPA_GetPtr(sortList, count++); 2515 while ((nextItem = (HTREEITEM)DPA_GetPtr(sortList, count++)) != NULL) 2516 { 2517 /* link the two current item toghether */ 2518 item->nextSibling = nextItem; 2519 nextItem->prevSibling = item; 2520 2521 if (prevItem == NULL) 2522 { 2523 /* this is the first item, update the parent */ 2524 parent->firstChild = item; 2525 item->prevSibling = NULL; 2526 } 2527 else 2528 { 2529 /* fix the back chaining */ 2530 item->prevSibling = prevItem; 2531 } 2532 2533 /* get ready for the next one */ 2534 prevItem = item; 2535 item = nextItem; 2536 } 2537 2538 /* the last item is pointed to by item and never has a sibling */ 2539 item->nextSibling = NULL; 2540 parent->lastChild = item; 2541 2542 DPA_Destroy(sortList); 2543 2544 TREEVIEW_VerifyTree(infoPtr); 2545 2546 TREEVIEW_QueueRefresh(infoPtr); 2547 2548 return TRUE; 2549 } 2083 2550 return FALSE; 2084 2085 cChildren = 0;2086 for(hti = root ? sortMe->hItem:sortMe->firstChild; hti; hti = infoPtr->items[(INT)hti].sibling)2087 cChildren++;2088 2089 /* Make sure there is something to sort */2090 if (cChildren > 1)2091 {2092 /* pointer organization */2093 HDPA sortList = DPA_Create(cChildren);2094 HTREEITEM itemHandle = root ? sortMe->hItem:sortMe->firstChild;2095 TREEVIEW_ITEM *itemPtr = &infoPtr->items[(INT)itemHandle];2096 2097 /* TREEVIEW_ITEM rechaining */2098 INT count = 0;2099 VOID *item = 0;2100 VOID *nextItem = 0;2101 VOID *prevItem = 0;2102 2103 /* Build the list of item to sort */2104 do2105 {2106 itemPtr = &infoPtr->items[(INT)itemHandle];2107 DPA_InsertPtr(2108 sortList, /* the list */2109 cChildren+1, /* force the insertion to be an append */2110 itemPtr); /* the ptr to store */2111 2112 /* Get the next sibling */2113 itemHandle = itemPtr->sibling;2114 } while (itemHandle != NULL);2115 2116 /* let DPA perform the sort activity */2117 if (pSort)2118 DPA_Sort(2119 sortList, /* what */2120 TREEVIEW_CallBackCompare, /* how */2121 hwnd); /* owner */2122 else2123 DPA_Sort (2124 sortList, /* what */2125 TREEVIEW_SortOnName, /* how */2126 hwnd); /* owner */2127 2128 /*2129 * Reorganized TREEVIEW_ITEM structures.2130 * Note that we know we have at least two elements.2131 */2132 2133 /* Get the first item and get ready to start... */2134 item = DPA_GetPtr(sortList, count++);2135 while ((nextItem = DPA_GetPtr(sortList, count++)) != NULL)2136 {2137 /* link the two current item toghether */2138 ((TREEVIEW_ITEM*)item)->sibling = ((TREEVIEW_ITEM*)nextItem)->hItem;2139 ((TREEVIEW_ITEM*)nextItem)->upsibling = ((TREEVIEW_ITEM*)item)->hItem;2140 2141 if (prevItem == NULL) /* this is the first item, update the parent */2142 {2143 if (root)2144 infoPtr->TopRootItem = ((TREEVIEW_ITEM*)item)->hItem;2145 else2146 sortMe->firstChild = ((TREEVIEW_ITEM*)item)->hItem;2147 ((TREEVIEW_ITEM*)item)->upsibling = NULL;2148 }2149 else /* fix the back chaining */2150 {2151 ((TREEVIEW_ITEM*)item)->upsibling = ((TREEVIEW_ITEM*)prevItem)->hItem;2152 }2153 2154 /* get ready for the next one */2155 prevItem = item;2156 item = nextItem;2157 }2158 2159 /* the last item is pointed to by item and never has a sibling */2160 ((TREEVIEW_ITEM*)item)->sibling = NULL;2161 2162 DPA_Destroy(sortList);2163 TREEVIEW_QueueRefresh(hwnd);2164 2165 return TRUE;2166 }2167 return FALSE;2168 2551 } 2169 2552 … … 2172 2555 * and sort the children of the TV item specified in lParam 2173 2556 */ 2174 static LRESULT WINAPI TREEVIEW_SortChildrenCB(HWND hwnd,WPARAM wParam,LPARAM lParam) 2175 { 2176 LPTVSORTCB pSort = (LPTVSORTCB) lParam; 2177 2178 return TREEVIEW_Sort (hwnd, wParam, pSort->hParent, pSort); 2557 static LRESULT 2558 TREEVIEW_SortChildrenCB(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 2559 { 2560 LPTVSORTCB pSort = (LPTVSORTCB)lParam; 2561 2562 return TREEVIEW_Sort(infoPtr, wParam, pSort->hParent, pSort); 2179 2563 } 2180 2564 … … 2183 2567 * Sort the children of the TV item specified in lParam. 2184 2568 */ 2185 static LRESULT WINAPI TREEVIEW_SortChildren(HWND hwnd,WPARAM wParam,LPARAM lParam) 2186 { 2187 return TREEVIEW_Sort (hwnd, (BOOL) wParam, (HTREEITEM) lParam, NULL); 2188 } 2189 2190 2191 int ffs(int mask) 2192 { 2193 int bit; 2194 2195 if (mask == 0) 2196 return(0); 2197 for (bit = 1; !(mask & 1); bit++) 2198 mask >>= 1; 2199 return(bit); 2200 } 2201 2202 /* the method used below isn't the most memory-friendly, but it avoids 2203 a lot of memory reallocations */ 2204 2205 /* BTW: we waste handle 0; 0 is not an allowed handle. */ 2206 2207 static LRESULT 2208 TREEVIEW_InsertItem(HWND hwnd,WPARAM wParam,LPARAM lParam,BOOL unicode) 2209 { 2210 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2211 TVINSERTSTRUCTW *ptdi; 2212 TVITEMEXW *tvItem; 2213 TREEVIEW_ITEM *wineItem, *parentItem, *prevsib, *sibItem; 2214 INT iItem,i,len; 2215 2216 if (infoPtr->hwndEdit) SetFocus(hwnd); 2217 2218 /* Item to insert */ 2219 ptdi = (LPTVINSERTSTRUCTW)lParam; 2220 2221 /* check if memory is available */ 2222 2223 if (infoPtr->uNumPtrsAlloced==0) { 2224 infoPtr->items = (TREEVIEW_ITEM*)COMCTL32_Alloc (TVITEM_ALLOC*sizeof (TREEVIEW_ITEM)); 2225 infoPtr->freeList= (INT*)COMCTL32_Alloc (((TVITEM_ALLOC>>5)) * sizeof (INT)); 2226 infoPtr->uNumPtrsAlloced=TVITEM_ALLOC; 2227 infoPtr->TopRootItem=(HTREEITEM)1; 2228 } 2229 2230 /* 2231 * Reallocate contiguous space for items 2232 */ 2233 if (infoPtr->uNumItems == (infoPtr->uNumPtrsAlloced-1) ) { 2234 TREEVIEW_ITEM *oldItems = infoPtr->items; 2235 INT *oldfreeList = infoPtr->freeList; 2236 2237 infoPtr->uNumPtrsAlloced*=2; 2238 infoPtr->items = (TREEVIEW_ITEM*)COMCTL32_Alloc (infoPtr->uNumPtrsAlloced*sizeof (TREEVIEW_ITEM)); 2239 infoPtr->freeList= (INT*)COMCTL32_Alloc (((infoPtr->uNumPtrsAlloced>>5))*sizeof (INT)); 2240 2241 memcpy (&infoPtr->items[0], &oldItems[0], 2242 infoPtr->uNumPtrsAlloced/2 * sizeof(TREEVIEW_ITEM)); 2243 memcpy (&infoPtr->freeList[0], &oldfreeList[0], 2244 (infoPtr->uNumPtrsAlloced>>6) * sizeof(INT)); 2245 2246 COMCTL32_Free (oldItems); 2247 COMCTL32_Free (oldfreeList); 2248 } 2249 2250 /* 2251 * Reset infoPtr structure with new stat according to current TV picture 2252 */ 2253 iItem=0; 2254 infoPtr->uNumItems++; 2255 if ((INT)infoPtr->uMaxHandle==(infoPtr->uNumItems-1)) { 2256 iItem=infoPtr->uNumItems; 2257 infoPtr->uMaxHandle = (HTREEITEM)((INT)infoPtr->uMaxHandle + 1); 2258 } else { /* check freelist */ 2259 for (i=0; i<infoPtr->uNumPtrsAlloced>>5; i++) { 2260 if (infoPtr->freeList[i]) { 2261 for(iItem = 0; iItem < 32; iItem++) 2262 { 2263 if(tv_test_bit(iItem, &infoPtr->freeList[i])) 2264 break; 2265 } 2266 tv_clear_bit(iItem,&infoPtr->freeList[i]); 2267 iItem+=i<<5; 2268 break; 2269 } 2270 } 2271 } 2272 2273 /* 2274 * Find the parent item of the new item 2275 */ 2276 tvItem = &ptdi->itemex; 2277 wineItem = &infoPtr->items[iItem]; 2278 2279 if ((ptdi->hParent==TVI_ROOT) || (ptdi->hParent==0)) { 2280 parentItem = NULL; 2281 wineItem->parent = 0; 2282 sibItem = &infoPtr->items [(INT)infoPtr->TopRootItem]; 2283 } 2284 else { 2285 parentItem = &infoPtr->items[(INT)ptdi->hParent]; 2286 2287 /* Do the insertion here it if it's the only item of this parent */ 2288 if (!parentItem->firstChild) 2289 parentItem->firstChild=(HTREEITEM)iItem; 2290 2291 wineItem->parent = ptdi->hParent; 2292 sibItem = &infoPtr->items [(INT)parentItem->firstChild]; 2293 } 2294 2295 2296 /* NOTE: I am moving some setup of the wineItem object that was initialy 2297 * done at the end of the function since some of the values are 2298 * required by the Callback sorting 2299 */ 2300 2301 if (tvItem->mask & TVIF_TEXT) 2302 { 2303 /* 2304 * Setup the item text stuff here since it's required by the Sort method 2305 * when the insertion are ordered 2306 */ 2307 if (unicode) 2308 { 2309 if (tvItem->pszText != LPSTR_TEXTCALLBACKW) 2569 static LRESULT 2570 TREEVIEW_SortChildren(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 2571 { 2572 return TREEVIEW_Sort(infoPtr, (BOOL)wParam, (HTREEITEM)lParam, NULL); 2573 } 2574 2575 2576 /* Expansion/Collapse ***************************************************/ 2577 2578 static BOOL 2579 TREEVIEW_SendExpanding(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 2580 UINT action) 2581 { 2582 return !TREEVIEW_SendTreeviewNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_ITEMEXPANDINGW:TVN_ITEMEXPANDINGA, action, 2583 TVIF_HANDLE | TVIF_STATE | TVIF_PARAM 2584 | TVIF_IMAGE | TVIF_SELECTEDIMAGE, 2585 0, wineItem); 2586 } 2587 2588 static VOID 2589 TREEVIEW_SendExpanded(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 2590 UINT action) 2591 { 2592 TREEVIEW_SendTreeviewNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_ITEMEXPANDEDW:TVN_ITEMEXPANDEDA, action, 2593 TVIF_HANDLE | TVIF_STATE | TVIF_PARAM 2594 | TVIF_IMAGE | TVIF_SELECTEDIMAGE, 2595 0, wineItem); 2596 } 2597 2598 2599 /* This corresponds to TVM_EXPAND with TVE_COLLAPSE. 2600 * bRemoveChildren corresponds to TVE_COLLAPSERESET. */ 2601 static BOOL 2602 TREEVIEW_Collapse(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 2603 BOOL bRemoveChildren, BOOL bUser) 2604 { 2605 UINT action = TVE_COLLAPSE | (bRemoveChildren ? TVE_COLLAPSERESET : 0); 2606 BOOL bSetSelection, bSetFirstVisible; 2607 2608 //TRACE("TVE_COLLAPSE %p %s\n", wineItem, TREEVIEW_ItemName(wineItem)); 2609 2610 if (!(wineItem->state & TVIS_EXPANDED) || wineItem->firstChild == NULL) 2611 return FALSE; 2612 2613 if (bUser) 2614 TREEVIEW_SendExpanding(infoPtr, wineItem, action); 2615 2616 wineItem->state &= ~TVIS_EXPANDED; 2617 2618 if (bUser) 2619 TREEVIEW_SendExpanded(infoPtr, wineItem, action); 2620 2621 bSetSelection = (infoPtr->selectedItem != NULL 2622 && TREEVIEW_IsChildOf(wineItem, infoPtr->selectedItem)); 2623 2624 if (TREEVIEW_IsChildOf(wineItem,infoPtr->firstVisible)) 2625 { 2626 infoPtr->lefttop.y += wineItem->rect.top; 2627 } 2628 2629 if (bRemoveChildren) 2630 { 2631 //TRACE("TVE_COLLAPSERESET\n"); 2632 wineItem->state &= ~TVIS_EXPANDEDONCE; 2633 TREEVIEW_RemoveAllChildren(infoPtr, wineItem); 2634 } 2635 2636 //update window 2637 //CB: todo: optimize! 2638 TREEVIEW_UnqueueRefresh(infoPtr,FALSE,FALSE); 2639 //CB: todo: precalc expanded items here 2640 TREEVIEW_CalcItems(infoPtr); 2641 TREEVIEW_Refresh(infoPtr); 2642 2643 if (bSetSelection) 2644 { 2645 /* Don't call DoSelectItem, it sends notifications. */ 2646 if (infoPtr->selectedItem) 2647 infoPtr->selectedItem->state &= ~TVIS_SELECTED; 2648 wineItem->state |= TVIS_SELECTED; 2649 infoPtr->selectedItem = wineItem; 2650 2651 TREEVIEW_EnsureVisible(infoPtr, wineItem); 2652 } 2653 2654 return TRUE; 2655 } 2656 2657 static BOOL 2658 TREEVIEW_Expand(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, 2659 BOOL bExpandPartial, BOOL bUser) 2660 { 2661 //TRACE("TVE_EXPAND\n"); 2662 2663 if (!TREEVIEW_HasChildren(infoPtr, wineItem) 2664 || (wineItem->state & TVIS_EXPANDED)) 2665 return FALSE; 2666 2667 //TRACE(" is not expanded...\n"); 2668 2669 if (bUser || !(wineItem->state & TVIS_EXPANDEDONCE)) 2670 { 2671 //TRACE(" and has never been expanded...\n"); 2672 2673 if (bExpandPartial) 2674 { 2675 return FALSE; //CB: how does this work??? (only display one level? nonsense in MSDN docu) 2676 wineItem->state ^=TVIS_EXPANDED; 2677 wineItem->state |=TVIS_EXPANDEDONCE; 2678 } 2679 2680 wineItem->state |= TVIS_EXPANDED; 2681 //TRACE(" TVN_ITEMEXPANDING sent...\n"); 2682 2683 if (!TREEVIEW_SendExpanding(infoPtr, wineItem, TVE_EXPAND)) 2684 { 2685 //TRACE(" TVN_ITEMEXPANDING returned TRUE, exiting...\n"); 2686 return FALSE; 2687 } 2688 2689 wineItem->state |= TVIS_EXPANDEDONCE; 2690 2691 TREEVIEW_SendExpanded(infoPtr, wineItem, TVE_EXPAND); 2692 2693 //TRACE(" TVN_ITEMEXPANDED sent...\n"); 2694 } 2695 else 2696 { 2697 /* this item has already been expanded */ 2698 wineItem->state |= TVIS_EXPANDED; 2699 } 2700 2701 //if (bExpandPartial) 2702 // FIXME("TVE_EXPANDPARTIAL not implemented\n"); 2703 2704 //update window 2705 //CB: todo: optimize! 2706 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,FALSE); 2707 2708 /* Scroll up so that as many children as possible are visible. 2709 * This looses when expanding causes an HScroll bar to appear, but we 2710 * don't know that yet, so the last item is obscured. */ 2711 if (wineItem->firstChild && wineItem->inclient && (infoPtr->firstVisible != wineItem) && (wineItem->lastChild->rect.bottom > infoPtr->clientHeight)) 2712 { 2713 INT childrenH = wineItem->lastChild->rect.bottom-wineItem->firstChild->rect.top; 2714 INT itemH = wineItem->rect.bottom-wineItem->rect.top; 2715 INT clientH = ((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight; 2716 2717 if (itemH+childrenH > clientH) 2310 2718 { 2311 len = lstrlenW(tvItem->pszText)+1; 2312 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 2313 lstrcpyW (wineItem->pszText, tvItem->pszText); 2314 wineItem->cchTextMax = len; 2719 infoPtr->lefttop.y += wineItem->rect.top; 2315 2720 } else 2316 2721 { 2317 wineItem->pszText = LPSTR_TEXTCALLBACKW; 2318 wineItem->cchTextMax = 0; 2722 INT diff = wineItem->lastChild->rect.bottom-clientH; 2723 2724 infoPtr->lefttop.y += diff; 2319 2725 } 2320 } else 2321 { 2322 if ((LPSTR)tvItem->pszText != LPSTR_TEXTCALLBACKA) 2323 { 2324 len = lstrlenA((LPSTR)tvItem->pszText)+1; 2325 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 2326 lstrcpyAtoW (wineItem->pszText,(LPSTR)tvItem->pszText); 2327 wineItem->cchTextMax = len; 2328 } else 2329 { 2330 wineItem->pszText = LPSTR_TEXTCALLBACKW; 2331 wineItem->cchTextMax = 0; 2332 } 2333 } 2334 } 2335 2336 if (tvItem->mask & TVIF_PARAM) 2337 wineItem->lParam=tvItem->lParam; 2338 2339 2340 wineItem->upsibling=0; /* needed in case we're the first item in a list */ 2341 wineItem->sibling=0; 2342 wineItem->firstChild=0; 2343 wineItem->hItem=(HTREEITEM)iItem; 2344 2345 if (sibItem != wineItem) 2346 { 2347 prevsib=NULL; 2348 2349 if (ptdi->hInsertAfter == TVI_FIRST) 2350 { 2351 if (wineItem->parent) { 2352 wineItem->sibling=parentItem->firstChild; 2353 parentItem->firstChild=(HTREEITEM)iItem; 2354 } else { 2355 wineItem->sibling=infoPtr->TopRootItem; 2356 infoPtr->TopRootItem=(HTREEITEM)iItem; 2357 } 2358 sibItem->upsibling=(HTREEITEM)iItem; 2359 } else if (ptdi->hInsertAfter == TVI_SORT) 2360 { 2361 TREEVIEW_ITEM *aChild; 2362 TREEVIEW_ITEM *previousChild = NULL; 2363 BOOL bItemInserted = FALSE; 2364 WCHAR* text; 2365 BOOL mustFree = FALSE; 2366 2367 if (parentItem) 2368 aChild = &infoPtr->items[(INT)parentItem->firstChild]; 2369 else 2370 aChild = &infoPtr->items[(INT)infoPtr->TopRootItem]; 2371 2372 /* lookup the text if using LPSTR_TEXTCALLBACKs */ 2373 if (wineItem->pszText == LPSTR_TEXTCALLBACKW) 2374 text = TREEVIEW_CallbackText(hwnd,wineItem,&mustFree); 2375 else 2376 text = wineItem->pszText; 2377 2378 /* Iterate the parent children to see where we fit in */ 2379 while ( aChild != NULL ) 2380 { 2381 INT comp; 2382 WCHAR* text2; 2383 BOOL mustFree2 = FALSE; 2384 2385 /* lookup the text if using LPSTR_TEXTCALLBACKs */ 2386 if (aChild->pszText == LPSTR_TEXTCALLBACKW) 2387 text2 = TREEVIEW_CallbackText(hwnd,aChild,&mustFree2); 2388 else 2389 text2 = aChild->pszText; 2390 2391 comp = lstrcmpW(text,text2); 2392 if (mustFree2) COMCTL32_Free(text2); 2393 if ( comp < 0 ) /* we are smaller than the current one */ 2394 { 2395 TREEVIEW_InsertBefore(infoPtr, wineItem, aChild, parentItem); 2396 bItemInserted = TRUE; 2397 break; 2398 } 2399 else if ( comp > 0 ) /* we are bigger than the current one */ 2400 { 2401 previousChild = aChild; 2402 aChild = (aChild->sibling == 0) /* This will help us to exit */ 2403 ? NULL /* if there is no more sibling */ 2404 : &infoPtr->items[(INT)aChild->sibling]; 2405 2406 /* Look at the next item */ 2407 continue; 2408 } 2409 else if ( comp == 0 ) 2410 { 2411 /* 2412 * An item with this name is already existing, therefore, 2413 * we add after the one we found 2414 */ 2415 TREEVIEW_InsertAfter(infoPtr, wineItem, aChild, parentItem); 2416 bItemInserted = TRUE; 2417 break; 2418 } 2419 } 2420 if (mustFree) COMCTL32_Free(text); 2421 2422 /* 2423 * we reach the end of the child list and the item as not 2424 * yet been inserted, therefore, insert it after the last child. 2425 */ 2426 if ( (! bItemInserted ) && (aChild == NULL) ) 2427 TREEVIEW_InsertAfter(infoPtr, wineItem, previousChild, parentItem); 2428 } else if (ptdi->hInsertAfter == TVI_LAST) 2429 { 2430 TVI_LAST_CASE: 2431 while (sibItem->sibling) { 2432 prevsib=sibItem; 2433 sibItem=&infoPtr->items [(INT)sibItem->sibling]; 2434 } 2435 sibItem->sibling=(HTREEITEM)iItem; 2436 wineItem->upsibling=sibItem->hItem; 2437 } else 2438 { 2439 while ((sibItem->sibling) && (sibItem->hItem!=ptdi->hInsertAfter)) 2440 { 2441 prevsib=sibItem; 2442 sibItem=&infoPtr->items [(INT)sibItem->sibling]; 2443 } 2444 if (sibItem->hItem!=ptdi->hInsertAfter) { 2445 goto TVI_LAST_CASE; 2446 } 2447 prevsib=sibItem; 2448 if (sibItem->sibling) { 2449 sibItem=&infoPtr->items [(INT)sibItem->sibling]; 2450 sibItem->upsibling=(HTREEITEM)iItem; 2451 wineItem->sibling=sibItem->hItem; 2452 } 2453 prevsib->sibling=(HTREEITEM)iItem; 2454 wineItem->upsibling=prevsib->hItem; 2455 } 2456 } 2457 2458 /* Fill in info structure */ 2459 2460 wineItem->mask = tvItem->mask; 2461 wineItem->iIntegral = 1; 2462 2463 if (tvItem->mask & TVIF_CHILDREN) 2464 wineItem->cChildren=tvItem->cChildren; 2465 2466 wineItem->expandBox.left = 0; /* Initialize the expandBox */ 2467 wineItem->expandBox.top = 0; 2468 wineItem->expandBox.right = 0; 2469 wineItem->expandBox.bottom = 0; 2470 2471 if (tvItem->mask & TVIF_IMAGE) 2472 wineItem->iImage = tvItem->iImage; 2473 2474 /* If the application sets TVIF_INTEGRAL without 2475 supplying a TVITEMEX structure, it's toast */ 2476 2477 if (tvItem->mask & TVIF_INTEGRAL) 2478 wineItem->iIntegral = tvItem->iIntegral; 2479 2480 if (tvItem->mask & TVIF_SELECTEDIMAGE) 2481 wineItem->iSelectedImage = tvItem->iSelectedImage; 2482 2483 if (tvItem->mask & TVIF_STATE) 2484 { 2485 wineItem->state = tvItem->state; 2486 wineItem->stateMask = tvItem->stateMask; 2487 } 2488 2489 wineItem->calculated = FALSE; 2490 //TREEVIEW_Sort(hwnd,0,NULL,NULL); //CB: the Corel people do this, I think it's wrong 2491 TREEVIEW_QueueRefresh(hwnd); 2492 2493 return (LRESULT) iItem; 2494 } 2495 2496 2497 static LRESULT 2498 TREEVIEW_DeleteItem (HWND hwnd, WPARAM wParam, LPARAM lParam) 2499 { 2500 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2501 INT iItem; 2502 TREEVIEW_ITEM *wineItem; 2503 2504 if (lParam == (INT)TVI_ROOT) 2505 { 2506 TREEVIEW_RemoveTree (hwnd); 2507 } else 2508 { 2509 iItem = (INT)lParam; 2510 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)iItem); 2511 if (!wineItem) return FALSE; 2512 2513 TREEVIEW_RemoveItem (hwnd, wineItem); 2514 } 2515 2516 TREEVIEW_QueueRefresh(hwnd); 2517 2518 return TRUE; 2519 } 2520 2521 2522 2523 static LRESULT 2524 TREEVIEW_GetIndent (HWND hwnd) 2525 { 2526 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2527 2528 return infoPtr->uIndent; 2529 } 2530 2531 static LRESULT 2532 TREEVIEW_SetIndent (HWND hwnd, WPARAM wParam) 2533 { 2534 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2535 INT newIndent; 2536 2537 newIndent = (INT)wParam; 2538 if (newIndent < MINIMUM_INDENT) newIndent = MINIMUM_INDENT; 2539 if (newIndent != infoPtr->uIndent) 2540 { 2541 infoPtr->uIndent = newIndent; 2542 infoPtr->uInternalStatus |= TV_CALCALL; 2543 TREEVIEW_QueueRefresh(hwnd); 2544 } 2545 2546 return 0; 2547 } 2548 2549 static LRESULT 2550 TREEVIEW_GetToolTips (HWND hwnd) 2551 { 2552 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2553 2554 return infoPtr->hwndToolTip; 2555 } 2556 2557 2558 static LRESULT 2559 TREEVIEW_SetToolTips (HWND hwnd, WPARAM wParam) 2560 { 2561 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2562 HWND prevToolTip; 2563 2564 prevToolTip = infoPtr->hwndToolTip; 2565 infoPtr->hwndToolTip = (HWND)wParam; 2566 2567 return prevToolTip; 2568 } 2569 2570 2571 static LRESULT CALLBACK 2572 TREEVIEW_GetEditControl (HWND hwnd) 2573 { 2574 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2575 2576 return infoPtr->hwndEdit; 2577 } 2578 2579 2580 //@@@PH: Note - this SubclassProc is sometimes called with the 2581 // wrong window handle. Therefore, infoPtr points to anything 2582 // but the expected structure. 2583 LRESULT CALLBACK 2584 TREEVIEW_Edit_SubclassProc (HWND hwnd, UINT uMsg, WPARAM wParam, 2585 LPARAM lParam) 2586 { 2587 BOOL bCancel = FALSE; 2588 static BOOL bIgnoreKillFocus = FALSE; 2589 2590 switch (uMsg) 2591 { 2592 case WM_PAINT: 2593 { 2594 LRESULT rc; 2595 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2596 //TRACE("WM_PAINT start\n"); 2597 rc = CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam); 2598 //TRACE("WM_PAINT done\n"); 2599 return rc; 2600 } 2601 2602 case WM_KILLFOCUS: 2603 if(bIgnoreKillFocus) 2604 { 2605 return TRUE; 2606 } 2607 break; 2608 2609 case WM_GETDLGCODE: 2610 return DLGC_WANTARROWS | DLGC_WANTALLKEYS; 2611 2612 case WM_KEYDOWN: 2613 if (VK_ESCAPE == (INT)wParam) 2614 { 2615 bCancel = TRUE; 2616 break; 2617 } 2618 else if (VK_RETURN == (INT)wParam) 2619 { 2620 break; 2621 } 2622 2623 default: 2624 { 2625 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2626 2627 //@@@PH 1999/11/05 method called with freed infoPtr memory object 2628 if (infoPtr != NULL) 2629 return CallWindowProcA( infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam); 2630 else 2631 break; 2632 } 2633 } 2634 2635 /* Processing LVN_ENDLABELEDIT message could kill the focus */ 2636 /* eg. Using a messagebox */ 2637 bIgnoreKillFocus = TRUE; 2638 TREEVIEW_EndEditLabelNow(GetParent(hwnd), bCancel); 2639 bIgnoreKillFocus = FALSE; 2640 2641 return 0; 2642 } 2643 2644 /* should handle edit control messages here */ 2645 2646 static LRESULT 2647 TREEVIEW_Command (HWND hwnd, WPARAM wParam, LPARAM lParam) 2648 2649 { 2650 switch (HIWORD(wParam)) 2651 { 2652 case EN_UPDATE: 2653 { 2654 /* 2655 * Adjust the edit window size 2656 */ 2657 char buffer[1024]; 2658 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2659 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, infoPtr->editItem); 2660 HDC hdc = GetDC(infoPtr->hwndEdit); 2661 SIZE sz; 2662 int len; 2663 HFONT hFont, hOldFont=0; 2664 2665 len = GetWindowTextA(infoPtr->hwndEdit, buffer, 1024); 2666 2667 /* Select font to get the right dimension of the string */ 2668 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0); 2669 if(hFont != 0) 2670 { 2671 hOldFont = SelectObject(hdc, hFont); 2672 } 2673 2674 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz)) 2675 { 2676 TEXTMETRICA textMetric; 2677 /* Add Extra spacing for the next character */ 2678 GetTextMetricsA(hdc, &textMetric); 2679 sz.cx += (textMetric.tmMaxCharWidth * 2); 2680 2681 SetWindowPos ( 2682 infoPtr->hwndEdit, 2683 HWND_TOP, 2684 0, 2685 0, 2686 sz.cx, 2687 editItem->text.bottom - editItem->text.top + 3, 2688 SWP_NOMOVE|SWP_DRAWFRAME); 2689 } 2690 2691 if(hFont != 0) 2692 { 2693 SelectObject(hdc, hOldFont); 2694 } 2695 2696 ReleaseDC(hwnd, hdc); 2697 break; 2698 } 2699 2700 default: 2701 return SendMessageA (GetParent (hwnd), WM_COMMAND, wParam, lParam); 2702 } 2703 2704 return 0; 2705 } 2706 2707 static LRESULT TREEVIEW_Size (HWND hwnd, WPARAM wParam, LPARAM lParam) 2708 { 2709 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2710 2711 if (wParam == SIZE_RESTORED) 2712 if (TREEVIEW_CalcItems(hwnd,0,infoPtr)) 2713 TREEVIEW_Refresh(hwnd); 2714 2715 return TRUE; 2716 } 2717 2718 static LRESULT 2719 TREEVIEW_StyleChanged (HWND hwnd, WPARAM wParam, LPARAM lParam) 2720 { 2721 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2722 2723 if (infoPtr->hwndEdit) SetFocus(hwnd); 2724 2725 infoPtr->uInternalStatus |= TV_CALCALL; 2726 TREEVIEW_QueueRefresh(hwnd); 2727 2728 return 0; 2729 } 2730 2731 static LRESULT 2732 TREEVIEW_SysColorChange(HWND hwnd,WPARAM wParam,LPARAM lParam) 2733 { 2734 TREEVIEW_Refresh(hwnd); 2735 2736 return DefWindowProcA(hwnd,WM_SYSCOLORCHANGE,wParam,lParam); 2737 } 2738 2739 static LRESULT 2740 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) 2741 { 2742 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam; 2743 TREEVIEW_INFO *infoPtr; 2744 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE); 2745 LOGFONTA logFont; 2746 TEXTMETRICA tm; 2747 HDC hdc; 2748 2749 /* allocate memory for info structure */ 2750 infoPtr = (TREEVIEW_INFO*)initControl(hwnd,sizeof(TREEVIEW_INFO)); 2751 2752 if (!infoPtr) return 0; 2753 2754 hdc = GetDC(hwnd); 2755 2756 /* set default settings */ 2757 infoPtr->uInternalStatus = TV_CALCALL; 2758 infoPtr->uNumItems = 0; 2759 infoPtr->clrBk = GetSysColor (COLOR_WINDOW); 2760 infoPtr->clrLine = GetSysColor (COLOR_WINDOWTEXT); 2761 infoPtr->clrInsertMark = GetSysColor (COLOR_BTNTEXT); 2762 infoPtr->lefttop.y = 0; 2763 infoPtr->lefttop.x = 0; 2764 infoPtr->uIndent = 15; 2765 infoPtr->himlNormal = NULL; 2766 infoPtr->himlState = NULL; 2767 infoPtr->uItemHeight = -1; 2768 infoPtr->uRealItemHeight = 0; 2769 infoPtr->uVScrollStep = 1; 2770 infoPtr->uVisibleHeight = lpcs->cy; 2771 infoPtr->uTotalHeight = 0; 2772 infoPtr->uVisibleWidth = lpcs->cx; 2773 infoPtr->uTotalWidth = 0; 2774 2775 GetTextMetricsA (hdc, &tm); 2776 infoPtr->hFont = GetStockObject (DEFAULT_GUI_FONT); 2777 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont); 2778 logFont.lfWeight = FW_BOLD; 2779 infoPtr->hBoldFont = CreateFontIndirectA (&logFont); 2780 2781 infoPtr->items = NULL; 2782 infoPtr->selectedItem = 0; 2783 infoPtr->clrText = -1; /* use system color */ 2784 infoPtr->dropItem = 0; 2785 infoPtr->insertMarkItem = 0; 2786 infoPtr->insertBeforeorAfter = 0; 2787 infoPtr->pCallBackSort = NULL; 2788 infoPtr->uScrollTime = 300; /* milliseconds */ 2789 infoPtr->hwndEdit = 0; 2790 infoPtr->pszISearch = NULL; 2791 infoPtr->uISearchLen = 0; 2792 2793 infoPtr->tipItem = 0; 2794 infoPtr->hwndToolTip = 0; 2795 if (!(dwStyle & TVS_NOTOOLTIPS)) 2796 { 2797 infoPtr->hwndToolTip = createToolTip(hwnd,TTF_TRACK | TTF_ABSOLUTE | TTF_TRANSPARENT,TRUE); 2798 SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,0); 2799 } 2800 2801 if (dwStyle & TVS_CHECKBOXES) 2802 { 2803 HBITMAP hbmLoad; 2804 int nIndex; 2805 2806 infoPtr->himlState = ImageList_Create (16, 16,ILC_COLOR | ILC_MASK, 15, 1); 2807 2808 //MSDN docu says: uses DrawFrameControl but never believe what they write 2809 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK)); 2810 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT); 2811 DeleteObject (hbmLoad); 2812 } 2813 ReleaseDC (hwnd, hdc); 2814 2815 return 0; 2816 } 2817 2818 static LRESULT 2819 TREEVIEW_Destroy (HWND hwnd) 2820 { 2821 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2822 2823 TREEVIEW_RemoveTree (hwnd); 2824 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 2825 KillTimer (hwnd, TV_REFRESH_TIMER); 2826 destroyToolTip(infoPtr->hwndToolTip); 2827 2828 /* Restore original windproc so that we can free infoPtr */ 2829 if (infoPtr->hwndEdit) 2830 SetWindowLongA (infoPtr->hwndEdit, GWL_WNDPROC, (DWORD)infoPtr->wpEditOrig); 2831 2832 DeleteObject(infoPtr->hBoldFont); 2833 COMCTL32_Free(infoPtr->pszISearch); 2834 doneControl(hwnd); 2835 2836 return 0; 2837 } 2838 2839 2840 static LRESULT 2841 TREEVIEW_Paint (HWND hwnd, WPARAM wParam, LPARAM lParam) 2842 { 2843 HDC hdc = (HDC)wParam; 2844 2845 if (!hdc) 2846 { 2847 PAINTSTRUCT ps; 2848 2849 hdc = BeginPaint(hwnd,&ps); 2850 TREEVIEW_Draw(hwnd, hdc,&ps.rcPaint); 2851 EndPaint(hwnd,&ps); 2852 } else 2853 TREEVIEW_Draw(hwnd,hdc,NULL); 2854 2855 return 0; 2856 } 2857 2858 static LRESULT 2859 TREEVIEW_SetFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) 2860 { 2861 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2862 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 2863 2864 sendNotify(hwnd,NM_SETFOCUS); 2865 2866 if (!(dwStyle & TVS_SHOWSELALWAYS)) 2867 { 2868 if (infoPtr->selectedItem) 2869 TREEVIEW_RefreshItem(hwnd,TREEVIEW_ValidItem(infoPtr,infoPtr->selectedItem),FALSE); 2870 else if (infoPtr->firstVisible) 2871 TREEVIEW_DoSelectItem(hwnd,TVGN_CARET,infoPtr->firstVisible,TVC_UNKNOWN); 2872 } 2873 2874 return 0; 2875 } 2876 2877 static LRESULT 2878 TREEVIEW_KillFocus (HWND hwnd, WPARAM wParam, LPARAM lParam) 2879 { 2880 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2881 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 2882 2883 sendNotify(hwnd,NM_KILLFOCUS); 2884 2885 if (!(dwStyle & TVS_SHOWSELALWAYS) && infoPtr->selectedItem) 2886 TREEVIEW_RefreshItem(hwnd,TREEVIEW_ValidItem(infoPtr,infoPtr->selectedItem),FALSE); 2887 2888 return 0; 2889 } 2890 2891 static LRESULT TREEVIEW_Enable(HWND hwnd,WPARAM wParam,LPARAM lParam) 2892 { 2893 TREEVIEW_Refresh(hwnd); 2894 2895 return DefWindowProcA(hwnd,WM_ENABLE,wParam,lParam); 2896 } 2897 2898 static LRESULT 2899 TREEVIEW_EraseBackground (HWND hwnd, WPARAM wParam, LPARAM lParam) 2900 { 2901 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2902 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk); 2903 RECT rect; 2904 2905 GetClientRect (hwnd, &rect); 2906 FillRect ((HDC)wParam, &rect, hBrush); 2907 DeleteObject (hBrush); 2726 } 2727 2728 TREEVIEW_CalcItems(infoPtr); 2729 TREEVIEW_Refresh(infoPtr); 2730 //CB: todo: check cx and cy to fit ranges! 2908 2731 2909 2732 return TRUE; 2910 2733 } 2911 2734 2912 static LRESULT TREEVIEW_GetDlgCode(HWND hwnd,WPARAM wParam,LPARAM lParam)2913 {2914 return DLGC_WANTARROWS | DLGC_WANTCHARS;2915 }2916 2917 /* Notifications */2918 2919 2735 static BOOL 2920 TREEVIEW_SendTreeviewNotify (HWND hwnd,UINT code,UINT action,HTREEITEM oldItem,HTREEITEM newItem) 2921 { 2922 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2923 NMTREEVIEWW nmhdr; 2924 TREEVIEW_ITEM *wineItem; 2925 CHAR *oldText = NULL,*newText = NULL; 2926 BOOL rc; 2927 2928 ZeroMemory(&nmhdr,sizeof(NMTREEVIEWW)); 2929 2930 nmhdr.action = action; 2931 if (oldItem) 2932 { 2933 wineItem = &infoPtr->items[(INT)oldItem]; 2934 nmhdr.itemOld.mask = wineItem->mask; 2935 nmhdr.itemOld.hItem = wineItem->hItem; 2936 nmhdr.itemOld.state = wineItem->state; 2937 nmhdr.itemOld.stateMask = wineItem->stateMask; 2938 nmhdr.itemOld.iImage = wineItem->iImage; 2939 if (!isUnicodeNotify(&infoPtr->header)) 2940 { 2941 if (!wineItem->pszText || (wineItem->pszText == LPSTR_TEXTCALLBACKW)) nmhdr.itemOld.pszText = NULL; else 2942 { 2943 INT len = lstrlenW(wineItem->pszText)+1; 2944 2945 oldText = (CHAR*)COMCTL32_Alloc(len); 2946 lstrcpyWtoA(oldText,wineItem->pszText); 2947 nmhdr.itemOld.pszText = (WCHAR*)oldText; 2948 } 2949 } else nmhdr.itemOld.pszText = wineItem->pszText; 2950 nmhdr.itemOld.cchTextMax= wineItem->cchTextMax; 2951 nmhdr.itemOld.iImage = wineItem->iImage; 2952 nmhdr.itemOld.iSelectedImage = wineItem->iSelectedImage; 2953 nmhdr.itemOld.cChildren = wineItem->cChildren; 2954 nmhdr.itemOld.lParam = wineItem->lParam; 2955 } 2956 2957 if (newItem) 2958 { 2959 wineItem = &infoPtr->items[(INT)newItem]; 2960 nmhdr.itemNew.mask = wineItem->mask; 2961 nmhdr.itemNew.hItem = wineItem->hItem; 2962 nmhdr.itemNew.state = wineItem->state; 2963 nmhdr.itemNew.stateMask = wineItem->stateMask; 2964 nmhdr.itemNew.iImage = wineItem->iImage; 2965 if (!isUnicodeNotify(&infoPtr->header)) 2966 { 2967 if (!wineItem->pszText || (wineItem->pszText == LPSTR_TEXTCALLBACKW)) nmhdr.itemNew.pszText = NULL; else 2968 { 2969 INT len = lstrlenW(wineItem->pszText)+1; 2970 2971 newText = (CHAR*)COMCTL32_Alloc(len); 2972 lstrcpyWtoA(newText,wineItem->pszText); 2973 nmhdr.itemNew.pszText = (WCHAR*)newText; 2974 } 2975 } else nmhdr.itemNew.pszText = wineItem->pszText; 2976 nmhdr.itemNew.cchTextMax= wineItem->cchTextMax; 2977 nmhdr.itemNew.iImage = wineItem->iImage; 2978 nmhdr.itemNew.iSelectedImage = wineItem->iSelectedImage; 2979 nmhdr.itemNew.cChildren = wineItem->cChildren; 2980 nmhdr.itemNew.lParam = wineItem->lParam; 2981 } 2982 2983 nmhdr.ptDrag.x = 0; 2984 nmhdr.ptDrag.y = 0; 2985 2986 rc = (BOOL)sendNotify(hwnd,code,&nmhdr.hdr); 2987 2988 if (oldText) COMCTL32_Free(oldText); 2989 if (newText) COMCTL32_Free(newText); 2990 2991 return rc; 2992 } 2993 2994 static BOOL 2995 TREEVIEW_SendTreeviewDnDNotify (HWND hwnd, UINT code, HTREEITEM dragItem, 2996 POINT pt) 2997 { 2998 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2999 NMTREEVIEWA nmhdr; 3000 TREEVIEW_ITEM *wineItem; 3001 3002 nmhdr.action = 0; 3003 wineItem=& infoPtr->items[(INT)dragItem]; 3004 nmhdr.itemNew.mask = wineItem->mask; 3005 nmhdr.itemNew.hItem = wineItem->hItem; 3006 nmhdr.itemNew.state = wineItem->state; 3007 nmhdr.itemNew.lParam = wineItem->lParam; 3008 3009 nmhdr.ptDrag.x = pt.x; 3010 nmhdr.ptDrag.y = pt.y; 3011 3012 return (BOOL)sendNotify(hwnd,code,&nmhdr.hdr); 3013 3014 } 3015 3016 static INT TREEVIEW_CallbackImage(HWND hwnd,TREEVIEW_ITEM *wineItem) 3017 { 3018 NMTVDISPINFOW tvdi; 3019 BOOL retval; 3020 3021 tvdi.item.mask = TVIF_IMAGE; 3022 tvdi.item.hItem = wineItem->hItem; 3023 tvdi.item.state = wineItem->state; 3024 tvdi.item.lParam = wineItem->lParam; 3025 tvdi.item.iImage = 0; 3026 3027 retval = (BOOL)sendNotify(hwnd,isUnicodeNotify(hwnd) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&tvdi.hdr); 3028 3029 if (tvdi.item.mask & TVIF_DI_SETITEM) 3030 wineItem->iImage = tvdi.item.iImage; 3031 3032 return tvdi.item.iImage; 3033 } 3034 3035 static INT TREEVIEW_CallbackSelectedImage(HWND hwnd,TREEVIEW_ITEM *wineItem) 3036 { 3037 NMTVDISPINFOW tvdi; 3038 BOOL retval; 3039 3040 tvdi.item.mask = TVIF_SELECTEDIMAGE; 3041 tvdi.item.hItem = wineItem->hItem; 3042 tvdi.item.state = wineItem->state; 3043 tvdi.item.lParam = wineItem->lParam; 3044 tvdi.item.iSelectedImage = 0; 3045 3046 retval = (BOOL)sendNotify(hwnd,isUnicodeNotify(hwnd) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&tvdi.hdr); 3047 3048 if (tvdi.item.mask & TVIF_DI_SETITEM) 3049 wineItem->iSelectedImage = tvdi.item.iSelectedImage; 3050 3051 return tvdi.item.iSelectedImage; 3052 } 3053 3054 static WCHAR* TREEVIEW_CallbackText(HWND hwnd,TREEVIEW_ITEM *wineItem,BOOL *mustFree) 3055 { 3056 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3057 NMTVDISPINFOW tvdi; 3058 BOOL retval; 3059 WCHAR *buf; 3060 3061 tvdi.item.mask = TVIF_TEXT; 3062 tvdi.item.hItem = wineItem->hItem; 3063 tvdi.item.state = wineItem->state; 3064 tvdi.item.lParam = wineItem->lParam; 3065 tvdi.item.pszText = (WCHAR*)COMCTL32_Alloc(128*(isUnicodeNotify(&infoPtr->header) ? sizeof(WCHAR):sizeof(CHAR))); 3066 tvdi.item.cchTextMax = 128; 3067 buf = tvdi.item.pszText; 3068 3069 retval = (BOOL)sendNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&tvdi.hdr); 3070 3071 if (tvdi.item.pszText == LPSTR_TEXTCALLBACKW) 3072 { 3073 *mustFree = FALSE; 3074 return NULL; 3075 } 3076 3077 if (isUnicodeNotify(&infoPtr->header)) 3078 { 3079 if (tvdi.item.mask & TVIF_DI_SETITEM) 3080 { 3081 if (buf == tvdi.item.pszText) 3082 { 3083 wineItem->pszText = tvdi.item.pszText; 3084 wineItem->cchTextMax = 128; 3085 } else 3086 { //user-supplied buffer 3087 INT len = lstrlenW(tvdi.item.pszText); 3088 3089 COMCTL32_Free(buf); 3090 if (len > 0) 3091 { 3092 len++; 3093 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 3094 lstrcpyW(wineItem->pszText,tvdi.item.pszText); 3095 wineItem->cchTextMax = len; 3096 } else 3097 { 3098 wineItem->pszText = NULL; 3099 wineItem->cchTextMax = len; 3100 } 3101 } 3102 *mustFree = FALSE; 3103 return wineItem->pszText; 3104 } else 3105 { 3106 if (buf != tvdi.item.pszText) 3107 { 3108 COMCTL32_Free(buf); 3109 *mustFree = FALSE; 3110 } else *mustFree = TRUE; 3111 return tvdi.item.pszText; 3112 } 3113 } else 3114 { 3115 if (tvdi.item.mask & TVIF_DI_SETITEM) 3116 { 3117 if (buf == tvdi.item.pszText) 3118 { 3119 wineItem->cchTextMax = 128; 3120 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(128*sizeof(WCHAR)); 3121 lstrcpynAtoW(wineItem->pszText,(CHAR*)tvdi.item.pszText,wineItem->cchTextMax); 3122 COMCTL32_Free(buf); 3123 } else 3124 { //user-supplied buffer 3125 INT len = lstrlenA((CHAR*)tvdi.item.pszText); 3126 3127 COMCTL32_Free(buf); 3128 if (len > 0) 3129 { 3130 len++; 3131 wineItem->pszText = (WCHAR*)COMCTL32_Alloc(len*sizeof(WCHAR)); 3132 lstrcpyAtoW(wineItem->pszText,(CHAR*)tvdi.item.pszText); 3133 wineItem->cchTextMax = len; 3134 } else 3135 { 3136 wineItem->pszText = NULL; 3137 wineItem->cchTextMax = len; 3138 } 3139 } 3140 *mustFree = FALSE; 3141 return wineItem->pszText; 3142 } else 3143 { 3144 INT len = lstrlenA((LPSTR)tvdi.item.pszText); 3145 WCHAR* textW = (WCHAR*)COMCTL32_Alloc((len+1)*sizeof(WCHAR)); 3146 3147 lstrcpyAtoW(textW,(LPSTR)tvdi.item.pszText); 3148 COMCTL32_Free(buf); 3149 *mustFree = TRUE; 3150 return textW; 3151 } 3152 } 3153 } 3154 3155 static INT TREEVIEW_CallbackChildren(HWND hwnd,TREEVIEW_ITEM *wineItem) 3156 { 3157 NMTVDISPINFOW tvdi; 3158 BOOL retval; 3159 3160 tvdi.item.mask = TVIF_CHILDREN; 3161 tvdi.item.hItem = wineItem->hItem; 3162 tvdi.item.state = wineItem->state; 3163 tvdi.item.lParam = wineItem->lParam; 3164 tvdi.item.cChildren = 0; 3165 3166 retval = (BOOL)sendNotify(hwnd,isUnicodeNotify(hwnd) ? TVN_GETDISPINFOW:TVN_GETDISPINFOA,&tvdi.hdr); 3167 3168 if (tvdi.item.mask & TVIF_DI_SETITEM) 3169 wineItem->cChildren = tvdi.item.cChildren; 3170 3171 return tvdi.item.cChildren; 3172 } 3173 3174 static BOOL 3175 TREEVIEW_SendCustomDrawNotify (HWND hwnd, DWORD dwDrawStage, HDC hdc, 3176 RECT rc) 3177 { 3178 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3179 NMTVCUSTOMDRAW nmcdhdr; 3180 LPNMCUSTOMDRAW nmcd; 3181 3182 nmcd = &nmcdhdr.nmcd; 3183 nmcd->dwDrawStage= dwDrawStage; 3184 nmcd->hdc = hdc; 3185 nmcd->rc.left = rc.left; 3186 nmcd->rc.right = rc.right; 3187 nmcd->rc.bottom = rc.bottom; 3188 nmcd->rc.top = rc.top; 3189 nmcd->dwItemSpec = 0; 3190 nmcd->uItemState = 0; 3191 nmcd->lItemlParam= 0; 3192 nmcdhdr.clrText = infoPtr->clrText; 3193 nmcdhdr.clrTextBk= infoPtr->clrBk; 3194 nmcdhdr.iLevel = 0; 3195 3196 return (BOOL)sendNotify(hwnd,NM_CUSTOMDRAW,&nmcdhdr.nmcd.hdr); 3197 } 3198 3199 /* FIXME: need to find out when the flags in uItemState need to be set */ 3200 3201 static BOOL 3202 TREEVIEW_SendCustomDrawItemNotify (HWND hwnd, HDC hdc, 3203 TREEVIEW_ITEM *wineItem, UINT uItemDrawState) 3204 { 3205 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3206 NMTVCUSTOMDRAW nmcdhdr; 3207 LPNMCUSTOMDRAW nmcd; 3208 DWORD dwDrawStage,dwItemSpec; 3209 UINT uItemState; 3210 INT retval; 3211 3212 dwDrawStage=CDDS_ITEM | uItemDrawState; 3213 dwItemSpec=(DWORD)wineItem->hItem; 3214 uItemState=0; 3215 if (wineItem->hItem == infoPtr->selectedItem) 3216 { 3217 uItemState|=CDIS_SELECTED; 3218 if (GetFocus() == hwnd) uItemState |= CDIS_FOCUS; 3219 } 3220 if (wineItem->hItem==infoPtr->hotItem) uItemState|=CDIS_HOT; 3221 3222 nmcd= & nmcdhdr.nmcd; 3223 nmcd->dwDrawStage= dwDrawStage; 3224 nmcd->hdc = hdc; 3225 nmcd->rc.left = wineItem->rect.left; 3226 nmcd->rc.right = wineItem->rect.right; 3227 nmcd->rc.bottom = wineItem->rect.bottom; 3228 nmcd->rc.top = wineItem->rect.top; 3229 nmcd->dwItemSpec = dwItemSpec; 3230 nmcd->uItemState = uItemState; 3231 nmcd->lItemlParam= wineItem->lParam; 3232 3233 nmcdhdr.clrText = infoPtr->clrText; 3234 nmcdhdr.clrTextBk= infoPtr->clrBk; 3235 nmcdhdr.iLevel = wineItem->iLevel; 3236 3237 //TRACE (treeview,"drawstage:%lx hdc:%x item:%lx, itemstate:%x\n", 3238 // dwDrawStage, hdc, dwItemSpec, uItemState); 3239 3240 retval = sendNotify(hwnd,NM_CUSTOMDRAW,&nmcdhdr.nmcd.hdr); 3241 3242 infoPtr->clrText=nmcdhdr.clrText; 3243 infoPtr->clrBk =nmcdhdr.clrTextBk; 3244 3245 return (BOOL) retval; 3246 } 3247 3248 static VOID TREEVIEW_SendKeyDownNotify(HWND hwnd,UINT code,WORD wVKey) 3249 { 3250 NMTVKEYDOWN nmkdhdr; 3251 3252 nmkdhdr.wVKey = wVKey; 3253 nmkdhdr.flags = 0; 3254 3255 sendNotify(hwnd,code,&nmkdhdr.hdr); 2736 TREEVIEW_Toggle(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem, BOOL bUser) 2737 { 2738 if (wineItem->state & TVIS_EXPANDED) 2739 return TREEVIEW_Collapse(infoPtr, wineItem, FALSE, bUser); 2740 else 2741 return TREEVIEW_Expand(infoPtr, wineItem, FALSE, bUser); 2742 } 2743 2744 static VOID 2745 TREEVIEW_ExpandAll(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 2746 { 2747 TREEVIEW_Expand(infoPtr, item, FALSE, TRUE); 2748 2749 for (item = item->firstChild; item != NULL; item = item->nextSibling) 2750 { 2751 if (TREEVIEW_HasChildren(infoPtr, item)) 2752 TREEVIEW_ExpandAll(infoPtr, item); 2753 } 3256 2754 } 3257 2755 … … 3263 2761 3264 2762 static LRESULT 3265 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam) 3266 { 3267 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 2763 TREEVIEW_ExpandMsg(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 2764 { 2765 TREEVIEW_ITEM *wineItem = (HTREEITEM)lParam; 2766 UINT flag = wParam; 2767 2768 if (!TREEVIEW_ValidItem(infoPtr, wineItem)) 2769 return 0; 2770 2771 switch (flag & TVE_TOGGLE) 2772 { 2773 case TVE_COLLAPSE: 2774 return TREEVIEW_Collapse(infoPtr, wineItem, flag & TVE_COLLAPSERESET, 2775 FALSE); 2776 2777 case TVE_EXPAND: 2778 return TREEVIEW_Expand(infoPtr, wineItem, flag & TVE_EXPANDPARTIAL, 2779 FALSE); 2780 2781 case TVE_TOGGLE: 2782 return TREEVIEW_Toggle(infoPtr, wineItem, TRUE); 2783 2784 default: 2785 return 0; 2786 } 2787 2788 } 2789 2790 /* Hit-Testing **********************************************************/ 2791 2792 static TREEVIEW_ITEM * 2793 TREEVIEW_HitTestPoint(TREEVIEW_INFO *infoPtr,POINT pt) 2794 { 3268 2795 TREEVIEW_ITEM *wineItem; 3269 UINT flag; 3270 INT expand; 3271 3272 flag = (UINT)wParam; 3273 expand = (INT)lParam; 3274 3275 wineItem = TREEVIEW_ValidItem (infoPtr,(HTREEITEM)expand); 3276 3277 if (!wineItem) 3278 return 0; 3279 3280 if (!TREEVIEW_HasChildren(hwnd, wineItem)) 3281 return 0; 3282 3283 if ((flag & 0xF) == TVE_TOGGLE) 3284 { 3285 if (wineItem->state & TVIS_EXPANDED) 3286 flag = (flag & ~0xF)+TVE_COLLAPSE; 2796 2797 if (!infoPtr->firstVisible) 2798 return NULL; 2799 2800 wineItem = infoPtr->firstVisible; 2801 2802 while (wineItem && (pt.y > wineItem->rect.bottom)) 2803 wineItem = TREEVIEW_GetNextListItem(infoPtr,wineItem); 2804 2805 return wineItem; 2806 } 2807 2808 static LRESULT 2809 TREEVIEW_HitTest(TREEVIEW_INFO *infoPtr,LPTVHITTESTINFO lpht,BOOL ignoreClientRect) 2810 { 2811 TREEVIEW_ITEM *wineItem; 2812 RECT rect; 2813 UINT status, x, y; 2814 2815 if (!lpht) return 0; 2816 2817 status = 0; 2818 x = lpht->pt.x; 2819 y = lpht->pt.y; 2820 lpht->hItem = 0; 2821 2822 if (!ignoreClientRect) 2823 { 2824 GetClientRect(infoPtr->hwnd,&rect); 2825 2826 if (x < rect.left) status |= TVHT_TOLEFT; 2827 else if (x > rect.right) status |= TVHT_TORIGHT; 2828 if (y < rect.top) status |= TVHT_ABOVE; 2829 else if (y > rect.bottom) status |= TVHT_BELOW; 2830 2831 if (status) 2832 { 2833 lpht->flags = status; 2834 return (LRESULT)(HTREEITEM)NULL; 2835 } 2836 } 2837 2838 wineItem = TREEVIEW_HitTestPoint(infoPtr,lpht->pt); 2839 if (!wineItem) 2840 { 2841 lpht->flags = TVHT_NOWHERE; 2842 return (LRESULT)(HTREEITEM)NULL; 2843 } 2844 2845 if (!wineItem->calculated) 2846 TREEVIEW_CalcItem(infoPtr,wineItem,0); 2847 2848 if (x >= wineItem->textOffset + wineItem->textWidth) 2849 { 2850 lpht->flags = TVHT_ONITEMRIGHT; 2851 } 2852 else if (x >= wineItem->textOffset) 2853 { 2854 lpht->flags = TVHT_ONITEMLABEL; 2855 } 2856 else if (x >= wineItem->imageOffset) 2857 { 2858 lpht->flags = TVHT_ONITEMICON; 2859 } 2860 else if (x >= wineItem->stateOffset) 2861 { 2862 lpht->flags = TVHT_ONITEMSTATEICON; 2863 } 2864 else if ((x >= wineItem->linesOffset) && (infoPtr->dwStyle & TVS_HASBUTTONS)) 2865 { 2866 lpht->flags = TVHT_ONITEMBUTTON; 2867 } 3287 2868 else 3288 flag = (flag & ~0xF)+TVE_EXPAND; 3289 } 3290 3291 switch (flag & 0xF) 3292 { 3293 case TVE_COLLAPSE: 3294 { 3295 POINT oldLeftTop = infoPtr->lefttop; 3296 3297 if (!wineItem->state & TVIS_EXPANDED) 3298 return 0; 3299 3300 if (flag & TVE_COLLAPSERESET) 3301 { 3302 wineItem->state &= ~(TVIS_EXPANDEDONCE | TVIS_EXPANDED); 3303 TREEVIEW_RemoveAllChildren (hwnd, wineItem); 3304 } else wineItem->state &= ~TVIS_EXPANDED; 3305 3306 //update window 3307 //CB: todo: optimize! 3308 TREEVIEW_UnqueueRefresh(hwnd,FALSE,FALSE); 3309 //CB: todo: precalc expanded items here 3310 TREEVIEW_CalcItems(hwnd,0,infoPtr); 3311 TREEVIEW_Refresh(hwnd); 3312 //CB: todo: check cx and cy to fit ranges! 3313 3314 //check selection 3315 HTREEITEM hItem = infoPtr->selectedItem; 3316 3317 if (!TREEVIEW_ValidItem (infoPtr, hItem)) 3318 hItem = wineItem->hItem; 3319 else 3320 { 3321 while (hItem) 2869 { 2870 lpht->flags = TVHT_ONITEMINDENT; 2871 } 2872 2873 lpht->hItem = wineItem; 2874 //TRACE("(%ld,%ld):result %x\n", lpht->pt.x, lpht->pt.y, lpht->flags); 2875 2876 return (LRESULT)wineItem; 2877 } 2878 2879 /* Item Label Editing ***************************************************/ 2880 2881 static LRESULT 2882 TREEVIEW_GetEditControl(TREEVIEW_INFO *infoPtr) 2883 { 2884 return infoPtr->hwndEdit; 2885 } 2886 2887 static LRESULT CALLBACK 2888 TREEVIEW_Edit_SubclassProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 2889 { 2890 TREEVIEW_INFO *infoPtr; 2891 BOOL bCancel = FALSE; 2892 2893 switch (uMsg) 2894 { 2895 case WM_PAINT: 3322 2896 { 3323 hItem = infoPtr->items[(INT)hItem].parent; 3324 3325 if (hItem == wineItem->hItem) 2897 LRESULT rc; 2898 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2899 2900 //TRACE("WM_PAINT start\n"); 2901 rc = CallWindowProcA(infoPtr->wpEditOrig, hwnd, uMsg, wParam, 2902 lParam); 2903 //TRACE("WM_PAINT done\n"); 2904 return rc; 2905 } 2906 2907 case WM_KILLFOCUS: 2908 { 2909 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2910 if (infoPtr->bIgnoreEditKillFocus) 2911 return TRUE; 2912 2913 break; 2914 } 2915 2916 case WM_GETDLGCODE: 2917 return DLGC_WANTARROWS | DLGC_WANTALLKEYS; 2918 2919 case WM_KEYDOWN: 2920 if (wParam == (WPARAM)VK_ESCAPE) 2921 { 2922 bCancel = TRUE; 3326 2923 break; 3327 2924 } 3328 } 3329 3330 if (hItem) 3331 TREEVIEW_DoSelectItem(hwnd,TVGN_CARET,hItem,TVC_UNKNOWN); 3332 3333 break; 3334 } 3335 3336 case TVE_EXPAND: 3337 { 3338 POINT oldLeftTop = infoPtr->lefttop; 3339 3340 if (wineItem->state & TVIS_EXPANDED) 3341 return 0; 3342 3343 if (flag & TVE_EXPANDPARTIAL) 3344 { 3345 return FALSE; //CB: how does this work??? (only display one level? nonsense in MSDN docu) 3346 wineItem->state ^=TVIS_EXPANDED; 3347 wineItem->state |=TVIS_EXPANDEDONCE; 3348 break; 3349 } 3350 3351 if (!(wineItem->state & TVIS_EXPANDEDONCE)) 3352 { 3353 //TRACE(treeview, " and has never been expanded...\n"); 3354 wineItem->state |= TVIS_EXPANDED; 3355 3356 /* this item has never been expanded */ 3357 if (TREEVIEW_SendTreeviewNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_ITEMEXPANDINGW:TVN_ITEMEXPANDINGA,TVE_EXPAND,0,(HTREEITEM)expand)) 3358 return FALSE; 3359 3360 3361 /* FIXME 3362 * Since the TVN_ITEMEXPANDING message may has caused the parent to 3363 * insert new items which in turn may have cause items placeholder 3364 * reallocation, I reassign the current item pointer so we have 3365 * something valid to work with... 3366 * However, this should not be necessary, 3367 * investigation required in TREEVIEW_InsertItemA 3368 */ 3369 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)expand); 3370 if (!wineItem) 2925 else if (wParam == (WPARAM)VK_RETURN) 3371 2926 { 3372 //ERR(treeview, 3373 // "Catastropic situation, cannot retreive item #%d\n", 3374 // expand); 3375 return FALSE; 2927 break; 3376 2928 } 3377 2929 3378 wineItem->state |= TVIS_EXPANDEDONCE; 3379 3380 TREEVIEW_SendTreeviewNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_ITEMEXPANDEDW:TVN_ITEMEXPANDEDA,TVE_EXPAND,0,(HTREEITEM)expand); 3381 } else 3382 { 3383 /* this item has already been expanded */ 3384 wineItem->state |= TVIS_EXPANDED; 3385 } 3386 3387 //update window 3388 //CB: todo: optimize! 3389 TREEVIEW_UnqueueRefresh(hwnd,FALSE,FALSE); 3390 //CB: todo: precalc expanded items here 3391 TREEVIEW_CalcItems(hwnd,0,infoPtr); 3392 TREEVIEW_Refresh(hwnd); 3393 //CB: todo: check cx and cy to fit ranges! 3394 3395 break; 3396 } 3397 2930 /* fall through */ 3398 2931 default: 3399 return FALSE; 3400 } 3401 3402 return TRUE; 3403 } 3404 3405 static LRESULT TREEVIEW_HitTest(HWND hwnd,LPTVHITTESTINFO lpht,BOOL ignoreClientRect) 3406 { 3407 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3408 TREEVIEW_ITEM *wineItem; 3409 RECT rect; 3410 UINT status; 3411 INT x,y; 3412 3413 if (!lpht) return 0; 3414 3415 status = 0; 3416 x = lpht->pt.x; 3417 y = lpht->pt.y; 3418 3419 if (!ignoreClientRect) 3420 { 3421 GetClientRect (hwnd, &rect); 3422 3423 if (x < rect.left) status |= TVHT_TOLEFT; 3424 if (x > rect.right) status |= TVHT_TORIGHT; 3425 if (y < rect.top ) status |= TVHT_ABOVE; 3426 if (y > rect.bottom) status |= TVHT_BELOW; 3427 3428 if (status) 3429 { 3430 lpht->flags = status; 3431 lpht->hItem = 0; 3432 3433 return 0; 3434 } 3435 } 3436 3437 if (infoPtr->firstVisible) 3438 { 3439 wineItem = &infoPtr->items [(INT)infoPtr->firstVisible]; 3440 3441 while ((wineItem != NULL) && (y > wineItem->rect.bottom)) 3442 wineItem = TREEVIEW_GetNextListItem(hwnd,infoPtr,wineItem); 3443 } else wineItem = NULL; 3444 3445 if (!wineItem) 3446 { 3447 lpht->flags = TVHT_NOWHERE; 3448 lpht->hItem = 0; 2932 { 2933 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2934 2935 //@@@PH 1999/11/05 method called with freed infoPtr memory object 2936 if (infoPtr != NULL) 2937 return CallWindowProcA(infoPtr->wpEditOrig, hwnd, uMsg, wParam, lParam); 2938 else 2939 break; 2940 } 2941 } 2942 2943 /* Processing TVN_ENDLABELEDIT message could kill the focus */ 2944 /* eg. Using a messagebox */ 2945 2946 infoPtr = TREEVIEW_GetInfoPtr(GetParent(hwnd)); 2947 infoPtr->bIgnoreEditKillFocus = TRUE; 2948 TREEVIEW_EndEditLabelNow(infoPtr, bCancel || !infoPtr->bLabelChanged); 2949 infoPtr->bIgnoreEditKillFocus = FALSE; 3449 2950 3450 2951 return 0; 3451 } 3452 3453 lpht->flags = 0; 3454 3455 if (x < wineItem->expandBox.left) { 3456 lpht->flags |= TVHT_ONITEMINDENT; 3457 goto done; 3458 } 3459 if ( PtInRect ( &wineItem->expandBox, lpht->pt)) { 3460 lpht->flags |= TVHT_ONITEMBUTTON; 3461 goto done; 3462 } 3463 if ( PtInRect ( &wineItem->bitmap, lpht->pt)) { 3464 lpht->flags |= TVHT_ONITEMICON; 3465 goto done; 3466 } 3467 if ( PtInRect ( &wineItem->statebitmap, lpht->pt)) { 3468 lpht->flags |= TVHT_ONITEMSTATEICON; 3469 goto done; 3470 } 3471 if ( PtInRect ( &wineItem->text, lpht->pt)) { 3472 lpht->flags |= TVHT_ONITEMLABEL; 3473 goto done; 3474 } 3475 3476 lpht->flags |= TVHT_ONITEMRIGHT; 3477 3478 done: 3479 lpht->hItem = wineItem->hItem; 3480 3481 return (LRESULT) wineItem->hItem; 3482 } 3483 3484 HWND TREEVIEW_EditLabel(HWND hwnd,HTREEITEM hItem,BOOL unicode) 2952 } 2953 2954 2955 /* should handle edit control messages here */ 2956 2957 static LRESULT 2958 TREEVIEW_Command(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 2959 { 2960 //TRACE("%x %ld\n", wParam, lParam); 2961 2962 switch (HIWORD(wParam)) 2963 { 2964 case EN_UPDATE: 2965 { 2966 /* 2967 * Adjust the edit window size 2968 */ 2969 char buffer[1024]; 2970 TREEVIEW_ITEM *editItem = infoPtr->selectedItem; 2971 HDC hdc = GetDC(infoPtr->hwndEdit); 2972 SIZE sz; 2973 int len; 2974 HFONT hFont, hOldFont = 0; 2975 2976 infoPtr->bLabelChanged = TRUE; 2977 2978 len = GetWindowTextA(infoPtr->hwndEdit, buffer, sizeof(buffer)); 2979 2980 /* Select font to get the right dimension of the string */ 2981 hFont = SendMessageA(infoPtr->hwndEdit, WM_GETFONT, 0, 0); 2982 if (hFont != 0) 2983 { 2984 hOldFont = SelectObject(hdc, hFont); 2985 } 2986 2987 if (GetTextExtentPoint32A(hdc, buffer, strlen(buffer), &sz)) 2988 { 2989 TEXTMETRICA textMetric; 2990 2991 /* Add Extra spacing for the next character */ 2992 GetTextMetricsA(hdc, &textMetric); 2993 sz.cx += (textMetric.tmMaxCharWidth * 2); 2994 2995 sz.cx = MAX(sz.cx, textMetric.tmMaxCharWidth * 3); 2996 sz.cx = MIN(sz.cx, 2997 infoPtr->clientWidth - editItem->textOffset + 2); 2998 2999 SetWindowPos(infoPtr->hwndEdit, 3000 HWND_TOP, 3001 0, 3002 0, 3003 sz.cx, 3004 editItem->rect.bottom - editItem->rect.top + 3, 3005 SWP_NOMOVE | SWP_DRAWFRAME); 3006 } 3007 3008 if (hFont != 0) 3009 { 3010 SelectObject(hdc, hOldFont); 3011 } 3012 3013 ReleaseDC(infoPtr->hwnd, hdc); 3014 break; 3015 } 3016 3017 default: 3018 return SendMessageA(GetParent(infoPtr->hwnd), WM_COMMAND, wParam, lParam); 3019 } 3020 3021 return 0; 3022 } 3023 3024 HWND TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr,HTREEITEM hItem,BOOL unicode) 3485 3025 { 3486 3026 SIZE sz; 3487 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3488 TREEVIEW_ITEM *editItem = TREEVIEW_ValidItem(infoPtr, (HTREEITEM)hItem); 3489 HINSTANCE hinst = GetWindowLongA(hwnd, GWL_HINSTANCE); 3027 TREEVIEW_ITEM *editItem = hItem; 3028 HINSTANCE hinst = GetWindowLongA(infoPtr->hwnd,GWL_HINSTANCE); 3490 3029 HDC hdc; 3491 3030 HFONT hOldFont = 0; 3492 3031 TEXTMETRICA textMetric; 3493 WCHAR* textW;3494 3032 CHAR* textA = NULL; 3495 BOOL mustFree = FALSE;3496 3033 NMTVDISPINFOW tvdi; 3497 3034 3498 if (! editItem)3499 return FALSE;3035 if (!TREEVIEW_ValidItem(infoPtr, editItem)) 3036 return (HWND)NULL; 3500 3037 3501 3038 if(infoPtr->hwndEdit) 3502 3039 return infoPtr->hwndEdit; 3503 3040 3041 infoPtr->bLabelChanged = FALSE; 3042 3504 3043 /* Make shure that edit item is selected */ 3505 3044 3506 TREEVIEW_DoSelectItem ( hwnd, TVGN_CARET, hItem, TVC_UNKNOWN); 3507 3508 if (editItem->pszText == LPSTR_TEXTCALLBACKW) 3509 textW = TREEVIEW_CallbackText(hwnd,editItem,&mustFree); 3510 else 3511 textW = editItem->pszText; 3512 3513 hdc = GetDC(hwnd); 3045 TREEVIEW_DoSelectItem ( infoPtr, TVGN_CARET, hItem, TVC_UNKNOWN); 3046 3047 TREEVIEW_UpdateDispInfo(infoPtr, editItem, TVIF_TEXT); 3048 3049 hdc = GetDC(infoPtr->hwnd); 3514 3050 /* Select the font to get appropriate metric dimensions */ 3515 3051 if(infoPtr->hFont != 0) … … 3519 3055 3520 3056 /*Get String Lenght in pixels */ 3521 GetTextExtentPoint32W(hdc, textW,lstrlenW(textW),&sz);3057 GetTextExtentPoint32W(hdc,editItem->pszText,lstrlenW(editItem->pszText),&sz); 3522 3058 3523 3059 /*Add Extra spacing for the next character */ … … 3525 3061 sz.cx += (textMetric.tmMaxCharWidth * 2); 3526 3062 3063 sz.cx = MAX(sz.cx, textMetric.tmMaxCharWidth * 3); 3064 sz.cx = MIN(sz.cx, infoPtr->clientWidth - editItem->textOffset + 2); 3065 3527 3066 if(infoPtr->hFont != 0) 3528 3067 { … … 3530 3069 } 3531 3070 3532 ReleaseDC( hwnd, hdc);3071 ReleaseDC(infoPtr->hwnd, hdc); 3533 3072 infoPtr->hwndEdit = CreateWindowExA ( 3534 3073 WS_EX_LEFT, … … 3537 3076 WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | WS_CLIPSIBLINGS | 3538 3077 ES_WANTRETURN | ES_LEFT, 3539 editItem->text .left - 2, editItem->text.top - 1,3540 sz.cx+3, editItem-> text.bottom - editItem->text.top + 3,3541 hwnd,3078 editItem->textOffset - 2, editItem->rect.top - 1, 3079 sz.cx+3, editItem->rect.bottom - editItem->rect.top + 3, 3080 infoPtr->hwnd, 3542 3081 0,hinst,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/ 3543 3082 3544 SendMessageA ( infoPtr->hwndEdit, WM_SETFONT, infoPtr->hFont, FALSE); 3545 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA ( 3546 infoPtr->hwndEdit, 3547 GWL_WNDPROC, 3548 (DWORD) TREEVIEW_Edit_SubclassProc); 3083 /* Get a 2D border. */ 3084 SetWindowLongA(infoPtr->hwndEdit, GWL_EXSTYLE,GetWindowLongA(infoPtr->hwndEdit, GWL_EXSTYLE) & ~WS_EX_CLIENTEDGE); 3085 SetWindowLongA(infoPtr->hwndEdit, GWL_STYLE,GetWindowLongA(infoPtr->hwndEdit, GWL_STYLE) | WS_BORDER); 3086 3087 SendMessageA(infoPtr->hwndEdit, WM_SETFONT, TREEVIEW_FontForItem(infoPtr, editItem),FALSE); 3088 3089 infoPtr->wpEditOrig = (WNDPROC)SetWindowLongA (infoPtr->hwndEdit,GWL_WNDPROC,(DWORD)TREEVIEW_Edit_SubclassProc); 3549 3090 3550 3091 tvdi.item.mask = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE | TVIF_PARAM; 3551 tvdi.item.hItem = editItem ->hItem;3092 tvdi.item.hItem = editItem; 3552 3093 tvdi.item.state = editItem->state; 3553 3094 tvdi.item.lParam = editItem->lParam; 3554 3095 if (isUnicodeNotify(&infoPtr->header)) 3555 3096 { 3556 tvdi.item.pszText = textW;3097 tvdi.item.pszText = editItem->pszText; 3557 3098 } else 3558 3099 { 3559 textA = HEAP_strdupWtoA(GetProcessHeap(),0, textW);3100 textA = HEAP_strdupWtoA(GetProcessHeap(),0,editItem->pszText); 3560 3101 tvdi.item.pszText = (LPWSTR)textA; 3561 3102 } 3562 3103 3563 if (sendNotify( hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINLABELEDITW:TVN_BEGINLABELEDITA,&tvdi.hdr))3104 if (sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINLABELEDITW:TVN_BEGINLABELEDITA,&tvdi.hdr)) 3564 3105 { 3565 3106 DestroyWindow(infoPtr->hwndEdit); 3566 3107 infoPtr->hwndEdit = 0; 3567 if (mustFree) COMCTL32_Free(textW); 3568 if (textA) COMCTL32_Free(textA); 3108 if (textA) HeapFree(GetProcessHeap(),0,textA); 3569 3109 3570 3110 return (HWND)0; … … 3572 3112 if (textA) HeapFree(GetProcessHeap(),0,textA); 3573 3113 3574 infoPtr-> editItem = hItem;3575 SetWindowTextW(infoPtr->hwndEdit, textW);3114 infoPtr->selectedItem = hItem; 3115 SetWindowTextW(infoPtr->hwndEdit,editItem->pszText); 3576 3116 SetFocus(infoPtr->hwndEdit); 3577 3117 SendMessageA(infoPtr->hwndEdit, EM_SETSEL, 0, -1); 3578 3118 ShowWindow(infoPtr->hwndEdit, SW_SHOW); 3579 if (mustFree) COMCTL32_Free(textW);3580 3119 3581 3120 return infoPtr->hwndEdit; … … 3583 3122 3584 3123 3585 LRESULT WINAPI 3586 TREEVIEW_EndEditLabelNow(HWND hwnd,BOOL bCancel) 3587 { 3588 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3589 TREEVIEW_ITEM *editedItem = TREEVIEW_ValidItem (infoPtr, infoPtr->editItem); 3124 static LRESULT 3125 TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr,BOOL bCancel) 3126 { 3127 TREEVIEW_ITEM *editedItem = infoPtr->selectedItem; 3590 3128 NMTVDISPINFOW tvdi; 3591 DWORD dwStyle = GetWindowLongA( hwnd,GWL_STYLE);3129 DWORD dwStyle = GetWindowLongA(infoPtr->hwnd,GWL_STYLE); 3592 3130 BOOL bCommit; 3593 3131 WCHAR *textW = NULL; … … 3599 3137 3600 3138 tvdi.item.mask = 0; 3601 tvdi.item.hItem = editedItem ->hItem;3139 tvdi.item.hItem = editedItem; 3602 3140 tvdi.item.state = editedItem->state; 3603 3141 tvdi.item.lParam = editedItem->lParam; … … 3612 3150 INT len = iLength+1; 3613 3151 3614 textA = (CHAR*)COMCTL32_Alloc( len*sizeof(CHAR));3152 textA = (CHAR*)COMCTL32_Alloc(1024*sizeof(CHAR)); 3615 3153 lstrcpynWtoA(textA,textW,len); 3616 3154 tvdi.item.pszText = (WCHAR*)textA; … … 3623 3161 } 3624 3162 3625 bCommit = (BOOL)sendNotify( hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_ENDLABELEDITW:TVN_ENDLABELEDITA,&tvdi.hdr);3163 bCommit = (BOOL)sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_ENDLABELEDITW:TVN_ENDLABELEDITA,&tvdi.hdr); 3626 3164 3627 3165 if (!bCancel && bCommit) /* Apply the changes */ 3628 3166 { 3629 WCHAR* text;3630 3167 BOOL mustFree = FALSE; 3631 3168 … … 3633 3170 lstrcpynAtoW(textW,textA,iLength+1); 3634 3171 3635 if (editedItem->pszText == LPSTR_TEXTCALLBACKW) 3636 text = TREEVIEW_CallbackText(hwnd,editedItem,&mustFree); 3637 else 3638 text = editedItem->pszText; 3639 3640 if (lstrcmpW(textW,text) != 0) 3641 { 3642 if (editedItem->pszText == LPSTR_TEXTCALLBACKW) 3172 if (lstrcmpW(textW,editedItem->pszText) != 0) 3173 { 3174 if (editedItem->callbackMask & TVIF_TEXT) 3643 3175 { 3644 3176 NMTVDISPINFOW tvdi; … … 3646 3178 3647 3179 tvdi.item.mask = TVIF_TEXT; 3648 tvdi.item.hItem = editedItem ->hItem;3180 tvdi.item.hItem = editedItem; 3649 3181 tvdi.item.state = editedItem->state; 3650 3182 tvdi.item.lParam = editedItem->lParam; … … 3659 3191 } 3660 3192 3661 retval = (BOOL)sendNotify( hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_SETDISPINFOW:TVN_SETDISPINFOA,&tvdi.hdr);3193 retval = (BOOL)sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_SETDISPINFOW:TVN_SETDISPINFOA,&tvdi.hdr); 3662 3194 } else 3663 3195 { 3664 if (!COMCTL32_ReAlloc( text,(iLength+1)*sizeof(WCHAR)))3196 if (!COMCTL32_ReAlloc(editedItem->pszText,(iLength+1)*sizeof(WCHAR))) 3665 3197 { 3666 3198 //ERR("OutOfMemory, cannot allocate space for label"); … … 3669 3201 if (textA) COMCTL32_Free(textA); 3670 3202 if (textW) COMCTL32_Free(textW); 3671 if (mustFree) COMCTL32_Free(text);3672 3203 3673 3204 return FALSE; … … 3679 3210 } 3680 3211 } 3681 if (mustFree) COMCTL32_Free(text);3682 3212 } 3683 3213 … … 3685 3215 DestroyWindow(infoPtr->hwndEdit); 3686 3216 infoPtr->hwndEdit = 0; 3687 infoPtr->editItem = 0;3688 3217 if (textA) COMCTL32_Free(textA); 3689 3218 if (textW) COMCTL32_Free(textW); 3690 3219 3691 3220 editedItem->calculated = FALSE; 3692 TREEVIEW_CalcItem(hwnd,0,dwStyle,infoPtr,editedItem); 3693 TREEVIEW_RefreshItem(hwnd,editedItem,TRUE); 3221 TREEVIEW_RefreshItem(infoPtr,editedItem,0); 3694 3222 3695 3223 return TRUE; 3696 3224 } 3697 3225 3226 static LRESULT 3227 TREEVIEW_HandleTimer (TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3228 { 3229 switch (wParam) 3230 { 3231 case TV_REFRESH_TIMER: 3232 KillTimer(infoPtr->hwnd,TV_REFRESH_TIMER); 3233 infoPtr->Timer &= ~TV_REFRESH_TIMER_SET; 3234 TREEVIEW_CalcItems(infoPtr); 3235 TREEVIEW_Refresh(infoPtr); 3236 return 0; 3237 3238 case TV_EDIT_TIMER: 3239 KillTimer(infoPtr->hwnd,TV_EDIT_TIMER); 3240 infoPtr->Timer &= ~TV_EDIT_TIMER_SET; 3241 TREEVIEW_EditLabel(infoPtr,infoPtr->selectedItem,TRUE); 3242 return 0; 3243 3244 case TV_INFOTIP_TIMER: 3245 TREEVIEW_CheckInfoTip(infoPtr); 3246 return 0; 3247 } 3248 3249 return 1; 3250 } 3251 3252 /* Mouse Tracking/Drag **************************************************/ 3698 3253 3699 3254 /*************************************************************************** … … 3701 3256 * Windows. 3702 3257 */ 3703 static LRESULT TREEVIEW_TrackMouse(HWND hwnd, POINT pt) 3704 { 3705 INT cxDrag = GetSystemMetrics(SM_CXDRAG); 3706 INT cyDrag = GetSystemMetrics(SM_CYDRAG); 3707 RECT r; 3708 MSG msg; 3709 3710 r.top = pt.y - cyDrag; 3711 r.left = pt.x - cxDrag; 3712 r.bottom = pt.y + cyDrag; 3713 r.right = pt.x + cxDrag; 3714 3715 SetCapture(hwnd); 3716 3717 while(1) 3718 { 3719 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE|PM_NOYIELD)) 3720 { 3721 if (msg.message == WM_MOUSEMOVE) 3722 { 3723 pt.x = (INT)LOWORD(msg.lParam); 3724 pt.y = (INT)HIWORD(msg.lParam); 3725 if (PtInRect(&r, pt)) 3726 continue; 3727 else 3258 static LRESULT 3259 TREEVIEW_TrackMouse(TREEVIEW_INFO *infoPtr, POINT pt) 3260 { 3261 INT cxDrag = GetSystemMetrics(SM_CXDRAG); 3262 INT cyDrag = GetSystemMetrics(SM_CYDRAG); 3263 RECT r; 3264 MSG msg; 3265 3266 r.top = pt.y - cyDrag; 3267 r.left = pt.x - cxDrag; 3268 r.bottom = pt.y + cyDrag; 3269 r.right = pt.x + cxDrag; 3270 3271 SetCapture(infoPtr->hwnd); 3272 3273 while (1) 3274 { 3275 if (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE | PM_NOYIELD)) 3276 { 3277 if (msg.message == WM_MOUSEMOVE) 3728 3278 { 3729 ReleaseCapture(); 3730 return 1; 3279 pt.x = (INT)LOWORD(msg.lParam); 3280 pt.y = (INT)HIWORD(msg.lParam); 3281 if (PtInRect(&r, pt)) 3282 continue; 3283 else 3284 { 3285 ReleaseCapture(); 3286 return 1; 3287 } 3731 3288 } 3732 } 3733 else if (msg.message >= WM_LBUTTONDOWN && 3734 msg.message <= WM_RBUTTONDBLCLK) 3735 { 3736 if (msg.message == WM_RBUTTONUP) 3737 TREEVIEW_RButtonUp (hwnd, &pt); 3738 break; 3739 } 3740 3741 DispatchMessageA( &msg ); 3742 } 3743 3744 if (GetCapture() != hwnd) 3745 return 0; 3746 } 3747 3748 ReleaseCapture(); 3749 return 0; 3750 } 3751 3752 static LRESULT 3753 TREEVIEW_LButtonDoubleClick (HWND hwnd, WPARAM wParam, LPARAM lParam) 3754 { 3755 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3289 else if (msg.message >= WM_LBUTTONDOWN && 3290 msg.message <= WM_RBUTTONDBLCLK) 3291 { 3292 if (msg.message == WM_RBUTTONUP) 3293 TREEVIEW_RButtonUp(infoPtr, &pt); 3294 break; 3295 } 3296 3297 DispatchMessageA(&msg); 3298 } 3299 3300 if (GetCapture() != infoPtr->hwnd) 3301 return 0; 3302 } 3303 3304 ReleaseCapture(); 3305 return 0; 3306 } 3307 3308 static LRESULT 3309 TREEVIEW_LButtonDoubleClick(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3310 { 3756 3311 TREEVIEW_ITEM *wineItem; 3757 TV_HITTESTINFO hit info;3758 3759 hit info.pt.x = (INT)LOWORD(lParam);3760 hit info.pt.y = (INT)HIWORD(lParam);3761 SetFocus ( hwnd);3312 TV_HITTESTINFO hit; 3313 3314 hit.pt.x = (INT)LOWORD(lParam); 3315 hit.pt.y = (INT)HIWORD(lParam); 3316 SetFocus (infoPtr->hwnd); 3762 3317 3763 3318 if (infoPtr->Timer & TV_EDIT_TIMER_SET) 3764 3319 { 3765 3320 /* If there is pending 'edit label' event - kill it now */ 3766 infoPtr->editItem = 0;3767 KillTimer (hwnd, TV_EDIT_TIMER);3768 } 3769 3770 if (! TREEVIEW_HitTest(hwnd,&hitinfo,FALSE) || !(hitinfo.flags & TVHT_ONITEM)) return FALSE;3771 wineItem = &infoPtr->items [(INT)hitinfo.hItem];3321 KillTimer(infoPtr->hwnd,TV_EDIT_TIMER); 3322 } 3323 3324 wineItem = (TREEVIEW_ITEM *)TREEVIEW_HitTest(infoPtr,&hit,FALSE); 3325 if (!wineItem) 3326 return 0; 3772 3327 3773 3328 //MSDN documentation says: stop on non zero. but this isn't true in this case 3774 if (!sendNotify(hwnd,NM_DBLCLK)) 3775 TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) wineItem->hItem); 3329 if (!sendNotify(infoPtr->hwnd,NM_DBLCLK)) 3330 { /* FIXME! */ 3331 switch (hit.flags) 3332 { 3333 case TVHT_ONITEMRIGHT: 3334 /* FIXME: we should not have send NM_DBLCLK in this case. */ 3335 break; 3336 3337 case TVHT_ONITEMINDENT: 3338 if (!(infoPtr->dwStyle & TVS_HASLINES)) 3339 { 3340 break; 3341 } else 3342 { 3343 int level = hit.pt.x / infoPtr->uIndent; 3344 3345 if (!(infoPtr->dwStyle & TVS_LINESATROOT)) level++; 3346 3347 while (wineItem->iLevel > level) 3348 { 3349 wineItem = wineItem->parent; 3350 } 3351 3352 /* fall through */ 3353 } 3354 3355 case TVHT_ONITEMLABEL: 3356 case TVHT_ONITEMICON: 3357 case TVHT_ONITEMSTATEICON: 3358 case TVHT_ONITEMBUTTON: 3359 TREEVIEW_Toggle(infoPtr, wineItem, TRUE); 3360 break; 3361 } 3362 } 3776 3363 3777 3364 return TRUE; 3778 3365 } 3779 3366 3780 HTREEITEM TREEVIEW_GetInfoTipItem(HWND hwnd,TREEVIEW_INFO *infoPtr,POINT pt) 3781 { 3782 TVHITTESTINFO ht; 3783 3784 ht.pt = pt; 3785 TREEVIEW_HitTest(hwnd,&ht,FALSE); 3786 3787 if (ht.hItem && (ht.flags & TVHT_ONITEM)) 3788 { 3789 TREEVIEW_ITEM *item; 3790 3791 item = &infoPtr->items[(INT)ht.hItem]; 3792 if (item->visible && ((item->text.left < 0) || (item->text.right > infoPtr->uVisibleWidth))) 3793 return ht.hItem; 3794 } 3795 3796 //check tool rect -> no flickering on tip frame 3797 if (infoPtr->tipItem) 3798 { 3799 POINT pt2 = pt; 3800 RECT rect; 3801 3802 GetWindowRect(infoPtr->hwndToolTip,&rect); 3803 ClientToScreen(hwnd,&pt2); 3804 return PtInRect(&rect,pt2) ? infoPtr->tipItem:0; 3805 } 3806 3807 return 0; 3808 } 3809 3810 VOID TREEVIEW_ShowInfoTip(HWND hwnd,TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item) 3811 { 3812 LPWSTR text; 3813 BOOL mustFree = FALSE; 3814 TTTOOLINFOW ti; 3815 POINT pt; 3816 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 3817 3818 if (dwStyle & TVS_INFOTIP) 3819 { 3820 NMTVGETINFOTIPW tvgit; 3821 WCHAR* buf = (WCHAR*)COMCTL32_Alloc(isUnicodeNotify(&infoPtr->header) ? INFOTIPSIZE*sizeof(WCHAR):INFOTIPSIZE*sizeof(CHAR)); 3822 3823 tvgit.pszText = buf; 3824 tvgit.cchTextMax = INFOTIPSIZE; 3825 tvgit.hItem = item->hItem; 3826 tvgit.lParam = item->lParam; 3827 3828 sendNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_GETINFOTIPW:TVN_GETINFOTIPA,&tvgit.hdr); 3829 if (isUnicodeNotify(&infoPtr->header)) 3830 { 3831 if (buf != tvgit.pszText) COMCTL32_Free(buf); else mustFree = TRUE; 3832 text = tvgit.pszText; 3833 } else 3834 { 3835 text = (WCHAR*)COMCTL32_Alloc(tvgit.cchTextMax*sizeof(WCHAR)); 3836 lstrcpyAtoW(text,(LPSTR)tvgit.pszText); 3837 COMCTL32_Free(buf); 3838 } 3839 } else 3840 { 3841 if (item->pszText == LPSTR_TEXTCALLBACKW) 3842 text = TREEVIEW_CallbackText(hwnd,item,&mustFree); 3843 else 3844 text = item->pszText; 3845 } 3846 3847 infoPtr->tipItem = item->hItem; 3848 SetTimer(hwnd,TV_INFOTIP_TIMER,TV_INFOTIP_DELAY,0); 3849 infoPtr->Timer |= TV_INFOTIP_TIMER_SET; 3850 3851 ti.cbSize = sizeof(ti); 3852 ti.uId = 0; 3853 ti.hwnd = hwnd; 3854 ti.hinst = 0; 3855 ti.lpszText = text; 3856 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 3857 pt.x = item->text.left; 3858 pt.y = item->text.top; 3859 ClientToScreen(hwnd,&pt); 3860 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKPOSITION,0,(LPARAM)MAKELPARAM(pt.x,pt.y)); 3861 SendMessageA(infoPtr->hwndToolTip,TTM_UPDATETIPTEXTW,0,(LPARAM)&ti); 3862 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti); 3863 3864 if (mustFree) COMCTL32_Free(text); 3865 } 3866 3867 VOID TREEVIEW_HideInfoTip(HWND hwnd,TREEVIEW_INFO *infoPtr) 3868 { 3869 if (infoPtr->tipItem) 3870 { 3871 TTTOOLINFOA ti; 3872 3873 infoPtr->tipItem = 0; 3874 KillTimer(hwnd,TV_INFOTIP_TIMER); 3875 infoPtr->Timer &= ~TV_INFOTIP_TIMER_SET; 3876 3877 ti.cbSize = sizeof(TTTOOLINFOA); 3878 ti.uId = 0; 3879 ti.hwnd = (UINT)hwnd; 3880 3881 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 3882 } 3883 } 3884 3885 static VOID TREEVIEW_CheckInfoTip(HWND hwnd) 3886 { 3887 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3888 HTREEITEM hItem; 3889 POINT pt; 3890 3891 GetCursorPos(&pt); 3892 ScreenToClient(hwnd,&pt); 3893 hItem = TREEVIEW_GetInfoTipItem(hwnd,infoPtr,pt); 3894 3895 if (hItem != infoPtr->tipItem) 3896 TREEVIEW_HideInfoTip(hwnd,infoPtr); 3897 } 3898 3899 HTREEITEM TREEVIEW_GetHottrackItem(HWND hwnd,TREEVIEW_INFO *infoPtr,POINT pt) 3900 { 3901 TVHITTESTINFO ht; 3902 3903 ht.pt = pt; 3904 TREEVIEW_HitTest(hwnd,&ht,FALSE); 3905 3906 return (ht.hItem && (ht.flags & TVHT_ONITEM)) ? ht.hItem:0; 3907 } 3908 3909 static LRESULT TREEVIEW_MouseMove(HWND hwnd,WPARAM wParam,LPARAM lParam) 3910 { 3911 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3912 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 3913 POINT pt; 3914 3915 pt.x = (INT)LOWORD(lParam); 3916 pt.y = (INT)HIWORD(lParam); 3917 3918 if (infoPtr->hwndToolTip) 3919 { 3920 HTREEITEM hItem = TREEVIEW_GetInfoTipItem(hwnd,infoPtr,pt); 3921 3922 if (infoPtr->tipItem != hItem) 3923 { 3924 if (hItem) 3925 { 3926 TREEVIEW_ITEM *item; 3927 3928 item = &infoPtr->items[(INT)hItem]; 3929 TREEVIEW_ShowInfoTip(hwnd,infoPtr,item); 3930 } else TREEVIEW_HideInfoTip(hwnd,infoPtr); 3931 } 3932 } 3933 3934 if (dwStyle & TVS_TRACKSELECT) 3935 { 3936 HTREEITEM hItem = TREEVIEW_GetHottrackItem(hwnd,infoPtr,pt); 3937 3938 if (infoPtr->hotItem != hItem) 3939 { 3940 TREEVIEW_ITEM *item; 3941 HDC hdc = 0; 3942 3943 item = TREEVIEW_ValidItem(infoPtr,infoPtr->hotItem); 3944 if (item) 3945 { 3946 if (!hdc) hdc = GetDC(hwnd); 3947 TREEVIEW_DrawHottrackLine(hdc,item); 3948 } 3949 if (hItem) 3950 { 3951 item = &infoPtr->items[(INT)hItem]; 3952 if (item) 3953 { 3954 if (!hdc) hdc = GetDC(hwnd); 3955 TREEVIEW_DrawHottrackLine(hdc,item); 3956 } 3957 } 3958 if (hdc) ReleaseDC(hwnd,hdc); 3959 } 3960 } 3961 3962 return 0; 3963 } 3964 3965 static LRESULT 3966 TREEVIEW_LButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 3967 { 3968 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3367 static LRESULT 3368 TREEVIEW_LButtonDown(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3369 { 3969 3370 TVHITTESTINFO ht; 3970 3371 BOOL bTrack; 3971 DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);3972 3372 3973 3373 /* If Edit control is active - kill it and return. … … 3978 3378 if (infoPtr->hwndEdit) 3979 3379 { 3980 SetFocus (hwnd);3380 SetFocus(infoPtr->hwnd); 3981 3381 return 0; 3982 3382 } … … 3985 3385 ht.pt.y = (INT)HIWORD(lParam); 3986 3386 3987 TREEVIEW_HitTest (hwnd,&ht,FALSE);3988 3989 bTrack = (ht.flags & TVHT_ONITEM) && !( dwStyle & TVS_DISABLEDRAGDROP);3387 TREEVIEW_HitTest(infoPtr,&ht,FALSE); 3388 3389 bTrack = (ht.flags & TVHT_ONITEM) && !(infoPtr->dwStyle & TVS_DISABLEDRAGDROP); 3990 3390 3991 3391 /* Send NM_CLICK right away */ 3992 3392 if (!bTrack) 3993 if (sendNotify( hwnd,NM_CLICK))3393 if (sendNotify(infoPtr->hwnd,NM_CLICK)) 3994 3394 goto setfocus; 3995 3395 3996 3396 if (ht.flags & TVHT_ONITEMBUTTON) 3997 3397 { 3998 TREEVIEW_ Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) ht.hItem);3398 TREEVIEW_Toggle(infoPtr,ht.hItem,TRUE); 3999 3399 goto setfocus; 4000 3400 } else if (bTrack) 4001 3401 { 4002 if (TREEVIEW_TrackMouse( hwnd,ht.pt))4003 { 4004 TREEVIEW_SendTreeviewDnDNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINDRAGW:TVN_BEGINDRAGA, ht.hItem, ht.pt);3402 if (TREEVIEW_TrackMouse(infoPtr,ht.pt)) 3403 { 3404 TREEVIEW_SendTreeviewDnDNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINDRAGW:TVN_BEGINDRAGA, ht.hItem, ht.pt); 4005 3405 infoPtr->dropItem = ht.hItem; 4006 3406 return 0; … … 4008 3408 } 4009 3409 4010 if (sendNotify( hwnd,NM_CLICK))3410 if (sendNotify(infoPtr->hwnd,NM_CLICK)) 4011 3411 goto setfocus; 4012 3412 … … 4015 3415 * and the click occured on the item label... 4016 3416 */ 4017 if (( dwStyle & TVS_EDITLABELS) && (ht.flags & TVHT_ONITEMLABEL) && (infoPtr->selectedItem == ht.hItem))3417 if ((infoPtr->dwStyle & TVS_EDITLABELS) && (ht.flags & TVHT_ONITEMLABEL) && (infoPtr->selectedItem == ht.hItem)) 4018 3418 { 4019 3419 if (infoPtr->Timer & TV_EDIT_TIMER_SET) 4020 KillTimer (hwnd, TV_EDIT_TIMER); 4021 4022 infoPtr->editItem = ht.hItem; 4023 SetTimer (hwnd, TV_EDIT_TIMER, GetDoubleClickTime(), 0); 4024 infoPtr->Timer|=TV_EDIT_TIMER_SET; 3420 KillTimer(infoPtr->hwnd,TV_EDIT_TIMER); 3421 3422 SetTimer(infoPtr->hwnd,TV_EDIT_TIMER,GetDoubleClickTime(),0); 3423 infoPtr->Timer |= TV_EDIT_TIMER_SET; 4025 3424 } else if (ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON)) 4026 3425 { 4027 TREEVIEW_DoSelectItem( hwnd,TVGN_CARET,ht.hItem,TVC_BYMOUSE);3426 TREEVIEW_DoSelectItem(infoPtr,TVGN_CARET,ht.hItem,TVC_BYMOUSE); 4028 3427 } else if (ht.flags & TVHT_ONITEMSTATEICON) 4029 3428 { 4030 if (dwStyle & TVS_CHECKBOXES) /* TVS_CHECKBOXES requires _us_ */ 4031 { /* to toggle the current state */ 4032 int state; 4033 TREEVIEW_ITEM *wineItem; 4034 4035 wineItem = TREEVIEW_ValidItem(infoPtr, ht.hItem); 4036 4037 state = 1-(wineItem->state>>12); 4038 wineItem->state &= ~TVIS_STATEIMAGEMASK; 4039 wineItem->state |= state<<12; 4040 if (wineItem->visible) 4041 { 4042 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 4043 InvalidateRect(hwnd,&wineItem->statebitmap,TRUE); 4044 } 3429 if (infoPtr->dwStyle & TVS_CHECKBOXES) 3430 { 3431 /* TVS_CHECKBOXES requires us to toggle the current state */ 3432 if (infoPtr->dwStyle & TVS_CHECKBOXES) 3433 TREEVIEW_ToggleItemState(infoPtr,ht.hItem); 4045 3434 } 4046 3435 } 4047 3436 4048 3437 setfocus: 4049 SetFocus (hwnd);3438 SetFocus(infoPtr->hwnd); 4050 3439 4051 3440 return 0; 4052 3441 } 4053 3442 4054 4055 static LRESULT 4056 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 4057 { 4058 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3443 static LRESULT 3444 TREEVIEW_RButtonDown(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3445 { 4059 3446 TVHITTESTINFO ht; 4060 3447 4061 3448 if (infoPtr->hwndEdit) 4062 3449 { 4063 SetFocus( hwnd);3450 SetFocus(infoPtr->hwnd); 4064 3451 return 0; 4065 3452 } … … 4068 3455 ht.pt.y = (INT)HIWORD(lParam); 4069 3456 4070 TREEVIEW_HitTest( hwnd,&ht,FALSE);4071 4072 if (TREEVIEW_TrackMouse( hwnd,ht.pt))3457 TREEVIEW_HitTest(infoPtr,&ht,FALSE); 3458 3459 if (TREEVIEW_TrackMouse(infoPtr,ht.pt)) 4073 3460 { 4074 3461 if (ht.hItem) 4075 3462 { 4076 TREEVIEW_SendTreeviewDnDNotify (hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINRDRAGW:TVN_BEGINDRAGA, ht.hItem, ht.pt);3463 TREEVIEW_SendTreeviewDnDNotify(infoPtr,isUnicodeNotify(&infoPtr->header) ? TVN_BEGINRDRAGW:TVN_BEGINDRAGA, ht.hItem, ht.pt); 4077 3464 infoPtr->dropItem = ht.hItem; 4078 3465 } … … 4080 3467 else 4081 3468 { 4082 SetFocus( hwnd);4083 sendNotify( hwnd,NM_RCLICK);3469 SetFocus(infoPtr->hwnd); 3470 sendNotify(infoPtr->hwnd,NM_RCLICK); 4084 3471 } 4085 3472 … … 4087 3474 } 4088 3475 4089 static LRESULT TREEVIEW_RButtonDoubleClick(HWND hwnd,WPARAM wParam,LPARAM lParam) 4090 { 4091 sendNotify(hwnd,NM_RDBLCLK); 4092 4093 return DefWindowProcA(hwnd,WM_RBUTTONDBLCLK,wParam,lParam); 4094 } 4095 4096 static LRESULT 4097 TREEVIEW_RButtonUp (HWND hwnd, LPPOINT pPt) 4098 { 4099 POINT pt; 4100 4101 pt.x = pPt->x; 4102 pt.y = pPt->y; 3476 static LRESULT 3477 TREEVIEW_RButtonUp(TREEVIEW_INFO *infoPtr, LPPOINT pPt) 3478 { 3479 POINT pt = *pPt; 4103 3480 4104 3481 /* Change to screen coordinate for WM_CONTEXTMENU */ 4105 ClientToScreen( hwnd, &pt);3482 ClientToScreen(infoPtr->hwnd, &pt); 4106 3483 4107 3484 /* Send the WM_CONTEXTMENU on a right click */ 4108 SendMessageA( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(pt.x, pt.y));3485 SendMessageA( infoPtr->hwnd, WM_CONTEXTMENU, (WPARAM)infoPtr->hwnd, MAKELPARAM(pt.x, pt.y)); 4109 3486 return 0; 4110 3487 } 4111 3488 4112 static LRESULT TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam) 4113 { 4114 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3489 static LRESULT TREEVIEW_CreateDragImage (TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3490 { 4115 3491 TREEVIEW_ITEM *dragItem; 4116 3492 INT cx,cy; … … 4121 3497 RECT rc; 4122 3498 HFONT hOldFont; 4123 WCHAR *itemtxt;4124 BOOL mustFree = FALSE;4125 3499 4126 3500 if (!(infoPtr->himlNormal)) return 0; 4127 dragItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM) lParam); 4128 4129 if (!dragItem) return 0; 4130 4131 if (dragItem->pszText == LPSTR_TEXTCALLBACKW) 4132 itemtxt = TREEVIEW_CallbackText(hwnd,dragItem,&mustFree); 4133 else 4134 itemtxt = dragItem->pszText; 3501 if (!dragItem || !TREEVIEW_ValidItem(infoPtr, dragItem)) 3502 return 0; 3503 3504 TREEVIEW_UpdateDispInfo(infoPtr, dragItem, TVIF_TEXT); 4135 3505 4136 3506 hwtop = GetDesktopWindow(); … … 4139 3509 4140 3510 hOldFont = SelectObject (hdc, infoPtr->hFont); 4141 GetTextExtentPoint32W (hdc, itemtxt, lstrlenW (itemtxt), &size);3511 GetTextExtentPoint32W (hdc, dragItem->pszText, lstrlenW (dragItem->pszText), &size); 4142 3512 4143 3513 hbmp = CreateCompatibleBitmap (htopdc, size.cx, size.cy); … … 4159 3529 4160 3530 SetRect (&rc, cx, 0, size.cx,size.cy); 4161 DrawTextW (hdc, itemtxt, lstrlenW (itemtxt), &rc, DT_LEFT);3531 DrawTextW (hdc, dragItem->pszText, lstrlenW(dragItem->pszText), &rc, DT_LEFT); 4162 3532 SelectObject (hdc, hOldFont); 4163 3533 SelectObject (hdc, hOldbmp); … … 4168 3538 DeleteObject (hbmp); 4169 3539 ReleaseDC (hwtop, htopdc); 4170 if (mustFree) COMCTL32_Free(itemtxt);4171 3540 4172 3541 return (LRESULT)infoPtr->dragList; 4173 3542 } 4174 3543 4175 4176 static LRESULT 4177 TREEVIEW_DoSelectItem (HWND hwnd, INT action, HTREEITEM newSelect, INT cause) 4178 { 4179 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4180 TREEVIEW_ITEM *prevItem,*wineItem; 4181 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE); 4182 INT prevSelect; 3544 /* Selection ************************************************************/ 3545 3546 static LRESULT 3547 TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect, 3548 INT cause) 3549 { 3550 TREEVIEW_ITEM *prevSelect; 4183 3551 BOOL refreshPrev = FALSE,refreshNew = FALSE; 4184 3552 4185 wineItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)newSelect); 4186 4187 if (wineItem && wineItem->parent) 4188 { 4189 TREEVIEW_ITEM *parent = TREEVIEW_ValidItem(infoPtr,wineItem->parent); 3553 assert(newSelect == NULL || TREEVIEW_ValidItem(infoPtr, newSelect)); 3554 3555 //TRACE("Entering item %p (%s), flag %x, cause %x, state %d\n", 3556 // newSelect, TREEVIEW_ItemName(newSelect), action, cause, 3557 // newSelect ? newSelect->state : 0); 3558 3559 if (newSelect && newSelect->parent) 3560 { 3561 TREEVIEW_ITEM *parent = newSelect->parent; 4190 3562 4191 3563 /* … … 4195 3567 while (parent && !(parent->state & TVIS_EXPANDED)) 4196 3568 { 4197 TREEVIEW_Expand(hwnd,TVE_EXPAND,(LPARAM)parent->hItem); 4198 parent = TREEVIEW_ValidItem(infoPtr,parent->parent); 4199 } 4200 } 3569 TREEVIEW_Expand(infoPtr,parent,FALSE,FALSE); 3570 parent = parent->parent; 3571 } 3572 } 3573 4201 3574 4202 3575 switch (action) 4203 3576 { 4204 3577 case TVGN_CARET: 4205 prevSelect = (INT)infoPtr->selectedItem; 4206 4207 if ((HTREEITEM)prevSelect == newSelect) 4208 return FALSE; 4209 4210 prevItem = TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect); 3578 prevSelect = infoPtr->selectedItem; 3579 3580 if (prevSelect == newSelect) 3581 return FALSE; 3582 3583 if (TREEVIEW_SendTreeviewNotify(infoPtr, 3584 isUnicodeNotify(&infoPtr->header) ? TVN_SELCHANGINGW:TVN_SELCHANGINGA, 3585 cause, 3586 TVIF_HANDLE | TVIF_STATE | TVIF_PARAM, 3587 prevSelect, 3588 newSelect)) 3589 return FALSE; /* FIXME: OK? */ 3590 3591 if (prevSelect) 3592 { 3593 refreshPrev = prevSelect->state & TVIS_SELECTED; 3594 prevSelect->state &= ~TVIS_SELECTED; 3595 } 4211 3596 4212 3597 if (newSelect) 4213 if (TREEVIEW_SendTreeviewNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_SELCHANGINGW:TVN_SELCHANGINGA,cause,(HTREEITEM)prevSelect,(HTREEITEM)newSelect))4214 return FALSE; /* FIXME: OK? */4215 4216 if (prevItem)4217 3598 { 4218 refresh Prev = prevItem->state & TVIS_SELECTED;4219 prevItem->state &= ~TVIS_SELECTED;3599 refreshNew = !(newSelect->state & TVIS_SELECTED); 3600 newSelect->state |= TVIS_SELECTED; 4220 3601 } 4221 if (wineItem) 4222 { 4223 refreshNew = !(wineItem->state & TVIS_SELECTED); 4224 wineItem->state |= TVIS_SELECTED; 4225 } 4226 4227 infoPtr->selectedItem = (HTREEITEM)newSelect; 4228 4229 if ((cause == TVC_BYMOUSE) && (dwStyle & TVS_SINGLEEXPAND)) 3602 3603 infoPtr->selectedItem = newSelect; 3604 3605 if ((cause == TVC_BYMOUSE) && (infoPtr->dwStyle & TVS_SINGLEEXPAND)) 4230 3606 { 4231 3607 BOOL control = GetKeyState(VK_CONTROL) & 0x8000; 4232 UINT rc = TREEVIEW_SendTreeviewNotify( hwnd,TVN_SINGLEEXPAND,0,prevItem->hItem,wineItem->hItem);4233 4234 if (!(rc & TVNRET_SKIPOLD) && !control && prevItem->state & TVIS_EXPANDED)4235 TREEVIEW_ Expand(hwnd,TVE_COLLAPSE,(LPARAM)prevItem->hItem);4236 if (!(rc & TVNRET_SKIPNEW) && TREEVIEW_HasChildren( hwnd,wineItem))4237 TREEVIEW_ Expand(hwnd,TVE_TOGGLE,(LPARAM)wineItem->hItem);3608 UINT rc = TREEVIEW_SendTreeviewNotify(infoPtr,TVN_SINGLEEXPAND,0,TVIF_HANDLE | TVIF_STATE | TVIF_PARAM,prevSelect,newSelect); 3609 3610 if (!(rc & TVNRET_SKIPOLD) && !control && (prevSelect->state & TVIS_EXPANDED)) 3611 TREEVIEW_Collapse(infoPtr,prevSelect,FALSE,FALSE); 3612 if (!(rc & TVNRET_SKIPNEW) && TREEVIEW_HasChildren(infoPtr,newSelect)) 3613 TREEVIEW_Toggle(infoPtr,newSelect,FALSE); 4238 3614 } 4239 3615 4240 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 4241 if (dwStyle & TVS_FULLROWSELECT) 3616 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 3617 TREEVIEW_EnsureVisible(infoPtr,infoPtr->selectedItem); 3618 if (infoPtr->dwStyle & TVS_FULLROWSELECT) 4242 3619 { 4243 3620 TREEVIEW_ITEM *item; 4244 3621 4245 3622 //deselect last selected row 4246 if (prev Item)3623 if (prevSelect) 4247 3624 { 4248 if (refreshPrev) TREEVIEW_RefreshItem( hwnd,prevItem,FALSE);4249 if (prev Item->upsibling)3625 if (refreshPrev) TREEVIEW_RefreshItem(infoPtr,prevSelect,TVIF_IMAGE | TVIF_TEXT); 3626 if (prevSelect->prevSibling) 4250 3627 { 4251 item = &infoPtr->items[(INT)prevItem->upsibling];3628 item = prevSelect->prevSibling; 4252 3629 while (item) 4253 3630 { … … 4255 3632 { 4256 3633 item->state &= ~TVIS_SELECTED; 4257 TREEVIEW_RefreshItem( hwnd,item,FALSE);3634 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT); 4258 3635 } 4259 item = &infoPtr->items[(INT)item->upsibling];3636 item = item->prevSibling; 4260 3637 } 4261 3638 } 4262 if (prev Item->sibling)3639 if (prevSelect->nextSibling) 4263 3640 { 4264 item = &infoPtr->items[(INT)prevItem->sibling];3641 item = prevSelect->nextSibling; 4265 3642 while (item) 4266 3643 { … … 4268 3645 { 4269 3646 item->state &= ~TVIS_SELECTED; 4270 TREEVIEW_RefreshItem( hwnd,item,FALSE);3647 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT); 4271 3648 } 4272 item = &infoPtr->items[(INT)item->sibling];3649 item = item->nextSibling; 4273 3650 } 4274 3651 } … … 4276 3653 4277 3654 //select new row 4278 if ( wineItem)3655 if (newSelect) 4279 3656 { 4280 if (refreshNew) TREEVIEW_RefreshItem( hwnd,wineItem,FALSE);4281 if ( wineItem->upsibling)3657 if (refreshNew) TREEVIEW_RefreshItem(infoPtr,newSelect,TVIF_IMAGE | TVIF_TEXT); 3658 if (newSelect->prevSibling) 4282 3659 { 4283 item = &infoPtr->items[(INT)wineItem->upsibling];3660 item = newSelect->prevSibling; 4284 3661 while (item) 4285 3662 { … … 4287 3664 { 4288 3665 item->state |= TVIS_SELECTED; 4289 TREEVIEW_RefreshItem( hwnd,item,FALSE);3666 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT); 4290 3667 } 4291 item = &infoPtr->items[(INT)item->upsibling];3668 item = item->prevSibling; 4292 3669 } 4293 3670 } 4294 if ( wineItem->sibling)3671 if (newSelect->nextSibling) 4295 3672 { 4296 item = &infoPtr->items[(INT)wineItem->sibling];3673 item = newSelect->nextSibling; 4297 3674 while (item) 4298 3675 { … … 4300 3677 { 4301 3678 item->state |= TVIS_SELECTED; 4302 TREEVIEW_RefreshItem( hwnd,item,FALSE);3679 TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT); 4303 3680 } 4304 item = &infoPtr->items[(INT)item->sibling];3681 item = item->nextSibling; 4305 3682 } 4306 3683 } … … 4308 3685 } else 4309 3686 { 4310 if (refreshPrev) TREEVIEW_RefreshItem( hwnd,prevItem,FALSE);4311 if (refreshNew) TREEVIEW_RefreshItem( hwnd,wineItem,FALSE);3687 if (refreshPrev) TREEVIEW_RefreshItem(infoPtr,prevSelect,TVIF_IMAGE | TVIF_TEXT); 3688 if (refreshNew) TREEVIEW_RefreshItem(infoPtr,newSelect,TVIF_IMAGE | TVIF_TEXT); 4312 3689 } 4313 3690 4314 TREEVIEW_SendTreeviewNotify(hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_SELCHANGEDW:TVN_SELCHANGEDA,cause,(HTREEITEM)prevSelect,(HTREEITEM)newSelect); 4315 3691 TREEVIEW_SendTreeviewNotify(infoPtr, 3692 isUnicodeNotify(&infoPtr->header) ? TVN_SELCHANGEDW:TVN_SELCHANGEDA, 3693 cause, 3694 TVIF_HANDLE | TVIF_STATE | TVIF_PARAM, 3695 prevSelect, 3696 newSelect); 4316 3697 break; 4317 3698 4318 3699 case TVGN_DROPHILITE: 4319 prev Item = TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);4320 4321 if (prev Item)3700 prevSelect = infoPtr->dropItem; 3701 3702 if (prevSelect) 4322 3703 { 4323 refreshPrev = prev Item->state & TVIS_DROPHILITED;4324 prev Item->state &= ~TVIS_DROPHILITED;3704 refreshPrev = prevSelect->state & TVIS_DROPHILITED; 3705 prevSelect->state &= ~TVIS_DROPHILITED; 4325 3706 } 4326 3707 4327 infoPtr->dropItem = (HTREEITEM)newSelect;4328 4329 if ( wineItem)3708 infoPtr->dropItem = newSelect; 3709 3710 if (newSelect) 4330 3711 { 4331 refreshNew = !( wineItem->state & TVIS_DROPHILITED);4332 wineItem->state |=TVIS_DROPHILITED;3712 refreshNew = !(newSelect->state & TVIS_DROPHILITED); 3713 newSelect->state |= TVIS_DROPHILITED; 4333 3714 } 4334 3715 4335 TREEVIEW_UnqueueRefresh( hwnd,TRUE,TRUE);4336 if (refreshPrev) TREEVIEW_RefreshItem( hwnd,prevItem,FALSE);4337 if (refreshNew) TREEVIEW_RefreshItem( hwnd,wineItem,FALSE);3716 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 3717 if (refreshPrev) TREEVIEW_RefreshItem(infoPtr,prevSelect,TVIF_IMAGE | TVIF_TEXT); 3718 if (refreshNew) TREEVIEW_RefreshItem(infoPtr,newSelect,TVIF_IMAGE | TVIF_TEXT); 4338 3719 4339 3720 break; … … 4346 3727 if (!infoPtr->firstVisible) return FALSE; 4347 3728 4348 firstVis = &infoPtr->items[(INT)infoPtr->firstVisible];4349 4350 if ( wineItem->rect.top < 0)4351 scrollY = wineItem->rect.top;3729 firstVis = infoPtr->firstVisible; 3730 3731 if (newSelect->rect.top < 0) 3732 scrollY = newSelect->rect.top; 4352 3733 else 4353 3734 { 4354 scrollY = MIN( wineItem->rect.top,(infoPtr->uTotalHeight-infoPtr->uVisibleHeight)-infoPtr->lefttop.y);4355 scrollY -= scrollY % infoPtr->u VScrollStep;3735 scrollY = MIN(newSelect->rect.top,(infoPtr->treeHeight-infoPtr->clientHeight)-infoPtr->lefttop.y); 3736 scrollY -= scrollY % infoPtr->uItemHeight; 4356 3737 } 4357 3738 … … 4359 3740 { 4360 3741 infoPtr->lefttop.y += scrollY; 4361 if (!TREEVIEW_UnqueueRefresh( hwnd,TRUE,TRUE))4362 TREEVIEW_CalcItems( hwnd,0,infoPtr);4363 4364 ScrollWindowEx( hwnd,0,-scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16));3742 if (!TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE)) 3743 TREEVIEW_CalcItems(infoPtr); 3744 3745 ScrollWindowEx(infoPtr->hwnd,0,-scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 4365 3746 } 4366 3747 4367 3748 break; 4368 3749 } 4369 } 4370 4371 return TRUE; 4372 } 4373 4374 static LRESULT 4375 TREEVIEW_SelectItem (HWND hwnd, WPARAM wParam, LPARAM lParam) 4376 { 4377 return TREEVIEW_DoSelectItem(hwnd,wParam,(HTREEITEM)lParam,TVC_UNKNOWN); 4378 } 4379 4380 static LRESULT 4381 TREEVIEW_GetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) 4382 { 4383 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4384 4385 return infoPtr->hFont; 4386 } 4387 4388 static LRESULT 4389 TREEVIEW_SetFont (HWND hwnd, WPARAM wParam, LPARAM lParam) 4390 { 4391 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4392 TEXTMETRICA tm; 4393 LOGFONTA logFont; 4394 HFONT hFont, hOldFont; 4395 INT height; 4396 HDC hdc; 4397 4398 infoPtr->hFont = (HFONT)wParam; 4399 4400 hFont = infoPtr->hFont ? infoPtr->hFont : GetStockObject (SYSTEM_FONT); 4401 4402 GetObjectA (infoPtr->hFont, sizeof (LOGFONTA), &logFont); 4403 logFont.lfWeight = FW_BOLD; 4404 DeleteObject(infoPtr->hBoldFont); 4405 infoPtr->hBoldFont = CreateFontIndirectA (&logFont); 4406 4407 SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,1); 4408 infoPtr->uInternalStatus |= TV_CALCALL; 4409 TREEVIEW_CalcItems(hwnd,0,infoPtr); 4410 4411 if (lParam) 4412 { 4413 TREEVIEW_UnqueueRefresh(hwnd,FALSE,FALSE); 4414 TREEVIEW_Refresh(hwnd); 4415 } 4416 4417 return 0; 4418 } 4419 4420 static LRESULT 4421 TREEVIEW_VScroll(HWND hwnd,WPARAM wParam,LPARAM lParam) 4422 { 4423 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3750 } 3751 3752 //TRACE("Leaving state %d\n", newSelect ? newSelect->state : 0); 3753 return TRUE; 3754 } 3755 3756 /* FIXME: handle NM_KILLFOCUS etc */ 3757 static LRESULT 3758 TREEVIEW_SelectItem(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3759 { 3760 HTREEITEM item = (HTREEITEM)lParam; 3761 3762 if (item != NULL && !TREEVIEW_ValidItem(infoPtr, item)) 3763 return FALSE; 3764 3765 //TRACE("%p (%s) %d\n", item, TREEVIEW_ItemName(item), (int)wParam); 3766 3767 if (!TREEVIEW_DoSelectItem(infoPtr, wParam, item, TVC_UNKNOWN)) 3768 return FALSE; 3769 3770 return TRUE; 3771 } 3772 3773 /* Scrolling ************************************************************/ 3774 3775 static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *infoPtr,HTREEITEM item) 3776 { 3777 RECT rect; 3778 INT scrollY; 3779 3780 if (!item) return FALSE; 3781 3782 if (!TREEVIEW_ValidItem(infoPtr,item)) 3783 return FALSE; 3784 3785 if (item && item->parent) 3786 { 3787 TREEVIEW_ITEM *parent = item->parent; 3788 3789 while (parent && !(parent->state & TVIS_EXPANDED)) 3790 { 3791 TREEVIEW_Expand(infoPtr,parent,FALSE,FALSE); 3792 parent = parent->parent; 3793 } 3794 } 3795 3796 TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE); 3797 GetClientRect(infoPtr->hwnd,&rect); 3798 if (item->rect.top < 0) 3799 scrollY = item->rect.top; 3800 else if (item->rect.bottom > rect.bottom) 3801 { 3802 INT mod; 3803 3804 scrollY = item->rect.bottom-rect.bottom; 3805 mod = scrollY % infoPtr->uItemHeight; 3806 if (mod) scrollY += infoPtr->uItemHeight-mod; 3807 } else return FALSE; 3808 3809 if (scrollY != 0) 3810 { 3811 infoPtr->lefttop.y += scrollY; 3812 TREEVIEW_CalcItems(infoPtr); 3813 ScrollWindowEx(infoPtr->hwnd,0,-scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 3814 3815 return TRUE; 3816 } 3817 3818 return FALSE; 3819 } 3820 3821 static LRESULT 3822 TREEVIEW_VScroll(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 3823 { 4424 3824 INT newY,mod; 4425 INT maxY = infoPtr-> uTotalHeight-infoPtr->uVisibleHeight;3825 INT maxY = infoPtr->treeHeight-infoPtr->clientHeight; 4426 3826 4427 3827 if (!(infoPtr->uInternalStatus & TV_VSCROLL)) return FALSE; 4428 3828 4429 mod = maxY % infoPtr->u VScrollStep;4430 if (mod > 0) maxY += infoPtr->u VScrollStep-mod;3829 mod = maxY % infoPtr->uItemHeight; 3830 if (mod > 0) maxY += infoPtr->uItemHeight-mod; 4431 3831 4432 3832 switch (LOWORD (wParam)) 4433 3833 { 4434 3834 case SB_LINEUP: 4435 newY = infoPtr->lefttop.y-infoPtr->u VScrollStep;3835 newY = infoPtr->lefttop.y-infoPtr->uItemHeight; 4436 3836 if (newY < 0) newY = 0; 4437 3837 break; 4438 3838 4439 3839 case SB_LINEDOWN: 4440 newY = infoPtr->lefttop.y+infoPtr->u VScrollStep;3840 newY = infoPtr->lefttop.y+infoPtr->uItemHeight; 4441 3841 if (newY > maxY) newY = maxY; 4442 3842 break; 4443 3843 4444 3844 case SB_PAGEUP: 4445 newY = infoPtr->lefttop.y-MAX(((INT)(infoPtr-> uVisibleHeight/infoPtr->uVScrollStep))*infoPtr->uVScrollStep,infoPtr->uVScrollStep);3845 newY = infoPtr->lefttop.y-MAX(((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight,infoPtr->uItemHeight); 4446 3846 if (newY < 0) newY = 0; 4447 3847 break; 4448 3848 4449 3849 case SB_PAGEDOWN: 4450 newY = infoPtr->lefttop.y+MAX(((INT)(infoPtr-> uVisibleHeight/infoPtr->uVScrollStep))*infoPtr->uVScrollStep,infoPtr->uVScrollStep);3850 newY = infoPtr->lefttop.y+MAX(((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight,infoPtr->uItemHeight); 4451 3851 if (newY > maxY) newY = maxY; 4452 3852 break; … … 4454 3854 case SB_THUMBTRACK: 4455 3855 newY = HIWORD(wParam); 4456 mod = newY % infoPtr->u VScrollStep;3856 mod = newY % infoPtr->uItemHeight; 4457 3857 if (mod > 0) newY -= mod; 4458 3858 break; … … 4465 3865 { 4466 3866 INT scrollY = infoPtr->lefttop.y-newY; 4467 4468 TREEVIEW_HideInfoTip(hwnd,infoPtr); 3867 SCROLLINFO info; 3868 3869 TREEVIEW_HideInfoTip(infoPtr); 4469 3870 infoPtr->lefttop.y = newY; 4470 if (!TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE)) 4471 TREEVIEW_CalcItems(hwnd,0,infoPtr); 4472 ScrollWindowEx(hwnd,0,scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 3871 if (!TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE)) 3872 TREEVIEW_MoveItems(infoPtr,0,scrollY); 3873 3874 info.cbSize = sizeof(info); 3875 info.nPos = infoPtr->lefttop.y; 3876 info.fMask = SIF_POS; 3877 SetScrollInfo(infoPtr->hwnd,SB_VERT,&info,TRUE); 3878 3879 ScrollWindowEx(infoPtr->hwnd,0,scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 4473 3880 4474 3881 return TRUE; … … 4479 3886 4480 3887 static LRESULT 4481 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam) 4482 { 4483 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 3888 TREEVIEW_HScroll(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 3889 { 4484 3890 int maxWidth; 4485 3891 int lastPos = infoPtr->lefttop.x; 3892 SCROLLINFO info; 4486 3893 4487 3894 if (!(infoPtr->uInternalStatus & TV_HSCROLL)) return FALSE; … … 4491 3898 case SB_LINEUP: 4492 3899 if (!infoPtr->lefttop.x) return FALSE; 4493 infoPtr->lefttop.x -= infoPtr->u RealItemHeight;3900 infoPtr->lefttop.x -= infoPtr->uItemHeight; 4494 3901 if (infoPtr->lefttop.x < 0) infoPtr->lefttop.x = 0; 4495 3902 break; 4496 3903 4497 3904 case SB_LINEDOWN: 4498 maxWidth = infoPtr-> uTotalWidth-infoPtr->uVisibleWidth;3905 maxWidth = infoPtr->treeWidth-infoPtr->clientWidth; 4499 3906 if (maxWidth <= 0) return FALSE; 4500 3907 if (infoPtr->lefttop.x == maxWidth) return FALSE; 4501 infoPtr->lefttop.x += infoPtr->u RealItemHeight; /*FIXME */3908 infoPtr->lefttop.x += infoPtr->uItemHeight; /*FIXME */ 4502 3909 if (infoPtr->lefttop.x > maxWidth) 4503 3910 infoPtr->lefttop.x = maxWidth; … … 4506 3913 case SB_PAGEUP: 4507 3914 if (!infoPtr->lefttop.x) return FALSE; 4508 infoPtr->lefttop.x -= infoPtr-> uVisibleWidth;3915 infoPtr->lefttop.x -= infoPtr->clientWidth; 4509 3916 if (infoPtr->lefttop.x < 0) infoPtr->lefttop.x = 0; 4510 3917 break; 4511 3918 4512 3919 case SB_PAGEDOWN: 4513 maxWidth = infoPtr-> uTotalWidth-infoPtr->uVisibleWidth;3920 maxWidth = infoPtr->treeWidth-infoPtr->clientWidth; 4514 3921 if (maxWidth <= 0) return FALSE; 4515 3922 if (infoPtr->lefttop.x == maxWidth) return FALSE; 4516 infoPtr->lefttop.x += infoPtr-> uVisibleWidth;3923 infoPtr->lefttop.x += infoPtr->clientWidth; 4517 3924 if (infoPtr->lefttop.x > maxWidth) 4518 3925 infoPtr->lefttop.x = maxWidth; … … 4520 3927 4521 3928 case SB_THUMBTRACK: 4522 maxWidth = infoPtr-> uTotalWidth-infoPtr->uVisibleWidth;3929 maxWidth = infoPtr->treeWidth-infoPtr->clientWidth; 4523 3930 if (maxWidth <= 0) return FALSE; 4524 3931 infoPtr->lefttop.x = HIWORD(wParam); … … 4533 3940 if (lastPos != infoPtr->lefttop.x) 4534 3941 { 4535 TREEVIEW_HideInfoTip(hwnd,infoPtr); 4536 if (!TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE)) 4537 TREEVIEW_CalcItems(hwnd,0,infoPtr); 4538 ScrollWindowEx(hwnd,lastPos-infoPtr->lefttop.x,0,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 3942 TREEVIEW_HideInfoTip(infoPtr); 3943 if (!TREEVIEW_UnqueueRefresh(infoPtr,TRUE,TRUE)) 3944 TREEVIEW_MoveItems(infoPtr,lastPos-infoPtr->lefttop.x,0); 3945 3946 info.cbSize = sizeof(info); 3947 info.nPos = infoPtr->lefttop.x; 3948 info.fMask = SIF_POS; 3949 SetScrollInfo(infoPtr->hwnd,SB_HORZ,&info,TRUE); 3950 3951 ScrollWindowEx(infoPtr->hwnd,lastPos-infoPtr->lefttop.x,0,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 4539 3952 4540 3953 return TRUE; … … 4544 3957 } 4545 3958 4546 static LRESULT TREEVIEW_MouseWheel (HWND hwnd, WPARAM wParam, LPARAM lParam) 4547 { 4548 4549 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4550 short gcWheelDelta = 0; 3959 static LRESULT 3960 TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 3961 { 3962 short gcWheelDelta; 4551 3963 UINT pulScrollLines = 3; 4552 3964 4553 if (wParam & (MK_SHIFT | MK_CONTROL)) 4554 return DefWindowProcA( hwnd, WM_MOUSEWHEEL, wParam, lParam ); 4555 4556 4557 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0); 4558 4559 gcWheelDelta -= (short) HIWORD(wParam); 3965 if (infoPtr->firstVisible == NULL) 3966 return TRUE; 3967 3968 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES, 0, &pulScrollLines, 0); 3969 3970 gcWheelDelta = -(short)HIWORD(wParam); 4560 3971 pulScrollLines *= (gcWheelDelta / WHEEL_DELTA); 4561 3972 4562 3973 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines) 4563 3974 { 4564 int wheelDy = pulScrollLines * infoPtr->u RealItemHeight;3975 int wheelDy = pulScrollLines * infoPtr->uItemHeight; 4565 3976 int newDy = infoPtr->lefttop.y + wheelDy; 4566 int maxDy = infoPtr-> uTotalHeight-infoPtr->uVisibleHeight;3977 int maxDy = infoPtr->treeHeight-infoPtr->clientHeight; 4567 3978 4568 3979 if (newDy > maxDy) newDy = maxDy; 3980 4569 3981 if (newDy < 0) newDy = 0; 4570 3982 4571 if (newDy == infoPtr->lefttop.y) return TRUE; 4572 4573 TREEVIEW_VScroll(hwnd, MAKEWPARAM(SB_THUMBTRACK,newDy),0); 4574 } 4575 return TRUE; 4576 } 4577 4578 static LRESULT 4579 TREEVIEW_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam) 4580 { 4581 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4582 HTREEITEM hNewSelection = 0; 4583 INT prevSelect = (INT)infoPtr->selectedItem; 4584 TREEVIEW_ITEM *prevItem = 4585 (prevSelect != 0 ) ? 4586 TREEVIEW_ValidItem (infoPtr, (HTREEITEM)prevSelect) : 4587 NULL; 4588 TREEVIEW_ITEM *newItem = NULL; 4589 BOOL control; 4590 4591 TREEVIEW_SendKeyDownNotify(hwnd,TVN_KEYDOWN,wParam); 4592 4593 control = GetKeyState(VK_CONTROL) & 0x8000; 4594 4595 if (control) 4596 { 4597 INT scrollMsg = -1; 4598 BOOL horz = FALSE; 4599 4600 switch (wParam) 4601 { 4602 case VK_UP: 4603 scrollMsg = SB_LINELEFT; 3983 TREEVIEW_VScroll(infoPtr, MAKEWPARAM(SB_THUMBTRACK, newDy), 0); 3984 } 3985 return TRUE; 3986 } 3987 3988 /* Create/Destroy *******************************************************/ 3989 3990 static LRESULT 3991 TREEVIEW_Create (HWND hwnd, WPARAM wParam, LPARAM lParam) 3992 { 3993 LPCREATESTRUCTA lpcs = (LPCREATESTRUCTA)lParam; 3994 TREEVIEW_INFO *infoPtr; 3995 RECT rcClient; 3996 3997 /* allocate memory for info structure */ 3998 infoPtr = (TREEVIEW_INFO*)initControl(hwnd,sizeof(TREEVIEW_INFO)); 3999 4000 if (!infoPtr) return 0; 4001 4002 /* set default settings */ 4003 infoPtr->hwnd = hwnd; 4004 infoPtr->dwStyle = GetWindowLongA(hwnd, GWL_STYLE); 4005 infoPtr->uInternalStatus = TV_CALCALL; 4006 infoPtr->Timer = 0; 4007 infoPtr->uNumItems = 0; 4008 infoPtr->cdmode = 0; 4009 infoPtr->uScrollTime = 300; /* milliseconds */ 4010 4011 GetClientRect(hwnd,&rcClient); 4012 4013 /* No scroll bars yet. */ 4014 infoPtr->clientWidth = rcClient.right; 4015 infoPtr->clientHeight = rcClient.bottom; 4016 4017 infoPtr->treeWidth = 0; 4018 infoPtr->treeHeight = 0; 4019 4020 infoPtr->uIndent = 19; 4021 infoPtr->selectedItem = 0; 4022 infoPtr->firstVisible = 0; 4023 infoPtr->maxDisplayOrder = 0; 4024 infoPtr->dropItem = 0; 4025 infoPtr->insertMarkItem = 0; 4026 infoPtr->insertBeforeorAfter = 0; 4027 4028 infoPtr->clrBk = GetSysColor(COLOR_WINDOW); 4029 infoPtr->clrText = -1; /* use system color */ 4030 infoPtr->clrLine = RGB(128, 128, 128); 4031 infoPtr->clrInsertMark = GetSysColor(COLOR_BTNTEXT); 4032 4033 infoPtr->lefttop.y = 0; 4034 infoPtr->lefttop.x = 0; 4035 4036 infoPtr->hwndEdit = 0; 4037 infoPtr->wpEditOrig = NULL; 4038 infoPtr->bIgnoreEditKillFocus = FALSE; 4039 infoPtr->bLabelChanged = FALSE; 4040 4041 infoPtr->himlNormal = NULL; 4042 infoPtr->himlState = NULL; 4043 infoPtr->normalImageWidth = 0; 4044 infoPtr->normalImageHeight = 0; 4045 infoPtr->stateImageWidth = 0; 4046 infoPtr->stateImageHeight = 0; 4047 4048 infoPtr->items = DPA_Create(16); 4049 4050 infoPtr->hFont = GetStockObject(DEFAULT_GUI_FONT); 4051 infoPtr->hBoldFont = TREEVIEW_CreateBoldFont(infoPtr->hFont); 4052 4053 infoPtr->uItemHeight = TREEVIEW_NaturalHeight(infoPtr); 4054 4055 infoPtr->root = TREEVIEW_AllocateItem(infoPtr); 4056 infoPtr->root->state = TVIS_EXPANDED; 4057 infoPtr->root->iLevel = -1; 4058 infoPtr->root->displayOrder = -1; 4059 4060 infoPtr->pszISearch = NULL; 4061 infoPtr->uISearchLen = 0; 4062 4063 infoPtr->tipItem = 0; 4064 infoPtr->hwndToolTip = 0; 4065 if (!(infoPtr->dwStyle & TVS_NOTOOLTIPS)) 4066 { 4067 infoPtr->hwndToolTip = createToolTip(hwnd,TTF_TRACK | TTF_ABSOLUTE | TTF_TRANSPARENT,TRUE); 4068 SendMessageA(infoPtr->hwndToolTip,WM_SETFONT,infoPtr->hFont,0); 4069 } 4070 4071 if (infoPtr->dwStyle & TVS_CHECKBOXES) 4072 { 4073 HBITMAP hbmLoad; 4074 int nIndex; 4075 4076 infoPtr->himlState = ImageList_Create (16, 16,ILC_COLOR | ILC_MASK, 15, 1); 4077 4078 //MSDN docu says: uses DrawFrameControl but never believe what they write 4079 hbmLoad = LoadBitmapA (COMCTL32_hModule, MAKEINTRESOURCEA(IDT_CHECK)); 4080 nIndex = ImageList_AddMasked (infoPtr->himlState, hbmLoad, CLR_DEFAULT); 4081 DeleteObject (hbmLoad); 4082 4083 infoPtr->stateImageWidth = 16; 4084 infoPtr->stateImageHeight = 16; 4085 } 4086 4087 return 0; 4088 } 4089 4090 static LRESULT 4091 TREEVIEW_Destroy(TREEVIEW_INFO *infoPtr) 4092 { 4093 TREEVIEW_RemoveTree(infoPtr); 4094 4095 /* tool tip is automatically destroyed: we are its owner */ 4096 4097 /* Restore original windproc. */ 4098 if (infoPtr->hwndEdit) 4099 SetWindowLongA(infoPtr->hwndEdit, GWL_WNDPROC,(LONG)infoPtr->wpEditOrig); 4100 4101 if (infoPtr->Timer & TV_REFRESH_TIMER_SET) 4102 KillTimer(infoPtr->hwnd, TV_REFRESH_TIMER); 4103 4104 DeleteObject(infoPtr->hBoldFont); 4105 COMCTL32_Free(infoPtr->pszISearch); 4106 doneControl(infoPtr->hwnd); 4107 4108 return 0; 4109 } 4110 4111 /* Miscellaneous Messages ***********************************************/ 4112 4113 static LRESULT 4114 TREEVIEW_ScrollKeyDown(TREEVIEW_INFO *infoPtr, WPARAM key) 4115 { 4116 static const struct 4117 { 4118 unsigned char code; 4119 } 4120 scroll[] = 4121 { 4122 #define SCROLL_ENTRY(dir, code) { ((dir) << 7) | (code) } 4123 SCROLL_ENTRY(SB_VERT, SB_PAGEUP), /* VK_PRIOR */ 4124 SCROLL_ENTRY(SB_VERT, SB_PAGEDOWN), /* VK_NEXT */ 4125 SCROLL_ENTRY(SB_VERT, SB_BOTTOM), /* VK_END */ 4126 SCROLL_ENTRY(SB_VERT, SB_TOP), /* VK_HOME */ 4127 SCROLL_ENTRY(SB_HORZ, SB_LINEUP), /* VK_LEFT */ 4128 SCROLL_ENTRY(SB_VERT, SB_LINEUP), /* VK_UP */ 4129 SCROLL_ENTRY(SB_HORZ, SB_LINEDOWN), /* VK_RIGHT */ 4130 SCROLL_ENTRY(SB_VERT, SB_LINEDOWN) /* VK_DOWN */ 4131 #undef SCROLL_ENTRY 4132 }; 4133 4134 if (key >= VK_PRIOR && key <= VK_DOWN) 4135 { 4136 unsigned char code = scroll[key - VK_PRIOR].code; 4137 4138 (((code & (1 << 7)) == (SB_HORZ << 7)) 4139 ? TREEVIEW_HScroll 4140 : TREEVIEW_VScroll)(infoPtr, code & 0x7F, 0); 4141 } 4142 4143 return 0; 4144 } 4145 4146 /************************************************************************ 4147 * TREEVIEW_KeyDown 4148 * 4149 * VK_UP Move selection to the previous non-hidden item. 4150 * VK_DOWN Move selection to the next non-hidden item. 4151 * VK_HOME Move selection to the first item. 4152 * VK_END Move selection to the last item. 4153 * VK_LEFT If expanded then collapse, otherwise move to parent. 4154 * VK_RIGHT If collapsed then expand, otherwise move to first child. 4155 * VK_ADD Expand. 4156 * VK_SUBTRACT Collapse. 4157 * VK_MULTIPLY Expand all. 4158 * VK_PRIOR Move up GetVisibleCount items. 4159 * VK_NEXT Move down GetVisibleCount items. 4160 * VK_BACK Move to parent. 4161 * CTRL-Left,Right,Up,Down,PgUp,PgDown,Home,End: Scroll without changing selection 4162 */ 4163 static LRESULT 4164 TREEVIEW_KeyDown(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4165 { 4166 /* If it is non-NULL and different, it will be selected and visible. */ 4167 TREEVIEW_ITEM *newSelection = NULL; 4168 TREEVIEW_ITEM *prevItem = infoPtr->selectedItem; 4169 4170 TREEVIEW_SendKeyDownNotify(infoPtr,TVN_KEYDOWN,wParam); 4171 4172 //TRACE("%x %lx\n", wParam, lParam); 4173 4174 if (prevItem == NULL) 4175 return FALSE; 4176 4177 if (GetAsyncKeyState(VK_CONTROL) & 0x8000) 4178 return TREEVIEW_ScrollKeyDown(infoPtr, wParam); 4179 4180 switch (wParam) 4181 { 4182 case VK_UP: 4183 newSelection = TREEVIEW_GetPrevListItem(infoPtr, prevItem); 4184 if (!newSelection) 4185 newSelection = infoPtr->root->firstChild; 4604 4186 break; 4605 4187 4606 4607 scrollMsg = SB_LINERIGHT;4188 case VK_DOWN: 4189 newSelection = TREEVIEW_GetNextListItem(infoPtr, prevItem); 4608 4190 break; 4609 4191 4610 case VK_LEFT: 4611 scrollMsg = SB_LINELEFT; 4612 horz = TRUE; 4192 case VK_HOME: 4193 newSelection = infoPtr->root->firstChild; 4613 4194 break; 4614 4195 4615 case VK_RIGHT:4616 scrollMsg = SB_LINERIGHT;4617 horz = TRUE;4196 case VK_END: 4197 newSelection = TREEVIEW_GetLastListItem(infoPtr, 4198 infoPtr->root->lastChild); 4618 4199 break; 4619 4200 4620 case VK_PRIOR: 4621 scrollMsg = SB_PAGELEFT; 4201 case VK_LEFT: 4202 if (prevItem->state & TVIS_EXPANDED) 4203 { 4204 TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE); 4205 } 4206 else if (prevItem->parent != infoPtr->root) 4207 { 4208 newSelection = prevItem->parent; 4209 } 4622 4210 break; 4623 4211 4624 case VK_NEXT: 4625 scrollMsg = SB_PAGERIGHT; 4212 case VK_RIGHT: 4213 if (TREEVIEW_HasChildren(infoPtr, prevItem)) 4214 { 4215 if (!(prevItem->state & TVIS_EXPANDED)) 4216 TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE); 4217 else 4218 { 4219 newSelection = prevItem->firstChild; 4220 } 4221 } 4222 4626 4223 break; 4627 } 4628 if (scrollMsg != -1) 4629 { 4630 SendMessageA(hwnd,horz ? WM_HSCROLL:WM_VSCROLL,MAKELONG(scrollMsg,0),0); 4631 return TRUE; 4632 } 4633 } 4634 4635 if (prevSelect == 0) 4636 return FALSE; 4637 4638 switch (wParam) 4639 { 4640 case VK_UP: 4641 newItem = TREEVIEW_GetPrevListItem(hwnd,infoPtr, prevItem); 4642 4643 if (!newItem) 4644 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem]; 4645 4646 hNewSelection = newItem->hItem; 4647 4224 4225 case VK_MULTIPLY: 4226 TREEVIEW_ExpandAll(infoPtr, prevItem); 4227 break; 4228 4229 case VK_ADD: 4230 if (!(prevItem->state & TVIS_EXPANDED)) 4231 TREEVIEW_Expand(infoPtr, prevItem, FALSE, TRUE); 4232 break; 4233 4234 case VK_SUBTRACT: 4235 if (prevItem->state & TVIS_EXPANDED) 4236 TREEVIEW_Collapse(infoPtr, prevItem, FALSE, TRUE); 4237 break; 4238 4239 case VK_PRIOR: 4240 newSelection 4241 = TREEVIEW_GetListItem(infoPtr, prevItem, 4242 -TREEVIEW_GetVisibleCount(infoPtr)); 4243 break; 4244 4245 case VK_NEXT: 4246 newSelection 4247 = TREEVIEW_GetListItem(infoPtr, prevItem, 4248 TREEVIEW_GetVisibleCount(infoPtr)); 4249 break; 4250 4251 case VK_RETURN: 4252 sendNotify(infoPtr->hwnd,NM_RETURN); 4648 4253 break; 4649 4254 4650 case VK_DOWN: 4651 newItem = TREEVIEW_GetNextListItem (hwnd,infoPtr, prevItem); 4652 4653 if (!newItem) 4654 newItem = prevItem; 4655 4656 hNewSelection = newItem->hItem; 4657 4658 break; 4659 4660 case VK_HOME: 4661 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem]; 4662 hNewSelection = newItem->hItem; 4663 4664 break; 4665 4666 case VK_END: 4667 newItem = &infoPtr->items[(INT)infoPtr->TopRootItem]; 4668 newItem = TREEVIEW_GetLastListItem (hwnd,infoPtr, newItem); 4669 hNewSelection = newItem->hItem; 4670 4671 break; 4672 4673 case VK_LEFT: 4674 if ( (prevItem->state & TVIS_EXPANDED) && 4675 TREEVIEW_HasChildren(hwnd, prevItem)) 4255 case VK_BACK: 4256 newSelection = prevItem->parent; 4257 if (newSelection == infoPtr->root) 4258 newSelection = NULL; 4259 break; 4260 4261 case VK_SPACE: 4262 if (infoPtr->dwStyle & TVS_CHECKBOXES) 4263 TREEVIEW_ToggleItemState(infoPtr, prevItem); 4264 break; 4265 } 4266 4267 if (newSelection && newSelection != prevItem) 4268 { 4269 if (TREEVIEW_DoSelectItem(infoPtr,TVGN_CARET,newSelection,TVC_BYKEYBOARD)) 4270 { 4271 TREEVIEW_EnsureVisible(infoPtr, newSelection); 4272 } 4273 } 4274 4275 return FALSE; 4276 } 4277 4278 static LRESULT 4279 TREEVIEW_Size(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4280 { 4281 if (wParam == SIZE_RESTORED) 4282 { 4283 infoPtr->clientWidth = LOWORD(lParam); 4284 infoPtr->clientHeight = HIWORD(lParam); 4285 if (TREEVIEW_CalcItems(infoPtr)) 4286 TREEVIEW_Refresh(infoPtr); 4287 } 4288 4289 return 0; 4290 } 4291 4292 static LRESULT 4293 TREEVIEW_StyleChanged(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4294 { 4295 //TRACE("(%x %lx)\n", wParam, lParam); 4296 4297 if (wParam == GWL_STYLE) 4298 infoPtr->dwStyle = ((LPSTYLESTRUCT)lParam)->styleNew; 4299 4300 if (infoPtr->hwndEdit) SetFocus(infoPtr->hwnd); 4301 4302 infoPtr->uInternalStatus |= TV_CALCALL; 4303 TREEVIEW_QueueRefresh(infoPtr); 4304 4305 return 0; 4306 } 4307 4308 static LRESULT 4309 TREEVIEW_SetFocus(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4310 { 4311 sendNotify(infoPtr->hwnd,NM_SETFOCUS); 4312 4313 if (!(infoPtr->dwStyle & TVS_SHOWSELALWAYS)) 4314 { 4315 if (infoPtr->selectedItem) 4316 TREEVIEW_RefreshItem(infoPtr,infoPtr->selectedItem,TVIF_IMAGE | TVIF_TEXT); 4317 else if (infoPtr->firstVisible) 4318 TREEVIEW_DoSelectItem(infoPtr,TVGN_CARET,infoPtr->firstVisible,TVC_UNKNOWN); 4319 } 4320 4321 return 0; 4322 } 4323 4324 static LRESULT 4325 TREEVIEW_KillFocus(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4326 { 4327 sendNotify(infoPtr->hwnd,NM_KILLFOCUS); 4328 4329 if (!(infoPtr->dwStyle & TVS_SHOWSELALWAYS) && infoPtr->selectedItem) 4330 TREEVIEW_RefreshItem(infoPtr,infoPtr->selectedItem,TVIF_IMAGE | TVIF_TEXT); 4331 4332 return 0; 4333 } 4334 4335 static LRESULT TREEVIEW_RButtonDoubleClick(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4336 { 4337 sendNotify(infoPtr->hwnd,NM_RDBLCLK); 4338 4339 return DefWindowProcA(infoPtr->hwnd,WM_RBUTTONDBLCLK,wParam,lParam); 4340 } 4341 4342 4343 HTREEITEM TREEVIEW_GetInfoTipItem(TREEVIEW_INFO *infoPtr,POINT pt) 4344 { 4345 TVHITTESTINFO ht; 4346 4347 ht.pt = pt; 4348 TREEVIEW_HitTest(infoPtr,&ht,FALSE); 4349 4350 if (ht.hItem && (ht.flags & TVHT_ONITEM)) 4351 { 4352 TREEVIEW_ITEM *item = ht.hItem; 4353 4354 if (item->inclient && ((item->textOffset < 0) || (item->textOffset+item->textWidth > infoPtr->clientWidth))) 4355 return ht.hItem; 4356 } 4357 4358 //check tool rect -> no flickering on tip frame 4359 if (infoPtr->tipItem) 4360 { 4361 POINT pt2 = pt; 4362 RECT rect; 4363 4364 GetWindowRect(infoPtr->hwndToolTip,&rect); 4365 ClientToScreen(infoPtr->hwnd,&pt2); 4366 return PtInRect(&rect,pt2) ? infoPtr->tipItem:0; 4367 } 4368 4369 return 0; 4370 } 4371 4372 VOID TREEVIEW_ShowInfoTip(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item) 4373 { 4374 LPWSTR text; 4375 BOOL mustFree = FALSE; 4376 TTTOOLINFOW ti; 4377 POINT pt; 4378 4379 if (infoPtr->dwStyle & TVS_INFOTIP) 4380 { 4381 NMTVGETINFOTIPW tvgit; 4382 WCHAR* buf = (WCHAR*)COMCTL32_Alloc(isUnicodeNotify(&infoPtr->header) ? INFOTIPSIZE*sizeof(WCHAR):INFOTIPSIZE*sizeof(CHAR)); 4383 4384 tvgit.pszText = buf; 4385 tvgit.cchTextMax = INFOTIPSIZE; 4386 tvgit.hItem = item; 4387 tvgit.lParam = item->lParam; 4388 4389 sendNotify(infoPtr->hwnd,isUnicodeNotify(&infoPtr->header) ? TVN_GETINFOTIPW:TVN_GETINFOTIPA,&tvgit.hdr); 4390 if (isUnicodeNotify(&infoPtr->header)) 4391 { 4392 if (buf != tvgit.pszText) COMCTL32_Free(buf); else mustFree = TRUE; 4393 text = tvgit.pszText; 4394 } else 4395 { 4396 text = (WCHAR*)COMCTL32_Alloc(tvgit.cchTextMax*sizeof(WCHAR)); 4397 mustFree = TRUE; 4398 lstrcpyAtoW(text,(LPSTR)tvgit.pszText); 4399 COMCTL32_Free(buf); 4400 } 4401 } else 4402 { 4403 TREEVIEW_UpdateDispInfo(infoPtr,item,TVIF_TEXT); 4404 text = item->pszText; 4405 } 4406 4407 infoPtr->tipItem = item; 4408 SetTimer(infoPtr->hwnd,TV_INFOTIP_TIMER,TV_INFOTIP_DELAY,0); 4409 infoPtr->Timer |= TV_INFOTIP_TIMER_SET; 4410 4411 ti.cbSize = sizeof(ti); 4412 ti.uId = 0; 4413 ti.hwnd = infoPtr->hwnd; 4414 ti.hinst = 0; 4415 ti.lpszText = text; 4416 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 4417 pt.x = item->textOffset; 4418 pt.y = item->rect.top; 4419 ClientToScreen(infoPtr->hwnd,&pt); 4420 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKPOSITION,0,(LPARAM)MAKELPARAM(pt.x,pt.y)); 4421 SendMessageA(infoPtr->hwndToolTip,TTM_UPDATETIPTEXTW,0,(LPARAM)&ti); 4422 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti); 4423 4424 if (mustFree) COMCTL32_Free(text); 4425 } 4426 4427 VOID TREEVIEW_HideInfoTip(TREEVIEW_INFO *infoPtr) 4428 { 4429 if (infoPtr->tipItem) 4430 { 4431 TTTOOLINFOA ti; 4432 4433 infoPtr->tipItem = 0; 4434 KillTimer(infoPtr->hwnd,TV_INFOTIP_TIMER); 4435 infoPtr->Timer &= ~TV_INFOTIP_TIMER_SET; 4436 4437 ti.cbSize = sizeof(TTTOOLINFOA); 4438 ti.uId = 0; 4439 ti.hwnd = (UINT)infoPtr->hwnd; 4440 4441 SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)FALSE,(LPARAM)&ti); 4442 } 4443 } 4444 4445 static VOID TREEVIEW_CheckInfoTip(TREEVIEW_INFO *infoPtr) 4446 { 4447 HTREEITEM hItem; 4448 POINT pt; 4449 4450 GetCursorPos(&pt); 4451 ScreenToClient(infoPtr->hwnd,&pt); 4452 hItem = TREEVIEW_GetInfoTipItem(infoPtr,pt); 4453 4454 if (hItem != infoPtr->tipItem) 4455 TREEVIEW_HideInfoTip(infoPtr); 4456 } 4457 4458 HTREEITEM TREEVIEW_GetHottrackItem(TREEVIEW_INFO *infoPtr,POINT pt) 4459 { 4460 TVHITTESTINFO ht; 4461 4462 ht.pt = pt; 4463 TREEVIEW_HitTest(infoPtr,&ht,FALSE); 4464 4465 return (ht.hItem && (ht.flags & TVHT_ONITEM)) ? ht.hItem:0; 4466 } 4467 4468 static LRESULT TREEVIEW_MouseMove(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4469 { 4470 POINT pt; 4471 4472 pt.x = (INT)LOWORD(lParam); 4473 pt.y = (INT)HIWORD(lParam); 4474 4475 if (infoPtr->hwndToolTip) 4476 { 4477 HTREEITEM hItem = TREEVIEW_GetInfoTipItem(infoPtr,pt); 4478 4479 if (infoPtr->tipItem != hItem) 4480 { 4481 if (hItem) 4676 4482 { 4677 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect ); 4678 } else if ((INT)prevItem->parent) 4483 TREEVIEW_ITEM *item = hItem; 4484 4485 TREEVIEW_ShowInfoTip(infoPtr,item); 4486 } else TREEVIEW_HideInfoTip(infoPtr); 4487 } 4488 } 4489 4490 if (infoPtr->dwStyle & TVS_TRACKSELECT) 4491 { 4492 HTREEITEM hItem = TREEVIEW_GetHottrackItem(infoPtr,pt); 4493 4494 if (infoPtr->hotItem != hItem) 4495 { 4496 TREEVIEW_ITEM *item; 4497 HDC hdc = 0; 4498 4499 item = infoPtr->hotItem; 4500 if (TREEVIEW_ValidItem(infoPtr,infoPtr->hotItem)) 4679 4501 { 4680 newItem = (& infoPtr->items[(INT)prevItem->parent]); 4681 4682 hNewSelection = newItem->hItem; //CB: what does Win32??? Please not the Corel hack!!! 4502 if (!hdc) hdc = GetDC(infoPtr->hwnd); 4503 TREEVIEW_DrawHottrackLine(hdc,item); 4683 4504 } 4684 4685 break; 4686 4687 case VK_RIGHT: 4688 if (TREEVIEW_HasChildren(hwnd, prevItem)) 4505 if (hItem) 4689 4506 { 4690 if (!(prevItem->state & TVIS_EXPANDED)) 4691 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect ); 4692 else 4693 { 4694 newItem = (& infoPtr->items[(INT)prevItem->firstChild]); 4695 hNewSelection = newItem->hItem; 4696 } 4507 item = hItem; 4508 if (item) 4509 { 4510 if (!hdc) hdc = GetDC(infoPtr->hwnd); 4511 TREEVIEW_DrawHottrackLine(hdc,item); 4512 } 4697 4513 } 4698 4699 break; 4700 4701 case VK_ADD: 4702 if (!(prevItem->state & TVIS_EXPANDED)) 4703 TREEVIEW_Expand(hwnd, TVE_EXPAND, prevSelect ); 4704 break; 4705 4706 case VK_SUBTRACT: 4707 if (prevItem->state & TVIS_EXPANDED) 4708 TREEVIEW_Expand(hwnd, TVE_COLLAPSE, prevSelect ); 4709 break; 4710 4711 case VK_PRIOR: 4712 newItem=TREEVIEW_GetListItem( 4713 hwnd, 4714 infoPtr, 4715 prevItem, 4716 -1*(TREEVIEW_GetVisibleCount(hwnd,0,0)-3)); 4717 if (!newItem) 4718 newItem = prevItem; 4719 4720 hNewSelection = newItem->hItem; 4721 4722 break; 4723 4724 case VK_NEXT: 4725 newItem=TREEVIEW_GetListItem( 4726 hwnd, 4727 infoPtr, 4728 prevItem, 4729 TREEVIEW_GetVisibleCount(hwnd,0,0)-3); 4730 4731 if (!newItem) 4732 newItem = prevItem; 4733 4734 hNewSelection = newItem->hItem; 4735 4736 break; 4737 4738 case VK_RETURN: 4739 sendNotify(hwnd,NM_RETURN); 4740 break; 4741 4742 case VK_BACK: 4743 4744 default: 4745 break; 4746 } 4747 4748 if (hNewSelection) 4749 { 4750 if (TREEVIEW_DoSelectItem(hwnd,TVGN_CARET,(HTREEITEM)hNewSelection,TVC_BYKEYBOARD)) 4751 { 4752 TREEVIEW_EnsureVisible(hwnd,hNewSelection); 4753 } 4754 } 4755 4756 return FALSE; 4757 } 4758 4759 static LRESULT TREEVIEW_Char(HWND hwnd,WPARAM wParam,LPARAM lParam) 4514 if (hdc) ReleaseDC(infoPtr->hwnd,hdc); 4515 } 4516 } 4517 4518 return 0; 4519 } 4520 4521 static LRESULT TREEVIEW_SetRedraw(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4522 { 4523 if (wParam) 4524 { 4525 if (!(infoPtr->uInternalStatus & TV_NOREDRAW)) return 0; 4526 infoPtr->uInternalStatus &= ~TV_NOREDRAW; 4527 TREEVIEW_CalcItems(infoPtr); 4528 TREEVIEW_Refresh(infoPtr); 4529 } else 4530 { 4531 infoPtr->uInternalStatus |= TV_NOREDRAW; 4532 } 4533 4534 return 0; 4535 } 4536 4537 static LRESULT 4538 TREEVIEW_SysColorChange(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4539 { 4540 TREEVIEW_Refresh(infoPtr); 4541 4542 return DefWindowProcA(infoPtr->hwnd,WM_SYSCOLORCHANGE,wParam,lParam); 4543 } 4544 4545 static LRESULT TREEVIEW_Enable(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4546 { 4547 TREEVIEW_Refresh(infoPtr); 4548 4549 return DefWindowProcA(infoPtr->hwnd,WM_ENABLE,wParam,lParam); 4550 } 4551 4552 static LRESULT 4553 TREEVIEW_EraseBackground(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam) 4554 { 4555 HBRUSH hBrush = CreateSolidBrush (infoPtr->clrBk); 4556 RECT rect; 4557 4558 GetClientRect (infoPtr->hwnd, &rect); 4559 FillRect ((HDC)wParam, &rect, hBrush); 4560 DeleteObject (hBrush); 4561 4562 return TRUE; 4563 } 4564 4565 static LRESULT TREEVIEW_GetDlgCode(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4566 { 4567 return DLGC_WANTARROWS | DLGC_WANTCHARS; 4568 } 4569 4570 4571 static LRESULT TREEVIEW_Char(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4760 4572 { 4761 4573 CHAR ch = (CHAR)wParam; 4762 4574 4763 TREEVIEW_ISearch( hwnd,ch);4575 TREEVIEW_ISearch(infoPtr,ch); 4764 4576 4765 4577 return 0; 4766 4578 } 4767 4579 4768 static LRESULT 4769 TREEVIEW_GetScrollTime (HWND hwnd) 4770 { 4771 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4772 4773 return infoPtr->uScrollTime; 4774 } 4775 4776 static LRESULT 4777 TREEVIEW_SetScrollTime (HWND hwnd, UINT uScrollTime) 4778 { 4779 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4780 UINT uOldScrollTime = infoPtr->uScrollTime; 4781 4782 infoPtr->uScrollTime = min (uScrollTime, 100); 4783 4784 return uOldScrollTime; 4785 } 4786 4787 static LRESULT TREEVIEW_EnsureVisible(HWND hwnd,HTREEITEM hItem) 4788 { 4789 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4790 TREEVIEW_ITEM *item; 4791 RECT rect; 4792 INT scrollY; 4793 4794 item = TREEVIEW_ValidItem(infoPtr,hItem); 4795 4796 if (!item) return FALSE; 4797 4798 if (item && item->parent) 4799 { 4800 TREEVIEW_ITEM *parent = TREEVIEW_ValidItem(infoPtr,item->parent); 4801 4802 while (parent && !(parent->state & TVIS_EXPANDED)) 4803 { 4804 TREEVIEW_Expand(hwnd,TVE_EXPAND,(LPARAM)parent->hItem); 4805 parent = TREEVIEW_ValidItem(infoPtr,parent->parent); 4806 } 4807 } 4808 4809 TREEVIEW_UnqueueRefresh(hwnd,TRUE,TRUE); 4810 GetClientRect(hwnd,&rect); 4811 if (item->rect.top < 0) 4812 scrollY = item->rect.top; 4813 else if (item->rect.bottom > rect.bottom) 4814 { 4815 INT mod; 4816 4817 scrollY = item->rect.bottom-rect.bottom; 4818 mod = scrollY % infoPtr->uVScrollStep; 4819 if (mod) scrollY += infoPtr->uVScrollStep-mod; 4820 } else return FALSE; 4821 4822 if (scrollY != 0) 4823 { 4824 infoPtr->lefttop.y += scrollY; 4825 TREEVIEW_CalcItems(hwnd,0,infoPtr); 4826 ScrollWindowEx(hwnd,0,-scrollY,NULL,NULL,0,NULL,SW_INVALIDATE | SW_SCROLLCHILDREN | (infoPtr->uScrollTime << 16)); 4827 4828 return TRUE; 4829 } 4830 4831 return FALSE; 4832 } 4833 4834 static BOOL TREEVIEW_Compare(HWND hwnd,TREEVIEW_ITEM *item,LPWSTR text,INT textlen,BOOL *matchLast) 4835 { 4836 WCHAR* itemtext; 4837 BOOL mustFree = FALSE,res; 4580 static BOOL TREEVIEW_Compare(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,LPWSTR text,INT textlen,BOOL *matchLast) 4581 { 4582 BOOL res; 4838 4583 INT itemlen; 4839 4584 4840 if (item->pszText == LPSTR_TEXTCALLBACKW) 4841 itemtext = TREEVIEW_CallbackText(hwnd,item,&mustFree); 4842 else 4843 itemtext = item->pszText; 4844 4845 itemlen = lstrlenW(itemtext); 4585 TREEVIEW_UpdateDispInfo(infoPtr,item,TVIF_TEXT); 4586 4587 itemlen = lstrlenW(item->pszText); 4846 4588 if (itemlen < textlen) 4847 4589 { … … 4849 4591 } else 4850 4592 { 4851 res = (lstrcmpniW(item text,text,textlen) == 0);4593 res = (lstrcmpniW(item->pszText,text,textlen) == 0); 4852 4594 } 4853 4595 if (!res && matchLast) … … 4855 4597 textlen--; 4856 4598 if ((textlen > 0) && (itemlen >= textlen)) 4857 *matchLast = (lstrcmpniW(item text,text,textlen) == 0);4599 *matchLast = (lstrcmpniW(item->pszText,text,textlen) == 0); 4858 4600 else 4859 4601 *matchLast = FALSE; 4860 4602 } 4861 if (mustFree) COMCTL32_Free(itemtext);4862 4603 4863 4604 return res; 4864 4605 } 4865 4606 4866 static TREEVIEW_ITEM* TREEVIEW_Search( HWND hwnd,TREEVIEW_INFO *infoPtr,INT iItem,LPWSTR text,INT textlen,TREEVIEW_ITEM **nearest)4867 { 4868 TREEVIEW_ITEM * item,*start;4607 static TREEVIEW_ITEM* TREEVIEW_Search(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,LPWSTR text,INT textlen,TREEVIEW_ITEM **nearest) 4608 { 4609 TREEVIEW_ITEM *start; 4869 4610 BOOL bMatchLast; 4870 4611 4871 item = start = &infoPtr->items[iItem];4612 start = item; 4872 4613 if (nearest) *nearest = NULL; 4873 4614 … … 4877 4618 if (nearest) 4878 4619 { 4879 if (TREEVIEW_Compare( hwnd,item,text,textlen,(!*nearest) ? &bMatchLast:NULL))4620 if (TREEVIEW_Compare(infoPtr,item,text,textlen,(!*nearest) ? &bMatchLast:NULL)) 4880 4621 return item; 4881 4622 else if (!*nearest && bMatchLast) … … 4883 4624 } else 4884 4625 { 4885 if (TREEVIEW_Compare( hwnd,item,text,textlen,NULL))4626 if (TREEVIEW_Compare(infoPtr,item,text,textlen,NULL)) 4886 4627 return item; 4887 4628 } 4888 item = TREEVIEW_GetNextListItem(hwnd,infoPtr,item); 4889 } 4890 4891 iItem = (INT)infoPtr->TopRootItem; 4892 item = &infoPtr->items[iItem]; 4629 item = TREEVIEW_GetNextListItem(infoPtr,item); 4630 } 4631 4632 item = infoPtr->root; 4893 4633 4894 4634 //search first to start … … 4897 4637 if (nearest) 4898 4638 { 4899 if (TREEVIEW_Compare( hwnd,item,text,textlen,(!*nearest) ? &bMatchLast:NULL))4639 if (TREEVIEW_Compare(infoPtr,item,text,textlen,(!*nearest) ? &bMatchLast:NULL)) 4900 4640 return item; 4901 4641 else if (!*nearest && bMatchLast) … … 4903 4643 } else 4904 4644 { 4905 if (TREEVIEW_Compare( hwnd,item,text,textlen,NULL))4645 if (TREEVIEW_Compare(infoPtr,item,text,textlen,NULL)) 4906 4646 return item; 4907 4647 } 4908 item = TREEVIEW_GetNextListItem( hwnd,infoPtr,item);4648 item = TREEVIEW_GetNextListItem(infoPtr,item); 4909 4649 } 4910 4650 … … 4914 4654 //NOTE: sister function in listview control -> sync changes 4915 4655 4916 static VOID TREEVIEW_ISearch(HWND hwnd,CHAR ch) 4917 { 4918 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4656 static VOID TREEVIEW_ISearch(TREEVIEW_INFO *infoPtr,CHAR ch) 4657 { 4919 4658 LPWSTR newString; 4920 INT len ,iItem;4659 INT len; 4921 4660 CHAR ch2[2]; 4922 4661 TREEVIEW_ITEM *item,*nearest = NULL; … … 4956 4695 if (infoPtr->selectedItem) 4957 4696 { 4958 iItem = (INT)infoPtr->selectedItem; 4959 item = &infoPtr->items[iItem]; 4697 item = infoPtr->selectedItem; 4960 4698 4961 4699 //check if new string is valid for old selection 4962 if (TREEVIEW_Compare( hwnd,item,newString,len,NULL))4700 if (TREEVIEW_Compare(infoPtr,item,newString,len,NULL)) 4963 4701 goto ISearchDone; 4964 4702 4965 4703 //no match, continue with next item 4966 item = TREEVIEW_GetNextListItem(hwnd,infoPtr,item); 4967 if (!item) item = &infoPtr->items[(INT)infoPtr->TopRootItem]; 4968 iItem = (INT)item->hItem; 4969 } else iItem = (INT)infoPtr->TopRootItem; 4704 item = TREEVIEW_GetNextListItem(infoPtr,item); 4705 if (!item) item = infoPtr->root; 4706 } else item = infoPtr->root; 4970 4707 4971 4708 //scan 4972 item = TREEVIEW_Search( hwnd,infoPtr,iItem,newString,len,checkNearest ? &nearest:NULL);4709 item = TREEVIEW_Search(infoPtr,item,newString,len,checkNearest ? &nearest:NULL); 4973 4710 4974 4711 if (!item && nearest) 4975 4712 { 4976 TREEVIEW_SelectItem( hwnd,(WPARAM)TVGN_CARET,(LPARAM)nearest->hItem);4977 TREEVIEW_EnsureVisible( hwnd,nearest->hItem);4713 TREEVIEW_SelectItem(infoPtr,(WPARAM)TVGN_CARET,(LPARAM)nearest); 4714 TREEVIEW_EnsureVisible(infoPtr,nearest); 4978 4715 infoPtr->dwISearchTime = GetTickCount(); 4979 4716 … … 4989 4726 infoPtr->pszISearch = newString; 4990 4727 infoPtr->uISearchLen = len; 4991 TREEVIEW_SelectItem( hwnd,(WPARAM)TVGN_CARET,(LPARAM)item->hItem);4992 TREEVIEW_EnsureVisible( hwnd,item->hItem);4728 TREEVIEW_SelectItem(infoPtr,(WPARAM)TVGN_CARET,(LPARAM)item); 4729 TREEVIEW_EnsureVisible(infoPtr,item); 4993 4730 infoPtr->dwISearchTime = GetTickCount(); 4994 4731 } else … … 4999 4736 } 5000 4737 5001 static LRESULT TREEVIEW_GetISearchString(HWND hwnd,LPWSTR lpsz,BOOL unicode) 5002 { 5003 TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd); 5004 4738 static LRESULT TREEVIEW_GetISearchString(TREEVIEW_INFO *infoPtr,LPWSTR lpsz,BOOL unicode) 4739 { 5005 4740 if (infoPtr->uISearchLen == 0) return 0; 5006 4741 … … 5013 4748 } 5014 4749 5015 static LRESULT TREEVIEW_SetCursor(HWND hwnd,WPARAM wParam,LPARAM lParam) 5016 { 5017 sendNotify(hwnd,NM_SETCURSOR); //CB: todo: result 5018 5019 return DefWindowProcA(hwnd,WM_SETCURSOR,wParam,lParam); 4750 static LRESULT TREEVIEW_SetCursor(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam) 4751 { 4752 sendNotify(infoPtr->hwnd,NM_SETCURSOR); //CB: todo: result 4753 4754 return DefWindowProcA(infoPtr->hwnd,WM_SETCURSOR,wParam,lParam); 4755 } 4756 4757 static LRESULT TREEVIEW_NCCreate(HWND hwnd,WPARAM wParam,LPARAM lParam) 4758 { 4759 DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE),oldStyle = dwStyle; 4760 4761 dwStyle &= ~(WS_HSCROLL | WS_VSCROLL); 4762 if (dwStyle != oldStyle) SetWindowLongA(hwnd,GWL_STYLE,dwStyle); 4763 4764 return DefWindowProcA(hwnd,WM_NCCREATE,wParam,lParam); 5020 4765 } 5021 4766 … … 5023 4768 TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) 5024 4769 { 5025 if (uMsg == WM_CREATE) 5026 return TREEVIEW_Create (hwnd, wParam, lParam); 5027 5028 if (!TREEVIEW_GetInfoPtr(hwnd)) 5029 return DefWindowProcA (hwnd, uMsg, wParam, lParam); 4770 TREEVIEW_INFO *infoPtr; 4771 4772 if (uMsg == WM_NCCREATE) 4773 { 4774 return TREEVIEW_NCCreate(hwnd,wParam,lParam); 4775 } else if (uMsg == WM_CREATE) 4776 { 4777 return TREEVIEW_Create(hwnd, wParam, lParam); 4778 } 4779 4780 infoPtr = TREEVIEW_GetInfoPtr(hwnd); 4781 if (infoPtr) TREEVIEW_VerifyTree(infoPtr); else goto def; 5030 4782 5031 4783 switch (uMsg) 5032 4784 { 5033 4785 case TVM_INSERTITEMA: 5034 return TREEVIEW_InsertItem( hwnd,wParam,lParam,FALSE);4786 return TREEVIEW_InsertItem(infoPtr,wParam,lParam,FALSE); 5035 4787 5036 4788 case TVM_INSERTITEMW: 5037 return TREEVIEW_InsertItem( hwnd,wParam,lParam,TRUE);4789 return TREEVIEW_InsertItem(infoPtr,wParam,lParam,TRUE); 5038 4790 5039 4791 case TVM_DELETEITEM: 5040 return TREEVIEW_DeleteItem (hwnd, wParam,lParam);4792 return TREEVIEW_DeleteItem(infoPtr,wParam,lParam); 5041 4793 5042 4794 case TVM_EXPAND: 5043 return TREEVIEW_Expand (hwnd, wParam,lParam);4795 return TREEVIEW_ExpandMsg(infoPtr,wParam,lParam); 5044 4796 5045 4797 case TVM_GETITEMRECT: 5046 return TREEVIEW_GetItemRect (hwnd, wParam,lParam);4798 return TREEVIEW_GetItemRect(infoPtr,wParam,lParam); 5047 4799 5048 4800 case TVM_GETCOUNT: 5049 return TREEVIEW_GetCount (hwnd, wParam,lParam);4801 return TREEVIEW_GetCount(infoPtr,wParam,lParam); 5050 4802 5051 4803 case TVM_GETINDENT: 5052 return TREEVIEW_GetIndent (hwnd);4804 return TREEVIEW_GetIndent(infoPtr); 5053 4805 5054 4806 case TVM_SETINDENT: 5055 return TREEVIEW_SetIndent (hwnd,wParam);4807 return TREEVIEW_SetIndent(infoPtr,wParam); 5056 4808 5057 4809 case TVM_GETIMAGELIST: 5058 return TREEVIEW_GetImageList (hwnd, wParam,lParam);4810 return TREEVIEW_GetImageList(infoPtr,wParam,lParam); 5059 4811 5060 4812 case TVM_SETIMAGELIST: 5061 return TREEVIEW_SetImageList ( hwnd, wParam, lParam);4813 return TREEVIEW_SetImageList (infoPtr, wParam, lParam); 5062 4814 5063 4815 case TVM_GETNEXTITEM: 5064 return TREEVIEW_GetNextItem ( hwnd, wParam, lParam);4816 return TREEVIEW_GetNextItem (infoPtr, wParam, lParam); 5065 4817 5066 4818 case TVM_SELECTITEM: 5067 return TREEVIEW_SelectItem ( hwnd, wParam, lParam);4819 return TREEVIEW_SelectItem (infoPtr, wParam, lParam); 5068 4820 5069 4821 case TVM_GETITEMA: 5070 return TREEVIEW_GetItem( hwnd,wParam,lParam,FALSE);4822 return TREEVIEW_GetItem(infoPtr,wParam,lParam,FALSE); 5071 4823 5072 4824 case TVM_GETITEMW: 5073 return TREEVIEW_GetItem( hwnd,wParam,lParam,TRUE);4825 return TREEVIEW_GetItem(infoPtr,wParam,lParam,TRUE); 5074 4826 5075 4827 case TVM_SETITEMA: 5076 return TREEVIEW_SetItem( hwnd,wParam,lParam,FALSE);4828 return TREEVIEW_SetItem(infoPtr,wParam,lParam,FALSE); 5077 4829 5078 4830 case TVM_SETITEMW: 5079 return TREEVIEW_SetItem( hwnd,wParam,lParam,TRUE);4831 return TREEVIEW_SetItem(infoPtr,wParam,lParam,TRUE); 5080 4832 5081 4833 case TVM_EDITLABELA: 5082 return TREEVIEW_EditLabel( hwnd,(HTREEITEM)lParam,FALSE);4834 return TREEVIEW_EditLabel(infoPtr,(HTREEITEM)lParam,FALSE); 5083 4835 5084 4836 case TVM_EDITLABELW: 5085 return TREEVIEW_EditLabel( hwnd,(HTREEITEM)lParam,TRUE);4837 return TREEVIEW_EditLabel(infoPtr,(HTREEITEM)lParam,TRUE); 5086 4838 5087 4839 case TVM_GETEDITCONTROL: 5088 return TREEVIEW_GetEditControl ( hwnd);4840 return TREEVIEW_GetEditControl (infoPtr); 5089 4841 5090 4842 case TVM_GETVISIBLECOUNT: 5091 return TREEVIEW_GetVisibleCount ( hwnd, wParam, lParam);4843 return TREEVIEW_GetVisibleCount (infoPtr); 5092 4844 5093 4845 case TVM_HITTEST: 5094 return TREEVIEW_HitTest( hwnd,(LPTVHITTESTINFO)lParam,FALSE);4846 return TREEVIEW_HitTest(infoPtr,(LPTVHITTESTINFO)lParam,FALSE); 5095 4847 5096 4848 case TVM_CREATEDRAGIMAGE: 5097 return TREEVIEW_CreateDragImage ( hwnd, wParam, lParam);4849 return TREEVIEW_CreateDragImage (infoPtr, wParam, lParam); 5098 4850 5099 4851 case TVM_SORTCHILDREN: 5100 return TREEVIEW_SortChildren( hwnd, wParam, lParam);4852 return TREEVIEW_SortChildren(infoPtr, wParam, lParam); 5101 4853 5102 4854 case TVM_ENSUREVISIBLE: 5103 return TREEVIEW_EnsureVisible( hwnd,(HTREEITEM)lParam);4855 return TREEVIEW_EnsureVisible(infoPtr,(HTREEITEM)lParam); 5104 4856 5105 4857 case TVM_SORTCHILDRENCB: 5106 return TREEVIEW_SortChildrenCB( hwnd, wParam, lParam);4858 return TREEVIEW_SortChildrenCB(infoPtr, wParam, lParam); 5107 4859 5108 4860 case TVM_ENDEDITLABELNOW: 5109 return TREEVIEW_EndEditLabelNow ( hwnd,(BOOL)wParam);4861 return TREEVIEW_EndEditLabelNow (infoPtr,(BOOL)wParam); 5110 4862 5111 4863 case TVM_GETISEARCHSTRINGA: 5112 return TREEVIEW_GetISearchString( hwnd,(LPWSTR)lParam,FALSE);4864 return TREEVIEW_GetISearchString(infoPtr,(LPWSTR)lParam,FALSE); 5113 4865 5114 4866 case TVM_GETISEARCHSTRINGW: 5115 return TREEVIEW_GetISearchString( hwnd,(LPWSTR)lParam,TRUE);4867 return TREEVIEW_GetISearchString(infoPtr,(LPWSTR)lParam,TRUE); 5116 4868 5117 4869 case TVM_GETTOOLTIPS: 5118 return TREEVIEW_GetToolTips ( hwnd);4870 return TREEVIEW_GetToolTips (infoPtr); 5119 4871 5120 4872 case TVM_SETTOOLTIPS: 5121 return TREEVIEW_SetToolTips ( hwnd, wParam);4873 return TREEVIEW_SetToolTips (infoPtr, wParam); 5122 4874 5123 4875 case TVM_SETINSERTMARK: 5124 return TREEVIEW_SetInsertMark ( hwnd,wParam, lParam);4876 return TREEVIEW_SetInsertMark (infoPtr,wParam, lParam); 5125 4877 5126 4878 case TVM_SETITEMHEIGHT: 5127 return TREEVIEW_SetItemHeight ( hwnd, wParam);4879 return TREEVIEW_SetItemHeight (infoPtr, wParam); 5128 4880 5129 4881 case TVM_GETITEMHEIGHT: 5130 return TREEVIEW_GetItemHeight ( hwnd);4882 return TREEVIEW_GetItemHeight (infoPtr); 5131 4883 5132 4884 case TVM_SETBKCOLOR: 5133 return TREEVIEW_SetBkColor ( hwnd, wParam, lParam);4885 return TREEVIEW_SetBkColor (infoPtr, wParam, lParam); 5134 4886 5135 4887 case TVM_SETTEXTCOLOR: 5136 return TREEVIEW_SetTextColor ( hwnd, wParam, lParam);4888 return TREEVIEW_SetTextColor (infoPtr, wParam, lParam); 5137 4889 5138 4890 case TVM_GETBKCOLOR: 5139 return TREEVIEW_GetBkColor ( hwnd);4891 return TREEVIEW_GetBkColor (infoPtr); 5140 4892 5141 4893 case TVM_GETTEXTCOLOR: 5142 return TREEVIEW_GetTextColor ( hwnd);4894 return TREEVIEW_GetTextColor (infoPtr); 5143 4895 5144 4896 case TVM_SETSCROLLTIME: 5145 return TREEVIEW_SetScrollTime ( hwnd, (UINT)wParam);4897 return TREEVIEW_SetScrollTime (infoPtr, (UINT)wParam); 5146 4898 5147 4899 case TVM_GETSCROLLTIME: 5148 return TREEVIEW_GetScrollTime ( hwnd);4900 return TREEVIEW_GetScrollTime (infoPtr); 5149 4901 5150 4902 case TVM_GETITEMSTATE: 5151 return TREEVIEW_GetItemState ( hwnd,wParam, lParam);4903 return TREEVIEW_GetItemState (infoPtr,wParam, lParam); 5152 4904 5153 4905 case TVM_GETLINECOLOR: 5154 return TREEVIEW_GetLineColor ( hwnd,wParam, lParam);4906 return TREEVIEW_GetLineColor (infoPtr,wParam, lParam); 5155 4907 5156 4908 case TVM_SETLINECOLOR: 5157 return TREEVIEW_SetLineColor ( hwnd,wParam, lParam);4909 return TREEVIEW_SetLineColor (infoPtr,wParam, lParam); 5158 4910 5159 4911 case TVM_SETINSERTMARKCOLOR: 5160 return TREEVIEW_SetInsertMarkColor ( hwnd,wParam, lParam);4912 return TREEVIEW_SetInsertMarkColor (infoPtr,wParam, lParam); 5161 4913 5162 4914 case TVM_GETINSERTMARKCOLOR: 5163 return TREEVIEW_GetInsertMarkColor ( hwnd,wParam, lParam);4915 return TREEVIEW_GetInsertMarkColor (infoPtr,wParam, lParam); 5164 4916 5165 4917 case WM_COMMAND: 5166 return TREEVIEW_Command ( hwnd, wParam, lParam);4918 return TREEVIEW_Command (infoPtr, wParam, lParam); 5167 4919 5168 4920 case WM_DESTROY: 5169 return TREEVIEW_Destroy ( hwnd);4921 return TREEVIEW_Destroy (infoPtr); 5170 4922 5171 4923 case WM_ENABLE: 5172 return TREEVIEW_Enable( hwnd,wParam,lParam);4924 return TREEVIEW_Enable(infoPtr,wParam,lParam); 5173 4925 5174 4926 case WM_ERASEBKGND: 5175 return TREEVIEW_EraseBackground ( hwnd, wParam, lParam);4927 return TREEVIEW_EraseBackground (infoPtr, wParam, lParam); 5176 4928 5177 4929 case WM_GETDLGCODE: 5178 return TREEVIEW_GetDlgCode( hwnd,wParam,lParam);4930 return TREEVIEW_GetDlgCode(infoPtr,wParam,lParam); 5179 4931 5180 4932 case WM_PAINT: 5181 return TREEVIEW_Paint ( hwnd, wParam, lParam);4933 return TREEVIEW_Paint (infoPtr, wParam, lParam); 5182 4934 5183 4935 case WM_GETFONT: 5184 return TREEVIEW_GetFont ( hwnd, wParam, lParam);4936 return TREEVIEW_GetFont (infoPtr, wParam, lParam); 5185 4937 5186 4938 case WM_SETFONT: 5187 return TREEVIEW_SetFont ( hwnd, wParam, lParam);4939 return TREEVIEW_SetFont (infoPtr, wParam, lParam); 5188 4940 5189 4941 case WM_KEYDOWN: 5190 return TREEVIEW_KeyDown ( hwnd, wParam, lParam);4942 return TREEVIEW_KeyDown (infoPtr, wParam, lParam); 5191 4943 5192 4944 case WM_CHAR: 5193 return TREEVIEW_Char( hwnd,wParam,lParam);4945 return TREEVIEW_Char(infoPtr,wParam,lParam); 5194 4946 5195 4947 case WM_SETFOCUS: 5196 return TREEVIEW_SetFocus ( hwnd, wParam, lParam);4948 return TREEVIEW_SetFocus (infoPtr, wParam, lParam); 5197 4949 5198 4950 case WM_KILLFOCUS: 5199 return TREEVIEW_KillFocus ( hwnd, wParam, lParam);4951 return TREEVIEW_KillFocus (infoPtr, wParam, lParam); 5200 4952 5201 4953 case WM_MOUSEMOVE: 5202 return TREEVIEW_MouseMove( hwnd,wParam,lParam);4954 return TREEVIEW_MouseMove(infoPtr,wParam,lParam); 5203 4955 5204 4956 case WM_LBUTTONDOWN: 5205 return TREEVIEW_LButtonDown ( hwnd, wParam, lParam);4957 return TREEVIEW_LButtonDown (infoPtr, wParam, lParam); 5206 4958 5207 4959 case WM_LBUTTONDBLCLK: 5208 return TREEVIEW_LButtonDoubleClick ( hwnd, wParam, lParam);4960 return TREEVIEW_LButtonDoubleClick (infoPtr, wParam, lParam); 5209 4961 5210 4962 case WM_RBUTTONDOWN: 5211 return TREEVIEW_RButtonDown ( hwnd, wParam, lParam);4963 return TREEVIEW_RButtonDown (infoPtr, wParam, lParam); 5212 4964 5213 4965 case WM_RBUTTONDBLCLK: 5214 return TREEVIEW_RButtonDoubleClick( hwnd,wParam,lParam);4966 return TREEVIEW_RButtonDoubleClick(infoPtr,wParam,lParam); 5215 4967 5216 4968 case WM_STYLECHANGED: 5217 return TREEVIEW_StyleChanged ( hwnd, wParam, lParam);4969 return TREEVIEW_StyleChanged (infoPtr, wParam, lParam); 5218 4970 5219 4971 case WM_SYSCOLORCHANGE: 5220 return TREEVIEW_SysColorChange( hwnd,wParam,lParam);4972 return TREEVIEW_SysColorChange(infoPtr,wParam,lParam); 5221 4973 5222 4974 case WM_SETCURSOR: 5223 return TREEVIEW_SetCursor( hwnd,wParam,lParam);4975 return TREEVIEW_SetCursor(infoPtr,wParam,lParam); 5224 4976 5225 4977 case WM_SETREDRAW: 5226 return TREEVIEW_SetRedraw( hwnd,wParam,lParam);4978 return TREEVIEW_SetRedraw(infoPtr,wParam,lParam); 5227 4979 5228 4980 case WM_TIMER: 5229 return TREEVIEW_HandleTimer ( hwnd, wParam, lParam);4981 return TREEVIEW_HandleTimer (infoPtr, wParam, lParam); 5230 4982 5231 4983 case WM_SIZE: 5232 return TREEVIEW_Size ( hwnd, wParam,lParam);4984 return TREEVIEW_Size (infoPtr, wParam,lParam); 5233 4985 5234 4986 case WM_HSCROLL: 5235 return TREEVIEW_HScroll ( hwnd, wParam, lParam);4987 return TREEVIEW_HScroll (infoPtr, wParam, lParam); 5236 4988 5237 4989 case WM_VSCROLL: 5238 return TREEVIEW_VScroll ( hwnd, wParam, lParam);4990 return TREEVIEW_VScroll (infoPtr, wParam, lParam); 5239 4991 5240 4992 case WM_MOUSEWHEEL: 5241 return TREEVIEW_MouseWheel ( hwnd, wParam, lParam);4993 return TREEVIEW_MouseWheel (infoPtr, wParam, lParam); 5242 4994 5243 4995 case WM_DRAWITEM: … … 5246 4998 5247 4999 default: 5000 def: 5248 5001 return defComCtl32ProcA(hwnd,uMsg,wParam,lParam); 5249 5002 } … … 5251 5004 } 5252 5005 5006 /* Tree Verification ****************************************************/ 5007 5008 #ifndef NDEBUG 5009 static inline void 5010 TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item); 5011 5012 static inline void TREEVIEW_VerifyItemCommon(TREEVIEW_INFO *infoPtr, 5013 TREEVIEW_ITEM *item) 5014 { 5015 TREEVIEW_WriteVerify("TV: checking infoPtr"); 5016 assert(infoPtr != NULL); 5017 TREEVIEW_WriteVerify("TV: checking item"); 5018 assert(item != NULL); 5019 5020 /* both NULL, or both non-null */ 5021 TREEVIEW_WriteVerify("TV: checking firstChild,lastChild"); 5022 assert((item->firstChild == NULL) == (item->lastChild == NULL)); 5023 5024 TREEVIEW_WriteVerify("TV: checking firstChild,lastChild != item"); 5025 assert(item->firstChild != item); 5026 assert(item->lastChild != item); 5027 5028 TREEVIEW_WriteVerify("TV: checking firstChild"); 5029 if (item->firstChild) 5030 { 5031 assert(item->firstChild->parent == item); 5032 assert(item->firstChild->prevSibling == NULL); 5033 } 5034 5035 TREEVIEW_WriteVerify("TV: checking lastChild"); 5036 if (item->lastChild) 5037 { 5038 TREEVIEW_WriteVerify("TV: checking lastChild->parent"); 5039 assert(item->lastChild->parent == item); 5040 TREEVIEW_WriteVerify("TV: checking lastChild->nextSibling"); 5041 assert(item->lastChild->nextSibling == NULL); 5042 } 5043 5044 TREEVIEW_WriteVerify("TV: checking nextSibling"); 5045 assert(item->nextSibling != item); 5046 if (item->nextSibling) 5047 { 5048 assert(item->nextSibling->parent == item->parent); 5049 assert(item->nextSibling->prevSibling == item); 5050 } 5051 5052 TREEVIEW_WriteVerify("TV: checking prevSibling"); 5053 assert(item->prevSibling != item); 5054 if (item->prevSibling) 5055 { 5056 assert(item->prevSibling->parent == item->parent); 5057 assert(item->prevSibling->nextSibling == item); 5058 } 5059 } 5060 5061 static inline void 5062 TREEVIEW_VerifyItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 5063 { 5064 TREEVIEW_WriteVerify("TV: checking item"); 5065 assert(item != NULL); 5066 5067 TREEVIEW_WriteVerify("TV: checking parent, iLevel"); 5068 assert(item->parent != NULL); 5069 assert(item->parent != item); 5070 assert(item->iLevel == item->parent->iLevel + 1); 5071 5072 TREEVIEW_WriteVerify("TV: checking PtrIndex"); 5073 assert(DPA_GetPtrIndex(infoPtr->items, item) != -1); 5074 5075 TREEVIEW_VerifyItemCommon(infoPtr, item); 5076 5077 TREEVIEW_VerifyChildren(infoPtr, item); 5078 } 5079 5080 static inline void 5081 TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item) 5082 { 5083 TREEVIEW_ITEM *child; 5084 assert(item != NULL); 5085 5086 for (child = item->firstChild; child != NULL; child = child->nextSibling) 5087 TREEVIEW_VerifyItem(infoPtr, child); 5088 } 5089 5090 static inline void 5091 TREEVIEW_VerifyRoot(TREEVIEW_INFO *infoPtr) 5092 { 5093 TREEVIEW_ITEM *root = infoPtr->root; 5094 5095 TREEVIEW_WriteVerify("TV: checking root"); 5096 assert(root != NULL); 5097 TREEVIEW_WriteVerify("TV: checking iLevel"); 5098 assert(root->iLevel == -1); 5099 TREEVIEW_WriteVerify("TV: checking parent"); 5100 assert(root->parent == NULL); 5101 TREEVIEW_WriteVerify("TV: checking prevSibling"); 5102 assert(root->prevSibling == NULL); 5103 5104 TREEVIEW_VerifyItemCommon(infoPtr, root); 5105 5106 TREEVIEW_VerifyChildren(infoPtr, root); 5107 } 5108 5109 static void 5110 TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr) 5111 { 5112 TREEVIEW_WriteVerify("TV: checking infoPtr"); 5113 assert(infoPtr != NULL); 5114 5115 TREEVIEW_VerifyRoot(infoPtr); 5116 } 5117 #endif 5118 5119 /* Class Registration ***************************************************/ 5253 5120 5254 5121 VOID TREEVIEW_Register (VOID)
Note:
See TracChangeset
for help on using the changeset viewer.