private void ScrollItems(int itemCount, int topShownIndex, bool scrollDown)
 {
     int dx = (scrollDown ? 1 : -1) * itemCount * myItemHeight;
     SmoothScroll.Info ssi = new SmoothScroll.Info(Handle, 0, (scrollDown ? 1 : -1) * itemCount * myItemHeight);
     ssi.clipRect = ssi.srcRect = new Rectangle(new Point(0, (topShownIndex + 1) * myItemHeight), ClientSize);
     ssi.scrollWindowFlags = NativeMethods.ScrollWindowFlags.Erase | NativeMethods.ScrollWindowFlags.Invalidate;
     SmoothScroll.ScrollWindow(ref ssi);
     UpdateToolTip();
 }
        private void _WndProc(ref Message m)
        {
            int lParam;
            switch (m.Msg)
            {
                case NativeMethods.WM_ERASEBKGND:
                    // Avoid drawing in area already used by items.  We will fully erase the item area
                    // as part of the draw item message.
                    var visibleItemHeight = 0;
                    if (myTree != null)
                    {
                        visibleItemHeight = (myTree.VisibleItemCount - TopIndex) * myItemHeight;
                    }

                    // Avoid using ClientRectangle here, since this is a cached WinForms property
                    // which may not be up to date in some cases, such as during a control resize.
                    NativeMethods.RECT clientRect;
                    NativeMethods.GetClientRect(Handle, out clientRect);
                    var remainingHeight = clientRect.height - visibleItemHeight;
                    if (remainingHeight > 0)
                    {
                        using (var g = Graphics.FromHdc(m.WParam))
                        {
                            Brush backBrush = null;
                            EnsureBrush(ref backBrush, BackColor);
                            try
                            {
                                g.FillRectangle(backBrush, 0, visibleItemHeight, clientRect.width, remainingHeight);
                            }
                            finally
                            {
                                CleanBrush(ref backBrush, BackColor);
                            }
                        }
                    }

                    // Nonzero return value indicates we've done the erasing.
                    m.Result = (IntPtr)1;
                    break;
                case NativeMethods.WM_NCCALCSIZE:
                    base.WndProc(ref m);
                    if ((int)m.WParam != 0 && HeaderVisible)
                    {
                        Marshal.WriteInt32(
                            m.LParam, NativeMethods.NCCALCSIZE_PARAMS.rgrc0TopOffset,
                            HeaderHeight + Marshal.ReadInt32(m.LParam, NativeMethods.NCCALCSIZE_PARAMS.rgrc0TopOffset));
                        myBorderOffset = -1;
                    }
                    break;
                case NativeMethods.WM_LBUTTONUP:
                    {
                        var restoreSelChange = GetStateFlag(VTCStateFlags.SelChangeFromMouse);
                        if (restoreSelChange)
                        {
                            SetStateFlag(VTCStateFlags.SelChangeFromMouse, true);
                        }
                        base.WndProc(ref m);
                        if (restoreSelChange)
                        {
                            SetStateFlag(VTCStateFlags.SelChangeFromMouse, false);
                        }
                    }
                    break;
                case NativeMethods.WM_KILLFOCUS:
                case NativeMethods.WM_SETFOCUS:
                    // If we're setting focus to a fake focus control, then don't
                    // redraw now. In particular, doing this with the header control
                    // will mess up the splitter lines.
                    if (!GetStateFlag(VTCStateFlags.RedrawOff)
                        && myUpdateCount == 0
                        && (m.WParam == IntPtr.Zero || !(IsDrawWithFocusWindow(m.WParam) || IsInPlaceEditWindow(m.WParam))))
                    {
                        RedrawVisibleSelectedItems();
                    }

                    // notify accessibility clients of focus change to caret item
                    if (m.Msg == NativeMethods.WM_SETFOCUS
                        && CurrentIndex != VirtualTreeConstant.NullIndex)
                    {
                        if (VirtualTreeAccEvents.ShouldNotify(VirtualTreeAccEvents.eventObjectFocus, this))
                        {
                            VirtualTreeAccEvents.Notify(
                                VirtualTreeAccEvents.eventObjectFocus, CurrentIndex,
                                CurrentColumn, this);
                        }
                    }

                    // We don't call the base on a WM_SETFOCUS, since DefWndProc will send a focus WinEvents,
                    // which we don't want.  We still need to raise events, however.
                    if (m.Msg == NativeMethods.WM_SETFOCUS)
                    {
                        OnGotFocus(EventArgs.Empty);
                    }
                    else
                    {
                        OnLostFocus(EventArgs.Empty);
                    }
                    break;
                case NativeMethods.WM_REFLECT + NativeMethods.WM_CHARTOITEM:
                    m.Result = (IntPtr)(-1);
                    break;
                case NativeMethods.WM_REFLECT + NativeMethods.WM_DRAWITEM:
                    WmReflectDrawItem(ref m);
                    break;
                case NativeMethods.WM_LBUTTONDBLCLK:
                    SetStyle(ControlStyles.UserMouse, true);
                    SetStateFlag(VTCStateFlags.CallDefWndProc, true);
                    base.WndProc(ref m);
                    if (GetStateFlag(VTCStateFlags.CallDefWndProc))
                    {
                        DefWndProc(ref m);
                    }
                    SetStyle(ControlStyles.UserMouse, false);
                    break;
                case NativeMethods.WM_LBUTTONDOWN:
                    {
                        // Handling the mouse down is a very delicate operation that
                        // involves letting us, and winforms all having a shot
                        // at the operation. WinForms does some useful things and sets
                        // internal state indicating the the mouse is down (and gets
                        // the capture, etc), but we don't want them to call DefWndProc
                        // because that will automatically do things like change selection
                        // when we click on an expansion button, or drag select in multiselect
                        // mode when we're trying to do a drag drop. The UserMouse=true style
                        // used here stops the control from calling DefWndProc so we can decide
                        // ourselves if it needs to be called or not to do standard selection
                        // processing for the control. Note that base.WndProc call here sets
                        // the WinForms state and calls our OnMouseDown, where most of the 
                        // processing is done.
                        var startIndex = CurrentIndex;
                        var skipStandardProcessing = true;
                        var localCallDefWndProc = true;
                        SetStyle(ControlStyles.UserMouse, true);
                        SetStateFlag(VTCStateFlags.CallDefWndProc, true);
                        SetStateFlag(VTCStateFlags.SelChangeFromMouse, true);
                        SetStateFlag(VTCStateFlags.StandardLButtonDownProcessing, false);
                        // WinForms discards the modifer key information in the original message.  Capture that here for use in OnMouseDown.  
                        if (0 != ((int)m.WParam & NativeMethods.MK_CONTROL))
                        {
                            SetStateFlag(VTCStateFlags.MouseButtonDownCtrl, true);
                        }
                        if (0 != ((int)m.WParam & NativeMethods.MK_SHIFT))
                        {
                            SetStateFlag(VTCStateFlags.MouseButtonDownShift, true);
                        }
                        try
                        {
                            base.WndProc(ref m);
                            localCallDefWndProc = GetStateFlag(VTCStateFlags.CallDefWndProc);
                            if (localCallDefWndProc)
                            {
                                if (myMouseDownHitInfo.HitTarget != VirtualTreeHitTargets.NoWhere)
                                {
                                    skipStandardProcessing = false;
                                    if (RequireColumnSwitchForSelection(ref myMouseDownHitInfo))
                                    {
                                        var columnChangeOnly = startIndex == myMouseDownHitInfo.Row;
                                        SetSelectionColumn(myMouseDownHitInfo.DisplayColumn, false);
                                            // don't fire events here, we'll fire when we set selection.
                                        if (columnChangeOnly)
                                        {
                                            startIndex = -1;
                                        }
                                    }
                                }
                            }
                            else if (GetStateFlag(VTCStateFlags.StandardLButtonDownProcessing))
                            {
                                // The selection pieces have already been taken care of, to the drag-drop and
                                // label edit bits.
                                skipStandardProcessing = false;
                                startIndex = -1;
                            }
                            SetStyle(ControlStyles.UserMouse, false);
                            var checkForDrag = !skipStandardProcessing && IsDragSource;
                            var multiSelect = GetStyleFlag(VTCStyleFlags.MultiSelect);
                            var fContinue = true;
                            if (checkForDrag && multiSelect)
                            {
                                // MultiSelect drag needs to be initiated before the DoSelectionChangeFromMouse
                                // call, not after. In the single select case, the default processing
                                // will select an item. But in the multiselect case, it will deselect
                                // the item if it is already selected, so we need to check for
                                // starting the drag before doing the default processing.
                                if (IsSelected(myMouseDownHitInfo.Row))
                                {
                                    checkForDrag = false;
                                    var p = new Point((int)m.LParam);
                                    if (CheckForDragBegin(
                                        p.X, p.Y, myMouseDownHitInfo.Row, myMouseDownHitInfo.DisplayColumn, ref localCallDefWndProc))
                                    {
                                        // Code repeated below
                                        var dragData = PopulateDragData(
                                            myMouseDownHitInfo.Row, myMouseDownHitInfo.DisplayColumn, DragReason.DragDrop);
                                        if (!dragData.IsEmpty)
                                        {
                                            if (startIndex != -1
                                                && startIndex != myMouseDownHitInfo.Row)
                                            {
                                                DoSelectionChanged();
                                            }
                                            DoDragDrop(dragData.Data, dragData.AllowedEffects);
                                            fContinue = false;
                                        }
                                    }
                                }
                                else
                                {
                                    checkForDrag = localCallDefWndProc; // Nothing is going to change
                                }
                            }
                            if (fContinue && localCallDefWndProc)
                            {
                                DoSelectionChangeFromMouse(
                                    ref myMouseDownHitInfo, 0 != ((int)m.WParam & NativeMethods.MK_SHIFT),
                                    0 != ((int)m.WParam & NativeMethods.MK_CONTROL), MouseButtons.Left);
                                if (startIndex == -1)
                                {
                                    // startIndex == -1 indicates we already set column selection above, and the caret index isn't changing.
                                    // need to fire events here, since to DoSelectionChangeFromMouse, it will look like nothing changed.
                                    DoSelectionChanged();
                                }
                            }
                            if (checkForDrag
                                &&
                                ((myMouseDownHitInfo.HitTarget
                                  & (VirtualTreeHitTargets.OnItem | VirtualTreeHitTargets.OnItemRight | VirtualTreeHitTargets.OnItemLeft))
                                 != 0)
                                &&
                                (!multiSelect || IsSelected(myMouseDownHitInfo.Row)))
                            {
                                var p = new Point((int)m.LParam);
                                var dummyPending = false;
                                if (CheckForDragBegin(
                                    p.X, p.Y, myMouseDownHitInfo.Row, myMouseDownHitInfo.DisplayColumn, ref dummyPending))
                                {
                                    // Code copied from above
                                    var dragData = PopulateDragData(
                                        myMouseDownHitInfo.Row, myMouseDownHitInfo.DisplayColumn, DragReason.DragDrop);
                                    if (!dragData.IsEmpty)
                                    {
                                        if (startIndex != -1
                                            && startIndex != myMouseDownHitInfo.Row)
                                        {
                                            DoSelectionChanged();
                                        }
                                        DoDragDrop(dragData.Data, dragData.AllowedEffects);
                                        fContinue = false;
                                    }
                                }
                            }
                            if (!skipStandardProcessing
                                && fContinue
                                &&
                                (0
                                 != (myMouseDownHitInfo.HitTarget
                                     & (VirtualTreeHitTargets.OnItemLabel | VirtualTreeHitTargets.OnItemRight
                                        | VirtualTreeHitTargets.OnItemLeft))))
                            {
                                StartEditTimer(myMouseDownHitInfo.Row, m.Msg);
                            }
                        }
                        finally
                        {
                            SetStateFlag(VTCStateFlags.MouseButtonDownCtrl, false);
                            SetStateFlag(VTCStateFlags.MouseButtonDownShift, false);
                            SetStateFlag(VTCStateFlags.SelChangeFromMouse, false);
                        }
                        break;
                    }
                case NativeMethods.WM_RBUTTONDOWN:
                    // Focus doesn't happen automatically on a right
                    // mouse click. Set this up front before other
                    // mouse events start firing.
                    if (!Focused)
                    {
                        Focus();
                    }
                    // WinForms discards the modifer key information in the original message.  Capture that here for use in OnMouseDown.  
                    if (0 != ((int)m.WParam & NativeMethods.MK_CONTROL))
                    {
                        SetStateFlag(VTCStateFlags.MouseButtonDownCtrl, true);
                    }
                    if (0 != ((int)m.WParam & NativeMethods.MK_SHIFT))
                    {
                        SetStateFlag(VTCStateFlags.MouseButtonDownShift, true);
                    }
                    try
                    {
                        base.WndProc(ref m);
                    }
                    finally
                    {
                        SetStateFlag(VTCStateFlags.MouseButtonDownCtrl, false);
                        SetStateFlag(VTCStateFlags.MouseButtonDownShift, false);
                    }
                    break;
                case NativeMethods.WM_MOUSEMOVE:
                    if (myTooltip != null || StandardCheckBoxes)
                    {
                        // update tooltips and checkbox hot-track state. 
                        UpdateMouseTargets();
                        if (myTooltip != null)
                        {
                            myTooltip.Relay(m.WParam, m.LParam);
                        }
                    }
                    base.WndProc(ref m);
                    break;
                case NativeMethods.WM_NCMOUSEMOVE:
                    if (myTooltip != null || StandardCheckBoxes)
                    {
                        // update tooltips and checkbox hot-track state. 
                        UpdateMouseTargets();
                        if (myTooltip != null)
                        {
                            myTooltip.Relay(m.WParam, m.LParam);
                        }
                    }
                    base.WndProc(ref m);
                    break;
                case NativeMethods.WM_MOUSELEAVE:
                    if (myRawMouseOverIndex != -1)
                    {
                        // make sure to invalidate checkbox hot-track region if necessary when the mouse leaves the control.
                        UpdateMouseTargets();
                    }
                    base.WndProc(ref m);
                    break;
                case NativeMethods.WM_NOTIFY:
                    // NMHDR is layed out hwndFrom/idFrom/code
                    if (myTooltip != null
                        &&
                        myTooltip.IsHandleCreated
                        &&
                        Marshal.ReadIntPtr(m.LParam) == myTooltip.Handle)
                    {
                        var fContinue = false;

#if DEBUG
                        // - to not have to compile structs used only in Asserts
                        Debug.Assert(Marshal.OffsetOf(typeof(NativeMethods.NMHDR), "code").ToInt32() == 8);
                        Debug.Assert(Marshal.OffsetOf(typeof(NativeMethods.TOOLTIPTEXT), "lpszText").ToInt32() == 12);
#endif
                        var code = Marshal.ReadIntPtr(m.LParam, 8).ToInt32();
                        switch (code)
                        {
                            case NativeMethods.TTN_NEEDTEXTA:
                            case NativeMethods.TTN_NEEDTEXTW:
                                if (myMouseOverIndex == VirtualTreeConstant.NullIndex)
                                {
                                    if (!UpdateMouseTargets())
                                    {
                                        fContinue = true;
                                        break;
                                    }
                                }
                                // This gets the active selection column,
                                // need to support all columns.
                                Marshal.WriteIntPtr(
                                    m.LParam,
                                    12,
                                    myTooltip.GetTextPtr(myTree, myMouseOverIndex, myMouseOverColumn, myTipType));
                                break;
                            case NativeMethods.TTN_SHOW:
                                if (myMouseOverIndex != VirtualTreeConstant.NullIndex)
                                {
                                    SetStateFlag(VTCStateFlags.ShowingTooltip, true);
                                    myTooltip.PositionTipWindow(this);
                                    m.Result = (IntPtr)1;
                                }
                                break;
                            case NativeMethods.TTN_POP:
                                SetStateFlag(VTCStateFlags.ShowingTooltip, false);
                                fContinue = true;
                                break;
                            default:
                                fContinue = true;
                                break;
                        }
                        if (!fContinue)
                        {
                            break;
                        }
                    }
                    base.WndProc(ref m);
                    break;

                case NativeMethods.WM_WINDOWPOSCHANGING:
                    {
                        var flags = (NativeMethods.SetWindowPosFlags)Marshal.ReadInt32(m.LParam, NativeMethods.WINDOWPOS.flagsOffset);
                        if (((NativeMethods.SetWindowPosFlags.SWP_NOSIZE | NativeMethods.SetWindowPosFlags.SWP_NOMOVE)
                             != (flags & (NativeMethods.SetWindowPosFlags.SWP_NOSIZE | NativeMethods.SetWindowPosFlags.SWP_NOMOVE)))
                            || (0 != (flags & NativeMethods.SetWindowPosFlags.SWP_FRAMECHANGED)))
                        {
                            // The exclusions are a strange case, but Windows was not sending a
                            // WM_WINDOWPOSCHANGED if SetWindowPos was called with NOMOVE | NOSIZE,
                            // so this was not getting turned back on and DrawItem was blocked until
                            // the next size
                            SetStateFlag(VTCStateFlags.WindowPositionChanging, true);
                        }
                        base.WndProc(ref m);
                        break;
                    }
                case NativeMethods.WM_WINDOWPOSCHANGED:
                    {
                        var oldWidth = ClientSize.Width;
                        base.WndProc(ref m);
                        SetStateFlag(VTCStateFlags.WindowPositionChanging, false);
                        var flags = (NativeMethods.SetWindowPosFlags)Marshal.ReadInt32(m.LParam, NativeMethods.WINDOWPOS.flagsOffset);
                        var sizeChanged = 0 == (flags & NativeMethods.SetWindowPosFlags.SWP_NOSIZE)
                                          && (oldWidth != ClientSize.Width && Width > 0);
                        if (HeaderVisible && myHeaderContainer != null)
                        {
                            var visibleChanged = ((flags
                                                   & (NativeMethods.SetWindowPosFlags.SWP_HIDEWINDOW
                                                      | NativeMethods.SetWindowPosFlags.SWP_SHOWWINDOW)) != 0);
                            var frameChanged = 0 != (flags & NativeMethods.SetWindowPosFlags.SWP_FRAMECHANGED);
                            var positionChanged = 0 == (flags & NativeMethods.SetWindowPosFlags.SWP_NOMOVE);
                            var zorderChanged = 0 == (flags & NativeMethods.SetWindowPosFlags.SWP_NOZORDER);
                            if (visibleChanged)
                            {
                                myHeaderContainer.Visible = ((flags & NativeMethods.SetWindowPosFlags.SWP_SHOWWINDOW) != 0);
                            }
                            if (sizeChanged || frameChanged)
                            {
                                myHeaderContainer.UpdateHeaderControlPosition(true);
                            }
                            if (zorderChanged)
                            {
                                myHeaderContainer.UpdateHeaderControlZOrder();
                            }

                            if (positionChanged
                                || frameChanged
                                || sizeChanged)
                            {
                                RepositionHeaderContainer();
                            }
                        }
                        if (sizeChanged)
                        {
                            if (myMctree != null
                                && myUpdateCount == 0)
                            {
                                var columns = (myColumnPermutation != null) ? myColumnPermutation.VisibleColumnCount : myMctree.ColumnCount;
                                if (columns > 1)
                                {
                                    // Following are conditions where we need to refresh completely on a resize:
                                    // 1.  Variable column bounds.  These change when resize occurs.
                                    // 2.  Left scroll bar.  This may adjust column widths
                                    // 3.  No vertical gridlines.  This causes us to use ellipsis string trimming, which may require repaint if text was truncated.
                                    if ((myHeaderBounds.HasVariableBounds || LeftScrollBar || !HasVerticalGridLines)
                                        && 0 == (flags & NativeMethods.SetWindowPosFlags.SWP_NOREDRAW))
                                    {
                                        Refresh();
                                    }
                                }
                            }
                        }
                        break;
                    }
                case NativeMethods.WM_SIZE:
                    {
                        lParam = (int)m.LParam;
                        var curSize = new Size(NativeMethods.UnsignedLOWORD(lParam), NativeMethods.UnsignedHIWORD(lParam));
                        var cacheLastSize = myLastSize;
                        var checkHScrollHack =
                            !GetStateFlag(VTCStateFlags.InFirstWmSize) &&
                            (curSize.Width != cacheLastSize.Width);
                        var iPrevPos = 0;
                        var scrollRegionClean = false;
                        if (checkHScrollHack)
                        {
                            checkHScrollHack = HasHorizontalScrollBar;
                            if (checkHScrollHack)
                            {
                                iPrevPos = myXPos;
                                // There are several options here to avoid the braindead (and heavily flashing)
                                // approach of fully invalidating the window when this happens.
                                var hRgn = NativeMethods.CreateRectRgn(0, 0, 0, 0);
                                if (hRgn != IntPtr.Zero)
                                {
                                    var regType = NativeMethods.GetUpdateRgn(m.HWnd, hRgn, false);
                                    switch (regType)
                                    {
                                        case NativeMethods.RegionType.Complex:
                                        case NativeMethods.RegionType.Simple:
                                            {
                                                var testRect = new NativeMethods.RECT(0, 0, cacheLastSize.Width, cacheLastSize.Height);
                                                if (NativeMethods.RectInRegion(hRgn, ref testRect))
                                                {
                                                    scrollRegionClean = false;
                                                }
                                                break;
                                            }
                                    }
                                    NativeMethods.DeleteObject(hRgn);
                                }
                            }
                        }
                        //Debug.WriteLine("WM_SIZE Before base WndProc " + myXPos.ToString() + " " + HasHorizontalScrollBar.ToString() + cacheLastSize.Width.ToString() + "/" + cacheLastSize.Height.ToString());
                        SetStateFlag(VTCStateFlags.InWmSize, true);
                        var inFirstSize = !GetStateFlag(VTCStateFlags.InFirstWmSize);
                        if (inFirstSize)
                        {
                            Redraw = false;
                            SetStateFlag(VTCStateFlags.InFirstWmSize, true);
                        }
                        base.WndProc(ref m);
                        if (inFirstSize)
                        {
                            SetStateFlag(VTCStateFlags.InFirstWmSize, false);
                            Redraw = true;
                        }
                        if (GetStateFlag(VTCStateFlags.InWmSize))
                        {
                            // WM_SIZE can recurse as the scrollbars come and go, use
                            // the last pass, not the first, to record the new size, but
                            // always use the first pass to do the scrolling.
                            myLastSize = curSize;
                            SetStateFlag(VTCStateFlags.InWmSize, false);
                        }
                        if (checkHScrollHack)
                        {
                            if (iPrevPos != myXPos)
                            {
                                if (scrollRegionClean)
                                {
                                    var ssi = new SmoothScroll.Info(m.HWnd, myLastSize.Width - cacheLastSize.Width, 0);
                                    ssi.scrollWindowFlags = NativeMethods.ScrollWindowFlags.Invalidate
                                                            | NativeMethods.ScrollWindowFlags.Erase;
                                    ssi.smoothScrollFlags = SmoothScroll.Flags.Immediate;
                                    ssi.srcRect.Width = cacheLastSize.Width;
                                    ssi.srcRect.Height = cacheLastSize.Height;
                                    Debug.WriteLine("Before Scrolling Window");
                                    SmoothScroll.ScrollWindow(this, ref ssi);
                                    Debug.WriteLine("After Scrolling Window");
                                }
                                else
                                {
                                    NativeMethods.InvalidateRect(m.HWnd, IntPtr.Zero, true);
                                }
                            }
                        }
                        if (inFirstSize)
                        {
                            //Debug.WriteLine("WM_SIZE After base WndProc " + myXPos.ToString() + " " + HasHorizontalScrollBar.ToString() + myLastSize.Width.ToString() + "/" + myLastSize.Height.ToString());
                            SizeWnd(myLastSize.Width, myLastSize.Height);
                        }
                        break;
                    }
                case NativeMethods.WM_HSCROLL:
                    DismissLabelEdit(false, true);
                    base.WndProc(ref m);
                    if (myHeaderContainer != null)
                    {
                        if (ItemCount == 0)
                        {
                            // DefWndProc does nothing if there are no items in the tree, so we
                            // need to do it ourselves to get the scrollbar to move.
                            var si = new NativeMethods.SCROLLINFO(0);
                            si.fMask = NativeMethods.ScrollInfoFlags.All;
                            NativeMethods.GetScrollInfo(m.HWnd, NativeMethods.ScrollBarType.Horizontal, ref si);
                            var newPos = si.nPos;
                            switch ((NativeMethods.ScrollAction)NativeMethods.UnsignedLOWORD((int)m.WParam))
                            {
                                case NativeMethods.ScrollAction.LineLeft:

                                    newPos -= HORIZONTAL_SCROLL_AMOUNT;
                                    break;
                                case NativeMethods.ScrollAction.LineRight:
                                    newPos += HORIZONTAL_SCROLL_AMOUNT;
                                    break;
                                case NativeMethods.ScrollAction.PageLeft:
                                    newPos -= si.nPage;
                                    break;
                                case NativeMethods.ScrollAction.PageRight:
                                    newPos += si.nPage;
                                    break;
                                case NativeMethods.ScrollAction.ThumbPosition:
                                case NativeMethods.ScrollAction.ThumbTrack:
                                    newPos = si.nTrackPos;
                                    break;
                            }
                            if (newPos != si.nPos)
                            {
                                newPos = Math.Min(Math.Max(0, newPos), si.nMax - si.nPage + 1);
                                if (newPos != si.nPos)
                                {
                                    NativeMethods.SetScrollPos(m.HWnd, NativeMethods.ScrollBarType.Horizontal, newPos, true);
                                }
                            }
                        }
                        myHeaderContainer.UpdateHeaderControlPosition(false);
                    }
                    //	wParam = (int)m.WParam;
                    //	HorzScroll((NativeMethods.ScrollAction)NativeMethods.LOWORD(wParam), NativeMethods.HIWORD(wParam));
                    break;

                case NativeMethods.WM_VSCROLL:
                    {
                        var fEndScroll =
                            (NativeMethods.ScrollAction)NativeMethods.UnsignedLOWORD((int)m.WParam) == NativeMethods.ScrollAction.EndScroll;
                        if (!fEndScroll
                            && !GetStateFlag(VTCStateFlags.InVerticalScroll))
                        {
                            DismissLabelEdit(false, true);
                            SetStateFlag(VTCStateFlags.InVerticalScroll, true);
                            myTopStartScroll = TopIndex;
                        }
                        base.WndProc(ref m);
                        if (fEndScroll)
                        {
                            SetStateFlag(VTCStateFlags.InVerticalScroll, false);
                            //BeginInvoke(new CallVoid(VScrollCompleted));
                            VScrollCompleted();
                        }
                        //VertScroll((NativeMethods.ScrollAction)NativeMethods.LOWORD(wParam), NativeMethods.HIWORD(wParam));
                        break;
                    }
                case NativeMethods.WM_MOUSEWHEEL:
                    DismissLabelEdit(false, true);
                    base.WndProc(ref m);
                    if (myHeaderContainer != null
                        && HasHorizontalScrollBar
                        && !HasVerticalScrollBar)
                    {
                        // if there's no vertical scroll bar, mousehweel scrolls horizontally so we need to
                        // update the header.
                        myHeaderContainer.UpdateHeaderControlPosition(false);
                    }
                    break;

                    //				case NativeMethods.WM_LBUTTONUP:
                    //					// Get the mouse location
                    //					//
                    //					int x = (int)(short)m.LParam;
                    //					int y = (int)m.LParam >> 16;
                    //					Point pt = new Point(x,y);
                    //					pt = PointToScreen(pt);
                    //					bool captured = Capture;
                    //					if (captured && UnsafeNativeMethods.WindowFromPoint(pt.X, pt.Y) == Handle) 
                    //					{
                    //						if (selectedItems != null) 
                    //						{
                    //							selectedItems.Dirty();
                    //						}
                    //						
                    //						if (!doubleClickFired && !ValidationCancelled) 
                    //						{
                    //							OnClick(EventArgs.Empty);
                    //						}
                    //						else 
                    //						{
                    //							doubleClickFired = false;
                    //							// WM_COMMAND is only fired if the user double clicks an item,
                    //							// so we can't use that as a double-click substitute
                    //							if (!ValidationCancelled) 
                    //							{
                    //								OnDoubleClick(EventArgs.Empty);
                    //							}
                    //						}
                    //					}
                    //					base.WndProc(ref m);
                    //					doubleClickFired = false;
                    //					break;
                    //
                    //				case NativeMethods.WM_LBUTTONDBLCLK:
                    //					//the Listbox gets  WM_LBUTTONDOWN - WM_LBUTTONUP -WM_LBUTTONDBLCLK - WM_LBUTTONUP...
                    //					//sequence for doubleclick...
                    //					//the first WM_LBUTTONUP, resets the flag for Doubleclick
                    //					//So its necessary for us to set it again...
                    //					doubleClickFired = true;
                    //					base.WndProc(ref m);
                    //					break;
                    //				
                    //				case NativeMethods.WM_WINDOWPOSCHANGED:
                    //					base.WndProc(ref m);
                    //					if (integralHeight && fontIsChanged) 
                    //					{
                    //						Height = Math.Max(Height,ItemHeight);
                    //						fontIsChanged = false;
                    //					}
                    //					break;
                case NativeMethods.WM_CONTEXTMENU:
                    ContextMenuEventArgs e = null;
                    if (m.LParam.ToInt32() != -1)
                    {
                        e = new ContextMenuEventArgs(NativeMethods.SignedLOWORD(m.LParam), NativeMethods.SignedHIWORD(m.LParam));
                    }
                    else
                    {
                        // context menu was invoked through the keyboard.  determine location based on
                        // current selection within the tree.
                        var index = CurrentIndex;
                        Point p;
                        if (index != -1)
                        {
                            var r = GetItemRectangle(CurrentIndex, CurrentColumn, true, true, null);
                            p = PointToScreen(new Point(r.Right, r.Bottom));
                        }
                        else
                        {
                            p = PointToScreen(Point.Empty);
                        }
                        e = new ContextMenuEventArgs(p.X, p.Y);
                    }
                    OnContextMenuInvoked(e);
                    break;
                case NativeMethods.WM_GETOBJECT:
                    OnWmGetObject(ref m);
                    break;
                case NativeMethods.WM_SYSCOLORCHANGE:
                case NativeMethods.WM_THEMECHANGED:
                    // theme changed, invalidate the indent bitmaps, which may contain themed button glyphs.
                    // this will get recreated the next time it's needed for painting
                    IndentBitmap = null;
                    // Also, let the header control change its theme
                    if (myHeaderContainer != null
                        && myHeaderContainer.IsHandleCreated)
                    {
                        NativeMethods.SendMessage(myHeaderContainer.HeaderControl.Handle, m.Msg, m.WParam, m.LParam);
                    }

                    break;
                    // UNDONE : following are provided temporarily for compatibility with existing Burton clients.
                    // should be removed once those clients switch to the corresponding public APIs.
                case NativeMethods.LB_SETSEL:
                    var select = m.WParam == IntPtr.Zero ? false : true;
                    if (m.LParam == (IntPtr)(-1))
                    {
                        if (select)
                        {
                            SelectAll();
                        }
                        else
                        {
                            ClearSelection();
                        }
                    }
                    else
                    {
                        SelectRange((int)m.LParam, (int)m.LParam, select);
                    }
                    m.Result = (IntPtr)1;
                    break;
                case NativeMethods.LB_SETANCHORINDEX:
                    AnchorIndex = (int)m.WParam;
                    m.Result = (IntPtr)1;
                    break;
                case NativeMethods.LB_GETANCHORINDEX:
                    m.Result = (IntPtr)AnchorIndex;
                    break;
                default:
                    base.WndProc(ref m);
                    break;
            }
        }