Changeset 3585 for trunk/src


Ignore:
Timestamp:
May 22, 2000, 7:25:13 PM (25 years ago)
Author:
cbratschi
Message:

merged with Corel WINE 20000513, added new DPA_* functions

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:33 cbratschi Exp $ */
     1/* $Id: animate.cpp,v 1.3 2000-05-22 17:25:06 cbratschi Exp $ */
    22/*
    33 * Animation control
     
    88 * Copyright 1999 Christoph Bratschi
    99 *
    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)
    1117 * Version: 5.00
    1218 */
     19
     20/*
     21 - Corel WINE 20000513 level
     22*/
    1323
    1424#include "winbase.h"
  • trunk/src/comctl32/comboex.cpp

    r3182 r3585  
    1 /* $Id: comboex.cpp,v 1.3 2000-03-21 17:30:40 cbratschi Exp $ */
     1/* $Id: comboex.cpp,v 1.4 2000-05-22 17:25:07 cbratschi Exp $ */
    22/*
    33 * ComboBoxEx control
     
    1919 */
    2020
     21/*
     22 - Corel WINE 20000513 level
     23*/
     24
    2125#include "winbase.h"
    2226#include "commctrl.h"
     
    176180{
    177181    COMBOEX_INFO *infoPtr = COMBOEX_GetInfoPtr (hwnd);
    178 
    179 
    180     if (infoPtr->hwndCombo)
    181         DestroyWindow (infoPtr->hwndCombo);
    182 
    183 
    184 
    185182
    186183    /* free comboex info data */
  • trunk/src/comctl32/comctl32.cpp

    r3410 r3585  
    1 /* $Id: comctl32.cpp,v 1.3 2000-04-16 18:52:38 cbratschi Exp $ */
     1/* $Id: comctl32.cpp,v 1.4 2000-05-22 17:25:07 cbratschi Exp $ */
    22/*
    33 * Win32 common controls implementation
     
    1313
    1414/*
    15  - Corel 20000212 level
    16  - WINE 20000130 level (commctrl.c)
     15 - Corel 20000513 level
     16 - (WINE 20000130 level (commctrl.c))
    1717*/
    1818
  • trunk/src/comctl32/comctl32undoc.cpp

    r3385 r3585  
    1 /* $Id: comctl32undoc.cpp,v 1.3 2000-04-15 14:22:11 cbratschi Exp $ */
     1/* $Id: comctl32undoc.cpp,v 1.4 2000-05-22 17:25:07 cbratschi Exp $ */
    22/*
    33 * Undocumented functions from COMCTL32.DLL
     
    1313
    1414/*
    15  - Corel 20000317 level
     15 - Corel 20000513 level
    1616 - (WINE 20000130 level)
    1717*/
     
    12771277        hdpa->ptrs =
    12781278            (LPVOID*)HeapAlloc (hdpa->hHeap, HEAP_ZERO_MEMORY,
    1279                                 2 * hdpa->nGrow * sizeof(LPVOID));
     1279                                hdpa->nGrow * sizeof(LPVOID));
    12801280        if (!hdpa->ptrs)
    12811281            return -1;
    1282         hdpa->nMaxCount = hdpa->nGrow * 2;
     1282        hdpa->nMaxCount = hdpa->nGrow;
    12831283        nIndex = 0;
    12841284    }
    12851285    else {
    1286         if (hdpa->nItemCount >= hdpa->nMaxCount) {
     1286        if (hdpa->nItemCount == hdpa->nMaxCount) {
    12871287//          TRACE (commctrl, "-- resizing\n");
    12881288            nNewItems = hdpa->nMaxCount + hdpa->nGrow;
     
    13501350        if (hdpa->nMaxCount > i) {
    13511351            /* within the allocated space, set a new boundary */
    1352             hdpa->nItemCount = i;
     1352            hdpa->nItemCount = i+1;
    13531353        }
    13541354        else {
    13551355            /* resize the block of memory */
    13561356            INT nNewItems =
    1357                 hdpa->nGrow * ((INT)(((i+1) - 1) / hdpa->nGrow) + 1);
     1357                hdpa->nGrow * (((i+1) / hdpa->nGrow) + 1);
    13581358            INT nSize = nNewItems * sizeof(LPVOID);
    13591359
     
    14131413
    14141414    hdpa->nItemCount --;
     1415    hdpa->ptrs[hdpa->nItemCount] = NULL;
    14151416
    14161417    /* 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;
    14191420
    14201421        nSize = nNewItems * sizeof(LPVOID);
     
    17051706    return hdpa;
    17061707}
    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 */
     1723HRESULT WINAPI
     1724DPA_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 */
     1819HRESULT WINAPI
     1820DPA_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
    17081827/**************************************************************************
    17091828 * Notification functions
  • trunk/src/comctl32/datetime.cpp

    r2895 r3585  
    1 /* $Id: datetime.cpp,v 1.2 2000-02-25 17:00:15 cbratschi Exp $ */
     1/* $Id: datetime.cpp,v 1.3 2000-05-22 17:25:07 cbratschi Exp $ */
    22/*
    33 * Date and time picker control
     
    1515 */
    1616
    17 /* WINE 20000130 level */
     17/* WINE 20000513 level */
    1818
    1919#include "winbase.h"
     
    2828#define DATETIME_GetInfoPtr(hwnd) ((DATETIME_INFO*)getInfoPtr(hwnd))
    2929
    30 static char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
    31                        "Thursday", "Friday", "Saturday", NULL};
    32 
    33 static char *monthtxt[] = {"January", "February", "March", "April", "May",
    34                            "June", "July", "August", "September", "October",
    35                            "November", "December"};
     30static const char *days[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
     31                            "Thursday", "Friday", "Saturday", NULL};
     32
     33static const char *monthtxt[] = {"January", "February", "March", "April", "May",
     34                                 "June", "July", "August", "September", "October",
     35                                 "November", "December"};
    3636
    3737static LRESULT
  • trunk/src/comctl32/header.cpp

    r3420 r3585  
    1 /* $Id: header.cpp,v 1.10 2000-04-18 16:02:37 cbratschi Exp $ */
     1/* $Id: header.cpp,v 1.11 2000-05-22 17:25:08 cbratschi Exp $ */
    22/*
    33 *  Header control
     
    1717/*
    1818 Most identical with:
    19  - Corel 20000317 level
     19 - Corel 20000513 level
    2020*/
    2121
  • trunk/src/comctl32/listview.cpp

    r3520 r3585  
    1 /*$Id: listview.cpp,v 1.18 2000-05-10 19:50:32 cbratschi Exp $*/
     1/*$Id: listview.cpp,v 1.19 2000-05-22 17:25:08 cbratschi Exp $*/
    22/*
    33 * Listview control
     
    5050/*
    5151 Most identical with:
    52  - Corel 20000317 level
     52 - Corel 20000513 level
    5353 - (WINE 20000130 level)
    5454*/
     
    831831}
    832832
     833static 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
    833847/***
    834848 * DESCRIPTION:
     
    851865  for (i = nFirst; i <= nLast; i++)
    852866  {
    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    }
    854871  }
    855872
    856873  LISTVIEW_SetItemFocus(hwnd, nItem);
    857   infoPtr->nSelectionMark = nItem;
    858874}
    859875
     
    873889  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO *)LISTVIEW_GetInfoPtr(hwnd);
    874890
    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  }
    876895
    877896  LISTVIEW_SetItemFocus(hwnd, nItem);
    878   infoPtr->nSelectionMark = nItem;
    879897}
    880898
     
    894912{
    895913  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  {
    906926    bResult = TRUE;
    907   }
    908 
    909   LISTVIEW_SetItemFocus(hwnd, nItem);
     927    state = LVIS_SELECTED;
     928  }
    910929  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  }
    911939
    912940  return bResult;
     
    970998      if ((i < nFirst) || (i > nLast))
    971999      {
    972         LISTVIEW_SetItemState(hwnd,i,0,LVIS_SELECTED);
     1000        if (LISTVIEW_IsItemSelected(infoPtr,i))
     1001        {
     1002          LISTVIEW_SetItemState(hwnd,i,0,LVIS_SELECTED);
     1003        }
    9731004      }
    9741005      else
    9751006      {
    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
    9791018  }
    9801019  else
     
    9911030    rcSel.bottom = max(ptSelMark.y, ptItem.y) + infoPtr->nItemHeight;
    9921031    LISTVIEW_SetSelectionRect(hwnd, rcSel);
    993   }
    994 
    995   LISTVIEW_SetItemFocus(hwnd, nItem);
     1032    LISTVIEW_SetItemFocus(hwnd, nItem);
     1033  }
    9961034}
    9971035
     
    36393677              if (isUnicodeNotify(&infoPtr->header))
    36403678              {
    3641                 Str_SetPtrW(&lpItemData->pszText,dispInfo.item.pszText);
     3679                Str_SetPtrW(&lpItemData->pszText,(dispInfo.item.pszText == LPSTR_TEXTCALLBACKW) ? NULL:dispInfo.item.pszText);
    36423680              } else
    36433681              {
    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;
    36453683
    36463684                if (lpItemData->pszText != LPSTR_TEXTCALLBACKW) COMCTL32_Free(lpItemData->pszText);
     
    36543692            }
    36553693            /* Make sure the source string is valid */
    3656             if (!dispInfo.item.pszText)
     3694            if (!dispInfo.item.pszText || (dispInfo.item.pszText == LPSTR_TEXTCALLBACKW))
    36573695            {
    36583696              if (!internal)
     
    64866524  INT maxY = infoPtr->maxScroll.y-infoPtr->scrollPage.y,oldY = infoPtr->lefttop.y;
    64876525
     6526  if (infoPtr->hwndEdit)
     6527  {
     6528    SendMessageA(infoPtr->hwndEdit, WM_KILLFOCUS, 0, 0);
     6529  }
     6530
    64886531  switch (nScrollCode)
    64896532  {
     
    65676610  LISTVIEW_INFO *infoPtr = (LISTVIEW_INFO*)LISTVIEW_GetInfoPtr(hwnd);
    65686611  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  }
    65696617
    65706618  switch (nScrollCode)
     
    67436791    break;
    67446792
     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
    67456805  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;
    67516815    break;
    67526816  }
     
    70117075  sendNotify(hwnd,NM_RELEASEDCAPTURE);
    70127076
    7013   if (infoPtr->bFocus == FALSE)
     7077  if (!infoPtr->bFocus)
    70147078    SetFocus(hwnd);
    70157079
     
    70247088    if (infoPtr->dwStyle & LVS_SINGLESEL)
    70257089    {
    7026       if ((LISTVIEW_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED) && infoPtr->bDoEditLabel != TRUE)
     7090      if (LISTVIEW_IsItemSelected(infoPtr,nItem) && !infoPtr->bDoEditLabel)
    70277091        infoPtr->bDoEditLabel = TRUE;
    70287092      else
     
    70337097      if ((wKey & MK_CONTROL) && (wKey & MK_SHIFT))
    70347098      {
    7035         if (bGroupSelect != FALSE)
     7099        if (bGroupSelect)
    70367100        {
    70377101          LISTVIEW_AddGroupSelection(hwnd, nItem);
     
    70527116      else
    70537117      {
    7054         if ((LISTVIEW_GetItemState(hwnd, nItem, LVIS_SELECTED) & LVIS_SELECTED) && (infoPtr->bDoEditLabel != TRUE))
     7118        if (LISTVIEW_IsItemSelected(infoPtr,nItem) && !infoPtr->bDoEditLabel)
    70557119          infoPtr->bDoEditLabel = TRUE;
    70567120        else
  • trunk/src/comctl32/monthcal.cpp

    r3145 r3585  
    1818 */
    1919
    20 /* WINE 20000130 level */
     20/* Corel WINE 20000513 level */
    2121
    2222#include "winbase.h"
  • trunk/src/comctl32/propsheet.cpp

    r3154 r3585  
    1 /* $Id: propsheet.cpp,v 1.3 2000-03-18 16:17:26 cbratschi Exp $ */
     1/* $Id: propsheet.cpp,v 1.4 2000-05-22 17:25:10 cbratschi Exp $ */
    22/*
    33 * Property Sheets
     
    1414
    1515/*
    16  - Corel WINE 20000317 level
     16 - Corel WINE 20000513 level
    1717 - (WINE 991212 level)
    1818*/
     
    380380       EnableWindow( owner, TRUE );
    381381   }
    382    retval = dlgInfo->idResult;
     382   retval = dlgInfo->dlgExtra->idResult;
    383383#endif
    384384   DestroyWindow( hwnd );
     
    10011001  DLGTEMPLATE* pTemplate;
    10021002  HWND hwndPage;
    1003   RECT rc;
     1003
    10041004  PropPageInfo* ppInfo = psInfo->proppage;
    1005   PADDING_INFO padding;
    10061005
    10071006//  TRACE("index %d\n", index);
     
    10441043  else
    10451044  {
    1046     pTemplate->style |= WS_CHILD | DS_CONTROL;
     1045    pTemplate->style |= WS_CHILDWINDOW | DS_CONTROL;
    10471046    pTemplate->style &= ~DS_MODALFRAME;
    10481047    pTemplate->style &= ~WS_CAPTION;
     
    10661065  ppInfo[index].hwndPage = hwndPage;
    10671066
    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   else
    1078   {
    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 
    10931067  return TRUE;
    10941068}
     
    11011075static BOOL PROPSHEET_ShowPage(HWND hwndDlg, int index, PropSheetInfo * psInfo)
    11021076{
     1077  RECT rc;
     1078  PADDING_INFO padding;
     1079  UINT pageWidth,pageHeight;
     1080
    11031081  if (index == psInfo->active_page)
    11041082    {
     
    11331111  }
    11341112
    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);
    11361149
    11371150  if (!(psInfo->ppshheader->dwFlags & PSH_WIZARD))
     
    13051318  }
    13061319
     1320  EnableWindow(GetDlgItem(hwndDlg, IDC_APPLY_BUTTON), FALSE);
     1321
    13071322  if(lParam)
    13081323  {
     1324     int result = TRUE;
     1325
    13091326     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);
    13101337  }
    13111338  else if(psInfo->active_page >= 0)
     
    14511478  {
    14521479    case PSBTN_APPLYNOW:
    1453       SendMessageA(hwndDlg, WM_COMMAND, IDC_APPLY_BUTTON, 0);
     1480      PROPSHEET_Apply(hwndDlg, 0);
    14541481      break;
     1482
    14551483    case PSBTN_BACK:
    14561484      PROPSHEET_Back(hwndDlg);
    14571485      break;
     1486
    14581487    case PSBTN_CANCEL:
    1459       SendMessageA(hwndDlg, WM_COMMAND, IDCANCEL, 0);
     1488      PROPSHEET_Cancel(hwndDlg, 0);
    14601489      break;
     1490
    14611491    case PSBTN_FINISH:
    14621492      PROPSHEET_Finish(hwndDlg);
    14631493      break;
     1494
    14641495    case PSBTN_HELP:
    1465       SendMessageA(hwndDlg, WM_COMMAND, IDHELP, 0);
     1496      PROPSHEET_Help(hwndDlg);
    14661497      break;
     1498
    14671499    case PSBTN_NEXT:
    14681500      PROPSHEET_Next(hwndDlg);
    14691501      break;
     1502
    14701503    case PSBTN_OK:
    1471       SendMessageA(hwndDlg, WM_COMMAND, IDOK, 0);
     1504      PROPSHEET_Apply(hwndDlg, 1);
    14721505      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);
    14761509  }
    14771510}
     
    21852218    {
    21862219      WORD wID = LOWORD(wParam);
     2220      PropSheetInfo* psInfo = (PropSheetInfo*) GetPropA(hwnd,PropSheetInfoStr);
    21872221
    21882222      switch (wID)
     
    21902224        case IDOK:
    21912225        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);
    22192227          break;
    2220         }
    22212228
    22222229        case IDC_BACK_BUTTON:
     
    22392246          PROPSHEET_Help(hwnd);
    22402247          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          }
    22412255      }
    22422256
  • trunk/src/comctl32/status.cpp

    r3154 r3585  
    1 /* $Id: status.cpp,v 1.2 2000-03-18 16:17:29 cbratschi Exp $ */
     1/* $Id: status.cpp,v 1.3 2000-05-22 17:25:11 cbratschi Exp $ */
    22/*
    33 * Interface code to StatusWindow widget/control
     
    99 */
    1010
    11 /* WINE 990923 level */
     11/* Corel WINE 20000513 level */
    1212
    1313#include "winbase.h"
     
    918918        DeleteObject (infoPtr->hDefaultFont);
    919919
    920     /* delete tool tip control */
    921     destroyToolTip(infoPtr->hwndToolTip);
    922 
    923920    doneControl(hwnd);
    924921
  • trunk/src/comctl32/tab.cpp

    r3369 r3585  
    1 /* $Id: tab.cpp,v 1.3 2000-04-12 16:38:59 cbratschi Exp $ */
     1/* $Id: tab.cpp,v 1.4 2000-05-22 17:25:11 cbratschi Exp $ */
    22/*
    33 * Tab control
     
    1212 *  Image list support
    1313 *  Multiline support
    14  *  Unicode support
    1514 */
    1615
    1716/* inconsistent: report! */
    1817/*
    19  - Corel WINE 20000317 level
     18 - Corel WINE 20000513 level
    2019 - (WINE 991212 level)
    2120*/
     
    4948
    5049/******************************************************************************
     50 * Hot-tracking timer constants
     51 */
     52#define TAB_HOTTRACK_TIMER            1
     53#define TAB_HOTTRACK_TIMER_INTERVAL   100   /* milliseconds */
     54
     55/******************************************************************************
    5156 * Prototypes
    5257 */
     
    5459static void TAB_InvalidateTabArea(HWND      hwnd, TAB_INFO* infoPtr);
    5560static void TAB_EnsureSelectionVisible(HWND hwnd, TAB_INFO* infoPtr);
     61static void TAB_DrawItem(HWND hwnd, HDC hdc, INT iItem);
     62static void TAB_DrawItemInterior(HWND hwnd, HDC hdc, INT iItem, RECT* drawRect);
    5663
    5764static VOID
     
    123130  if ((iItem < 0) || (iItem >= infoPtr->uNumItem)) return 0;
    124131
    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      {
    131142        infoPtr->iSelected = iItem;
    132143        sendNotify(hwnd,TCN_SELCHANGE);
     
    166177  RECT*       selectedRect)
    167178{
    168   RECT tmpItemRect;
     179  RECT tmpItemRect,clientRect;
     180  LONG        lStyle  = GetWindowLongA(hwnd, GWL_STYLE);
    169181
    170182  /*
    171183   * Perform a sanity check and a trivial visibility check.
    172184   */
    173   if ( (infoPtr->uNumItem == 0) ||
     185  if ( (infoPtr->uNumItem <= 0) ||
    174186       (itemIndex >= infoPtr->uNumItem) ||
    175        (itemIndex < infoPtr->leftmostVisible) )
     187       (!(lStyle &TCS_MULTILINE) && (itemIndex < infoPtr->leftmostVisible)) )
    176188    return FALSE;
    177189
     
    187199   */
    188200  *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 }
    189226
    190227  /*
     
    409446TAB_LButtonUp (HWND hwnd, WPARAM wParam, LPARAM lParam)
    410447{
     448  sendNotify(hwnd,NM_CLICK);
     449
     450  return 0;
     451}
     452
     453static LRESULT
     454TAB_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 */
     469static void
     470TAB_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 */
     490static VOID CALLBACK
     491TAB_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 */
     542static void
     543TAB_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 */
     625static LRESULT
     626TAB_MouseMove (HWND hwnd, WPARAM wParam, LPARAM lParam)
     627{
     628  int redrawLeave;
     629  int redrawEnter;
     630
    411631  TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
    412   POINT pt;
    413   INT newItem;
    414   UINT dummy;
    415632
    416633  if (infoPtr->hwndToolTip)
     
    418635                    WM_LBUTTONDOWN, wParam, lParam);
    419636
    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
    462646  return 0;
    463647}
     
    486670     */
    487671    if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
    488       prc->bottom += infoPtr->tabHeight;
     672      prc->bottom += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
    489673    else
    490       prc->top -= infoPtr->tabHeight;
     674      prc->top -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
    491675
    492676    /*
     
    520704     */
    521705    if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
    522       prc->bottom -= infoPtr->tabHeight;
     706      prc->bottom -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
    523707    else
    524       prc->top += infoPtr->tabHeight;
     708      prc->top += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
    525709
    526710  }
     
    543727  TAB_INFO *infoPtr = TAB_GetInfoPtr(hwnd);
    544728
    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;
    565743}
    566744
     
    576754  const RECT* clientRect)
    577755{
     756  INT maxRange = 0;
     757
    578758  if (infoPtr->needsScrolling)
    579759  {
    580760    RECT controlPos;
     761    INT vsize, tabwidth;
    581762
    582763    /*
     
    607788       * control.
    608789       */
    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,
    612793                                          controlPos.left, controlPos.top,
    613794                                          controlPos.right - controlPos.left,
     
    627808                   SWP_SHOWWINDOW | SWP_NOZORDER);
    628809    }
     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    }
    629830  }
    630831  else
     
    638839    }
    639840  }
     841
     842  if (infoPtr->hwndUpDown)
     843     SendMessageA(infoPtr->hwndUpDown, UDM_SETRANGE32, 0, maxRange);
    640844}
    641845
     
    657861  INT         curItem;
    658862  INT         curItemLeftPos;
     863  INT         curItemRowCount;
    659864  HFONT       hFont, hOldFont;
    660865  HDC         hdc;
     
    681886   */
    682887  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))
    685891  {
    686892    int item_height;
     
    717923  {
    718924    /*
    719      * Calculate the vertical position of the tab
    720      */
    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     else
    729     {
    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     /*
    737925     * Set the leftmost position of the tab.
    738926     */
    739927    infoPtr->items[curItem].rect.left = curItemLeftPos;
    740928
    741     if ((lStyle & TCS_FIXEDWIDTH) || (lStyle & TCS_OWNERDRAWFIXED))
     929    if ((lStyle & TCS_FIXEDWIDTH) || ((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet))
    742930    {
    743931      infoPtr->items[curItem].rect.right = infoPtr->items[curItem].rect.left +
     
    753941       * Calculate how wide the tab is depending on the text it contains
    754942       */
    755       //SvL: Bugfix: text is unicode, not ascii
    756943      GetTextExtentPoint32W(hdc, infoPtr->items[curItem].pszText,
    757944                            lstrlenW(infoPtr->items[curItem].pszText), &size);
     
    771958    }
    772959
     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
    773981//    TRACE("TextSize: %i\n ", size.cx);
    774982//    TRACE("Rect: T %i, L %i, B %i, R %i\n",
     
    788996  }
    789997
    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);
    8011110
    8021111  /*
     
    8051114  SelectObject (hdc, hOldFont);
    8061115  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 */
     1124static void
     1125TAB_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);
    8071297}
    8081298
     
    8381328    HPEN   hwPen     = GetSysColorPen (COLOR_3DHILIGHT);
    8391329    HPEN   hbPen     = GetSysColorPen (COLOR_BTNSHADOW);
    840     HPEN   hsdPen    = GetSysColorPen (COLOR_BTNTEXT);
    8411330    HPEN   hfocusPen = CreatePen(PS_DOT, 1, GetSysColor(COLOR_BTNTEXT));
    8421331    HPEN   holdPen;
    8431332    INT    oldBkMode;
    844     INT    cx,cy;
    8451333    BOOL deleteBrush = TRUE;
    8461334
     
    8591347         * Background color.
    8601348         */
    861         if (!(lStyle & TCS_OWNERDRAWFIXED))
     1349        if (!((lStyle & TCS_OWNERDRAWFIXED) && infoPtr->fSizeSet))
    8621350        {
    8631351          COLORREF bk = GetSysColor(COLOR_3DHILIGHT);
     
    8671355          SetBkColor(hdc, bk);
    8681356
     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;
    8691365        }
    8701366
     
    9751471    }
    9761472
    977     /*
    978      * Text pen
    979      */
    980     SelectObject(hdc, hsdPen);
    981 
    9821473    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);
    10091477
    10101478    /*
     
    10321500    SelectObject(hdc, holdPen);
    10331501    DeleteObject(hfocusPen);
    1034     DeleteObject(hbr);
     1502    if (deleteBrush) DeleteObject(hbr);
    10351503  }
    10361504}
     
    10581526  if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
    10591527  {
    1060     rect.bottom -= infoPtr->tabHeight;
     1528    rect.bottom -= (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
    10611529  }
    10621530  else
    10631531  {
    1064     rect.top += infoPtr->tabHeight;
     1532    rect.top += (infoPtr->tabHeight - 2) * (infoPtr->uNumRows + 1) + 2;
    10651533  }
    10661534
     
    11371605     */
    11381606    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);
    11391614  }
    11401615
     
    11841659  TAB_INFO* infoPtr)
    11851660{
    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  }
    11901701
    11911702  /*
     
    11961707    return;
    11971708
    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));
    12681751}
    12691752
     
    12851768  if (GetWindowLongA(hwnd, GWL_STYLE) & TCS_BOTTOM)
    12861769  {
    1287     clientRect.top = clientRect.bottom - (infoPtr->tabHeight + 1);
     1770    clientRect.top = clientRect.bottom - (infoPtr->tabHeight *
     1771                                           (infoPtr->uNumRows + 1) + 3);
    12881772  }
    12891773  else
    12901774  {
    1291     clientRect.bottom = clientRect.top + (infoPtr->tabHeight + 1);
     1775    clientRect.bottom = clientRect.top + (infoPtr->tabHeight *
     1776                                           (infoPtr->uNumRows + 1) + 1);
    12921777  }
    12931778
     
    14621947  }
    14631948
     1949  infoPtr->fSizeSet = TRUE;
     1950
    14641951  return lResult;
    14651952}
     
    14941981  if (tabItem->mask & TCIF_TEXT) {
    14951982   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);
    14991986  }
    15001987
     
    16732160  infoPtr->uNumItem = 0;
    16742161  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);
    16752168
    16762169  return TRUE;
     
    17812274
    17822275  infoPtr->uNumItem        = 0;
     2276  infoPtr->uNumRows        = 0;
    17832277  infoPtr->hFont           = 0;
    17842278  infoPtr->items           = 0;
    17852279  infoPtr->hcurArrow       = LoadCursorA (0, IDC_ARROWA);
    17862280  infoPtr->iSelected       = -1;
    1787   infoPtr->uFocus          = 0;
     2281  infoPtr->iHotTracked     = -1;
     2282  infoPtr->uFocus          = -1;
    17882283  infoPtr->hwndToolTip     = 0;
    17892284  infoPtr->DoRedraw        = TRUE;
     
    17912286  infoPtr->hwndUpDown      = 0;
    17922287  infoPtr->leftmostVisible = 0;
     2288  infoPtr->fSizeSet        = FALSE;
    17932289
    17942290  /* The tab control always has the WS_CLIPSIBLINGS style. Even
     
    18472343  }
    18482344
    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);
    18542347
    18552348  doneControl(hwnd);
     2349
     2350  return 0;
     2351}
     2352
     2353static LRESULT TAB_StyleChanged(HWND hwnd,WPARAM wParam,LPARAM lParam)
     2354{
     2355  TAB_SetItemBounds (hwnd);
     2356  InvalidateRect(hwnd, NULL, TRUE);
    18562357
    18572358  return 0;
     
    19302431      return 0;
    19312432
    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 
    19402433    case TCM_HIGHLIGHTITEM:
    19412434//      FIXME (tab, "Unimplemented msg TCM_HIGHLIGHTITEM\n");
     
    20112504    case WM_HSCROLL:
    20122505      return TAB_OnHScroll(hwnd, (int)LOWORD(wParam), (int)HIWORD(wParam), (HWND)lParam);
     2506
     2507    case WM_STYLECHANGED:
     2508      return TAB_StyleChanged(hwnd,wParam,lParam);
    20132509
    20142510    case WM_KILLFOCUS:
     
    20352531
    20362532  ZeroMemory (&wndClass, sizeof(WNDCLASSA));
    2037   wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
     2533  wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
    20382534  wndClass.lpfnWndProc   = (WNDPROC)TAB_WindowProc;
    20392535  wndClass.cbClsExtra    = 0;
  • trunk/src/comctl32/toolbar.cpp

    r3428 r3585  
    1 /* $Id: toolbar.cpp,v 1.5 2000-04-19 14:47:24 sandervl Exp $ */
     1/* $Id: toolbar.cpp,v 1.6 2000-05-22 17:25:12 cbratschi Exp $ */
    22/*
    33 * Toolbar control
     
    2929
    3030/*
    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)
    3833*/
    3934
     
    16001595            return -1;
    16011596
    1602 //        TRACE ("adding %d bitmaps!\n", nButtons);
     1597        //TRACE ("adding %d bitmaps!\n", nButtons);
    16031598    }
    16041599
    16051600    if (!(infoPtr->himlDef)) {
    16061601        /* 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);
    16121608        infoPtr->himlInt = infoPtr->himlDef;
    16131609    }
     
    34623458    TOOLBAR_INFO *infoPtr = TOOLBAR_GetInfoPtr (hwnd);
    34633459
    3464     /* delete tooltip control */
    3465     if (infoPtr->hwndToolTip)
    3466         DestroyWindow (infoPtr->hwndToolTip);
    3467 
    34683460    /* delete button data */
    34693461    if (infoPtr->buttons)
     
    34723464
    34733465      //SvL: Check pointers
    3474       for (x = 0;x < infoPtr->nNumButtons;x++) 
    3475         if(infoPtr->buttons[x].pszName)
    3476                 COMCTL32_Free(infoPtr->buttons[x].pszName);
     3466      for (x = 0;x < infoPtr->nNumButtons;x++)
     3467        if(infoPtr->buttons[x].pszName)
     3468                COMCTL32_Free(infoPtr->buttons[x].pszName);
    34773469
    34783470      COMCTL32_Free(infoPtr->buttons);
  • trunk/src/comctl32/tooltips.cpp

    r3285 r3585  
    1 /* $Id: tooltips.cpp,v 1.7 2000-03-31 14:44:23 cbratschi Exp $ */
     1/* $Id: tooltips.cpp,v 1.8 2000-05-22 17:25:12 cbratschi Exp $ */
    22/*
    33 * Tool tip control
     
    1818
    1919/*
    20  - Corel WINE 20000317 level
     20 - Corel WINE 20000513 level
    2121 - (WINE 20000130 level)
    2222*/
     
    15121512    TOOLTIPS_INFO *infoPtr = TOOLTIPS_GetInfoPtr (hwnd);
    15131513
     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
    15141523    TOOLTIPS_Hide (hwnd, infoPtr);
    15151524
     
    15531562            infoPtr->nOldTool = infoPtr->nTool;
    15541563            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);
    15591568
    15601569            if (infoPtr->bActive && (infoPtr->nTool != infoPtr->nOldTool))
     
    15631572              {
    15641573                SetTimer(hwnd,ID_TIMERSHOW,infoPtr->nInitialTime,0);
    1565 //              TRACE (tooltips, "timer 1 started!\n");
     1574                //TRACE (tooltips, "timer 1 started!\n");
    15661575              } else
    15671576              {
     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
    15681586                TOOLTIPS_Hide(hwnd,infoPtr);
    15691587                SetTimer (hwnd,ID_TIMERSHOW,infoPtr->nReshowTime,0);
    1570 //              TRACE (tooltips, "timer 2 started!\n");
     1588                //TRACE (tooltips, "timer 2 started!\n");
    15711589              }
    15721590            }
     
    15741592            {
    15751593              SetTimer(hwnd,ID_TIMERLEAVE,100,0);
    1576 //            TRACE (tooltips, "timer 3 started!\n");
     1594              //TRACE (tooltips, "timer 3 started!\n");
    15771595            }
    15781596            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 $ */
    22/*
    33 * Trackbar control
     
    5252#define SCALE_SPACE 1
    5353
    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
    5657
    5758#define CHANNEL_NOSEL_HEIGHT 4 //min no sel height
     
    7475#define TOOLTIP_YSPACE 5
    7576
    76 static BOOL TRACKBAR_SendNotify (HWND hwnd, UINT code);
    77 
    78 static void TRACKBAR_RecalculateTics (HWND hwnd,TRACKBAR_INFO *infoPtr,BOOL restoreOld)
     77static const WORD pattern[8] =
     78     {0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA};
     79
     80static BOOL TRACKBAR_SendNotify(TRACKBAR_INFO *infoPtr,UINT code);
     81
     82static void TRACKBAR_RecalculateTics(TRACKBAR_INFO *infoPtr,BOOL restoreOld)
    7983{
    8084    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
    8487    {
    8588      COMCTL32_Free(infoPtr->tics);
     
    9093    }
    9194
    92     if (restoreOld && !(dwStyle & TBS_AUTOTICKS) && infoPtr->tics != NULL)
     95    if (restoreOld && !(infoPtr->dwStyle & TBS_AUTOTICKS) && infoPtr->tics)
    9396    { //check old ticks
    9497      LPLONG oldTics = (LONG*)COMCTL32_Alloc(infoPtr->uNumTics*sizeof(DWORD));
     
    111114    }
    112115
    113     if (infoPtr->uTicFreq && (infoPtr->nRangeMax > infoPtr->nRangeMin) && (dwStyle & TBS_AUTOTICKS))
     116    if (infoPtr->uTicFreq && (infoPtr->nRangeMax > infoPtr->nRangeMin) && (infoPtr->dwStyle & TBS_AUTOTICKS))
    114117    {
    115118      //Tics without start and end tic
     
    168171    else if (pos < infoPtr->nRangeMin) pos = infoPtr->nRangeMin;
    169172
    170 //    TRACE (trackbar,"%.2f\n",pos);
    171173    return pos;
    172174}
     
    174176
    175177static VOID
    176 TRACKBAR_CalcChannel (HWND hwnd,TRACKBAR_INFO *infoPtr)
    177 {
    178     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
     178TRACKBAR_CalcChannel(TRACKBAR_INFO *infoPtr)
     179{
    179180    INT channelSize;
    180181    RECT lpRect,*channel = &infoPtr->rcChannel;
    181182    INT thumbDiff;
    182183
    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);
    186187    else channelSize = CHANNEL_NOSEL_HEIGHT;
    187188
    188189    thumbDiff = (infoPtr->uThumbLen-channelSize)/2;
    189190
    190     if (dwStyle & TBS_VERT)
     191    if (infoPtr->dwStyle & TBS_VERT)
    191192    {
    192193      channel->top    = lpRect.top+CHANNEL_SPACE;
    193194      channel->bottom = lpRect.bottom-CHANNEL_SPACE;
    194195
    195       if ((dwStyle & TBS_BOTH) || (dwStyle & TBS_NOTICKS))
     196      if ((infoPtr->dwStyle & TBS_BOTH) || (infoPtr->dwStyle & TBS_NOTICKS))
    196197      { //center
    197198        channel->left  = (lpRect.right-channelSize)/2;
    198199        channel->right = (lpRect.right+channelSize)/2;
    199       } else if (dwStyle & TBS_LEFT)
     200      } else if (infoPtr->dwStyle & TBS_LEFT)
    200201      {
    201202        channel->left  = lpRect.left+thumbDiff+CHANNEL_SCALE_SPACE;
     
    210211      channel->left = lpRect.left+CHANNEL_SPACE;
    211212      channel->right = lpRect.right-CHANNEL_SPACE;
    212       if ((dwStyle & TBS_BOTH) || (dwStyle & TBS_NOTICKS))
     213      if ((infoPtr->dwStyle & TBS_BOTH) || (infoPtr->dwStyle & TBS_NOTICKS))
    213214      { //center
    214215        channel->top    = (lpRect.bottom-channelSize)/2;
    215216        channel->bottom = (lpRect.bottom+channelSize)/2;
    216       } else if (dwStyle & TBS_TOP)
     217      } else if (infoPtr->dwStyle & TBS_TOP)
    217218      {
    218219        channel->top    = lpRect.top+thumbDiff+CHANNEL_SCALE_SPACE;
     
    226227}
    227228
    228 //Calculate thumb size
    229 
    230229static VOID
    231 TRACKBAR_CalcThumb(HWND hwnd,TRACKBAR_INFO *infoPtr)
     230TRACKBAR_CalcThumb(TRACKBAR_INFO *infoPtr)
    232231{
    233232    RECT *thumb;
     
    235234    int range, width;
    236235    int x,y;
    237     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
    238236    int thumbFactor = 2;
    239237
     
    241239    fullThumb = &infoPtr->rcFullThumb;
    242240    range = infoPtr->nRangeMax-infoPtr->nRangeMin;
    243     if (dwStyle & TBS_VERT)
     241    if (infoPtr->dwStyle & TBS_VERT)
    244242    {
    245243      width = infoPtr->rcChannel.bottom-infoPtr->rcChannel.top;
     
    252250      thumb->right = thumb->left+infoPtr->uThumbLen;
    253251      CopyRect(fullThumb,thumb);
    254       if (dwStyle & TBS_BOTH) return;
     252      if (infoPtr->dwStyle & TBS_BOTH) return;
    255253      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;
    257255    } else
    258256    {
     
    266264      thumb->bottom = thumb->top+infoPtr->uThumbLen;
    267265      CopyRect(fullThumb,thumb);
    268       if (dwStyle & TBS_BOTH) return;
     266      if (infoPtr->dwStyle & TBS_BOTH) return;
    269267      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;
    271269    }
    272270}
    273271
    274272static VOID
    275 TRACKBAR_CalcSelection (HWND hwnd, TRACKBAR_INFO *infoPtr)
     273TRACKBAR_CalcSelection(TRACKBAR_INFO *infoPtr)
    276274{
    277275    RECT *selection;
     
    285283    if ((range <= 0) || (selMin == selMax)) SetRectEmpty(selection);
    286284    else
    287         if (!(GetWindowLongA(hwnd, GWL_STYLE) & TBS_VERT))
     285        if (!(infoPtr->dwStyle & TBS_VERT))
    288286        {   //Horizontal
    289287            width = infoPtr->rcChannel.right-infoPtr->rcChannel.left;
     
    307305
    308306static VOID
    309 TRACKBAR_DrawHorizTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos,
    310                        int flags, COLORREF clrTic)
     307TRACKBAR_DrawHorizTic(TRACKBAR_INFO *infoPtr,HDC hdc,LONG ticPos,int flags,COLORREF clrTic)
    311308{
    312309    RECT rcChannel = infoPtr->rcChannel;
     
    386383
    387384static VOID
    388 TRACKBAR_DrawVertTic (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos,
    389                       int flags, COLORREF clrTic)
     385TRACKBAR_DrawVertTic(TRACKBAR_INFO *infoPtr,HDC hdc,LONG ticPos,int flags,COLORREF clrTic)
    390386{
    391387    RECT rcChannel = infoPtr->rcChannel;
     
    467463
    468464static VOID
    469 TRACKBAR_DrawTics (TRACKBAR_INFO *infoPtr, HDC hdc, LONG ticPos,
    470                    int flags, COLORREF clrTic)
     465TRACKBAR_DrawTics(TRACKBAR_INFO *infoPtr,HDC hdc,LONG ticPos,int flags,COLORREF clrTic)
    471466{
    472467    if (flags & TBS_VERT)
     
    489484//draw thumb, call only from draw!
    490485
    491 static VOID TRACKBAR_DrawThumb(TRACKBAR_INFO *infoPtr,HWND hwnd,HDC hdc,DWORD dwStyle)
    492 {
    493     if (!(dwStyle & TBS_NOTHUMB))
     486static VOID TRACKBAR_DrawThumb(TRACKBAR_INFO *infoPtr,HDC hdc)
     487{
     488    if (!(infoPtr->dwStyle & TBS_NOTHUMB))
    494489    {
    495490      HBRUSH hbr,hbrOld;
    496491      RECT thumb = infoPtr->rcThumb;
    497492
    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;
    500495      hbrOld = SelectObject(hdc,hbr);
    501496
    502       if (dwStyle & TBS_BOTH)
     497      if (infoPtr->dwStyle & TBS_BOTH)
    503498      {
    504499        DrawEdge(hdc,&thumb,EDGE_RAISED,BF_RECT | BF_ADJUST);
     
    509504        RECT triangle;  /* for correct shadows of thumb */
    510505
    511         if (dwStyle & TBS_VERT)
     506        if (infoPtr->dwStyle & TBS_VERT)
    512507        { //Vertical
    513508
    514           if (dwStyle & TBS_LEFT)
     509          if (infoPtr->dwStyle & TBS_LEFT)
    515510          {
    516511            HPEN oldPen,pen;
     
    606601        { //Horizontal
    607602
    608           if (dwStyle & TBS_TOP)
     603          if (infoPtr->dwStyle & TBS_TOP)
    609604          {
    610605            //Outline
     
    689684      }
    690685      SelectObject(hdc,hbrOld);
    691       DeleteObject(hbr);
     686      if (hbr != infoPtr->hbrThumb) DeleteObject(hbr);
    692687    }
    693688}
     
    695690//draw the trackbar
    696691
    697 static VOID TRACKBAR_Draw(HWND hwnd,HDC hdc)
    698 {
    699     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    700     DWORD dwStyle = GetWindowLongA(hwnd, GWL_STYLE);
     692static VOID TRACKBAR_Draw(TRACKBAR_INFO *infoPtr,HDC hdc)
     693{
    701694    RECT rcClient,rcChannel,rcSelection;
    702695    HBRUSH hBrush;
     
    705698    LRESULT cdctlres,cdres;
    706699
    707     GetClientRect(hwnd,&rcClient);
     700    GetClientRect(infoPtr->hwnd,&rcClient);
    708701
    709702    //Custom draw
     
    711704    cdraw.hdc          = hdc;
    712705    cdraw.dwItemSpec   = 0;
    713     cdraw.uItemState   = CDIS_DEFAULT;
     706    cdraw.uItemState   = infoPtr->bFocus ? CDIS_FOCUS:CDIS_DEFAULT;
    714707    cdraw.rc           = rcClient;
    715708    cdraw.lItemlParam  = 0;
    716709
    717     cdctlres = sendNotify(hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
     710    cdctlres = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
    718711
    719712    if (cdctlres & CDRF_SKIPDEFAULT) return;
     
    734727      if (infoPtr->flags & TB_THUMBSIZECHANGED)
    735728      {
    736         TRACKBAR_CalcChannel(hwnd,infoPtr);
    737         TRACKBAR_CalcSelection(hwnd,infoPtr);
     729        TRACKBAR_CalcChannel(infoPtr);
     730        TRACKBAR_CalcSelection(infoPtr);
    738731      }
    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);
    742735    infoPtr->flags &= ~ (TB_THUMBCHANGED | TB_SELECTIONCHANGED | TB_DRAGPOSVALID);
    743736
     
    750743      cdraw.rc             = infoPtr->rcChannel;
    751744
    752       cdres = sendNotify(hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
     745      cdres = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
    753746    } else cdres = 0;
    754747
     
    759752      DrawEdge(hdc,&rcChannel,EDGE_SUNKEN,BF_RECT | BF_ADJUST);
    760753
    761       if (dwStyle & TBS_ENABLESELRANGE)           /* fill the channel */
     754      if (infoPtr->dwStyle & TBS_ENABLESELRANGE)           /* fill the channel */
    762755      {
    763756        HBRUSH hbr = CreateSolidBrush(RGB(255,255,255));
    764757        FillRect(hdc,&rcChannel,hbr);
    765758        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)))
    768761           {
    769762             hbr = CreateSolidBrush (COLOR_HIGHLIGHT);
     
    777770        cdraw.dwDrawStage    = CDDS_ITEMPOSTPAINT;
    778771
    779         sendNotify(hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
     772        sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
    780773      }
    781774    }
     
    789782      SetRectEmpty(&cdraw.rc);
    790783
    791       cdres = sendNotify(hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
     784      cdres = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
    792785    } else cdres = 0;
    793786
    794787    if (!(cdres & CDRF_SKIPDEFAULT))
    795788    {
    796       if (!(dwStyle & TBS_NOTICKS))
     789      if (!(infoPtr->dwStyle & TBS_NOTICKS))
    797790      {
    798         int ticFlags = dwStyle & 0x0f;
     791        int ticFlags = infoPtr->dwStyle & 0x0f;
    799792        COLORREF clrTic = GetSysColor(COLOR_3DDKSHADOW);
    800793        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;
    802795
    803796        //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)))
    805798        {
    806799          //draw all pixels at once -> much faster
    807           if (dwStyle & TBS_VERT)
     800          if (infoPtr->dwStyle & TBS_VERT)
    808801          {
    809802            if ((ticFlags & TBS_LEFT) || (ticFlags & TBS_BOTH))
     
    827820        TRACKBAR_DrawTics(infoPtr,hdc,0,ticFlags | TIC_RIGHTEDGE,clrTic);
    828821
    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)))
    832825              {
    833826                TRACKBAR_DrawTics(infoPtr,hdc,infoPtr->nSelMin,ticFlags | TIC_SELECTIONMARKMIN,clrTic);
     
    840833        cdraw.dwDrawStage    = CDDS_ITEMPOSTPAINT;
    841834
    842         sendNotify(hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
     835        sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
    843836      }
    844837    }
     
    852845      cdraw.rc             = infoPtr->rcFullThumb;
    853846
    854       cdres = sendNotify(hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
     847      cdres = sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
    855848    } else cdres = 0;
    856849
    857850    if (!(cdres & CDRF_SKIPDEFAULT))
    858851    {
    859       TRACKBAR_DrawThumb(infoPtr,hwnd,hdc,dwStyle);
     852      TRACKBAR_DrawThumb(infoPtr,hdc);
    860853
    861854      if (cdctlres & CDRF_NOTIFYITEMDRAW)
     
    863856        cdraw.dwDrawStage    = CDDS_ITEMPOSTPAINT;
    864857
    865         sendNotify(hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
     858        sendNotify(infoPtr->hwnd,NM_CUSTOMDRAW,&cdraw.hdr);
    866859      }
    867860
    868861    }
    869862
    870     if (infoPtr->bFocus && IsWindowEnabled(hwnd)) DrawFocusRect(hdc,&rcClient);
     863    if (infoPtr->bFocus && IsWindowEnabled(infoPtr->hwnd)) DrawFocusRect(hdc,&rcClient);
    871864
    872865    if (cdctlres & CDRF_NOTIFYPOSTPAINT)
     
    874867      cdraw.dwDrawStage    = CDDS_POSTPAINT;
    875868      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);
    879872    }
    880873
     
    883876//update thumb position
    884877
    885 static VOID TRACKBAR_UpdateThumbPosition(HWND hwnd,INT lastPos,BOOL mustRedraw)
     878static VOID TRACKBAR_UpdateThumbPosition(TRACKBAR_INFO *infoPtr,INT lastPos,BOOL mustRedraw)
    886879{
    887880   HDC hdc;
    888    TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd);
    889    DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
    890881   RECT lastRect,newRect,updateRect;
    891882   HDC hdcCompatible;
     
    903894   if (!mustRedraw && (infoPtr->nPos == lastPos)) return;
    904895
    905    if (dwStyle & TBS_NOTHUMB) return;
    906 
    907    TRACKBAR_CalcThumb(hwnd,infoPtr);
     896   if (infoPtr->dwStyle & TBS_NOTHUMB) return;
     897
     898   TRACKBAR_CalcThumb(infoPtr);
    908899   infoPtr->flags &= ~TB_THUMBCHANGED;
    909900   newRect = infoPtr->rcFullThumb;
     
    923914   updateRect.top = MIN(lastRect.top,newRect.top);
    924915   updateRect.bottom = MAX(lastRect.bottom,newRect.bottom);
    925    hdc = GetDC(hwnd);
     916   hdc = GetDC(infoPtr->hwnd);
    926917   hdcCompatible = CreateCompatibleDC(hdc);
    927918   bitmap = CreateCompatibleBitmap(hdc,updateRect.right,updateRect.bottom);
    928919   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)
    931922   {
    932923     if ((lastRect.top > newRect.top) && (lastRect.top < newRect.bottom))
     
    954945   DeleteObject(bitmap);
    955946   DeleteDC(hdcCompatible);
    956    ReleaseDC(hwnd,hdc);
     947   ReleaseDC(infoPtr->hwnd,hdc);
    957948}
    958949
    959950//redraw everything
    960951
    961 static VOID TRACKBAR_Refresh (HWND hwnd)
     952static VOID TRACKBAR_Refresh(TRACKBAR_INFO *infoPtr)
    962953{
    963954   HDC hdc;
    964955
    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);
    968959}
    969960
    970961static VOID
    971 TRACKBAR_AlignBuddies (HWND hwnd, TRACKBAR_INFO *infoPtr)
    972 {
    973     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
    974     HWND hwndParent = GetParent(hwnd);
     962TRACKBAR_AlignBuddies(TRACKBAR_INFO *infoPtr)
     963{
     964    HWND hwndParent = GetParent(infoPtr->hwnd);
    975965    RECT rcSelf,rcBuddy;
    976966    INT x, y;
    977967
    978     GetWindowRect(hwnd,&rcSelf);
     968    GetWindowRect(infoPtr->hwnd,&rcSelf);
    979969    MapWindowPoints(HWND_DESKTOP,hwndParent,(LPPOINT)&rcSelf,2);
    980970
     
    984974      GetWindowRect(infoPtr->hwndBuddyLA,&rcBuddy);
    985975
    986       if (dwStyle & TBS_VERT)
     976      if (infoPtr->dwStyle & TBS_VERT)
    987977      { //above
    988978        x = (infoPtr->rcChannel.right+infoPtr->rcChannel.left)/2-(rcBuddy.right-rcBuddy.left)/2+rcSelf.left;
     
    1003993      GetWindowRect(infoPtr->hwndBuddyRB,&rcBuddy);
    1004994
    1005       if (dwStyle & TBS_VERT)
     995      if (infoPtr->dwStyle & TBS_VERT)
    1006996      { //below
    1007997        x = (infoPtr->rcChannel.right+infoPtr->rcChannel.left)/2-(rcBuddy.right-rcBuddy.left)/2+rcSelf.left;
     
    10171007}
    10181008
    1019 
    1020 static LRESULT
    1021 TRACKBAR_ClearSel (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1022 {
    1023     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1024 
     1009static LRESULT
     1010TRACKBAR_ClearSel(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1011{
    10251012    if (infoPtr->nSelMin != infoPtr->nSelMax)
    10261013    {
     
    10291016      infoPtr->flags |= TB_SELECTIONCHANGED;
    10301017
    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
     1024static LRESULT
     1025TRACKBAR_ClearTics(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1026{
     1027    if (!(infoPtr->dwStyle & (TBS_AUTOTICKS | TBS_NOTICKS))) return 0;
    10441028
    10451029    if (infoPtr->tics)
     
    10491033      infoPtr->uNumTics = 0;
    10501034
    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
     1042static LRESULT
     1043TRACKBAR_GetBuddy(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1044{
    10631045    if (wParam)
    10641046      return (LRESULT)infoPtr->hwndBuddyLA; //left or above
     
    10671049}
    10681050
    1069 
    1070 static LRESULT
    1071 TRACKBAR_GetChannelRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1072 {
    1073     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1051static LRESULT
     1052TRACKBAR_GetChannelRect(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1053{
    10741054    LPRECT lprc = (LPRECT)lParam;
    10751055
     
    10811061}
    10821062
    1083 
    1084 static LRESULT
    1085 TRACKBAR_GetLineSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1086 {
    1087     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1088 
     1063static LRESULT
     1064TRACKBAR_GetLineSize(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1065{
    10891066    return infoPtr->nLineSize;
    10901067}
     
    10921069
    10931070static 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;
     1071TRACKBAR_GetNumTics(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1072{
     1073    if (infoPtr->dwStyle & TBS_NOTICKS) return 0;
    10991074
    11001075    return infoPtr->uNumTics+2; //includes last and first tick
    11011076}
    11021077
    1103 
    1104 static LRESULT
    1105 TRACKBAR_GetPageSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1106 {
    1107     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1108 
     1078static LRESULT
     1079TRACKBAR_GetPageSize(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1080{
    11091081    return infoPtr->nPageSize;
    11101082}
     
    11121084
    11131085static LRESULT
    1114 TRACKBAR_GetPos (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1115 {
    1116     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1117 
     1086TRACKBAR_GetPos(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1087{
    11181088    return infoPtr->nPos;
    11191089}
     
    11211091
    11221092static LRESULT
    1123 TRACKBAR_GetRangeMax (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1124 {
    1125     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1126 
     1093TRACKBAR_GetRangeMax(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1094{
    11271095    return infoPtr->nRangeMax;
    11281096}
     
    11301098
    11311099static LRESULT
    1132 TRACKBAR_GetRangeMin (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1133 {
    1134     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1135 
     1100TRACKBAR_GetRangeMin(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1101{
    11361102    return infoPtr->nRangeMin;
    11371103}
     
    11391105
    11401106static LRESULT
    1141 TRACKBAR_GetSelEnd (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1142 {
    1143     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1144 
     1107TRACKBAR_GetSelEnd(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1108{
    11451109    return infoPtr->nSelMax;
    11461110}
     
    11481112
    11491113static LRESULT
    1150 TRACKBAR_GetSelStart (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1151 {
    1152     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1153 
     1114TRACKBAR_GetSelStart(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1115{
    11541116    return infoPtr->nSelMin;
    11551117}
     
    11571119
    11581120static LRESULT
    1159 TRACKBAR_GetThumbLength (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1160 {
    1161     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1162 
     1121TRACKBAR_GetThumbLength(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1122{
    11631123    return infoPtr->uThumbLen;
    11641124}
    11651125
    11661126static LRESULT
    1167 TRACKBAR_GetPTics (HWND hwnd)
    1168 {
    1169     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1170 
     1127TRACKBAR_GetPTics(TRACKBAR_INFO *infoPtr)
     1128{
    11711129    return (LRESULT)infoPtr->tics;
    11721130}
    11731131
    11741132static LRESULT
    1175 TRACKBAR_GetThumbRect (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1176 {
    1177     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1133TRACKBAR_GetThumbRect(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1134{
    11781135    LPRECT lprc = (LPRECT)lParam;
    11791136
     
    11871144
    11881145static LRESULT
    1189 TRACKBAR_GetTic (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1190 {
    1191     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1146TRACKBAR_GetTic(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1147{
    11921148    INT iTic;
    11931149
     
    12011157
    12021158static LRESULT
    1203 TRACKBAR_GetTicPos (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1204 {
    1205     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1159TRACKBAR_GetTicPos(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1160{
    12061161    INT iTic, range, width, pos;
    12071162
     
    12191174
    12201175static 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)
     1176TRACKBAR_GetToolTips(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1177{
     1178    if (infoPtr->dwStyle & TBS_TOOLTIPS)
    12261179        return (LRESULT)infoPtr->hwndToolTip;
    12271180    return 0;
     
    12301183
    12311184static LRESULT
    1232 TRACKBAR_SetBuddy (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1233 {
    1234     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd);
     1185TRACKBAR_SetBuddy(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1186{
    12351187    HWND hwndTemp;
    12361188
    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;
    12381190
    12391191    if (wParam)
     
    12491201    }
    12501202
    1251     TRACKBAR_AlignBuddies(hwnd,infoPtr);
     1203    TRACKBAR_AlignBuddies(infoPtr);
    12521204
    12531205    return (LRESULT)hwndTemp;
     
    12561208
    12571209static LRESULT
    1258 TRACKBAR_SetLineSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1259 {
    1260     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1210TRACKBAR_SetLineSize(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1211{
    12611212    INT nTemp = infoPtr->nLineSize;
    12621213
     
    12681219
    12691220static LRESULT
    1270 TRACKBAR_SetPageSize (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1271 {
    1272     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1221TRACKBAR_SetPageSize(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1222{
    12731223    INT nTemp = infoPtr->nPageSize;
    12741224
     
    12801230
    12811231static LRESULT
    1282 TRACKBAR_SetPos (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1283 {
    1284     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1232TRACKBAR_SetPos(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1233{
    12851234    INT lastPos = infoPtr->nPos;
    12861235
     
    12961245    infoPtr->flags |= TB_THUMBPOSCHANGED;
    12971246
    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
     1253static LRESULT
     1254TRACKBAR_SetRange(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1255{
    13081256    int newMin,newMax;
    1309     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
    13101257
    13111258    newMin = (INT)LOWORD(lParam);
     
    13601307    infoPtr->nPageSize = (infoPtr->nRangeMax-infoPtr->nRangeMin)/5;
    13611308    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
     1317static LRESULT
     1318TRACKBAR_SetRangeMax(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1319{
    13751320    if ((INT)lParam <= infoPtr->nRangeMin) return 0;
    13761321    if (infoPtr->nRangeMax == (INT)lParam) return 0;
     
    13851330    infoPtr->nPageSize = (infoPtr->nRangeMax-infoPtr->nRangeMin)/5;
    13861331    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
     1340static LRESULT
     1341TRACKBAR_SetRangeMin(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1342{
    14001343    if ((INT)lParam >= infoPtr->nRangeMax) return 0;
    14011344    if (infoPtr->nRangeMin == (INT)lParam) return 0;
     
    14101353    infoPtr->nPageSize = (infoPtr->nRangeMax-infoPtr->nRangeMin)/5;
    14111354    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
     1363static LRESULT
     1364TRACKBAR_SetTicFreq(TRACKBAR_INFO *infoPtr,WPARAM wParam)
     1365{
    14251366    if (infoPtr->uTicFreq == (UINT)wParam) return 0;
    14261367
    1427     if (!(GetWindowLongA(hwnd,GWL_STYLE) & TBS_AUTOTICKS)) return 0;
     1368    if (!(infoPtr->dwStyle & TBS_AUTOTICKS)) return 0;
    14281369
    14291370    infoPtr->uTicFreq = (UINT)wParam;
    14301371
    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
     1379static LRESULT
     1380TRACKBAR_SetSel(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1381{
    14431382    INT newMin,newMax,oldMin,oldMax;
    14441383
     
    14591398    if (infoPtr->nSelMin > infoPtr->nSelMax) infoPtr->nSelMin = infoPtr->nSelMax;
    14601399
    1461     if (!GetWindowLongA(hwnd, GWL_STYLE) & TBS_ENABLESELRANGE) return 0;
     1400    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)) return 0;
    14621401
    14631402    if ((oldMin != newMin) || (oldMax != newMax))
    14641403    {
    14651404      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
     1411static LRESULT
     1412TRACKBAR_SetSelEnd(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1413{
    14771414    INT oldMax;
    14781415
     
    14871424    if (infoPtr->nSelMin > infoPtr->nSelMax) infoPtr->nSelMin = infoPtr->nSelMax;
    14881425
    1489     if (!GetWindowLongA(hwnd,GWL_STYLE) & TBS_ENABLESELRANGE) return 0;
     1426    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)) return 0;
    14901427
    14911428    if (oldMax != infoPtr->nSelMax)
    14921429    {
    14931430      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
     1437static LRESULT
     1438TRACKBAR_SetSelStart(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1439{
    15051440    INT oldMin;
    15061441
     
    15151450    if (infoPtr->nSelMin > infoPtr->nSelMax) infoPtr->nSelMin = infoPtr->nSelMax;
    15161451
    1517     if (!GetWindowLongA(hwnd,GWL_STYLE) & TBS_ENABLESELRANGE) return 0;
     1452    if (!(infoPtr->dwStyle & TBS_ENABLESELRANGE)) return 0;
    15181453
    15191454    if (oldMin != infoPtr->nSelMin)
    15201455    {
    15211456      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
     1463static LRESULT
     1464TRACKBAR_SetThumbLength(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1465{
    15341466    if (infoPtr->uThumbLen == (UINT)wParam) return 0;
    15351467
    1536     if (GetWindowLongA(hwnd,GWL_STYLE) & TBS_FIXEDLENGTH) return 0;
     1468    if (infoPtr->dwStyle & TBS_FIXEDLENGTH) return 0;
    15371469
    15381470    infoPtr->uThumbLen = MAX((UINT)wParam,THUMB_MINLEN);
    15391471    infoPtr->flags |= TB_THUMBSIZECHANGED | TB_THUMBCHANGED;
    15401472
    1541     TRACKBAR_Refresh(hwnd);
     1473    TRACKBAR_Refresh(infoPtr);
    15421474
    15431475    return 0;
     
    15691501
    15701502static LRESULT
    1571 TRACKBAR_SetTic (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1572 {
    1573     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1503TRACKBAR_SetTic(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1504{
    15741505    INT nPos = (INT)lParam;
    15751506    INT x;
    15761507
    1577     if (!(GetWindowLongA(hwnd, GWL_STYLE) & (TBS_AUTOTICKS | TBS_NOTICKS))) return 0;
     1508    if (!(infoPtr->dwStyle & (TBS_AUTOTICKS | TBS_NOTICKS))) return 0;
    15781509
    15791510    if ((nPos < infoPtr->nRangeMin) || (nPos > infoPtr->nRangeMax)) return FALSE;
     
    15921523    TRACKBAR_QuickSort(infoPtr->tics,0,infoPtr->uNumTics-1);
    15931524
    1594     TRACKBAR_Refresh(hwnd);
     1525    TRACKBAR_Refresh(infoPtr);
    15951526
    15961527    return TRUE;
    15971528}
    15981529
    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);
     1530static LRESULT
     1531TRACKBAR_SetTipSide(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1532{
    16051533    INT fTemp = infoPtr->fLocation;
    16061534
    1607     if (dwStyle & TBS_VERT)
     1535    if (infoPtr->dwStyle & TBS_VERT)
    16081536    {
    16091537      if ((wParam == TBTS_LEFT) || (wParam == TBTS_RIGHT)) infoPtr->fLocation = (INT)wParam;
     
    16161544}
    16171545
    1618 
    1619 static LRESULT
    1620 TRACKBAR_SetToolTips (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1621 {
    1622     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
    1623 
     1546static LRESULT
     1547TRACKBAR_SetToolTips(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1548{
    16241549    infoPtr->hwndToolTip = (HWND)wParam;
    16251550
     
    16281553
    16291554static LRESULT
    1630 TRACKBAR_InitializeThumb (HWND hwnd)
    1631 {
    1632     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1555TRACKBAR_InitializeThumb(TRACKBAR_INFO *infoPtr)
     1556{
    16331557    RECT clientRect;
    1634     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
    16351558    INT scaleSize;
    16361559
    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 */
    16391562
    16401563    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);
    16431566    else scaleSize += SCALE_SIZE+SCALE_SPACE;
    16441567
    1645     if (dwStyle & TBS_VERT)
     1568    if (infoPtr->dwStyle & TBS_VERT)
    16461569    {
    16471570      INT width = clientRect.right-clientRect.left;
     
    16551578    }
    16561579
    1657     TRACKBAR_CalcChannel(hwnd,infoPtr);
    1658     TRACKBAR_CalcThumb(hwnd,infoPtr);
     1580    TRACKBAR_CalcChannel(infoPtr);
     1581    TRACKBAR_CalcThumb(infoPtr);
    16591582
    16601583    infoPtr->flags &= ~TB_SELECTIONCHANGED;
     
    16631586}
    16641587
    1665 
    1666 static LRESULT
    1667 TRACKBAR_Create (HWND hwnd, WPARAM wParam, LPARAM lParam)
     1588static LRESULT
     1589TRACKBAR_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
     1599static LRESULT
     1600TRACKBAR_Create(HWND hwnd,WPARAM wParam,LPARAM lParam)
    16681601{
    16691602    TRACKBAR_INFO *infoPtr;
    1670     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
     1603    LOGBRUSH lb;
    16711604
    16721605    infoPtr = (TRACKBAR_INFO*)initControl(hwnd,sizeof(TRACKBAR_INFO));
    16731606
    16741607    /* set default values */
     1608    infoPtr->hwnd    = hwnd;
     1609    infoPtr->dwStyle = GetWindowLongA(hwnd,GWL_STYLE);;
     1610
    16751611    infoPtr->nRangeMin  = 0;
    16761612    infoPtr->nRangeMax  = 100;
     
    16841620    infoPtr->uTicFreq   = 1;
    16851621    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);
    16871630
    16881631    infoPtr->hwndBuddyLA = 0;
     
    16911634    infoPtr->bFocus      = FALSE;
    16921635
    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;
    16961639    } else
    16971640    {
    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);
    17021645
    17031646    /* Create tooltip control */
    1704     if (dwStyle & TBS_TOOLTIPS)
     1647    if (infoPtr->dwStyle & TBS_TOOLTIPS)
    17051648    {
    17061649      UINT uFlags = TTF_TRACK | TTF_ABSOLUTE;
    17071650
    1708       if (dwStyle & TBS_VERT)
     1651      if (infoPtr->dwStyle & TBS_VERT)
    17091652        if (infoPtr->fLocation == TBTS_RIGHT)
    17101653          uFlags |= TTF_ALIGNRIGHT | TTF_VCENTER;
     
    17231666}
    17241667
    1725 
    1726 static LRESULT
    1727 TRACKBAR_Destroy (HWND hwnd, WPARAM wParam, LPARAM lParam)
    1728 {
    1729     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr (hwnd);
     1668static LRESULT
     1669TRACKBAR_Destroy(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1670{
     1671    if (infoPtr->hbrThumb)
     1672      DeleteObject((HGDIOBJ)infoPtr->hbrThumb);
    17301673
    17311674    /* delete tooltip control */
     
    17331676
    17341677    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
     1683static VOID TRACKBAR_CalcToolTipPos(TRACKBAR_INFO *infoPtr,POINT *pt)
     1684{
     1685  if (infoPtr->dwStyle & TBS_VERT)
    17431686  {
    17441687    if (infoPtr->fLocation == TBTS_RIGHT)
     
    17641707    }
    17651708  }
    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
     1712static LRESULT
     1713TRACKBAR_LButtonDown(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1714{
    17741715    int clickPlace,prevPos,vertical;
    17751716    DOUBLE clickPos;
     
    17771718    POINT clickPoint;
    17781719
    1779     SetFocus (hwnd);
    1780 
    1781     vertical = dwStyle & TBS_VERT;
     1720    SetFocus(infoPtr->hwnd);
     1721
     1722    vertical = infoPtr->dwStyle & TBS_VERT;
    17821723    clickPoint.x = (INT)LOWORD(lParam);
    17831724    clickPoint.y = (INT)HIWORD(lParam);
     
    17931734         (clickPoint.y >= thumb.top) &&
    17941735         (clickPoint.y <= thumb.bottom) &&
    1795          (((dwStyle & TBS_BOTH) &&
     1736         (((infoPtr->dwStyle & TBS_BOTH) &&
    17961737           (clickPoint.x >= thumb.left) &&
    17971738           (clickPoint.x <= thumb.right)
    17981739          ) ||
    1799           ((dwStyle & TBS_LEFT) &&
     1740          ((infoPtr->dwStyle & TBS_LEFT) &&
    18001741           (clickPoint.x <= thumb.right) &&
    18011742           ((clickPoint.x >= thumb.left) ||
     
    18071748           )
    18081749          ) ||
    1809           (!(dwStyle & (TBS_BOTH | TBS_LEFT)) &&
     1750          (!(infoPtr->dwStyle & (TBS_BOTH | TBS_LEFT)) &&
    18101751           (clickPoint.x >= thumb.left) &&
    18111752           ((clickPoint.x <= thumb.right) ||
     
    18211762         (clickPoint.x >= thumb.left) &&
    18221763         (clickPoint.x <= thumb.right) &&
    1823          (((dwStyle & TBS_BOTH) &&
     1764         (((infoPtr->dwStyle & TBS_BOTH) &&
    18241765           (clickPoint.y >= thumb.top) &&
    18251766           (clickPoint.y <= thumb.bottom)
    18261767          ) ||
    1827           ((dwStyle & TBS_TOP) &&
     1768          ((infoPtr->dwStyle & TBS_TOP) &&
    18281769           (clickPoint.y <= thumb.bottom) &&
    18291770           ((clickPoint.y >= thumb.top) ||
     
    18351776           )
    18361777          ) ||
    1837           (!(dwStyle & (TBS_BOTH | TBS_TOP)) &&
     1778          (!(infoPtr->dwStyle & (TBS_BOTH | TBS_TOP)) &&
    18381779           (clickPoint.y >= thumb.top) &&
    18391780           ((clickPoint.y <= thumb.bottom) ||
     
    18481789       {
    18491790         infoPtr->flags |= TB_DRAG_MODE;
    1850          if (dwStyle & TBS_TOOLTIPS)
     1791         if (infoPtr->dwStyle & TBS_TOOLTIPS)
    18511792         {  /* enable tooltip */
    18521793           TTTOOLINFOA ti;
     
    18561797           ti.cbSize   = sizeof(TTTOOLINFOA);
    18571798           ti.uId      = 0;
    1858            ti.hwnd     = (UINT)hwnd;
     1799           ti.hwnd     = (UINT)infoPtr->hwnd;
    18591800           ti.hinst    = 0;
    1860            sprintf (buf,"%d",infoPtr->nPos);
     1801           sprintf (buf,"%ld",infoPtr->nPos);
    18611802           ti.lpszText = (LPSTR)buf;
    18621803
    18631804           infoPtr->flags |= TB_SHOW_TOOLTIP;
    1864            SetCapture(hwnd);
     1805           SetCapture(infoPtr->hwnd);
    18651806
    18661807           SendMessageA(infoPtr->hwndToolTip,TTM_UPDATETIPTEXTA,0,(LPARAM)&ti);
    1867            TRACKBAR_CalcToolTipPos(hwnd,dwStyle,infoPtr,&pt);
     1808           TRACKBAR_CalcToolTipPos(infoPtr,&pt);
    18681809           SendMessageA(infoPtr->hwndToolTip,TTM_TRACKPOSITION,0,(LPARAM)MAKELPARAM(pt.x,pt.y));
    18691810
    18701811           SendMessageA(infoPtr->hwndToolTip,TTM_TRACKACTIVATE,(WPARAM)TRUE,(LPARAM)&ti);
    18711812         }
    1872          SetCapture(hwnd);
    1873          TRACKBAR_UpdateThumbPosition(hwnd,infoPtr->nPos,TRUE); //change arrow color
     1813         SetCapture(infoPtr->hwnd);
     1814         TRACKBAR_UpdateThumbPosition(infoPtr,infoPtr->nPos,TRUE); //change arrow color
    18741815         return 0;
    18751816       }
     
    18831824              //ScrollMode
    18841825              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);
    18871828
    18881829              return 0;
     
    18961837      infoPtr->nPos += infoPtr->nPageSize;
    18971838      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);
    18991840    } else
    19001841    {  /* similar to VK_PRIOR */
    19011842      infoPtr->nPos -= infoPtr->nPageSize;
    19021843      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);
    19041845    }
    19051846
     
    19071848    {
    19081849      infoPtr->flags |= TB_THUMBPOSCHANGED;
    1909       TRACKBAR_UpdateThumbPosition(hwnd,prevPos,TRUE);
     1850      TRACKBAR_UpdateThumbPosition(infoPtr,prevPos,TRUE);
    19101851    }
    19111852
    19121853    //ScrollMode
    19131854    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
     1862static LRESULT
     1863TRACKBAR_LButtonUp(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1864{
    19261865    if (infoPtr->flags & TB_DRAG_MODE)
    19271866    {
    1928       TRACKBAR_SendNotify(hwnd,TB_ENDTRACK);
     1867      TRACKBAR_SendNotify(infoPtr,TB_ENDTRACK);
    19291868
    19301869      infoPtr->flags &= ~TB_DRAG_MODE;
    19311870
    1932       if (GetCapture() == hwnd)
     1871      if (GetCapture() == infoPtr->hwnd)
    19331872      {
    1934         sendNotify(hwnd,NM_RELEASEDCAPTURE);
     1873        sendNotify(infoPtr->hwnd,NM_RELEASEDCAPTURE);
    19351874
    19361875        ReleaseCapture();
    19371876      }
    19381877
    1939       TRACKBAR_UpdateThumbPosition(hwnd,infoPtr->nPos,TRUE); //change arrow color
     1878      TRACKBAR_UpdateThumbPosition(infoPtr,infoPtr->nPos,TRUE); //change arrow color
    19401879    }
    19411880
     
    19441883      infoPtr->flags &= ~TB_SCROLL_MODE;
    19451884
    1946       if (GetCapture() == hwnd)
     1885      if (GetCapture() == infoPtr->hwnd)
    19471886      {
    1948         sendNotify(hwnd,NM_RELEASEDCAPTURE);
     1887        sendNotify(infoPtr->hwnd,NM_RELEASEDCAPTURE);
    19491888
    19501889        ReleaseCapture();
    19511890      }
    19521891
    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)
    19571896    { /* disable tooltip */
    19581897      TTTOOLINFOA ti;
     
    19601899      ti.cbSize   = sizeof(TTTOOLINFOA);
    19611900      ti.uId      = 0;
    1962       ti.hwnd     = (UINT)hwnd;
     1901      ti.hwnd     = (UINT)infoPtr->hwnd;
    19631902
    19641903      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
     1910static LRESULT TRACKBAR_Timer(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1911{
    19761912  POINT mousePoint;
    19771913  INT mousePlace,prevPos,newPos,vertical;
     
    19791915
    19801916  GetCursorPos(&mousePoint);
    1981   ScreenToClient(hwnd,&mousePoint);
    1982 
    1983   vertical = dwStyle & TBS_VERT;
     1917  ScreenToClient(infoPtr->hwnd,&mousePoint);
     1918
     1919  vertical = infoPtr->dwStyle & TBS_VERT;
    19841920  if (vertical) mousePlace = mousePoint.y;
    19851921  else mousePlace = mousePoint.x;
     
    19961932      infoPtr->nPos += infoPtr->nPageSize;
    19971933      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);
    19991935    } else
    20001936    {  /* similar to VK_PRIOR */
    20011937      infoPtr->nPos -= infoPtr->nPageSize;
    20021938      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);
    20041940    }
    20051941
     
    20071943    {
    20081944      infoPtr->flags |= TB_THUMBPOSCHANGED;
    2009       TRACKBAR_UpdateThumbPosition(hwnd,prevPos,FALSE);
     1945      TRACKBAR_UpdateThumbPosition(infoPtr,prevPos,FALSE);
    20101946    }
    20111947
     
    20141950
    20151951static 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);
     1952TRACKBAR_CaptureChanged(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1953{
     1954    sendNotify(infoPtr->hwnd,NM_RELEASEDCAPTURE);
    20271955
    20281956    if (infoPtr->flags & TB_DRAGPOSVALID)
     
    20301958      int lastPos = infoPtr->nPos;
    20311959      infoPtr->nPos = infoPtr->dragPos;
    2032       if (lastPos != infoPtr->nPos) TRACKBAR_UpdateThumbPosition(hwnd,lastPos,TRUE);
     1960      if (lastPos != infoPtr->nPos) TRACKBAR_UpdateThumbPosition(infoPtr,lastPos,TRUE);
    20331961    }
    20341962
     
    20381966    {
    20391967      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
     1976static LRESULT
     1977TRACKBAR_Paint(TRACKBAR_INFO *infoPtr,WPARAM wParam)
    20501978{
    20511979    HDC hdc;
    20521980    PAINTSTRUCT ps;
    20531981
    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
     1989static LRESULT
     1990TRACKBAR_SetFocus(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     1991{
    20651992    HDC hdc;
    20661993    RECT rcClient;
    20671994
    2068 //    TRACE (trackbar,"\n");
    2069     if (!infoPtr->bFocus && IsWindowEnabled(hwnd))
     1995    if (!infoPtr->bFocus && IsWindowEnabled(infoPtr->hwnd))
    20701996    {
    20711997      infoPtr->bFocus = TRUE;
    20721998
    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
     2007static LRESULT
     2008TRACKBAR_KillFocus(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     2009{
    20862010    HDC hdc;
    20872011    RECT rcClient;
    20882012
    2089 //    TRACE (trackbar,"\n");
    20902013
    20912014    infoPtr->flags &= ~TB_DRAG_MODE;
    2092     if (infoPtr->bFocus && IsWindowEnabled(hwnd))
     2015    if (infoPtr->bFocus && IsWindowEnabled(infoPtr->hwnd))
    20932016    {
    20942017      infoPtr->bFocus = FALSE;
    20952018
    2096       GetClientRect(hwnd,&rcClient);
    2097       hdc = GetDC (hwnd);
     2019      GetClientRect(infoPtr->hwnd,&rcClient);
     2020      hdc = GetDC(infoPtr->hwnd);
    20982021      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
     2028static LRESULT
     2029TRACKBAR_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
     2063static BOOL TRACKBAR_SendNotify(TRACKBAR_INFO *infoPtr,UINT code)
     2064{
     2065  if (infoPtr->dwStyle & TBS_VERT)
     2066    return sendVScroll(infoPtr->hwnd,code);
    21212067  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
     2071static LRESULT
     2072TRACKBAR_MouseMove(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     2073{
    21312074    SHORT clickPlace;
    21322075    DOUBLE dragPos;
     
    21342077    if (!(infoPtr->flags & TB_DRAG_MODE)) return TRUE;
    21352078
    2136     if (dwStyle & TBS_VERT) clickPlace = (SHORT)HIWORD(lParam);
     2079    if (infoPtr->dwStyle & TBS_VERT) clickPlace = (SHORT)HIWORD(lParam);
    21372080    else clickPlace = (SHORT)LOWORD(lParam);
    21382081
    2139     dragPos = TRACKBAR_ConvertPlaceToPosition(infoPtr,clickPlace,dwStyle & TBS_VERT);
     2082    dragPos = TRACKBAR_ConvertPlaceToPosition(infoPtr,clickPlace,infoPtr->dwStyle & TBS_VERT);
    21402083    if (dragPos > ((INT)dragPos)+0.5) infoPtr->dragPos = dragPos + 1;
    21412084    else infoPtr->dragPos = dragPos;
     
    21452088    infoPtr->flags |= TB_DRAGPOSVALID;
    21462089
    2147     TRACKBAR_UpdateThumbPosition(hwnd,infoPtr->nPos,FALSE); //infoPtr->nPos now set
    2148 
    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));
    21502093
    21512094    if (infoPtr->flags & TB_SHOW_TOOLTIP)
     
    21562099
    21572100      ti.cbSize = sizeof(TTTOOLINFOA);
    2158       ti.hwnd = hwnd;
     2101      ti.hwnd = infoPtr->hwnd;
    21592102      ti.uId = 0;
    21602103      ti.hinst = 0;
     
    21632106
    21642107      SendMessageA(infoPtr->hwndToolTip,TTM_UPDATETIPTEXTA,0,(LPARAM)&ti);
    2165       TRACKBAR_CalcToolTipPos(hwnd,dwStyle,infoPtr,&pt);
     2108      TRACKBAR_CalcToolTipPos(infoPtr,&pt);
    21662109      SendMessageA(infoPtr->hwndToolTip,TTM_TRACKPOSITION,0,(LPARAM)MAKELPARAM(pt.x,pt.y));
    21672110    }
     
    21712114
    21722115static LRESULT
    2173 TRACKBAR_Enable(HWND hwnd,WPARAM wParam,LPARAM lParam)
    2174 {
    2175   TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd);
     2116TRACKBAR_Enable(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     2117{
    21762118  BOOL oldFocus = infoPtr->bFocus;
    21772119
    2178   if (wParam) infoPtr->bFocus = (GetFocus() == hwnd);
     2120  if (wParam) infoPtr->bFocus = (GetFocus() == infoPtr->hwnd);
    21792121  else infoPtr->bFocus = FALSE;
    21802122
    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);
    21832125
    21842126  return 0;
     
    21862128
    21872129static LRESULT
    2188 TRACKBAR_KeyDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
    2189 {
    2190     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd);
     2130TRACKBAR_KeyDown(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     2131{
    21912132    INT pos;
    2192 
    2193 //    TRACE (trackbar, "%x\n",wParam);
    21942133
    21952134    if (infoPtr->flags & TB_DRAG_MODE) return TRUE;
     
    22032142        if (infoPtr->nPos < infoPtr->nRangeMin)
    22042143            infoPtr->nPos = infoPtr->nRangeMin;
    2205         TRACKBAR_SendNotify(hwnd,TB_LINEUP);
     2144        TRACKBAR_SendNotify(infoPtr,TB_LINEUP);
    22062145        break;
    22072146    case VK_RIGHT:
     
    22112150        if (infoPtr->nPos > infoPtr->nRangeMax)
    22122151            infoPtr->nPos = infoPtr->nRangeMax;
    2213         TRACKBAR_SendNotify (hwnd, TB_LINEDOWN);
     2152        TRACKBAR_SendNotify(infoPtr,TB_LINEDOWN);
    22142153        break;
    22152154    case VK_NEXT:
     
    22182157        if (infoPtr->nPos > infoPtr->nRangeMax)
    22192158            infoPtr->nPos = infoPtr->nRangeMax;
    2220         TRACKBAR_SendNotify (hwnd, TB_PAGEUP);
     2159        TRACKBAR_SendNotify(infoPtr,TB_PAGEUP);
    22212160        break;
    22222161    case VK_PRIOR:
     
    22252164        if (infoPtr->nPos < infoPtr->nRangeMin)
    22262165            infoPtr->nPos = infoPtr->nRangeMin;
    2227         TRACKBAR_SendNotify (hwnd, TB_PAGEDOWN);
     2166        TRACKBAR_SendNotify(infoPtr,TB_PAGEDOWN);
    22282167        break;
    22292168    case VK_HOME:
    22302169        if (infoPtr->nPos == infoPtr->nRangeMin) return FALSE;
    22312170        infoPtr->nPos = infoPtr->nRangeMin;
    2232         TRACKBAR_SendNotify (hwnd, TB_TOP);
     2171        TRACKBAR_SendNotify(infoPtr,TB_TOP);
    22332172        break;
    22342173    case VK_END:
    22352174        if (infoPtr->nPos == infoPtr->nRangeMax) return FALSE;
    22362175        infoPtr->nPos = infoPtr->nRangeMax;
    2237         TRACKBAR_SendNotify (hwnd, TB_BOTTOM);
     2176        TRACKBAR_SendNotify(infoPtr,TB_BOTTOM);
    22382177        break;
     2178
     2179      default:
     2180        return FALSE;
    22392181    }
    22402182
     
    22422184    {
    22432185      infoPtr->flags |= TB_THUMBPOSCHANGED;
    2244       TRACKBAR_UpdateThumbPosition(hwnd,pos,FALSE);
     2186      TRACKBAR_UpdateThumbPosition(infoPtr,pos,FALSE);
    22452187    }
    22462188
     
    22502192
    22512193static LRESULT
    2252 TRACKBAR_KeyUp (HWND hwnd, WPARAM wParam)
    2253 {
    2254     TRACKBAR_INFO *infoPtr = TRACKBAR_GetInfoPtr(hwnd);
    2255 
     2194TRACKBAR_KeyUp(TRACKBAR_INFO *infoPtr,WPARAM wParam)
     2195{
    22562196    if (infoPtr->flags & TB_DRAG_MODE) return TRUE;
    22572197
     
    22652205    case VK_HOME:
    22662206    case VK_END:
    2267         TRACKBAR_SendNotify (hwnd, TB_ENDTRACK);
     2207        TRACKBAR_SendNotify(infoPtr,TB_ENDTRACK);
    22682208    }
    22692209    return TRUE;
    22702210}
    22712211
     2212static LRESULT
     2213TRACKBAR_StyleChanged(TRACKBAR_INFO *infoPtr,WPARAM wParam,LPSTYLESTRUCT lParam)
     2214{
     2215  TRACKBAR_CalcChannel(infoPtr);
     2216
     2217  return 0;
     2218}
    22722219
    22732220static LRESULT WINAPI
    2274 TRACKBAR_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    2275 {
    2276     switch (uMsg)
    2277     {
     2221TRACKBAR_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  {
    22782235    case TBM_CLEARSEL:
    2279         return TRACKBAR_ClearSel (hwnd, wParam, lParam);
     2236        return TRACKBAR_ClearSel(infoPtr,wParam,lParam);
    22802237
    22812238    case TBM_CLEARTICS:
    2282         return TRACKBAR_ClearTics (hwnd, wParam, lParam);
     2239        return TRACKBAR_ClearTics(infoPtr,wParam,lParam);
    22832240
    22842241    case TBM_GETBUDDY:
    2285         return TRACKBAR_GetBuddy (hwnd, wParam, lParam);
     2242        return TRACKBAR_GetBuddy(infoPtr,wParam,lParam);
    22862243
    22872244    case TBM_GETCHANNELRECT:
    2288         return TRACKBAR_GetChannelRect (hwnd, wParam, lParam);
     2245        return TRACKBAR_GetChannelRect(infoPtr,wParam,lParam);
    22892246
    22902247    case TBM_GETLINESIZE:
    2291         return TRACKBAR_GetLineSize (hwnd, wParam, lParam);
     2248        return TRACKBAR_GetLineSize(infoPtr,wParam,lParam);
    22922249
    22932250    case TBM_GETNUMTICS:
    2294         return TRACKBAR_GetNumTics (hwnd, wParam, lParam);
     2251        return TRACKBAR_GetNumTics(infoPtr,wParam,lParam);
    22952252
    22962253    case TBM_GETPAGESIZE:
    2297         return TRACKBAR_GetPageSize (hwnd, wParam, lParam);
     2254        return TRACKBAR_GetPageSize(infoPtr,wParam,lParam);
    22982255
    22992256    case TBM_GETPOS:
    2300         return TRACKBAR_GetPos (hwnd, wParam, lParam);
     2257        return TRACKBAR_GetPos(infoPtr,wParam,lParam);
    23012258
    23022259    case TBM_GETPTICS:
    2303         return TRACKBAR_GetPTics (hwnd);
     2260        return TRACKBAR_GetPTics(infoPtr);
    23042261
    23052262    case TBM_GETRANGEMAX:
    2306         return TRACKBAR_GetRangeMax (hwnd, wParam, lParam);
     2263        return TRACKBAR_GetRangeMax(infoPtr,wParam,lParam);
    23072264
    23082265    case TBM_GETRANGEMIN:
    2309         return TRACKBAR_GetRangeMin (hwnd, wParam, lParam);
     2266        return TRACKBAR_GetRangeMin(infoPtr,wParam,lParam);
    23102267
    23112268    case TBM_GETSELEND:
    2312         return TRACKBAR_GetSelEnd (hwnd, wParam, lParam);
     2269        return TRACKBAR_GetSelEnd(infoPtr,wParam,lParam);
    23132270
    23142271    case TBM_GETSELSTART:
    2315         return TRACKBAR_GetSelStart (hwnd, wParam, lParam);
     2272        return TRACKBAR_GetSelStart(infoPtr,wParam,lParam);
    23162273
    23172274    case TBM_GETTHUMBLENGTH:
    2318         return TRACKBAR_GetThumbLength (hwnd, wParam, lParam);
     2275        return TRACKBAR_GetThumbLength(infoPtr,wParam,lParam);
    23192276
    23202277    case TBM_GETTHUMBRECT:
    2321         return TRACKBAR_GetThumbRect (hwnd, wParam, lParam);
     2278        return TRACKBAR_GetThumbRect(infoPtr,wParam,lParam);
    23222279
    23232280    case TBM_GETTIC:
    2324         return TRACKBAR_GetTic (hwnd, wParam, lParam);
     2281        return TRACKBAR_GetTic(infoPtr,wParam,lParam);
    23252282
    23262283    case TBM_GETTICPOS:
    2327         return TRACKBAR_GetTicPos (hwnd, wParam, lParam);
     2284        return TRACKBAR_GetTicPos(infoPtr,wParam,lParam);
    23282285
    23292286    case TBM_GETTOOLTIPS:
    2330         return TRACKBAR_GetToolTips (hwnd, wParam, lParam);
     2287        return TRACKBAR_GetToolTips(infoPtr,wParam,lParam);
    23312288
    23322289    case TBM_SETBUDDY:
    2333         return TRACKBAR_SetBuddy (hwnd, wParam, lParam);
     2290        return TRACKBAR_SetBuddy(infoPtr,wParam,lParam);
    23342291
    23352292    case TBM_SETLINESIZE:
    2336         return TRACKBAR_SetLineSize (hwnd, wParam, lParam);
     2293        return TRACKBAR_SetLineSize(infoPtr,wParam,lParam);
    23372294
    23382295    case TBM_SETPAGESIZE:
    2339         return TRACKBAR_SetPageSize (hwnd, wParam, lParam);
     2296        return TRACKBAR_SetPageSize(infoPtr,wParam,lParam);
    23402297
    23412298    case TBM_SETPOS:
    2342         return TRACKBAR_SetPos (hwnd, wParam, lParam);
     2299        return TRACKBAR_SetPos(infoPtr,wParam,lParam);
    23432300
    23442301    case TBM_SETRANGE:
    2345         return TRACKBAR_SetRange (hwnd, wParam, lParam);
     2302        return TRACKBAR_SetRange(infoPtr,wParam,lParam);
    23462303
    23472304    case TBM_SETRANGEMAX:
    2348         return TRACKBAR_SetRangeMax (hwnd, wParam, lParam);
     2305        return TRACKBAR_SetRangeMax(infoPtr,wParam,lParam);
    23492306
    23502307    case TBM_SETRANGEMIN:
    2351         return TRACKBAR_SetRangeMin (hwnd, wParam, lParam);
     2308        return TRACKBAR_SetRangeMin(infoPtr,wParam,lParam);
    23522309
    23532310    case TBM_SETSEL:
    2354         return TRACKBAR_SetSel (hwnd, wParam, lParam);
     2311        return TRACKBAR_SetSel(infoPtr,wParam,lParam);
    23552312
    23562313    case TBM_SETSELEND:
    2357         return TRACKBAR_SetSelEnd (hwnd, wParam, lParam);
     2314        return TRACKBAR_SetSelEnd(infoPtr,wParam,lParam);
    23582315
    23592316    case TBM_SETSELSTART:
    2360         return TRACKBAR_SetSelStart (hwnd, wParam, lParam);
     2317        return TRACKBAR_SetSelStart(infoPtr,wParam,lParam);
    23612318
    23622319    case TBM_SETTHUMBLENGTH:
    2363         return TRACKBAR_SetThumbLength (hwnd, wParam, lParam);
     2320        return TRACKBAR_SetThumbLength(infoPtr,wParam,lParam);
    23642321
    23652322    case TBM_SETTIC:
    2366         return TRACKBAR_SetTic (hwnd, wParam, lParam);
     2323        return TRACKBAR_SetTic(infoPtr,wParam,lParam);
    23672324
    23682325    case TBM_SETTICFREQ:
    2369         return TRACKBAR_SetTicFreq (hwnd, wParam);
     2326        return TRACKBAR_SetTicFreq(infoPtr,wParam);
    23702327
    23712328    case TBM_SETTIPSIDE:
    2372         return TRACKBAR_SetTipSide (hwnd, wParam, lParam);
     2329        return TRACKBAR_SetTipSide(infoPtr,wParam,lParam);
    23732330
    23742331    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);
    23792333
    23802334    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);
    23852336
    23862337    case WM_DESTROY:
    2387         return TRACKBAR_Destroy (hwnd, wParam, lParam);
     2338        return TRACKBAR_Destroy(infoPtr,wParam,lParam);
    23882339
    23892340    case WM_ENABLE:
    2390         return TRACKBAR_Enable(hwnd,wParam,lParam);
     2341        return TRACKBAR_Enable(infoPtr,wParam,lParam);
    23912342
    23922343    case WM_ERASEBKGND:
     
    23972348
    23982349    case WM_KEYDOWN:
    2399         return TRACKBAR_KeyDown (hwnd, wParam, lParam);
     2350        return TRACKBAR_KeyDown(infoPtr,wParam,lParam);
    24002351
    24012352    case WM_KEYUP:
    2402         return TRACKBAR_KeyUp (hwnd, wParam);
     2353        return TRACKBAR_KeyUp(infoPtr,wParam);
    24032354
    24042355    case WM_LBUTTONDOWN:
    2405         return TRACKBAR_LButtonDown (hwnd, wParam, lParam);
     2356        return TRACKBAR_LButtonDown(infoPtr,wParam,lParam);
    24062357
    24072358    case WM_LBUTTONUP:
    2408         return TRACKBAR_LButtonUp (hwnd, wParam, lParam);
     2359        return TRACKBAR_LButtonUp(infoPtr,wParam,lParam);
    24092360
    24102361    case WM_TIMER:
    2411         return TRACKBAR_Timer(hwnd,wParam,lParam);
     2362        return TRACKBAR_Timer(infoPtr,wParam,lParam);
    24122363
    24132364    case WM_MOUSEMOVE:
    2414         return TRACKBAR_MouseMove (hwnd, wParam, lParam);
     2365        return TRACKBAR_MouseMove(infoPtr,wParam,lParam);
    24152366
    24162367    case WM_PAINT:
    2417         return TRACKBAR_Paint (hwnd, wParam);
     2368        return TRACKBAR_Paint(infoPtr,wParam);
    24182369
    24192370    case WM_SETFOCUS:
    2420         return TRACKBAR_SetFocus (hwnd, wParam, lParam);
     2371        return TRACKBAR_SetFocus(infoPtr,wParam,lParam);
    24212372
    24222373    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);
    24242378
    24252379    case WM_SIZE:
    2426         return TRACKBAR_Size (hwnd, wParam, lParam);
     2380        return TRACKBAR_Size(infoPtr,wParam,lParam);
    24272381
    24282382    case WM_WININICHANGE:
    2429         return TRACKBAR_InitializeThumb (hwnd);
     2383        return TRACKBAR_InitializeThumb(infoPtr);
     2384
     2385    case WM_SYSCOLORCHANGE:
     2386        return TRACKBAR_InitColors(infoPtr,TRUE);
    24302387
    24312388    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);
    24362394    }
    24372395    return 0;
     
    24422400TRACKBAR_Register (VOID)
    24432401{
    2444     WNDCLASSA wndClass;
    2445 
    2446     ZeroMemory (&wndClass, sizeof(WNDCLASSA));
    2447     wndClass.style         = CS_GLOBALCLASS;
    2448     wndClass.lpfnWndProc   = (WNDPROC)TRACKBAR_WindowProc;
    2449     wndClass.cbClsExtra    = 0;
    2450     wndClass.cbWndExtra    = sizeof(TRACKBAR_INFO *);
    2451     wndClass.hCursor       = LoadCursorA (0, IDC_ARROWA);
    2452     wndClass.hbrBackground = (HBRUSH)(COLOR_3DFACE + 1);
    2453     wndClass.lpszClassName = TRACKBAR_CLASSA;
    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);
    24562414}
    24572415
     
    24602418TRACKBAR_Unregister (VOID)
    24612419{
    2462     UnregisterClassA (TRACKBAR_CLASSA, (HINSTANCE)NULL);
    2463 }
    2464 
     2420  UnregisterClassA (TRACKBAR_CLASSA, (HINSTANCE)NULL);
     2421}
     2422
  • trunk/src/comctl32/treeview.cpp

    r3520 r3585  
    1 /* $Id: treeview.cpp,v 1.13 2000-05-10 19:50:33 cbratschi Exp $ */
     1/* $Id: treeview.cpp,v 1.14 2000-05-22 17:25:13 cbratschi Exp $ */
    22/* Treeview control
    33 *
     
    88 * Copyright 1999-2000 Christoph Bratschi (cbratschi@datacomm.ch)
    99 *
     10 * Note that TREEVIEW_INFO * and HTREEITEM are the same thing.
    1011 *
    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.
    1512 *
    1613 * Status: complete (many things untested)
     
    3027 - expand not finished
    3128 - 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
    3247*/
    3348
     49#include <assert.h>
    3450#include <stdlib.h>
    3551#include <string.h>
    3652#include <math.h>
     53#include <limits.h>
    3754#include "winbase.h"
    3855#include "wingdi.h"
     
    4562/* ffs should be in <string.h>. */
    4663
    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
     78typedef VOID (*TREEVIEW_ItemEnumFunc)(TREEVIEW_INFO *, TREEVIEW_ITEM *,LPVOID);
     79
     80static BOOL    TREEVIEW_UnqueueRefresh(TREEVIEW_INFO *,BOOL calc,BOOL refresh);
     81static void    TREEVIEW_QueueRefresh(TREEVIEW_INFO *);
     82static void    TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr);
     83static void    TREEVIEW_RefreshItem(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,DWORD changed);
     84
     85static VOID    TREEVIEW_HideInfoTip(TREEVIEW_INFO *infoPtr);
     86static LRESULT TREEVIEW_DoSelectItem(TREEVIEW_INFO *, INT, HTREEITEM, INT);
     87static LRESULT TREEVIEW_EnsureVisible(TREEVIEW_INFO *, HTREEITEM);
     88static LRESULT TREEVIEW_RButtonUp(TREEVIEW_INFO *, LPPOINT);
     89static LRESULT TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr, BOOL bCancel);
     90static VOID    TREEVIEW_UpdateScrollBars(TREEVIEW_INFO *infoPtr, BOOL);
     91static VOID    TREEVIEW_CheckInfoTip(TREEVIEW_INFO *infoPtr);
     92static VOID    TREEVIEW_ISearch(TREEVIEW_INFO *infoPtr,CHAR ch);
     93
     94/* Random Utilities *****************************************************/
     95
     96#ifdef NDEBUG
     97static inline void
     98TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr)
     99{
     100    (void)infoPtr;
     101}
     102
     103#else
     104/* The definition is at the end of the file. */
     105static void TREEVIEW_VerifyTree(TREEVIEW_INFO *infoPtr);
     106#ifndef NDEBUG_TEXT
     107static void TREEVIEW_WriteVerify(CHAR *text)
     108{
     109  dprintf((text));
     110}
     111#else
     112static 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. */
     121static inline int
     122TREEVIEW_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.
    51131 */
    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.
     132static BOOL
     133TREEVIEW_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
     144static HFONT
     145TREEVIEW_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
     155static inline HFONT
     156TREEVIEW_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 */
     162static const WCHAR *
     163TREEVIEW_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. */
     176static BOOL
     177TREEVIEW_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
    95193 */
     194static TREEVIEW_ITEM *
     195TREEVIEW_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}
    96213
    97214/***************************************************************************
    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
    170216 * considering the tree hierarchy.
    171217 */
    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]);
     218static TREEVIEW_ITEM *
     219TREEVIEW_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;
    192234    }
    193235    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    }
    206242}
    207243
     
    211247 * considering the tree hierarchy.
    212248 */
    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;
     249static TREEVIEW_ITEM *
     250TREEVIEW_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;
    247282}
    248283
     
    254289 *             forward if count is >0.
    255290 */
    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 
     291static TREEVIEW_ITEM *
     292TREEVIEW_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
     323static VOID
     324TREEVIEW_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
     337static VOID
     338TREEVIEW_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
     353static 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
     407static BOOL
     408TREEVIEW_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
     424static BOOL
     425TREEVIEW_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 */
     445static BOOL
     446TREEVIEW_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
     486static void
     487TREEVIEW_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
     498static void
     499TREEVIEW_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
     563static 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}
    298572
    299573/***************************************************************************
    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.
    301580 */
    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 
     581static INT
     582TREEVIEW_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
     591static VOID
     592TREEVIEW_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
     618static INT CALLBACK
     619TREEVIEW_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
     631static 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);
    1217635  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
     638static BOOL TREEVIEW_CalcItems(TREEVIEW_INFO *infoPtr)
    1358639{
    1359640  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;
    1365644  INT maxXScroll,maxYScroll;
    1366645  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
    1419667    if ((infoPtr->uInternalStatus & TV_CALCALL) || !item->calculated)
    1420668    {
    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);
    1475699  infoPtr->uInternalStatus &= ~TV_CALCALL;
    1476   infoPtr->uTotalHeight = y;
    1477 
    1478   //check cx and cy
     700
     701  // 3) check lefttop
    1479702  yDiff = xDiff = 0;
    1480703
    1481   maxYScroll = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
     704  maxYScroll = infoPtr->treeHeight-infoPtr->clientHeight;
    1482705  if (maxYScroll < 0) maxYScroll = 0;
    1483706  if (infoPtr->lefttop.y > maxYScroll)
    1484707  {
    1485     INT mod = maxYScroll % infoPtr->uVScrollStep;
    1486 
    1487     if (mod > 0) maxYScroll += infoPtr->uVScrollStep-mod;
     708    INT mod = maxYScroll % infoPtr->uItemHeight;
     709
     710    if (mod > 0) maxYScroll += infoPtr->uItemHeight-mod;
    1488711    yDiff = infoPtr->lefttop.y-maxYScroll;
    1489712    infoPtr->lefttop.y = maxYScroll;
    1490713  }
    1491714
    1492   maxXScroll = infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
     715  maxXScroll = infoPtr->treeWidth-infoPtr->clientWidth;
    1493716  if (maxXScroll < 0) maxXScroll = 0;
    1494717  if (infoPtr->lefttop.x > maxXScroll)
     
    1501724  if (changedLeftTop)
    1502725  {
    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)
    1545747    {
    1546748      SCROLLINFO info;
    1547       INT visH = ((INT)(infoPtr->uVisibleHeight/infoPtr->uVScrollStep))*infoPtr->uVScrollStep;
     749      INT visH = ((INT)(infoPtr->clientHeight/infoPtr->uItemHeight))*infoPtr->uItemHeight;
    1548750
    1549751      info.cbSize = sizeof(info);
    1550752      info.nMin   = 0;
    1551       info.nMax   = infoPtr->uTotalHeight-1;
     753      info.nMax   = infoPtr->treeHeight-1;
    1552754      info.nPos   = infoPtr->lefttop.y;
    1553755      info.nPage  = visH;
    1554756      info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
    1555757      infoPtr->uInternalStatus |= TV_VSCROLL;
    1556       SetScrollInfo(hwnd,SB_VERT,&info,TRUE);
     758      SetScrollInfo(infoPtr->hwnd,SB_VERT,&info,TRUE);
    1557759    } else
    1558760    {
    1559761      if (infoPtr->uInternalStatus & TV_VSCROLL)
    1560         ShowScrollBar(hwnd,SB_VERT,FALSE);
     762        ShowScrollBar(infoPtr->hwnd,SB_VERT,FALSE);
    1561763      infoPtr->uInternalStatus &= ~TV_VSCROLL;
    1562764    }
    1563     if (!(dwStyle & TVS_NOHSCROLL) && (infoPtr->uTotalWidth > infoPtr->uVisibleWidth))
     765    if (!(infoPtr->dwStyle & TVS_NOHSCROLL) && (infoPtr->treeWidth > infoPtr->clientWidth))
    1564766    {
    1565767      SCROLLINFO info;
     
    1567769      info.cbSize = sizeof(info);
    1568770      info.nMin   = 0;
    1569       info.nMax   = infoPtr->uTotalWidth-1;
     771      info.nMax   = infoPtr->treeWidth-1;
    1570772      info.nPos   = infoPtr->lefttop.x;
    1571       info.nPage  = MAX(infoPtr->uVisibleWidth,1);
     773      info.nPage  = MAX(infoPtr->clientWidth,1);
    1572774      info.fMask  = SIF_RANGE | SIF_POS | SIF_PAGE;
    1573775      infoPtr->uInternalStatus |= TV_HSCROLL;
    1574       SetScrollInfo(hwnd,SB_HORZ,&info,TRUE);
     776      SetScrollInfo(infoPtr->hwnd,SB_HORZ,&info,TRUE);
    1575777    } else
    1576778    {
    1577779      if (infoPtr->uInternalStatus & TV_HSCROLL)
    1578         ShowScrollBar(hwnd,SB_HORZ,FALSE);
     780        ShowScrollBar(infoPtr->hwnd,SB_HORZ,FALSE);
    1579781      infoPtr->uInternalStatus &= ~TV_HSCROLL;
    1580782    }
     
    1582784  {
    1583785    if (infoPtr->uInternalStatus & (TV_VSCROLL | TV_HSCROLL))
    1584       ShowScrollBar(hwnd,SB_BOTH,FALSE);
     786      ShowScrollBar(infoPtr->hwnd,SB_BOTH,FALSE);
    1585787    infoPtr->uInternalStatus &= ~(TV_VSCROLL | TV_HSCROLL);
    1586788  }
    1587789
     790  infoPtr->dwStyle = GetWindowLongA(infoPtr->hwnd,GWL_STYLE);
     791
    1588792  return changedLeftTop;
    1589793}
    1590794
     795static 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
     819static TREEVIEW_ITEM *
     820TREEVIEW_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. */
    1591839static 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;
     840TREEVIEW_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 */
     853static void
     854TREEVIEW_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 */
     887static void
     888TREEVIEW_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
     917static BOOL
     918TREEVIEW_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. */
     1051static LRESULT
     1052TREEVIEW_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 ************************************************************/
     1204static void
     1205TREEVIEW_RemoveItem(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *wineItem);
     1206
     1207static void
     1208TREEVIEW_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
     1226static void
     1227TREEVIEW_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
     1251static void
     1252TREEVIEW_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. */
     1282static void
     1283TREEVIEW_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
     1290static LRESULT
     1291TREEVIEW_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
     1339static LRESULT
     1340TREEVIEW_GetIndent(TREEVIEW_INFO *infoPtr)
     1341{
     1342  return infoPtr->uIndent;
     1343}
     1344
     1345static LRESULT
     1346TREEVIEW_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
     1365static LRESULT
     1366TREEVIEW_GetToolTips(TREEVIEW_INFO *infoPtr)
     1367{
     1368    return infoPtr->hwndToolTip;
     1369}
     1370
     1371static LRESULT
     1372TREEVIEW_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
     1382static LRESULT
     1383TREEVIEW_GetScrollTime(TREEVIEW_INFO *infoPtr)
     1384{
     1385    return infoPtr->uScrollTime;
     1386}
     1387
     1388static LRESULT
     1389TREEVIEW_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
     1399static LRESULT
     1400TREEVIEW_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
     1415static LRESULT
     1416TREEVIEW_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. */
     1461static UINT
     1462TREEVIEW_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
     1482static LRESULT
     1483TREEVIEW_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
     1510static LRESULT
     1511TREEVIEW_GetItemHeight(TREEVIEW_INFO *infoPtr)
     1512{
     1513    return infoPtr->uItemHeight;
     1514}
     1515
     1516
     1517static LRESULT
     1518TREEVIEW_GetFont(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     1519{
     1520    return infoPtr->hFont;
     1521}
     1522
     1523static LRESULT
     1524TREEVIEW_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
     1548static LRESULT
     1549TREEVIEW_GetLineColor(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     1550{
     1551    return (LRESULT)infoPtr->clrLine;
     1552}
     1553
     1554static LRESULT
     1555TREEVIEW_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
     1565static LRESULT
     1566TREEVIEW_GetTextColor(TREEVIEW_INFO *infoPtr)
     1567{
     1568    return (LRESULT)infoPtr->clrText;
     1569}
     1570
     1571static LRESULT
     1572TREEVIEW_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
     1585static LRESULT
     1586TREEVIEW_GetBkColor(TREEVIEW_INFO *infoPtr)
     1587{
     1588    return (LRESULT)infoPtr->clrBk;
     1589}
     1590
     1591static LRESULT
     1592TREEVIEW_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
     1605static LRESULT
     1606TREEVIEW_GetInsertMarkColor(TREEVIEW_INFO *infoPtr, WPARAM wParam,
     1607                            LPARAM lParam)
     1608{
     1609    return (LRESULT)infoPtr->clrInsertMark;
     1610}
     1611
     1612static LRESULT
     1613TREEVIEW_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
     1624static LRESULT
     1625TREEVIEW_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 */
     1642static LRESULT
     1643TREEVIEW_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
     1686static inline LRESULT
     1687TREEVIEW_GetVisibleCount(TREEVIEW_INFO *infoPtr)
     1688{
     1689    /* Suprise! This does not take integral height into account. */
     1690    return infoPtr->clientHeight / infoPtr->uItemHeight;
     1691}
     1692
     1693static LRESULT
     1694TREEVIEW_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. */
     1744static LRESULT
     1745TREEVIEW_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
     1776static LRESULT
     1777TREEVIEW_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
     1787static LRESULT
     1788TREEVIEW_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
     1872static LRESULT
     1873TREEVIEW_GetCount(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     1874{
     1875    return (LRESULT)infoPtr->uNumItems;
     1876}
     1877
     1878static VOID
     1879TREEVIEW_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. */
     1906static void
     1907TREEVIEW_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
     2002static 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
     2021static void
     2022TREEVIEW_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
     2255static 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
     2271static 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
     2291static void
     2292TREEVIEW_Draw(TREEVIEW_INFO *infoPtr,HDC hdc,RECT *updateRect)
     2293{
    15972294    RECT rect;
    15982295    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);
    16062301    if ((rect.left == rect.right) || (rect.top == rect.bottom)) return;
    16072302
    1608     infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(hwnd, CDDS_PREPAINT, hdc, rect);
     2303    infoPtr->cdmode = TREEVIEW_SendCustomDrawNotify(infoPtr,CDDS_PREPAINT,hdc,rect);
    16092304
    16102305    if (infoPtr->cdmode == CDRF_SKIPDEFAULT) return;
    16112306
    1612     //draw items
    1613 
    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
    16232318      {
    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);
    16362323      }
    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    }
    16542326
    16552327    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
     2331static void TREEVIEW_Refresh(TREEVIEW_INFO *infoPtr)
     2332{
     2333  TREEVIEW_UnqueueRefresh(infoPtr,TRUE,FALSE);
     2334
     2335  InvalidateRect(infoPtr->hwnd,NULL,TRUE);
     2336}
     2337
     2338static 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
     2358static LRESULT
     2359TREEVIEW_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);
    16692370  } else
    1670   {
    1671     infoPtr->uInternalStatus |= TV_NOREDRAW;
    1672   }
     2371      TREEVIEW_Draw(infoPtr,hdc,NULL);
    16732372
    16742373  return 0;
    16752374}
    16762375
    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 **************************************************************/
    20052377
    20062378/***************************************************************************
    20072379 * Forward the DPA local callback to the treeview owner callback
    20082380 */
    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);
     2381static INT WINAPI
     2382TREEVIEW_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);
    20182393}
    20192394
     
    20212396 * Treeview native sort routine: sort on item text.
    20222397 */
    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;
     2398static INT WINAPI
     2399TREEVIEW_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. */
     2413static INT
     2414TREEVIEW_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. */
     2427static HDPA
     2428TREEVIEW_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;
    20482445}
    20492446
     
    20592456 */
    20602457
    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)
     2458static LRESULT
     2459TREEVIEW_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    }
    20832550    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     do
    2105     {
    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         else
    2123                 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         else
    2146           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;
    21682551}
    21692552
     
    21722555 * and sort the children of the TV item specified in lParam
    21732556 */
    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);
     2557static LRESULT
     2558TREEVIEW_SortChildrenCB(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     2559{
     2560    LPTVSORTCB pSort = (LPTVSORTCB)lParam;
     2561
     2562    return TREEVIEW_Sort(infoPtr, wParam, pSort->hParent, pSort);
    21792563}
    21802564
     
    21832567 * Sort the children of the TV item specified in lParam.
    21842568 */
    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)
     2569static LRESULT
     2570TREEVIEW_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
     2578static BOOL
     2579TREEVIEW_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
     2588static VOID
     2589TREEVIEW_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. */
     2601static BOOL
     2602TREEVIEW_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
     2657static BOOL
     2658TREEVIEW_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        {
     2675return 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)
    23102718      {
    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;
    23152720      } else
    23162721      {
    2317         wineItem->pszText = LPSTR_TEXTCALLBACKW;
    2318         wineItem->cchTextMax = 0;
     2722        INT diff = wineItem->lastChild->rect.bottom-clientH;
     2723
     2724        infoPtr->lefttop.y += diff;
    23192725      }
    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!
    29082731
    29092732    return TRUE;
    29102733}
    29112734
    2912 static LRESULT TREEVIEW_GetDlgCode(HWND hwnd,WPARAM wParam,LPARAM lParam)
    2913 {
    2914   return DLGC_WANTARROWS | DLGC_WANTCHARS;
    2915 }
    2916 
    2917 /* Notifications */
    2918 
    29192735static 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);
     2736TREEVIEW_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
     2744static VOID
     2745TREEVIEW_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    }
    32562754}
    32572755
     
    32632761
    32642762static LRESULT
    3265 TREEVIEW_Expand (HWND hwnd, WPARAM wParam, LPARAM lParam)
    3266 {
    3267   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
     2763TREEVIEW_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
     2792static TREEVIEW_ITEM *
     2793TREEVIEW_HitTestPoint(TREEVIEW_INFO *infoPtr,POINT pt)
     2794{
    32682795  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
     2808static LRESULT
     2809TREEVIEW_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    }
    32872868    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
     2881static LRESULT
     2882TREEVIEW_GetEditControl(TREEVIEW_INFO *infoPtr)
     2883{
     2884    return infoPtr->hwndEdit;
     2885}
     2886
     2887static LRESULT CALLBACK
     2888TREEVIEW_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:
    33222896        {
    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;
    33262923            break;
    33272924        }
    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)
    33712926        {
    3372           //ERR(treeview,
    3373           //  "Catastropic situation, cannot retreive item #%d\n",
    3374           //  expand);
    3375           return FALSE;
     2927            break;
    33762928        }
    33772929
    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 */
    33982931    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;
    34492950
    34502951    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
     2957static LRESULT
     2958TREEVIEW_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
     3024HWND TREEVIEW_EditLabel(TREEVIEW_INFO *infoPtr,HTREEITEM hItem,BOOL unicode)
    34853025{
    34863026  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);
    34903029  HDC hdc;
    34913030  HFONT hOldFont = 0;
    34923031  TEXTMETRICA textMetric;
    3493   WCHAR* textW;
    34943032  CHAR* textA = NULL;
    3495   BOOL mustFree = FALSE;
    34963033  NMTVDISPINFOW tvdi;
    34973034
    3498   if (!editItem)
    3499     return FALSE;
     3035  if (!TREEVIEW_ValidItem(infoPtr, editItem))
     3036    return (HWND)NULL;
    35003037
    35013038  if(infoPtr->hwndEdit)
    35023039    return infoPtr->hwndEdit;
    35033040
     3041  infoPtr->bLabelChanged = FALSE;
     3042
    35043043  /* Make shure that edit item is selected */
    35053044
    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);
    35143050  /* Select the font to get appropriate metric dimensions */
    35153051  if(infoPtr->hFont != 0)
     
    35193055
    35203056  /*Get String Lenght in pixels */
    3521   GetTextExtentPoint32W(hdc,textW,lstrlenW(textW),&sz);
     3057  GetTextExtentPoint32W(hdc,editItem->pszText,lstrlenW(editItem->pszText),&sz);
    35223058
    35233059  /*Add Extra spacing for the next character */
     
    35253061  sz.cx += (textMetric.tmMaxCharWidth * 2);
    35263062
     3063  sz.cx = MAX(sz.cx, textMetric.tmMaxCharWidth * 3);
     3064  sz.cx = MIN(sz.cx, infoPtr->clientWidth - editItem->textOffset + 2);
     3065
    35273066  if(infoPtr->hFont != 0)
    35283067  {
     
    35303069  }
    35313070
    3532   ReleaseDC(hwnd, hdc);
     3071  ReleaseDC(infoPtr->hwnd, hdc);
    35333072  infoPtr->hwndEdit = CreateWindowExA (
    35343073                         WS_EX_LEFT,
     
    35373076                         WS_CHILD | WS_BORDER | ES_AUTOHSCROLL | WS_CLIPSIBLINGS |
    35383077                         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,
    35423081                         0,hinst,0); /* FIXME: (HMENU)IDTVEDIT,pcs->hInstance,0);*/
    35433082
    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);
    35493090
    35503091  tvdi.item.mask        = TVIF_HANDLE | TVIF_TEXT | TVIF_STATE | TVIF_PARAM;
    3551   tvdi.item.hItem       = editItem->hItem;
     3092  tvdi.item.hItem       = editItem;
    35523093  tvdi.item.state       = editItem->state;
    35533094  tvdi.item.lParam      = editItem->lParam;
    35543095  if (isUnicodeNotify(&infoPtr->header))
    35553096  {
    3556     tvdi.item.pszText     = textW;
     3097    tvdi.item.pszText     = editItem->pszText;
    35573098  } else
    35583099  {
    3559     textA = HEAP_strdupWtoA(GetProcessHeap(),0,textW);
     3100    textA = HEAP_strdupWtoA(GetProcessHeap(),0,editItem->pszText);
    35603101    tvdi.item.pszText = (LPWSTR)textA;
    35613102  }
    35623103
    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))
    35643105  {
    35653106     DestroyWindow(infoPtr->hwndEdit);
    35663107     infoPtr->hwndEdit = 0;
    3567      if (mustFree) COMCTL32_Free(textW);
    3568      if (textA) COMCTL32_Free(textA);
     3108     if (textA) HeapFree(GetProcessHeap(),0,textA);
    35693109
    35703110     return (HWND)0;
     
    35723112  if (textA) HeapFree(GetProcessHeap(),0,textA);
    35733113
    3574   infoPtr->editItem = hItem;
    3575   SetWindowTextW(infoPtr->hwndEdit,textW);
     3114  infoPtr->selectedItem = hItem;
     3115  SetWindowTextW(infoPtr->hwndEdit,editItem->pszText);
    35763116  SetFocus(infoPtr->hwndEdit);
    35773117  SendMessageA(infoPtr->hwndEdit, EM_SETSEL, 0, -1);
    35783118  ShowWindow(infoPtr->hwndEdit, SW_SHOW);
    3579   if (mustFree) COMCTL32_Free(textW);
    35803119
    35813120  return infoPtr->hwndEdit;
     
    35833122
    35843123
    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);
     3124static LRESULT
     3125TREEVIEW_EndEditLabelNow(TREEVIEW_INFO *infoPtr,BOOL bCancel)
     3126{
     3127  TREEVIEW_ITEM *editedItem = infoPtr->selectedItem;
    35903128  NMTVDISPINFOW tvdi;
    3591   DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
     3129  DWORD dwStyle = GetWindowLongA(infoPtr->hwnd,GWL_STYLE);
    35923130  BOOL bCommit;
    35933131  WCHAR *textW = NULL;
     
    35993137
    36003138  tvdi.item.mask        = 0;
    3601   tvdi.item.hItem       = editedItem->hItem;
     3139  tvdi.item.hItem       = editedItem;
    36023140  tvdi.item.state       = editedItem->state;
    36033141  tvdi.item.lParam      = editedItem->lParam;
     
    36123150      INT len = iLength+1;
    36133151
    3614       textA = (CHAR*)COMCTL32_Alloc(len*sizeof(CHAR));
     3152      textA = (CHAR*)COMCTL32_Alloc(1024*sizeof(CHAR));
    36153153      lstrcpynWtoA(textA,textW,len);
    36163154      tvdi.item.pszText = (WCHAR*)textA;
     
    36233161  }
    36243162
    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);
    36263164
    36273165  if (!bCancel && bCommit) /* Apply the changes */
    36283166  {
    3629     WCHAR* text;
    36303167    BOOL mustFree = FALSE;
    36313168
     
    36333170      lstrcpynAtoW(textW,textA,iLength+1);
    36343171
    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)
    36433175      {
    36443176        NMTVDISPINFOW tvdi;
     
    36463178
    36473179        tvdi.item.mask        = TVIF_TEXT;
    3648         tvdi.item.hItem       = editedItem->hItem;
     3180        tvdi.item.hItem       = editedItem;
    36493181        tvdi.item.state       = editedItem->state;
    36503182        tvdi.item.lParam      = editedItem->lParam;
     
    36593191        }
    36603192
    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);
    36623194      } else
    36633195      {
    3664         if (!COMCTL32_ReAlloc(text,(iLength+1)*sizeof(WCHAR)))
     3196        if (!COMCTL32_ReAlloc(editedItem->pszText,(iLength+1)*sizeof(WCHAR)))
    36653197        {
    36663198          //ERR("OutOfMemory, cannot allocate space for label");
     
    36693201          if (textA) COMCTL32_Free(textA);
    36703202          if (textW) COMCTL32_Free(textW);
    3671           if (mustFree) COMCTL32_Free(text);
    36723203
    36733204          return FALSE;
     
    36793210      }
    36803211    }
    3681     if (mustFree) COMCTL32_Free(text);
    36823212  }
    36833213
     
    36853215  DestroyWindow(infoPtr->hwndEdit);
    36863216  infoPtr->hwndEdit = 0;
    3687   infoPtr->editItem = 0;
    36883217  if (textA) COMCTL32_Free(textA);
    36893218  if (textW) COMCTL32_Free(textW);
    36903219
    36913220  editedItem->calculated = FALSE;
    3692   TREEVIEW_CalcItem(hwnd,0,dwStyle,infoPtr,editedItem);
    3693   TREEVIEW_RefreshItem(hwnd,editedItem,TRUE);
     3221  TREEVIEW_RefreshItem(infoPtr,editedItem,0);
    36943222
    36953223  return TRUE;
    36963224}
    36973225
     3226static LRESULT
     3227TREEVIEW_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 **************************************************/
    36983253
    36993254/***************************************************************************
     
    37013256 * Windows.
    37023257 */
    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
     3258static LRESULT
     3259TREEVIEW_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)
    37283278            {
    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                }
    37313288            }
    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
     3308static LRESULT
     3309TREEVIEW_LButtonDoubleClick(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     3310{
    37563311  TREEVIEW_ITEM *wineItem;
    3757   TV_HITTESTINFO hitinfo;
    3758 
    3759   hitinfo.pt.x = (INT)LOWORD(lParam);
    3760   hitinfo.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);
    37623317
    37633318  if (infoPtr->Timer & TV_EDIT_TIMER_SET)
    37643319  {
    37653320     /* 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;
    37723327
    37733328  //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 }
    37763363
    37773364 return TRUE;
    37783365}
    37793366
    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);
     3367static LRESULT
     3368TREEVIEW_LButtonDown(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     3369{
    39693370  TVHITTESTINFO ht;
    39703371  BOOL bTrack;
    3971   DWORD dwStyle = GetWindowLongA (hwnd, GWL_STYLE);
    39723372
    39733373  /* If Edit control is active - kill it and return.
     
    39783378  if (infoPtr->hwndEdit)
    39793379  {
    3980      SetFocus (hwnd);
     3380     SetFocus(infoPtr->hwnd);
    39813381     return 0;
    39823382  }
     
    39853385  ht.pt.y = (INT)HIWORD(lParam);
    39863386
    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);
    39903390
    39913391  /* Send NM_CLICK right away */
    39923392  if (!bTrack)
    3993      if (sendNotify(hwnd,NM_CLICK))
     3393     if (sendNotify(infoPtr->hwnd,NM_CLICK))
    39943394        goto setfocus;
    39953395
    39963396  if (ht.flags & TVHT_ONITEMBUTTON)
    39973397  {
    3998     TREEVIEW_Expand (hwnd, (WPARAM) TVE_TOGGLE, (LPARAM) ht.hItem);
     3398    TREEVIEW_Toggle(infoPtr,ht.hItem,TRUE);
    39993399    goto setfocus;
    40003400  } else if (bTrack)
    40013401  {
    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);
    40053405      infoPtr->dropItem = ht.hItem;
    40063406      return 0;
     
    40083408  }
    40093409
    4010   if (sendNotify(hwnd,NM_CLICK))
     3410  if (sendNotify(infoPtr->hwnd,NM_CLICK))
    40113411     goto setfocus;
    40123412
     
    40153415   * and the click occured on the item label...
    40163416   */
    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))
    40183418  {
    40193419    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;
    40253424  } else if (ht.flags & (TVHT_ONITEMLABEL | TVHT_ONITEMICON))
    40263425  {
    4027     TREEVIEW_DoSelectItem(hwnd,TVGN_CARET,ht.hItem,TVC_BYMOUSE);
     3426    TREEVIEW_DoSelectItem(infoPtr,TVGN_CARET,ht.hItem,TVC_BYMOUSE);
    40283427  } else if (ht.flags & TVHT_ONITEMSTATEICON)
    40293428  {
    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);
    40453434    }
    40463435  }
    40473436
    40483437setfocus:
    4049   SetFocus (hwnd);
     3438  SetFocus(infoPtr->hwnd);
    40503439
    40513440  return 0;
    40523441}
    40533442
    4054 
    4055 static LRESULT
    4056 TREEVIEW_RButtonDown (HWND hwnd, WPARAM wParam, LPARAM lParam)
    4057 {
    4058  TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
     3443static LRESULT
     3444TREEVIEW_RButtonDown(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     3445{
    40593446   TVHITTESTINFO ht;
    40603447
    40613448   if (infoPtr->hwndEdit)
    40623449   {
    4063       SetFocus(hwnd);
     3450      SetFocus(infoPtr->hwnd);
    40643451      return 0;
    40653452   }
     
    40683455   ht.pt.y = (INT)HIWORD(lParam);
    40693456
    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))
    40733460   {
    40743461      if (ht.hItem)
    40753462      {
    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);
    40773464         infoPtr->dropItem = ht.hItem;
    40783465      }
     
    40803467   else
    40813468   {
    4082       SetFocus(hwnd);
    4083       sendNotify(hwnd,NM_RCLICK);
     3469      SetFocus(infoPtr->hwnd);
     3470      sendNotify(infoPtr->hwnd,NM_RCLICK);
    40843471   }
    40853472
     
    40873474}
    40883475
    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;
     3476static LRESULT
     3477TREEVIEW_RButtonUp(TREEVIEW_INFO *infoPtr, LPPOINT pPt)
     3478{
     3479    POINT pt = *pPt;
    41033480
    41043481    /* Change to screen coordinate for WM_CONTEXTMENU */
    4105     ClientToScreen(hwnd, &pt);
     3482    ClientToScreen(infoPtr->hwnd, &pt);
    41063483
    41073484    /* 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));
    41093486    return 0;
    41103487}
    41113488
    4112 static LRESULT TREEVIEW_CreateDragImage (HWND hwnd, WPARAM wParam, LPARAM lParam)
    4113 {
    4114   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
     3489static LRESULT TREEVIEW_CreateDragImage (TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     3490{
    41153491  TREEVIEW_ITEM *dragItem;
    41163492  INT cx,cy;
     
    41213497  RECT  rc;
    41223498  HFONT hOldFont;
    4123   WCHAR *itemtxt;
    4124   BOOL mustFree = FALSE;
    41253499
    41263500  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);
    41353505
    41363506  hwtop = GetDesktopWindow();
     
    41393509
    41403510  hOldFont = SelectObject (hdc, infoPtr->hFont);
    4141   GetTextExtentPoint32W (hdc, itemtxt, lstrlenW (itemtxt), &size);
     3511  GetTextExtentPoint32W (hdc, dragItem->pszText, lstrlenW (dragItem->pszText), &size);
    41423512
    41433513  hbmp = CreateCompatibleBitmap (htopdc, size.cx, size.cy);
     
    41593529
    41603530  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);
    41623532  SelectObject (hdc, hOldFont);
    41633533  SelectObject (hdc, hOldbmp);
     
    41683538  DeleteObject (hbmp);
    41693539  ReleaseDC (hwtop, htopdc);
    4170   if (mustFree) COMCTL32_Free(itemtxt);
    41713540
    41723541  return (LRESULT)infoPtr->dragList;
    41733542}
    41743543
    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
     3546static LRESULT
     3547TREEVIEW_DoSelectItem(TREEVIEW_INFO *infoPtr, INT action, HTREEITEM newSelect,
     3548                      INT cause)
     3549{
     3550  TREEVIEW_ITEM *prevSelect;
    41833551  BOOL refreshPrev = FALSE,refreshNew = FALSE;
    41843552
    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;
    41903562
    41913563    /*
     
    41953567    while (parent && !(parent->state & TVIS_EXPANDED))
    41963568    {
    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
    42013574
    42023575  switch (action)
    42033576  {
    42043577    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      }
    42113596
    42123597      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)
    42173598      {
    4218         refreshPrev = prevItem->state & TVIS_SELECTED;
    4219         prevItem->state &= ~TVIS_SELECTED;
     3599        refreshNew = !(newSelect->state & TVIS_SELECTED);
     3600        newSelect->state |= TVIS_SELECTED;
    42203601      }
    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))
    42303606      {
    42313607        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);
    42383614      }
    42393615
    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)
    42423619      {
    42433620        TREEVIEW_ITEM *item;
    42443621
    42453622        //deselect last selected row
    4246         if (prevItem)
     3623        if (prevSelect)
    42473624        {
    4248           if (refreshPrev) TREEVIEW_RefreshItem(hwnd,prevItem,FALSE);
    4249           if (prevItem->upsibling)
     3625          if (refreshPrev) TREEVIEW_RefreshItem(infoPtr,prevSelect,TVIF_IMAGE | TVIF_TEXT);
     3626          if (prevSelect->prevSibling)
    42503627          {
    4251             item = &infoPtr->items[(INT)prevItem->upsibling];
     3628            item = prevSelect->prevSibling;
    42523629            while (item)
    42533630            {
     
    42553632              {
    42563633                item->state &= ~TVIS_SELECTED;
    4257                 TREEVIEW_RefreshItem(hwnd,item,FALSE);
     3634                TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT);
    42583635              }
    4259               item = &infoPtr->items[(INT)item->upsibling];
     3636              item = item->prevSibling;
    42603637            }
    42613638          }
    4262           if (prevItem->sibling)
     3639          if (prevSelect->nextSibling)
    42633640          {
    4264             item = &infoPtr->items[(INT)prevItem->sibling];
     3641            item = prevSelect->nextSibling;
    42653642            while (item)
    42663643            {
     
    42683645              {
    42693646                item->state &= ~TVIS_SELECTED;
    4270                 TREEVIEW_RefreshItem(hwnd,item,FALSE);
     3647                TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT);
    42713648              }
    4272               item = &infoPtr->items[(INT)item->sibling];
     3649              item = item->nextSibling;
    42733650            }
    42743651          }
     
    42763653
    42773654        //select new row
    4278         if (wineItem)
     3655        if (newSelect)
    42793656        {
    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)
    42823659          {
    4283             item = &infoPtr->items[(INT)wineItem->upsibling];
     3660            item = newSelect->prevSibling;
    42843661            while (item)
    42853662            {
     
    42873664              {
    42883665                item->state |= TVIS_SELECTED;
    4289                 TREEVIEW_RefreshItem(hwnd,item,FALSE);
     3666                TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT);
    42903667              }
    4291               item = &infoPtr->items[(INT)item->upsibling];
     3668              item = item->prevSibling;
    42923669            }
    42933670          }
    4294           if (wineItem->sibling)
     3671          if (newSelect->nextSibling)
    42953672          {
    4296             item =  &infoPtr->items[(INT)wineItem->sibling];
     3673            item =  newSelect->nextSibling;
    42973674            while (item)
    42983675            {
     
    43003677              {
    43013678                item->state |= TVIS_SELECTED;
    4302                 TREEVIEW_RefreshItem(hwnd,item,FALSE);
     3679                TREEVIEW_RefreshItem(infoPtr,item,TVIF_IMAGE | TVIF_TEXT);
    43033680              }
    4304               item = &infoPtr->items[(INT)item->sibling];
     3681              item = item->nextSibling;
    43053682            }
    43063683          }
     
    43083685      } else
    43093686      {
    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);
    43123689      }
    43133690
    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);
    43163697      break;
    43173698
    43183699    case TVGN_DROPHILITE:
    4319       prevItem = TREEVIEW_ValidItem (infoPtr, infoPtr->dropItem);
    4320 
    4321       if (prevItem)
     3700      prevSelect = infoPtr->dropItem;
     3701
     3702      if (prevSelect)
    43223703      {
    4323         refreshPrev = prevItem->state & TVIS_DROPHILITED;
    4324         prevItem->state &= ~TVIS_DROPHILITED;
     3704        refreshPrev = prevSelect->state & TVIS_DROPHILITED;
     3705        prevSelect->state &= ~TVIS_DROPHILITED;
    43253706      }
    43263707
    4327       infoPtr->dropItem = (HTREEITEM)newSelect;
    4328 
    4329       if (wineItem)
     3708      infoPtr->dropItem = newSelect;
     3709
     3710      if (newSelect)
    43303711      {
    4331         refreshNew = !(wineItem->state & TVIS_DROPHILITED);
    4332         wineItem->state |=TVIS_DROPHILITED;
     3712        refreshNew = !(newSelect->state & TVIS_DROPHILITED);
     3713        newSelect->state |= TVIS_DROPHILITED;
    43333714      }
    43343715
    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);
    43383719
    43393720      break;
     
    43463727      if (!infoPtr->firstVisible) return FALSE;
    43473728
    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;
    43523733      else
    43533734      {
    4354         scrollY = MIN(wineItem->rect.top,(infoPtr->uTotalHeight-infoPtr->uVisibleHeight)-infoPtr->lefttop.y);
    4355         scrollY -= scrollY % infoPtr->uVScrollStep;
     3735        scrollY = MIN(newSelect->rect.top,(infoPtr->treeHeight-infoPtr->clientHeight)-infoPtr->lefttop.y);
     3736        scrollY -= scrollY % infoPtr->uItemHeight;
    43563737      }
    43573738
     
    43593740      {
    43603741        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));
    43653746      }
    43663747
    43673748      break;
    43683749    }
    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 */
     3757static LRESULT
     3758TREEVIEW_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
     3775static 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
     3821static LRESULT
     3822TREEVIEW_VScroll(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     3823{
    44243824  INT newY,mod;
    4425   INT maxY = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
     3825  INT maxY = infoPtr->treeHeight-infoPtr->clientHeight;
    44263826
    44273827  if (!(infoPtr->uInternalStatus & TV_VSCROLL)) return FALSE;
    44283828
    4429   mod = maxY % infoPtr->uVScrollStep;
    4430   if (mod > 0) maxY += infoPtr->uVScrollStep-mod;
     3829  mod = maxY % infoPtr->uItemHeight;
     3830  if (mod > 0) maxY += infoPtr->uItemHeight-mod;
    44313831
    44323832  switch (LOWORD (wParam))
    44333833  {
    44343834    case SB_LINEUP:
    4435       newY = infoPtr->lefttop.y-infoPtr->uVScrollStep;
     3835      newY = infoPtr->lefttop.y-infoPtr->uItemHeight;
    44363836      if (newY < 0) newY = 0;
    44373837      break;
    44383838
    44393839    case SB_LINEDOWN:
    4440       newY = infoPtr->lefttop.y+infoPtr->uVScrollStep;
     3840      newY = infoPtr->lefttop.y+infoPtr->uItemHeight;
    44413841      if (newY > maxY) newY = maxY;
    44423842      break;
    44433843
    44443844    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);
    44463846      if (newY < 0) newY = 0;
    44473847      break;
    44483848
    44493849    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);
    44513851      if (newY > maxY) newY = maxY;
    44523852      break;
     
    44543854    case SB_THUMBTRACK:
    44553855      newY = HIWORD(wParam);
    4456       mod = newY % infoPtr->uVScrollStep;
     3856      mod = newY % infoPtr->uItemHeight;
    44573857      if (mod > 0) newY -= mod;
    44583858      break;
     
    44653865  {
    44663866    INT scrollY = infoPtr->lefttop.y-newY;
    4467 
    4468     TREEVIEW_HideInfoTip(hwnd,infoPtr);
     3867    SCROLLINFO info;
     3868
     3869    TREEVIEW_HideInfoTip(infoPtr);
    44693870    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));
    44733880
    44743881    return TRUE;
     
    44793886
    44803887static LRESULT
    4481 TREEVIEW_HScroll (HWND hwnd, WPARAM wParam, LPARAM lParam)
    4482 {
    4483   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
     3888TREEVIEW_HScroll(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     3889{
    44843890  int maxWidth;
    44853891  int lastPos = infoPtr->lefttop.x;
     3892  SCROLLINFO info;
    44863893
    44873894  if (!(infoPtr->uInternalStatus & TV_HSCROLL)) return FALSE;
     
    44913898    case SB_LINEUP:
    44923899      if (!infoPtr->lefttop.x) return FALSE;
    4493       infoPtr->lefttop.x -= infoPtr->uRealItemHeight;
     3900      infoPtr->lefttop.x -= infoPtr->uItemHeight;
    44943901      if (infoPtr->lefttop.x < 0) infoPtr->lefttop.x = 0;
    44953902      break;
    44963903
    44973904    case SB_LINEDOWN:
    4498       maxWidth = infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
     3905      maxWidth = infoPtr->treeWidth-infoPtr->clientWidth;
    44993906      if (maxWidth <= 0) return FALSE;
    45003907      if (infoPtr->lefttop.x == maxWidth) return FALSE;
    4501       infoPtr->lefttop.x += infoPtr->uRealItemHeight; /*FIXME */
     3908      infoPtr->lefttop.x += infoPtr->uItemHeight; /*FIXME */
    45023909      if (infoPtr->lefttop.x > maxWidth)
    45033910        infoPtr->lefttop.x = maxWidth;
     
    45063913    case SB_PAGEUP:
    45073914      if (!infoPtr->lefttop.x) return FALSE;
    4508       infoPtr->lefttop.x -= infoPtr->uVisibleWidth;
     3915      infoPtr->lefttop.x -= infoPtr->clientWidth;
    45093916      if (infoPtr->lefttop.x < 0) infoPtr->lefttop.x = 0;
    45103917      break;
    45113918
    45123919    case SB_PAGEDOWN:
    4513       maxWidth = infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
     3920      maxWidth = infoPtr->treeWidth-infoPtr->clientWidth;
    45143921      if (maxWidth <= 0) return FALSE;
    45153922      if (infoPtr->lefttop.x == maxWidth) return FALSE;
    4516       infoPtr->lefttop.x += infoPtr->uVisibleWidth;
     3923      infoPtr->lefttop.x += infoPtr->clientWidth;
    45173924      if (infoPtr->lefttop.x > maxWidth)
    45183925        infoPtr->lefttop.x = maxWidth;
     
    45203927
    45213928    case SB_THUMBTRACK:
    4522       maxWidth = infoPtr->uTotalWidth-infoPtr->uVisibleWidth;
     3929      maxWidth = infoPtr->treeWidth-infoPtr->clientWidth;
    45233930      if (maxWidth <= 0) return FALSE;
    45243931      infoPtr->lefttop.x = HIWORD(wParam);
     
    45333940  if (lastPos != infoPtr->lefttop.x)
    45343941  {
    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));
    45393952
    45403953    return TRUE;
     
    45443957}
    45453958
    4546 static LRESULT TREEVIEW_MouseWheel (HWND hwnd, WPARAM wParam, LPARAM lParam)
    4547 {
    4548 
    4549     TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
    4550     short gcWheelDelta = 0;
     3959static LRESULT
     3960TREEVIEW_MouseWheel(TREEVIEW_INFO *infoPtr, WPARAM wParam, LPARAM lParam)
     3961{
     3962    short gcWheelDelta;
    45513963    UINT pulScrollLines = 3;
    45523964
    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);
    45603971    pulScrollLines *= (gcWheelDelta / WHEEL_DELTA);
    45613972
    45623973    if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
    45633974    {
    4564         int wheelDy = pulScrollLines * infoPtr->uRealItemHeight;
     3975        int wheelDy = pulScrollLines * infoPtr->uItemHeight;
    45653976        int newDy = infoPtr->lefttop.y + wheelDy;
    4566         int maxDy = infoPtr->uTotalHeight-infoPtr->uVisibleHeight;
     3977        int maxDy = infoPtr->treeHeight-infoPtr->clientHeight;
    45673978
    45683979        if (newDy > maxDy) newDy = maxDy;
     3980
    45693981        if (newDy < 0) newDy = 0;
    45703982
    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
     3990static LRESULT
     3991TREEVIEW_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
     4090static LRESULT
     4091TREEVIEW_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
     4113static LRESULT
     4114TREEVIEW_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 */
     4163static LRESULT
     4164TREEVIEW_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;
    46044186        break;
    46054187
    4606       case VK_DOWN:
    4607         scrollMsg = SB_LINERIGHT;
     4188    case VK_DOWN:
     4189        newSelection = TREEVIEW_GetNextListItem(infoPtr, prevItem);
    46084190        break;
    46094191
    4610       case VK_LEFT:
    4611         scrollMsg = SB_LINELEFT;
    4612         horz = TRUE;
     4192    case VK_HOME:
     4193        newSelection = infoPtr->root->firstChild;
    46134194        break;
    46144195
    4615       case VK_RIGHT:
    4616         scrollMsg = SB_LINERIGHT;
    4617         horz = TRUE;
     4196    case VK_END:
     4197        newSelection = TREEVIEW_GetLastListItem(infoPtr,
     4198                                                infoPtr->root->lastChild);
    46184199        break;
    46194200
    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        }
    46224210        break;
    46234211
    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
    46264223        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);
    46484253      break;
    46494254
    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
     4278static LRESULT
     4279TREEVIEW_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
     4292static LRESULT
     4293TREEVIEW_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
     4308static LRESULT
     4309TREEVIEW_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
     4324static LRESULT
     4325TREEVIEW_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
     4335static 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
     4343HTREEITEM 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
     4372VOID 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
     4427VOID 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
     4445static 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
     4458HTREEITEM 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
     4468static 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)
    46764482      {
    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))
    46794501      {
    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);
    46834504      }
    4684 
    4685       break;
    4686 
    4687     case VK_RIGHT:
    4688       if (TREEVIEW_HasChildren(hwnd, prevItem))
     4505      if (hItem)
    46894506      {
    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        }
    46974513      }
    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
     4521static 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
     4537static LRESULT
     4538TREEVIEW_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
     4545static 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
     4552static LRESULT
     4553TREEVIEW_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
     4565static LRESULT TREEVIEW_GetDlgCode(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
     4566{
     4567  return DLGC_WANTARROWS | DLGC_WANTCHARS;
     4568}
     4569
     4570
     4571static LRESULT TREEVIEW_Char(TREEVIEW_INFO *infoPtr,WPARAM wParam,LPARAM lParam)
    47604572{
    47614573  CHAR ch = (CHAR)wParam;
    47624574
    4763   TREEVIEW_ISearch(hwnd,ch);
     4575  TREEVIEW_ISearch(infoPtr,ch);
    47644576
    47654577  return 0;
    47664578}
    47674579
    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;
     4580static BOOL TREEVIEW_Compare(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,LPWSTR text,INT textlen,BOOL *matchLast)
     4581{
     4582  BOOL res;
    48384583  INT itemlen;
    48394584
    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);
    48464588  if (itemlen < textlen)
    48474589  {
     
    48494591  } else
    48504592  {
    4851     res = (lstrcmpniW(itemtext,text,textlen) == 0);
     4593    res = (lstrcmpniW(item->pszText,text,textlen) == 0);
    48524594  }
    48534595  if (!res && matchLast)
     
    48554597    textlen--;
    48564598    if ((textlen > 0) && (itemlen >= textlen))
    4857       *matchLast = (lstrcmpniW(itemtext,text,textlen) == 0);
     4599      *matchLast = (lstrcmpniW(item->pszText,text,textlen) == 0);
    48584600    else
    48594601      *matchLast = FALSE;
    48604602  }
    4861   if (mustFree) COMCTL32_Free(itemtext);
    48624603
    48634604  return res;
    48644605}
    48654606
    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;
     4607static TREEVIEW_ITEM* TREEVIEW_Search(TREEVIEW_INFO *infoPtr,TREEVIEW_ITEM *item,LPWSTR text,INT textlen,TREEVIEW_ITEM **nearest)
     4608{
     4609  TREEVIEW_ITEM *start;
    48694610  BOOL bMatchLast;
    48704611
    4871   item = start = &infoPtr->items[iItem];
     4612  start = item;
    48724613  if (nearest) *nearest = NULL;
    48734614
     
    48774618    if (nearest)
    48784619    {
    4879       if (TREEVIEW_Compare(hwnd,item,text,textlen,(!*nearest) ? &bMatchLast:NULL))
     4620      if (TREEVIEW_Compare(infoPtr,item,text,textlen,(!*nearest) ? &bMatchLast:NULL))
    48804621        return item;
    48814622      else if (!*nearest && bMatchLast)
     
    48834624    } else
    48844625    {
    4885       if (TREEVIEW_Compare(hwnd,item,text,textlen,NULL))
     4626      if (TREEVIEW_Compare(infoPtr,item,text,textlen,NULL))
    48864627        return item;
    48874628    }
    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;
    48934633
    48944634  //search first to start
     
    48974637    if (nearest)
    48984638    {
    4899       if (TREEVIEW_Compare(hwnd,item,text,textlen,(!*nearest) ? &bMatchLast:NULL))
     4639      if (TREEVIEW_Compare(infoPtr,item,text,textlen,(!*nearest) ? &bMatchLast:NULL))
    49004640        return item;
    49014641      else if (!*nearest && bMatchLast)
     
    49034643    } else
    49044644    {
    4905       if (TREEVIEW_Compare(hwnd,item,text,textlen,NULL))
     4645      if (TREEVIEW_Compare(infoPtr,item,text,textlen,NULL))
    49064646        return item;
    49074647    }
    4908     item = TREEVIEW_GetNextListItem(hwnd,infoPtr,item);
     4648    item = TREEVIEW_GetNextListItem(infoPtr,item);
    49094649  }
    49104650
     
    49144654//NOTE: sister function in listview control -> sync changes
    49154655
    4916 static VOID TREEVIEW_ISearch(HWND hwnd,CHAR ch)
    4917 {
    4918   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
     4656static VOID TREEVIEW_ISearch(TREEVIEW_INFO *infoPtr,CHAR ch)
     4657{
    49194658  LPWSTR newString;
    4920   INT len,iItem;
     4659  INT len;
    49214660  CHAR ch2[2];
    49224661  TREEVIEW_ITEM *item,*nearest = NULL;
     
    49564695  if (infoPtr->selectedItem)
    49574696  {
    4958     iItem = (INT)infoPtr->selectedItem;
    4959     item = &infoPtr->items[iItem];
     4697    item = infoPtr->selectedItem;
    49604698
    49614699    //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))
    49634701      goto ISearchDone;
    49644702
    49654703    //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;
    49704707
    49714708  //scan
    4972   item = TREEVIEW_Search(hwnd,infoPtr,iItem,newString,len,checkNearest ? &nearest:NULL);
     4709  item = TREEVIEW_Search(infoPtr,item,newString,len,checkNearest ? &nearest:NULL);
    49734710
    49744711  if (!item && nearest)
    49754712  {
    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);
    49784715    infoPtr->dwISearchTime = GetTickCount();
    49794716
     
    49894726    infoPtr->pszISearch = newString;
    49904727    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);
    49934730    infoPtr->dwISearchTime = GetTickCount();
    49944731  } else
     
    49994736}
    50004737
    5001 static LRESULT TREEVIEW_GetISearchString(HWND hwnd,LPWSTR lpsz,BOOL unicode)
    5002 {
    5003   TREEVIEW_INFO *infoPtr = TREEVIEW_GetInfoPtr(hwnd);
    5004 
     4738static LRESULT TREEVIEW_GetISearchString(TREEVIEW_INFO *infoPtr,LPWSTR lpsz,BOOL unicode)
     4739{
    50054740  if (infoPtr->uISearchLen == 0) return 0;
    50064741
     
    50134748}
    50144749
    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);
     4750static 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
     4757static 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);
    50204765}
    50214766
     
    50234768TREEVIEW_WindowProc (HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
    50244769{
    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;
    50304782
    50314783    switch (uMsg)
    50324784    {
    50334785        case TVM_INSERTITEMA:
    5034           return TREEVIEW_InsertItem(hwnd,wParam,lParam,FALSE);
     4786          return TREEVIEW_InsertItem(infoPtr,wParam,lParam,FALSE);
    50354787
    50364788        case TVM_INSERTITEMW:
    5037           return TREEVIEW_InsertItem(hwnd,wParam,lParam,TRUE);
     4789          return TREEVIEW_InsertItem(infoPtr,wParam,lParam,TRUE);
    50384790
    50394791        case TVM_DELETEITEM:
    5040           return TREEVIEW_DeleteItem (hwnd, wParam, lParam);
     4792          return TREEVIEW_DeleteItem(infoPtr,wParam,lParam);
    50414793
    50424794        case TVM_EXPAND:
    5043           return TREEVIEW_Expand (hwnd, wParam, lParam);
     4795          return TREEVIEW_ExpandMsg(infoPtr,wParam,lParam);
    50444796
    50454797        case TVM_GETITEMRECT:
    5046           return TREEVIEW_GetItemRect (hwnd, wParam, lParam);
     4798          return TREEVIEW_GetItemRect(infoPtr,wParam,lParam);
    50474799
    50484800        case TVM_GETCOUNT:
    5049           return TREEVIEW_GetCount (hwnd, wParam, lParam);
     4801          return TREEVIEW_GetCount(infoPtr,wParam,lParam);
    50504802
    50514803        case TVM_GETINDENT:
    5052           return TREEVIEW_GetIndent (hwnd);
     4804          return TREEVIEW_GetIndent(infoPtr);
    50534805
    50544806        case TVM_SETINDENT:
    5055           return TREEVIEW_SetIndent (hwnd, wParam);
     4807          return TREEVIEW_SetIndent(infoPtr,wParam);
    50564808
    50574809        case TVM_GETIMAGELIST:
    5058           return TREEVIEW_GetImageList (hwnd, wParam, lParam);
     4810          return TREEVIEW_GetImageList(infoPtr,wParam,lParam);
    50594811
    50604812        case TVM_SETIMAGELIST:
    5061           return TREEVIEW_SetImageList (hwnd, wParam, lParam);
     4813          return TREEVIEW_SetImageList (infoPtr, wParam, lParam);
    50624814
    50634815        case TVM_GETNEXTITEM:
    5064           return TREEVIEW_GetNextItem (hwnd, wParam, lParam);
     4816          return TREEVIEW_GetNextItem (infoPtr, wParam, lParam);
    50654817
    50664818        case TVM_SELECTITEM:
    5067           return TREEVIEW_SelectItem (hwnd, wParam, lParam);
     4819          return TREEVIEW_SelectItem (infoPtr, wParam, lParam);
    50684820
    50694821        case TVM_GETITEMA:
    5070           return TREEVIEW_GetItem(hwnd,wParam,lParam,FALSE);
     4822          return TREEVIEW_GetItem(infoPtr,wParam,lParam,FALSE);
    50714823
    50724824        case TVM_GETITEMW:
    5073           return TREEVIEW_GetItem(hwnd,wParam,lParam,TRUE);
     4825          return TREEVIEW_GetItem(infoPtr,wParam,lParam,TRUE);
    50744826
    50754827        case TVM_SETITEMA:
    5076           return TREEVIEW_SetItem(hwnd,wParam,lParam,FALSE);
     4828          return TREEVIEW_SetItem(infoPtr,wParam,lParam,FALSE);
    50774829
    50784830        case TVM_SETITEMW:
    5079           return TREEVIEW_SetItem(hwnd,wParam,lParam,TRUE);
     4831          return TREEVIEW_SetItem(infoPtr,wParam,lParam,TRUE);
    50804832
    50814833        case TVM_EDITLABELA:
    5082           return TREEVIEW_EditLabel(hwnd,(HTREEITEM)lParam,FALSE);
     4834          return TREEVIEW_EditLabel(infoPtr,(HTREEITEM)lParam,FALSE);
    50834835
    50844836        case TVM_EDITLABELW:
    5085           return TREEVIEW_EditLabel(hwnd,(HTREEITEM)lParam,TRUE);
     4837          return TREEVIEW_EditLabel(infoPtr,(HTREEITEM)lParam,TRUE);
    50864838
    50874839        case TVM_GETEDITCONTROL:
    5088           return TREEVIEW_GetEditControl (hwnd);
     4840          return TREEVIEW_GetEditControl (infoPtr);
    50894841
    50904842        case TVM_GETVISIBLECOUNT:
    5091           return TREEVIEW_GetVisibleCount (hwnd, wParam, lParam);
     4843          return TREEVIEW_GetVisibleCount (infoPtr);
    50924844
    50934845        case TVM_HITTEST:
    5094           return TREEVIEW_HitTest(hwnd,(LPTVHITTESTINFO)lParam,FALSE);
     4846          return TREEVIEW_HitTest(infoPtr,(LPTVHITTESTINFO)lParam,FALSE);
    50954847
    50964848        case TVM_CREATEDRAGIMAGE:
    5097           return TREEVIEW_CreateDragImage (hwnd, wParam, lParam);
     4849          return TREEVIEW_CreateDragImage (infoPtr, wParam, lParam);
    50984850
    50994851        case TVM_SORTCHILDREN:
    5100           return TREEVIEW_SortChildren(hwnd, wParam, lParam);
     4852          return TREEVIEW_SortChildren(infoPtr, wParam, lParam);
    51014853
    51024854        case TVM_ENSUREVISIBLE:
    5103           return TREEVIEW_EnsureVisible(hwnd,(HTREEITEM)lParam);
     4855          return TREEVIEW_EnsureVisible(infoPtr,(HTREEITEM)lParam);
    51044856
    51054857        case TVM_SORTCHILDRENCB:
    5106           return TREEVIEW_SortChildrenCB(hwnd, wParam, lParam);
     4858          return TREEVIEW_SortChildrenCB(infoPtr, wParam, lParam);
    51074859
    51084860        case TVM_ENDEDITLABELNOW:
    5109           return TREEVIEW_EndEditLabelNow (hwnd,(BOOL)wParam);
     4861          return TREEVIEW_EndEditLabelNow (infoPtr,(BOOL)wParam);
    51104862
    51114863        case TVM_GETISEARCHSTRINGA:
    5112           return TREEVIEW_GetISearchString(hwnd,(LPWSTR)lParam,FALSE);
     4864          return TREEVIEW_GetISearchString(infoPtr,(LPWSTR)lParam,FALSE);
    51134865
    51144866        case TVM_GETISEARCHSTRINGW:
    5115           return TREEVIEW_GetISearchString(hwnd,(LPWSTR)lParam,TRUE);
     4867          return TREEVIEW_GetISearchString(infoPtr,(LPWSTR)lParam,TRUE);
    51164868
    51174869        case TVM_GETTOOLTIPS:
    5118           return TREEVIEW_GetToolTips (hwnd);
     4870          return TREEVIEW_GetToolTips (infoPtr);
    51194871
    51204872        case TVM_SETTOOLTIPS:
    5121           return TREEVIEW_SetToolTips (hwnd, wParam);
     4873          return TREEVIEW_SetToolTips (infoPtr, wParam);
    51224874
    51234875        case TVM_SETINSERTMARK:
    5124           return TREEVIEW_SetInsertMark (hwnd,wParam, lParam);
     4876          return TREEVIEW_SetInsertMark (infoPtr,wParam, lParam);
    51254877
    51264878        case TVM_SETITEMHEIGHT:
    5127           return TREEVIEW_SetItemHeight (hwnd, wParam);
     4879          return TREEVIEW_SetItemHeight (infoPtr, wParam);
    51284880
    51294881        case TVM_GETITEMHEIGHT:
    5130           return TREEVIEW_GetItemHeight (hwnd);
     4882          return TREEVIEW_GetItemHeight (infoPtr);
    51314883
    51324884        case TVM_SETBKCOLOR:
    5133           return TREEVIEW_SetBkColor (hwnd, wParam, lParam);
     4885          return TREEVIEW_SetBkColor (infoPtr, wParam, lParam);
    51344886
    51354887        case TVM_SETTEXTCOLOR:
    5136           return TREEVIEW_SetTextColor (hwnd, wParam, lParam);
     4888          return TREEVIEW_SetTextColor (infoPtr, wParam, lParam);
    51374889
    51384890        case TVM_GETBKCOLOR:
    5139           return TREEVIEW_GetBkColor (hwnd);
     4891          return TREEVIEW_GetBkColor (infoPtr);
    51404892
    51414893        case TVM_GETTEXTCOLOR:
    5142           return TREEVIEW_GetTextColor (hwnd);
     4894          return TREEVIEW_GetTextColor (infoPtr);
    51434895
    51444896        case TVM_SETSCROLLTIME:
    5145           return TREEVIEW_SetScrollTime (hwnd, (UINT)wParam);
     4897          return TREEVIEW_SetScrollTime (infoPtr, (UINT)wParam);
    51464898
    51474899        case TVM_GETSCROLLTIME:
    5148           return TREEVIEW_GetScrollTime (hwnd);
     4900          return TREEVIEW_GetScrollTime (infoPtr);
    51494901
    51504902        case TVM_GETITEMSTATE:
    5151           return TREEVIEW_GetItemState (hwnd,wParam, lParam);
     4903          return TREEVIEW_GetItemState (infoPtr,wParam, lParam);
    51524904
    51534905        case TVM_GETLINECOLOR:
    5154           return TREEVIEW_GetLineColor (hwnd,wParam, lParam);
     4906          return TREEVIEW_GetLineColor (infoPtr,wParam, lParam);
    51554907
    51564908        case TVM_SETLINECOLOR:
    5157           return TREEVIEW_SetLineColor (hwnd,wParam, lParam);
     4909          return TREEVIEW_SetLineColor (infoPtr,wParam, lParam);
    51584910
    51594911        case TVM_SETINSERTMARKCOLOR:
    5160           return TREEVIEW_SetInsertMarkColor (hwnd,wParam, lParam);
     4912          return TREEVIEW_SetInsertMarkColor (infoPtr,wParam, lParam);
    51614913
    51624914        case TVM_GETINSERTMARKCOLOR:
    5163           return TREEVIEW_GetInsertMarkColor (hwnd,wParam, lParam);
     4915          return TREEVIEW_GetInsertMarkColor (infoPtr,wParam, lParam);
    51644916
    51654917        case WM_COMMAND:
    5166           return TREEVIEW_Command (hwnd, wParam, lParam);
     4918          return TREEVIEW_Command (infoPtr, wParam, lParam);
    51674919
    51684920        case WM_DESTROY:
    5169           return TREEVIEW_Destroy (hwnd);
     4921          return TREEVIEW_Destroy (infoPtr);
    51704922
    51714923        case WM_ENABLE:
    5172           return TREEVIEW_Enable(hwnd,wParam,lParam);
     4924          return TREEVIEW_Enable(infoPtr,wParam,lParam);
    51734925
    51744926        case WM_ERASEBKGND:
    5175           return TREEVIEW_EraseBackground (hwnd, wParam, lParam);
     4927          return TREEVIEW_EraseBackground (infoPtr, wParam, lParam);
    51764928
    51774929        case WM_GETDLGCODE:
    5178           return TREEVIEW_GetDlgCode(hwnd,wParam,lParam);
     4930          return TREEVIEW_GetDlgCode(infoPtr,wParam,lParam);
    51794931
    51804932        case WM_PAINT:
    5181           return TREEVIEW_Paint (hwnd, wParam, lParam);
     4933          return TREEVIEW_Paint (infoPtr, wParam, lParam);
    51824934
    51834935        case WM_GETFONT:
    5184           return TREEVIEW_GetFont (hwnd, wParam, lParam);
     4936          return TREEVIEW_GetFont (infoPtr, wParam, lParam);
    51854937
    51864938        case WM_SETFONT:
    5187           return TREEVIEW_SetFont (hwnd, wParam, lParam);
     4939          return TREEVIEW_SetFont (infoPtr, wParam, lParam);
    51884940
    51894941        case WM_KEYDOWN:
    5190           return TREEVIEW_KeyDown (hwnd, wParam, lParam);
     4942          return TREEVIEW_KeyDown (infoPtr, wParam, lParam);
    51914943
    51924944        case WM_CHAR:
    5193           return TREEVIEW_Char(hwnd,wParam,lParam);
     4945          return TREEVIEW_Char(infoPtr,wParam,lParam);
    51944946
    51954947        case WM_SETFOCUS:
    5196           return TREEVIEW_SetFocus (hwnd, wParam, lParam);
     4948          return TREEVIEW_SetFocus (infoPtr, wParam, lParam);
    51974949
    51984950        case WM_KILLFOCUS:
    5199           return TREEVIEW_KillFocus (hwnd, wParam, lParam);
     4951          return TREEVIEW_KillFocus (infoPtr, wParam, lParam);
    52004952
    52014953        case WM_MOUSEMOVE:
    5202           return TREEVIEW_MouseMove(hwnd,wParam,lParam);
     4954          return TREEVIEW_MouseMove(infoPtr,wParam,lParam);
    52034955
    52044956        case WM_LBUTTONDOWN:
    5205           return TREEVIEW_LButtonDown (hwnd, wParam, lParam);
     4957          return TREEVIEW_LButtonDown (infoPtr, wParam, lParam);
    52064958
    52074959        case WM_LBUTTONDBLCLK:
    5208           return TREEVIEW_LButtonDoubleClick (hwnd, wParam, lParam);
     4960          return TREEVIEW_LButtonDoubleClick (infoPtr, wParam, lParam);
    52094961
    52104962        case WM_RBUTTONDOWN:
    5211           return TREEVIEW_RButtonDown (hwnd, wParam, lParam);
     4963          return TREEVIEW_RButtonDown (infoPtr, wParam, lParam);
    52124964
    52134965        case WM_RBUTTONDBLCLK:
    5214           return TREEVIEW_RButtonDoubleClick(hwnd,wParam,lParam);
     4966          return TREEVIEW_RButtonDoubleClick(infoPtr,wParam,lParam);
    52154967
    52164968        case WM_STYLECHANGED:
    5217           return TREEVIEW_StyleChanged (hwnd, wParam, lParam);
     4969          return TREEVIEW_StyleChanged (infoPtr, wParam, lParam);
    52184970
    52194971        case WM_SYSCOLORCHANGE:
    5220           return TREEVIEW_SysColorChange(hwnd,wParam,lParam);
     4972          return TREEVIEW_SysColorChange(infoPtr,wParam,lParam);
    52214973
    52224974        case WM_SETCURSOR:
    5223           return TREEVIEW_SetCursor(hwnd,wParam,lParam);
     4975          return TREEVIEW_SetCursor(infoPtr,wParam,lParam);
    52244976
    52254977        case WM_SETREDRAW:
    5226           return TREEVIEW_SetRedraw(hwnd,wParam,lParam);
     4978          return TREEVIEW_SetRedraw(infoPtr,wParam,lParam);
    52274979
    52284980        case WM_TIMER:
    5229           return TREEVIEW_HandleTimer (hwnd, wParam, lParam);
     4981          return TREEVIEW_HandleTimer (infoPtr, wParam, lParam);
    52304982
    52314983        case WM_SIZE:
    5232           return TREEVIEW_Size (hwnd, wParam,lParam);
     4984          return TREEVIEW_Size (infoPtr, wParam,lParam);
    52334985
    52344986        case WM_HSCROLL:
    5235           return TREEVIEW_HScroll (hwnd, wParam, lParam);
     4987          return TREEVIEW_HScroll (infoPtr, wParam, lParam);
    52364988
    52374989        case WM_VSCROLL:
    5238           return TREEVIEW_VScroll (hwnd, wParam, lParam);
     4990          return TREEVIEW_VScroll (infoPtr, wParam, lParam);
    52394991
    52404992        case WM_MOUSEWHEEL:
    5241           return TREEVIEW_MouseWheel (hwnd, wParam, lParam);
     4993          return TREEVIEW_MouseWheel (infoPtr, wParam, lParam);
    52424994
    52434995        case WM_DRAWITEM:
     
    52464998
    52474999        default:
     5000def:
    52485001          return defComCtl32ProcA(hwnd,uMsg,wParam,lParam);
    52495002      }
     
    52515004}
    52525005
     5006/* Tree Verification ****************************************************/
     5007
     5008#ifndef NDEBUG
     5009static inline void
     5010TREEVIEW_VerifyChildren(TREEVIEW_INFO *infoPtr, TREEVIEW_ITEM *item);
     5011
     5012static 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
     5061static inline void
     5062TREEVIEW_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
     5080static inline void
     5081TREEVIEW_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
     5090static inline void
     5091TREEVIEW_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
     5109static void
     5110TREEVIEW_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 ***************************************************/
    52535120
    52545121VOID TREEVIEW_Register (VOID)
Note: See TracChangeset for help on using the changeset viewer.